diff --git a/mobile/openapi/lib/api/activities_api.dart b/mobile/openapi/lib/api/activities_api.dart index b92f95be7..697598ac9 100644 Binary files a/mobile/openapi/lib/api/activities_api.dart and b/mobile/openapi/lib/api/activities_api.dart differ diff --git a/mobile/openapi/lib/api/albums_api.dart b/mobile/openapi/lib/api/albums_api.dart index 1042a2850..713bcafee 100644 Binary files a/mobile/openapi/lib/api/albums_api.dart and b/mobile/openapi/lib/api/albums_api.dart differ diff --git a/mobile/openapi/lib/api/assets_api.dart b/mobile/openapi/lib/api/assets_api.dart index e737397fc..5fda01a59 100644 Binary files a/mobile/openapi/lib/api/assets_api.dart and b/mobile/openapi/lib/api/assets_api.dart differ diff --git a/mobile/openapi/lib/api/deprecated_api.dart b/mobile/openapi/lib/api/deprecated_api.dart index d0d92d804..33bcaf062 100644 Binary files a/mobile/openapi/lib/api/deprecated_api.dart and b/mobile/openapi/lib/api/deprecated_api.dart differ diff --git a/mobile/openapi/lib/api/faces_api.dart b/mobile/openapi/lib/api/faces_api.dart index 1d2e7401e..43d63b47b 100644 Binary files a/mobile/openapi/lib/api/faces_api.dart and b/mobile/openapi/lib/api/faces_api.dart differ diff --git a/mobile/openapi/lib/api/jobs_api.dart b/mobile/openapi/lib/api/jobs_api.dart index 9dda59a88..41517f814 100644 Binary files a/mobile/openapi/lib/api/jobs_api.dart and b/mobile/openapi/lib/api/jobs_api.dart differ diff --git a/mobile/openapi/lib/api/map_api.dart b/mobile/openapi/lib/api/map_api.dart index 6302ac304..4ce62bd96 100644 Binary files a/mobile/openapi/lib/api/map_api.dart and b/mobile/openapi/lib/api/map_api.dart differ diff --git a/mobile/openapi/lib/api/memories_api.dart b/mobile/openapi/lib/api/memories_api.dart index 314595e84..913205428 100644 Binary files a/mobile/openapi/lib/api/memories_api.dart and b/mobile/openapi/lib/api/memories_api.dart differ diff --git a/mobile/openapi/lib/api/notifications_api.dart b/mobile/openapi/lib/api/notifications_api.dart index 2de59a0a7..d4e2b1d80 100644 Binary files a/mobile/openapi/lib/api/notifications_api.dart and b/mobile/openapi/lib/api/notifications_api.dart differ diff --git a/mobile/openapi/lib/api/partners_api.dart b/mobile/openapi/lib/api/partners_api.dart index 7d18f6d86..3b15b9090 100644 Binary files a/mobile/openapi/lib/api/partners_api.dart and b/mobile/openapi/lib/api/partners_api.dart differ diff --git a/mobile/openapi/lib/api/people_api.dart b/mobile/openapi/lib/api/people_api.dart index c38e61584..c8c182142 100644 Binary files a/mobile/openapi/lib/api/people_api.dart and b/mobile/openapi/lib/api/people_api.dart differ diff --git a/mobile/openapi/lib/api/queues_api.dart b/mobile/openapi/lib/api/queues_api.dart index 50575ed70..ecb556e43 100644 Binary files a/mobile/openapi/lib/api/queues_api.dart and b/mobile/openapi/lib/api/queues_api.dart differ diff --git a/mobile/openapi/lib/api/search_api.dart b/mobile/openapi/lib/api/search_api.dart index ee5f64753..1b8ed3d9e 100644 Binary files a/mobile/openapi/lib/api/search_api.dart and b/mobile/openapi/lib/api/search_api.dart differ diff --git a/mobile/openapi/lib/api/shared_links_api.dart b/mobile/openapi/lib/api/shared_links_api.dart index 587a9640b..7f11db76d 100644 Binary files a/mobile/openapi/lib/api/shared_links_api.dart and b/mobile/openapi/lib/api/shared_links_api.dart differ diff --git a/mobile/openapi/lib/api/stacks_api.dart b/mobile/openapi/lib/api/stacks_api.dart index 66fa1881a..a691af2a7 100644 Binary files a/mobile/openapi/lib/api/stacks_api.dart and b/mobile/openapi/lib/api/stacks_api.dart differ diff --git a/mobile/openapi/lib/api/users_admin_api.dart b/mobile/openapi/lib/api/users_admin_api.dart index 842a3ebc5..59a4b6009 100644 Binary files a/mobile/openapi/lib/api/users_admin_api.dart and b/mobile/openapi/lib/api/users_admin_api.dart differ diff --git a/mobile/openapi/lib/api/users_api.dart b/mobile/openapi/lib/api/users_api.dart index f398d9c81..7ccae02c7 100644 Binary files a/mobile/openapi/lib/api/users_api.dart and b/mobile/openapi/lib/api/users_api.dart differ diff --git a/mobile/openapi/lib/model/activity_create_dto.dart b/mobile/openapi/lib/model/activity_create_dto.dart index ce4b4a017..fb4b6d084 100644 Binary files a/mobile/openapi/lib/model/activity_create_dto.dart and b/mobile/openapi/lib/model/activity_create_dto.dart differ diff --git a/mobile/openapi/lib/model/activity_response_dto.dart b/mobile/openapi/lib/model/activity_response_dto.dart index 25fb0f53f..dadb45d8a 100644 Binary files a/mobile/openapi/lib/model/activity_response_dto.dart and b/mobile/openapi/lib/model/activity_response_dto.dart differ diff --git a/mobile/openapi/lib/model/activity_statistics_response_dto.dart b/mobile/openapi/lib/model/activity_statistics_response_dto.dart index 27c478230..15ad2a170 100644 Binary files a/mobile/openapi/lib/model/activity_statistics_response_dto.dart and b/mobile/openapi/lib/model/activity_statistics_response_dto.dart differ diff --git a/mobile/openapi/lib/model/add_users_dto.dart b/mobile/openapi/lib/model/add_users_dto.dart index 531c1ec78..1dad23481 100644 Binary files a/mobile/openapi/lib/model/add_users_dto.dart and b/mobile/openapi/lib/model/add_users_dto.dart differ diff --git a/mobile/openapi/lib/model/admin_onboarding_update_dto.dart b/mobile/openapi/lib/model/admin_onboarding_update_dto.dart index 298bf318a..6daba2a79 100644 Binary files a/mobile/openapi/lib/model/admin_onboarding_update_dto.dart and b/mobile/openapi/lib/model/admin_onboarding_update_dto.dart differ diff --git a/mobile/openapi/lib/model/album_response_dto.dart b/mobile/openapi/lib/model/album_response_dto.dart index 2f53706e7..43e686fbd 100644 Binary files a/mobile/openapi/lib/model/album_response_dto.dart and b/mobile/openapi/lib/model/album_response_dto.dart differ diff --git a/mobile/openapi/lib/model/album_statistics_response_dto.dart b/mobile/openapi/lib/model/album_statistics_response_dto.dart index 9e19002cf..127334e68 100644 Binary files a/mobile/openapi/lib/model/album_statistics_response_dto.dart and b/mobile/openapi/lib/model/album_statistics_response_dto.dart differ diff --git a/mobile/openapi/lib/model/album_user_add_dto.dart b/mobile/openapi/lib/model/album_user_add_dto.dart index e1f24377d..c448a0b4b 100644 Binary files a/mobile/openapi/lib/model/album_user_add_dto.dart and b/mobile/openapi/lib/model/album_user_add_dto.dart differ diff --git a/mobile/openapi/lib/model/album_user_create_dto.dart b/mobile/openapi/lib/model/album_user_create_dto.dart index 93a0661b3..800674834 100644 Binary files a/mobile/openapi/lib/model/album_user_create_dto.dart and b/mobile/openapi/lib/model/album_user_create_dto.dart differ diff --git a/mobile/openapi/lib/model/album_user_response_dto.dart b/mobile/openapi/lib/model/album_user_response_dto.dart index bbae03fba..8d0c01cfb 100644 Binary files a/mobile/openapi/lib/model/album_user_response_dto.dart and b/mobile/openapi/lib/model/album_user_response_dto.dart differ diff --git a/mobile/openapi/lib/model/album_user_role.dart b/mobile/openapi/lib/model/album_user_role.dart index c0d61cd7f..d797fdc2e 100644 Binary files a/mobile/openapi/lib/model/album_user_role.dart and b/mobile/openapi/lib/model/album_user_role.dart differ diff --git a/mobile/openapi/lib/model/albums_add_assets_dto.dart b/mobile/openapi/lib/model/albums_add_assets_dto.dart index bdbf68980..d6aa3db1c 100644 Binary files a/mobile/openapi/lib/model/albums_add_assets_dto.dart and b/mobile/openapi/lib/model/albums_add_assets_dto.dart differ diff --git a/mobile/openapi/lib/model/albums_add_assets_response_dto.dart b/mobile/openapi/lib/model/albums_add_assets_response_dto.dart index 4ad2c5e15..743a9f064 100644 Binary files a/mobile/openapi/lib/model/albums_add_assets_response_dto.dart and b/mobile/openapi/lib/model/albums_add_assets_response_dto.dart differ diff --git a/mobile/openapi/lib/model/albums_response.dart b/mobile/openapi/lib/model/albums_response.dart index 4f9a8eb8f..520ee171c 100644 Binary files a/mobile/openapi/lib/model/albums_response.dart and b/mobile/openapi/lib/model/albums_response.dart differ diff --git a/mobile/openapi/lib/model/albums_update.dart b/mobile/openapi/lib/model/albums_update.dart index d61b5c139..107c65dd1 100644 Binary files a/mobile/openapi/lib/model/albums_update.dart and b/mobile/openapi/lib/model/albums_update.dart differ diff --git a/mobile/openapi/lib/model/api_key_create_dto.dart b/mobile/openapi/lib/model/api_key_create_dto.dart index 848774e9c..e64b12782 100644 Binary files a/mobile/openapi/lib/model/api_key_create_dto.dart and b/mobile/openapi/lib/model/api_key_create_dto.dart differ diff --git a/mobile/openapi/lib/model/api_key_create_response_dto.dart b/mobile/openapi/lib/model/api_key_create_response_dto.dart index cdaa70e37..7540c4bb2 100644 Binary files a/mobile/openapi/lib/model/api_key_create_response_dto.dart and b/mobile/openapi/lib/model/api_key_create_response_dto.dart differ diff --git a/mobile/openapi/lib/model/api_key_response_dto.dart b/mobile/openapi/lib/model/api_key_response_dto.dart index fd0d91f67..32ba54334 100644 Binary files a/mobile/openapi/lib/model/api_key_response_dto.dart and b/mobile/openapi/lib/model/api_key_response_dto.dart differ diff --git a/mobile/openapi/lib/model/api_key_update_dto.dart b/mobile/openapi/lib/model/api_key_update_dto.dart index 7f32c9511..ba107bcda 100644 Binary files a/mobile/openapi/lib/model/api_key_update_dto.dart and b/mobile/openapi/lib/model/api_key_update_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_bulk_delete_dto.dart b/mobile/openapi/lib/model/asset_bulk_delete_dto.dart index c4453054b..055ef1601 100644 Binary files a/mobile/openapi/lib/model/asset_bulk_delete_dto.dart and b/mobile/openapi/lib/model/asset_bulk_delete_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_bulk_update_dto.dart b/mobile/openapi/lib/model/asset_bulk_update_dto.dart index d7e75ae36..c77026586 100644 Binary files a/mobile/openapi/lib/model/asset_bulk_update_dto.dart and b/mobile/openapi/lib/model/asset_bulk_update_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_bulk_upload_check_dto.dart b/mobile/openapi/lib/model/asset_bulk_upload_check_dto.dart index 36c13bfdf..66f46795e 100644 Binary files a/mobile/openapi/lib/model/asset_bulk_upload_check_dto.dart and b/mobile/openapi/lib/model/asset_bulk_upload_check_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_bulk_upload_check_item.dart b/mobile/openapi/lib/model/asset_bulk_upload_check_item.dart index 13dfa340f..65f81926e 100644 Binary files a/mobile/openapi/lib/model/asset_bulk_upload_check_item.dart and b/mobile/openapi/lib/model/asset_bulk_upload_check_item.dart differ diff --git a/mobile/openapi/lib/model/asset_bulk_upload_check_response_dto.dart b/mobile/openapi/lib/model/asset_bulk_upload_check_response_dto.dart index 8c3651e9f..b37bb0de8 100644 Binary files a/mobile/openapi/lib/model/asset_bulk_upload_check_response_dto.dart and b/mobile/openapi/lib/model/asset_bulk_upload_check_response_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_bulk_upload_check_result.dart b/mobile/openapi/lib/model/asset_bulk_upload_check_result.dart index 88e46dae7..b56370f68 100644 Binary files a/mobile/openapi/lib/model/asset_bulk_upload_check_result.dart and b/mobile/openapi/lib/model/asset_bulk_upload_check_result.dart differ diff --git a/mobile/openapi/lib/model/asset_copy_dto.dart b/mobile/openapi/lib/model/asset_copy_dto.dart index ba19cb1db..2e68c5c11 100644 Binary files a/mobile/openapi/lib/model/asset_copy_dto.dart and b/mobile/openapi/lib/model/asset_copy_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_delta_sync_dto.dart b/mobile/openapi/lib/model/asset_delta_sync_dto.dart index 845aadcdc..22c09752d 100644 Binary files a/mobile/openapi/lib/model/asset_delta_sync_dto.dart and b/mobile/openapi/lib/model/asset_delta_sync_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_delta_sync_response_dto.dart b/mobile/openapi/lib/model/asset_delta_sync_response_dto.dart index a64e1a2fb..7351840b1 100644 Binary files a/mobile/openapi/lib/model/asset_delta_sync_response_dto.dart and b/mobile/openapi/lib/model/asset_delta_sync_response_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_edit_action.dart b/mobile/openapi/lib/model/asset_edit_action.dart index 12aacfb68..3754cb450 100644 Binary files a/mobile/openapi/lib/model/asset_edit_action.dart and b/mobile/openapi/lib/model/asset_edit_action.dart differ diff --git a/mobile/openapi/lib/model/asset_edit_action_crop.dart b/mobile/openapi/lib/model/asset_edit_action_crop.dart index 3b55a105d..7672ed825 100644 Binary files a/mobile/openapi/lib/model/asset_edit_action_crop.dart and b/mobile/openapi/lib/model/asset_edit_action_crop.dart differ diff --git a/mobile/openapi/lib/model/asset_edit_action_list_dto.dart b/mobile/openapi/lib/model/asset_edit_action_list_dto.dart index 48c1e1592..e843c66e8 100644 Binary files a/mobile/openapi/lib/model/asset_edit_action_list_dto.dart and b/mobile/openapi/lib/model/asset_edit_action_list_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_edit_action_list_dto_edits_inner.dart b/mobile/openapi/lib/model/asset_edit_action_list_dto_edits_inner.dart index c4c049663..00c9be238 100644 Binary files a/mobile/openapi/lib/model/asset_edit_action_list_dto_edits_inner.dart and b/mobile/openapi/lib/model/asset_edit_action_list_dto_edits_inner.dart differ diff --git a/mobile/openapi/lib/model/asset_edit_action_mirror.dart b/mobile/openapi/lib/model/asset_edit_action_mirror.dart index 782d317b7..aef98fc1a 100644 Binary files a/mobile/openapi/lib/model/asset_edit_action_mirror.dart and b/mobile/openapi/lib/model/asset_edit_action_mirror.dart differ diff --git a/mobile/openapi/lib/model/asset_edit_action_rotate.dart b/mobile/openapi/lib/model/asset_edit_action_rotate.dart index 1104c0630..302e6a0ce 100644 Binary files a/mobile/openapi/lib/model/asset_edit_action_rotate.dart and b/mobile/openapi/lib/model/asset_edit_action_rotate.dart differ diff --git a/mobile/openapi/lib/model/asset_edits_dto.dart b/mobile/openapi/lib/model/asset_edits_dto.dart index 26757dce3..3bfbce859 100644 Binary files a/mobile/openapi/lib/model/asset_edits_dto.dart and b/mobile/openapi/lib/model/asset_edits_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_face_create_dto.dart b/mobile/openapi/lib/model/asset_face_create_dto.dart index 29e8244a9..3ecc20c69 100644 Binary files a/mobile/openapi/lib/model/asset_face_create_dto.dart and b/mobile/openapi/lib/model/asset_face_create_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_face_delete_dto.dart b/mobile/openapi/lib/model/asset_face_delete_dto.dart index 2e53b0699..a1f3731be 100644 Binary files a/mobile/openapi/lib/model/asset_face_delete_dto.dart and b/mobile/openapi/lib/model/asset_face_delete_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_face_response_dto.dart b/mobile/openapi/lib/model/asset_face_response_dto.dart index c05b51164..61d972a0c 100644 Binary files a/mobile/openapi/lib/model/asset_face_response_dto.dart and b/mobile/openapi/lib/model/asset_face_response_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_face_update_dto.dart b/mobile/openapi/lib/model/asset_face_update_dto.dart index 71bdde8e9..102762755 100644 Binary files a/mobile/openapi/lib/model/asset_face_update_dto.dart and b/mobile/openapi/lib/model/asset_face_update_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_face_update_item.dart b/mobile/openapi/lib/model/asset_face_update_item.dart index c2c480325..a81b21e13 100644 Binary files a/mobile/openapi/lib/model/asset_face_update_item.dart and b/mobile/openapi/lib/model/asset_face_update_item.dart differ diff --git a/mobile/openapi/lib/model/asset_face_without_person_response_dto.dart b/mobile/openapi/lib/model/asset_face_without_person_response_dto.dart index 8bf07e153..1ae5cef07 100644 Binary files a/mobile/openapi/lib/model/asset_face_without_person_response_dto.dart and b/mobile/openapi/lib/model/asset_face_without_person_response_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_full_sync_dto.dart b/mobile/openapi/lib/model/asset_full_sync_dto.dart index 7151094b9..3fabb1cac 100644 Binary files a/mobile/openapi/lib/model/asset_full_sync_dto.dart and b/mobile/openapi/lib/model/asset_full_sync_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_ids_dto.dart b/mobile/openapi/lib/model/asset_ids_dto.dart index b44888f39..85e5cc3ae 100644 Binary files a/mobile/openapi/lib/model/asset_ids_dto.dart and b/mobile/openapi/lib/model/asset_ids_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_ids_response_dto.dart b/mobile/openapi/lib/model/asset_ids_response_dto.dart index ff63091ca..974528302 100644 Binary files a/mobile/openapi/lib/model/asset_ids_response_dto.dart and b/mobile/openapi/lib/model/asset_ids_response_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_job_name.dart b/mobile/openapi/lib/model/asset_job_name.dart index 11e0555b8..7625677bb 100644 Binary files a/mobile/openapi/lib/model/asset_job_name.dart and b/mobile/openapi/lib/model/asset_job_name.dart differ diff --git a/mobile/openapi/lib/model/asset_jobs_dto.dart b/mobile/openapi/lib/model/asset_jobs_dto.dart index 0f8bfab00..0aa5544a3 100644 Binary files a/mobile/openapi/lib/model/asset_jobs_dto.dart and b/mobile/openapi/lib/model/asset_jobs_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_media_response_dto.dart b/mobile/openapi/lib/model/asset_media_response_dto.dart index 75428ec5f..905e738b6 100644 Binary files a/mobile/openapi/lib/model/asset_media_response_dto.dart and b/mobile/openapi/lib/model/asset_media_response_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_media_status.dart b/mobile/openapi/lib/model/asset_media_status.dart index 42fec08cc..b45918e5c 100644 Binary files a/mobile/openapi/lib/model/asset_media_status.dart and b/mobile/openapi/lib/model/asset_media_status.dart differ diff --git a/mobile/openapi/lib/model/asset_metadata_bulk_delete_dto.dart b/mobile/openapi/lib/model/asset_metadata_bulk_delete_dto.dart index 23c34d715..6376ebc53 100644 Binary files a/mobile/openapi/lib/model/asset_metadata_bulk_delete_dto.dart and b/mobile/openapi/lib/model/asset_metadata_bulk_delete_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_metadata_bulk_delete_item_dto.dart b/mobile/openapi/lib/model/asset_metadata_bulk_delete_item_dto.dart index a3a111f9f..90417b79e 100644 Binary files a/mobile/openapi/lib/model/asset_metadata_bulk_delete_item_dto.dart and b/mobile/openapi/lib/model/asset_metadata_bulk_delete_item_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_metadata_bulk_response_dto.dart b/mobile/openapi/lib/model/asset_metadata_bulk_response_dto.dart index 15c130930..b79a69372 100644 Binary files a/mobile/openapi/lib/model/asset_metadata_bulk_response_dto.dart and b/mobile/openapi/lib/model/asset_metadata_bulk_response_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_metadata_bulk_upsert_dto.dart b/mobile/openapi/lib/model/asset_metadata_bulk_upsert_dto.dart index fe9d9ed25..a5e770b02 100644 Binary files a/mobile/openapi/lib/model/asset_metadata_bulk_upsert_dto.dart and b/mobile/openapi/lib/model/asset_metadata_bulk_upsert_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_metadata_bulk_upsert_item_dto.dart b/mobile/openapi/lib/model/asset_metadata_bulk_upsert_item_dto.dart index 25a219537..caaf379b3 100644 Binary files a/mobile/openapi/lib/model/asset_metadata_bulk_upsert_item_dto.dart and b/mobile/openapi/lib/model/asset_metadata_bulk_upsert_item_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_metadata_response_dto.dart b/mobile/openapi/lib/model/asset_metadata_response_dto.dart index cccf42ae8..2c3faab17 100644 Binary files a/mobile/openapi/lib/model/asset_metadata_response_dto.dart and b/mobile/openapi/lib/model/asset_metadata_response_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_metadata_upsert_dto.dart b/mobile/openapi/lib/model/asset_metadata_upsert_dto.dart index 45d044feb..b1473d482 100644 Binary files a/mobile/openapi/lib/model/asset_metadata_upsert_dto.dart and b/mobile/openapi/lib/model/asset_metadata_upsert_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_metadata_upsert_item_dto.dart b/mobile/openapi/lib/model/asset_metadata_upsert_item_dto.dart index 3d247f857..8a6bcb9b0 100644 Binary files a/mobile/openapi/lib/model/asset_metadata_upsert_item_dto.dart and b/mobile/openapi/lib/model/asset_metadata_upsert_item_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_order.dart b/mobile/openapi/lib/model/asset_order.dart index ca04e2b78..21edd95ff 100644 Binary files a/mobile/openapi/lib/model/asset_order.dart and b/mobile/openapi/lib/model/asset_order.dart differ diff --git a/mobile/openapi/lib/model/asset_response_dto.dart b/mobile/openapi/lib/model/asset_response_dto.dart index 27aa3b98f..5422ccf55 100644 Binary files a/mobile/openapi/lib/model/asset_response_dto.dart and b/mobile/openapi/lib/model/asset_response_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_stack_response_dto.dart b/mobile/openapi/lib/model/asset_stack_response_dto.dart index bb4becb12..229e7aa71 100644 Binary files a/mobile/openapi/lib/model/asset_stack_response_dto.dart and b/mobile/openapi/lib/model/asset_stack_response_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_stats_response_dto.dart b/mobile/openapi/lib/model/asset_stats_response_dto.dart index d11ce55a5..201550c87 100644 Binary files a/mobile/openapi/lib/model/asset_stats_response_dto.dart and b/mobile/openapi/lib/model/asset_stats_response_dto.dart differ diff --git a/mobile/openapi/lib/model/asset_type_enum.dart b/mobile/openapi/lib/model/asset_type_enum.dart index 1022beb24..b6e035119 100644 Binary files a/mobile/openapi/lib/model/asset_type_enum.dart and b/mobile/openapi/lib/model/asset_type_enum.dart differ diff --git a/mobile/openapi/lib/model/asset_visibility.dart b/mobile/openapi/lib/model/asset_visibility.dart index 498bf17c3..6290dffb2 100644 Binary files a/mobile/openapi/lib/model/asset_visibility.dart and b/mobile/openapi/lib/model/asset_visibility.dart differ diff --git a/mobile/openapi/lib/model/audio_codec.dart b/mobile/openapi/lib/model/audio_codec.dart index ea1e96f36..095c61699 100644 Binary files a/mobile/openapi/lib/model/audio_codec.dart and b/mobile/openapi/lib/model/audio_codec.dart differ diff --git a/mobile/openapi/lib/model/auth_status_response_dto.dart b/mobile/openapi/lib/model/auth_status_response_dto.dart index 4e823506e..23b9d4052 100644 Binary files a/mobile/openapi/lib/model/auth_status_response_dto.dart and b/mobile/openapi/lib/model/auth_status_response_dto.dart differ diff --git a/mobile/openapi/lib/model/avatar_update.dart b/mobile/openapi/lib/model/avatar_update.dart index 875eb138a..a817832da 100644 Binary files a/mobile/openapi/lib/model/avatar_update.dart and b/mobile/openapi/lib/model/avatar_update.dart differ diff --git a/mobile/openapi/lib/model/bulk_id_error_reason.dart b/mobile/openapi/lib/model/bulk_id_error_reason.dart index cdaf70217..ea56e9dbb 100644 Binary files a/mobile/openapi/lib/model/bulk_id_error_reason.dart and b/mobile/openapi/lib/model/bulk_id_error_reason.dart differ diff --git a/mobile/openapi/lib/model/bulk_id_response_dto.dart b/mobile/openapi/lib/model/bulk_id_response_dto.dart index 67a587e8d..cd122785d 100644 Binary files a/mobile/openapi/lib/model/bulk_id_response_dto.dart and b/mobile/openapi/lib/model/bulk_id_response_dto.dart differ diff --git a/mobile/openapi/lib/model/bulk_ids_dto.dart b/mobile/openapi/lib/model/bulk_ids_dto.dart index 6a7f8ceee..7e7864a28 100644 Binary files a/mobile/openapi/lib/model/bulk_ids_dto.dart and b/mobile/openapi/lib/model/bulk_ids_dto.dart differ diff --git a/mobile/openapi/lib/model/cast_response.dart b/mobile/openapi/lib/model/cast_response.dart index d49f1ad3d..0b7f0738f 100644 Binary files a/mobile/openapi/lib/model/cast_response.dart and b/mobile/openapi/lib/model/cast_response.dart differ diff --git a/mobile/openapi/lib/model/cast_update.dart b/mobile/openapi/lib/model/cast_update.dart index 870763913..8dbf80f17 100644 Binary files a/mobile/openapi/lib/model/cast_update.dart and b/mobile/openapi/lib/model/cast_update.dart differ diff --git a/mobile/openapi/lib/model/change_password_dto.dart b/mobile/openapi/lib/model/change_password_dto.dart index 4a897f407..3dd6e437d 100644 Binary files a/mobile/openapi/lib/model/change_password_dto.dart and b/mobile/openapi/lib/model/change_password_dto.dart differ diff --git a/mobile/openapi/lib/model/check_existing_assets_dto.dart b/mobile/openapi/lib/model/check_existing_assets_dto.dart index 42ce6d5c3..6e4a47109 100644 Binary files a/mobile/openapi/lib/model/check_existing_assets_dto.dart and b/mobile/openapi/lib/model/check_existing_assets_dto.dart differ diff --git a/mobile/openapi/lib/model/check_existing_assets_response_dto.dart b/mobile/openapi/lib/model/check_existing_assets_response_dto.dart index ad93578eb..9fb13f100 100644 Binary files a/mobile/openapi/lib/model/check_existing_assets_response_dto.dart and b/mobile/openapi/lib/model/check_existing_assets_response_dto.dart differ diff --git a/mobile/openapi/lib/model/clip_config.dart b/mobile/openapi/lib/model/clip_config.dart index b500d20f2..915e4975e 100644 Binary files a/mobile/openapi/lib/model/clip_config.dart and b/mobile/openapi/lib/model/clip_config.dart differ diff --git a/mobile/openapi/lib/model/colorspace.dart b/mobile/openapi/lib/model/colorspace.dart index e0c1658be..e871e140f 100644 Binary files a/mobile/openapi/lib/model/colorspace.dart and b/mobile/openapi/lib/model/colorspace.dart differ diff --git a/mobile/openapi/lib/model/contributor_count_response_dto.dart b/mobile/openapi/lib/model/contributor_count_response_dto.dart index e0e16ee42..1bef8f29d 100644 Binary files a/mobile/openapi/lib/model/contributor_count_response_dto.dart and b/mobile/openapi/lib/model/contributor_count_response_dto.dart differ diff --git a/mobile/openapi/lib/model/cq_mode.dart b/mobile/openapi/lib/model/cq_mode.dart index f660fabf1..efd788b5f 100644 Binary files a/mobile/openapi/lib/model/cq_mode.dart and b/mobile/openapi/lib/model/cq_mode.dart differ diff --git a/mobile/openapi/lib/model/create_album_dto.dart b/mobile/openapi/lib/model/create_album_dto.dart index ff8c1df64..183a41c77 100644 Binary files a/mobile/openapi/lib/model/create_album_dto.dart and b/mobile/openapi/lib/model/create_album_dto.dart differ diff --git a/mobile/openapi/lib/model/create_library_dto.dart b/mobile/openapi/lib/model/create_library_dto.dart index 2b8085be6..69942fee5 100644 Binary files a/mobile/openapi/lib/model/create_library_dto.dart and b/mobile/openapi/lib/model/create_library_dto.dart differ diff --git a/mobile/openapi/lib/model/create_profile_image_response_dto.dart b/mobile/openapi/lib/model/create_profile_image_response_dto.dart index ee98142e8..20d7cbd5e 100644 Binary files a/mobile/openapi/lib/model/create_profile_image_response_dto.dart and b/mobile/openapi/lib/model/create_profile_image_response_dto.dart differ diff --git a/mobile/openapi/lib/model/database_backup_config.dart b/mobile/openapi/lib/model/database_backup_config.dart index d82128bd4..419968c3f 100644 Binary files a/mobile/openapi/lib/model/database_backup_config.dart and b/mobile/openapi/lib/model/database_backup_config.dart differ diff --git a/mobile/openapi/lib/model/download_archive_info.dart b/mobile/openapi/lib/model/download_archive_info.dart index 5f3fd1a8c..97a3346a6 100644 Binary files a/mobile/openapi/lib/model/download_archive_info.dart and b/mobile/openapi/lib/model/download_archive_info.dart differ diff --git a/mobile/openapi/lib/model/download_info_dto.dart b/mobile/openapi/lib/model/download_info_dto.dart index 6f4777975..a1ba44920 100644 Binary files a/mobile/openapi/lib/model/download_info_dto.dart and b/mobile/openapi/lib/model/download_info_dto.dart differ diff --git a/mobile/openapi/lib/model/download_response.dart b/mobile/openapi/lib/model/download_response.dart index 041da44b7..32e948747 100644 Binary files a/mobile/openapi/lib/model/download_response.dart and b/mobile/openapi/lib/model/download_response.dart differ diff --git a/mobile/openapi/lib/model/download_response_dto.dart b/mobile/openapi/lib/model/download_response_dto.dart index 5c6bd1126..81912e1d3 100644 Binary files a/mobile/openapi/lib/model/download_response_dto.dart and b/mobile/openapi/lib/model/download_response_dto.dart differ diff --git a/mobile/openapi/lib/model/download_update.dart b/mobile/openapi/lib/model/download_update.dart index 8df825a92..4acc1c8bd 100644 Binary files a/mobile/openapi/lib/model/download_update.dart and b/mobile/openapi/lib/model/download_update.dart differ diff --git a/mobile/openapi/lib/model/duplicate_detection_config.dart b/mobile/openapi/lib/model/duplicate_detection_config.dart index e4fc35202..43233826e 100644 Binary files a/mobile/openapi/lib/model/duplicate_detection_config.dart and b/mobile/openapi/lib/model/duplicate_detection_config.dart differ diff --git a/mobile/openapi/lib/model/duplicate_response_dto.dart b/mobile/openapi/lib/model/duplicate_response_dto.dart index 6ac7c4687..6c85dc801 100644 Binary files a/mobile/openapi/lib/model/duplicate_response_dto.dart and b/mobile/openapi/lib/model/duplicate_response_dto.dart differ diff --git a/mobile/openapi/lib/model/email_notifications_response.dart b/mobile/openapi/lib/model/email_notifications_response.dart index d6dcfb927..08a3d580c 100644 Binary files a/mobile/openapi/lib/model/email_notifications_response.dart and b/mobile/openapi/lib/model/email_notifications_response.dart differ diff --git a/mobile/openapi/lib/model/email_notifications_update.dart b/mobile/openapi/lib/model/email_notifications_update.dart index dad0a52fd..e158e4559 100644 Binary files a/mobile/openapi/lib/model/email_notifications_update.dart and b/mobile/openapi/lib/model/email_notifications_update.dart differ diff --git a/mobile/openapi/lib/model/exif_response_dto.dart b/mobile/openapi/lib/model/exif_response_dto.dart index 17397b208..6bb58a8ab 100644 Binary files a/mobile/openapi/lib/model/exif_response_dto.dart and b/mobile/openapi/lib/model/exif_response_dto.dart differ diff --git a/mobile/openapi/lib/model/face_dto.dart b/mobile/openapi/lib/model/face_dto.dart index c84a518b8..ec5f5c8a6 100644 Binary files a/mobile/openapi/lib/model/face_dto.dart and b/mobile/openapi/lib/model/face_dto.dart differ diff --git a/mobile/openapi/lib/model/facial_recognition_config.dart b/mobile/openapi/lib/model/facial_recognition_config.dart index 439efbbfa..4b9d7a6e9 100644 Binary files a/mobile/openapi/lib/model/facial_recognition_config.dart and b/mobile/openapi/lib/model/facial_recognition_config.dart differ diff --git a/mobile/openapi/lib/model/folders_response.dart b/mobile/openapi/lib/model/folders_response.dart index 248b64b05..906a95a83 100644 Binary files a/mobile/openapi/lib/model/folders_response.dart and b/mobile/openapi/lib/model/folders_response.dart differ diff --git a/mobile/openapi/lib/model/folders_update.dart b/mobile/openapi/lib/model/folders_update.dart index 023471775..edd58014d 100644 Binary files a/mobile/openapi/lib/model/folders_update.dart and b/mobile/openapi/lib/model/folders_update.dart differ diff --git a/mobile/openapi/lib/model/image_format.dart b/mobile/openapi/lib/model/image_format.dart index 479b519e2..1a0dde5de 100644 Binary files a/mobile/openapi/lib/model/image_format.dart and b/mobile/openapi/lib/model/image_format.dart differ diff --git a/mobile/openapi/lib/model/job_create_dto.dart b/mobile/openapi/lib/model/job_create_dto.dart index fe6743cba..3a3412384 100644 Binary files a/mobile/openapi/lib/model/job_create_dto.dart and b/mobile/openapi/lib/model/job_create_dto.dart differ diff --git a/mobile/openapi/lib/model/job_name.dart b/mobile/openapi/lib/model/job_name.dart index b027c9211..96b9339b7 100644 Binary files a/mobile/openapi/lib/model/job_name.dart and b/mobile/openapi/lib/model/job_name.dart differ diff --git a/mobile/openapi/lib/model/job_settings_dto.dart b/mobile/openapi/lib/model/job_settings_dto.dart index af354bef9..73a0187dd 100644 Binary files a/mobile/openapi/lib/model/job_settings_dto.dart and b/mobile/openapi/lib/model/job_settings_dto.dart differ diff --git a/mobile/openapi/lib/model/library_response_dto.dart b/mobile/openapi/lib/model/library_response_dto.dart index 3cf124850..aa9158e59 100644 Binary files a/mobile/openapi/lib/model/library_response_dto.dart and b/mobile/openapi/lib/model/library_response_dto.dart differ diff --git a/mobile/openapi/lib/model/library_stats_response_dto.dart b/mobile/openapi/lib/model/library_stats_response_dto.dart index afe67da31..6eec3ae8d 100644 Binary files a/mobile/openapi/lib/model/library_stats_response_dto.dart and b/mobile/openapi/lib/model/library_stats_response_dto.dart differ diff --git a/mobile/openapi/lib/model/license_key_dto.dart b/mobile/openapi/lib/model/license_key_dto.dart index d27d579bb..ea1fee9d7 100644 Binary files a/mobile/openapi/lib/model/license_key_dto.dart and b/mobile/openapi/lib/model/license_key_dto.dart differ diff --git a/mobile/openapi/lib/model/license_response_dto.dart b/mobile/openapi/lib/model/license_response_dto.dart index 6d3009433..84ff72c1e 100644 Binary files a/mobile/openapi/lib/model/license_response_dto.dart and b/mobile/openapi/lib/model/license_response_dto.dart differ diff --git a/mobile/openapi/lib/model/login_credential_dto.dart b/mobile/openapi/lib/model/login_credential_dto.dart index 7e892ab5f..1fdfdc3d4 100644 Binary files a/mobile/openapi/lib/model/login_credential_dto.dart and b/mobile/openapi/lib/model/login_credential_dto.dart differ diff --git a/mobile/openapi/lib/model/login_response_dto.dart b/mobile/openapi/lib/model/login_response_dto.dart index 82a4f9b3e..c6938c239 100644 Binary files a/mobile/openapi/lib/model/login_response_dto.dart and b/mobile/openapi/lib/model/login_response_dto.dart differ diff --git a/mobile/openapi/lib/model/logout_response_dto.dart b/mobile/openapi/lib/model/logout_response_dto.dart index aa94904e2..b50db2c28 100644 Binary files a/mobile/openapi/lib/model/logout_response_dto.dart and b/mobile/openapi/lib/model/logout_response_dto.dart differ diff --git a/mobile/openapi/lib/model/machine_learning_availability_checks_dto.dart b/mobile/openapi/lib/model/machine_learning_availability_checks_dto.dart index 84b318142..dc0cf5fac 100644 Binary files a/mobile/openapi/lib/model/machine_learning_availability_checks_dto.dart and b/mobile/openapi/lib/model/machine_learning_availability_checks_dto.dart differ diff --git a/mobile/openapi/lib/model/maintenance_action.dart b/mobile/openapi/lib/model/maintenance_action.dart index 59cfd0b21..ebf5ec0f7 100644 Binary files a/mobile/openapi/lib/model/maintenance_action.dart and b/mobile/openapi/lib/model/maintenance_action.dart differ diff --git a/mobile/openapi/lib/model/maintenance_auth_dto.dart b/mobile/openapi/lib/model/maintenance_auth_dto.dart index 919da5502..f9511bdd2 100644 Binary files a/mobile/openapi/lib/model/maintenance_auth_dto.dart and b/mobile/openapi/lib/model/maintenance_auth_dto.dart differ diff --git a/mobile/openapi/lib/model/maintenance_detect_install_storage_folder_dto.dart b/mobile/openapi/lib/model/maintenance_detect_install_storage_folder_dto.dart index e2a1e35de..ad524914b 100644 Binary files a/mobile/openapi/lib/model/maintenance_detect_install_storage_folder_dto.dart and b/mobile/openapi/lib/model/maintenance_detect_install_storage_folder_dto.dart differ diff --git a/mobile/openapi/lib/model/maintenance_login_dto.dart b/mobile/openapi/lib/model/maintenance_login_dto.dart index 45f56bd3b..64cf6b234 100644 Binary files a/mobile/openapi/lib/model/maintenance_login_dto.dart and b/mobile/openapi/lib/model/maintenance_login_dto.dart differ diff --git a/mobile/openapi/lib/model/maintenance_status_response_dto.dart b/mobile/openapi/lib/model/maintenance_status_response_dto.dart index 124fa674f..52dbb5b95 100644 Binary files a/mobile/openapi/lib/model/maintenance_status_response_dto.dart and b/mobile/openapi/lib/model/maintenance_status_response_dto.dart differ diff --git a/mobile/openapi/lib/model/manual_job_name.dart b/mobile/openapi/lib/model/manual_job_name.dart index 311215ad9..d09790a81 100644 Binary files a/mobile/openapi/lib/model/manual_job_name.dart and b/mobile/openapi/lib/model/manual_job_name.dart differ diff --git a/mobile/openapi/lib/model/map_marker_response_dto.dart b/mobile/openapi/lib/model/map_marker_response_dto.dart index 74ac51a27..c0a47a545 100644 Binary files a/mobile/openapi/lib/model/map_marker_response_dto.dart and b/mobile/openapi/lib/model/map_marker_response_dto.dart differ diff --git a/mobile/openapi/lib/model/map_reverse_geocode_response_dto.dart b/mobile/openapi/lib/model/map_reverse_geocode_response_dto.dart index 6d8757d39..85435485e 100644 Binary files a/mobile/openapi/lib/model/map_reverse_geocode_response_dto.dart and b/mobile/openapi/lib/model/map_reverse_geocode_response_dto.dart differ diff --git a/mobile/openapi/lib/model/memories_response.dart b/mobile/openapi/lib/model/memories_response.dart index cb42f596a..63d4094cd 100644 Binary files a/mobile/openapi/lib/model/memories_response.dart and b/mobile/openapi/lib/model/memories_response.dart differ diff --git a/mobile/openapi/lib/model/memories_update.dart b/mobile/openapi/lib/model/memories_update.dart index 39c46ffd2..d27cef022 100644 Binary files a/mobile/openapi/lib/model/memories_update.dart and b/mobile/openapi/lib/model/memories_update.dart differ diff --git a/mobile/openapi/lib/model/memory_create_dto.dart b/mobile/openapi/lib/model/memory_create_dto.dart index 15985f2f1..7fd938b31 100644 Binary files a/mobile/openapi/lib/model/memory_create_dto.dart and b/mobile/openapi/lib/model/memory_create_dto.dart differ diff --git a/mobile/openapi/lib/model/memory_response_dto.dart b/mobile/openapi/lib/model/memory_response_dto.dart index 7d50259e2..1835095cf 100644 Binary files a/mobile/openapi/lib/model/memory_response_dto.dart and b/mobile/openapi/lib/model/memory_response_dto.dart differ diff --git a/mobile/openapi/lib/model/memory_statistics_response_dto.dart b/mobile/openapi/lib/model/memory_statistics_response_dto.dart index a9a10ad32..bde78de48 100644 Binary files a/mobile/openapi/lib/model/memory_statistics_response_dto.dart and b/mobile/openapi/lib/model/memory_statistics_response_dto.dart differ diff --git a/mobile/openapi/lib/model/memory_update_dto.dart b/mobile/openapi/lib/model/memory_update_dto.dart index e750f9faa..4905b161b 100644 Binary files a/mobile/openapi/lib/model/memory_update_dto.dart and b/mobile/openapi/lib/model/memory_update_dto.dart differ diff --git a/mobile/openapi/lib/model/merge_person_dto.dart b/mobile/openapi/lib/model/merge_person_dto.dart index fd225276b..8a647890c 100644 Binary files a/mobile/openapi/lib/model/merge_person_dto.dart and b/mobile/openapi/lib/model/merge_person_dto.dart differ diff --git a/mobile/openapi/lib/model/metadata_search_dto.dart b/mobile/openapi/lib/model/metadata_search_dto.dart index 7d8d2b131..4a7ca403a 100644 Binary files a/mobile/openapi/lib/model/metadata_search_dto.dart and b/mobile/openapi/lib/model/metadata_search_dto.dart differ diff --git a/mobile/openapi/lib/model/notification_create_dto.dart b/mobile/openapi/lib/model/notification_create_dto.dart index 07985353b..1288da867 100644 Binary files a/mobile/openapi/lib/model/notification_create_dto.dart and b/mobile/openapi/lib/model/notification_create_dto.dart differ diff --git a/mobile/openapi/lib/model/notification_delete_all_dto.dart b/mobile/openapi/lib/model/notification_delete_all_dto.dart index 4be1b89e9..1b398a4f3 100644 Binary files a/mobile/openapi/lib/model/notification_delete_all_dto.dart and b/mobile/openapi/lib/model/notification_delete_all_dto.dart differ diff --git a/mobile/openapi/lib/model/notification_dto.dart b/mobile/openapi/lib/model/notification_dto.dart index 4f730b4e5..30d43de11 100644 Binary files a/mobile/openapi/lib/model/notification_dto.dart and b/mobile/openapi/lib/model/notification_dto.dart differ diff --git a/mobile/openapi/lib/model/notification_update_all_dto.dart b/mobile/openapi/lib/model/notification_update_all_dto.dart index a6393b275..a15705832 100644 Binary files a/mobile/openapi/lib/model/notification_update_all_dto.dart and b/mobile/openapi/lib/model/notification_update_all_dto.dart differ diff --git a/mobile/openapi/lib/model/notification_update_dto.dart b/mobile/openapi/lib/model/notification_update_dto.dart index e76496eb9..eddf9c7e1 100644 Binary files a/mobile/openapi/lib/model/notification_update_dto.dart and b/mobile/openapi/lib/model/notification_update_dto.dart differ diff --git a/mobile/openapi/lib/model/o_auth_authorize_response_dto.dart b/mobile/openapi/lib/model/o_auth_authorize_response_dto.dart index 869c3be75..7eedc4567 100644 Binary files a/mobile/openapi/lib/model/o_auth_authorize_response_dto.dart and b/mobile/openapi/lib/model/o_auth_authorize_response_dto.dart differ diff --git a/mobile/openapi/lib/model/o_auth_callback_dto.dart b/mobile/openapi/lib/model/o_auth_callback_dto.dart index ea8cac31a..d94374935 100644 Binary files a/mobile/openapi/lib/model/o_auth_callback_dto.dart and b/mobile/openapi/lib/model/o_auth_callback_dto.dart differ diff --git a/mobile/openapi/lib/model/o_auth_config_dto.dart b/mobile/openapi/lib/model/o_auth_config_dto.dart index bb3e8d448..1c9ce8d5b 100644 Binary files a/mobile/openapi/lib/model/o_auth_config_dto.dart and b/mobile/openapi/lib/model/o_auth_config_dto.dart differ diff --git a/mobile/openapi/lib/model/o_auth_token_endpoint_auth_method.dart b/mobile/openapi/lib/model/o_auth_token_endpoint_auth_method.dart index fc528888b..77466d61d 100644 Binary files a/mobile/openapi/lib/model/o_auth_token_endpoint_auth_method.dart and b/mobile/openapi/lib/model/o_auth_token_endpoint_auth_method.dart differ diff --git a/mobile/openapi/lib/model/ocr_config.dart b/mobile/openapi/lib/model/ocr_config.dart index 51746c492..d97cd5ffc 100644 Binary files a/mobile/openapi/lib/model/ocr_config.dart and b/mobile/openapi/lib/model/ocr_config.dart differ diff --git a/mobile/openapi/lib/model/on_this_day_dto.dart b/mobile/openapi/lib/model/on_this_day_dto.dart index bfcc4fd63..93ec956f5 100644 Binary files a/mobile/openapi/lib/model/on_this_day_dto.dart and b/mobile/openapi/lib/model/on_this_day_dto.dart differ diff --git a/mobile/openapi/lib/model/onboarding_dto.dart b/mobile/openapi/lib/model/onboarding_dto.dart index 670b6a5c6..8499bc9b9 100644 Binary files a/mobile/openapi/lib/model/onboarding_dto.dart and b/mobile/openapi/lib/model/onboarding_dto.dart differ diff --git a/mobile/openapi/lib/model/onboarding_response_dto.dart b/mobile/openapi/lib/model/onboarding_response_dto.dart index 033466e96..2b0dbe2b9 100644 Binary files a/mobile/openapi/lib/model/onboarding_response_dto.dart and b/mobile/openapi/lib/model/onboarding_response_dto.dart differ diff --git a/mobile/openapi/lib/model/partner_create_dto.dart b/mobile/openapi/lib/model/partner_create_dto.dart index 09d60c5c7..30aa96ff3 100644 Binary files a/mobile/openapi/lib/model/partner_create_dto.dart and b/mobile/openapi/lib/model/partner_create_dto.dart differ diff --git a/mobile/openapi/lib/model/partner_response_dto.dart b/mobile/openapi/lib/model/partner_response_dto.dart index f61df86b4..5789938d1 100644 Binary files a/mobile/openapi/lib/model/partner_response_dto.dart and b/mobile/openapi/lib/model/partner_response_dto.dart differ diff --git a/mobile/openapi/lib/model/partner_update_dto.dart b/mobile/openapi/lib/model/partner_update_dto.dart index 25cf21776..db3516e3a 100644 Binary files a/mobile/openapi/lib/model/partner_update_dto.dart and b/mobile/openapi/lib/model/partner_update_dto.dart differ diff --git a/mobile/openapi/lib/model/people_response.dart b/mobile/openapi/lib/model/people_response.dart index 1312c7387..c09560e08 100644 Binary files a/mobile/openapi/lib/model/people_response.dart and b/mobile/openapi/lib/model/people_response.dart differ diff --git a/mobile/openapi/lib/model/people_response_dto.dart b/mobile/openapi/lib/model/people_response_dto.dart index 901c38ade..f345657e7 100644 Binary files a/mobile/openapi/lib/model/people_response_dto.dart and b/mobile/openapi/lib/model/people_response_dto.dart differ diff --git a/mobile/openapi/lib/model/people_update.dart b/mobile/openapi/lib/model/people_update.dart index fb4eeeb43..fe16479ba 100644 Binary files a/mobile/openapi/lib/model/people_update.dart and b/mobile/openapi/lib/model/people_update.dart differ diff --git a/mobile/openapi/lib/model/people_update_dto.dart b/mobile/openapi/lib/model/people_update_dto.dart index f771084f7..c9ce74d65 100644 Binary files a/mobile/openapi/lib/model/people_update_dto.dart and b/mobile/openapi/lib/model/people_update_dto.dart differ diff --git a/mobile/openapi/lib/model/people_update_item.dart b/mobile/openapi/lib/model/people_update_item.dart index ce324b859..5e20aeb46 100644 Binary files a/mobile/openapi/lib/model/people_update_item.dart and b/mobile/openapi/lib/model/people_update_item.dart differ diff --git a/mobile/openapi/lib/model/permission.dart b/mobile/openapi/lib/model/permission.dart index 01bb68953..9092ede78 100644 Binary files a/mobile/openapi/lib/model/permission.dart and b/mobile/openapi/lib/model/permission.dart differ diff --git a/mobile/openapi/lib/model/person_create_dto.dart b/mobile/openapi/lib/model/person_create_dto.dart index 87b426eae..f2ba702c2 100644 Binary files a/mobile/openapi/lib/model/person_create_dto.dart and b/mobile/openapi/lib/model/person_create_dto.dart differ diff --git a/mobile/openapi/lib/model/person_response_dto.dart b/mobile/openapi/lib/model/person_response_dto.dart index a6ad5e0c2..455dfb98d 100644 Binary files a/mobile/openapi/lib/model/person_response_dto.dart and b/mobile/openapi/lib/model/person_response_dto.dart differ diff --git a/mobile/openapi/lib/model/person_statistics_response_dto.dart b/mobile/openapi/lib/model/person_statistics_response_dto.dart index d9f84e9f4..d2b45c8cc 100644 Binary files a/mobile/openapi/lib/model/person_statistics_response_dto.dart and b/mobile/openapi/lib/model/person_statistics_response_dto.dart differ diff --git a/mobile/openapi/lib/model/person_update_dto.dart b/mobile/openapi/lib/model/person_update_dto.dart index 6736b4e17..b56940e51 100644 Binary files a/mobile/openapi/lib/model/person_update_dto.dart and b/mobile/openapi/lib/model/person_update_dto.dart differ diff --git a/mobile/openapi/lib/model/person_with_faces_response_dto.dart b/mobile/openapi/lib/model/person_with_faces_response_dto.dart index 9b2e40cf5..f31c04b69 100644 Binary files a/mobile/openapi/lib/model/person_with_faces_response_dto.dart and b/mobile/openapi/lib/model/person_with_faces_response_dto.dart differ diff --git a/mobile/openapi/lib/model/pin_code_change_dto.dart b/mobile/openapi/lib/model/pin_code_change_dto.dart index 2e9967aa6..068cc9e91 100644 Binary files a/mobile/openapi/lib/model/pin_code_change_dto.dart and b/mobile/openapi/lib/model/pin_code_change_dto.dart differ diff --git a/mobile/openapi/lib/model/pin_code_reset_dto.dart b/mobile/openapi/lib/model/pin_code_reset_dto.dart index 358534867..c37be76f1 100644 Binary files a/mobile/openapi/lib/model/pin_code_reset_dto.dart and b/mobile/openapi/lib/model/pin_code_reset_dto.dart differ diff --git a/mobile/openapi/lib/model/pin_code_setup_dto.dart b/mobile/openapi/lib/model/pin_code_setup_dto.dart index 09933790d..e2f08f102 100644 Binary files a/mobile/openapi/lib/model/pin_code_setup_dto.dart and b/mobile/openapi/lib/model/pin_code_setup_dto.dart differ diff --git a/mobile/openapi/lib/model/places_response_dto.dart b/mobile/openapi/lib/model/places_response_dto.dart index 4f7778826..94aa58eba 100644 Binary files a/mobile/openapi/lib/model/places_response_dto.dart and b/mobile/openapi/lib/model/places_response_dto.dart differ diff --git a/mobile/openapi/lib/model/plugin_action_response_dto.dart b/mobile/openapi/lib/model/plugin_action_response_dto.dart index 5ba54f6eb..34fa314ba 100644 Binary files a/mobile/openapi/lib/model/plugin_action_response_dto.dart and b/mobile/openapi/lib/model/plugin_action_response_dto.dart differ diff --git a/mobile/openapi/lib/model/plugin_context_type.dart b/mobile/openapi/lib/model/plugin_context_type.dart index 797d2c3d3..6f4ac91fd 100644 Binary files a/mobile/openapi/lib/model/plugin_context_type.dart and b/mobile/openapi/lib/model/plugin_context_type.dart differ diff --git a/mobile/openapi/lib/model/plugin_filter_response_dto.dart b/mobile/openapi/lib/model/plugin_filter_response_dto.dart index 5873d72f0..ea6411a9c 100644 Binary files a/mobile/openapi/lib/model/plugin_filter_response_dto.dart and b/mobile/openapi/lib/model/plugin_filter_response_dto.dart differ diff --git a/mobile/openapi/lib/model/plugin_response_dto.dart b/mobile/openapi/lib/model/plugin_response_dto.dart index afa6f3e1a..7a9989647 100644 Binary files a/mobile/openapi/lib/model/plugin_response_dto.dart and b/mobile/openapi/lib/model/plugin_response_dto.dart differ diff --git a/mobile/openapi/lib/model/plugin_trigger_response_dto.dart b/mobile/openapi/lib/model/plugin_trigger_response_dto.dart index a6ee1c6b6..16a9604bc 100644 Binary files a/mobile/openapi/lib/model/plugin_trigger_response_dto.dart and b/mobile/openapi/lib/model/plugin_trigger_response_dto.dart differ diff --git a/mobile/openapi/lib/model/plugin_trigger_type.dart b/mobile/openapi/lib/model/plugin_trigger_type.dart index b200f1b9e..9ae64acf6 100644 Binary files a/mobile/openapi/lib/model/plugin_trigger_type.dart and b/mobile/openapi/lib/model/plugin_trigger_type.dart differ diff --git a/mobile/openapi/lib/model/purchase_response.dart b/mobile/openapi/lib/model/purchase_response.dart index a11720697..e55c28662 100644 Binary files a/mobile/openapi/lib/model/purchase_response.dart and b/mobile/openapi/lib/model/purchase_response.dart differ diff --git a/mobile/openapi/lib/model/purchase_update.dart b/mobile/openapi/lib/model/purchase_update.dart index 69057e6c5..913faf9bc 100644 Binary files a/mobile/openapi/lib/model/purchase_update.dart and b/mobile/openapi/lib/model/purchase_update.dart differ diff --git a/mobile/openapi/lib/model/queue_command.dart b/mobile/openapi/lib/model/queue_command.dart index f03ec6ecc..3cf689a02 100644 Binary files a/mobile/openapi/lib/model/queue_command.dart and b/mobile/openapi/lib/model/queue_command.dart differ diff --git a/mobile/openapi/lib/model/queue_command_dto.dart b/mobile/openapi/lib/model/queue_command_dto.dart index ded848c12..9e1eea15d 100644 Binary files a/mobile/openapi/lib/model/queue_command_dto.dart and b/mobile/openapi/lib/model/queue_command_dto.dart differ diff --git a/mobile/openapi/lib/model/queue_job_response_dto.dart b/mobile/openapi/lib/model/queue_job_response_dto.dart index 1bfaa5619..2ce63784e 100644 Binary files a/mobile/openapi/lib/model/queue_job_response_dto.dart and b/mobile/openapi/lib/model/queue_job_response_dto.dart differ diff --git a/mobile/openapi/lib/model/queue_response_dto.dart b/mobile/openapi/lib/model/queue_response_dto.dart index c5d4ed8e3..ac9244514 100644 Binary files a/mobile/openapi/lib/model/queue_response_dto.dart and b/mobile/openapi/lib/model/queue_response_dto.dart differ diff --git a/mobile/openapi/lib/model/queue_statistics_dto.dart b/mobile/openapi/lib/model/queue_statistics_dto.dart index c27c4a589..c9a37ee30 100644 Binary files a/mobile/openapi/lib/model/queue_statistics_dto.dart and b/mobile/openapi/lib/model/queue_statistics_dto.dart differ diff --git a/mobile/openapi/lib/model/queue_status_legacy_dto.dart b/mobile/openapi/lib/model/queue_status_legacy_dto.dart index 88c4eac34..de6ce6331 100644 Binary files a/mobile/openapi/lib/model/queue_status_legacy_dto.dart and b/mobile/openapi/lib/model/queue_status_legacy_dto.dart differ diff --git a/mobile/openapi/lib/model/queue_update_dto.dart b/mobile/openapi/lib/model/queue_update_dto.dart index ce89e5187..28aafe95f 100644 Binary files a/mobile/openapi/lib/model/queue_update_dto.dart and b/mobile/openapi/lib/model/queue_update_dto.dart differ diff --git a/mobile/openapi/lib/model/random_search_dto.dart b/mobile/openapi/lib/model/random_search_dto.dart index 96d670fd9..7e0fb0c5c 100644 Binary files a/mobile/openapi/lib/model/random_search_dto.dart and b/mobile/openapi/lib/model/random_search_dto.dart differ diff --git a/mobile/openapi/lib/model/ratings_response.dart b/mobile/openapi/lib/model/ratings_response.dart index 8e1951277..4346fa5c5 100644 Binary files a/mobile/openapi/lib/model/ratings_response.dart and b/mobile/openapi/lib/model/ratings_response.dart differ diff --git a/mobile/openapi/lib/model/ratings_update.dart b/mobile/openapi/lib/model/ratings_update.dart index 5d9f9a655..8079172e2 100644 Binary files a/mobile/openapi/lib/model/ratings_update.dart and b/mobile/openapi/lib/model/ratings_update.dart differ diff --git a/mobile/openapi/lib/model/reverse_geocoding_state_response_dto.dart b/mobile/openapi/lib/model/reverse_geocoding_state_response_dto.dart index 5b3648b46..6ad8c1a7b 100644 Binary files a/mobile/openapi/lib/model/reverse_geocoding_state_response_dto.dart and b/mobile/openapi/lib/model/reverse_geocoding_state_response_dto.dart differ diff --git a/mobile/openapi/lib/model/search_album_response_dto.dart b/mobile/openapi/lib/model/search_album_response_dto.dart index e9b47e85e..8841251e4 100644 Binary files a/mobile/openapi/lib/model/search_album_response_dto.dart and b/mobile/openapi/lib/model/search_album_response_dto.dart differ diff --git a/mobile/openapi/lib/model/search_asset_response_dto.dart b/mobile/openapi/lib/model/search_asset_response_dto.dart index 3d214e61d..acb81f28e 100644 Binary files a/mobile/openapi/lib/model/search_asset_response_dto.dart and b/mobile/openapi/lib/model/search_asset_response_dto.dart differ diff --git a/mobile/openapi/lib/model/search_explore_item.dart b/mobile/openapi/lib/model/search_explore_item.dart index d44b2cd70..408901187 100644 Binary files a/mobile/openapi/lib/model/search_explore_item.dart and b/mobile/openapi/lib/model/search_explore_item.dart differ diff --git a/mobile/openapi/lib/model/search_explore_response_dto.dart b/mobile/openapi/lib/model/search_explore_response_dto.dart index 3b5d4f984..07ce26c9b 100644 Binary files a/mobile/openapi/lib/model/search_explore_response_dto.dart and b/mobile/openapi/lib/model/search_explore_response_dto.dart differ diff --git a/mobile/openapi/lib/model/search_facet_count_response_dto.dart b/mobile/openapi/lib/model/search_facet_count_response_dto.dart index f8eee8448..8318fbfb3 100644 Binary files a/mobile/openapi/lib/model/search_facet_count_response_dto.dart and b/mobile/openapi/lib/model/search_facet_count_response_dto.dart differ diff --git a/mobile/openapi/lib/model/search_facet_response_dto.dart b/mobile/openapi/lib/model/search_facet_response_dto.dart index aeec873c8..43b5ac5c8 100644 Binary files a/mobile/openapi/lib/model/search_facet_response_dto.dart and b/mobile/openapi/lib/model/search_facet_response_dto.dart differ diff --git a/mobile/openapi/lib/model/search_statistics_response_dto.dart b/mobile/openapi/lib/model/search_statistics_response_dto.dart index 84f31373d..5aebe4d6a 100644 Binary files a/mobile/openapi/lib/model/search_statistics_response_dto.dart and b/mobile/openapi/lib/model/search_statistics_response_dto.dart differ diff --git a/mobile/openapi/lib/model/server_about_response_dto.dart b/mobile/openapi/lib/model/server_about_response_dto.dart index 5d53d5fde..1ae53763f 100644 Binary files a/mobile/openapi/lib/model/server_about_response_dto.dart and b/mobile/openapi/lib/model/server_about_response_dto.dart differ diff --git a/mobile/openapi/lib/model/server_apk_links_dto.dart b/mobile/openapi/lib/model/server_apk_links_dto.dart index 086a2f172..222701846 100644 Binary files a/mobile/openapi/lib/model/server_apk_links_dto.dart and b/mobile/openapi/lib/model/server_apk_links_dto.dart differ diff --git a/mobile/openapi/lib/model/server_config_dto.dart b/mobile/openapi/lib/model/server_config_dto.dart index 8e701472b..fec096d51 100644 Binary files a/mobile/openapi/lib/model/server_config_dto.dart and b/mobile/openapi/lib/model/server_config_dto.dart differ diff --git a/mobile/openapi/lib/model/server_features_dto.dart b/mobile/openapi/lib/model/server_features_dto.dart index 7b5980ca1..79494b74e 100644 Binary files a/mobile/openapi/lib/model/server_features_dto.dart and b/mobile/openapi/lib/model/server_features_dto.dart differ diff --git a/mobile/openapi/lib/model/server_media_types_response_dto.dart b/mobile/openapi/lib/model/server_media_types_response_dto.dart index 506cbb44b..6a2aaeb9e 100644 Binary files a/mobile/openapi/lib/model/server_media_types_response_dto.dart and b/mobile/openapi/lib/model/server_media_types_response_dto.dart differ diff --git a/mobile/openapi/lib/model/server_stats_response_dto.dart b/mobile/openapi/lib/model/server_stats_response_dto.dart index 531fa8f03..ef2fa458e 100644 Binary files a/mobile/openapi/lib/model/server_stats_response_dto.dart and b/mobile/openapi/lib/model/server_stats_response_dto.dart differ diff --git a/mobile/openapi/lib/model/server_storage_response_dto.dart b/mobile/openapi/lib/model/server_storage_response_dto.dart index 8d12e7783..476b048b4 100644 Binary files a/mobile/openapi/lib/model/server_storage_response_dto.dart and b/mobile/openapi/lib/model/server_storage_response_dto.dart differ diff --git a/mobile/openapi/lib/model/server_theme_dto.dart b/mobile/openapi/lib/model/server_theme_dto.dart index 69e1b2d2c..957cf84d5 100644 Binary files a/mobile/openapi/lib/model/server_theme_dto.dart and b/mobile/openapi/lib/model/server_theme_dto.dart differ diff --git a/mobile/openapi/lib/model/server_version_history_response_dto.dart b/mobile/openapi/lib/model/server_version_history_response_dto.dart index c81cb0e8b..c3b704901 100644 Binary files a/mobile/openapi/lib/model/server_version_history_response_dto.dart and b/mobile/openapi/lib/model/server_version_history_response_dto.dart differ diff --git a/mobile/openapi/lib/model/server_version_response_dto.dart b/mobile/openapi/lib/model/server_version_response_dto.dart index 751347fab..a13cd81ad 100644 Binary files a/mobile/openapi/lib/model/server_version_response_dto.dart and b/mobile/openapi/lib/model/server_version_response_dto.dart differ diff --git a/mobile/openapi/lib/model/session_create_dto.dart b/mobile/openapi/lib/model/session_create_dto.dart index aacf1150a..3874bc330 100644 Binary files a/mobile/openapi/lib/model/session_create_dto.dart and b/mobile/openapi/lib/model/session_create_dto.dart differ diff --git a/mobile/openapi/lib/model/session_create_response_dto.dart b/mobile/openapi/lib/model/session_create_response_dto.dart index e16597f3b..f35232b0e 100644 Binary files a/mobile/openapi/lib/model/session_create_response_dto.dart and b/mobile/openapi/lib/model/session_create_response_dto.dart differ diff --git a/mobile/openapi/lib/model/session_response_dto.dart b/mobile/openapi/lib/model/session_response_dto.dart index 85acb8a35..ed8416082 100644 Binary files a/mobile/openapi/lib/model/session_response_dto.dart and b/mobile/openapi/lib/model/session_response_dto.dart differ diff --git a/mobile/openapi/lib/model/session_unlock_dto.dart b/mobile/openapi/lib/model/session_unlock_dto.dart index 4cfeb1438..48ee75fb0 100644 Binary files a/mobile/openapi/lib/model/session_unlock_dto.dart and b/mobile/openapi/lib/model/session_unlock_dto.dart differ diff --git a/mobile/openapi/lib/model/session_update_dto.dart b/mobile/openapi/lib/model/session_update_dto.dart index cd170b1ba..3ab430dea 100644 Binary files a/mobile/openapi/lib/model/session_update_dto.dart and b/mobile/openapi/lib/model/session_update_dto.dart differ diff --git a/mobile/openapi/lib/model/set_maintenance_mode_dto.dart b/mobile/openapi/lib/model/set_maintenance_mode_dto.dart index d2fe900d4..14bf584bb 100644 Binary files a/mobile/openapi/lib/model/set_maintenance_mode_dto.dart and b/mobile/openapi/lib/model/set_maintenance_mode_dto.dart differ diff --git a/mobile/openapi/lib/model/shared_link_create_dto.dart b/mobile/openapi/lib/model/shared_link_create_dto.dart index 644227bd6..2675ad4be 100644 Binary files a/mobile/openapi/lib/model/shared_link_create_dto.dart and b/mobile/openapi/lib/model/shared_link_create_dto.dart differ diff --git a/mobile/openapi/lib/model/shared_link_edit_dto.dart b/mobile/openapi/lib/model/shared_link_edit_dto.dart index f13bc6977..b22232add 100644 Binary files a/mobile/openapi/lib/model/shared_link_edit_dto.dart and b/mobile/openapi/lib/model/shared_link_edit_dto.dart differ diff --git a/mobile/openapi/lib/model/shared_link_response_dto.dart b/mobile/openapi/lib/model/shared_link_response_dto.dart index d81e1dfa3..d9aec48c3 100644 Binary files a/mobile/openapi/lib/model/shared_link_response_dto.dart and b/mobile/openapi/lib/model/shared_link_response_dto.dart differ diff --git a/mobile/openapi/lib/model/shared_link_type.dart b/mobile/openapi/lib/model/shared_link_type.dart index efab97c20..6a17a9c76 100644 Binary files a/mobile/openapi/lib/model/shared_link_type.dart and b/mobile/openapi/lib/model/shared_link_type.dart differ diff --git a/mobile/openapi/lib/model/shared_links_response.dart b/mobile/openapi/lib/model/shared_links_response.dart index 80875e617..510e94e43 100644 Binary files a/mobile/openapi/lib/model/shared_links_response.dart and b/mobile/openapi/lib/model/shared_links_response.dart differ diff --git a/mobile/openapi/lib/model/shared_links_update.dart b/mobile/openapi/lib/model/shared_links_update.dart index 5d9eda300..8e792b4f4 100644 Binary files a/mobile/openapi/lib/model/shared_links_update.dart and b/mobile/openapi/lib/model/shared_links_update.dart differ diff --git a/mobile/openapi/lib/model/sign_up_dto.dart b/mobile/openapi/lib/model/sign_up_dto.dart index 7e0ff4045..54c8fa07d 100644 Binary files a/mobile/openapi/lib/model/sign_up_dto.dart and b/mobile/openapi/lib/model/sign_up_dto.dart differ diff --git a/mobile/openapi/lib/model/smart_search_dto.dart b/mobile/openapi/lib/model/smart_search_dto.dart index 24f040a92..7d43cea87 100644 Binary files a/mobile/openapi/lib/model/smart_search_dto.dart and b/mobile/openapi/lib/model/smart_search_dto.dart differ diff --git a/mobile/openapi/lib/model/source_type.dart b/mobile/openapi/lib/model/source_type.dart index 4da5aba49..ed164172a 100644 Binary files a/mobile/openapi/lib/model/source_type.dart and b/mobile/openapi/lib/model/source_type.dart differ diff --git a/mobile/openapi/lib/model/stack_create_dto.dart b/mobile/openapi/lib/model/stack_create_dto.dart index cb51081eb..6b08c8340 100644 Binary files a/mobile/openapi/lib/model/stack_create_dto.dart and b/mobile/openapi/lib/model/stack_create_dto.dart differ diff --git a/mobile/openapi/lib/model/stack_response_dto.dart b/mobile/openapi/lib/model/stack_response_dto.dart index b6cb747ca..638dfb525 100644 Binary files a/mobile/openapi/lib/model/stack_response_dto.dart and b/mobile/openapi/lib/model/stack_response_dto.dart differ diff --git a/mobile/openapi/lib/model/stack_update_dto.dart b/mobile/openapi/lib/model/stack_update_dto.dart index 0101499ed..e81c204f9 100644 Binary files a/mobile/openapi/lib/model/stack_update_dto.dart and b/mobile/openapi/lib/model/stack_update_dto.dart differ diff --git a/mobile/openapi/lib/model/statistics_search_dto.dart b/mobile/openapi/lib/model/statistics_search_dto.dart index e0965352e..fce2feb42 100644 Binary files a/mobile/openapi/lib/model/statistics_search_dto.dart and b/mobile/openapi/lib/model/statistics_search_dto.dart differ diff --git a/mobile/openapi/lib/model/storage_folder.dart b/mobile/openapi/lib/model/storage_folder.dart index df66bc187..8579d48f2 100644 Binary files a/mobile/openapi/lib/model/storage_folder.dart and b/mobile/openapi/lib/model/storage_folder.dart differ diff --git a/mobile/openapi/lib/model/sync_ack_delete_dto.dart b/mobile/openapi/lib/model/sync_ack_delete_dto.dart index 998f812f2..b72ae8c5a 100644 Binary files a/mobile/openapi/lib/model/sync_ack_delete_dto.dart and b/mobile/openapi/lib/model/sync_ack_delete_dto.dart differ diff --git a/mobile/openapi/lib/model/sync_ack_dto.dart b/mobile/openapi/lib/model/sync_ack_dto.dart index c7fafa17d..747f67155 100644 Binary files a/mobile/openapi/lib/model/sync_ack_dto.dart and b/mobile/openapi/lib/model/sync_ack_dto.dart differ diff --git a/mobile/openapi/lib/model/sync_ack_set_dto.dart b/mobile/openapi/lib/model/sync_ack_set_dto.dart index 0d9eedc38..531a9dc76 100644 Binary files a/mobile/openapi/lib/model/sync_ack_set_dto.dart and b/mobile/openapi/lib/model/sync_ack_set_dto.dart differ diff --git a/mobile/openapi/lib/model/sync_album_delete_v1.dart b/mobile/openapi/lib/model/sync_album_delete_v1.dart index ae5ba3da5..a6fdf5c68 100644 Binary files a/mobile/openapi/lib/model/sync_album_delete_v1.dart and b/mobile/openapi/lib/model/sync_album_delete_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_album_to_asset_delete_v1.dart b/mobile/openapi/lib/model/sync_album_to_asset_delete_v1.dart index d18c850b2..08952b90e 100644 Binary files a/mobile/openapi/lib/model/sync_album_to_asset_delete_v1.dart and b/mobile/openapi/lib/model/sync_album_to_asset_delete_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_album_to_asset_v1.dart b/mobile/openapi/lib/model/sync_album_to_asset_v1.dart index 6908f320f..5f38b3508 100644 Binary files a/mobile/openapi/lib/model/sync_album_to_asset_v1.dart and b/mobile/openapi/lib/model/sync_album_to_asset_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_album_user_delete_v1.dart b/mobile/openapi/lib/model/sync_album_user_delete_v1.dart index f2b0fbee2..526bcc6b6 100644 Binary files a/mobile/openapi/lib/model/sync_album_user_delete_v1.dart and b/mobile/openapi/lib/model/sync_album_user_delete_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_album_user_v1.dart b/mobile/openapi/lib/model/sync_album_user_v1.dart index 0b4968b34..3fc897206 100644 Binary files a/mobile/openapi/lib/model/sync_album_user_v1.dart and b/mobile/openapi/lib/model/sync_album_user_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_album_v1.dart b/mobile/openapi/lib/model/sync_album_v1.dart index 8ac8246d4..6c89d9372 100644 Binary files a/mobile/openapi/lib/model/sync_album_v1.dart and b/mobile/openapi/lib/model/sync_album_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_asset_delete_v1.dart b/mobile/openapi/lib/model/sync_asset_delete_v1.dart index c1787caf0..1d5a94777 100644 Binary files a/mobile/openapi/lib/model/sync_asset_delete_v1.dart and b/mobile/openapi/lib/model/sync_asset_delete_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_asset_exif_v1.dart b/mobile/openapi/lib/model/sync_asset_exif_v1.dart index d4fdc9249..ff9efdfea 100644 Binary files a/mobile/openapi/lib/model/sync_asset_exif_v1.dart and b/mobile/openapi/lib/model/sync_asset_exif_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_asset_face_delete_v1.dart b/mobile/openapi/lib/model/sync_asset_face_delete_v1.dart index 0992bfdcb..9cfb8814a 100644 Binary files a/mobile/openapi/lib/model/sync_asset_face_delete_v1.dart and b/mobile/openapi/lib/model/sync_asset_face_delete_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_asset_face_v1.dart b/mobile/openapi/lib/model/sync_asset_face_v1.dart index 60d1766e3..647a07d5e 100644 Binary files a/mobile/openapi/lib/model/sync_asset_face_v1.dart and b/mobile/openapi/lib/model/sync_asset_face_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_asset_metadata_delete_v1.dart b/mobile/openapi/lib/model/sync_asset_metadata_delete_v1.dart index cf67b68dd..326555ef1 100644 Binary files a/mobile/openapi/lib/model/sync_asset_metadata_delete_v1.dart and b/mobile/openapi/lib/model/sync_asset_metadata_delete_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_asset_metadata_v1.dart b/mobile/openapi/lib/model/sync_asset_metadata_v1.dart index 4fa6ed84e..4a6662393 100644 Binary files a/mobile/openapi/lib/model/sync_asset_metadata_v1.dart and b/mobile/openapi/lib/model/sync_asset_metadata_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_asset_v1.dart b/mobile/openapi/lib/model/sync_asset_v1.dart index 1d0e73539..debde4488 100644 Binary files a/mobile/openapi/lib/model/sync_asset_v1.dart and b/mobile/openapi/lib/model/sync_asset_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_auth_user_v1.dart b/mobile/openapi/lib/model/sync_auth_user_v1.dart index 1dab7f47e..0edd804c6 100644 Binary files a/mobile/openapi/lib/model/sync_auth_user_v1.dart and b/mobile/openapi/lib/model/sync_auth_user_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_entity_type.dart b/mobile/openapi/lib/model/sync_entity_type.dart index 1b4ca91f3..d1e321f39 100644 Binary files a/mobile/openapi/lib/model/sync_entity_type.dart and b/mobile/openapi/lib/model/sync_entity_type.dart differ diff --git a/mobile/openapi/lib/model/sync_memory_asset_delete_v1.dart b/mobile/openapi/lib/model/sync_memory_asset_delete_v1.dart index a9af77e92..c37682d02 100644 Binary files a/mobile/openapi/lib/model/sync_memory_asset_delete_v1.dart and b/mobile/openapi/lib/model/sync_memory_asset_delete_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_memory_asset_v1.dart b/mobile/openapi/lib/model/sync_memory_asset_v1.dart index d26e3c9a2..2cfab98af 100644 Binary files a/mobile/openapi/lib/model/sync_memory_asset_v1.dart and b/mobile/openapi/lib/model/sync_memory_asset_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_memory_delete_v1.dart b/mobile/openapi/lib/model/sync_memory_delete_v1.dart index 9702da5aa..d5f63ec8f 100644 Binary files a/mobile/openapi/lib/model/sync_memory_delete_v1.dart and b/mobile/openapi/lib/model/sync_memory_delete_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_memory_v1.dart b/mobile/openapi/lib/model/sync_memory_v1.dart index 2ae2b01fd..c506738d9 100644 Binary files a/mobile/openapi/lib/model/sync_memory_v1.dart and b/mobile/openapi/lib/model/sync_memory_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_partner_delete_v1.dart b/mobile/openapi/lib/model/sync_partner_delete_v1.dart index f5e10d657..64dfb4eb9 100644 Binary files a/mobile/openapi/lib/model/sync_partner_delete_v1.dart and b/mobile/openapi/lib/model/sync_partner_delete_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_partner_v1.dart b/mobile/openapi/lib/model/sync_partner_v1.dart index e551c4c83..9f9c3d14c 100644 Binary files a/mobile/openapi/lib/model/sync_partner_v1.dart and b/mobile/openapi/lib/model/sync_partner_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_person_delete_v1.dart b/mobile/openapi/lib/model/sync_person_delete_v1.dart index 002f5c5b8..526bc2618 100644 Binary files a/mobile/openapi/lib/model/sync_person_delete_v1.dart and b/mobile/openapi/lib/model/sync_person_delete_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_person_v1.dart b/mobile/openapi/lib/model/sync_person_v1.dart index 6749beb3e..fc2c36aa8 100644 Binary files a/mobile/openapi/lib/model/sync_person_v1.dart and b/mobile/openapi/lib/model/sync_person_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_request_type.dart b/mobile/openapi/lib/model/sync_request_type.dart index c3dc1c4d6..135af3c7b 100644 Binary files a/mobile/openapi/lib/model/sync_request_type.dart and b/mobile/openapi/lib/model/sync_request_type.dart differ diff --git a/mobile/openapi/lib/model/sync_stack_delete_v1.dart b/mobile/openapi/lib/model/sync_stack_delete_v1.dart index 22c6d99a5..2a7398291 100644 Binary files a/mobile/openapi/lib/model/sync_stack_delete_v1.dart and b/mobile/openapi/lib/model/sync_stack_delete_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_stack_v1.dart b/mobile/openapi/lib/model/sync_stack_v1.dart index c65affe8c..e4487ccfa 100644 Binary files a/mobile/openapi/lib/model/sync_stack_v1.dart and b/mobile/openapi/lib/model/sync_stack_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_stream_dto.dart b/mobile/openapi/lib/model/sync_stream_dto.dart index 9884eef34..932477cb1 100644 Binary files a/mobile/openapi/lib/model/sync_stream_dto.dart and b/mobile/openapi/lib/model/sync_stream_dto.dart differ diff --git a/mobile/openapi/lib/model/sync_user_delete_v1.dart b/mobile/openapi/lib/model/sync_user_delete_v1.dart index 09411cb79..bbbdc147d 100644 Binary files a/mobile/openapi/lib/model/sync_user_delete_v1.dart and b/mobile/openapi/lib/model/sync_user_delete_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_user_metadata_delete_v1.dart b/mobile/openapi/lib/model/sync_user_metadata_delete_v1.dart index f39acc617..61340a8f8 100644 Binary files a/mobile/openapi/lib/model/sync_user_metadata_delete_v1.dart and b/mobile/openapi/lib/model/sync_user_metadata_delete_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_user_metadata_v1.dart b/mobile/openapi/lib/model/sync_user_metadata_v1.dart index cf39b6d96..23803d0be 100644 Binary files a/mobile/openapi/lib/model/sync_user_metadata_v1.dart and b/mobile/openapi/lib/model/sync_user_metadata_v1.dart differ diff --git a/mobile/openapi/lib/model/sync_user_v1.dart b/mobile/openapi/lib/model/sync_user_v1.dart index b9fad5ae8..6d425130a 100644 Binary files a/mobile/openapi/lib/model/sync_user_v1.dart and b/mobile/openapi/lib/model/sync_user_v1.dart differ diff --git a/mobile/openapi/lib/model/system_config_f_fmpeg_dto.dart b/mobile/openapi/lib/model/system_config_f_fmpeg_dto.dart index 0acfc9e8f..6c7acbd21 100644 Binary files a/mobile/openapi/lib/model/system_config_f_fmpeg_dto.dart and b/mobile/openapi/lib/model/system_config_f_fmpeg_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_faces_dto.dart b/mobile/openapi/lib/model/system_config_faces_dto.dart index 4e18eb8de..f57303c31 100644 Binary files a/mobile/openapi/lib/model/system_config_faces_dto.dart and b/mobile/openapi/lib/model/system_config_faces_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_generated_fullsize_image_dto.dart b/mobile/openapi/lib/model/system_config_generated_fullsize_image_dto.dart index e7111771b..b5640f82c 100644 Binary files a/mobile/openapi/lib/model/system_config_generated_fullsize_image_dto.dart and b/mobile/openapi/lib/model/system_config_generated_fullsize_image_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_generated_image_dto.dart b/mobile/openapi/lib/model/system_config_generated_image_dto.dart index a46fc13d2..3e8fed2c6 100644 Binary files a/mobile/openapi/lib/model/system_config_generated_image_dto.dart and b/mobile/openapi/lib/model/system_config_generated_image_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_image_dto.dart b/mobile/openapi/lib/model/system_config_image_dto.dart index 783eaa7d4..217a666a6 100644 Binary files a/mobile/openapi/lib/model/system_config_image_dto.dart and b/mobile/openapi/lib/model/system_config_image_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_library_scan_dto.dart b/mobile/openapi/lib/model/system_config_library_scan_dto.dart index 6a6558b4b..28ea603c2 100644 Binary files a/mobile/openapi/lib/model/system_config_library_scan_dto.dart and b/mobile/openapi/lib/model/system_config_library_scan_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_library_watch_dto.dart b/mobile/openapi/lib/model/system_config_library_watch_dto.dart index 1a1f5d712..b4f171bd2 100644 Binary files a/mobile/openapi/lib/model/system_config_library_watch_dto.dart and b/mobile/openapi/lib/model/system_config_library_watch_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_logging_dto.dart b/mobile/openapi/lib/model/system_config_logging_dto.dart index f025221ef..54278893d 100644 Binary files a/mobile/openapi/lib/model/system_config_logging_dto.dart and b/mobile/openapi/lib/model/system_config_logging_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_machine_learning_dto.dart b/mobile/openapi/lib/model/system_config_machine_learning_dto.dart index da689936f..2a0f1ffbc 100644 Binary files a/mobile/openapi/lib/model/system_config_machine_learning_dto.dart and b/mobile/openapi/lib/model/system_config_machine_learning_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_map_dto.dart b/mobile/openapi/lib/model/system_config_map_dto.dart index d53d5711d..109babd37 100644 Binary files a/mobile/openapi/lib/model/system_config_map_dto.dart and b/mobile/openapi/lib/model/system_config_map_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_new_version_check_dto.dart b/mobile/openapi/lib/model/system_config_new_version_check_dto.dart index c63d2abc1..ec2b400df 100644 Binary files a/mobile/openapi/lib/model/system_config_new_version_check_dto.dart and b/mobile/openapi/lib/model/system_config_new_version_check_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_nightly_tasks_dto.dart b/mobile/openapi/lib/model/system_config_nightly_tasks_dto.dart index ab7b4b37c..cfb18b181 100644 Binary files a/mobile/openapi/lib/model/system_config_nightly_tasks_dto.dart and b/mobile/openapi/lib/model/system_config_nightly_tasks_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_o_auth_dto.dart b/mobile/openapi/lib/model/system_config_o_auth_dto.dart index c8f91be1f..82195e498 100644 Binary files a/mobile/openapi/lib/model/system_config_o_auth_dto.dart and b/mobile/openapi/lib/model/system_config_o_auth_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_password_login_dto.dart b/mobile/openapi/lib/model/system_config_password_login_dto.dart index 69c8942bb..1328a6aca 100644 Binary files a/mobile/openapi/lib/model/system_config_password_login_dto.dart and b/mobile/openapi/lib/model/system_config_password_login_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_reverse_geocoding_dto.dart b/mobile/openapi/lib/model/system_config_reverse_geocoding_dto.dart index 6c1673d46..0374e19be 100644 Binary files a/mobile/openapi/lib/model/system_config_reverse_geocoding_dto.dart and b/mobile/openapi/lib/model/system_config_reverse_geocoding_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_server_dto.dart b/mobile/openapi/lib/model/system_config_server_dto.dart index 8099292dd..200f75f7c 100644 Binary files a/mobile/openapi/lib/model/system_config_server_dto.dart and b/mobile/openapi/lib/model/system_config_server_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_smtp_dto.dart b/mobile/openapi/lib/model/system_config_smtp_dto.dart index fcde49cf3..a3d14cda6 100644 Binary files a/mobile/openapi/lib/model/system_config_smtp_dto.dart and b/mobile/openapi/lib/model/system_config_smtp_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_smtp_transport_dto.dart b/mobile/openapi/lib/model/system_config_smtp_transport_dto.dart index 46307046b..9e16e5bad 100644 Binary files a/mobile/openapi/lib/model/system_config_smtp_transport_dto.dart and b/mobile/openapi/lib/model/system_config_smtp_transport_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_storage_template_dto.dart b/mobile/openapi/lib/model/system_config_storage_template_dto.dart index 596aafc19..f9f37e48a 100644 Binary files a/mobile/openapi/lib/model/system_config_storage_template_dto.dart and b/mobile/openapi/lib/model/system_config_storage_template_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_template_storage_option_dto.dart b/mobile/openapi/lib/model/system_config_template_storage_option_dto.dart index f8586d344..6f8151303 100644 Binary files a/mobile/openapi/lib/model/system_config_template_storage_option_dto.dart and b/mobile/openapi/lib/model/system_config_template_storage_option_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_theme_dto.dart b/mobile/openapi/lib/model/system_config_theme_dto.dart index a97c2cf84..fca38f71f 100644 Binary files a/mobile/openapi/lib/model/system_config_theme_dto.dart and b/mobile/openapi/lib/model/system_config_theme_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_trash_dto.dart b/mobile/openapi/lib/model/system_config_trash_dto.dart index 51b39e9a5..9bdaef92d 100644 Binary files a/mobile/openapi/lib/model/system_config_trash_dto.dart and b/mobile/openapi/lib/model/system_config_trash_dto.dart differ diff --git a/mobile/openapi/lib/model/system_config_user_dto.dart b/mobile/openapi/lib/model/system_config_user_dto.dart index 8e6bd3c9c..a7313560e 100644 Binary files a/mobile/openapi/lib/model/system_config_user_dto.dart and b/mobile/openapi/lib/model/system_config_user_dto.dart differ diff --git a/mobile/openapi/lib/model/tag_bulk_assets_dto.dart b/mobile/openapi/lib/model/tag_bulk_assets_dto.dart index 26a575e19..16abc3bcd 100644 Binary files a/mobile/openapi/lib/model/tag_bulk_assets_dto.dart and b/mobile/openapi/lib/model/tag_bulk_assets_dto.dart differ diff --git a/mobile/openapi/lib/model/tag_bulk_assets_response_dto.dart b/mobile/openapi/lib/model/tag_bulk_assets_response_dto.dart index 009f26bfe..5566846e3 100644 Binary files a/mobile/openapi/lib/model/tag_bulk_assets_response_dto.dart and b/mobile/openapi/lib/model/tag_bulk_assets_response_dto.dart differ diff --git a/mobile/openapi/lib/model/tag_create_dto.dart b/mobile/openapi/lib/model/tag_create_dto.dart index 9a5171074..fd6a10163 100644 Binary files a/mobile/openapi/lib/model/tag_create_dto.dart and b/mobile/openapi/lib/model/tag_create_dto.dart differ diff --git a/mobile/openapi/lib/model/tag_response_dto.dart b/mobile/openapi/lib/model/tag_response_dto.dart index cd684b163..9a7191215 100644 Binary files a/mobile/openapi/lib/model/tag_response_dto.dart and b/mobile/openapi/lib/model/tag_response_dto.dart differ diff --git a/mobile/openapi/lib/model/tag_update_dto.dart b/mobile/openapi/lib/model/tag_update_dto.dart index ab1adb127..98cb6af52 100644 Binary files a/mobile/openapi/lib/model/tag_update_dto.dart and b/mobile/openapi/lib/model/tag_update_dto.dart differ diff --git a/mobile/openapi/lib/model/tag_upsert_dto.dart b/mobile/openapi/lib/model/tag_upsert_dto.dart index d60a00f46..3581ef1e8 100644 Binary files a/mobile/openapi/lib/model/tag_upsert_dto.dart and b/mobile/openapi/lib/model/tag_upsert_dto.dart differ diff --git a/mobile/openapi/lib/model/tags_response.dart b/mobile/openapi/lib/model/tags_response.dart index 2470edf97..1e4a4bd10 100644 Binary files a/mobile/openapi/lib/model/tags_response.dart and b/mobile/openapi/lib/model/tags_response.dart differ diff --git a/mobile/openapi/lib/model/tags_update.dart b/mobile/openapi/lib/model/tags_update.dart index d99236914..e42357e3d 100644 Binary files a/mobile/openapi/lib/model/tags_update.dart and b/mobile/openapi/lib/model/tags_update.dart differ diff --git a/mobile/openapi/lib/model/template_dto.dart b/mobile/openapi/lib/model/template_dto.dart index f818e0508..b1eab848e 100644 Binary files a/mobile/openapi/lib/model/template_dto.dart and b/mobile/openapi/lib/model/template_dto.dart differ diff --git a/mobile/openapi/lib/model/template_response_dto.dart b/mobile/openapi/lib/model/template_response_dto.dart index 3c3224a54..f19c1eae7 100644 Binary files a/mobile/openapi/lib/model/template_response_dto.dart and b/mobile/openapi/lib/model/template_response_dto.dart differ diff --git a/mobile/openapi/lib/model/test_email_response_dto.dart b/mobile/openapi/lib/model/test_email_response_dto.dart index 33e6c042d..e14783f3c 100644 Binary files a/mobile/openapi/lib/model/test_email_response_dto.dart and b/mobile/openapi/lib/model/test_email_response_dto.dart differ diff --git a/mobile/openapi/lib/model/time_bucket_asset_response_dto.dart b/mobile/openapi/lib/model/time_bucket_asset_response_dto.dart index 58032b7c5..720323cd1 100644 Binary files a/mobile/openapi/lib/model/time_bucket_asset_response_dto.dart and b/mobile/openapi/lib/model/time_bucket_asset_response_dto.dart differ diff --git a/mobile/openapi/lib/model/tone_mapping.dart b/mobile/openapi/lib/model/tone_mapping.dart index e05aea2b7..a1db2f5c9 100644 Binary files a/mobile/openapi/lib/model/tone_mapping.dart and b/mobile/openapi/lib/model/tone_mapping.dart differ diff --git a/mobile/openapi/lib/model/transcode_hw_accel.dart b/mobile/openapi/lib/model/transcode_hw_accel.dart index de5006341..22d20de32 100644 Binary files a/mobile/openapi/lib/model/transcode_hw_accel.dart and b/mobile/openapi/lib/model/transcode_hw_accel.dart differ diff --git a/mobile/openapi/lib/model/transcode_policy.dart b/mobile/openapi/lib/model/transcode_policy.dart index 6e9617428..ab3a876a9 100644 Binary files a/mobile/openapi/lib/model/transcode_policy.dart and b/mobile/openapi/lib/model/transcode_policy.dart differ diff --git a/mobile/openapi/lib/model/trash_response_dto.dart b/mobile/openapi/lib/model/trash_response_dto.dart index 2df154d06..7edd5d032 100644 Binary files a/mobile/openapi/lib/model/trash_response_dto.dart and b/mobile/openapi/lib/model/trash_response_dto.dart differ diff --git a/mobile/openapi/lib/model/update_album_dto.dart b/mobile/openapi/lib/model/update_album_dto.dart index 8353dba14..46ce8b0ec 100644 Binary files a/mobile/openapi/lib/model/update_album_dto.dart and b/mobile/openapi/lib/model/update_album_dto.dart differ diff --git a/mobile/openapi/lib/model/update_album_user_dto.dart b/mobile/openapi/lib/model/update_album_user_dto.dart index 43218cae6..9d934eb46 100644 Binary files a/mobile/openapi/lib/model/update_album_user_dto.dart and b/mobile/openapi/lib/model/update_album_user_dto.dart differ diff --git a/mobile/openapi/lib/model/update_asset_dto.dart b/mobile/openapi/lib/model/update_asset_dto.dart index 7b364f138..42e8ec387 100644 Binary files a/mobile/openapi/lib/model/update_asset_dto.dart and b/mobile/openapi/lib/model/update_asset_dto.dart differ diff --git a/mobile/openapi/lib/model/update_library_dto.dart b/mobile/openapi/lib/model/update_library_dto.dart index 6a4f36906..628bdc005 100644 Binary files a/mobile/openapi/lib/model/update_library_dto.dart and b/mobile/openapi/lib/model/update_library_dto.dart differ diff --git a/mobile/openapi/lib/model/usage_by_user_dto.dart b/mobile/openapi/lib/model/usage_by_user_dto.dart index 80235915f..da1fe600a 100644 Binary files a/mobile/openapi/lib/model/usage_by_user_dto.dart and b/mobile/openapi/lib/model/usage_by_user_dto.dart differ diff --git a/mobile/openapi/lib/model/user_admin_create_dto.dart b/mobile/openapi/lib/model/user_admin_create_dto.dart index 8c8b70fbc..320d31806 100644 Binary files a/mobile/openapi/lib/model/user_admin_create_dto.dart and b/mobile/openapi/lib/model/user_admin_create_dto.dart differ diff --git a/mobile/openapi/lib/model/user_admin_delete_dto.dart b/mobile/openapi/lib/model/user_admin_delete_dto.dart index 2cf68ad7b..6be70f37b 100644 Binary files a/mobile/openapi/lib/model/user_admin_delete_dto.dart and b/mobile/openapi/lib/model/user_admin_delete_dto.dart differ diff --git a/mobile/openapi/lib/model/user_admin_response_dto.dart b/mobile/openapi/lib/model/user_admin_response_dto.dart index e5ae8e1d4..706f65cf3 100644 Binary files a/mobile/openapi/lib/model/user_admin_response_dto.dart and b/mobile/openapi/lib/model/user_admin_response_dto.dart differ diff --git a/mobile/openapi/lib/model/user_admin_update_dto.dart b/mobile/openapi/lib/model/user_admin_update_dto.dart index 9605552d2..3cce65745 100644 Binary files a/mobile/openapi/lib/model/user_admin_update_dto.dart and b/mobile/openapi/lib/model/user_admin_update_dto.dart differ diff --git a/mobile/openapi/lib/model/user_avatar_color.dart b/mobile/openapi/lib/model/user_avatar_color.dart index 4cd7dd320..4fcf51855 100644 Binary files a/mobile/openapi/lib/model/user_avatar_color.dart and b/mobile/openapi/lib/model/user_avatar_color.dart differ diff --git a/mobile/openapi/lib/model/user_license.dart b/mobile/openapi/lib/model/user_license.dart index 9bed8d5c4..f02dc73be 100644 Binary files a/mobile/openapi/lib/model/user_license.dart and b/mobile/openapi/lib/model/user_license.dart differ diff --git a/mobile/openapi/lib/model/user_metadata_key.dart b/mobile/openapi/lib/model/user_metadata_key.dart index 845b5ae9b..2b4c11a73 100644 Binary files a/mobile/openapi/lib/model/user_metadata_key.dart and b/mobile/openapi/lib/model/user_metadata_key.dart differ diff --git a/mobile/openapi/lib/model/user_response_dto.dart b/mobile/openapi/lib/model/user_response_dto.dart index a02da2994..bf0e2cbf0 100644 Binary files a/mobile/openapi/lib/model/user_response_dto.dart and b/mobile/openapi/lib/model/user_response_dto.dart differ diff --git a/mobile/openapi/lib/model/user_status.dart b/mobile/openapi/lib/model/user_status.dart index 596abf324..130bd650f 100644 Binary files a/mobile/openapi/lib/model/user_status.dart and b/mobile/openapi/lib/model/user_status.dart differ diff --git a/mobile/openapi/lib/model/user_update_me_dto.dart b/mobile/openapi/lib/model/user_update_me_dto.dart index 779e07ffa..066c435eb 100644 Binary files a/mobile/openapi/lib/model/user_update_me_dto.dart and b/mobile/openapi/lib/model/user_update_me_dto.dart differ diff --git a/mobile/openapi/lib/model/validate_access_token_response_dto.dart b/mobile/openapi/lib/model/validate_access_token_response_dto.dart index 5e36efcfe..16b9d0f92 100644 Binary files a/mobile/openapi/lib/model/validate_access_token_response_dto.dart and b/mobile/openapi/lib/model/validate_access_token_response_dto.dart differ diff --git a/mobile/openapi/lib/model/validate_library_dto.dart b/mobile/openapi/lib/model/validate_library_dto.dart index 79ddb9a54..59c368078 100644 Binary files a/mobile/openapi/lib/model/validate_library_dto.dart and b/mobile/openapi/lib/model/validate_library_dto.dart differ diff --git a/mobile/openapi/lib/model/validate_library_import_path_response_dto.dart b/mobile/openapi/lib/model/validate_library_import_path_response_dto.dart index 11fbbd74c..78cc03dc9 100644 Binary files a/mobile/openapi/lib/model/validate_library_import_path_response_dto.dart and b/mobile/openapi/lib/model/validate_library_import_path_response_dto.dart differ diff --git a/mobile/openapi/lib/model/validate_library_response_dto.dart b/mobile/openapi/lib/model/validate_library_response_dto.dart index e0dc2a2d1..37f6ad07d 100644 Binary files a/mobile/openapi/lib/model/validate_library_response_dto.dart and b/mobile/openapi/lib/model/validate_library_response_dto.dart differ diff --git a/mobile/openapi/lib/model/version_check_state_response_dto.dart b/mobile/openapi/lib/model/version_check_state_response_dto.dart index d3f9a6cd9..71075a681 100644 Binary files a/mobile/openapi/lib/model/version_check_state_response_dto.dart and b/mobile/openapi/lib/model/version_check_state_response_dto.dart differ diff --git a/mobile/openapi/lib/model/video_codec.dart b/mobile/openapi/lib/model/video_codec.dart index 307b20875..ba6441c8f 100644 Binary files a/mobile/openapi/lib/model/video_codec.dart and b/mobile/openapi/lib/model/video_codec.dart differ diff --git a/mobile/openapi/lib/model/video_container.dart b/mobile/openapi/lib/model/video_container.dart index b8efc94ad..b1a47c872 100644 Binary files a/mobile/openapi/lib/model/video_container.dart and b/mobile/openapi/lib/model/video_container.dart differ diff --git a/mobile/openapi/lib/model/workflow_action_item_dto.dart b/mobile/openapi/lib/model/workflow_action_item_dto.dart index cb0c39eae..9222dd6ba 100644 Binary files a/mobile/openapi/lib/model/workflow_action_item_dto.dart and b/mobile/openapi/lib/model/workflow_action_item_dto.dart differ diff --git a/mobile/openapi/lib/model/workflow_action_response_dto.dart b/mobile/openapi/lib/model/workflow_action_response_dto.dart index 5132623e8..8f77e9cf2 100644 Binary files a/mobile/openapi/lib/model/workflow_action_response_dto.dart and b/mobile/openapi/lib/model/workflow_action_response_dto.dart differ diff --git a/mobile/openapi/lib/model/workflow_create_dto.dart b/mobile/openapi/lib/model/workflow_create_dto.dart index c6e44743a..38665a191 100644 Binary files a/mobile/openapi/lib/model/workflow_create_dto.dart and b/mobile/openapi/lib/model/workflow_create_dto.dart differ diff --git a/mobile/openapi/lib/model/workflow_filter_item_dto.dart b/mobile/openapi/lib/model/workflow_filter_item_dto.dart index bd8090b05..52e29c3e9 100644 Binary files a/mobile/openapi/lib/model/workflow_filter_item_dto.dart and b/mobile/openapi/lib/model/workflow_filter_item_dto.dart differ diff --git a/mobile/openapi/lib/model/workflow_filter_response_dto.dart b/mobile/openapi/lib/model/workflow_filter_response_dto.dart index 94dce27a3..355378ada 100644 Binary files a/mobile/openapi/lib/model/workflow_filter_response_dto.dart and b/mobile/openapi/lib/model/workflow_filter_response_dto.dart differ diff --git a/mobile/openapi/lib/model/workflow_response_dto.dart b/mobile/openapi/lib/model/workflow_response_dto.dart index 1ad36f300..ae3e6510a 100644 Binary files a/mobile/openapi/lib/model/workflow_response_dto.dart and b/mobile/openapi/lib/model/workflow_response_dto.dart differ diff --git a/mobile/openapi/lib/model/workflow_update_dto.dart b/mobile/openapi/lib/model/workflow_update_dto.dart index 135c032b7..9891fff07 100644 Binary files a/mobile/openapi/lib/model/workflow_update_dto.dart and b/mobile/openapi/lib/model/workflow_update_dto.dart differ diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index 341ef32ca..7f85bbc1c 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -10,6 +10,7 @@ "name": "albumId", "required": true, "in": "query", + "description": "Album ID", "schema": { "format": "uuid", "type": "string" @@ -19,6 +20,7 @@ "name": "assetId", "required": false, "in": "query", + "description": "Asset ID (if activity is for an asset)", "schema": { "format": "uuid", "type": "string" @@ -28,6 +30,7 @@ "name": "level", "required": false, "in": "query", + "description": "Filter by activity level", "schema": { "$ref": "#/components/schemas/ReactionLevel" } @@ -36,6 +39,7 @@ "name": "type", "required": false, "in": "query", + "description": "Filter by activity type", "schema": { "$ref": "#/components/schemas/ReactionType" } @@ -44,6 +48,7 @@ "name": "userId", "required": false, "in": "query", + "description": "Filter by user ID", "schema": { "format": "uuid", "type": "string" @@ -165,6 +170,7 @@ "name": "albumId", "required": true, "in": "query", + "description": "Album ID", "schema": { "format": "uuid", "type": "string" @@ -174,6 +180,7 @@ "name": "assetId", "required": false, "in": "query", + "description": "Asset ID (if activity is for an asset)", "schema": { "format": "uuid", "type": "string" @@ -926,6 +933,7 @@ "name": "id", "required": false, "in": "query", + "description": "User ID filter", "schema": { "format": "uuid", "type": "string" @@ -935,6 +943,7 @@ "name": "withDeleted", "required": false, "in": "query", + "description": "Include deleted users", "schema": { "type": "boolean" } @@ -1520,6 +1529,7 @@ "name": "isFavorite", "required": false, "in": "query", + "description": "Filter by favorite status", "schema": { "type": "boolean" } @@ -1528,6 +1538,7 @@ "name": "isTrashed", "required": false, "in": "query", + "description": "Filter by trash status", "schema": { "type": "boolean" } @@ -1536,6 +1547,7 @@ "name": "visibility", "required": false, "in": "query", + "description": "Filter by visibility", "schema": { "$ref": "#/components/schemas/AssetVisibility" } @@ -1596,7 +1608,7 @@ "name": "assetId", "required": false, "in": "query", - "description": "Only returns albums that contain the asset\nIgnores the shared parameter\nundefined: get all albums", + "description": "Filter albums containing this asset ID (ignores shared parameter)", "schema": { "format": "uuid", "type": "string" @@ -1606,6 +1618,7 @@ "name": "shared", "required": false, "in": "query", + "description": "Filter by shared status: true = only shared, false = only own, undefined = all", "schema": { "type": "boolean" } @@ -1929,6 +1942,7 @@ "name": "withoutAssets", "required": false, "in": "query", + "description": "Exclude assets from response", "schema": { "type": "boolean" } @@ -3068,6 +3082,7 @@ "name": "deviceId", "required": true, "in": "path", + "description": "Device ID", "schema": { "type": "string" } @@ -3346,6 +3361,7 @@ "name": "count", "required": false, "in": "query", + "description": "Number of random assets to return", "schema": { "minimum": 1, "type": "number" @@ -3407,6 +3423,7 @@ "name": "isFavorite", "required": false, "in": "query", + "description": "Filter by favorite status", "schema": { "type": "boolean" } @@ -3415,6 +3432,7 @@ "name": "isTrashed", "required": false, "in": "query", + "description": "Filter by trash status", "schema": { "type": "boolean" } @@ -3423,6 +3441,7 @@ "name": "visibility", "required": false, "in": "query", + "description": "Filter by visibility", "schema": { "$ref": "#/components/schemas/AssetVisibility" } @@ -3927,6 +3946,7 @@ "name": "id", "required": true, "in": "path", + "description": "Asset ID", "schema": { "format": "uuid", "type": "string" @@ -3936,6 +3956,7 @@ "name": "key", "required": true, "in": "path", + "description": "Metadata key", "schema": { "type": "string" } @@ -3986,6 +4007,7 @@ "name": "id", "required": true, "in": "path", + "description": "Asset ID", "schema": { "format": "uuid", "type": "string" @@ -3995,6 +4017,7 @@ "name": "key", "required": true, "in": "path", + "description": "Metadata key", "schema": { "type": "string" } @@ -4117,6 +4140,7 @@ "name": "edited", "required": false, "in": "query", + "description": "Return edited asset if available", "schema": { "default": false, "type": "boolean" @@ -4286,6 +4310,7 @@ "name": "edited", "required": false, "in": "query", + "description": "Return edited asset if available", "schema": { "default": false, "type": "boolean" @@ -4312,6 +4337,7 @@ "name": "size", "required": false, "in": "query", + "description": "Asset media size", "schema": { "$ref": "#/components/schemas/AssetMediaSize" } @@ -5306,6 +5332,7 @@ "name": "id", "required": true, "in": "query", + "description": "Face ID", "schema": { "format": "uuid", "type": "string" @@ -5661,6 +5688,7 @@ "name": "name", "required": true, "in": "path", + "description": "Queue name", "schema": { "$ref": "#/components/schemas/QueueName" } @@ -6216,6 +6244,7 @@ "name": "fileCreatedAfter", "required": false, "in": "query", + "description": "Filter assets created after this date", "schema": { "format": "date-time", "type": "string" @@ -6225,6 +6254,7 @@ "name": "fileCreatedBefore", "required": false, "in": "query", + "description": "Filter assets created before this date", "schema": { "format": "date-time", "type": "string" @@ -6234,6 +6264,7 @@ "name": "isArchived", "required": false, "in": "query", + "description": "Filter by archived status", "schema": { "type": "boolean" } @@ -6242,6 +6273,7 @@ "name": "isFavorite", "required": false, "in": "query", + "description": "Filter by favorite status", "schema": { "type": "boolean" } @@ -6250,6 +6282,7 @@ "name": "withPartners", "required": false, "in": "query", + "description": "Include partner assets", "schema": { "type": "boolean" } @@ -6258,6 +6291,7 @@ "name": "withSharedAlbums", "required": false, "in": "query", + "description": "Include shared album assets", "schema": { "type": "boolean" } @@ -6320,6 +6354,7 @@ "name": "lat", "required": true, "in": "query", + "description": "Latitude (-90 to 90)", "schema": { "format": "double", "type": "number" @@ -6329,6 +6364,7 @@ "name": "lon", "required": true, "in": "query", + "description": "Longitude (-180 to 180)", "schema": { "format": "double", "type": "number" @@ -6392,6 +6428,7 @@ "name": "for", "required": false, "in": "query", + "description": "Filter by date", "schema": { "format": "date-time", "type": "string" @@ -6401,6 +6438,7 @@ "name": "isSaved", "required": false, "in": "query", + "description": "Filter by saved status", "schema": { "type": "boolean" } @@ -6409,6 +6447,7 @@ "name": "isTrashed", "required": false, "in": "query", + "description": "Include trashed memories", "schema": { "type": "boolean" } @@ -6417,6 +6456,7 @@ "name": "order", "required": false, "in": "query", + "description": "Sort order", "schema": { "$ref": "#/components/schemas/MemorySearchOrder" } @@ -6435,6 +6475,7 @@ "name": "type", "required": false, "in": "query", + "description": "Memory type", "schema": { "$ref": "#/components/schemas/MemoryType" } @@ -6555,6 +6596,7 @@ "name": "for", "required": false, "in": "query", + "description": "Filter by date", "schema": { "format": "date-time", "type": "string" @@ -6564,6 +6606,7 @@ "name": "isSaved", "required": false, "in": "query", + "description": "Filter by saved status", "schema": { "type": "boolean" } @@ -6572,6 +6615,7 @@ "name": "isTrashed", "required": false, "in": "query", + "description": "Include trashed memories", "schema": { "type": "boolean" } @@ -6580,6 +6624,7 @@ "name": "order", "required": false, "in": "query", + "description": "Sort order", "schema": { "$ref": "#/components/schemas/MemorySearchOrder" } @@ -6598,6 +6643,7 @@ "name": "type", "required": false, "in": "query", + "description": "Memory type", "schema": { "$ref": "#/components/schemas/MemoryType" } @@ -7031,6 +7077,7 @@ "name": "id", "required": false, "in": "query", + "description": "Filter by notification ID", "schema": { "format": "uuid", "type": "string" @@ -7040,6 +7087,7 @@ "name": "level", "required": false, "in": "query", + "description": "Filter by notification level", "schema": { "$ref": "#/components/schemas/NotificationLevel" } @@ -7048,6 +7096,7 @@ "name": "type", "required": false, "in": "query", + "description": "Filter by notification type", "schema": { "$ref": "#/components/schemas/NotificationType" } @@ -7056,6 +7105,7 @@ "name": "unread", "required": false, "in": "query", + "description": "Filter by unread status", "schema": { "type": "boolean" } @@ -7583,6 +7633,7 @@ "name": "direction", "required": true, "in": "query", + "description": "Partner direction", "schema": { "$ref": "#/components/schemas/PartnerDirection" } @@ -7932,6 +7983,7 @@ "name": "closestAssetId", "required": false, "in": "query", + "description": "Closest asset ID for similarity search", "schema": { "format": "uuid", "type": "string" @@ -7941,6 +7993,7 @@ "name": "closestPersonId", "required": false, "in": "query", + "description": "Closest person ID for similarity search", "schema": { "format": "uuid", "type": "string" @@ -7973,6 +8026,7 @@ "name": "withHidden", "required": false, "in": "query", + "description": "Include hidden people", "schema": { "type": "boolean" } @@ -8801,6 +8855,7 @@ "name": "name", "required": true, "in": "path", + "description": "Queue name", "schema": { "$ref": "#/components/schemas/QueueName" } @@ -8855,6 +8910,7 @@ "name": "name", "required": true, "in": "path", + "description": "Queue name", "schema": { "$ref": "#/components/schemas/QueueName" } @@ -8921,6 +8977,7 @@ "name": "name", "required": true, "in": "path", + "description": "Queue name", "schema": { "$ref": "#/components/schemas/QueueName" } @@ -8978,6 +9035,7 @@ "name": "name", "required": true, "in": "path", + "description": "Queue name", "schema": { "$ref": "#/components/schemas/QueueName" } @@ -8986,6 +9044,7 @@ "name": "status", "required": false, "in": "query", + "description": "Filter jobs by status", "schema": { "type": "array", "items": { @@ -9154,6 +9213,7 @@ "name": "albumIds", "required": false, "in": "query", + "description": "Filter by album IDs", "schema": { "type": "array", "items": { @@ -9166,6 +9226,7 @@ "name": "city", "required": false, "in": "query", + "description": "Filter by city name", "schema": { "nullable": true, "type": "string" @@ -9175,6 +9236,7 @@ "name": "country", "required": false, "in": "query", + "description": "Filter by country name", "schema": { "nullable": true, "type": "string" @@ -9184,6 +9246,7 @@ "name": "createdAfter", "required": false, "in": "query", + "description": "Filter by creation date (after)", "schema": { "format": "date-time", "type": "string" @@ -9193,6 +9256,7 @@ "name": "createdBefore", "required": false, "in": "query", + "description": "Filter by creation date (before)", "schema": { "format": "date-time", "type": "string" @@ -9202,6 +9266,7 @@ "name": "deviceId", "required": false, "in": "query", + "description": "Device ID to filter by", "schema": { "type": "string" } @@ -9210,6 +9275,7 @@ "name": "isEncoded", "required": false, "in": "query", + "description": "Filter by encoded status", "schema": { "type": "boolean" } @@ -9218,6 +9284,7 @@ "name": "isFavorite", "required": false, "in": "query", + "description": "Filter by favorite status", "schema": { "type": "boolean" } @@ -9226,6 +9293,7 @@ "name": "isMotion", "required": false, "in": "query", + "description": "Filter by motion photo status", "schema": { "type": "boolean" } @@ -9234,6 +9302,7 @@ "name": "isNotInAlbum", "required": false, "in": "query", + "description": "Filter assets not in any album", "schema": { "type": "boolean" } @@ -9242,6 +9311,7 @@ "name": "isOffline", "required": false, "in": "query", + "description": "Filter by offline status", "schema": { "type": "boolean" } @@ -9250,6 +9320,7 @@ "name": "lensModel", "required": false, "in": "query", + "description": "Filter by lens model", "schema": { "nullable": true, "type": "string" @@ -9259,6 +9330,7 @@ "name": "libraryId", "required": false, "in": "query", + "description": "Library ID to filter by", "schema": { "format": "uuid", "nullable": true, @@ -9269,6 +9341,7 @@ "name": "make", "required": false, "in": "query", + "description": "Filter by camera make", "schema": { "type": "string" } @@ -9277,6 +9350,7 @@ "name": "minFileSize", "required": false, "in": "query", + "description": "Minimum file size in bytes", "schema": { "minimum": 0, "type": "integer" @@ -9286,6 +9360,7 @@ "name": "model", "required": false, "in": "query", + "description": "Filter by camera model", "schema": { "nullable": true, "type": "string" @@ -9295,6 +9370,7 @@ "name": "ocr", "required": false, "in": "query", + "description": "Filter by OCR text content", "schema": { "type": "string" } @@ -9303,6 +9379,7 @@ "name": "personIds", "required": false, "in": "query", + "description": "Filter by person IDs", "schema": { "type": "array", "items": { @@ -9315,6 +9392,7 @@ "name": "rating", "required": false, "in": "query", + "description": "Filter by rating", "schema": { "minimum": -1, "maximum": 5, @@ -9325,6 +9403,7 @@ "name": "size", "required": false, "in": "query", + "description": "Number of results to return", "schema": { "minimum": 1, "maximum": 1000, @@ -9335,6 +9414,7 @@ "name": "state", "required": false, "in": "query", + "description": "Filter by state/province name", "schema": { "nullable": true, "type": "string" @@ -9344,6 +9424,7 @@ "name": "tagIds", "required": false, "in": "query", + "description": "Filter by tag IDs", "schema": { "nullable": true, "type": "array", @@ -9357,6 +9438,7 @@ "name": "takenAfter", "required": false, "in": "query", + "description": "Filter by taken date (after)", "schema": { "format": "date-time", "type": "string" @@ -9366,6 +9448,7 @@ "name": "takenBefore", "required": false, "in": "query", + "description": "Filter by taken date (before)", "schema": { "format": "date-time", "type": "string" @@ -9375,6 +9458,7 @@ "name": "trashedAfter", "required": false, "in": "query", + "description": "Filter by trash date (after)", "schema": { "format": "date-time", "type": "string" @@ -9384,6 +9468,7 @@ "name": "trashedBefore", "required": false, "in": "query", + "description": "Filter by trash date (before)", "schema": { "format": "date-time", "type": "string" @@ -9393,6 +9478,7 @@ "name": "type", "required": false, "in": "query", + "description": "Asset type filter", "schema": { "$ref": "#/components/schemas/AssetTypeEnum" } @@ -9401,6 +9487,7 @@ "name": "updatedAfter", "required": false, "in": "query", + "description": "Filter by update date (after)", "schema": { "format": "date-time", "type": "string" @@ -9410,6 +9497,7 @@ "name": "updatedBefore", "required": false, "in": "query", + "description": "Filter by update date (before)", "schema": { "format": "date-time", "type": "string" @@ -9419,6 +9507,7 @@ "name": "visibility", "required": false, "in": "query", + "description": "Filter by visibility", "schema": { "$ref": "#/components/schemas/AssetVisibility" } @@ -9427,6 +9516,7 @@ "name": "withDeleted", "required": false, "in": "query", + "description": "Include deleted assets", "schema": { "type": "boolean" } @@ -9435,6 +9525,7 @@ "name": "withExif", "required": false, "in": "query", + "description": "Include EXIF data in response", "schema": { "type": "boolean" } @@ -9557,6 +9648,7 @@ "name": "name", "required": true, "in": "query", + "description": "Person name to search for", "schema": { "type": "string" } @@ -9565,6 +9657,7 @@ "name": "withHidden", "required": false, "in": "query", + "description": "Include hidden people", "schema": { "type": "boolean" } @@ -9627,6 +9720,7 @@ "name": "name", "required": true, "in": "query", + "description": "Place name to search for", "schema": { "type": "string" } @@ -9872,6 +9966,7 @@ "name": "country", "required": false, "in": "query", + "description": "Filter by country", "schema": { "type": "string" } @@ -9880,6 +9975,7 @@ "name": "includeNull", "required": false, "in": "query", + "description": "Include null values in suggestions", "x-immich-history": [ { "version": "v1.111.0", @@ -9899,6 +9995,7 @@ "name": "lensModel", "required": false, "in": "query", + "description": "Filter by lens model", "schema": { "type": "string" } @@ -9907,6 +10004,7 @@ "name": "make", "required": false, "in": "query", + "description": "Filter by camera make", "schema": { "type": "string" } @@ -9915,6 +10013,7 @@ "name": "model", "required": false, "in": "query", + "description": "Filter by camera model", "schema": { "type": "string" } @@ -9923,6 +10022,7 @@ "name": "state", "required": false, "in": "query", + "description": "Filter by state/province", "schema": { "type": "string" } @@ -9931,6 +10031,7 @@ "name": "type", "required": true, "in": "query", + "description": "Suggestion type", "schema": { "$ref": "#/components/schemas/SearchSuggestionType" } @@ -10994,6 +11095,7 @@ "name": "albumId", "required": false, "in": "query", + "description": "Filter by album ID", "schema": { "format": "uuid", "type": "string" @@ -11003,6 +11105,7 @@ "name": "id", "required": false, "in": "query", + "description": "Filter by shared link ID", "x-immich-history": [ { "version": "v2.5.0", @@ -11138,6 +11241,7 @@ "name": "password", "required": false, "in": "query", + "description": "Link password", "schema": { "example": "password", "type": "string" @@ -11155,6 +11259,7 @@ "name": "token", "required": false, "in": "query", + "description": "Access token", "schema": { "type": "string" } @@ -11617,6 +11722,7 @@ "name": "primaryAssetId", "required": false, "in": "query", + "description": "Filter by primary asset ID", "schema": { "format": "uuid", "type": "string" @@ -15132,9 +15238,11 @@ "APIKeyCreateDto": { "properties": { "name": { + "description": "API key name", "type": "string" }, "permissions": { + "description": "List of permissions", "items": { "$ref": "#/components/schemas/Permission" }, @@ -15153,6 +15261,7 @@ "$ref": "#/components/schemas/APIKeyResponseDto" }, "secret": { + "description": "API key secret (only shown once)", "type": "string" } }, @@ -15165,22 +15274,27 @@ "APIKeyResponseDto": { "properties": { "createdAt": { + "description": "Creation date", "format": "date-time", "type": "string" }, "id": { + "description": "API key ID", "type": "string" }, "name": { + "description": "API key name", "type": "string" }, "permissions": { + "description": "List of permissions", "items": { "$ref": "#/components/schemas/Permission" }, "type": "array" }, "updatedAt": { + "description": "Last update date", "format": "date-time", "type": "string" } @@ -15197,9 +15311,11 @@ "APIKeyUpdateDto": { "properties": { "name": { + "description": "API key name", "type": "string" }, "permissions": { + "description": "List of permissions", "items": { "$ref": "#/components/schemas/Permission" }, @@ -15212,14 +15328,17 @@ "ActivityCreateDto": { "properties": { "albumId": { + "description": "Album ID", "format": "uuid", "type": "string" }, "assetId": { + "description": "Asset ID (if activity is for an asset)", "format": "uuid", "type": "string" }, "comment": { + "description": "Comment text (required if type is comment)", "type": "string" }, "type": { @@ -15227,7 +15346,8 @@ { "$ref": "#/components/schemas/ReactionType" } - ] + ], + "description": "Activity type (like or comment)" } }, "required": [ @@ -15239,18 +15359,22 @@ "ActivityResponseDto": { "properties": { "assetId": { + "description": "Asset ID (if activity is for an asset)", "nullable": true, "type": "string" }, "comment": { + "description": "Comment text (for comment activities)", "nullable": true, "type": "string" }, "createdAt": { + "description": "Creation date", "format": "date-time", "type": "string" }, "id": { + "description": "Activity ID", "type": "string" }, "type": { @@ -15258,7 +15382,8 @@ { "$ref": "#/components/schemas/ReactionType" } - ] + ], + "description": "Activity type" }, "user": { "$ref": "#/components/schemas/UserResponseDto" @@ -15276,9 +15401,11 @@ "ActivityStatisticsResponseDto": { "properties": { "comments": { + "description": "Number of comments", "type": "integer" }, "likes": { + "description": "Number of likes", "type": "integer" } }, @@ -15291,6 +15418,7 @@ "AddUsersDto": { "properties": { "albumUsers": { + "description": "Album users to add", "items": { "$ref": "#/components/schemas/AlbumUserAddDto" }, @@ -15306,6 +15434,7 @@ "AdminOnboardingUpdateDto": { "properties": { "isOnboarded": { + "description": "Is admin onboarded", "type": "boolean" } }, @@ -15317,9 +15446,11 @@ "AlbumResponseDto": { "properties": { "albumName": { + "description": "Album name", "type": "string" }, "albumThumbnailAssetId": { + "description": "Thumbnail asset ID", "nullable": true, "type": "string" }, @@ -15330,6 +15461,7 @@ "type": "array" }, "assetCount": { + "description": "Number of assets", "type": "integer" }, "assets": { @@ -15345,26 +15477,33 @@ "type": "array" }, "createdAt": { + "description": "Creation date", "format": "date-time", "type": "string" }, "description": { + "description": "Album description", "type": "string" }, "endDate": { + "description": "End date (latest asset)", "format": "date-time", "type": "string" }, "hasSharedLink": { + "description": "Has shared link", "type": "boolean" }, "id": { + "description": "Album ID", "type": "string" }, "isActivityEnabled": { + "description": "Activity feed enabled", "type": "boolean" }, "lastModifiedAssetTimestamp": { + "description": "Last modified asset timestamp", "format": "date-time", "type": "string" }, @@ -15373,22 +15512,27 @@ { "$ref": "#/components/schemas/AssetOrder" } - ] + ], + "description": "Asset sort order" }, "owner": { "$ref": "#/components/schemas/UserResponseDto" }, "ownerId": { + "description": "Owner user ID", "type": "string" }, "shared": { + "description": "Is shared album", "type": "boolean" }, "startDate": { + "description": "Start date (earliest asset)", "format": "date-time", "type": "string" }, "updatedAt": { + "description": "Last update date", "format": "date-time", "type": "string" } @@ -15414,12 +15558,15 @@ "AlbumStatisticsResponseDto": { "properties": { "notShared": { + "description": "Number of non-shared albums", "type": "integer" }, "owned": { + "description": "Number of owned albums", "type": "integer" }, "shared": { + "description": "Number of shared albums", "type": "integer" } }, @@ -15438,9 +15585,11 @@ "$ref": "#/components/schemas/AlbumUserRole" } ], - "default": "editor" + "default": "editor", + "description": "Album user role" }, "userId": { + "description": "User ID", "format": "uuid", "type": "string" } @@ -15457,9 +15606,11 @@ { "$ref": "#/components/schemas/AlbumUserRole" } - ] + ], + "description": "Album user role" }, "userId": { + "description": "User ID", "format": "uuid", "type": "string" } @@ -15477,7 +15628,8 @@ { "$ref": "#/components/schemas/AlbumUserRole" } - ] + ], + "description": "Album user role" }, "user": { "$ref": "#/components/schemas/UserResponseDto" @@ -15490,6 +15642,7 @@ "type": "object" }, "AlbumUserRole": { + "description": "Album user role", "enum": [ "editor", "viewer" @@ -15499,6 +15652,7 @@ "AlbumsAddAssetsDto": { "properties": { "albumIds": { + "description": "Album IDs", "items": { "format": "uuid", "type": "string" @@ -15506,6 +15660,7 @@ "type": "array" }, "assetIds": { + "description": "Asset IDs", "items": { "format": "uuid", "type": "string" @@ -15526,9 +15681,11 @@ { "$ref": "#/components/schemas/BulkIdErrorReason" } - ] + ], + "description": "Error reason" }, "success": { + "description": "Operation success", "type": "boolean" } }, @@ -15545,7 +15702,8 @@ "$ref": "#/components/schemas/AssetOrder" } ], - "default": "desc" + "default": "desc", + "description": "Default asset order for albums" } }, "required": [ @@ -15554,13 +15712,15 @@ "type": "object" }, "AlbumsUpdate": { + "description": "Album preferences", "properties": { "defaultAssetOrder": { "allOf": [ { "$ref": "#/components/schemas/AssetOrder" } - ] + ], + "description": "Default asset order for albums" } }, "type": "object" @@ -15568,9 +15728,11 @@ "AssetBulkDeleteDto": { "properties": { "force": { + "description": "Force delete even if in use", "type": "boolean" }, "ids": { + "description": "IDs to process", "items": { "format": "uuid", "type": "string" @@ -15586,19 +15748,24 @@ "AssetBulkUpdateDto": { "properties": { "dateTimeOriginal": { + "description": "Original date and time", "type": "string" }, "dateTimeRelative": { + "description": "Relative time offset in seconds", "type": "number" }, "description": { + "description": "Asset description", "type": "string" }, "duplicateId": { + "description": "Duplicate asset ID", "nullable": true, "type": "string" }, "ids": { + "description": "Asset IDs to update", "items": { "format": "uuid", "type": "string" @@ -15606,20 +15773,25 @@ "type": "array" }, "isFavorite": { + "description": "Mark as favorite", "type": "boolean" }, "latitude": { + "description": "Latitude coordinate", "type": "number" }, "longitude": { + "description": "Longitude coordinate", "type": "number" }, "rating": { + "description": "Rating", "maximum": 5, "minimum": -1, "type": "number" }, "timeZone": { + "description": "Time zone (IANA timezone)", "type": "string" }, "visibility": { @@ -15627,7 +15799,8 @@ { "$ref": "#/components/schemas/AssetVisibility" } - ] + ], + "description": "Asset visibility" } }, "required": [ @@ -15638,6 +15811,7 @@ "AssetBulkUploadCheckDto": { "properties": { "assets": { + "description": "Assets to check", "items": { "$ref": "#/components/schemas/AssetBulkUploadCheckItem" }, @@ -15652,10 +15826,11 @@ "AssetBulkUploadCheckItem": { "properties": { "checksum": { - "description": "base64 or hex encoded sha1 hash", + "description": "Base64 or hex encoded SHA1 hash", "type": "string" }, "id": { + "description": "Asset ID", "type": "string" } }, @@ -15668,6 +15843,7 @@ "AssetBulkUploadCheckResponseDto": { "properties": { "results": { + "description": "Upload check results", "items": { "$ref": "#/components/schemas/AssetBulkUploadCheckResult" }, @@ -15682,6 +15858,7 @@ "AssetBulkUploadCheckResult": { "properties": { "action": { + "description": "Upload action", "enum": [ "accept", "reject" @@ -15689,15 +15866,19 @@ "type": "string" }, "assetId": { + "description": "Existing asset ID if duplicate", "type": "string" }, "id": { + "description": "Asset ID", "type": "string" }, "isTrashed": { + "description": "Whether existing asset is trashed", "type": "boolean" }, "reason": { + "description": "Rejection reason if rejected", "enum": [ "duplicate", "unsupported-format" @@ -15715,29 +15896,36 @@ "properties": { "albums": { "default": true, + "description": "Copy album associations", "type": "boolean" }, "favorite": { "default": true, + "description": "Copy favorite status", "type": "boolean" }, "sharedLinks": { "default": true, + "description": "Copy shared links", "type": "boolean" }, "sidecar": { "default": true, + "description": "Copy sidecar file", "type": "boolean" }, "sourceId": { + "description": "Source asset ID", "format": "uuid", "type": "string" }, "stack": { "default": true, + "description": "Copy stack association", "type": "boolean" }, "targetId": { + "description": "Target asset ID", "format": "uuid", "type": "string" } @@ -15751,10 +15939,12 @@ "AssetDeltaSyncDto": { "properties": { "updatedAfter": { + "description": "Sync assets updated after this date", "format": "date-time", "type": "string" }, "userIds": { + "description": "User IDs to sync", "items": { "format": "uuid", "type": "string" @@ -15771,15 +15961,18 @@ "AssetDeltaSyncResponseDto": { "properties": { "deleted": { + "description": "Deleted asset IDs", "items": { "type": "string" }, "type": "array" }, "needsFullSync": { + "description": "Whether full sync is needed", "type": "boolean" }, "upserted": { + "description": "Upserted assets", "items": { "$ref": "#/components/schemas/AssetResponseDto" }, @@ -15794,6 +15987,7 @@ "type": "object" }, "AssetEditAction": { + "description": "Type of edit action to perform", "enum": [ "crop", "rotate", @@ -15808,7 +16002,8 @@ { "$ref": "#/components/schemas/AssetEditAction" } - ] + ], + "description": "Type of edit action to perform" }, "parameters": { "$ref": "#/components/schemas/CropParameters" @@ -15823,7 +16018,7 @@ "AssetEditActionListDto": { "properties": { "edits": { - "description": "list of edits", + "description": "List of edit actions to apply (crop, rotate, or mirror)", "items": { "anyOf": [ { @@ -15853,7 +16048,8 @@ { "$ref": "#/components/schemas/AssetEditAction" } - ] + ], + "description": "Type of edit action to perform" }, "parameters": { "$ref": "#/components/schemas/MirrorParameters" @@ -15872,7 +16068,8 @@ { "$ref": "#/components/schemas/AssetEditAction" } - ] + ], + "description": "Type of edit action to perform" }, "parameters": { "$ref": "#/components/schemas/RotateParameters" @@ -15887,11 +16084,12 @@ "AssetEditsDto": { "properties": { "assetId": { + "description": "Asset ID to apply edits to", "format": "uuid", "type": "string" }, "edits": { - "description": "list of edits", + "description": "List of edit actions to apply (crop, rotate, or mirror)", "items": { "anyOf": [ { @@ -15918,29 +16116,37 @@ "AssetFaceCreateDto": { "properties": { "assetId": { + "description": "Asset ID", "format": "uuid", "type": "string" }, "height": { + "description": "Face bounding box height", "type": "integer" }, "imageHeight": { + "description": "Image height in pixels", "type": "integer" }, "imageWidth": { + "description": "Image width in pixels", "type": "integer" }, "personId": { + "description": "Person ID", "format": "uuid", "type": "string" }, "width": { + "description": "Face bounding box width", "type": "integer" }, "x": { + "description": "Face bounding box X coordinate", "type": "integer" }, "y": { + "description": "Face bounding box Y coordinate", "type": "integer" } }, @@ -15959,6 +16165,7 @@ "AssetFaceDeleteDto": { "properties": { "force": { + "description": "Force delete even if person has other faces", "type": "boolean" } }, @@ -15970,25 +16177,32 @@ "AssetFaceResponseDto": { "properties": { "boundingBoxX1": { + "description": "Bounding box X1 coordinate", "type": "integer" }, "boundingBoxX2": { + "description": "Bounding box X2 coordinate", "type": "integer" }, "boundingBoxY1": { + "description": "Bounding box Y1 coordinate", "type": "integer" }, "boundingBoxY2": { + "description": "Bounding box Y2 coordinate", "type": "integer" }, "id": { + "description": "Face ID", "format": "uuid", "type": "string" }, "imageHeight": { + "description": "Image height in pixels", "type": "integer" }, "imageWidth": { + "description": "Image width in pixels", "type": "integer" }, "person": { @@ -15997,6 +16211,7 @@ "$ref": "#/components/schemas/PersonResponseDto" } ], + "description": "Person associated with face", "nullable": true }, "sourceType": { @@ -16004,7 +16219,8 @@ { "$ref": "#/components/schemas/SourceType" } - ] + ], + "description": "Face detection source type" } }, "required": [ @@ -16022,6 +16238,7 @@ "AssetFaceUpdateDto": { "properties": { "data": { + "description": "Face update items", "items": { "$ref": "#/components/schemas/AssetFaceUpdateItem" }, @@ -16036,10 +16253,12 @@ "AssetFaceUpdateItem": { "properties": { "assetId": { + "description": "Asset ID", "format": "uuid", "type": "string" }, "personId": { + "description": "Person ID", "format": "uuid", "type": "string" } @@ -16053,25 +16272,32 @@ "AssetFaceWithoutPersonResponseDto": { "properties": { "boundingBoxX1": { + "description": "Bounding box X1 coordinate", "type": "integer" }, "boundingBoxX2": { + "description": "Bounding box X2 coordinate", "type": "integer" }, "boundingBoxY1": { + "description": "Bounding box Y1 coordinate", "type": "integer" }, "boundingBoxY2": { + "description": "Bounding box Y2 coordinate", "type": "integer" }, "id": { + "description": "Face ID", "format": "uuid", "type": "string" }, "imageHeight": { + "description": "Image height in pixels", "type": "integer" }, "imageWidth": { + "description": "Image width in pixels", "type": "integer" }, "sourceType": { @@ -16079,7 +16305,8 @@ { "$ref": "#/components/schemas/SourceType" } - ] + ], + "description": "Face detection source type" } }, "required": [ @@ -16096,18 +16323,22 @@ "AssetFullSyncDto": { "properties": { "lastId": { + "description": "Last asset ID (pagination)", "format": "uuid", "type": "string" }, "limit": { + "description": "Maximum number of assets to return", "minimum": 1, "type": "integer" }, "updatedUntil": { + "description": "Sync assets updated until this date", "format": "date-time", "type": "string" }, "userId": { + "description": "Filter by user ID", "format": "uuid", "type": "string" } @@ -16121,6 +16352,7 @@ "AssetIdsDto": { "properties": { "assetIds": { + "description": "Asset IDs", "items": { "format": "uuid", "type": "string" @@ -16136,9 +16368,11 @@ "AssetIdsResponseDto": { "properties": { "assetId": { + "description": "Asset ID", "type": "string" }, "error": { + "description": "Error reason if failed", "enum": [ "duplicate", "no_permission", @@ -16147,6 +16381,7 @@ "type": "string" }, "success": { + "description": "Whether operation succeeded", "type": "boolean" } }, @@ -16157,6 +16392,7 @@ "type": "object" }, "AssetJobName": { + "description": "Job name", "enum": [ "refresh-faces", "refresh-metadata", @@ -16168,6 +16404,7 @@ "AssetJobsDto": { "properties": { "assetIds": { + "description": "Asset IDs", "items": { "format": "uuid", "type": "string" @@ -16179,7 +16416,8 @@ { "$ref": "#/components/schemas/AssetJobName" } - ] + ], + "description": "Job name" } }, "required": [ @@ -16191,43 +16429,54 @@ "AssetMediaCreateDto": { "properties": { "assetData": { + "description": "Asset file data", "format": "binary", "type": "string" }, "deviceAssetId": { + "description": "Device asset ID", "type": "string" }, "deviceId": { + "description": "Device ID", "type": "string" }, "duration": { + "description": "Duration (for videos)", "type": "string" }, "fileCreatedAt": { + "description": "File creation date", "format": "date-time", "type": "string" }, "fileModifiedAt": { + "description": "File modification date", "format": "date-time", "type": "string" }, "filename": { + "description": "Filename", "type": "string" }, "isFavorite": { + "description": "Mark as favorite", "type": "boolean" }, "livePhotoVideoId": { + "description": "Live photo video ID", "format": "uuid", "type": "string" }, "metadata": { + "description": "Asset metadata items", "items": { "$ref": "#/components/schemas/AssetMetadataUpsertItemDto" }, "type": "array" }, "sidecarData": { + "description": "Sidecar file data", "format": "binary", "type": "string" }, @@ -16236,7 +16485,8 @@ { "$ref": "#/components/schemas/AssetVisibility" } - ] + ], + "description": "Asset visibility" } }, "required": [ @@ -16251,27 +16501,34 @@ "AssetMediaReplaceDto": { "properties": { "assetData": { + "description": "Asset file data", "format": "binary", "type": "string" }, "deviceAssetId": { + "description": "Device asset ID", "type": "string" }, "deviceId": { + "description": "Device ID", "type": "string" }, "duration": { + "description": "Duration (for videos)", "type": "string" }, "fileCreatedAt": { + "description": "File creation date", "format": "date-time", "type": "string" }, "fileModifiedAt": { + "description": "File modification date", "format": "date-time", "type": "string" }, "filename": { + "description": "Filename", "type": "string" } }, @@ -16287,6 +16544,7 @@ "AssetMediaResponseDto": { "properties": { "id": { + "description": "Asset media ID", "type": "string" }, "status": { @@ -16294,7 +16552,8 @@ { "$ref": "#/components/schemas/AssetMediaStatus" } - ] + ], + "description": "Upload status" } }, "required": [ @@ -16313,6 +16572,7 @@ "type": "string" }, "AssetMediaStatus": { + "description": "Upload status", "enum": [ "created", "replaced", @@ -16323,6 +16583,7 @@ "AssetMetadataBulkDeleteDto": { "properties": { "items": { + "description": "Metadata items to delete", "items": { "$ref": "#/components/schemas/AssetMetadataBulkDeleteItemDto" }, @@ -16337,10 +16598,12 @@ "AssetMetadataBulkDeleteItemDto": { "properties": { "assetId": { + "description": "Asset ID", "format": "uuid", "type": "string" }, "key": { + "description": "Metadata key", "type": "string" } }, @@ -16353,16 +16616,20 @@ "AssetMetadataBulkResponseDto": { "properties": { "assetId": { + "description": "Asset ID", "type": "string" }, "key": { + "description": "Metadata key", "type": "string" }, "updatedAt": { + "description": "Last update date", "format": "date-time", "type": "string" }, "value": { + "description": "Metadata value (object)", "type": "object" } }, @@ -16377,6 +16644,7 @@ "AssetMetadataBulkUpsertDto": { "properties": { "items": { + "description": "Metadata items to upsert", "items": { "$ref": "#/components/schemas/AssetMetadataBulkUpsertItemDto" }, @@ -16391,13 +16659,16 @@ "AssetMetadataBulkUpsertItemDto": { "properties": { "assetId": { + "description": "Asset ID", "format": "uuid", "type": "string" }, "key": { + "description": "Metadata key", "type": "string" }, "value": { + "description": "Metadata value (object)", "type": "object" } }, @@ -16411,13 +16682,16 @@ "AssetMetadataResponseDto": { "properties": { "key": { + "description": "Metadata key", "type": "string" }, "updatedAt": { + "description": "Last update date", "format": "date-time", "type": "string" }, "value": { + "description": "Metadata value (object)", "type": "object" } }, @@ -16431,6 +16705,7 @@ "AssetMetadataUpsertDto": { "properties": { "items": { + "description": "Metadata items to upsert", "items": { "$ref": "#/components/schemas/AssetMetadataUpsertItemDto" }, @@ -16445,9 +16720,11 @@ "AssetMetadataUpsertItemDto": { "properties": { "key": { + "description": "Metadata key", "type": "string" }, "value": { + "description": "Metadata value (object)", "type": "object" } }, @@ -16540,6 +16817,7 @@ "type": "object" }, "AssetOrder": { + "description": "Asset sort order", "enum": [ "asc", "desc" @@ -16549,7 +16827,7 @@ "AssetResponseDto": { "properties": { "checksum": { - "description": "base64 encoded sha1 hash", + "description": "Base64 encoded SHA1 hash", "type": "string" }, "createdAt": { @@ -16559,16 +16837,20 @@ "type": "string" }, "deviceAssetId": { + "description": "Device asset ID", "type": "string" }, "deviceId": { + "description": "Device ID", "type": "string" }, "duplicateId": { + "description": "Duplicate group ID", "nullable": true, "type": "string" }, "duration": { + "description": "Video duration (for videos)", "type": "string" }, "exifInfo": { @@ -16587,19 +16869,24 @@ "type": "string" }, "hasMetadata": { + "description": "Whether asset has metadata", "type": "boolean" }, "height": { + "description": "Asset height", "nullable": true, "type": "number" }, "id": { + "description": "Asset ID", "type": "string" }, "isArchived": { + "description": "Is archived", "type": "boolean" }, "isEdited": { + "description": "Is edited", "type": "boolean", "x-immich-history": [ { @@ -16614,16 +16901,21 @@ "x-immich-state": "Beta" }, "isFavorite": { + "description": "Is favorite", "type": "boolean" }, "isOffline": { + "description": "Is offline", "type": "boolean" }, "isTrashed": { + "description": "Is trashed", "type": "boolean" }, "libraryId": { "deprecated": true, + "description": "Library ID", + "format": "uuid", "nullable": true, "type": "string", "x-immich-history": [ @@ -16639,6 +16931,7 @@ "x-immich-state": "Deprecated" }, "livePhotoVideoId": { + "description": "Live photo video ID", "nullable": true, "type": "string" }, @@ -16649,18 +16942,22 @@ "type": "string" }, "originalFileName": { + "description": "Original file name", "type": "string" }, "originalMimeType": { + "description": "Original MIME type", "type": "string" }, "originalPath": { + "description": "Original file path", "type": "string" }, "owner": { "$ref": "#/components/schemas/UserResponseDto" }, "ownerId": { + "description": "Owner user ID", "type": "string" }, "people": { @@ -16671,6 +16968,7 @@ }, "resized": { "deprecated": true, + "description": "Is resized", "type": "boolean", "x-immich-history": [ { @@ -16699,6 +16997,7 @@ "type": "array" }, "thumbhash": { + "description": "Thumbhash for thumbnail generation", "nullable": true, "type": "string" }, @@ -16707,7 +17006,8 @@ { "$ref": "#/components/schemas/AssetTypeEnum" } - ] + ], + "description": "Asset type" }, "unassignedFaces": { "items": { @@ -16726,9 +17026,11 @@ { "$ref": "#/components/schemas/AssetVisibility" } - ] + ], + "description": "Asset visibility" }, "width": { + "description": "Asset width", "nullable": true, "type": "number" } @@ -16764,12 +17066,15 @@ "AssetStackResponseDto": { "properties": { "assetCount": { + "description": "Number of assets in stack", "type": "integer" }, "id": { + "description": "Stack ID", "type": "string" }, "primaryAssetId": { + "description": "Primary asset ID", "type": "string" } }, @@ -16783,12 +17088,15 @@ "AssetStatsResponseDto": { "properties": { "images": { + "description": "Number of images", "type": "integer" }, "total": { + "description": "Total number of assets", "type": "integer" }, "videos": { + "description": "Number of videos", "type": "integer" } }, @@ -16800,6 +17108,7 @@ "type": "object" }, "AssetTypeEnum": { + "description": "Asset type", "enum": [ "IMAGE", "VIDEO", @@ -16809,6 +17118,7 @@ "type": "string" }, "AssetVisibility": { + "description": "Asset visibility", "enum": [ "archive", "timeline", @@ -16818,6 +17128,7 @@ "type": "string" }, "AudioCodec": { + "description": "Target audio codec", "enum": [ "mp3", "aac", @@ -16829,18 +17140,23 @@ "AuthStatusResponseDto": { "properties": { "expiresAt": { + "description": "Session expiration date", "type": "string" }, "isElevated": { + "description": "Is elevated session", "type": "boolean" }, "password": { + "description": "Has password set", "type": "boolean" }, "pinCode": { + "description": "Has PIN code set", "type": "boolean" }, "pinExpiresAt": { + "description": "PIN expiration date", "type": "string" } }, @@ -16858,12 +17174,14 @@ { "$ref": "#/components/schemas/UserAvatarColor" } - ] + ], + "description": "Avatar color" } }, "type": "object" }, "BulkIdErrorReason": { + "description": "Error reason", "enum": [ "duplicate", "no_permission", @@ -16875,6 +17193,7 @@ "BulkIdResponseDto": { "properties": { "error": { + "description": "Error reason if failed", "enum": [ "duplicate", "no_permission", @@ -16884,9 +17203,11 @@ "type": "string" }, "id": { + "description": "ID", "type": "string" }, "success": { + "description": "Whether operation succeeded", "type": "boolean" } }, @@ -16899,6 +17220,7 @@ "BulkIdsDto": { "properties": { "ids": { + "description": "IDs to process", "items": { "format": "uuid", "type": "string" @@ -16914,9 +17236,11 @@ "CLIPConfig": { "properties": { "enabled": { + "description": "Whether the task is enabled", "type": "boolean" }, "modelName": { + "description": "Name of the model to use", "type": "string" } }, @@ -16927,6 +17251,7 @@ "type": "object" }, "CQMode": { + "description": "CQ mode", "enum": [ "auto", "cqp", @@ -16938,6 +17263,7 @@ "properties": { "gCastEnabled": { "default": false, + "description": "Whether Google Cast is enabled", "type": "boolean" } }, @@ -16949,6 +17275,7 @@ "CastUpdate": { "properties": { "gCastEnabled": { + "description": "Whether Google Cast is enabled", "type": "boolean" } }, @@ -16958,14 +17285,17 @@ "properties": { "invalidateSessions": { "default": false, + "description": "Invalidate all other sessions", "type": "boolean" }, "newPassword": { + "description": "New password (min 8 characters)", "example": "password", "minLength": 8, "type": "string" }, "password": { + "description": "Current password", "example": "password", "type": "string" } @@ -16979,6 +17309,7 @@ "CheckExistingAssetsDto": { "properties": { "deviceAssetIds": { + "description": "Device asset IDs to check", "items": { "type": "string" }, @@ -16986,6 +17317,7 @@ "type": "array" }, "deviceId": { + "description": "Device ID", "type": "string" } }, @@ -16998,6 +17330,7 @@ "CheckExistingAssetsResponseDto": { "properties": { "existingIds": { + "description": "Existing asset IDs", "items": { "type": "string" }, @@ -17010,6 +17343,7 @@ "type": "object" }, "Colorspace": { + "description": "Colorspace", "enum": [ "srgb", "p3" @@ -17019,9 +17353,11 @@ "ContributorCountResponseDto": { "properties": { "assetCount": { + "description": "Number of assets contributed", "type": "integer" }, "userId": { + "description": "User ID", "type": "string" } }, @@ -17034,15 +17370,18 @@ "CreateAlbumDto": { "properties": { "albumName": { + "description": "Album name", "type": "string" }, "albumUsers": { + "description": "Album users", "items": { "$ref": "#/components/schemas/AlbumUserCreateDto" }, "type": "array" }, "assetIds": { + "description": "Initial asset IDs", "items": { "format": "uuid", "type": "string" @@ -17050,6 +17389,7 @@ "type": "array" }, "description": { + "description": "Album description", "type": "string" } }, @@ -17061,6 +17401,7 @@ "CreateLibraryDto": { "properties": { "exclusionPatterns": { + "description": "Exclusion patterns (max 128)", "items": { "type": "string" }, @@ -17069,6 +17410,7 @@ "uniqueItems": true }, "importPaths": { + "description": "Import paths (max 128)", "items": { "type": "string" }, @@ -17077,9 +17419,11 @@ "uniqueItems": true }, "name": { + "description": "Library name", "type": "string" }, "ownerId": { + "description": "Owner user ID", "format": "uuid", "type": "string" } @@ -17092,6 +17436,7 @@ "CreateProfileImageDto": { "properties": { "file": { + "description": "Profile image file", "format": "binary", "type": "string" } @@ -17104,13 +17449,16 @@ "CreateProfileImageResponseDto": { "properties": { "profileChangedAt": { + "description": "Profile image change date", "format": "date-time", "type": "string" }, "profileImagePath": { + "description": "Profile image file path", "type": "string" }, "userId": { + "description": "User ID", "type": "string" } }, @@ -17155,12 +17503,15 @@ "DatabaseBackupConfig": { "properties": { "cronExpression": { + "description": "Cron expression", "type": "string" }, "enabled": { + "description": "Enabled", "type": "boolean" }, "keepLastAmount": { + "description": "Keep last amount", "minimum": 1, "type": "number" } @@ -17227,12 +17578,14 @@ "DownloadArchiveInfo": { "properties": { "assetIds": { + "description": "Asset IDs in this archive", "items": { "type": "string" }, "type": "array" }, "size": { + "description": "Archive size in bytes", "type": "integer" } }, @@ -17245,14 +17598,17 @@ "DownloadInfoDto": { "properties": { "albumId": { + "description": "Album ID to download", "format": "uuid", "type": "string" }, "archiveSize": { + "description": "Archive size limit in bytes", "minimum": 1, "type": "integer" }, "assetIds": { + "description": "Asset IDs to download", "items": { "format": "uuid", "type": "string" @@ -17260,6 +17616,7 @@ "type": "array" }, "userId": { + "description": "User ID to download assets from", "format": "uuid", "type": "string" } @@ -17269,10 +17626,12 @@ "DownloadResponse": { "properties": { "archiveSize": { + "description": "Maximum archive size in bytes", "type": "integer" }, "includeEmbeddedVideos": { "default": false, + "description": "Whether to include embedded videos in downloads", "type": "boolean" } }, @@ -17285,12 +17644,14 @@ "DownloadResponseDto": { "properties": { "archives": { + "description": "Archive information", "items": { "$ref": "#/components/schemas/DownloadArchiveInfo" }, "type": "array" }, "totalSize": { + "description": "Total size in bytes", "type": "integer" } }, @@ -17303,10 +17664,12 @@ "DownloadUpdate": { "properties": { "archiveSize": { + "description": "Maximum archive size in bytes", "minimum": 1, "type": "integer" }, "includeEmbeddedVideos": { + "description": "Whether to include embedded videos in downloads", "type": "boolean" } }, @@ -17315,9 +17678,11 @@ "DuplicateDetectionConfig": { "properties": { "enabled": { + "description": "Whether the task is enabled", "type": "boolean" }, "maxDistance": { + "description": "Maximum distance threshold for duplicate detection", "format": "double", "maximum": 0.1, "minimum": 0.001, @@ -17333,12 +17698,14 @@ "DuplicateResponseDto": { "properties": { "assets": { + "description": "Duplicate assets", "items": { "$ref": "#/components/schemas/AssetResponseDto" }, "type": "array" }, "duplicateId": { + "description": "Duplicate group ID", "type": "string" } }, @@ -17351,12 +17718,15 @@ "EmailNotificationsResponse": { "properties": { "albumInvite": { + "description": "Whether to receive email notifications for album invites", "type": "boolean" }, "albumUpdate": { + "description": "Whether to receive email notifications for album updates", "type": "boolean" }, "enabled": { + "description": "Whether email notifications are enabled", "type": "boolean" } }, @@ -17370,12 +17740,15 @@ "EmailNotificationsUpdate": { "properties": { "albumInvite": { + "description": "Whether to receive email notifications for album invites", "type": "boolean" }, "albumUpdate": { + "description": "Whether to receive email notifications for album updates", "type": "boolean" }, "enabled": { + "description": "Whether email notifications are enabled", "type": "boolean" } }, @@ -17385,114 +17758,136 @@ "properties": { "city": { "default": null, + "description": "City name", "nullable": true, "type": "string" }, "country": { "default": null, + "description": "Country name", "nullable": true, "type": "string" }, "dateTimeOriginal": { "default": null, + "description": "Original date/time", "format": "date-time", "nullable": true, "type": "string" }, "description": { "default": null, + "description": "Image description", "nullable": true, "type": "string" }, "exifImageHeight": { "default": null, + "description": "Image height in pixels", "nullable": true, "type": "number" }, "exifImageWidth": { "default": null, + "description": "Image width in pixels", "nullable": true, "type": "number" }, "exposureTime": { "default": null, + "description": "Exposure time", "nullable": true, "type": "string" }, "fNumber": { "default": null, + "description": "F-number (aperture)", "nullable": true, "type": "number" }, "fileSizeInByte": { "default": null, + "description": "File size in bytes", "format": "int64", "nullable": true, "type": "integer" }, "focalLength": { "default": null, + "description": "Focal length in mm", "nullable": true, "type": "number" }, "iso": { "default": null, + "description": "ISO sensitivity", "nullable": true, "type": "number" }, "latitude": { "default": null, + "description": "GPS latitude", "nullable": true, "type": "number" }, "lensModel": { "default": null, + "description": "Lens model", "nullable": true, "type": "string" }, "longitude": { "default": null, + "description": "GPS longitude", "nullable": true, "type": "number" }, "make": { "default": null, + "description": "Camera make", "nullable": true, "type": "string" }, "model": { "default": null, + "description": "Camera model", "nullable": true, "type": "string" }, "modifyDate": { "default": null, + "description": "Modification date/time", "format": "date-time", "nullable": true, "type": "string" }, "orientation": { "default": null, + "description": "Image orientation", "nullable": true, "type": "string" }, "projectionType": { "default": null, + "description": "Projection type", "nullable": true, "type": "string" }, "rating": { "default": null, + "description": "Rating", "nullable": true, "type": "number" }, "state": { "default": null, + "description": "State/province name", "nullable": true, "type": "string" }, "timeZone": { "default": null, + "description": "Time zone", "nullable": true, "type": "string" } @@ -17502,6 +17897,7 @@ "FaceDto": { "properties": { "id": { + "description": "Face ID", "format": "uuid", "type": "string" } @@ -17514,25 +17910,30 @@ "FacialRecognitionConfig": { "properties": { "enabled": { + "description": "Whether the task is enabled", "type": "boolean" }, "maxDistance": { + "description": "Maximum distance threshold for face recognition", "format": "double", "maximum": 2, "minimum": 0.1, "type": "number" }, "minFaces": { + "description": "Minimum number of faces required for recognition", "minimum": 1, "type": "integer" }, "minScore": { + "description": "Minimum confidence score for face detection", "format": "double", "maximum": 1, "minimum": 0.1, "type": "number" }, "modelName": { + "description": "Name of the model to use", "type": "string" } }, @@ -17549,10 +17950,12 @@ "properties": { "enabled": { "default": false, + "description": "Whether folders are enabled", "type": "boolean" }, "sidebarWeb": { "default": false, + "description": "Whether folders appear in web sidebar", "type": "boolean" } }, @@ -17565,15 +17968,18 @@ "FoldersUpdate": { "properties": { "enabled": { + "description": "Whether folders are enabled", "type": "boolean" }, "sidebarWeb": { + "description": "Whether folders appear in web sidebar", "type": "boolean" } }, "type": "object" }, "ImageFormat": { + "description": "Image format", "enum": [ "jpeg", "webp" @@ -17587,7 +17993,8 @@ { "$ref": "#/components/schemas/ManualJobName" } - ] + ], + "description": "Job name" } }, "required": [ @@ -17596,6 +18003,7 @@ "type": "object" }, "JobName": { + "description": "Job name", "enum": [ "AssetDelete", "AssetDeleteCheck", @@ -17659,6 +18067,7 @@ "JobSettingsDto": { "properties": { "concurrency": { + "description": "Concurrency", "minimum": 1, "type": "integer" } @@ -17671,39 +18080,48 @@ "LibraryResponseDto": { "properties": { "assetCount": { + "description": "Number of assets", "type": "integer" }, "createdAt": { + "description": "Creation date", "format": "date-time", "type": "string" }, "exclusionPatterns": { + "description": "Exclusion patterns", "items": { "type": "string" }, "type": "array" }, "id": { + "description": "Library ID", "type": "string" }, "importPaths": { + "description": "Import paths", "items": { "type": "string" }, "type": "array" }, "name": { + "description": "Library name", "type": "string" }, "ownerId": { + "description": "Owner user ID", "type": "string" }, "refreshedAt": { + "description": "Last refresh date", "format": "date-time", "nullable": true, "type": "string" }, "updatedAt": { + "description": "Last update date", "format": "date-time", "type": "string" } @@ -17725,19 +18143,23 @@ "properties": { "photos": { "default": 0, + "description": "Number of photos", "type": "integer" }, "total": { "default": 0, + "description": "Total number of assets", "type": "integer" }, "usage": { "default": 0, + "description": "Storage usage in bytes", "format": "int64", "type": "integer" }, "videos": { "default": 0, + "description": "Number of videos", "type": "integer" } }, @@ -17752,9 +18174,11 @@ "LicenseKeyDto": { "properties": { "activationKey": { + "description": "Activation key", "type": "string" }, "licenseKey": { + "description": "License key (format: IM(SV|CL)(-XXXX){8})", "pattern": "/IM(SV|CL)(-[\\dA-Za-z]{4}){8}/", "type": "string" } @@ -17768,13 +18192,16 @@ "LicenseResponseDto": { "properties": { "activatedAt": { + "description": "Activation date", "format": "date-time", "type": "string" }, "activationKey": { + "description": "Activation key", "type": "string" }, "licenseKey": { + "description": "License key (format: IM(SV|CL)(-XXXX){8})", "pattern": "/IM(SV|CL)(-[\\dA-Za-z]{4}){8}/", "type": "string" } @@ -17800,11 +18227,13 @@ "LoginCredentialDto": { "properties": { "email": { + "description": "User email", "example": "testuser@email.com", "format": "email", "type": "string" }, "password": { + "description": "User password", "example": "password", "type": "string" } @@ -17818,27 +18247,35 @@ "LoginResponseDto": { "properties": { "accessToken": { + "description": "Access token", "type": "string" }, "isAdmin": { + "description": "Is admin user", "type": "boolean" }, "isOnboarded": { + "description": "Is onboarded", "type": "boolean" }, "name": { + "description": "User name", "type": "string" }, "profileImagePath": { + "description": "Profile image path", "type": "string" }, "shouldChangePassword": { + "description": "Should change password", "type": "boolean" }, "userEmail": { + "description": "User email", "type": "string" }, "userId": { + "description": "User ID", "type": "string" } }, @@ -17857,9 +18294,11 @@ "LogoutResponseDto": { "properties": { "redirectUri": { + "description": "Redirect URI", "type": "string" }, "successful": { + "description": "Logout successful", "type": "boolean" } }, @@ -17872,6 +18311,7 @@ "MachineLearningAvailabilityChecksDto": { "properties": { "enabled": { + "description": "Enabled", "type": "boolean" }, "interval": { @@ -17889,6 +18329,7 @@ "type": "object" }, "MaintenanceAction": { + "description": "Maintenance action", "enum": [ "start", "end", @@ -17900,6 +18341,7 @@ "MaintenanceAuthDto": { "properties": { "username": { + "description": "Maintenance username", "type": "string" } }, @@ -17925,6 +18367,7 @@ "MaintenanceDetectInstallStorageFolderDto": { "properties": { "files": { + "description": "Number of files in the folder", "type": "number" }, "folder": { @@ -17932,12 +18375,15 @@ { "$ref": "#/components/schemas/StorageFolder" } - ] + ], + "description": "Storage folder" }, "readable": { + "description": "Whether the folder is readable", "type": "boolean" }, "writable": { + "description": "Whether the folder is writable", "type": "boolean" } }, @@ -17952,6 +18398,7 @@ "MaintenanceLoginDto": { "properties": { "token": { + "description": "Maintenance token", "type": "string" } }, @@ -17964,7 +18411,8 @@ { "$ref": "#/components/schemas/MaintenanceAction" } - ] + ], + "description": "Maintenance action" }, "active": { "type": "boolean" @@ -17986,6 +18434,7 @@ "type": "object" }, "ManualJobName": { + "description": "Job name", "enum": [ "person-cleanup", "tag-cleanup", @@ -17999,25 +18448,31 @@ "MapMarkerResponseDto": { "properties": { "city": { + "description": "City name", "nullable": true, "type": "string" }, "country": { + "description": "Country name", "nullable": true, "type": "string" }, "id": { + "description": "Asset ID", "type": "string" }, "lat": { + "description": "Latitude", "format": "double", "type": "number" }, "lon": { + "description": "Longitude", "format": "double", "type": "number" }, "state": { + "description": "State/Province name", "nullable": true, "type": "string" } @@ -18035,14 +18490,17 @@ "MapReverseGeocodeResponseDto": { "properties": { "city": { + "description": "City name", "nullable": true, "type": "string" }, "country": { + "description": "Country name", "nullable": true, "type": "string" }, "state": { + "description": "State/Province name", "nullable": true, "type": "string" } @@ -18058,10 +18516,12 @@ "properties": { "duration": { "default": 5, + "description": "Memory duration in seconds", "type": "integer" }, "enabled": { "default": true, + "description": "Whether memories are enabled", "type": "boolean" } }, @@ -18074,10 +18534,12 @@ "MemoriesUpdate": { "properties": { "duration": { + "description": "Memory duration in seconds", "minimum": 1, "type": "integer" }, "enabled": { + "description": "Whether memories are enabled", "type": "boolean" } }, @@ -18086,6 +18548,7 @@ "MemoryCreateDto": { "properties": { "assetIds": { + "description": "Asset IDs to associate with memory", "items": { "format": "uuid", "type": "string" @@ -18096,13 +18559,16 @@ "$ref": "#/components/schemas/OnThisDayDto" }, "isSaved": { + "description": "Is memory saved", "type": "boolean" }, "memoryAt": { + "description": "Memory date", "format": "date-time", "type": "string" }, "seenAt": { + "description": "Date when memory was seen", "format": "date-time", "type": "string" }, @@ -18111,7 +18577,8 @@ { "$ref": "#/components/schemas/MemoryType" } - ] + ], + "description": "Memory type" } }, "required": [ @@ -18130,6 +18597,7 @@ "type": "array" }, "createdAt": { + "description": "Creation date", "format": "date-time", "type": "string" }, @@ -18137,31 +18605,39 @@ "$ref": "#/components/schemas/OnThisDayDto" }, "deletedAt": { + "description": "Deletion date", "format": "date-time", "type": "string" }, "hideAt": { + "description": "Date when memory should be hidden", "format": "date-time", "type": "string" }, "id": { + "description": "Memory ID", "type": "string" }, "isSaved": { + "description": "Is memory saved", "type": "boolean" }, "memoryAt": { + "description": "Memory date", "format": "date-time", "type": "string" }, "ownerId": { + "description": "Owner user ID", "type": "string" }, "seenAt": { + "description": "Date when memory was seen", "format": "date-time", "type": "string" }, "showAt": { + "description": "Date when memory should be shown", "format": "date-time", "type": "string" }, @@ -18170,9 +18646,11 @@ { "$ref": "#/components/schemas/MemoryType" } - ] + ], + "description": "Memory type" }, "updatedAt": { + "description": "Last update date", "format": "date-time", "type": "string" } @@ -18201,6 +18679,7 @@ "MemoryStatisticsResponseDto": { "properties": { "total": { + "description": "Total number of memories", "type": "integer" } }, @@ -18218,13 +18697,16 @@ "MemoryUpdateDto": { "properties": { "isSaved": { + "description": "Is memory saved", "type": "boolean" }, "memoryAt": { + "description": "Memory date", "format": "date-time", "type": "string" }, "seenAt": { + "description": "Date when memory was seen", "format": "date-time", "type": "string" } @@ -18234,6 +18716,7 @@ "MergePersonDto": { "properties": { "ids": { + "description": "Person IDs to merge", "items": { "format": "uuid", "type": "string" @@ -18249,6 +18732,7 @@ "MetadataSearchDto": { "properties": { "albumIds": { + "description": "Filter by album IDs", "items": { "format": "uuid", "type": "string" @@ -18256,72 +18740,92 @@ "type": "array" }, "checksum": { + "description": "Filter by file checksum", "type": "string" }, "city": { + "description": "Filter by city name", "nullable": true, "type": "string" }, "country": { + "description": "Filter by country name", "nullable": true, "type": "string" }, "createdAfter": { + "description": "Filter by creation date (after)", "format": "date-time", "type": "string" }, "createdBefore": { + "description": "Filter by creation date (before)", "format": "date-time", "type": "string" }, "description": { + "description": "Filter by description text", "type": "string" }, "deviceAssetId": { + "description": "Filter by device asset ID", "type": "string" }, "deviceId": { + "description": "Device ID to filter by", "type": "string" }, "encodedVideoPath": { + "description": "Filter by encoded video file path", "type": "string" }, "id": { + "description": "Filter by asset ID", "format": "uuid", "type": "string" }, "isEncoded": { + "description": "Filter by encoded status", "type": "boolean" }, "isFavorite": { + "description": "Filter by favorite status", "type": "boolean" }, "isMotion": { + "description": "Filter by motion photo status", "type": "boolean" }, "isNotInAlbum": { + "description": "Filter assets not in any album", "type": "boolean" }, "isOffline": { + "description": "Filter by offline status", "type": "boolean" }, "lensModel": { + "description": "Filter by lens model", "nullable": true, "type": "string" }, "libraryId": { + "description": "Library ID to filter by", "format": "uuid", "nullable": true, "type": "string" }, "make": { + "description": "Filter by camera make", "type": "string" }, "model": { + "description": "Filter by camera model", "nullable": true, "type": "string" }, "ocr": { + "description": "Filter by OCR text content", "type": "string" }, "order": { @@ -18330,19 +18834,24 @@ "$ref": "#/components/schemas/AssetOrder" } ], - "default": "desc" + "default": "desc", + "description": "Sort order" }, "originalFileName": { + "description": "Filter by original file name", "type": "string" }, "originalPath": { + "description": "Filter by original file path", "type": "string" }, "page": { + "description": "Page number", "minimum": 1, "type": "number" }, "personIds": { + "description": "Filter by person IDs", "items": { "format": "uuid", "type": "string" @@ -18350,23 +18859,28 @@ "type": "array" }, "previewPath": { + "description": "Filter by preview file path", "type": "string" }, "rating": { + "description": "Filter by rating", "maximum": 5, "minimum": -1, "type": "number" }, "size": { + "description": "Number of results to return", "maximum": 1000, "minimum": 1, "type": "number" }, "state": { + "description": "Filter by state/province name", "nullable": true, "type": "string" }, "tagIds": { + "description": "Filter by tag IDs", "items": { "format": "uuid", "type": "string" @@ -18375,21 +18889,26 @@ "type": "array" }, "takenAfter": { + "description": "Filter by taken date (after)", "format": "date-time", "type": "string" }, "takenBefore": { + "description": "Filter by taken date (before)", "format": "date-time", "type": "string" }, "thumbnailPath": { + "description": "Filter by thumbnail file path", "type": "string" }, "trashedAfter": { + "description": "Filter by trash date (after)", "format": "date-time", "type": "string" }, "trashedBefore": { + "description": "Filter by trash date (before)", "format": "date-time", "type": "string" }, @@ -18398,13 +18917,16 @@ { "$ref": "#/components/schemas/AssetTypeEnum" } - ] + ], + "description": "Asset type filter" }, "updatedAfter": { + "description": "Filter by update date (after)", "format": "date-time", "type": "string" }, "updatedBefore": { + "description": "Filter by update date (before)", "format": "date-time", "type": "string" }, @@ -18413,18 +18935,23 @@ { "$ref": "#/components/schemas/AssetVisibility" } - ] + ], + "description": "Filter by visibility" }, "withDeleted": { + "description": "Include deleted assets", "type": "boolean" }, "withExif": { + "description": "Include EXIF data in response", "type": "boolean" }, "withPeople": { + "description": "Include assets with people", "type": "boolean" }, "withStacked": { + "description": "Include stacked assets", "type": "boolean" } }, @@ -18457,9 +18984,11 @@ "NotificationCreateDto": { "properties": { "data": { + "description": "Additional notification data", "type": "object" }, "description": { + "description": "Notification description", "nullable": true, "type": "string" }, @@ -18468,14 +18997,17 @@ { "$ref": "#/components/schemas/NotificationLevel" } - ] + ], + "description": "Notification level" }, "readAt": { + "description": "Date when notification was read", "format": "date-time", "nullable": true, "type": "string" }, "title": { + "description": "Notification title", "type": "string" }, "type": { @@ -18483,9 +19015,11 @@ { "$ref": "#/components/schemas/NotificationType" } - ] + ], + "description": "Notification type" }, "userId": { + "description": "User ID to send notification to", "format": "uuid", "type": "string" } @@ -18499,6 +19033,7 @@ "NotificationDeleteAllDto": { "properties": { "ids": { + "description": "Notification IDs to delete", "items": { "format": "uuid", "type": "string" @@ -18514,16 +19049,20 @@ "NotificationDto": { "properties": { "createdAt": { + "description": "Creation date", "format": "date-time", "type": "string" }, "data": { + "description": "Additional notification data", "type": "object" }, "description": { + "description": "Notification description", "type": "string" }, "id": { + "description": "Notification ID", "type": "string" }, "level": { @@ -18531,13 +19070,16 @@ { "$ref": "#/components/schemas/NotificationLevel" } - ] + ], + "description": "Notification level" }, "readAt": { + "description": "Date when notification was read", "format": "date-time", "type": "string" }, "title": { + "description": "Notification title", "type": "string" }, "type": { @@ -18545,7 +19087,8 @@ { "$ref": "#/components/schemas/NotificationType" } - ] + ], + "description": "Notification type" } }, "required": [ @@ -18580,6 +19123,7 @@ "NotificationUpdateAllDto": { "properties": { "ids": { + "description": "Notification IDs to update", "items": { "format": "uuid", "type": "string" @@ -18587,6 +19131,7 @@ "type": "array" }, "readAt": { + "description": "Date when notifications were read", "format": "date-time", "nullable": true, "type": "string" @@ -18600,6 +19145,7 @@ "NotificationUpdateDto": { "properties": { "readAt": { + "description": "Date when notification was read", "format": "date-time", "nullable": true, "type": "string" @@ -18610,6 +19156,7 @@ "OAuthAuthorizeResponseDto": { "properties": { "url": { + "description": "OAuth authorization URL", "type": "string" } }, @@ -18621,12 +19168,15 @@ "OAuthCallbackDto": { "properties": { "codeVerifier": { + "description": "OAuth code verifier (PKCE)", "type": "string" }, "state": { + "description": "OAuth state parameter", "type": "string" }, "url": { + "description": "OAuth callback URL", "type": "string" } }, @@ -18638,12 +19188,15 @@ "OAuthConfigDto": { "properties": { "codeChallenge": { + "description": "OAuth code challenge (PKCE)", "type": "string" }, "redirectUri": { + "description": "OAuth redirect URI", "type": "string" }, "state": { + "description": "OAuth state parameter", "type": "string" } }, @@ -18653,6 +19206,7 @@ "type": "object" }, "OAuthTokenEndpointAuthMethod": { + "description": "Token endpoint auth method", "enum": [ "client_secret_post", "client_secret_basic" @@ -18662,25 +19216,30 @@ "OcrConfig": { "properties": { "enabled": { + "description": "Whether the task is enabled", "type": "boolean" }, "maxResolution": { + "description": "Maximum resolution for OCR processing", "minimum": 1, "type": "integer" }, "minDetectionScore": { + "description": "Minimum confidence score for text detection", "format": "double", "maximum": 1, "minimum": 0.1, "type": "number" }, "minRecognitionScore": { + "description": "Minimum confidence score for text recognition", "format": "double", "maximum": 1, "minimum": 0.1, "type": "number" }, "modelName": { + "description": "Name of the model to use", "type": "string" } }, @@ -18696,6 +19255,7 @@ "OnThisDayDto": { "properties": { "year": { + "description": "Year for on this day memory", "minimum": 1, "type": "number" } @@ -18708,6 +19268,7 @@ "OnboardingDto": { "properties": { "isOnboarded": { + "description": "Is user onboarded", "type": "boolean" } }, @@ -18719,6 +19280,7 @@ "OnboardingResponseDto": { "properties": { "isOnboarded": { + "description": "Is user onboarded", "type": "boolean" } }, @@ -18730,6 +19292,7 @@ "PartnerCreateDto": { "properties": { "sharedWithId": { + "description": "User ID to share with", "format": "uuid", "type": "string" } @@ -18753,25 +19316,32 @@ { "$ref": "#/components/schemas/UserAvatarColor" } - ] + ], + "description": "Avatar color" }, "email": { + "description": "User email", "type": "string" }, "id": { + "description": "User ID", "type": "string" }, "inTimeline": { + "description": "Show in timeline", "type": "boolean" }, "name": { + "description": "User name", "type": "string" }, "profileChangedAt": { + "description": "Profile change date", "format": "date-time", "type": "string" }, "profileImagePath": { + "description": "Profile image path", "type": "string" } }, @@ -18788,6 +19358,7 @@ "PartnerUpdateDto": { "properties": { "inTimeline": { + "description": "Show partner assets in timeline", "type": "boolean" } }, @@ -18800,10 +19371,12 @@ "properties": { "enabled": { "default": true, + "description": "Whether people are enabled", "type": "boolean" }, "sidebarWeb": { "default": false, + "description": "Whether people appear in web sidebar", "type": "boolean" } }, @@ -18816,6 +19389,7 @@ "PeopleResponseDto": { "properties": { "hasNextPage": { + "description": "Whether there are more pages", "type": "boolean", "x-immich-history": [ { @@ -18830,15 +19404,18 @@ "x-immich-state": "Stable" }, "hidden": { + "description": "Number of hidden people", "type": "integer" }, "people": { + "description": "List of people", "items": { "$ref": "#/components/schemas/PersonResponseDto" }, "type": "array" }, "total": { + "description": "Total number of people", "type": "integer" } }, @@ -18852,9 +19429,11 @@ "PeopleUpdate": { "properties": { "enabled": { + "description": "Whether people are enabled", "type": "boolean" }, "sidebarWeb": { + "description": "Whether people appear in web sidebar", "type": "boolean" } }, @@ -18863,6 +19442,7 @@ "PeopleUpdateDto": { "properties": { "people": { + "description": "People to update", "items": { "$ref": "#/components/schemas/PeopleUpdateItem" }, @@ -18877,33 +19457,35 @@ "PeopleUpdateItem": { "properties": { "birthDate": { - "description": "Person date of birth.\nNote: the mobile app cannot currently set the birth date to null.", + "description": "Person date of birth", "format": "date", "nullable": true, "type": "string" }, "color": { + "description": "Person color (hex)", "nullable": true, "type": "string" }, "featureFaceAssetId": { - "description": "Asset is used to get the feature face thumbnail.", + "description": "Asset ID used for feature face thumbnail", "format": "uuid", "type": "string" }, "id": { - "description": "Person id.", + "description": "Person ID", "type": "string" }, "isFavorite": { + "description": "Mark as favorite", "type": "boolean" }, "isHidden": { - "description": "Person visibility", + "description": "Person visibility (hidden)", "type": "boolean" }, "name": { - "description": "Person name.", + "description": "Person name", "type": "string" } }, @@ -18913,6 +19495,7 @@ "type": "object" }, "Permission": { + "description": "List of permissions", "enum": [ "all", "activity.create", @@ -19076,24 +19659,26 @@ "PersonCreateDto": { "properties": { "birthDate": { - "description": "Person date of birth.\nNote: the mobile app cannot currently set the birth date to null.", + "description": "Person date of birth", "format": "date", "nullable": true, "type": "string" }, "color": { + "description": "Person color (hex)", "nullable": true, "type": "string" }, "isFavorite": { + "description": "Mark as favorite", "type": "boolean" }, "isHidden": { - "description": "Person visibility", + "description": "Person visibility (hidden)", "type": "boolean" }, "name": { - "description": "Person name.", + "description": "Person name", "type": "string" } }, @@ -19102,11 +19687,13 @@ "PersonResponseDto": { "properties": { "birthDate": { + "description": "Person date of birth", "format": "date", "nullable": true, "type": "string" }, "color": { + "description": "Person color (hex)", "type": "string", "x-immich-history": [ { @@ -19121,9 +19708,11 @@ "x-immich-state": "Stable" }, "id": { + "description": "Person ID", "type": "string" }, "isFavorite": { + "description": "Is favorite", "type": "boolean", "x-immich-history": [ { @@ -19138,15 +19727,19 @@ "x-immich-state": "Stable" }, "isHidden": { + "description": "Is hidden", "type": "boolean" }, "name": { + "description": "Person name", "type": "string" }, "thumbnailPath": { + "description": "Thumbnail path", "type": "string" }, "updatedAt": { + "description": "Last update date", "format": "date-time", "type": "string", "x-immich-history": [ @@ -19174,6 +19767,7 @@ "PersonStatisticsResponseDto": { "properties": { "assets": { + "description": "Number of assets", "type": "integer" } }, @@ -19185,29 +19779,31 @@ "PersonUpdateDto": { "properties": { "birthDate": { - "description": "Person date of birth.\nNote: the mobile app cannot currently set the birth date to null.", + "description": "Person date of birth", "format": "date", "nullable": true, "type": "string" }, "color": { + "description": "Person color (hex)", "nullable": true, "type": "string" }, "featureFaceAssetId": { - "description": "Asset is used to get the feature face thumbnail.", + "description": "Asset ID used for feature face thumbnail", "format": "uuid", "type": "string" }, "isFavorite": { + "description": "Mark as favorite", "type": "boolean" }, "isHidden": { - "description": "Person visibility", + "description": "Person visibility (hidden)", "type": "boolean" }, "name": { - "description": "Person name.", + "description": "Person name", "type": "string" } }, @@ -19216,11 +19812,13 @@ "PersonWithFacesResponseDto": { "properties": { "birthDate": { + "description": "Person date of birth", "format": "date", "nullable": true, "type": "string" }, "color": { + "description": "Person color (hex)", "type": "string", "x-immich-history": [ { @@ -19235,15 +19833,18 @@ "x-immich-state": "Stable" }, "faces": { + "description": "Face detections", "items": { "$ref": "#/components/schemas/AssetFaceWithoutPersonResponseDto" }, "type": "array" }, "id": { + "description": "Person ID", "type": "string" }, "isFavorite": { + "description": "Is favorite", "type": "boolean", "x-immich-history": [ { @@ -19258,15 +19859,19 @@ "x-immich-state": "Stable" }, "isHidden": { + "description": "Is hidden", "type": "boolean" }, "name": { + "description": "Person name", "type": "string" }, "thumbnailPath": { + "description": "Thumbnail path", "type": "string" }, "updatedAt": { + "description": "Last update date", "format": "date-time", "type": "string", "x-immich-history": [ @@ -19295,13 +19900,16 @@ "PinCodeChangeDto": { "properties": { "newPinCode": { + "description": "New PIN code (4-6 digits)", "example": "123456", "type": "string" }, "password": { + "description": "User password (required if PIN code is not provided)", "type": "string" }, "pinCode": { + "description": "New PIN code (4-6 digits)", "example": "123456", "type": "string" } @@ -19314,9 +19922,11 @@ "PinCodeResetDto": { "properties": { "password": { + "description": "User password (required if PIN code is not provided)", "type": "string" }, "pinCode": { + "description": "New PIN code (4-6 digits)", "example": "123456", "type": "string" } @@ -19326,6 +19936,7 @@ "PinCodeSetupDto": { "properties": { "pinCode": { + "description": "PIN code (4-6 digits)", "example": "123456", "type": "string" } @@ -19338,18 +19949,23 @@ "PlacesResponseDto": { "properties": { "admin1name": { + "description": "Administrative level 1 name (state/province)", "type": "string" }, "admin2name": { + "description": "Administrative level 2 name (county/district)", "type": "string" }, "latitude": { + "description": "Latitude coordinate", "type": "number" }, "longitude": { + "description": "Longitude coordinate", "type": "number" }, "name": { + "description": "Place name", "type": "string" } }, @@ -19363,28 +19979,35 @@ "PluginActionResponseDto": { "properties": { "description": { + "description": "Action description", "type": "string" }, "id": { + "description": "Action ID", "type": "string" }, "methodName": { + "description": "Method name", "type": "string" }, "pluginId": { + "description": "Plugin ID", "type": "string" }, "schema": { + "description": "Action schema", "nullable": true, "type": "object" }, "supportedContexts": { + "description": "Supported contexts", "items": { "$ref": "#/components/schemas/PluginContextType" }, "type": "array" }, "title": { + "description": "Action title", "type": "string" } }, @@ -19400,6 +20023,7 @@ "type": "object" }, "PluginContextType": { + "description": "Context type", "enum": [ "asset", "album", @@ -19410,28 +20034,35 @@ "PluginFilterResponseDto": { "properties": { "description": { + "description": "Filter description", "type": "string" }, "id": { + "description": "Filter ID", "type": "string" }, "methodName": { + "description": "Method name", "type": "string" }, "pluginId": { + "description": "Plugin ID", "type": "string" }, "schema": { + "description": "Filter schema", "nullable": true, "type": "object" }, "supportedContexts": { + "description": "Supported contexts", "items": { "$ref": "#/components/schemas/PluginContextType" }, "type": "array" }, "title": { + "description": "Filter title", "type": "string" } }, @@ -19449,39 +20080,49 @@ "PluginResponseDto": { "properties": { "actions": { + "description": "Plugin actions", "items": { "$ref": "#/components/schemas/PluginActionResponseDto" }, "type": "array" }, "author": { + "description": "Plugin author", "type": "string" }, "createdAt": { + "description": "Creation date", "type": "string" }, "description": { + "description": "Plugin description", "type": "string" }, "filters": { + "description": "Plugin filters", "items": { "$ref": "#/components/schemas/PluginFilterResponseDto" }, "type": "array" }, "id": { + "description": "Plugin ID", "type": "string" }, "name": { + "description": "Plugin name", "type": "string" }, "title": { + "description": "Plugin title", "type": "string" }, "updatedAt": { + "description": "Last update date", "type": "string" }, "version": { + "description": "Plugin version", "type": "string" } }, @@ -19506,14 +20147,16 @@ { "$ref": "#/components/schemas/PluginContextType" } - ] + ], + "description": "Context type" }, "type": { "allOf": [ { "$ref": "#/components/schemas/PluginTriggerType" } - ] + ], + "description": "Trigger type" } }, "required": [ @@ -19523,6 +20166,7 @@ "type": "object" }, "PluginTriggerType": { + "description": "Trigger type", "enum": [ "AssetCreate", "PersonRecognized" @@ -19532,9 +20176,11 @@ "PurchaseResponse": { "properties": { "hideBuyButtonUntil": { + "description": "Date until which to hide buy button", "type": "string" }, "showSupportBadge": { + "description": "Whether to show support badge", "type": "boolean" } }, @@ -19547,15 +20193,18 @@ "PurchaseUpdate": { "properties": { "hideBuyButtonUntil": { + "description": "Date until which to hide buy button", "type": "string" }, "showSupportBadge": { + "description": "Whether to show support badge", "type": "boolean" } }, "type": "object" }, "QueueCommand": { + "description": "Queue command to execute", "enum": [ "start", "pause", @@ -19572,9 +20221,11 @@ { "$ref": "#/components/schemas/QueueCommand" } - ] + ], + "description": "Queue command to execute" }, "force": { + "description": "Force the command execution (if applicable)", "type": "boolean" } }, @@ -19606,9 +20257,11 @@ "QueueJobResponseDto": { "properties": { "data": { + "description": "Job data payload", "type": "object" }, "id": { + "description": "Job ID", "type": "string" }, "name": { @@ -19616,9 +20269,11 @@ { "$ref": "#/components/schemas/JobName" } - ] + ], + "description": "Job name" }, "timestamp": { + "description": "Job creation timestamp", "type": "integer" } }, @@ -19666,6 +20321,7 @@ "QueueResponseDto": { "properties": { "isPaused": { + "description": "Whether the queue is paused", "type": "boolean" }, "name": { @@ -19673,7 +20329,8 @@ { "$ref": "#/components/schemas/QueueName" } - ] + ], + "description": "Queue name" }, "statistics": { "$ref": "#/components/schemas/QueueStatisticsDto" @@ -19704,21 +20361,27 @@ "QueueStatisticsDto": { "properties": { "active": { + "description": "Number of active jobs", "type": "integer" }, "completed": { + "description": "Number of completed jobs", "type": "integer" }, "delayed": { + "description": "Number of delayed jobs", "type": "integer" }, "failed": { + "description": "Number of failed jobs", "type": "integer" }, "paused": { + "description": "Number of paused jobs", "type": "integer" }, "waiting": { + "description": "Number of waiting jobs", "type": "integer" } }, @@ -19735,9 +20398,11 @@ "QueueStatusLegacyDto": { "properties": { "isActive": { + "description": "Whether the queue is currently active (has running jobs)", "type": "boolean" }, "isPaused": { + "description": "Whether the queue is paused", "type": "boolean" } }, @@ -19750,6 +20415,7 @@ "QueueUpdateDto": { "properties": { "isPaused": { + "description": "Whether to pause the queue", "type": "boolean" } }, @@ -19837,6 +20503,7 @@ "RandomSearchDto": { "properties": { "albumIds": { + "description": "Filter by album IDs", "items": { "format": "uuid", "type": "string" @@ -19844,59 +20511,75 @@ "type": "array" }, "city": { + "description": "Filter by city name", "nullable": true, "type": "string" }, "country": { + "description": "Filter by country name", "nullable": true, "type": "string" }, "createdAfter": { + "description": "Filter by creation date (after)", "format": "date-time", "type": "string" }, "createdBefore": { + "description": "Filter by creation date (before)", "format": "date-time", "type": "string" }, "deviceId": { + "description": "Device ID to filter by", "type": "string" }, "isEncoded": { + "description": "Filter by encoded status", "type": "boolean" }, "isFavorite": { + "description": "Filter by favorite status", "type": "boolean" }, "isMotion": { + "description": "Filter by motion photo status", "type": "boolean" }, "isNotInAlbum": { + "description": "Filter assets not in any album", "type": "boolean" }, "isOffline": { + "description": "Filter by offline status", "type": "boolean" }, "lensModel": { + "description": "Filter by lens model", "nullable": true, "type": "string" }, "libraryId": { + "description": "Library ID to filter by", "format": "uuid", "nullable": true, "type": "string" }, "make": { + "description": "Filter by camera make", "type": "string" }, "model": { + "description": "Filter by camera model", "nullable": true, "type": "string" }, "ocr": { + "description": "Filter by OCR text content", "type": "string" }, "personIds": { + "description": "Filter by person IDs", "items": { "format": "uuid", "type": "string" @@ -19904,20 +20587,24 @@ "type": "array" }, "rating": { + "description": "Filter by rating", "maximum": 5, "minimum": -1, "type": "number" }, "size": { + "description": "Number of results to return", "maximum": 1000, "minimum": 1, "type": "number" }, "state": { + "description": "Filter by state/province name", "nullable": true, "type": "string" }, "tagIds": { + "description": "Filter by tag IDs", "items": { "format": "uuid", "type": "string" @@ -19926,18 +20613,22 @@ "type": "array" }, "takenAfter": { + "description": "Filter by taken date (after)", "format": "date-time", "type": "string" }, "takenBefore": { + "description": "Filter by taken date (before)", "format": "date-time", "type": "string" }, "trashedAfter": { + "description": "Filter by trash date (after)", "format": "date-time", "type": "string" }, "trashedBefore": { + "description": "Filter by trash date (before)", "format": "date-time", "type": "string" }, @@ -19946,13 +20637,16 @@ { "$ref": "#/components/schemas/AssetTypeEnum" } - ] + ], + "description": "Asset type filter" }, "updatedAfter": { + "description": "Filter by update date (after)", "format": "date-time", "type": "string" }, "updatedBefore": { + "description": "Filter by update date (before)", "format": "date-time", "type": "string" }, @@ -19961,18 +20655,23 @@ { "$ref": "#/components/schemas/AssetVisibility" } - ] + ], + "description": "Filter by visibility" }, "withDeleted": { + "description": "Include deleted assets", "type": "boolean" }, "withExif": { + "description": "Include EXIF data in response", "type": "boolean" }, "withPeople": { + "description": "Include assets with people", "type": "boolean" }, "withStacked": { + "description": "Include stacked assets", "type": "boolean" } }, @@ -19982,6 +20681,7 @@ "properties": { "enabled": { "default": false, + "description": "Whether ratings are enabled", "type": "boolean" } }, @@ -19993,6 +20693,7 @@ "RatingsUpdate": { "properties": { "enabled": { + "description": "Whether ratings are enabled", "type": "boolean" } }, @@ -20015,10 +20716,12 @@ "ReverseGeocodingStateResponseDto": { "properties": { "lastImportFileName": { + "description": "Last import file name", "nullable": true, "type": "string" }, "lastUpdate": { + "description": "Last update timestamp", "nullable": true, "type": "string" } @@ -20044,6 +20747,7 @@ "SearchAlbumResponseDto": { "properties": { "count": { + "description": "Number of albums in this page", "type": "integer" }, "facets": { @@ -20059,6 +20763,7 @@ "type": "array" }, "total": { + "description": "Total number of matching albums", "type": "integer" } }, @@ -20073,6 +20778,7 @@ "SearchAssetResponseDto": { "properties": { "count": { + "description": "Number of assets in this page", "type": "integer" }, "facets": { @@ -20088,10 +20794,12 @@ "type": "array" }, "nextPage": { + "description": "Next page token", "nullable": true, "type": "string" }, "total": { + "description": "Total number of matching assets", "type": "integer" } }, @@ -20110,6 +20818,7 @@ "$ref": "#/components/schemas/AssetResponseDto" }, "value": { + "description": "Explore value", "type": "string" } }, @@ -20122,6 +20831,7 @@ "SearchExploreResponseDto": { "properties": { "fieldName": { + "description": "Explore field name", "type": "string" }, "items": { @@ -20140,9 +20850,11 @@ "SearchFacetCountResponseDto": { "properties": { "count": { + "description": "Number of assets with this facet value", "type": "integer" }, "value": { + "description": "Facet value", "type": "string" } }, @@ -20155,12 +20867,14 @@ "SearchFacetResponseDto": { "properties": { "counts": { + "description": "Facet counts", "items": { "$ref": "#/components/schemas/SearchFacetCountResponseDto" }, "type": "array" }, "fieldName": { + "description": "Facet field name", "type": "string" } }, @@ -20188,6 +20902,7 @@ "SearchStatisticsResponseDto": { "properties": { "total": { + "description": "Total number of matching assets", "type": "integer" } }, @@ -20210,66 +20925,87 @@ "ServerAboutResponseDto": { "properties": { "build": { + "description": "Build identifier", "type": "string" }, "buildImage": { + "description": "Build image name", "type": "string" }, "buildImageUrl": { + "description": "Build image URL", "type": "string" }, "buildUrl": { + "description": "Build URL", "type": "string" }, "exiftool": { + "description": "ExifTool version", "type": "string" }, "ffmpeg": { + "description": "FFmpeg version", "type": "string" }, "imagemagick": { + "description": "ImageMagick version", "type": "string" }, "libvips": { + "description": "libvips version", "type": "string" }, "licensed": { + "description": "Whether the server is licensed", "type": "boolean" }, "nodejs": { + "description": "Node.js version", "type": "string" }, "repository": { + "description": "Repository name", "type": "string" }, "repositoryUrl": { + "description": "Repository URL", "type": "string" }, "sourceCommit": { + "description": "Source commit hash", "type": "string" }, "sourceRef": { + "description": "Source reference (branch/tag)", "type": "string" }, "sourceUrl": { + "description": "Source URL", "type": "string" }, "thirdPartyBugFeatureUrl": { + "description": "Third-party bug/feature URL", "type": "string" }, "thirdPartyDocumentationUrl": { + "description": "Third-party documentation URL", "type": "string" }, "thirdPartySourceUrl": { + "description": "Third-party source URL", "type": "string" }, "thirdPartySupportUrl": { + "description": "Third-party support URL", "type": "string" }, "version": { + "description": "Server version", "type": "string" }, "versionUrl": { + "description": "URL to version information", "type": "string" } }, @@ -20283,15 +21019,19 @@ "ServerApkLinksDto": { "properties": { "arm64v8a": { + "description": "APK download link for ARM64 v8a architecture", "type": "string" }, "armeabiv7a": { + "description": "APK download link for ARM EABI v7a architecture", "type": "string" }, "universal": { + "description": "APK download link for universal architecture", "type": "string" }, "x86_64": { + "description": "APK download link for x86_64 architecture", "type": "string" } }, @@ -20306,36 +21046,47 @@ "ServerConfigDto": { "properties": { "externalDomain": { + "description": "External domain URL", "type": "string" }, "isInitialized": { + "description": "Whether the server has been initialized", "type": "boolean" }, "isOnboarded": { + "description": "Whether the admin has completed onboarding", "type": "boolean" }, "loginPageMessage": { + "description": "Login page message", "type": "string" }, "maintenanceMode": { + "description": "Whether maintenance mode is active", "type": "boolean" }, "mapDarkStyleUrl": { + "description": "Map dark style URL", "type": "string" }, "mapLightStyleUrl": { + "description": "Map light style URL", "type": "string" }, "oauthButtonText": { + "description": "OAuth button text", "type": "string" }, "publicUsers": { + "description": "Whether public user registration is enabled", "type": "boolean" }, "trashDays": { + "description": "Number of days before trashed assets are permanently deleted", "type": "integer" }, "userDeleteDelay": { + "description": "Delay in days before deleted users are permanently removed", "type": "integer" } }, @@ -20357,48 +21108,63 @@ "ServerFeaturesDto": { "properties": { "configFile": { + "description": "Whether config file is available", "type": "boolean" }, "duplicateDetection": { + "description": "Whether duplicate detection is enabled", "type": "boolean" }, "email": { + "description": "Whether email notifications are enabled", "type": "boolean" }, "facialRecognition": { + "description": "Whether facial recognition is enabled", "type": "boolean" }, "importFaces": { + "description": "Whether face import is enabled", "type": "boolean" }, "map": { + "description": "Whether map feature is enabled", "type": "boolean" }, "oauth": { + "description": "Whether OAuth is enabled", "type": "boolean" }, "oauthAutoLaunch": { + "description": "Whether OAuth auto-launch is enabled", "type": "boolean" }, "ocr": { + "description": "Whether OCR is enabled", "type": "boolean" }, "passwordLogin": { + "description": "Whether password login is enabled", "type": "boolean" }, "reverseGeocoding": { + "description": "Whether reverse geocoding is enabled", "type": "boolean" }, "search": { + "description": "Whether search is enabled", "type": "boolean" }, "sidecar": { + "description": "Whether sidecar files are supported", "type": "boolean" }, "smartSearch": { + "description": "Whether smart search is enabled", "type": "boolean" }, "trash": { + "description": "Whether trash feature is enabled", "type": "boolean" } }, @@ -20424,18 +21190,21 @@ "ServerMediaTypesResponseDto": { "properties": { "image": { + "description": "Supported image MIME types", "items": { "type": "string" }, "type": "array" }, "sidecar": { + "description": "Supported sidecar MIME types", "items": { "type": "string" }, "type": "array" }, "video": { + "description": "Supported video MIME types", "items": { "type": "string" }, @@ -20466,10 +21235,12 @@ "properties": { "photos": { "default": 0, + "description": "Total number of photos", "type": "integer" }, "usage": { "default": 0, + "description": "Total storage usage in bytes", "format": "int64", "type": "integer" }, @@ -20492,16 +21263,19 @@ }, "usagePhotos": { "default": 0, + "description": "Storage usage for photos in bytes", "format": "int64", "type": "integer" }, "usageVideos": { "default": 0, + "description": "Storage usage for videos in bytes", "format": "int64", "type": "integer" }, "videos": { "default": 0, + "description": "Total number of videos", "type": "integer" } }, @@ -20518,27 +21292,34 @@ "ServerStorageResponseDto": { "properties": { "diskAvailable": { + "description": "Available disk space (human-readable format)", "type": "string" }, "diskAvailableRaw": { + "description": "Available disk space in bytes", "format": "int64", "type": "integer" }, "diskSize": { + "description": "Total disk size (human-readable format)", "type": "string" }, "diskSizeRaw": { + "description": "Total disk size in bytes", "format": "int64", "type": "integer" }, "diskUsagePercentage": { + "description": "Disk usage percentage (0-100)", "format": "double", "type": "number" }, "diskUse": { + "description": "Used disk space (human-readable format)", "type": "string" }, "diskUseRaw": { + "description": "Used disk space in bytes", "format": "int64", "type": "integer" } @@ -20557,6 +21338,7 @@ "ServerThemeDto": { "properties": { "customCss": { + "description": "Custom CSS for theming", "type": "string" } }, @@ -20568,13 +21350,16 @@ "ServerVersionHistoryResponseDto": { "properties": { "createdAt": { + "description": "When this version was first seen", "format": "date-time", "type": "string" }, "id": { + "description": "Version history entry ID", "type": "string" }, "version": { + "description": "Version string", "type": "string" } }, @@ -20588,12 +21373,15 @@ "ServerVersionResponseDto": { "properties": { "major": { + "description": "Major version number", "type": "integer" }, "minor": { + "description": "Minor version number", "type": "integer" }, "patch": { + "description": "Patch version number", "type": "integer" } }, @@ -20607,13 +21395,15 @@ "SessionCreateDto": { "properties": { "deviceOS": { + "description": "Device OS", "type": "string" }, "deviceType": { + "description": "Device type", "type": "string" }, "duration": { - "description": "session duration, in seconds", + "description": "Session duration in seconds", "minimum": 1, "type": "number" } @@ -20623,34 +21413,44 @@ "SessionCreateResponseDto": { "properties": { "appVersion": { + "description": "App version", "nullable": true, "type": "string" }, "createdAt": { + "description": "Creation date", "type": "string" }, "current": { + "description": "Is current session", "type": "boolean" }, "deviceOS": { + "description": "Device OS", "type": "string" }, "deviceType": { + "description": "Device type", "type": "string" }, "expiresAt": { + "description": "Expiration date", "type": "string" }, "id": { + "description": "Session ID", "type": "string" }, "isPendingSyncReset": { + "description": "Is pending sync reset", "type": "boolean" }, "token": { + "description": "Session token", "type": "string" }, "updatedAt": { + "description": "Last update date", "type": "string" } }, @@ -20670,31 +21470,40 @@ "SessionResponseDto": { "properties": { "appVersion": { + "description": "App version", "nullable": true, "type": "string" }, "createdAt": { + "description": "Creation date", "type": "string" }, "current": { + "description": "Is current session", "type": "boolean" }, "deviceOS": { + "description": "Device OS", "type": "string" }, "deviceType": { + "description": "Device type", "type": "string" }, "expiresAt": { + "description": "Expiration date", "type": "string" }, "id": { + "description": "Session ID", "type": "string" }, "isPendingSyncReset": { + "description": "Is pending sync reset", "type": "boolean" }, "updatedAt": { + "description": "Last update date", "type": "string" } }, @@ -20713,9 +21522,11 @@ "SessionUnlockDto": { "properties": { "password": { + "description": "User password (required if PIN code is not provided)", "type": "string" }, "pinCode": { + "description": "New PIN code (4-6 digits)", "example": "123456", "type": "string" } @@ -20725,6 +21536,7 @@ "SessionUpdateDto": { "properties": { "isPendingSyncReset": { + "description": "Reset pending sync state", "type": "boolean" } }, @@ -20737,9 +21549,11 @@ { "$ref": "#/components/schemas/MaintenanceAction" } - ] + ], + "description": "Maintenance action" }, "restoreBackupFilename": { + "description": "Restore backup filename", "type": "string" } }, @@ -20751,17 +21565,21 @@ "SharedLinkCreateDto": { "properties": { "albumId": { + "description": "Album ID (for album sharing)", "format": "uuid", "type": "string" }, "allowDownload": { "default": true, + "description": "Allow downloads", "type": "boolean" }, "allowUpload": { + "description": "Allow uploads", "type": "boolean" }, "assetIds": { + "description": "Asset IDs (for individual assets)", "items": { "format": "uuid", "type": "string" @@ -20769,24 +21587,29 @@ "type": "array" }, "description": { + "description": "Link description", "nullable": true, "type": "string" }, "expiresAt": { "default": null, + "description": "Expiration date", "format": "date-time", "nullable": true, "type": "string" }, "password": { + "description": "Link password", "nullable": true, "type": "string" }, "showMetadata": { "default": true, + "description": "Show metadata", "type": "boolean" }, "slug": { + "description": "Custom URL slug", "nullable": true, "type": "string" }, @@ -20795,7 +21618,8 @@ { "$ref": "#/components/schemas/SharedLinkType" } - ] + ], + "description": "Shared link type" } }, "required": [ @@ -20806,32 +21630,39 @@ "SharedLinkEditDto": { "properties": { "allowDownload": { + "description": "Allow downloads", "type": "boolean" }, "allowUpload": { + "description": "Allow uploads", "type": "boolean" }, "changeExpiryTime": { - "description": "Few clients cannot send null to set the expiryTime to never.\nSetting this flag and not sending expiryAt is considered as null instead.\nClients that can send null values can ignore this.", + "description": "Whether to change the expiry time. Few clients cannot send null to set the expiryTime to never. Setting this flag and not sending expiryAt is considered as null instead. Clients that can send null values can ignore this.", "type": "boolean" }, "description": { + "description": "Link description", "nullable": true, "type": "string" }, "expiresAt": { + "description": "Expiration date", "format": "date-time", "nullable": true, "type": "string" }, "password": { + "description": "Link password", "nullable": true, "type": "string" }, "showMetadata": { + "description": "Show metadata", "type": "boolean" }, "slug": { + "description": "Custom URL slug", "nullable": true, "type": "string" } @@ -20844,9 +21675,11 @@ "$ref": "#/components/schemas/AlbumResponseDto" }, "allowDownload": { + "description": "Allow downloads", "type": "boolean" }, "allowUpload": { + "description": "Allow uploads", "type": "boolean" }, "assets": { @@ -20856,36 +21689,45 @@ "type": "array" }, "createdAt": { + "description": "Creation date", "format": "date-time", "type": "string" }, "description": { + "description": "Link description", "nullable": true, "type": "string" }, "expiresAt": { + "description": "Expiration date", "format": "date-time", "nullable": true, "type": "string" }, "id": { + "description": "Shared link ID", "type": "string" }, "key": { + "description": "Encryption key (base64url)", "type": "string" }, "password": { + "description": "Has password", "nullable": true, "type": "string" }, "showMetadata": { + "description": "Show metadata", "type": "boolean" }, "slug": { + "description": "Custom URL slug", "nullable": true, "type": "string" }, "token": { + "description": "Access token", "nullable": true, "type": "string" }, @@ -20894,9 +21736,11 @@ { "$ref": "#/components/schemas/SharedLinkType" } - ] + ], + "description": "Shared link type" }, "userId": { + "description": "Owner user ID", "type": "string" } }, @@ -20918,6 +21762,7 @@ "type": "object" }, "SharedLinkType": { + "description": "Shared link type", "enum": [ "ALBUM", "INDIVIDUAL" @@ -20928,10 +21773,12 @@ "properties": { "enabled": { "default": true, + "description": "Whether shared links are enabled", "type": "boolean" }, "sidebarWeb": { "default": false, + "description": "Whether shared links appear in web sidebar", "type": "boolean" } }, @@ -20944,9 +21791,11 @@ "SharedLinksUpdate": { "properties": { "enabled": { + "description": "Whether shared links are enabled", "type": "boolean" }, "sidebarWeb": { + "description": "Whether shared links appear in web sidebar", "type": "boolean" } }, @@ -20955,15 +21804,18 @@ "SignUpDto": { "properties": { "email": { + "description": "User email", "example": "testuser@email.com", "format": "email", "type": "string" }, "name": { + "description": "User name", "example": "Admin", "type": "string" }, "password": { + "description": "User password", "example": "password", "type": "string" } @@ -20978,6 +21830,7 @@ "SmartSearchDto": { "properties": { "albumIds": { + "description": "Filter by album IDs", "items": { "format": "uuid", "type": "string" @@ -20985,66 +21838,84 @@ "type": "array" }, "city": { + "description": "Filter by city name", "nullable": true, "type": "string" }, "country": { + "description": "Filter by country name", "nullable": true, "type": "string" }, "createdAfter": { + "description": "Filter by creation date (after)", "format": "date-time", "type": "string" }, "createdBefore": { + "description": "Filter by creation date (before)", "format": "date-time", "type": "string" }, "deviceId": { + "description": "Device ID to filter by", "type": "string" }, "isEncoded": { + "description": "Filter by encoded status", "type": "boolean" }, "isFavorite": { + "description": "Filter by favorite status", "type": "boolean" }, "isMotion": { + "description": "Filter by motion photo status", "type": "boolean" }, "isNotInAlbum": { + "description": "Filter assets not in any album", "type": "boolean" }, "isOffline": { + "description": "Filter by offline status", "type": "boolean" }, "language": { + "description": "Search language code", "type": "string" }, "lensModel": { + "description": "Filter by lens model", "nullable": true, "type": "string" }, "libraryId": { + "description": "Library ID to filter by", "format": "uuid", "nullable": true, "type": "string" }, "make": { + "description": "Filter by camera make", "type": "string" }, "model": { + "description": "Filter by camera model", "nullable": true, "type": "string" }, "ocr": { + "description": "Filter by OCR text content", "type": "string" }, "page": { + "description": "Page number", "minimum": 1, "type": "number" }, "personIds": { + "description": "Filter by person IDs", "items": { "format": "uuid", "type": "string" @@ -21052,27 +21923,33 @@ "type": "array" }, "query": { + "description": "Natural language search query", "type": "string" }, "queryAssetId": { + "description": "Asset ID to use as search reference", "format": "uuid", "type": "string" }, "rating": { + "description": "Filter by rating", "maximum": 5, "minimum": -1, "type": "number" }, "size": { + "description": "Number of results to return", "maximum": 1000, "minimum": 1, "type": "number" }, "state": { + "description": "Filter by state/province name", "nullable": true, "type": "string" }, "tagIds": { + "description": "Filter by tag IDs", "items": { "format": "uuid", "type": "string" @@ -21081,18 +21958,22 @@ "type": "array" }, "takenAfter": { + "description": "Filter by taken date (after)", "format": "date-time", "type": "string" }, "takenBefore": { + "description": "Filter by taken date (before)", "format": "date-time", "type": "string" }, "trashedAfter": { + "description": "Filter by trash date (after)", "format": "date-time", "type": "string" }, "trashedBefore": { + "description": "Filter by trash date (before)", "format": "date-time", "type": "string" }, @@ -21101,13 +21982,16 @@ { "$ref": "#/components/schemas/AssetTypeEnum" } - ] + ], + "description": "Asset type filter" }, "updatedAfter": { + "description": "Filter by update date (after)", "format": "date-time", "type": "string" }, "updatedBefore": { + "description": "Filter by update date (before)", "format": "date-time", "type": "string" }, @@ -21116,18 +22000,22 @@ { "$ref": "#/components/schemas/AssetVisibility" } - ] + ], + "description": "Filter by visibility" }, "withDeleted": { + "description": "Include deleted assets", "type": "boolean" }, "withExif": { + "description": "Include EXIF data in response", "type": "boolean" } }, "type": "object" }, "SourceType": { + "description": "Face detection source type", "enum": [ "machine-learning", "exif", @@ -21138,7 +22026,7 @@ "StackCreateDto": { "properties": { "assetIds": { - "description": "first asset becomes the primary", + "description": "Asset IDs (first becomes primary, min 2)", "items": { "format": "uuid", "type": "string" @@ -21155,15 +22043,18 @@ "StackResponseDto": { "properties": { "assets": { + "description": "Stack assets", "items": { "$ref": "#/components/schemas/AssetResponseDto" }, "type": "array" }, "id": { + "description": "Stack ID", "type": "string" }, "primaryAssetId": { + "description": "Primary asset ID", "type": "string" } }, @@ -21177,6 +22068,7 @@ "StackUpdateDto": { "properties": { "primaryAssetId": { + "description": "Primary asset ID", "format": "uuid", "type": "string" } @@ -21186,6 +22078,7 @@ "StatisticsSearchDto": { "properties": { "albumIds": { + "description": "Filter by album IDs", "items": { "format": "uuid", "type": "string" @@ -21193,62 +22086,79 @@ "type": "array" }, "city": { + "description": "Filter by city name", "nullable": true, "type": "string" }, "country": { + "description": "Filter by country name", "nullable": true, "type": "string" }, "createdAfter": { + "description": "Filter by creation date (after)", "format": "date-time", "type": "string" }, "createdBefore": { + "description": "Filter by creation date (before)", "format": "date-time", "type": "string" }, "description": { + "description": "Filter by description text", "type": "string" }, "deviceId": { + "description": "Device ID to filter by", "type": "string" }, "isEncoded": { + "description": "Filter by encoded status", "type": "boolean" }, "isFavorite": { + "description": "Filter by favorite status", "type": "boolean" }, "isMotion": { + "description": "Filter by motion photo status", "type": "boolean" }, "isNotInAlbum": { + "description": "Filter assets not in any album", "type": "boolean" }, "isOffline": { + "description": "Filter by offline status", "type": "boolean" }, "lensModel": { + "description": "Filter by lens model", "nullable": true, "type": "string" }, "libraryId": { + "description": "Library ID to filter by", "format": "uuid", "nullable": true, "type": "string" }, "make": { + "description": "Filter by camera make", "type": "string" }, "model": { + "description": "Filter by camera model", "nullable": true, "type": "string" }, "ocr": { + "description": "Filter by OCR text content", "type": "string" }, "personIds": { + "description": "Filter by person IDs", "items": { "format": "uuid", "type": "string" @@ -21256,15 +22166,18 @@ "type": "array" }, "rating": { + "description": "Filter by rating", "maximum": 5, "minimum": -1, "type": "number" }, "state": { + "description": "Filter by state/province name", "nullable": true, "type": "string" }, "tagIds": { + "description": "Filter by tag IDs", "items": { "format": "uuid", "type": "string" @@ -21273,18 +22186,22 @@ "type": "array" }, "takenAfter": { + "description": "Filter by taken date (after)", "format": "date-time", "type": "string" }, "takenBefore": { + "description": "Filter by taken date (before)", "format": "date-time", "type": "string" }, "trashedAfter": { + "description": "Filter by trash date (after)", "format": "date-time", "type": "string" }, "trashedBefore": { + "description": "Filter by trash date (before)", "format": "date-time", "type": "string" }, @@ -21293,13 +22210,16 @@ { "$ref": "#/components/schemas/AssetTypeEnum" } - ] + ], + "description": "Asset type filter" }, "updatedAfter": { + "description": "Filter by update date (after)", "format": "date-time", "type": "string" }, "updatedBefore": { + "description": "Filter by update date (before)", "format": "date-time", "type": "string" }, @@ -21308,12 +22228,14 @@ { "$ref": "#/components/schemas/AssetVisibility" } - ] + ], + "description": "Filter by visibility" } }, "type": "object" }, "StorageFolder": { + "description": "Storage folder", "enum": [ "encoded-video", "library", @@ -21327,6 +22249,7 @@ "SyncAckDeleteDto": { "properties": { "types": { + "description": "Sync entity types to delete acks for", "items": { "$ref": "#/components/schemas/SyncEntityType" }, @@ -21338,6 +22261,7 @@ "SyncAckDto": { "properties": { "ack": { + "description": "Acknowledgment ID", "type": "string" }, "type": { @@ -21345,7 +22269,8 @@ { "$ref": "#/components/schemas/SyncEntityType" } - ] + ], + "description": "Sync entity type" } }, "required": [ @@ -21357,6 +22282,7 @@ "SyncAckSetDto": { "properties": { "acks": { + "description": "Acknowledgment IDs (max 1000)", "items": { "type": "string" }, @@ -21376,6 +22302,7 @@ "SyncAlbumDeleteV1": { "properties": { "albumId": { + "description": "Album ID", "type": "string" } }, @@ -21387,9 +22314,11 @@ "SyncAlbumToAssetDeleteV1": { "properties": { "albumId": { + "description": "Album ID", "type": "string" }, "assetId": { + "description": "Asset ID", "type": "string" } }, @@ -21402,9 +22331,11 @@ "SyncAlbumToAssetV1": { "properties": { "albumId": { + "description": "Album ID", "type": "string" }, "assetId": { + "description": "Asset ID", "type": "string" } }, @@ -21417,9 +22348,11 @@ "SyncAlbumUserDeleteV1": { "properties": { "albumId": { + "description": "Album ID", "type": "string" }, "userId": { + "description": "User ID", "type": "string" } }, @@ -21432,6 +22365,7 @@ "SyncAlbumUserV1": { "properties": { "albumId": { + "description": "Album ID", "type": "string" }, "role": { @@ -21439,9 +22373,11 @@ { "$ref": "#/components/schemas/AlbumUserRole" } - ] + ], + "description": "Album user role" }, "userId": { + "description": "User ID", "type": "string" } }, @@ -21455,19 +22391,24 @@ "SyncAlbumV1": { "properties": { "createdAt": { + "description": "Created at", "format": "date-time", "type": "string" }, "description": { + "description": "Album description", "type": "string" }, "id": { + "description": "Album ID", "type": "string" }, "isActivityEnabled": { + "description": "Is activity enabled", "type": "boolean" }, "name": { + "description": "Album name", "type": "string" }, "order": { @@ -21478,13 +22419,16 @@ ] }, "ownerId": { + "description": "Owner ID", "type": "string" }, "thumbnailAssetId": { + "description": "Thumbnail asset ID", "nullable": true, "type": "string" }, "updatedAt": { + "description": "Updated at", "format": "date-time", "type": "string" } @@ -21505,6 +22449,7 @@ "SyncAssetDeleteV1": { "properties": { "assetId": { + "description": "Asset ID", "type": "string" } }, @@ -21516,108 +22461,133 @@ "SyncAssetExifV1": { "properties": { "assetId": { + "description": "Asset ID", "type": "string" }, "city": { + "description": "City", "nullable": true, "type": "string" }, "country": { + "description": "Country", "nullable": true, "type": "string" }, "dateTimeOriginal": { + "description": "Date time original", "format": "date-time", "nullable": true, "type": "string" }, "description": { + "description": "Description", "nullable": true, "type": "string" }, "exifImageHeight": { + "description": "Exif image height", "nullable": true, "type": "integer" }, "exifImageWidth": { + "description": "Exif image width", "nullable": true, "type": "integer" }, "exposureTime": { + "description": "Exposure time", "nullable": true, "type": "string" }, "fNumber": { + "description": "F number", "format": "double", "nullable": true, "type": "number" }, "fileSizeInByte": { + "description": "File size in byte", "nullable": true, "type": "integer" }, "focalLength": { + "description": "Focal length", "format": "double", "nullable": true, "type": "number" }, "fps": { + "description": "FPS", "format": "double", "nullable": true, "type": "number" }, "iso": { + "description": "ISO", "nullable": true, "type": "integer" }, "latitude": { + "description": "Latitude", "format": "double", "nullable": true, "type": "number" }, "lensModel": { + "description": "Lens model", "nullable": true, "type": "string" }, "longitude": { + "description": "Longitude", "format": "double", "nullable": true, "type": "number" }, "make": { + "description": "Make", "nullable": true, "type": "string" }, "model": { + "description": "Model", "nullable": true, "type": "string" }, "modifyDate": { + "description": "Modify date", "format": "date-time", "nullable": true, "type": "string" }, "orientation": { + "description": "Orientation", "nullable": true, "type": "string" }, "profileDescription": { + "description": "Profile description", "nullable": true, "type": "string" }, "projectionType": { + "description": "Projection type", "nullable": true, "type": "string" }, "rating": { + "description": "Rating", "nullable": true, "type": "integer" }, "state": { + "description": "State", "nullable": true, "type": "string" }, "timeZone": { + "description": "Time zone", "nullable": true, "type": "string" } @@ -21654,6 +22624,7 @@ "SyncAssetFaceDeleteV1": { "properties": { "assetFaceId": { + "description": "Asset face ID", "type": "string" } }, @@ -21665,6 +22636,7 @@ "SyncAssetFaceV1": { "properties": { "assetId": { + "description": "Asset ID", "type": "string" }, "boundingBoxX1": { @@ -21680,6 +22652,7 @@ "type": "integer" }, "id": { + "description": "Asset face ID", "type": "string" }, "imageHeight": { @@ -21689,10 +22662,12 @@ "type": "integer" }, "personId": { + "description": "Person ID", "nullable": true, "type": "string" }, "sourceType": { + "description": "Source type", "type": "string" } }, @@ -21713,9 +22688,11 @@ "SyncAssetMetadataDeleteV1": { "properties": { "assetId": { + "description": "Asset ID", "type": "string" }, "key": { + "description": "Key", "type": "string" } }, @@ -21728,12 +22705,15 @@ "SyncAssetMetadataV1": { "properties": { "assetId": { + "description": "Asset ID", "type": "string" }, "key": { + "description": "Key", "type": "string" }, "value": { + "description": "Value", "type": "object" } }, @@ -21747,64 +22727,80 @@ "SyncAssetV1": { "properties": { "checksum": { + "description": "Checksum", "type": "string" }, "deletedAt": { + "description": "Deleted at", "format": "date-time", "nullable": true, "type": "string" }, "duration": { + "description": "Duration", "nullable": true, "type": "string" }, "fileCreatedAt": { + "description": "File created at", "format": "date-time", "nullable": true, "type": "string" }, "fileModifiedAt": { + "description": "File modified at", "format": "date-time", "nullable": true, "type": "string" }, "height": { + "description": "Asset height", "nullable": true, "type": "integer" }, "id": { + "description": "Asset ID", "type": "string" }, "isEdited": { + "description": "Is edited", "type": "boolean" }, "isFavorite": { + "description": "Is favorite", "type": "boolean" }, "libraryId": { + "description": "Library ID", "nullable": true, "type": "string" }, "livePhotoVideoId": { + "description": "Live photo video ID", "nullable": true, "type": "string" }, "localDateTime": { + "description": "Local date time", "format": "date-time", "nullable": true, "type": "string" }, "originalFileName": { + "description": "Original file name", "type": "string" }, "ownerId": { + "description": "Owner ID", "type": "string" }, "stackId": { + "description": "Stack ID", "nullable": true, "type": "string" }, "thumbhash": { + "description": "Thumbhash", "nullable": true, "type": "string" }, @@ -21813,16 +22809,19 @@ { "$ref": "#/components/schemas/AssetTypeEnum" } - ] + ], + "description": "Asset type" }, "visibility": { "allOf": [ { "$ref": "#/components/schemas/AssetVisibility" } - ] + ], + "description": "Asset visibility" }, "width": { + "description": "Asset width", "nullable": true, "type": "integer" } @@ -21858,36 +22857,46 @@ "$ref": "#/components/schemas/UserAvatarColor" } ], + "description": "User avatar color", "nullable": true }, "deletedAt": { + "description": "User deleted at", "format": "date-time", "nullable": true, "type": "string" }, "email": { + "description": "User email", "type": "string" }, "hasProfileImage": { + "description": "User has profile image", "type": "boolean" }, "id": { + "description": "User ID", "type": "string" }, "isAdmin": { + "description": "User is admin", "type": "boolean" }, "name": { + "description": "User name", "type": "string" }, "oauthId": { + "description": "User OAuth ID", "type": "string" }, "pinCode": { + "description": "User pin code", "nullable": true, "type": "string" }, "profileChangedAt": { + "description": "User profile changed at", "format": "date-time", "type": "string" }, @@ -21899,6 +22908,7 @@ "type": "integer" }, "storageLabel": { + "description": "User storage label", "nullable": true, "type": "string" } @@ -21925,6 +22935,7 @@ "type": "object" }, "SyncEntityType": { + "description": "Sync entity type", "enum": [ "AuthUserV1", "UserV1", @@ -21979,9 +22990,11 @@ "SyncMemoryAssetDeleteV1": { "properties": { "assetId": { + "description": "Asset ID", "type": "string" }, "memoryId": { + "description": "Memory ID", "type": "string" } }, @@ -21994,9 +23007,11 @@ "SyncMemoryAssetV1": { "properties": { "assetId": { + "description": "Asset ID", "type": "string" }, "memoryId": { + "description": "Memory ID", "type": "string" } }, @@ -22009,6 +23024,7 @@ "SyncMemoryDeleteV1": { "properties": { "memoryId": { + "description": "Memory ID", "type": "string" } }, @@ -22020,41 +23036,51 @@ "SyncMemoryV1": { "properties": { "createdAt": { + "description": "Created at", "format": "date-time", "type": "string" }, "data": { + "description": "Data", "type": "object" }, "deletedAt": { + "description": "Deleted at", "format": "date-time", "nullable": true, "type": "string" }, "hideAt": { + "description": "Hide at", "format": "date-time", "nullable": true, "type": "string" }, "id": { + "description": "Memory ID", "type": "string" }, "isSaved": { + "description": "Is saved", "type": "boolean" }, "memoryAt": { + "description": "Memory at", "format": "date-time", "type": "string" }, "ownerId": { + "description": "Owner ID", "type": "string" }, "seenAt": { + "description": "Seen at", "format": "date-time", "nullable": true, "type": "string" }, "showAt": { + "description": "Show at", "format": "date-time", "nullable": true, "type": "string" @@ -22064,9 +23090,11 @@ { "$ref": "#/components/schemas/MemoryType" } - ] + ], + "description": "Memory type" }, "updatedAt": { + "description": "Updated at", "format": "date-time", "type": "string" } @@ -22090,9 +23118,11 @@ "SyncPartnerDeleteV1": { "properties": { "sharedById": { + "description": "Shared by ID", "type": "string" }, "sharedWithId": { + "description": "Shared with ID", "type": "string" } }, @@ -22105,12 +23135,15 @@ "SyncPartnerV1": { "properties": { "inTimeline": { + "description": "In timeline", "type": "boolean" }, "sharedById": { + "description": "Shared by ID", "type": "string" }, "sharedWithId": { + "description": "Shared with ID", "type": "string" } }, @@ -22124,6 +23157,7 @@ "SyncPersonDeleteV1": { "properties": { "personId": { + "description": "Person ID", "type": "string" } }, @@ -22135,38 +23169,48 @@ "SyncPersonV1": { "properties": { "birthDate": { + "description": "Birth date", "format": "date-time", "nullable": true, "type": "string" }, "color": { + "description": "Color", "nullable": true, "type": "string" }, "createdAt": { + "description": "Created at", "format": "date-time", "type": "string" }, "faceAssetId": { + "description": "Face asset ID", "nullable": true, "type": "string" }, "id": { + "description": "Person ID", "type": "string" }, "isFavorite": { + "description": "Is favorite", "type": "boolean" }, "isHidden": { + "description": "Is hidden", "type": "boolean" }, "name": { + "description": "Person name", "type": "string" }, "ownerId": { + "description": "Owner ID", "type": "string" }, "updatedAt": { + "description": "Updated at", "format": "date-time", "type": "string" } @@ -22186,6 +23230,7 @@ "type": "object" }, "SyncRequestType": { + "description": "Sync request types", "enum": [ "AlbumsV1", "AlbumUsersV1", @@ -22217,6 +23262,7 @@ "SyncStackDeleteV1": { "properties": { "stackId": { + "description": "Stack ID", "type": "string" } }, @@ -22228,19 +23274,24 @@ "SyncStackV1": { "properties": { "createdAt": { + "description": "Created at", "format": "date-time", "type": "string" }, "id": { + "description": "Stack ID", "type": "string" }, "ownerId": { + "description": "Owner ID", "type": "string" }, "primaryAssetId": { + "description": "Primary asset ID", "type": "string" }, "updatedAt": { + "description": "Updated at", "format": "date-time", "type": "string" } @@ -22257,9 +23308,11 @@ "SyncStreamDto": { "properties": { "reset": { + "description": "Reset sync state", "type": "boolean" }, "types": { + "description": "Sync request types", "items": { "$ref": "#/components/schemas/SyncRequestType" }, @@ -22274,6 +23327,7 @@ "SyncUserDeleteV1": { "properties": { "userId": { + "description": "User ID", "type": "string" } }, @@ -22289,9 +23343,11 @@ { "$ref": "#/components/schemas/UserMetadataKey" } - ] + ], + "description": "User metadata key" }, "userId": { + "description": "User ID", "type": "string" } }, @@ -22308,12 +23364,15 @@ { "$ref": "#/components/schemas/UserMetadataKey" } - ] + ], + "description": "User metadata key" }, "userId": { + "description": "User ID", "type": "string" }, "value": { + "description": "User metadata value", "type": "object" } }, @@ -22332,26 +23391,33 @@ "$ref": "#/components/schemas/UserAvatarColor" } ], + "description": "User avatar color", "nullable": true }, "deletedAt": { + "description": "User deleted at", "format": "date-time", "nullable": true, "type": "string" }, "email": { + "description": "User email", "type": "string" }, "hasProfileImage": { + "description": "User has profile image", "type": "boolean" }, "id": { + "description": "User ID", "type": "string" }, "name": { + "description": "User name", "type": "string" }, "profileChangedAt": { + "description": "User profile changed at", "format": "date-time", "type": "string" } @@ -22476,30 +23542,36 @@ { "$ref": "#/components/schemas/TranscodeHWAccel" } - ] + ], + "description": "Transcode hardware acceleration" }, "accelDecode": { + "description": "Accelerated decode", "type": "boolean" }, "acceptedAudioCodecs": { + "description": "Accepted audio codecs", "items": { "$ref": "#/components/schemas/AudioCodec" }, "type": "array" }, "acceptedContainers": { + "description": "Accepted containers", "items": { "$ref": "#/components/schemas/VideoContainer" }, "type": "array" }, "acceptedVideoCodecs": { + "description": "Accepted video codecs", "items": { "$ref": "#/components/schemas/VideoCodec" }, "type": "array" }, "bframes": { + "description": "B-frames", "maximum": 16, "minimum": -1, "type": "integer" @@ -22509,27 +23581,34 @@ { "$ref": "#/components/schemas/CQMode" } - ] + ], + "description": "CQ mode" }, "crf": { + "description": "CRF", "maximum": 51, "minimum": 0, "type": "integer" }, "gopSize": { + "description": "GOP size", "minimum": 0, "type": "integer" }, "maxBitrate": { + "description": "Max bitrate", "type": "string" }, "preferredHwDevice": { + "description": "Preferred hardware device", "type": "string" }, "preset": { + "description": "Preset", "type": "string" }, "refs": { + "description": "References", "maximum": 6, "minimum": 0, "type": "integer" @@ -22539,9 +23618,11 @@ { "$ref": "#/components/schemas/AudioCodec" } - ] + ], + "description": "Target audio codec" }, "targetResolution": { + "description": "Target resolution", "type": "string" }, "targetVideoCodec": { @@ -22549,12 +23630,15 @@ { "$ref": "#/components/schemas/VideoCodec" } - ] + ], + "description": "Target video codec" }, "temporalAQ": { + "description": "Temporal AQ", "type": "boolean" }, "threads": { + "description": "Threads", "minimum": 0, "type": "integer" }, @@ -22563,16 +23647,19 @@ { "$ref": "#/components/schemas/ToneMapping" } - ] + ], + "description": "Tone mapping" }, "transcode": { "allOf": [ { "$ref": "#/components/schemas/TranscodePolicy" } - ] + ], + "description": "Transcode policy" }, "twoPass": { + "description": "Two pass", "type": "boolean" } }, @@ -22604,6 +23691,7 @@ "SystemConfigFacesDto": { "properties": { "import": { + "description": "Import", "type": "boolean" } }, @@ -22615,6 +23703,7 @@ "SystemConfigGeneratedFullsizeImageDto": { "properties": { "enabled": { + "description": "Enabled", "type": "boolean" }, "format": { @@ -22622,13 +23711,16 @@ { "$ref": "#/components/schemas/ImageFormat" } - ] + ], + "description": "Image format" }, "progressive": { "default": false, + "description": "Progressive", "type": "boolean" }, "quality": { + "description": "Quality", "maximum": 100, "minimum": 1, "type": "integer" @@ -22648,18 +23740,21 @@ { "$ref": "#/components/schemas/ImageFormat" } - ] + ], + "description": "Image format" }, "progressive": { "default": false, "type": "boolean" }, "quality": { + "description": "Quality", "maximum": 100, "minimum": 1, "type": "integer" }, "size": { + "description": "Size", "minimum": 1, "type": "integer" } @@ -22678,9 +23773,11 @@ { "$ref": "#/components/schemas/Colorspace" } - ] + ], + "description": "Colorspace" }, "extractEmbedded": { + "description": "Extract embedded", "type": "boolean" }, "fullsize": { @@ -22786,6 +23883,7 @@ "type": "string" }, "enabled": { + "description": "Enabled", "type": "boolean" } }, @@ -22798,6 +23896,7 @@ "SystemConfigLibraryWatchDto": { "properties": { "enabled": { + "description": "Enabled", "type": "boolean" } }, @@ -22809,6 +23908,7 @@ "SystemConfigLoggingDto": { "properties": { "enabled": { + "description": "Enabled", "type": "boolean" }, "level": { @@ -22837,6 +23937,7 @@ "$ref": "#/components/schemas/DuplicateDetectionConfig" }, "enabled": { + "description": "Enabled", "type": "boolean" }, "facialRecognition": { @@ -22873,6 +23974,7 @@ "type": "string" }, "enabled": { + "description": "Enabled", "type": "boolean" }, "lightStyle": { @@ -22901,6 +24003,7 @@ "SystemConfigNewVersionCheckDto": { "properties": { "enabled": { + "description": "Enabled", "type": "boolean" } }, @@ -22912,21 +24015,26 @@ "SystemConfigNightlyTasksDto": { "properties": { "clusterNewFaces": { + "description": "Cluster new faces", "type": "boolean" }, "databaseCleanup": { + "description": "Database cleanup", "type": "boolean" }, "generateMemories": { + "description": "Generate memories", "type": "boolean" }, "missingThumbnails": { + "description": "Missing thumbnails", "type": "boolean" }, "startTime": { "type": "string" }, "syncQuotaUsage": { + "description": "Sync quota usage", "type": "boolean" } }, @@ -22954,58 +24062,74 @@ "SystemConfigOAuthDto": { "properties": { "autoLaunch": { + "description": "Auto launch", "type": "boolean" }, "autoRegister": { + "description": "Auto register", "type": "boolean" }, "buttonText": { + "description": "Button text", "type": "string" }, "clientId": { + "description": "Client ID", "type": "string" }, "clientSecret": { + "description": "Client secret", "type": "string" }, "defaultStorageQuota": { + "description": "Default storage quota", "format": "int64", "minimum": 0, "nullable": true, "type": "integer" }, "enabled": { + "description": "Enabled", "type": "boolean" }, "issuerUrl": { + "description": "Issuer URL", "type": "string" }, "mobileOverrideEnabled": { + "description": "Mobile override enabled", "type": "boolean" }, "mobileRedirectUri": { + "description": "Mobile redirect URI", "format": "uri", "type": "string" }, "profileSigningAlgorithm": { + "description": "Profile signing algorithm", "type": "string" }, "roleClaim": { + "description": "Role claim", "type": "string" }, "scope": { + "description": "Scope", "type": "string" }, "signingAlgorithm": { "type": "string" }, "storageLabelClaim": { + "description": "Storage label claim", "type": "string" }, "storageQuotaClaim": { + "description": "Storage quota claim", "type": "string" }, "timeout": { + "description": "Timeout", "minimum": 1, "type": "integer" }, @@ -23014,7 +24138,8 @@ { "$ref": "#/components/schemas/OAuthTokenEndpointAuthMethod" } - ] + ], + "description": "Token endpoint auth method" } }, "required": [ @@ -23042,6 +24167,7 @@ "SystemConfigPasswordLoginDto": { "properties": { "enabled": { + "description": "Enabled", "type": "boolean" } }, @@ -23053,6 +24179,7 @@ "SystemConfigReverseGeocodingDto": { "properties": { "enabled": { + "description": "Enabled", "type": "boolean" } }, @@ -23064,13 +24191,16 @@ "SystemConfigServerDto": { "properties": { "externalDomain": { + "description": "External domain", "format": "uri", "type": "string" }, "loginPageMessage": { + "description": "Login page message", "type": "string" }, "publicUsers": { + "description": "Public users", "type": "boolean" } }, @@ -23084,12 +24214,15 @@ "SystemConfigSmtpDto": { "properties": { "enabled": { + "description": "Whether SMTP email notifications are enabled", "type": "boolean" }, "from": { + "description": "Email address to send from", "type": "string" }, "replyTo": { + "description": "Email address for replies", "type": "string" }, "transport": { @@ -23107,23 +24240,29 @@ "SystemConfigSmtpTransportDto": { "properties": { "host": { + "description": "SMTP server hostname", "type": "string" }, "ignoreCert": { + "description": "Whether to ignore SSL certificate errors", "type": "boolean" }, "password": { + "description": "SMTP password", "type": "string" }, "port": { + "description": "SMTP server port", "maximum": 65535, "minimum": 0, "type": "number" }, "secure": { + "description": "Whether to use secure connection (TLS/SSL)", "type": "boolean" }, "username": { + "description": "SMTP username", "type": "string" } }, @@ -23140,12 +24279,15 @@ "SystemConfigStorageTemplateDto": { "properties": { "enabled": { + "description": "Enabled", "type": "boolean" }, "hashVerificationEnabled": { + "description": "Hash verification enabled", "type": "boolean" }, "template": { + "description": "Template", "type": "string" } }, @@ -23178,48 +24320,56 @@ "SystemConfigTemplateStorageOptionDto": { "properties": { "dayOptions": { + "description": "Available day format options for storage template", "items": { "type": "string" }, "type": "array" }, "hourOptions": { + "description": "Available hour format options for storage template", "items": { "type": "string" }, "type": "array" }, "minuteOptions": { + "description": "Available minute format options for storage template", "items": { "type": "string" }, "type": "array" }, "monthOptions": { + "description": "Available month format options for storage template", "items": { "type": "string" }, "type": "array" }, "presetOptions": { + "description": "Available preset template options", "items": { "type": "string" }, "type": "array" }, "secondOptions": { + "description": "Available second format options for storage template", "items": { "type": "string" }, "type": "array" }, "weekOptions": { + "description": "Available week format options for storage template", "items": { "type": "string" }, "type": "array" }, "yearOptions": { + "description": "Available year format options for storage template", "items": { "type": "string" }, @@ -23252,6 +24402,7 @@ "SystemConfigThemeDto": { "properties": { "customCss": { + "description": "Custom CSS for theming", "type": "string" } }, @@ -23263,10 +24414,12 @@ "SystemConfigTrashDto": { "properties": { "days": { + "description": "Days", "minimum": 0, "type": "integer" }, "enabled": { + "description": "Enabled", "type": "boolean" } }, @@ -23279,6 +24432,7 @@ "SystemConfigUserDto": { "properties": { "deleteDelay": { + "description": "Delete delay", "minimum": 1, "type": "integer" } @@ -23291,6 +24445,7 @@ "TagBulkAssetsDto": { "properties": { "assetIds": { + "description": "Asset IDs", "items": { "format": "uuid", "type": "string" @@ -23298,6 +24453,7 @@ "type": "array" }, "tagIds": { + "description": "Tag IDs", "items": { "format": "uuid", "type": "string" @@ -23314,6 +24470,7 @@ "TagBulkAssetsResponseDto": { "properties": { "count": { + "description": "Number of assets tagged", "type": "integer" } }, @@ -23325,13 +24482,16 @@ "TagCreateDto": { "properties": { "color": { + "description": "Tag color (hex)", "pattern": "^#?([0-9A-F]{3}|[0-9A-F]{4}|[0-9A-F]{6}|[0-9A-F]{8})$", "type": "string" }, "name": { + "description": "Tag name", "type": "string" }, "parentId": { + "description": "Parent tag ID", "format": "uuid", "nullable": true, "type": "string" @@ -23345,26 +24505,33 @@ "TagResponseDto": { "properties": { "color": { + "description": "Tag color (hex)", "type": "string" }, "createdAt": { + "description": "Creation date", "format": "date-time", "type": "string" }, "id": { + "description": "Tag ID", "type": "string" }, "name": { + "description": "Tag name", "type": "string" }, "parentId": { + "description": "Parent tag ID", "type": "string" }, "updatedAt": { + "description": "Last update date", "format": "date-time", "type": "string" }, "value": { + "description": "Tag value (full path)", "type": "string" } }, @@ -23380,6 +24547,7 @@ "TagUpdateDto": { "properties": { "color": { + "description": "Tag color (hex)", "nullable": true, "type": "string" } @@ -23389,6 +24557,7 @@ "TagUpsertDto": { "properties": { "tags": { + "description": "Tag names to upsert", "items": { "type": "string" }, @@ -23404,10 +24573,12 @@ "properties": { "enabled": { "default": true, + "description": "Whether tags are enabled", "type": "boolean" }, "sidebarWeb": { "default": true, + "description": "Whether tags appear in web sidebar", "type": "boolean" } }, @@ -23420,9 +24591,11 @@ "TagsUpdate": { "properties": { "enabled": { + "description": "Whether tags are enabled", "type": "boolean" }, "sidebarWeb": { + "description": "Whether tags appear in web sidebar", "type": "boolean" } }, @@ -23431,6 +24604,7 @@ "TemplateDto": { "properties": { "template": { + "description": "Template name", "type": "string" } }, @@ -23442,9 +24616,11 @@ "TemplateResponseDto": { "properties": { "html": { + "description": "Template HTML content", "type": "string" }, "name": { + "description": "Template name", "type": "string" } }, @@ -23457,6 +24633,7 @@ "TestEmailResponseDto": { "properties": { "messageId": { + "description": "Email message ID", "type": "string" } }, @@ -23492,7 +24669,7 @@ "type": "array" }, "fileCreatedAt": { - "description": "Array of file creation timestamps in UTC (ISO 8601 format, without timezone)", + "description": "Array of file creation timestamps in UTC", "items": { "type": "string" }, @@ -23647,6 +24824,7 @@ "type": "object" }, "ToneMapping": { + "description": "Tone mapping", "enum": [ "hable", "mobius", @@ -23656,6 +24834,7 @@ "type": "string" }, "TranscodeHWAccel": { + "description": "Transcode hardware acceleration", "enum": [ "nvenc", "qsv", @@ -23666,6 +24845,7 @@ "type": "string" }, "TranscodePolicy": { + "description": "Transcode policy", "enum": [ "all", "optimal", @@ -23678,6 +24858,7 @@ "TrashResponseDto": { "properties": { "count": { + "description": "Number of items in trash", "type": "integer" } }, @@ -23689,16 +24870,20 @@ "UpdateAlbumDto": { "properties": { "albumName": { + "description": "Album name", "type": "string" }, "albumThumbnailAssetId": { + "description": "Album thumbnail asset ID", "format": "uuid", "type": "string" }, "description": { + "description": "Album description", "type": "string" }, "isActivityEnabled": { + "description": "Enable activity feed", "type": "boolean" }, "order": { @@ -23706,7 +24891,8 @@ { "$ref": "#/components/schemas/AssetOrder" } - ] + ], + "description": "Asset sort order" } }, "type": "object" @@ -23718,7 +24904,8 @@ { "$ref": "#/components/schemas/AlbumUserRole" } - ] + ], + "description": "Album user role" } }, "required": [ @@ -23729,26 +24916,33 @@ "UpdateAssetDto": { "properties": { "dateTimeOriginal": { + "description": "Original date and time", "type": "string" }, "description": { + "description": "Asset description", "type": "string" }, "isFavorite": { + "description": "Mark as favorite", "type": "boolean" }, "latitude": { + "description": "Latitude coordinate", "type": "number" }, "livePhotoVideoId": { + "description": "Live photo video ID", "format": "uuid", "nullable": true, "type": "string" }, "longitude": { + "description": "Longitude coordinate", "type": "number" }, "rating": { + "description": "Rating", "maximum": 5, "minimum": -1, "type": "number" @@ -23758,7 +24952,8 @@ { "$ref": "#/components/schemas/AssetVisibility" } - ] + ], + "description": "Asset visibility" } }, "type": "object" @@ -23766,6 +24961,7 @@ "UpdateLibraryDto": { "properties": { "exclusionPatterns": { + "description": "Exclusion patterns (max 128)", "items": { "type": "string" }, @@ -23774,6 +24970,7 @@ "uniqueItems": true }, "importPaths": { + "description": "Import paths (max 128)", "items": { "type": "string" }, @@ -23782,6 +24979,7 @@ "uniqueItems": true }, "name": { + "description": "Library name", "type": "string" } }, @@ -23790,32 +24988,40 @@ "UsageByUserDto": { "properties": { "photos": { + "description": "Number of photos", "type": "integer" }, "quotaSizeInBytes": { + "description": "User quota size in bytes (null if unlimited)", "format": "int64", "nullable": true, "type": "integer" }, "usage": { + "description": "Total storage usage in bytes", "format": "int64", "type": "integer" }, "usagePhotos": { + "description": "Storage usage for photos in bytes", "format": "int64", "type": "integer" }, "usageVideos": { + "description": "Storage usage for videos in bytes", "format": "int64", "type": "integer" }, "userId": { + "description": "User ID", "type": "string" }, "userName": { + "description": "User name", "type": "string" }, "videos": { + "description": "Number of videos", "type": "integer" } }, @@ -23839,34 +25045,43 @@ "$ref": "#/components/schemas/UserAvatarColor" } ], + "description": "Avatar color", "nullable": true }, "email": { + "description": "User email", "format": "email", "type": "string" }, "isAdmin": { + "description": "Grant admin privileges", "type": "boolean" }, "name": { + "description": "User name", "type": "string" }, "notify": { + "description": "Send notification email", "type": "boolean" }, "password": { + "description": "User password", "type": "string" }, "quotaSizeInBytes": { + "description": "Storage quota in bytes", "format": "int64", "minimum": 0, "nullable": true, "type": "integer" }, "shouldChangePassword": { + "description": "Require password change on next login", "type": "boolean" }, "storageLabel": { + "description": "Storage label", "nullable": true, "type": "string" } @@ -23881,6 +25096,7 @@ "UserAdminDeleteDto": { "properties": { "force": { + "description": "Force delete even if user has assets", "type": "boolean" } }, @@ -23893,24 +25109,30 @@ { "$ref": "#/components/schemas/UserAvatarColor" } - ] + ], + "description": "Avatar color" }, "createdAt": { + "description": "Creation date", "format": "date-time", "type": "string" }, "deletedAt": { + "description": "Deletion date", "format": "date-time", "nullable": true, "type": "string" }, "email": { + "description": "User email", "type": "string" }, "id": { + "description": "User ID", "type": "string" }, "isAdmin": { + "description": "Is admin user", "type": "boolean" }, "license": { @@ -23919,32 +25141,40 @@ "$ref": "#/components/schemas/UserLicense" } ], + "description": "User license", "nullable": true }, "name": { + "description": "User name", "type": "string" }, "oauthId": { + "description": "OAuth ID", "type": "string" }, "profileChangedAt": { + "description": "Profile change date", "format": "date-time", "type": "string" }, "profileImagePath": { + "description": "Profile image path", "type": "string" }, "quotaSizeInBytes": { + "description": "Storage quota in bytes", "format": "int64", "nullable": true, "type": "integer" }, "quotaUsageInBytes": { + "description": "Storage usage in bytes", "format": "int64", "nullable": true, "type": "integer" }, "shouldChangePassword": { + "description": "Require password change on next login", "type": "boolean" }, "status": { @@ -23952,13 +25182,16 @@ { "$ref": "#/components/schemas/UserStatus" } - ] + ], + "description": "User status" }, "storageLabel": { + "description": "Storage label", "nullable": true, "type": "string" }, "updatedAt": { + "description": "Last update date", "format": "date-time", "type": "string" } @@ -23992,36 +25225,45 @@ "$ref": "#/components/schemas/UserAvatarColor" } ], + "description": "Avatar color", "nullable": true }, "email": { + "description": "User email", "format": "email", "type": "string" }, "isAdmin": { + "description": "Grant admin privileges", "type": "boolean" }, "name": { + "description": "User name", "type": "string" }, "password": { + "description": "User password", "type": "string" }, "pinCode": { + "description": "PIN code", "example": "123456", "nullable": true, "type": "string" }, "quotaSizeInBytes": { + "description": "Storage quota in bytes", "format": "int64", "minimum": 0, "nullable": true, "type": "integer" }, "shouldChangePassword": { + "description": "Require password change on next login", "type": "boolean" }, "storageLabel": { + "description": "Storage label", "nullable": true, "type": "string" } @@ -24029,6 +25271,7 @@ "type": "object" }, "UserAvatarColor": { + "description": "Avatar color", "enum": [ "primary", "pink", @@ -24046,13 +25289,16 @@ "UserLicense": { "properties": { "activatedAt": { + "description": "Activation date", "format": "date-time", "type": "string" }, "activationKey": { + "description": "Activation key", "type": "string" }, "licenseKey": { + "description": "License key", "type": "string" } }, @@ -24064,6 +25310,7 @@ "type": "object" }, "UserMetadataKey": { + "description": "User metadata key", "enum": [ "preferences", "license", @@ -24170,22 +25417,28 @@ { "$ref": "#/components/schemas/UserAvatarColor" } - ] + ], + "description": "Avatar color" }, "email": { + "description": "User email", "type": "string" }, "id": { + "description": "User ID", "type": "string" }, "name": { + "description": "User name", "type": "string" }, "profileChangedAt": { + "description": "Profile change date", "format": "date-time", "type": "string" }, "profileImagePath": { + "description": "Profile image path", "type": "string" } }, @@ -24200,6 +25453,7 @@ "type": "object" }, "UserStatus": { + "description": "User status", "enum": [ "active", "removing", @@ -24215,16 +25469,20 @@ "$ref": "#/components/schemas/UserAvatarColor" } ], + "description": "Avatar color", "nullable": true }, "email": { + "description": "User email", "format": "email", "type": "string" }, "name": { + "description": "User name", "type": "string" }, "password": { + "description": "User password (deprecated, use change password endpoint)", "type": "string" } }, @@ -24233,6 +25491,7 @@ "ValidateAccessTokenResponseDto": { "properties": { "authStatus": { + "description": "Authentication status", "type": "boolean" } }, @@ -24244,6 +25503,7 @@ "ValidateLibraryDto": { "properties": { "exclusionPatterns": { + "description": "Exclusion patterns (max 128)", "items": { "type": "string" }, @@ -24252,6 +25512,7 @@ "uniqueItems": true }, "importPaths": { + "description": "Import paths to validate (max 128)", "items": { "type": "string" }, @@ -24265,13 +25526,16 @@ "ValidateLibraryImportPathResponseDto": { "properties": { "importPath": { + "description": "Import path", "type": "string" }, "isValid": { "default": false, + "description": "Is valid", "type": "boolean" }, "message": { + "description": "Validation message", "type": "string" } }, @@ -24284,6 +25548,7 @@ "ValidateLibraryResponseDto": { "properties": { "importPaths": { + "description": "Validation results for import paths", "items": { "$ref": "#/components/schemas/ValidateLibraryImportPathResponseDto" }, @@ -24295,10 +25560,12 @@ "VersionCheckStateResponseDto": { "properties": { "checkedAt": { + "description": "Last check timestamp", "nullable": true, "type": "string" }, "releaseVersion": { + "description": "Release version", "nullable": true, "type": "string" } @@ -24310,6 +25577,7 @@ "type": "object" }, "VideoCodec": { + "description": "Target video codec", "enum": [ "h264", "hevc", @@ -24319,6 +25587,7 @@ "type": "string" }, "VideoContainer": { + "description": "Accepted containers", "enum": [ "mov", "mp4", @@ -24330,9 +25599,11 @@ "WorkflowActionItemDto": { "properties": { "actionConfig": { + "description": "Action configuration", "type": "object" }, "pluginActionId": { + "description": "Plugin action ID", "format": "uuid", "type": "string" } @@ -24345,19 +25616,24 @@ "WorkflowActionResponseDto": { "properties": { "actionConfig": { + "description": "Action configuration", "nullable": true, "type": "object" }, "id": { + "description": "Action ID", "type": "string" }, "order": { + "description": "Action order", "type": "number" }, "pluginActionId": { + "description": "Plugin action ID", "type": "string" }, "workflowId": { + "description": "Workflow ID", "type": "string" } }, @@ -24373,24 +25649,29 @@ "WorkflowCreateDto": { "properties": { "actions": { + "description": "Workflow actions", "items": { "$ref": "#/components/schemas/WorkflowActionItemDto" }, "type": "array" }, "description": { + "description": "Workflow description", "type": "string" }, "enabled": { + "description": "Workflow enabled", "type": "boolean" }, "filters": { + "description": "Workflow filters", "items": { "$ref": "#/components/schemas/WorkflowFilterItemDto" }, "type": "array" }, "name": { + "description": "Workflow name", "type": "string" }, "triggerType": { @@ -24398,7 +25679,8 @@ { "$ref": "#/components/schemas/PluginTriggerType" } - ] + ], + "description": "Workflow trigger type" } }, "required": [ @@ -24412,9 +25694,11 @@ "WorkflowFilterItemDto": { "properties": { "filterConfig": { + "description": "Filter configuration", "type": "object" }, "pluginFilterId": { + "description": "Plugin filter ID", "format": "uuid", "type": "string" } @@ -24427,19 +25711,24 @@ "WorkflowFilterResponseDto": { "properties": { "filterConfig": { + "description": "Filter configuration", "nullable": true, "type": "object" }, "id": { + "description": "Filter ID", "type": "string" }, "order": { + "description": "Filter order", "type": "number" }, "pluginFilterId": { + "description": "Plugin filter ID", "type": "string" }, "workflowId": { + "description": "Workflow ID", "type": "string" } }, @@ -24455,34 +25744,42 @@ "WorkflowResponseDto": { "properties": { "actions": { + "description": "Workflow actions", "items": { "$ref": "#/components/schemas/WorkflowActionResponseDto" }, "type": "array" }, "createdAt": { + "description": "Creation date", "type": "string" }, "description": { + "description": "Workflow description", "type": "string" }, "enabled": { + "description": "Workflow enabled", "type": "boolean" }, "filters": { + "description": "Workflow filters", "items": { "$ref": "#/components/schemas/WorkflowFilterResponseDto" }, "type": "array" }, "id": { + "description": "Workflow ID", "type": "string" }, "name": { + "description": "Workflow name", "nullable": true, "type": "string" }, "ownerId": { + "description": "Owner user ID", "type": "string" }, "triggerType": { @@ -24490,7 +25787,8 @@ { "$ref": "#/components/schemas/PluginTriggerType" } - ] + ], + "description": "Workflow trigger type" } }, "required": [ @@ -24509,24 +25807,29 @@ "WorkflowUpdateDto": { "properties": { "actions": { + "description": "Workflow actions", "items": { "$ref": "#/components/schemas/WorkflowActionItemDto" }, "type": "array" }, "description": { + "description": "Workflow description", "type": "string" }, "enabled": { + "description": "Workflow enabled", "type": "boolean" }, "filters": { + "description": "Workflow filters", "items": { "$ref": "#/components/schemas/WorkflowFilterItemDto" }, "type": "array" }, "name": { + "description": "Workflow name", "type": "string" }, "triggerType": { @@ -24534,7 +25837,8 @@ { "$ref": "#/components/schemas/PluginTriggerType" } - ] + ], + "description": "Workflow trigger type" } }, "type": "object" diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts index 9d111559a..d8c960a39 100644 --- a/open-api/typescript-sdk/src/fetch-client.ts +++ b/open-api/typescript-sdk/src/fetch-client.ts @@ -15,29 +15,46 @@ export const servers = { server1: "/api" }; export type UserResponseDto = { + /** Avatar color */ avatarColor: UserAvatarColor; + /** User email */ email: string; + /** User ID */ id: string; + /** User name */ name: string; + /** Profile change date */ profileChangedAt: string; + /** Profile image path */ profileImagePath: string; }; export type ActivityResponseDto = { + /** Asset ID (if activity is for an asset) */ assetId: string | null; + /** Comment text (for comment activities) */ comment?: string | null; + /** Creation date */ createdAt: string; + /** Activity ID */ id: string; + /** Activity type */ "type": ReactionType; user: UserResponseDto; }; export type ActivityCreateDto = { + /** Album ID */ albumId: string; + /** Asset ID (if activity is for an asset) */ assetId?: string; + /** Comment text (required if type is comment) */ comment?: string; + /** Activity type (like or comment) */ "type": ReactionType; }; export type ActivityStatisticsResponseDto = { + /** Number of comments */ comments: number; + /** Number of likes */ likes: number; }; export type DatabaseBackupDeleteDto = { @@ -54,25 +71,34 @@ export type DatabaseBackupUploadDto = { file?: Blob; }; export type SetMaintenanceModeDto = { + /** Maintenance action */ action: MaintenanceAction; + /** Restore backup filename */ restoreBackupFilename?: string; }; export type MaintenanceDetectInstallStorageFolderDto = { + /** Number of files in the folder */ files: number; + /** Storage folder */ folder: StorageFolder; + /** Whether the folder is readable */ readable: boolean; + /** Whether the folder is writable */ writable: boolean; }; export type MaintenanceDetectInstallResponseDto = { storage: MaintenanceDetectInstallStorageFolderDto[]; }; export type MaintenanceLoginDto = { + /** Maintenance token */ token?: string; }; export type MaintenanceAuthDto = { + /** Maintenance username */ username: string; }; export type MaintenanceStatusResponseDto = { + /** Maintenance action */ action: MaintenanceAction; active: boolean; error?: string; @@ -80,137 +106,224 @@ export type MaintenanceStatusResponseDto = { task?: string; }; export type NotificationCreateDto = { + /** Additional notification data */ data?: object; + /** Notification description */ description?: string | null; + /** Notification level */ level?: NotificationLevel; + /** Date when notification was read */ readAt?: string | null; + /** Notification title */ title: string; + /** Notification type */ "type"?: NotificationType; + /** User ID to send notification to */ userId: string; }; export type NotificationDto = { + /** Creation date */ createdAt: string; + /** Additional notification data */ data?: object; + /** Notification description */ description?: string; + /** Notification ID */ id: string; + /** Notification level */ level: NotificationLevel; + /** Date when notification was read */ readAt?: string; + /** Notification title */ title: string; + /** Notification type */ "type": NotificationType; }; export type TemplateDto = { + /** Template name */ template: string; }; export type TemplateResponseDto = { + /** Template HTML content */ html: string; + /** Template name */ name: string; }; export type SystemConfigSmtpTransportDto = { + /** SMTP server hostname */ host: string; + /** Whether to ignore SSL certificate errors */ ignoreCert: boolean; + /** SMTP password */ password: string; + /** SMTP server port */ port: number; + /** Whether to use secure connection (TLS/SSL) */ secure: boolean; + /** SMTP username */ username: string; }; export type SystemConfigSmtpDto = { + /** Whether SMTP email notifications are enabled */ enabled: boolean; + /** Email address to send from */ "from": string; + /** Email address for replies */ replyTo: string; transport: SystemConfigSmtpTransportDto; }; export type TestEmailResponseDto = { + /** Email message ID */ messageId: string; }; export type UserLicense = { + /** Activation date */ activatedAt: string; + /** Activation key */ activationKey: string; + /** License key */ licenseKey: string; }; export type UserAdminResponseDto = { + /** Avatar color */ avatarColor: UserAvatarColor; + /** Creation date */ createdAt: string; + /** Deletion date */ deletedAt: string | null; + /** User email */ email: string; + /** User ID */ id: string; + /** Is admin user */ isAdmin: boolean; + /** User license */ license: (UserLicense) | null; + /** User name */ name: string; + /** OAuth ID */ oauthId: string; + /** Profile change date */ profileChangedAt: string; + /** Profile image path */ profileImagePath: string; + /** Storage quota in bytes */ quotaSizeInBytes: number | null; + /** Storage usage in bytes */ quotaUsageInBytes: number | null; + /** Require password change on next login */ shouldChangePassword: boolean; + /** User status */ status: UserStatus; + /** Storage label */ storageLabel: string | null; + /** Last update date */ updatedAt: string; }; export type UserAdminCreateDto = { + /** Avatar color */ avatarColor?: (UserAvatarColor) | null; + /** User email */ email: string; + /** Grant admin privileges */ isAdmin?: boolean; + /** User name */ name: string; + /** Send notification email */ notify?: boolean; + /** User password */ password: string; + /** Storage quota in bytes */ quotaSizeInBytes?: number | null; + /** Require password change on next login */ shouldChangePassword?: boolean; + /** Storage label */ storageLabel?: string | null; }; export type UserAdminDeleteDto = { + /** Force delete even if user has assets */ force?: boolean; }; export type UserAdminUpdateDto = { + /** Avatar color */ avatarColor?: (UserAvatarColor) | null; + /** User email */ email?: string; + /** Grant admin privileges */ isAdmin?: boolean; + /** User name */ name?: string; + /** User password */ password?: string; + /** PIN code */ pinCode?: string | null; + /** Storage quota in bytes */ quotaSizeInBytes?: number | null; + /** Require password change on next login */ shouldChangePassword?: boolean; + /** Storage label */ storageLabel?: string | null; }; export type AlbumsResponse = { + /** Default asset order for albums */ defaultAssetOrder: AssetOrder; }; export type CastResponse = { + /** Whether Google Cast is enabled */ gCastEnabled: boolean; }; export type DownloadResponse = { + /** Maximum archive size in bytes */ archiveSize: number; + /** Whether to include embedded videos in downloads */ includeEmbeddedVideos: boolean; }; export type EmailNotificationsResponse = { + /** Whether to receive email notifications for album invites */ albumInvite: boolean; + /** Whether to receive email notifications for album updates */ albumUpdate: boolean; + /** Whether email notifications are enabled */ enabled: boolean; }; export type FoldersResponse = { + /** Whether folders are enabled */ enabled: boolean; + /** Whether folders appear in web sidebar */ sidebarWeb: boolean; }; export type MemoriesResponse = { + /** Memory duration in seconds */ duration: number; + /** Whether memories are enabled */ enabled: boolean; }; export type PeopleResponse = { + /** Whether people are enabled */ enabled: boolean; + /** Whether people appear in web sidebar */ sidebarWeb: boolean; }; export type PurchaseResponse = { + /** Date until which to hide buy button */ hideBuyButtonUntil: string; + /** Whether to show support badge */ showSupportBadge: boolean; }; export type RatingsResponse = { + /** Whether ratings are enabled */ enabled: boolean; }; export type SharedLinksResponse = { + /** Whether shared links are enabled */ enabled: boolean; + /** Whether shared links appear in web sidebar */ sidebarWeb: boolean; }; export type TagsResponse = { + /** Whether tags are enabled */ enabled: boolean; + /** Whether tags appear in web sidebar */ sidebarWeb: boolean; }; export type UserPreferencesResponseDto = { @@ -227,48 +340,69 @@ export type UserPreferencesResponseDto = { tags: TagsResponse; }; export type AlbumsUpdate = { + /** Default asset order for albums */ defaultAssetOrder?: AssetOrder; }; export type AvatarUpdate = { + /** Avatar color */ color?: UserAvatarColor; }; export type CastUpdate = { + /** Whether Google Cast is enabled */ gCastEnabled?: boolean; }; export type DownloadUpdate = { + /** Maximum archive size in bytes */ archiveSize?: number; + /** Whether to include embedded videos in downloads */ includeEmbeddedVideos?: boolean; }; export type EmailNotificationsUpdate = { + /** Whether to receive email notifications for album invites */ albumInvite?: boolean; + /** Whether to receive email notifications for album updates */ albumUpdate?: boolean; + /** Whether email notifications are enabled */ enabled?: boolean; }; export type FoldersUpdate = { + /** Whether folders are enabled */ enabled?: boolean; + /** Whether folders appear in web sidebar */ sidebarWeb?: boolean; }; export type MemoriesUpdate = { + /** Memory duration in seconds */ duration?: number; + /** Whether memories are enabled */ enabled?: boolean; }; export type PeopleUpdate = { + /** Whether people are enabled */ enabled?: boolean; + /** Whether people appear in web sidebar */ sidebarWeb?: boolean; }; export type PurchaseUpdate = { + /** Date until which to hide buy button */ hideBuyButtonUntil?: string; + /** Whether to show support badge */ showSupportBadge?: boolean; }; export type RatingsUpdate = { + /** Whether ratings are enabled */ enabled?: boolean; }; export type SharedLinksUpdate = { + /** Whether shared links are enabled */ enabled?: boolean; + /** Whether shared links appear in web sidebar */ sidebarWeb?: boolean; }; export type TagsUpdate = { + /** Whether tags are enabled */ enabled?: boolean; + /** Whether tags appear in web sidebar */ sidebarWeb?: boolean; }; export type UserPreferencesUpdateDto = { @@ -286,325 +420,531 @@ export type UserPreferencesUpdateDto = { tags?: TagsUpdate; }; export type SessionResponseDto = { + /** App version */ appVersion: string | null; + /** Creation date */ createdAt: string; + /** Is current session */ current: boolean; + /** Device OS */ deviceOS: string; + /** Device type */ deviceType: string; + /** Expiration date */ expiresAt?: string; + /** Session ID */ id: string; + /** Is pending sync reset */ isPendingSyncReset: boolean; + /** Last update date */ updatedAt: string; }; export type AssetStatsResponseDto = { + /** Number of images */ images: number; + /** Total number of assets */ total: number; + /** Number of videos */ videos: number; }; export type AlbumUserResponseDto = { + /** Album user role */ role: AlbumUserRole; user: UserResponseDto; }; export type ExifResponseDto = { + /** City name */ city?: string | null; + /** Country name */ country?: string | null; + /** Original date/time */ dateTimeOriginal?: string | null; + /** Image description */ description?: string | null; + /** Image height in pixels */ exifImageHeight?: number | null; + /** Image width in pixels */ exifImageWidth?: number | null; + /** Exposure time */ exposureTime?: string | null; + /** F-number (aperture) */ fNumber?: number | null; + /** File size in bytes */ fileSizeInByte?: number | null; + /** Focal length in mm */ focalLength?: number | null; + /** ISO sensitivity */ iso?: number | null; + /** GPS latitude */ latitude?: number | null; + /** Lens model */ lensModel?: string | null; + /** GPS longitude */ longitude?: number | null; + /** Camera make */ make?: string | null; + /** Camera model */ model?: string | null; + /** Modification date/time */ modifyDate?: string | null; + /** Image orientation */ orientation?: string | null; + /** Projection type */ projectionType?: string | null; + /** Rating */ rating?: number | null; + /** State/province name */ state?: string | null; + /** Time zone */ timeZone?: string | null; }; export type AssetFaceWithoutPersonResponseDto = { + /** Bounding box X1 coordinate */ boundingBoxX1: number; + /** Bounding box X2 coordinate */ boundingBoxX2: number; + /** Bounding box Y1 coordinate */ boundingBoxY1: number; + /** Bounding box Y2 coordinate */ boundingBoxY2: number; + /** Face ID */ id: string; + /** Image height in pixels */ imageHeight: number; + /** Image width in pixels */ imageWidth: number; + /** Face detection source type */ sourceType?: SourceType; }; export type PersonWithFacesResponseDto = { + /** Person date of birth */ birthDate: string | null; + /** Person color (hex) */ color?: string; + /** Face detections */ faces: AssetFaceWithoutPersonResponseDto[]; + /** Person ID */ id: string; + /** Is favorite */ isFavorite?: boolean; + /** Is hidden */ isHidden: boolean; + /** Person name */ name: string; + /** Thumbnail path */ thumbnailPath: string; + /** Last update date */ updatedAt?: string; }; export type AssetStackResponseDto = { + /** Number of assets in stack */ assetCount: number; + /** Stack ID */ id: string; + /** Primary asset ID */ primaryAssetId: string; }; export type TagResponseDto = { + /** Tag color (hex) */ color?: string; + /** Creation date */ createdAt: string; + /** Tag ID */ id: string; + /** Tag name */ name: string; + /** Parent tag ID */ parentId?: string; + /** Last update date */ updatedAt: string; + /** Tag value (full path) */ value: string; }; export type AssetResponseDto = { - /** base64 encoded sha1 hash */ + /** Base64 encoded SHA1 hash */ checksum: string; /** The UTC timestamp when the asset was originally uploaded to Immich. */ createdAt: string; + /** Device asset ID */ deviceAssetId: string; + /** Device ID */ deviceId: string; + /** Duplicate group ID */ duplicateId?: string | null; + /** Video duration (for videos) */ duration: string; exifInfo?: ExifResponseDto; /** The actual UTC timestamp when the file was created/captured, preserving timezone information. This is the authoritative timestamp for chronological sorting within timeline groups. Combined with timezone data, this can be used to determine the exact moment the photo was taken. */ fileCreatedAt: string; /** The UTC timestamp when the file was last modified on the filesystem. This reflects the last time the physical file was changed, which may be different from when the photo was originally taken. */ fileModifiedAt: string; + /** Whether asset has metadata */ hasMetadata: boolean; + /** Asset height */ height: number | null; + /** Asset ID */ id: string; + /** Is archived */ isArchived: boolean; + /** Is edited */ isEdited: boolean; + /** Is favorite */ isFavorite: boolean; + /** Is offline */ isOffline: boolean; + /** Is trashed */ isTrashed: boolean; + /** Library ID */ libraryId?: string | null; + /** Live photo video ID */ livePhotoVideoId?: string | null; /** The local date and time when the photo/video was taken, derived from EXIF metadata. This represents the photographer's local time regardless of timezone, stored as a timezone-agnostic timestamp. Used for timeline grouping by "local" days and months. */ localDateTime: string; + /** Original file name */ originalFileName: string; + /** Original MIME type */ originalMimeType?: string; + /** Original file path */ originalPath: string; owner?: UserResponseDto; + /** Owner user ID */ ownerId: string; people?: PersonWithFacesResponseDto[]; + /** Is resized */ resized?: boolean; stack?: (AssetStackResponseDto) | null; tags?: TagResponseDto[]; + /** Thumbhash for thumbnail generation */ thumbhash: string | null; + /** Asset type */ "type": AssetTypeEnum; unassignedFaces?: AssetFaceWithoutPersonResponseDto[]; /** The UTC timestamp when the asset record was last updated in the database. This is automatically maintained by the database and reflects when any field in the asset was last modified. */ updatedAt: string; + /** Asset visibility */ visibility: AssetVisibility; + /** Asset width */ width: number | null; }; export type ContributorCountResponseDto = { + /** Number of assets contributed */ assetCount: number; + /** User ID */ userId: string; }; export type AlbumResponseDto = { + /** Album name */ albumName: string; + /** Thumbnail asset ID */ albumThumbnailAssetId: string | null; albumUsers: AlbumUserResponseDto[]; + /** Number of assets */ assetCount: number; assets: AssetResponseDto[]; contributorCounts?: ContributorCountResponseDto[]; + /** Creation date */ createdAt: string; + /** Album description */ description: string; + /** End date (latest asset) */ endDate?: string; + /** Has shared link */ hasSharedLink: boolean; + /** Album ID */ id: string; + /** Activity feed enabled */ isActivityEnabled: boolean; + /** Last modified asset timestamp */ lastModifiedAssetTimestamp?: string; + /** Asset sort order */ order?: AssetOrder; owner: UserResponseDto; + /** Owner user ID */ ownerId: string; + /** Is shared album */ shared: boolean; + /** Start date (earliest asset) */ startDate?: string; + /** Last update date */ updatedAt: string; }; export type AlbumUserCreateDto = { + /** Album user role */ role: AlbumUserRole; + /** User ID */ userId: string; }; export type CreateAlbumDto = { + /** Album name */ albumName: string; + /** Album users */ albumUsers?: AlbumUserCreateDto[]; + /** Initial asset IDs */ assetIds?: string[]; + /** Album description */ description?: string; }; export type AlbumsAddAssetsDto = { + /** Album IDs */ albumIds: string[]; + /** Asset IDs */ assetIds: string[]; }; export type AlbumsAddAssetsResponseDto = { + /** Error reason */ error?: BulkIdErrorReason; + /** Operation success */ success: boolean; }; export type AlbumStatisticsResponseDto = { + /** Number of non-shared albums */ notShared: number; + /** Number of owned albums */ owned: number; + /** Number of shared albums */ shared: number; }; export type UpdateAlbumDto = { + /** Album name */ albumName?: string; + /** Album thumbnail asset ID */ albumThumbnailAssetId?: string; + /** Album description */ description?: string; + /** Enable activity feed */ isActivityEnabled?: boolean; + /** Asset sort order */ order?: AssetOrder; }; export type BulkIdsDto = { + /** IDs to process */ ids: string[]; }; export type BulkIdResponseDto = { + /** Error reason if failed */ error?: Error; + /** ID */ id: string; + /** Whether operation succeeded */ success: boolean; }; export type UpdateAlbumUserDto = { + /** Album user role */ role: AlbumUserRole; }; export type AlbumUserAddDto = { + /** Album user role */ role?: AlbumUserRole; + /** User ID */ userId: string; }; export type AddUsersDto = { + /** Album users to add */ albumUsers: AlbumUserAddDto[]; }; export type ApiKeyResponseDto = { + /** Creation date */ createdAt: string; + /** API key ID */ id: string; + /** API key name */ name: string; + /** List of permissions */ permissions: Permission[]; + /** Last update date */ updatedAt: string; }; export type ApiKeyCreateDto = { + /** API key name */ name?: string; + /** List of permissions */ permissions: Permission[]; }; export type ApiKeyCreateResponseDto = { apiKey: ApiKeyResponseDto; + /** API key secret (only shown once) */ secret: string; }; export type ApiKeyUpdateDto = { + /** API key name */ name?: string; + /** List of permissions */ permissions?: Permission[]; }; export type AssetBulkDeleteDto = { + /** Force delete even if in use */ force?: boolean; + /** IDs to process */ ids: string[]; }; export type AssetMetadataUpsertItemDto = { + /** Metadata key */ key: string; + /** Metadata value (object) */ value: object; }; export type AssetMediaCreateDto = { + /** Asset file data */ assetData: Blob; + /** Device asset ID */ deviceAssetId: string; + /** Device ID */ deviceId: string; + /** Duration (for videos) */ duration?: string; + /** File creation date */ fileCreatedAt: string; + /** File modification date */ fileModifiedAt: string; + /** Filename */ filename?: string; + /** Mark as favorite */ isFavorite?: boolean; + /** Live photo video ID */ livePhotoVideoId?: string; + /** Asset metadata items */ metadata?: AssetMetadataUpsertItemDto[]; + /** Sidecar file data */ sidecarData?: Blob; + /** Asset visibility */ visibility?: AssetVisibility; }; export type AssetMediaResponseDto = { + /** Asset media ID */ id: string; + /** Upload status */ status: AssetMediaStatus; }; export type AssetBulkUpdateDto = { + /** Original date and time */ dateTimeOriginal?: string; + /** Relative time offset in seconds */ dateTimeRelative?: number; + /** Asset description */ description?: string; + /** Duplicate asset ID */ duplicateId?: string | null; + /** Asset IDs to update */ ids: string[]; + /** Mark as favorite */ isFavorite?: boolean; + /** Latitude coordinate */ latitude?: number; + /** Longitude coordinate */ longitude?: number; + /** Rating */ rating?: number; + /** Time zone (IANA timezone) */ timeZone?: string; + /** Asset visibility */ visibility?: AssetVisibility; }; export type AssetBulkUploadCheckItem = { - /** base64 or hex encoded sha1 hash */ + /** Base64 or hex encoded SHA1 hash */ checksum: string; + /** Asset ID */ id: string; }; export type AssetBulkUploadCheckDto = { + /** Assets to check */ assets: AssetBulkUploadCheckItem[]; }; export type AssetBulkUploadCheckResult = { + /** Upload action */ action: Action; + /** Existing asset ID if duplicate */ assetId?: string; + /** Asset ID */ id: string; + /** Whether existing asset is trashed */ isTrashed?: boolean; + /** Rejection reason if rejected */ reason?: Reason; }; export type AssetBulkUploadCheckResponseDto = { + /** Upload check results */ results: AssetBulkUploadCheckResult[]; }; export type AssetCopyDto = { + /** Copy album associations */ albums?: boolean; + /** Copy favorite status */ favorite?: boolean; + /** Copy shared links */ sharedLinks?: boolean; + /** Copy sidecar file */ sidecar?: boolean; + /** Source asset ID */ sourceId: string; + /** Copy stack association */ stack?: boolean; + /** Target asset ID */ targetId: string; }; export type CheckExistingAssetsDto = { + /** Device asset IDs to check */ deviceAssetIds: string[]; + /** Device ID */ deviceId: string; }; export type CheckExistingAssetsResponseDto = { + /** Existing asset IDs */ existingIds: string[]; }; export type AssetJobsDto = { + /** Asset IDs */ assetIds: string[]; + /** Job name */ name: AssetJobName; }; export type AssetMetadataBulkDeleteItemDto = { + /** Asset ID */ assetId: string; + /** Metadata key */ key: string; }; export type AssetMetadataBulkDeleteDto = { + /** Metadata items to delete */ items: AssetMetadataBulkDeleteItemDto[]; }; export type AssetMetadataBulkUpsertItemDto = { + /** Asset ID */ assetId: string; + /** Metadata key */ key: string; + /** Metadata value (object) */ value: object; }; export type AssetMetadataBulkUpsertDto = { + /** Metadata items to upsert */ items: AssetMetadataBulkUpsertItemDto[]; }; export type AssetMetadataBulkResponseDto = { + /** Asset ID */ assetId: string; + /** Metadata key */ key: string; + /** Last update date */ updatedAt: string; + /** Metadata value (object) */ value: object; }; export type UpdateAssetDto = { + /** Original date and time */ dateTimeOriginal?: string; + /** Asset description */ description?: string; + /** Mark as favorite */ isFavorite?: boolean; + /** Latitude coordinate */ latitude?: number; + /** Live photo video ID */ livePhotoVideoId?: string | null; + /** Longitude coordinate */ longitude?: number; + /** Rating */ rating?: number; + /** Asset visibility */ visibility?: AssetVisibility; }; export type CropParameters = { @@ -618,6 +958,7 @@ export type CropParameters = { y: number; }; export type AssetEditActionCrop = { + /** Type of edit action to perform */ action: AssetEditAction; parameters: CropParameters; }; @@ -626,6 +967,7 @@ export type RotateParameters = { angle: number; }; export type AssetEditActionRotate = { + /** Type of edit action to perform */ action: AssetEditAction; parameters: RotateParameters; }; @@ -634,24 +976,30 @@ export type MirrorParameters = { axis: MirrorAxis; }; export type AssetEditActionMirror = { + /** Type of edit action to perform */ action: AssetEditAction; parameters: MirrorParameters; }; export type AssetEditsDto = { + /** Asset ID to apply edits to */ assetId: string; - /** list of edits */ + /** List of edit actions to apply (crop, rotate, or mirror) */ edits: (AssetEditActionCrop | AssetEditActionRotate | AssetEditActionMirror)[]; }; export type AssetEditActionListDto = { - /** list of edits */ + /** List of edit actions to apply (crop, rotate, or mirror) */ edits: (AssetEditActionCrop | AssetEditActionRotate | AssetEditActionMirror)[]; }; export type AssetMetadataResponseDto = { + /** Metadata key */ key: string; + /** Last update date */ updatedAt: string; + /** Metadata value (object) */ value: object; }; export type AssetMetadataUpsertDto = { + /** Metadata items to upsert */ items: AssetMetadataUpsertItemDto[]; }; export type AssetOcrResponseDto = { @@ -681,136 +1029,221 @@ export type AssetOcrResponseDto = { y4: number; }; export type AssetMediaReplaceDto = { + /** Asset file data */ assetData: Blob; + /** Device asset ID */ deviceAssetId: string; + /** Device ID */ deviceId: string; + /** Duration (for videos) */ duration?: string; + /** File creation date */ fileCreatedAt: string; + /** File modification date */ fileModifiedAt: string; + /** Filename */ filename?: string; }; export type SignUpDto = { + /** User email */ email: string; + /** User name */ name: string; + /** User password */ password: string; }; export type ChangePasswordDto = { + /** Invalidate all other sessions */ invalidateSessions?: boolean; + /** New password (min 8 characters) */ newPassword: string; + /** Current password */ password: string; }; export type LoginCredentialDto = { + /** User email */ email: string; + /** User password */ password: string; }; export type LoginResponseDto = { + /** Access token */ accessToken: string; + /** Is admin user */ isAdmin: boolean; + /** Is onboarded */ isOnboarded: boolean; + /** User name */ name: string; + /** Profile image path */ profileImagePath: string; + /** Should change password */ shouldChangePassword: boolean; + /** User email */ userEmail: string; + /** User ID */ userId: string; }; export type LogoutResponseDto = { + /** Redirect URI */ redirectUri: string; + /** Logout successful */ successful: boolean; }; export type PinCodeResetDto = { + /** User password (required if PIN code is not provided) */ password?: string; + /** New PIN code (4-6 digits) */ pinCode?: string; }; export type PinCodeSetupDto = { + /** PIN code (4-6 digits) */ pinCode: string; }; export type PinCodeChangeDto = { + /** New PIN code (4-6 digits) */ newPinCode: string; + /** User password (required if PIN code is not provided) */ password?: string; + /** New PIN code (4-6 digits) */ pinCode?: string; }; export type SessionUnlockDto = { + /** User password (required if PIN code is not provided) */ password?: string; + /** New PIN code (4-6 digits) */ pinCode?: string; }; export type AuthStatusResponseDto = { + /** Session expiration date */ expiresAt?: string; + /** Is elevated session */ isElevated: boolean; + /** Has password set */ password: boolean; + /** Has PIN code set */ pinCode: boolean; + /** PIN expiration date */ pinExpiresAt?: string; }; export type ValidateAccessTokenResponseDto = { + /** Authentication status */ authStatus: boolean; }; export type AssetIdsDto = { + /** Asset IDs */ assetIds: string[]; }; export type DownloadInfoDto = { + /** Album ID to download */ albumId?: string; + /** Archive size limit in bytes */ archiveSize?: number; + /** Asset IDs to download */ assetIds?: string[]; + /** User ID to download assets from */ userId?: string; }; export type DownloadArchiveInfo = { + /** Asset IDs in this archive */ assetIds: string[]; + /** Archive size in bytes */ size: number; }; export type DownloadResponseDto = { + /** Archive information */ archives: DownloadArchiveInfo[]; + /** Total size in bytes */ totalSize: number; }; export type DuplicateResponseDto = { + /** Duplicate assets */ assets: AssetResponseDto[]; + /** Duplicate group ID */ duplicateId: string; }; export type PersonResponseDto = { + /** Person date of birth */ birthDate: string | null; + /** Person color (hex) */ color?: string; + /** Person ID */ id: string; + /** Is favorite */ isFavorite?: boolean; + /** Is hidden */ isHidden: boolean; + /** Person name */ name: string; + /** Thumbnail path */ thumbnailPath: string; + /** Last update date */ updatedAt?: string; }; export type AssetFaceResponseDto = { + /** Bounding box X1 coordinate */ boundingBoxX1: number; + /** Bounding box X2 coordinate */ boundingBoxX2: number; + /** Bounding box Y1 coordinate */ boundingBoxY1: number; + /** Bounding box Y2 coordinate */ boundingBoxY2: number; + /** Face ID */ id: string; + /** Image height in pixels */ imageHeight: number; + /** Image width in pixels */ imageWidth: number; + /** Person associated with face */ person: (PersonResponseDto) | null; + /** Face detection source type */ sourceType?: SourceType; }; export type AssetFaceCreateDto = { + /** Asset ID */ assetId: string; + /** Face bounding box height */ height: number; + /** Image height in pixels */ imageHeight: number; + /** Image width in pixels */ imageWidth: number; + /** Person ID */ personId: string; + /** Face bounding box width */ width: number; + /** Face bounding box X coordinate */ x: number; + /** Face bounding box Y coordinate */ y: number; }; export type AssetFaceDeleteDto = { + /** Force delete even if person has other faces */ force: boolean; }; export type FaceDto = { + /** Face ID */ id: string; }; export type QueueStatisticsDto = { + /** Number of active jobs */ active: number; + /** Number of completed jobs */ completed: number; + /** Number of delayed jobs */ delayed: number; + /** Number of failed jobs */ failed: number; + /** Number of paused jobs */ paused: number; + /** Number of waiting jobs */ waiting: number; }; export type QueueStatusLegacyDto = { + /** Whether the queue is currently active (has running jobs) */ isActive: boolean; + /** Whether the queue is paused */ isPaused: boolean; }; export type QueueResponseLegacyDto = { @@ -838,238 +1271,359 @@ export type QueuesResponseLegacyDto = { workflow: QueueResponseLegacyDto; }; export type JobCreateDto = { + /** Job name */ name: ManualJobName; }; export type QueueCommandDto = { + /** Queue command to execute */ command: QueueCommand; + /** Force the command execution (if applicable) */ force?: boolean; }; export type LibraryResponseDto = { + /** Number of assets */ assetCount: number; + /** Creation date */ createdAt: string; + /** Exclusion patterns */ exclusionPatterns: string[]; + /** Library ID */ id: string; + /** Import paths */ importPaths: string[]; + /** Library name */ name: string; + /** Owner user ID */ ownerId: string; + /** Last refresh date */ refreshedAt: string | null; + /** Last update date */ updatedAt: string; }; export type CreateLibraryDto = { + /** Exclusion patterns (max 128) */ exclusionPatterns?: string[]; + /** Import paths (max 128) */ importPaths?: string[]; + /** Library name */ name?: string; + /** Owner user ID */ ownerId: string; }; export type UpdateLibraryDto = { + /** Exclusion patterns (max 128) */ exclusionPatterns?: string[]; + /** Import paths (max 128) */ importPaths?: string[]; + /** Library name */ name?: string; }; export type LibraryStatsResponseDto = { + /** Number of photos */ photos: number; + /** Total number of assets */ total: number; + /** Storage usage in bytes */ usage: number; + /** Number of videos */ videos: number; }; export type ValidateLibraryDto = { + /** Exclusion patterns (max 128) */ exclusionPatterns?: string[]; + /** Import paths to validate (max 128) */ importPaths?: string[]; }; export type ValidateLibraryImportPathResponseDto = { + /** Import path */ importPath: string; + /** Is valid */ isValid: boolean; + /** Validation message */ message?: string; }; export type ValidateLibraryResponseDto = { + /** Validation results for import paths */ importPaths?: ValidateLibraryImportPathResponseDto[]; }; export type MapMarkerResponseDto = { + /** City name */ city: string | null; + /** Country name */ country: string | null; + /** Asset ID */ id: string; + /** Latitude */ lat: number; + /** Longitude */ lon: number; + /** State/Province name */ state: string | null; }; export type MapReverseGeocodeResponseDto = { + /** City name */ city: string | null; + /** Country name */ country: string | null; + /** State/Province name */ state: string | null; }; export type OnThisDayDto = { + /** Year for on this day memory */ year: number; }; export type MemoryResponseDto = { assets: AssetResponseDto[]; + /** Creation date */ createdAt: string; data: OnThisDayDto; + /** Deletion date */ deletedAt?: string; + /** Date when memory should be hidden */ hideAt?: string; + /** Memory ID */ id: string; + /** Is memory saved */ isSaved: boolean; + /** Memory date */ memoryAt: string; + /** Owner user ID */ ownerId: string; + /** Date when memory was seen */ seenAt?: string; + /** Date when memory should be shown */ showAt?: string; + /** Memory type */ "type": MemoryType; + /** Last update date */ updatedAt: string; }; export type MemoryCreateDto = { + /** Asset IDs to associate with memory */ assetIds?: string[]; data: OnThisDayDto; + /** Is memory saved */ isSaved?: boolean; + /** Memory date */ memoryAt: string; + /** Date when memory was seen */ seenAt?: string; + /** Memory type */ "type": MemoryType; }; export type MemoryStatisticsResponseDto = { + /** Total number of memories */ total: number; }; export type MemoryUpdateDto = { + /** Is memory saved */ isSaved?: boolean; + /** Memory date */ memoryAt?: string; + /** Date when memory was seen */ seenAt?: string; }; export type NotificationDeleteAllDto = { + /** Notification IDs to delete */ ids: string[]; }; export type NotificationUpdateAllDto = { + /** Notification IDs to update */ ids: string[]; + /** Date when notifications were read */ readAt?: string | null; }; export type NotificationUpdateDto = { + /** Date when notification was read */ readAt?: string | null; }; export type OAuthConfigDto = { + /** OAuth code challenge (PKCE) */ codeChallenge?: string; + /** OAuth redirect URI */ redirectUri: string; + /** OAuth state parameter */ state?: string; }; export type OAuthAuthorizeResponseDto = { + /** OAuth authorization URL */ url: string; }; export type OAuthCallbackDto = { + /** OAuth code verifier (PKCE) */ codeVerifier?: string; + /** OAuth state parameter */ state?: string; + /** OAuth callback URL */ url: string; }; export type PartnerResponseDto = { + /** Avatar color */ avatarColor: UserAvatarColor; + /** User email */ email: string; + /** User ID */ id: string; + /** Show in timeline */ inTimeline?: boolean; + /** User name */ name: string; + /** Profile change date */ profileChangedAt: string; + /** Profile image path */ profileImagePath: string; }; export type PartnerCreateDto = { + /** User ID to share with */ sharedWithId: string; }; export type PartnerUpdateDto = { + /** Show partner assets in timeline */ inTimeline: boolean; }; export type PeopleResponseDto = { + /** Whether there are more pages */ hasNextPage?: boolean; + /** Number of hidden people */ hidden: number; + /** List of people */ people: PersonResponseDto[]; + /** Total number of people */ total: number; }; export type PersonCreateDto = { - /** Person date of birth. - Note: the mobile app cannot currently set the birth date to null. */ + /** Person date of birth */ birthDate?: string | null; + /** Person color (hex) */ color?: string | null; + /** Mark as favorite */ isFavorite?: boolean; - /** Person visibility */ + /** Person visibility (hidden) */ isHidden?: boolean; - /** Person name. */ + /** Person name */ name?: string; }; export type PeopleUpdateItem = { - /** Person date of birth. - Note: the mobile app cannot currently set the birth date to null. */ + /** Person date of birth */ birthDate?: string | null; + /** Person color (hex) */ color?: string | null; - /** Asset is used to get the feature face thumbnail. */ + /** Asset ID used for feature face thumbnail */ featureFaceAssetId?: string; - /** Person id. */ + /** Person ID */ id: string; + /** Mark as favorite */ isFavorite?: boolean; - /** Person visibility */ + /** Person visibility (hidden) */ isHidden?: boolean; - /** Person name. */ + /** Person name */ name?: string; }; export type PeopleUpdateDto = { + /** People to update */ people: PeopleUpdateItem[]; }; export type PersonUpdateDto = { - /** Person date of birth. - Note: the mobile app cannot currently set the birth date to null. */ + /** Person date of birth */ birthDate?: string | null; + /** Person color (hex) */ color?: string | null; - /** Asset is used to get the feature face thumbnail. */ + /** Asset ID used for feature face thumbnail */ featureFaceAssetId?: string; + /** Mark as favorite */ isFavorite?: boolean; - /** Person visibility */ + /** Person visibility (hidden) */ isHidden?: boolean; - /** Person name. */ + /** Person name */ name?: string; }; export type MergePersonDto = { + /** Person IDs to merge */ ids: string[]; }; export type AssetFaceUpdateItem = { + /** Asset ID */ assetId: string; + /** Person ID */ personId: string; }; export type AssetFaceUpdateDto = { + /** Face update items */ data: AssetFaceUpdateItem[]; }; export type PersonStatisticsResponseDto = { + /** Number of assets */ assets: number; }; export type PluginActionResponseDto = { + /** Action description */ description: string; + /** Action ID */ id: string; + /** Method name */ methodName: string; + /** Plugin ID */ pluginId: string; + /** Action schema */ schema: object | null; + /** Supported contexts */ supportedContexts: PluginContextType[]; + /** Action title */ title: string; }; export type PluginFilterResponseDto = { + /** Filter description */ description: string; + /** Filter ID */ id: string; + /** Method name */ methodName: string; + /** Plugin ID */ pluginId: string; + /** Filter schema */ schema: object | null; + /** Supported contexts */ supportedContexts: PluginContextType[]; + /** Filter title */ title: string; }; export type PluginResponseDto = { + /** Plugin actions */ actions: PluginActionResponseDto[]; + /** Plugin author */ author: string; + /** Creation date */ createdAt: string; + /** Plugin description */ description: string; + /** Plugin filters */ filters: PluginFilterResponseDto[]; + /** Plugin ID */ id: string; + /** Plugin name */ name: string; + /** Plugin title */ title: string; + /** Last update date */ updatedAt: string; + /** Plugin version */ version: string; }; export type PluginTriggerResponseDto = { + /** Context type */ contextType: PluginContextType; + /** Trigger type */ "type": PluginTriggerType; }; export type QueueResponseDto = { + /** Whether the queue is paused */ isPaused: boolean; + /** Queue name */ name: QueueName; statistics: QueueStatisticsDto; }; export type QueueUpdateDto = { + /** Whether to pause the queue */ isPaused?: boolean; }; export type QueueDeleteDto = { @@ -1077,84 +1631,143 @@ export type QueueDeleteDto = { failed?: boolean; }; export type QueueJobResponseDto = { + /** Job data payload */ data: object; + /** Job ID */ id?: string; + /** Job name */ name: JobName; + /** Job creation timestamp */ timestamp: number; }; export type SearchExploreItem = { data: AssetResponseDto; + /** Explore value */ value: string; }; export type SearchExploreResponseDto = { + /** Explore field name */ fieldName: string; items: SearchExploreItem[]; }; export type MetadataSearchDto = { + /** Filter by album IDs */ albumIds?: string[]; + /** Filter by file checksum */ checksum?: string; + /** Filter by city name */ city?: string | null; + /** Filter by country name */ country?: string | null; + /** Filter by creation date (after) */ createdAfter?: string; + /** Filter by creation date (before) */ createdBefore?: string; + /** Filter by description text */ description?: string; + /** Filter by device asset ID */ deviceAssetId?: string; + /** Device ID to filter by */ deviceId?: string; + /** Filter by encoded video file path */ encodedVideoPath?: string; + /** Filter by asset ID */ id?: string; + /** Filter by encoded status */ isEncoded?: boolean; + /** Filter by favorite status */ isFavorite?: boolean; + /** Filter by motion photo status */ isMotion?: boolean; + /** Filter assets not in any album */ isNotInAlbum?: boolean; + /** Filter by offline status */ isOffline?: boolean; + /** Filter by lens model */ lensModel?: string | null; + /** Library ID to filter by */ libraryId?: string | null; + /** Filter by camera make */ make?: string; + /** Filter by camera model */ model?: string | null; + /** Filter by OCR text content */ ocr?: string; + /** Sort order */ order?: AssetOrder; + /** Filter by original file name */ originalFileName?: string; + /** Filter by original file path */ originalPath?: string; + /** Page number */ page?: number; + /** Filter by person IDs */ personIds?: string[]; + /** Filter by preview file path */ previewPath?: string; + /** Filter by rating */ rating?: number; + /** Number of results to return */ size?: number; + /** Filter by state/province name */ state?: string | null; + /** Filter by tag IDs */ tagIds?: string[] | null; + /** Filter by taken date (after) */ takenAfter?: string; + /** Filter by taken date (before) */ takenBefore?: string; + /** Filter by thumbnail file path */ thumbnailPath?: string; + /** Filter by trash date (after) */ trashedAfter?: string; + /** Filter by trash date (before) */ trashedBefore?: string; + /** Asset type filter */ "type"?: AssetTypeEnum; + /** Filter by update date (after) */ updatedAfter?: string; + /** Filter by update date (before) */ updatedBefore?: string; + /** Filter by visibility */ visibility?: AssetVisibility; + /** Include deleted assets */ withDeleted?: boolean; + /** Include EXIF data in response */ withExif?: boolean; + /** Include assets with people */ withPeople?: boolean; + /** Include stacked assets */ withStacked?: boolean; }; export type SearchFacetCountResponseDto = { + /** Number of assets with this facet value */ count: number; + /** Facet value */ value: string; }; export type SearchFacetResponseDto = { + /** Facet counts */ counts: SearchFacetCountResponseDto[]; + /** Facet field name */ fieldName: string; }; export type SearchAlbumResponseDto = { + /** Number of albums in this page */ count: number; facets: SearchFacetResponseDto[]; items: AlbumResponseDto[]; + /** Total number of matching albums */ total: number; }; export type SearchAssetResponseDto = { + /** Number of assets in this page */ count: number; facets: SearchFacetResponseDto[]; items: AssetResponseDto[]; + /** Next page token */ nextPage: string | null; + /** Total number of matching assets */ total: number; }; export type SearchResponseDto = { @@ -1162,189 +1775,351 @@ export type SearchResponseDto = { assets: SearchAssetResponseDto; }; export type PlacesResponseDto = { + /** Administrative level 1 name (state/province) */ admin1name?: string; + /** Administrative level 2 name (county/district) */ admin2name?: string; + /** Latitude coordinate */ latitude: number; + /** Longitude coordinate */ longitude: number; + /** Place name */ name: string; }; export type RandomSearchDto = { + /** Filter by album IDs */ albumIds?: string[]; + /** Filter by city name */ city?: string | null; + /** Filter by country name */ country?: string | null; + /** Filter by creation date (after) */ createdAfter?: string; + /** Filter by creation date (before) */ createdBefore?: string; + /** Device ID to filter by */ deviceId?: string; + /** Filter by encoded status */ isEncoded?: boolean; + /** Filter by favorite status */ isFavorite?: boolean; + /** Filter by motion photo status */ isMotion?: boolean; + /** Filter assets not in any album */ isNotInAlbum?: boolean; + /** Filter by offline status */ isOffline?: boolean; + /** Filter by lens model */ lensModel?: string | null; + /** Library ID to filter by */ libraryId?: string | null; + /** Filter by camera make */ make?: string; + /** Filter by camera model */ model?: string | null; + /** Filter by OCR text content */ ocr?: string; + /** Filter by person IDs */ personIds?: string[]; + /** Filter by rating */ rating?: number; + /** Number of results to return */ size?: number; + /** Filter by state/province name */ state?: string | null; + /** Filter by tag IDs */ tagIds?: string[] | null; + /** Filter by taken date (after) */ takenAfter?: string; + /** Filter by taken date (before) */ takenBefore?: string; + /** Filter by trash date (after) */ trashedAfter?: string; + /** Filter by trash date (before) */ trashedBefore?: string; + /** Asset type filter */ "type"?: AssetTypeEnum; + /** Filter by update date (after) */ updatedAfter?: string; + /** Filter by update date (before) */ updatedBefore?: string; + /** Filter by visibility */ visibility?: AssetVisibility; + /** Include deleted assets */ withDeleted?: boolean; + /** Include EXIF data in response */ withExif?: boolean; + /** Include assets with people */ withPeople?: boolean; + /** Include stacked assets */ withStacked?: boolean; }; export type SmartSearchDto = { + /** Filter by album IDs */ albumIds?: string[]; + /** Filter by city name */ city?: string | null; + /** Filter by country name */ country?: string | null; + /** Filter by creation date (after) */ createdAfter?: string; + /** Filter by creation date (before) */ createdBefore?: string; + /** Device ID to filter by */ deviceId?: string; + /** Filter by encoded status */ isEncoded?: boolean; + /** Filter by favorite status */ isFavorite?: boolean; + /** Filter by motion photo status */ isMotion?: boolean; + /** Filter assets not in any album */ isNotInAlbum?: boolean; + /** Filter by offline status */ isOffline?: boolean; + /** Search language code */ language?: string; + /** Filter by lens model */ lensModel?: string | null; + /** Library ID to filter by */ libraryId?: string | null; + /** Filter by camera make */ make?: string; + /** Filter by camera model */ model?: string | null; + /** Filter by OCR text content */ ocr?: string; + /** Page number */ page?: number; + /** Filter by person IDs */ personIds?: string[]; + /** Natural language search query */ query?: string; + /** Asset ID to use as search reference */ queryAssetId?: string; + /** Filter by rating */ rating?: number; + /** Number of results to return */ size?: number; + /** Filter by state/province name */ state?: string | null; + /** Filter by tag IDs */ tagIds?: string[] | null; + /** Filter by taken date (after) */ takenAfter?: string; + /** Filter by taken date (before) */ takenBefore?: string; + /** Filter by trash date (after) */ trashedAfter?: string; + /** Filter by trash date (before) */ trashedBefore?: string; + /** Asset type filter */ "type"?: AssetTypeEnum; + /** Filter by update date (after) */ updatedAfter?: string; + /** Filter by update date (before) */ updatedBefore?: string; + /** Filter by visibility */ visibility?: AssetVisibility; + /** Include deleted assets */ withDeleted?: boolean; + /** Include EXIF data in response */ withExif?: boolean; }; export type StatisticsSearchDto = { + /** Filter by album IDs */ albumIds?: string[]; + /** Filter by city name */ city?: string | null; + /** Filter by country name */ country?: string | null; + /** Filter by creation date (after) */ createdAfter?: string; + /** Filter by creation date (before) */ createdBefore?: string; + /** Filter by description text */ description?: string; + /** Device ID to filter by */ deviceId?: string; + /** Filter by encoded status */ isEncoded?: boolean; + /** Filter by favorite status */ isFavorite?: boolean; + /** Filter by motion photo status */ isMotion?: boolean; + /** Filter assets not in any album */ isNotInAlbum?: boolean; + /** Filter by offline status */ isOffline?: boolean; + /** Filter by lens model */ lensModel?: string | null; + /** Library ID to filter by */ libraryId?: string | null; + /** Filter by camera make */ make?: string; + /** Filter by camera model */ model?: string | null; + /** Filter by OCR text content */ ocr?: string; + /** Filter by person IDs */ personIds?: string[]; + /** Filter by rating */ rating?: number; + /** Filter by state/province name */ state?: string | null; + /** Filter by tag IDs */ tagIds?: string[] | null; + /** Filter by taken date (after) */ takenAfter?: string; + /** Filter by taken date (before) */ takenBefore?: string; + /** Filter by trash date (after) */ trashedAfter?: string; + /** Filter by trash date (before) */ trashedBefore?: string; + /** Asset type filter */ "type"?: AssetTypeEnum; + /** Filter by update date (after) */ updatedAfter?: string; + /** Filter by update date (before) */ updatedBefore?: string; + /** Filter by visibility */ visibility?: AssetVisibility; }; export type SearchStatisticsResponseDto = { + /** Total number of matching assets */ total: number; }; export type ServerAboutResponseDto = { + /** Build identifier */ build?: string; + /** Build image name */ buildImage?: string; + /** Build image URL */ buildImageUrl?: string; + /** Build URL */ buildUrl?: string; + /** ExifTool version */ exiftool?: string; + /** FFmpeg version */ ffmpeg?: string; + /** ImageMagick version */ imagemagick?: string; + /** libvips version */ libvips?: string; + /** Whether the server is licensed */ licensed: boolean; + /** Node.js version */ nodejs?: string; + /** Repository name */ repository?: string; + /** Repository URL */ repositoryUrl?: string; + /** Source commit hash */ sourceCommit?: string; + /** Source reference (branch/tag) */ sourceRef?: string; + /** Source URL */ sourceUrl?: string; + /** Third-party bug/feature URL */ thirdPartyBugFeatureUrl?: string; + /** Third-party documentation URL */ thirdPartyDocumentationUrl?: string; + /** Third-party source URL */ thirdPartySourceUrl?: string; + /** Third-party support URL */ thirdPartySupportUrl?: string; + /** Server version */ version: string; + /** URL to version information */ versionUrl: string; }; export type ServerApkLinksDto = { + /** APK download link for ARM64 v8a architecture */ arm64v8a: string; + /** APK download link for ARM EABI v7a architecture */ armeabiv7a: string; + /** APK download link for universal architecture */ universal: string; + /** APK download link for x86_64 architecture */ x86_64: string; }; export type ServerConfigDto = { + /** External domain URL */ externalDomain: string; + /** Whether the server has been initialized */ isInitialized: boolean; + /** Whether the admin has completed onboarding */ isOnboarded: boolean; + /** Login page message */ loginPageMessage: string; + /** Whether maintenance mode is active */ maintenanceMode: boolean; + /** Map dark style URL */ mapDarkStyleUrl: string; + /** Map light style URL */ mapLightStyleUrl: string; + /** OAuth button text */ oauthButtonText: string; + /** Whether public user registration is enabled */ publicUsers: boolean; + /** Number of days before trashed assets are permanently deleted */ trashDays: number; + /** Delay in days before deleted users are permanently removed */ userDeleteDelay: number; }; export type ServerFeaturesDto = { + /** Whether config file is available */ configFile: boolean; + /** Whether duplicate detection is enabled */ duplicateDetection: boolean; + /** Whether email notifications are enabled */ email: boolean; + /** Whether facial recognition is enabled */ facialRecognition: boolean; + /** Whether face import is enabled */ importFaces: boolean; + /** Whether map feature is enabled */ map: boolean; + /** Whether OAuth is enabled */ oauth: boolean; + /** Whether OAuth auto-launch is enabled */ oauthAutoLaunch: boolean; + /** Whether OCR is enabled */ ocr: boolean; + /** Whether password login is enabled */ passwordLogin: boolean; + /** Whether reverse geocoding is enabled */ reverseGeocoding: boolean; + /** Whether search is enabled */ search: boolean; + /** Whether sidecar files are supported */ sidecar: boolean; + /** Whether smart search is enabled */ smartSearch: boolean; + /** Whether trash feature is enabled */ trash: boolean; }; export type LicenseResponseDto = { + /** Activation date */ activatedAt: string; + /** Activation key */ activationKey: string; + /** License key (format: IM(SV|CL)(-XXXX){8}) */ licenseKey: string; }; export type LicenseKeyDto = { + /** Activation key */ activationKey: string; + /** License key (format: IM(SV|CL)(-XXXX){8}) */ licenseKey: string; }; export type ServerMediaTypesResponseDto = { + /** Supported image MIME types */ image: string[]; + /** Supported sidecar MIME types */ sidecar: string[]; + /** Supported video MIME types */ video: string[]; }; export type ServerPingResponse = {}; @@ -1352,209 +2127,335 @@ export type ServerPingResponseRead = { res: string; }; export type UsageByUserDto = { + /** Number of photos */ photos: number; + /** User quota size in bytes (null if unlimited) */ quotaSizeInBytes: number | null; + /** Total storage usage in bytes */ usage: number; + /** Storage usage for photos in bytes */ usagePhotos: number; + /** Storage usage for videos in bytes */ usageVideos: number; + /** User ID */ userId: string; + /** User name */ userName: string; + /** Number of videos */ videos: number; }; export type ServerStatsResponseDto = { + /** Total number of photos */ photos: number; + /** Total storage usage in bytes */ usage: number; usageByUser: UsageByUserDto[]; + /** Storage usage for photos in bytes */ usagePhotos: number; + /** Storage usage for videos in bytes */ usageVideos: number; + /** Total number of videos */ videos: number; }; export type ServerStorageResponseDto = { + /** Available disk space (human-readable format) */ diskAvailable: string; + /** Available disk space in bytes */ diskAvailableRaw: number; + /** Total disk size (human-readable format) */ diskSize: string; + /** Total disk size in bytes */ diskSizeRaw: number; + /** Disk usage percentage (0-100) */ diskUsagePercentage: number; + /** Used disk space (human-readable format) */ diskUse: string; + /** Used disk space in bytes */ diskUseRaw: number; }; export type ServerThemeDto = { + /** Custom CSS for theming */ customCss: string; }; export type ServerVersionResponseDto = { + /** Major version number */ major: number; + /** Minor version number */ minor: number; + /** Patch version number */ patch: number; }; export type VersionCheckStateResponseDto = { + /** Last check timestamp */ checkedAt: string | null; + /** Release version */ releaseVersion: string | null; }; export type ServerVersionHistoryResponseDto = { + /** When this version was first seen */ createdAt: string; + /** Version history entry ID */ id: string; + /** Version string */ version: string; }; export type SessionCreateDto = { + /** Device OS */ deviceOS?: string; + /** Device type */ deviceType?: string; - /** session duration, in seconds */ + /** Session duration in seconds */ duration?: number; }; export type SessionCreateResponseDto = { + /** App version */ appVersion: string | null; + /** Creation date */ createdAt: string; + /** Is current session */ current: boolean; + /** Device OS */ deviceOS: string; + /** Device type */ deviceType: string; + /** Expiration date */ expiresAt?: string; + /** Session ID */ id: string; + /** Is pending sync reset */ isPendingSyncReset: boolean; + /** Session token */ token: string; + /** Last update date */ updatedAt: string; }; export type SessionUpdateDto = { + /** Reset pending sync state */ isPendingSyncReset?: boolean; }; export type SharedLinkResponseDto = { album?: AlbumResponseDto; + /** Allow downloads */ allowDownload: boolean; + /** Allow uploads */ allowUpload: boolean; assets: AssetResponseDto[]; + /** Creation date */ createdAt: string; + /** Link description */ description: string | null; + /** Expiration date */ expiresAt: string | null; + /** Shared link ID */ id: string; + /** Encryption key (base64url) */ key: string; + /** Has password */ password: string | null; + /** Show metadata */ showMetadata: boolean; + /** Custom URL slug */ slug: string | null; + /** Access token */ token?: string | null; + /** Shared link type */ "type": SharedLinkType; + /** Owner user ID */ userId: string; }; export type SharedLinkCreateDto = { + /** Album ID (for album sharing) */ albumId?: string; + /** Allow downloads */ allowDownload?: boolean; + /** Allow uploads */ allowUpload?: boolean; + /** Asset IDs (for individual assets) */ assetIds?: string[]; + /** Link description */ description?: string | null; + /** Expiration date */ expiresAt?: string | null; + /** Link password */ password?: string | null; + /** Show metadata */ showMetadata?: boolean; + /** Custom URL slug */ slug?: string | null; + /** Shared link type */ "type": SharedLinkType; }; export type SharedLinkEditDto = { + /** Allow downloads */ allowDownload?: boolean; + /** Allow uploads */ allowUpload?: boolean; - /** Few clients cannot send null to set the expiryTime to never. - Setting this flag and not sending expiryAt is considered as null instead. - Clients that can send null values can ignore this. */ + /** Whether to change the expiry time. Few clients cannot send null to set the expiryTime to never. Setting this flag and not sending expiryAt is considered as null instead. Clients that can send null values can ignore this. */ changeExpiryTime?: boolean; + /** Link description */ description?: string | null; + /** Expiration date */ expiresAt?: string | null; + /** Link password */ password?: string | null; + /** Show metadata */ showMetadata?: boolean; + /** Custom URL slug */ slug?: string | null; }; export type AssetIdsResponseDto = { + /** Asset ID */ assetId: string; + /** Error reason if failed */ error?: Error2; + /** Whether operation succeeded */ success: boolean; }; export type StackResponseDto = { + /** Stack assets */ assets: AssetResponseDto[]; + /** Stack ID */ id: string; + /** Primary asset ID */ primaryAssetId: string; }; export type StackCreateDto = { - /** first asset becomes the primary */ + /** Asset IDs (first becomes primary, min 2) */ assetIds: string[]; }; export type StackUpdateDto = { + /** Primary asset ID */ primaryAssetId?: string; }; export type SyncAckDeleteDto = { + /** Sync entity types to delete acks for */ types?: SyncEntityType[]; }; export type SyncAckDto = { + /** Acknowledgment ID */ ack: string; + /** Sync entity type */ "type": SyncEntityType; }; export type SyncAckSetDto = { + /** Acknowledgment IDs (max 1000) */ acks: string[]; }; export type AssetDeltaSyncDto = { + /** Sync assets updated after this date */ updatedAfter: string; + /** User IDs to sync */ userIds: string[]; }; export type AssetDeltaSyncResponseDto = { + /** Deleted asset IDs */ deleted: string[]; + /** Whether full sync is needed */ needsFullSync: boolean; + /** Upserted assets */ upserted: AssetResponseDto[]; }; export type AssetFullSyncDto = { + /** Last asset ID (pagination) */ lastId?: string; + /** Maximum number of assets to return */ limit: number; + /** Sync assets updated until this date */ updatedUntil: string; + /** Filter by user ID */ userId?: string; }; export type SyncStreamDto = { + /** Reset sync state */ reset?: boolean; + /** Sync request types */ types: SyncRequestType[]; }; export type DatabaseBackupConfig = { + /** Cron expression */ cronExpression: string; + /** Enabled */ enabled: boolean; + /** Keep last amount */ keepLastAmount: number; }; export type SystemConfigBackupsDto = { database: DatabaseBackupConfig; }; export type SystemConfigFFmpegDto = { + /** Transcode hardware acceleration */ accel: TranscodeHWAccel; + /** Accelerated decode */ accelDecode: boolean; + /** Accepted audio codecs */ acceptedAudioCodecs: AudioCodec[]; + /** Accepted containers */ acceptedContainers: VideoContainer[]; + /** Accepted video codecs */ acceptedVideoCodecs: VideoCodec[]; + /** B-frames */ bframes: number; + /** CQ mode */ cqMode: CQMode; + /** CRF */ crf: number; + /** GOP size */ gopSize: number; + /** Max bitrate */ maxBitrate: string; + /** Preferred hardware device */ preferredHwDevice: string; + /** Preset */ preset: string; + /** References */ refs: number; + /** Target audio codec */ targetAudioCodec: AudioCodec; + /** Target resolution */ targetResolution: string; + /** Target video codec */ targetVideoCodec: VideoCodec; + /** Temporal AQ */ temporalAQ: boolean; + /** Threads */ threads: number; + /** Tone mapping */ tonemap: ToneMapping; + /** Transcode policy */ transcode: TranscodePolicy; + /** Two pass */ twoPass: boolean; }; export type SystemConfigGeneratedFullsizeImageDto = { + /** Enabled */ enabled: boolean; + /** Image format */ format: ImageFormat; + /** Progressive */ progressive?: boolean; + /** Quality */ quality: number; }; export type SystemConfigGeneratedImageDto = { + /** Image format */ format: ImageFormat; progressive?: boolean; + /** Quality */ quality: number; + /** Size */ size: number; }; export type SystemConfigImageDto = { + /** Colorspace */ colorspace: Colorspace; + /** Extract embedded */ extractEmbedded: boolean; fullsize: SystemConfigGeneratedFullsizeImageDto; preview: SystemConfigGeneratedImageDto; thumbnail: SystemConfigGeneratedImageDto; }; export type JobSettingsDto = { + /** Concurrency */ concurrency: number; }; export type SystemConfigJobDto = { @@ -1575,9 +2476,11 @@ export type SystemConfigJobDto = { }; export type SystemConfigLibraryScanDto = { cronExpression: string; + /** Enabled */ enabled: boolean; }; export type SystemConfigLibraryWatchDto = { + /** Enabled */ enabled: boolean; }; export type SystemConfigLibraryDto = { @@ -1585,40 +2488,57 @@ export type SystemConfigLibraryDto = { watch: SystemConfigLibraryWatchDto; }; export type SystemConfigLoggingDto = { + /** Enabled */ enabled: boolean; level: LogLevel; }; export type MachineLearningAvailabilityChecksDto = { + /** Enabled */ enabled: boolean; interval: number; timeout: number; }; export type ClipConfig = { + /** Whether the task is enabled */ enabled: boolean; + /** Name of the model to use */ modelName: string; }; export type DuplicateDetectionConfig = { + /** Whether the task is enabled */ enabled: boolean; + /** Maximum distance threshold for duplicate detection */ maxDistance: number; }; export type FacialRecognitionConfig = { + /** Whether the task is enabled */ enabled: boolean; + /** Maximum distance threshold for face recognition */ maxDistance: number; + /** Minimum number of faces required for recognition */ minFaces: number; + /** Minimum confidence score for face detection */ minScore: number; + /** Name of the model to use */ modelName: string; }; export type OcrConfig = { + /** Whether the task is enabled */ enabled: boolean; + /** Maximum resolution for OCR processing */ maxResolution: number; + /** Minimum confidence score for text detection */ minDetectionScore: number; + /** Minimum confidence score for text recognition */ minRecognitionScore: number; + /** Name of the model to use */ modelName: string; }; export type SystemConfigMachineLearningDto = { availabilityChecks: MachineLearningAvailabilityChecksDto; clip: ClipConfig; duplicateDetection: DuplicateDetectionConfig; + /** Enabled */ enabled: boolean; facialRecognition: FacialRecognitionConfig; ocr: OcrConfig; @@ -1626,63 +2546,96 @@ export type SystemConfigMachineLearningDto = { }; export type SystemConfigMapDto = { darkStyle: string; + /** Enabled */ enabled: boolean; lightStyle: string; }; export type SystemConfigFacesDto = { + /** Import */ "import": boolean; }; export type SystemConfigMetadataDto = { faces: SystemConfigFacesDto; }; export type SystemConfigNewVersionCheckDto = { + /** Enabled */ enabled: boolean; }; export type SystemConfigNightlyTasksDto = { + /** Cluster new faces */ clusterNewFaces: boolean; + /** Database cleanup */ databaseCleanup: boolean; + /** Generate memories */ generateMemories: boolean; + /** Missing thumbnails */ missingThumbnails: boolean; startTime: string; + /** Sync quota usage */ syncQuotaUsage: boolean; }; export type SystemConfigNotificationsDto = { smtp: SystemConfigSmtpDto; }; export type SystemConfigOAuthDto = { + /** Auto launch */ autoLaunch: boolean; + /** Auto register */ autoRegister: boolean; + /** Button text */ buttonText: string; + /** Client ID */ clientId: string; + /** Client secret */ clientSecret: string; + /** Default storage quota */ defaultStorageQuota: number | null; + /** Enabled */ enabled: boolean; + /** Issuer URL */ issuerUrl: string; + /** Mobile override enabled */ mobileOverrideEnabled: boolean; + /** Mobile redirect URI */ mobileRedirectUri: string; + /** Profile signing algorithm */ profileSigningAlgorithm: string; + /** Role claim */ roleClaim: string; + /** Scope */ scope: string; signingAlgorithm: string; + /** Storage label claim */ storageLabelClaim: string; + /** Storage quota claim */ storageQuotaClaim: string; + /** Timeout */ timeout: number; + /** Token endpoint auth method */ tokenEndpointAuthMethod: OAuthTokenEndpointAuthMethod; }; export type SystemConfigPasswordLoginDto = { + /** Enabled */ enabled: boolean; }; export type SystemConfigReverseGeocodingDto = { + /** Enabled */ enabled: boolean; }; export type SystemConfigServerDto = { + /** External domain */ externalDomain: string; + /** Login page message */ loginPageMessage: string; + /** Public users */ publicUsers: boolean; }; export type SystemConfigStorageTemplateDto = { + /** Enabled */ enabled: boolean; + /** Hash verification enabled */ hashVerificationEnabled: boolean; + /** Template */ template: string; }; export type SystemConfigTemplateEmailsDto = { @@ -1694,13 +2647,17 @@ export type SystemConfigTemplatesDto = { email: SystemConfigTemplateEmailsDto; }; export type SystemConfigThemeDto = { + /** Custom CSS for theming */ customCss: string; }; export type SystemConfigTrashDto = { + /** Days */ days: number; + /** Enabled */ enabled: boolean; }; export type SystemConfigUserDto = { + /** Delete delay */ deleteDelay: number; }; export type SystemConfigDto = { @@ -1727,38 +2684,57 @@ export type SystemConfigDto = { user: SystemConfigUserDto; }; export type SystemConfigTemplateStorageOptionDto = { + /** Available day format options for storage template */ dayOptions: string[]; + /** Available hour format options for storage template */ hourOptions: string[]; + /** Available minute format options for storage template */ minuteOptions: string[]; + /** Available month format options for storage template */ monthOptions: string[]; + /** Available preset template options */ presetOptions: string[]; + /** Available second format options for storage template */ secondOptions: string[]; + /** Available week format options for storage template */ weekOptions: string[]; + /** Available year format options for storage template */ yearOptions: string[]; }; export type AdminOnboardingUpdateDto = { + /** Is admin onboarded */ isOnboarded: boolean; }; export type ReverseGeocodingStateResponseDto = { + /** Last import file name */ lastImportFileName: string | null; + /** Last update timestamp */ lastUpdate: string | null; }; export type TagCreateDto = { + /** Tag color (hex) */ color?: string; + /** Tag name */ name: string; + /** Parent tag ID */ parentId?: string | null; }; export type TagUpsertDto = { + /** Tag names to upsert */ tags: string[]; }; export type TagBulkAssetsDto = { + /** Asset IDs */ assetIds: string[]; + /** Tag IDs */ tagIds: string[]; }; export type TagBulkAssetsResponseDto = { + /** Number of assets tagged */ count: number; }; export type TagUpdateDto = { + /** Tag color (hex) */ color?: string | null; }; export type TimeBucketAssetResponseDto = { @@ -1768,7 +2744,7 @@ export type TimeBucketAssetResponseDto = { country: (string | null)[]; /** Array of video durations in HH:MM:SS format (null for images) */ duration: (string | null)[]; - /** Array of file creation timestamps in UTC (ISO 8601 format, without timezone) */ + /** Array of file creation timestamps in UTC */ fileCreatedAt: string[]; /** Array of asset IDs in the time bucket */ id: string[]; @@ -1806,279 +2782,461 @@ export type TimeBucketsResponseDto = { timeBucket: string; }; export type TrashResponseDto = { + /** Number of items in trash */ count: number; }; export type UserUpdateMeDto = { + /** Avatar color */ avatarColor?: (UserAvatarColor) | null; + /** User email */ email?: string; + /** User name */ name?: string; + /** User password (deprecated, use change password endpoint) */ password?: string; }; export type OnboardingResponseDto = { + /** Is user onboarded */ isOnboarded: boolean; }; export type OnboardingDto = { + /** Is user onboarded */ isOnboarded: boolean; }; export type CreateProfileImageDto = { + /** Profile image file */ file: Blob; }; export type CreateProfileImageResponseDto = { + /** Profile image change date */ profileChangedAt: string; + /** Profile image file path */ profileImagePath: string; + /** User ID */ userId: string; }; export type WorkflowActionResponseDto = { + /** Action configuration */ actionConfig: object | null; + /** Action ID */ id: string; + /** Action order */ order: number; + /** Plugin action ID */ pluginActionId: string; + /** Workflow ID */ workflowId: string; }; export type WorkflowFilterResponseDto = { + /** Filter configuration */ filterConfig: object | null; + /** Filter ID */ id: string; + /** Filter order */ order: number; + /** Plugin filter ID */ pluginFilterId: string; + /** Workflow ID */ workflowId: string; }; export type WorkflowResponseDto = { + /** Workflow actions */ actions: WorkflowActionResponseDto[]; + /** Creation date */ createdAt: string; + /** Workflow description */ description: string; + /** Workflow enabled */ enabled: boolean; + /** Workflow filters */ filters: WorkflowFilterResponseDto[]; + /** Workflow ID */ id: string; + /** Workflow name */ name: string | null; + /** Owner user ID */ ownerId: string; + /** Workflow trigger type */ triggerType: PluginTriggerType; }; export type WorkflowActionItemDto = { + /** Action configuration */ actionConfig?: object; + /** Plugin action ID */ pluginActionId: string; }; export type WorkflowFilterItemDto = { + /** Filter configuration */ filterConfig?: object; + /** Plugin filter ID */ pluginFilterId: string; }; export type WorkflowCreateDto = { + /** Workflow actions */ actions: WorkflowActionItemDto[]; + /** Workflow description */ description?: string; + /** Workflow enabled */ enabled?: boolean; + /** Workflow filters */ filters: WorkflowFilterItemDto[]; + /** Workflow name */ name: string; + /** Workflow trigger type */ triggerType: PluginTriggerType; }; export type WorkflowUpdateDto = { + /** Workflow actions */ actions?: WorkflowActionItemDto[]; + /** Workflow description */ description?: string; + /** Workflow enabled */ enabled?: boolean; + /** Workflow filters */ filters?: WorkflowFilterItemDto[]; + /** Workflow name */ name?: string; + /** Workflow trigger type */ triggerType?: PluginTriggerType; }; export type SyncAckV1 = {}; export type SyncAlbumDeleteV1 = { + /** Album ID */ albumId: string; }; export type SyncAlbumToAssetDeleteV1 = { + /** Album ID */ albumId: string; + /** Asset ID */ assetId: string; }; export type SyncAlbumToAssetV1 = { + /** Album ID */ albumId: string; + /** Asset ID */ assetId: string; }; export type SyncAlbumUserDeleteV1 = { + /** Album ID */ albumId: string; + /** User ID */ userId: string; }; export type SyncAlbumUserV1 = { + /** Album ID */ albumId: string; + /** Album user role */ role: AlbumUserRole; + /** User ID */ userId: string; }; export type SyncAlbumV1 = { + /** Created at */ createdAt: string; + /** Album description */ description: string; + /** Album ID */ id: string; + /** Is activity enabled */ isActivityEnabled: boolean; + /** Album name */ name: string; order: AssetOrder; + /** Owner ID */ ownerId: string; + /** Thumbnail asset ID */ thumbnailAssetId: string | null; + /** Updated at */ updatedAt: string; }; export type SyncAssetDeleteV1 = { + /** Asset ID */ assetId: string; }; export type SyncAssetExifV1 = { + /** Asset ID */ assetId: string; + /** City */ city: string | null; + /** Country */ country: string | null; + /** Date time original */ dateTimeOriginal: string | null; + /** Description */ description: string | null; + /** Exif image height */ exifImageHeight: number | null; + /** Exif image width */ exifImageWidth: number | null; + /** Exposure time */ exposureTime: string | null; + /** F number */ fNumber: number | null; + /** File size in byte */ fileSizeInByte: number | null; + /** Focal length */ focalLength: number | null; + /** FPS */ fps: number | null; + /** ISO */ iso: number | null; + /** Latitude */ latitude: number | null; + /** Lens model */ lensModel: string | null; + /** Longitude */ longitude: number | null; + /** Make */ make: string | null; + /** Model */ model: string | null; + /** Modify date */ modifyDate: string | null; + /** Orientation */ orientation: string | null; + /** Profile description */ profileDescription: string | null; + /** Projection type */ projectionType: string | null; + /** Rating */ rating: number | null; + /** State */ state: string | null; + /** Time zone */ timeZone: string | null; }; export type SyncAssetFaceDeleteV1 = { + /** Asset face ID */ assetFaceId: string; }; export type SyncAssetFaceV1 = { + /** Asset ID */ assetId: string; boundingBoxX1: number; boundingBoxX2: number; boundingBoxY1: number; boundingBoxY2: number; + /** Asset face ID */ id: string; imageHeight: number; imageWidth: number; + /** Person ID */ personId: string | null; + /** Source type */ sourceType: string; }; export type SyncAssetMetadataDeleteV1 = { + /** Asset ID */ assetId: string; + /** Key */ key: string; }; export type SyncAssetMetadataV1 = { + /** Asset ID */ assetId: string; + /** Key */ key: string; + /** Value */ value: object; }; export type SyncAssetV1 = { + /** Checksum */ checksum: string; + /** Deleted at */ deletedAt: string | null; + /** Duration */ duration: string | null; + /** File created at */ fileCreatedAt: string | null; + /** File modified at */ fileModifiedAt: string | null; + /** Asset height */ height: number | null; + /** Asset ID */ id: string; + /** Is edited */ isEdited: boolean; + /** Is favorite */ isFavorite: boolean; + /** Library ID */ libraryId: string | null; + /** Live photo video ID */ livePhotoVideoId: string | null; + /** Local date time */ localDateTime: string | null; + /** Original file name */ originalFileName: string; + /** Owner ID */ ownerId: string; + /** Stack ID */ stackId: string | null; + /** Thumbhash */ thumbhash: string | null; + /** Asset type */ "type": AssetTypeEnum; + /** Asset visibility */ visibility: AssetVisibility; + /** Asset width */ width: number | null; }; export type SyncAuthUserV1 = { + /** User avatar color */ avatarColor: (UserAvatarColor) | null; + /** User deleted at */ deletedAt: string | null; + /** User email */ email: string; + /** User has profile image */ hasProfileImage: boolean; + /** User ID */ id: string; + /** User is admin */ isAdmin: boolean; + /** User name */ name: string; + /** User OAuth ID */ oauthId: string; + /** User pin code */ pinCode: string | null; + /** User profile changed at */ profileChangedAt: string; quotaSizeInBytes: number | null; quotaUsageInBytes: number; + /** User storage label */ storageLabel: string | null; }; export type SyncCompleteV1 = {}; export type SyncMemoryAssetDeleteV1 = { + /** Asset ID */ assetId: string; + /** Memory ID */ memoryId: string; }; export type SyncMemoryAssetV1 = { + /** Asset ID */ assetId: string; + /** Memory ID */ memoryId: string; }; export type SyncMemoryDeleteV1 = { + /** Memory ID */ memoryId: string; }; export type SyncMemoryV1 = { + /** Created at */ createdAt: string; + /** Data */ data: object; + /** Deleted at */ deletedAt: string | null; + /** Hide at */ hideAt: string | null; + /** Memory ID */ id: string; + /** Is saved */ isSaved: boolean; + /** Memory at */ memoryAt: string; + /** Owner ID */ ownerId: string; + /** Seen at */ seenAt: string | null; + /** Show at */ showAt: string | null; + /** Memory type */ "type": MemoryType; + /** Updated at */ updatedAt: string; }; export type SyncPartnerDeleteV1 = { + /** Shared by ID */ sharedById: string; + /** Shared with ID */ sharedWithId: string; }; export type SyncPartnerV1 = { + /** In timeline */ inTimeline: boolean; + /** Shared by ID */ sharedById: string; + /** Shared with ID */ sharedWithId: string; }; export type SyncPersonDeleteV1 = { + /** Person ID */ personId: string; }; export type SyncPersonV1 = { + /** Birth date */ birthDate: string | null; + /** Color */ color: string | null; + /** Created at */ createdAt: string; + /** Face asset ID */ faceAssetId: string | null; + /** Person ID */ id: string; + /** Is favorite */ isFavorite: boolean; + /** Is hidden */ isHidden: boolean; + /** Person name */ name: string; + /** Owner ID */ ownerId: string; + /** Updated at */ updatedAt: string; }; export type SyncResetV1 = {}; export type SyncStackDeleteV1 = { + /** Stack ID */ stackId: string; }; export type SyncStackV1 = { + /** Created at */ createdAt: string; + /** Stack ID */ id: string; + /** Owner ID */ ownerId: string; + /** Primary asset ID */ primaryAssetId: string; + /** Updated at */ updatedAt: string; }; export type SyncUserDeleteV1 = { + /** User ID */ userId: string; }; export type SyncUserMetadataDeleteV1 = { + /** User metadata key */ key: UserMetadataKey; + /** User ID */ userId: string; }; export type SyncUserMetadataV1 = { + /** User metadata key */ key: UserMetadataKey; + /** User ID */ userId: string; + /** User metadata value */ value: object; }; export type SyncUserV1 = { + /** User avatar color */ avatarColor: (UserAvatarColor) | null; + /** User deleted at */ deletedAt: string | null; + /** User email */ email: string; + /** User has profile image */ hasProfileImage: boolean; + /** User ID */ id: string; + /** User name */ name: string; + /** User profile changed at */ profileChangedAt: string; }; /** diff --git a/server/src/controllers/maintenance.controller.spec.ts b/server/src/controllers/maintenance.controller.spec.ts new file mode 100644 index 000000000..094028687 --- /dev/null +++ b/server/src/controllers/maintenance.controller.spec.ts @@ -0,0 +1,39 @@ +import { MaintenanceController } from 'src/controllers/maintenance.controller'; +import { MaintenanceAction } from 'src/enum'; +import { MaintenanceService } from 'src/services/maintenance.service'; +import request from 'supertest'; +import { errorDto } from 'test/medium/responses'; +import { ControllerContext, controllerSetup, mockBaseService } from 'test/utils'; + +describe(MaintenanceController.name, () => { + let ctx: ControllerContext; + const service = mockBaseService(MaintenanceService); + + beforeAll(async () => { + ctx = await controllerSetup(MaintenanceController, [{ provide: MaintenanceService, useValue: service }]); + return () => ctx.close(); + }); + + beforeEach(() => { + service.resetAllMocks(); + ctx.reset(); + }); + + describe('POST /admin/maintenance', () => { + it('should be an authenticated route', async () => { + await request(ctx.getHttpServer()).post('/admin/maintenance').send(); + expect(ctx.authenticate).toHaveBeenCalled(); + }); + + it('should require a backup file when action is restore', async () => { + const { status, body } = await request(ctx.getHttpServer()).post('/admin/maintenance').send({ + action: MaintenanceAction.RestoreDatabase, + }); + expect(status).toBe(400); + expect(body).toEqual( + errorDto.badRequest(['restoreBackupFilename must be a string', 'restoreBackupFilename should not be empty']), + ); + expect(ctx.authenticate).toHaveBeenCalled(); + }); + }); +}); diff --git a/server/src/decorators.ts b/server/src/decorators.ts index 054bbf8fe..87a3900a7 100644 --- a/server/src/decorators.ts +++ b/server/src/decorators.ts @@ -171,7 +171,7 @@ export const Endpoint = ({ history, ...options }: EndpointOptions) => { return applyDecorators(...decorators); }; -type PropertyOptions = ApiPropertyOptions & { history?: HistoryBuilder }; +export type PropertyOptions = ApiPropertyOptions & { history?: HistoryBuilder }; export const Property = ({ history, ...options }: PropertyOptions) => { const extensions = history?.getExtensions() ?? {}; diff --git a/server/src/dtos/activity.dto.ts b/server/src/dtos/activity.dto.ts index 4b11a16e1..6464d8850 100644 --- a/server/src/dtos/activity.dto.ts +++ b/server/src/dtos/activity.dto.ts @@ -1,4 +1,4 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { IsNotEmpty, IsString, ValidateIf } from 'class-validator'; import { Activity } from 'src/database'; import { mapUser, UserResponseDto } from 'src/dtos/user.dto'; @@ -17,48 +17,55 @@ export enum ReactionLevel { export type MaybeDuplicate = { duplicate: boolean; value: T }; export class ActivityResponseDto { + @ApiProperty({ description: 'Activity ID' }) id!: string; + @ApiProperty({ description: 'Creation date', format: 'date-time' }) createdAt!: Date; - @ValidateEnum({ enum: ReactionType, name: 'ReactionType' }) + @ValidateEnum({ enum: ReactionType, name: 'ReactionType', description: 'Activity type' }) type!: ReactionType; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) user!: UserResponseDto; + @ApiProperty({ description: 'Asset ID (if activity is for an asset)' }) assetId!: string | null; + @ApiPropertyOptional({ description: 'Comment text (for comment activities)' }) comment?: string | null; } export class ActivityStatisticsResponseDto { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of comments' }) comments!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of likes' }) likes!: number; } export class ActivityDto { - @ValidateUUID() + @ValidateUUID({ description: 'Album ID' }) albumId!: string; - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Asset ID (if activity is for an asset)' }) assetId?: string; } export class ActivitySearchDto extends ActivityDto { - @ValidateEnum({ enum: ReactionType, name: 'ReactionType', optional: true }) + @ValidateEnum({ enum: ReactionType, name: 'ReactionType', description: 'Filter by activity type', optional: true }) type?: ReactionType; - @ValidateEnum({ enum: ReactionLevel, name: 'ReactionLevel', optional: true }) + @ValidateEnum({ enum: ReactionLevel, name: 'ReactionLevel', description: 'Filter by activity level', optional: true }) level?: ReactionLevel; - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Filter by user ID' }) userId?: string; } const isComment = (dto: ActivityCreateDto) => dto.type === ReactionType.COMMENT; export class ActivityCreateDto extends ActivityDto { - @ValidateEnum({ enum: ReactionType, name: 'ReactionType' }) + @ValidateEnum({ enum: ReactionType, name: 'ReactionType', description: 'Activity type (like or comment)' }) type!: ReactionType; + @ApiPropertyOptional({ description: 'Comment text (required if type is comment)' }) @ValidateIf(isComment) @IsNotEmpty() @IsString() diff --git a/server/src/dtos/album.dto.ts b/server/src/dtos/album.dto.ts index 2f3f22099..0f46ebaa4 100644 --- a/server/src/dtos/album.dto.ts +++ b/server/src/dtos/album.dto.ts @@ -1,4 +1,4 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; import { ArrayNotEmpty, IsArray, IsString, ValidateNested } from 'class-validator'; import _ from 'lodash'; @@ -11,156 +11,181 @@ import { AlbumUserRole, AssetOrder } from 'src/enum'; import { Optional, ValidateBoolean, ValidateEnum, ValidateUUID } from 'src/validation'; export class AlbumInfoDto { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Exclude assets from response' }) withoutAssets?: boolean; } export class AlbumUserAddDto { - @ValidateUUID() + @ValidateUUID({ description: 'User ID' }) userId!: string; - @ValidateEnum({ enum: AlbumUserRole, name: 'AlbumUserRole', default: AlbumUserRole.Editor }) + @ValidateEnum({ + enum: AlbumUserRole, + name: 'AlbumUserRole', + description: 'Album user role', + default: AlbumUserRole.Editor, + }) role?: AlbumUserRole; } export class AddUsersDto { + @ApiProperty({ description: 'Album users to add' }) @ArrayNotEmpty() albumUsers!: AlbumUserAddDto[]; } export class AlbumUserCreateDto { - @ValidateUUID() + @ValidateUUID({ description: 'User ID' }) userId!: string; - @ValidateEnum({ enum: AlbumUserRole, name: 'AlbumUserRole' }) + @ValidateEnum({ enum: AlbumUserRole, name: 'AlbumUserRole', description: 'Album user role' }) role!: AlbumUserRole; } export class CreateAlbumDto { + @ApiProperty({ description: 'Album name' }) @IsString() - @ApiProperty() albumName!: string; + @ApiPropertyOptional({ description: 'Album description' }) @IsString() @Optional() description?: string; + @ApiPropertyOptional({ description: 'Album users' }) @Optional() @IsArray() @ValidateNested({ each: true }) @Type(() => AlbumUserCreateDto) albumUsers?: AlbumUserCreateDto[]; - @ValidateUUID({ optional: true, each: true }) + @ValidateUUID({ optional: true, each: true, description: 'Initial asset IDs' }) assetIds?: string[]; } export class AlbumsAddAssetsDto { - @ValidateUUID({ each: true }) + @ValidateUUID({ each: true, description: 'Album IDs' }) albumIds!: string[]; - @ValidateUUID({ each: true }) + @ValidateUUID({ each: true, description: 'Asset IDs' }) assetIds!: string[]; } export class AlbumsAddAssetsResponseDto { + @ApiProperty({ description: 'Operation success' }) success!: boolean; - @ValidateEnum({ enum: BulkIdErrorReason, name: 'BulkIdErrorReason', optional: true }) + @ValidateEnum({ enum: BulkIdErrorReason, name: 'BulkIdErrorReason', description: 'Error reason', optional: true }) error?: BulkIdErrorReason; } export class UpdateAlbumDto { + @ApiPropertyOptional({ description: 'Album name' }) @Optional() @IsString() albumName?: string; + @ApiPropertyOptional({ description: 'Album description' }) @Optional() @IsString() description?: string; - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Album thumbnail asset ID' }) albumThumbnailAssetId?: string; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Enable activity feed' }) isActivityEnabled?: boolean; - @ValidateEnum({ enum: AssetOrder, name: 'AssetOrder', optional: true }) + @ValidateEnum({ enum: AssetOrder, name: 'AssetOrder', description: 'Asset sort order', optional: true }) order?: AssetOrder; } export class GetAlbumsDto { - @ValidateBoolean({ optional: true }) - /** - * true: only shared albums - * false: only non-shared own albums - * undefined: shared and owned albums - */ + @ValidateBoolean({ + optional: true, + description: 'Filter by shared status: true = only shared, false = only own, undefined = all', + }) shared?: boolean; - /** - * Only returns albums that contain the asset - * Ignores the shared parameter - * undefined: get all albums - */ - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Filter albums containing this asset ID (ignores shared parameter)' }) assetId?: string; } export class AlbumStatisticsResponseDto { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of owned albums' }) owned!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of shared albums' }) shared!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of non-shared albums' }) notShared!: number; } export class UpdateAlbumUserDto { - @ValidateEnum({ enum: AlbumUserRole, name: 'AlbumUserRole' }) + @ValidateEnum({ enum: AlbumUserRole, name: 'AlbumUserRole', description: 'Album user role' }) role!: AlbumUserRole; } export class AlbumUserResponseDto { + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) user!: UserResponseDto; - @ValidateEnum({ enum: AlbumUserRole, name: 'AlbumUserRole' }) + @ValidateEnum({ enum: AlbumUserRole, name: 'AlbumUserRole', description: 'Album user role' }) role!: AlbumUserRole; } export class ContributorCountResponseDto { - @ApiProperty() + @ApiProperty({ description: 'User ID' }) userId!: string; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of assets contributed' }) assetCount!: number; } export class AlbumResponseDto { + @ApiProperty({ description: 'Album ID' }) id!: string; + @ApiProperty({ description: 'Owner user ID' }) ownerId!: string; + @ApiProperty({ description: 'Album name' }) albumName!: string; + @ApiProperty({ description: 'Album description' }) description!: string; + @ApiProperty({ description: 'Creation date' }) createdAt!: Date; + @ApiProperty({ description: 'Last update date' }) updatedAt!: Date; + @ApiProperty({ description: 'Thumbnail asset ID' }) albumThumbnailAssetId!: string | null; + @ApiProperty({ description: 'Is shared album' }) shared!: boolean; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) albumUsers!: AlbumUserResponseDto[]; + @ApiProperty({ description: 'Has shared link' }) hasSharedLink!: boolean; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) assets!: AssetResponseDto[]; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) owner!: UserResponseDto; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of assets' }) assetCount!: number; + @ApiPropertyOptional({ description: 'Last modified asset timestamp' }) lastModifiedAssetTimestamp?: Date; + @ApiPropertyOptional({ description: 'Start date (earliest asset)' }) startDate?: Date; + @ApiPropertyOptional({ description: 'End date (latest asset)' }) endDate?: Date; + @ApiProperty({ description: 'Activity feed enabled' }) isActivityEnabled!: boolean; - @ValidateEnum({ enum: AssetOrder, name: 'AssetOrder', optional: true }) + @ValidateEnum({ enum: AssetOrder, name: 'AssetOrder', description: 'Asset sort order', optional: true }) order?: AssetOrder; - // Optional per-user contribution counts for shared albums + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) @Type(() => ContributorCountResponseDto) - @ApiProperty({ type: [ContributorCountResponseDto], required: false }) contributorCounts?: ContributorCountResponseDto[]; } diff --git a/server/src/dtos/api-key.dto.ts b/server/src/dtos/api-key.dto.ts index c9475fa2b..273082c41 100644 --- a/server/src/dtos/api-key.dto.ts +++ b/server/src/dtos/api-key.dto.ts @@ -1,38 +1,55 @@ +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { ArrayMinSize, IsNotEmpty, IsString } from 'class-validator'; import { Permission } from 'src/enum'; import { Optional, ValidateEnum } from 'src/validation'; + export class APIKeyCreateDto { + @ApiPropertyOptional({ description: 'API key name' }) @IsString() @IsNotEmpty() @Optional() name?: string; - @ValidateEnum({ enum: Permission, name: 'Permission', each: true }) + @ValidateEnum({ enum: Permission, name: 'Permission', each: true, description: 'List of permissions' }) @ArrayMinSize(1) permissions!: Permission[]; } export class APIKeyUpdateDto { + @ApiPropertyOptional({ description: 'API key name' }) @Optional() @IsString() @IsNotEmpty() name?: string; - @ValidateEnum({ enum: Permission, name: 'Permission', each: true, optional: true }) + @ValidateEnum({ + enum: Permission, + name: 'Permission', + description: 'List of permissions', + each: true, + optional: true, + }) @ArrayMinSize(1) permissions?: Permission[]; } -export class APIKeyCreateResponseDto { - secret!: string; - apiKey!: APIKeyResponseDto; -} - export class APIKeyResponseDto { + @ApiProperty({ description: 'API key ID' }) id!: string; + @ApiProperty({ description: 'API key name' }) name!: string; + @ApiProperty({ description: 'Creation date' }) createdAt!: Date; + @ApiProperty({ description: 'Last update date' }) updatedAt!: Date; - @ValidateEnum({ enum: Permission, name: 'Permission', each: true }) + @ValidateEnum({ enum: Permission, name: 'Permission', each: true, description: 'List of permissions' }) permissions!: Permission[]; } + +export class APIKeyCreateResponseDto { + @ApiProperty({ description: 'API key secret (only shown once)' }) + secret!: string; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) + apiKey!: APIKeyResponseDto; +} diff --git a/server/src/dtos/asset-ids.response.dto.ts b/server/src/dtos/asset-ids.response.dto.ts index fdc9942e3..427117518 100644 --- a/server/src/dtos/asset-ids.response.dto.ts +++ b/server/src/dtos/asset-ids.response.dto.ts @@ -1,3 +1,4 @@ +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { ValidateUUID } from 'src/validation'; /** @deprecated Use `BulkIdResponseDto` instead */ @@ -9,8 +10,11 @@ export enum AssetIdErrorReason { /** @deprecated Use `BulkIdResponseDto` instead */ export class AssetIdsResponseDto { + @ApiProperty({ description: 'Asset ID' }) assetId!: string; + @ApiProperty({ description: 'Whether operation succeeded' }) success!: boolean; + @ApiPropertyOptional({ description: 'Error reason if failed', enum: AssetIdErrorReason }) error?: AssetIdErrorReason; } @@ -22,12 +26,15 @@ export enum BulkIdErrorReason { } export class BulkIdsDto { - @ValidateUUID({ each: true }) + @ValidateUUID({ each: true, description: 'IDs to process' }) ids!: string[]; } export class BulkIdResponseDto { + @ApiProperty({ description: 'ID' }) id!: string; + @ApiProperty({ description: 'Whether operation succeeded' }) success!: boolean; + @ApiPropertyOptional({ description: 'Error reason if failed', enum: BulkIdErrorReason }) error?: BulkIdErrorReason; } diff --git a/server/src/dtos/asset-media-response.dto.ts b/server/src/dtos/asset-media-response.dto.ts index 887762dbd..345c1bf41 100644 --- a/server/src/dtos/asset-media-response.dto.ts +++ b/server/src/dtos/asset-media-response.dto.ts @@ -1,3 +1,4 @@ +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { ValidateEnum } from 'src/validation'; export enum AssetMediaStatus { @@ -6,8 +7,9 @@ export enum AssetMediaStatus { DUPLICATE = 'duplicate', } export class AssetMediaResponseDto { - @ValidateEnum({ enum: AssetMediaStatus, name: 'AssetMediaStatus' }) + @ValidateEnum({ enum: AssetMediaStatus, name: 'AssetMediaStatus', description: 'Upload status' }) status!: AssetMediaStatus; + @ApiProperty({ description: 'Asset media ID' }) id!: string; } @@ -22,17 +24,24 @@ export enum AssetRejectReason { } export class AssetBulkUploadCheckResult { + @ApiProperty({ description: 'Asset ID' }) id!: string; + @ApiProperty({ description: 'Upload action', enum: AssetUploadAction }) action!: AssetUploadAction; + @ApiPropertyOptional({ description: 'Rejection reason if rejected', enum: AssetRejectReason }) reason?: AssetRejectReason; + @ApiPropertyOptional({ description: 'Existing asset ID if duplicate' }) assetId?: string; + @ApiPropertyOptional({ description: 'Whether existing asset is trashed' }) isTrashed?: boolean; } export class AssetBulkUploadCheckResponseDto { + @ApiProperty({ description: 'Upload check results' }) results!: AssetBulkUploadCheckResult[]; } export class CheckExistingAssetsResponseDto { + @ApiProperty({ description: 'Existing asset IDs' }) existingIds!: string[]; } diff --git a/server/src/dtos/asset-media.dto.ts b/server/src/dtos/asset-media.dto.ts index 3935774f3..465585037 100644 --- a/server/src/dtos/asset-media.dto.ts +++ b/server/src/dtos/asset-media.dto.ts @@ -1,5 +1,5 @@ import { BadRequestException } from '@nestjs/common'; -import { ApiProperty } from '@nestjs/swagger'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { plainToInstance, Transform, Type } from 'class-transformer'; import { ArrayNotEmpty, IsArray, IsNotEmpty, IsString, ValidateNested } from 'class-validator'; import { AssetMetadataUpsertItemDto } from 'src/dtos/asset.dto'; @@ -18,10 +18,10 @@ export enum AssetMediaSize { } export class AssetMediaOptionsDto { - @ValidateEnum({ enum: AssetMediaSize, name: 'AssetMediaSize', optional: true }) + @ValidateEnum({ enum: AssetMediaSize, name: 'AssetMediaSize', description: 'Asset media size', optional: true }) size?: AssetMediaSize; - @ValidateBoolean({ optional: true, default: false }) + @ValidateBoolean({ optional: true, description: 'Return edited asset if available', default: false }) edited?: boolean; } @@ -32,44 +32,49 @@ export enum UploadFieldName { } class AssetMediaBase { + @ApiProperty({ description: 'Device asset ID' }) @IsNotEmpty() @IsString() deviceAssetId!: string; + @ApiProperty({ description: 'Device ID' }) @IsNotEmpty() @IsString() deviceId!: string; - @ValidateDate() + @ValidateDate({ description: 'File creation date' }) fileCreatedAt!: Date; - @ValidateDate() + @ValidateDate({ description: 'File modification date' }) fileModifiedAt!: Date; + @ApiPropertyOptional({ description: 'Duration (for videos)' }) @Optional() @IsString() duration?: string; + @ApiPropertyOptional({ description: 'Filename' }) @Optional() @IsString() filename?: string; // The properties below are added to correctly generate the API docs // and client SDKs. Validation should be handled in the controller. - @ApiProperty({ type: 'string', format: 'binary' }) + @ApiProperty({ type: 'string', format: 'binary', description: 'Asset file data' }) [UploadFieldName.ASSET_DATA]!: any; } export class AssetMediaCreateDto extends AssetMediaBase { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Mark as favorite' }) isFavorite?: boolean; - @ValidateEnum({ enum: AssetVisibility, name: 'AssetVisibility', optional: true }) + @ValidateEnum({ enum: AssetVisibility, name: 'AssetVisibility', description: 'Asset visibility', optional: true }) visibility?: AssetVisibility; - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Live photo video ID' }) livePhotoVideoId?: string; + @ApiPropertyOptional({ description: 'Asset metadata items' }) @Transform(({ value }) => { try { const json = JSON.parse(value); @@ -84,24 +89,26 @@ export class AssetMediaCreateDto extends AssetMediaBase { @IsArray() metadata?: AssetMetadataUpsertItemDto[]; - @ApiProperty({ type: 'string', format: 'binary', required: false }) + @ApiProperty({ type: 'string', format: 'binary', required: false, description: 'Sidecar file data' }) [UploadFieldName.SIDECAR_DATA]?: any; } export class AssetMediaReplaceDto extends AssetMediaBase {} export class AssetBulkUploadCheckItem { + @ApiProperty({ description: 'Asset ID' }) @IsString() @IsNotEmpty() id!: string; - /** base64 or hex encoded sha1 hash */ + @ApiProperty({ description: 'Base64 or hex encoded SHA1 hash' }) @IsString() @IsNotEmpty() checksum!: string; } export class AssetBulkUploadCheckDto { + @ApiProperty({ description: 'Assets to check' }) @IsArray() @ValidateNested({ each: true }) @Type(() => AssetBulkUploadCheckItem) @@ -109,11 +116,13 @@ export class AssetBulkUploadCheckDto { } export class CheckExistingAssetsDto { + @ApiProperty({ description: 'Device asset IDs to check' }) @ArrayNotEmpty() @IsString({ each: true }) @IsNotEmpty({ each: true }) deviceAssetIds!: string[]; + @ApiProperty({ description: 'Device ID' }) @IsNotEmpty() deviceId!: string; } diff --git a/server/src/dtos/asset-response.dto.ts b/server/src/dtos/asset-response.dto.ts index 92ee3c587..e163b386b 100644 --- a/server/src/dtos/asset-response.dto.ts +++ b/server/src/dtos/asset-response.dto.ts @@ -1,4 +1,4 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Selectable } from 'kysely'; import { AssetFace, AssetFile, Exif, Stack, Tag, User } from 'src/database'; import { HistoryBuilder, Property } from 'src/decorators'; @@ -18,13 +18,16 @@ import { ImageDimensions } from 'src/types'; import { getDimensions } from 'src/utils/asset.util'; import { hexOrBufferToBase64 } from 'src/utils/bytes'; import { mimeTypes } from 'src/utils/mime-types'; -import { ValidateEnum } from 'src/validation'; +import { ValidateEnum, ValidateUUID } from 'src/validation'; export class SanitizedAssetResponseDto { + @ApiProperty({ description: 'Asset ID' }) id!: string; - @ValidateEnum({ enum: AssetType, name: 'AssetTypeEnum' }) + @ValidateEnum({ enum: AssetType, name: 'AssetTypeEnum', description: 'Asset type' }) type!: AssetType; + @ApiProperty({ description: 'Thumbhash for thumbnail generation' }) thumbhash!: string | null; + @ApiPropertyOptional({ description: 'Original MIME type' }) originalMimeType?: string; @ApiProperty({ type: 'string', @@ -34,10 +37,15 @@ export class SanitizedAssetResponseDto { example: '2024-01-15T14:30:00.000Z', }) localDateTime!: Date; + @ApiProperty({ description: 'Video duration (for videos)' }) duration!: string; + @ApiPropertyOptional({ description: 'Live photo video ID' }) livePhotoVideoId?: string | null; + @ApiProperty({ description: 'Whether asset has metadata' }) hasMetadata!: boolean; + @ApiProperty({ description: 'Asset width' }) width!: number | null; + @ApiProperty({ description: 'Asset height' }) height!: number | null; } @@ -49,13 +57,24 @@ export class AssetResponseDto extends SanitizedAssetResponseDto { example: '2024-01-15T20:30:00.000Z', }) createdAt!: Date; + @ApiProperty({ description: 'Device asset ID' }) deviceAssetId!: string; + @ApiProperty({ description: 'Device ID' }) deviceId!: string; + @ApiProperty({ description: 'Owner user ID' }) ownerId!: string; + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) owner?: UserResponseDto; - @Property({ history: new HistoryBuilder().added('v1').deprecated('v1') }) + @ValidateUUID({ + nullable: true, + description: 'Library ID', + history: new HistoryBuilder().added('v1').deprecated('v1'), + }) libraryId?: string | null; + @ApiProperty({ description: 'Original file path' }) originalPath!: string; + @ApiProperty({ description: 'Original file name' }) originalFileName!: string; @ApiProperty({ type: 'string', @@ -81,24 +100,39 @@ export class AssetResponseDto extends SanitizedAssetResponseDto { example: '2024-01-16T12:45:30.000Z', }) updatedAt!: Date; + @ApiProperty({ description: 'Is favorite' }) isFavorite!: boolean; + @ApiProperty({ description: 'Is archived' }) isArchived!: boolean; + @ApiProperty({ description: 'Is trashed' }) isTrashed!: boolean; + @ApiProperty({ description: 'Is offline' }) isOffline!: boolean; - @ValidateEnum({ enum: AssetVisibility, name: 'AssetVisibility' }) + @ValidateEnum({ enum: AssetVisibility, name: 'AssetVisibility', description: 'Asset visibility' }) visibility!: AssetVisibility; + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) exifInfo?: ExifResponseDto; + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) tags?: TagResponseDto[]; + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) people?: PersonWithFacesResponseDto[]; + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) unassignedFaces?: AssetFaceWithoutPersonResponseDto[]; - /**base64 encoded sha1 hash */ + @ApiProperty({ description: 'Base64 encoded SHA1 hash' }) checksum!: string; + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) stack?: AssetStackResponseDto | null; + @ApiPropertyOptional({ description: 'Duplicate group ID' }) duplicateId?: string | null; - @Property({ history: new HistoryBuilder().added('v1').deprecated('v1.113.0') }) + @Property({ description: 'Is resized', history: new HistoryBuilder().added('v1').deprecated('v1.113.0') }) resized?: boolean; - @Property({ history: new HistoryBuilder().added('v2.5.0').beta('v2.5.0') }) + @Property({ description: 'Is edited', history: new HistoryBuilder().added('v2.5.0').beta('v2.5.0') }) isEdited!: boolean; } @@ -143,11 +177,13 @@ export type MapAsset = { }; export class AssetStackResponseDto { + @ApiProperty({ description: 'Stack ID' }) id!: string; + @ApiProperty({ description: 'Primary asset ID' }) primaryAssetId!: string; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of assets in stack' }) assetCount!: number; } diff --git a/server/src/dtos/asset.dto.ts b/server/src/dtos/asset.dto.ts index 5ac79a989..47226e150 100644 --- a/server/src/dtos/asset.dto.ts +++ b/server/src/dtos/asset.dto.ts @@ -22,6 +22,7 @@ import { AssetStats } from 'src/repositories/asset.repository'; import { IsNotSiblingOf, Optional, ValidateBoolean, ValidateEnum, ValidateString, ValidateUUID } from 'src/validation'; export class DeviceIdDto { + @ApiProperty({ description: 'Device ID' }) @IsNotEmpty() @IsString() deviceId!: string; @@ -32,49 +33,57 @@ const hasGPS = (o: { latitude: undefined; longitude: undefined }) => const ValidateGPS = () => ValidateIf(hasGPS); export class UpdateAssetBase { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Mark as favorite' }) isFavorite?: boolean; - @ValidateEnum({ enum: AssetVisibility, name: 'AssetVisibility', optional: true }) + @ValidateEnum({ enum: AssetVisibility, name: 'AssetVisibility', optional: true, description: 'Asset visibility' }) visibility?: AssetVisibility; + @ApiProperty({ description: 'Original date and time' }) @Optional() @IsDateString() dateTimeOriginal?: string; + @ApiProperty({ description: 'Latitude coordinate' }) @ValidateGPS() @IsLatitude() @IsNotEmpty() latitude?: number; + @ApiProperty({ description: 'Longitude coordinate' }) @ValidateGPS() @IsLongitude() @IsNotEmpty() longitude?: number; + @ApiProperty({ description: 'Rating' }) @Optional() @IsInt() @Max(5) @Min(-1) rating?: number; + @ApiProperty({ description: 'Asset description' }) @Optional() @IsString() description?: string; } export class AssetBulkUpdateDto extends UpdateAssetBase { - @ValidateUUID({ each: true }) + @ValidateUUID({ each: true, description: 'Asset IDs to update' }) ids!: string[]; + @ApiProperty({ description: 'Duplicate asset ID' }) @Optional() duplicateId?: string | null; + @ApiProperty({ description: 'Relative time offset in seconds' }) @IsNotSiblingOf(['dateTimeOriginal']) @Optional() @IsInt() dateTimeRelative?: number; + @ApiProperty({ description: 'Time zone (IANA timezone)' }) @IsNotSiblingOf(['dateTimeOriginal']) @IsTimeZone() @Optional() @@ -82,11 +91,12 @@ export class AssetBulkUpdateDto extends UpdateAssetBase { } export class UpdateAssetDto extends UpdateAssetBase { - @ValidateUUID({ optional: true, nullable: true }) + @ValidateUUID({ optional: true, nullable: true, description: 'Live photo video ID' }) livePhotoVideoId?: string | null; } export class RandomAssetsDto { + @ApiProperty({ description: 'Number of random assets to return' }) @Optional() @IsInt() @IsPositive() @@ -95,12 +105,12 @@ export class RandomAssetsDto { } export class AssetBulkDeleteDto extends BulkIdsDto { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Force delete even if in use' }) force?: boolean; } export class AssetIdsDto { - @ValidateUUID({ each: true }) + @ValidateUUID({ each: true, description: 'Asset IDs' }) assetIds!: string[]; } @@ -112,41 +122,42 @@ export enum AssetJobName { } export class AssetJobsDto extends AssetIdsDto { - @ValidateEnum({ enum: AssetJobName, name: 'AssetJobName' }) + @ValidateEnum({ enum: AssetJobName, name: 'AssetJobName', description: 'Job name' }) name!: AssetJobName; } export class AssetStatsDto { - @ValidateEnum({ enum: AssetVisibility, name: 'AssetVisibility', optional: true }) + @ValidateEnum({ enum: AssetVisibility, name: 'AssetVisibility', description: 'Filter by visibility', optional: true }) visibility?: AssetVisibility; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Filter by favorite status' }) isFavorite?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Filter by trash status' }) isTrashed?: boolean; } export class AssetStatsResponseDto { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ description: 'Number of images', type: 'integer' }) images!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ description: 'Number of videos', type: 'integer' }) videos!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ description: 'Total number of assets', type: 'integer' }) total!: number; } export class AssetMetadataRouteParams { - @ValidateUUID() + @ValidateUUID({ description: 'Asset ID' }) id!: string; - @ValidateString() + @ValidateString({ description: 'Metadata key' }) key!: string; } export class AssetMetadataUpsertDto { + @ApiProperty({ description: 'Metadata items to upsert' }) @IsArray() @ValidateNested({ each: true }) @Type(() => AssetMetadataUpsertItemDto) @@ -154,14 +165,16 @@ export class AssetMetadataUpsertDto { } export class AssetMetadataUpsertItemDto { - @ValidateString() + @ValidateString({ description: 'Metadata key' }) key!: string; + @ApiProperty({ description: 'Metadata value (object)' }) @IsObject() value!: object; } export class AssetMetadataBulkUpsertDto { + @ApiProperty({ description: 'Metadata items to upsert' }) @IsArray() @ValidateNested({ each: true }) @Type(() => AssetMetadataBulkUpsertItemDto) @@ -169,17 +182,19 @@ export class AssetMetadataBulkUpsertDto { } export class AssetMetadataBulkUpsertItemDto { - @ValidateUUID() + @ValidateUUID({ description: 'Asset ID' }) assetId!: string; - @ValidateString() + @ValidateString({ description: 'Metadata key' }) key!: string; + @ApiProperty({ description: 'Metadata value (object)' }) @IsObject() value!: object; } export class AssetMetadataBulkDeleteDto { + @ApiProperty({ description: 'Metadata items to delete' }) @IsArray() @ValidateNested({ each: true }) @Type(() => AssetMetadataBulkDeleteItemDto) @@ -187,49 +202,54 @@ export class AssetMetadataBulkDeleteDto { } export class AssetMetadataBulkDeleteItemDto { - @ValidateUUID() + @ValidateUUID({ description: 'Asset ID' }) assetId!: string; - @ValidateString() + @ValidateString({ description: 'Metadata key' }) key!: string; } export class AssetMetadataResponseDto { - @ValidateString() + @ValidateString({ description: 'Metadata key' }) key!: string; + + @ApiProperty({ description: 'Metadata value (object)' }) value!: object; + + @ApiProperty({ description: 'Last update date' }) updatedAt!: Date; } export class AssetMetadataBulkResponseDto extends AssetMetadataResponseDto { + @ApiProperty({ description: 'Asset ID' }) assetId!: string; } export class AssetCopyDto { - @ValidateUUID() + @ValidateUUID({ description: 'Source asset ID' }) sourceId!: string; - @ValidateUUID() + @ValidateUUID({ description: 'Target asset ID' }) targetId!: string; - @ValidateBoolean({ optional: true, default: true }) + @ValidateBoolean({ optional: true, description: 'Copy shared links', default: true }) sharedLinks?: boolean; - @ValidateBoolean({ optional: true, default: true }) + @ValidateBoolean({ optional: true, description: 'Copy album associations', default: true }) albums?: boolean; - @ValidateBoolean({ optional: true, default: true }) + @ValidateBoolean({ optional: true, description: 'Copy sidecar file', default: true }) sidecar?: boolean; - @ValidateBoolean({ optional: true, default: true }) + @ValidateBoolean({ optional: true, description: 'Copy stack association', default: true }) stack?: boolean; - @ValidateBoolean({ optional: true, default: true }) + @ValidateBoolean({ optional: true, description: 'Copy favorite status', default: true }) favorite?: boolean; } export class AssetDownloadOriginalDto { - @ValidateBoolean({ optional: true, default: false }) + @ValidateBoolean({ optional: true, description: 'Return edited asset if available', default: false }) edited?: boolean; } diff --git a/server/src/dtos/auth.dto.ts b/server/src/dtos/auth.dto.ts index d700fc2ab..3df82f4ef 100644 --- a/server/src/dtos/auth.dto.ts +++ b/server/src/dtos/auth.dto.ts @@ -1,4 +1,4 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Transform } from 'class-transformer'; import { IsEmail, IsNotEmpty, IsString, MinLength } from 'class-validator'; import { AuthApiKey, AuthSession, AuthSharedLink, AuthUser, UserAdmin } from 'src/database'; @@ -12,34 +12,46 @@ export type CookieResponse = { }; export class AuthDto { + @ApiProperty({ description: 'Authenticated user' }) user!: AuthUser; + @ApiPropertyOptional({ description: 'API key (if authenticated via API key)' }) apiKey?: AuthApiKey; + @ApiPropertyOptional({ description: 'Shared link (if authenticated via shared link)' }) sharedLink?: AuthSharedLink; + @ApiPropertyOptional({ description: 'Session (if authenticated via session)' }) session?: AuthSession; } export class LoginCredentialDto { + @ApiProperty({ example: 'testuser@email.com', description: 'User email' }) @IsEmail({ require_tld: false }) @Transform(toEmail) @IsNotEmpty() - @ApiProperty({ example: 'testuser@email.com' }) email!: string; + @ApiProperty({ example: 'password', description: 'User password' }) @IsString() @IsNotEmpty() - @ApiProperty({ example: 'password' }) password!: string; } export class LoginResponseDto { + @ApiProperty({ description: 'Access token' }) accessToken!: string; + @ApiProperty({ description: 'User ID' }) userId!: string; + @ApiProperty({ description: 'User email' }) userEmail!: string; + @ApiProperty({ description: 'User name' }) name!: string; + @ApiProperty({ description: 'Profile image path' }) profileImagePath!: string; + @ApiProperty({ description: 'Is admin user' }) isAdmin!: boolean; + @ApiProperty({ description: 'Should change password' }) shouldChangePassword!: boolean; + @ApiProperty({ description: 'Is onboarded' }) isOnboarded!: boolean; } @@ -61,42 +73,47 @@ export function mapLoginResponse(entity: UserAdmin, accessToken: string): LoginR } export class LogoutResponseDto { + @ApiProperty({ description: 'Logout successful' }) successful!: boolean; + @ApiProperty({ description: 'Redirect URI' }) redirectUri!: string; } export class SignUpDto extends LoginCredentialDto { + @ApiProperty({ example: 'Admin', description: 'User name' }) @IsString() @IsNotEmpty() - @ApiProperty({ example: 'Admin' }) name!: string; } export class ChangePasswordDto { + @ApiProperty({ example: 'password', description: 'Current password' }) @IsString() @IsNotEmpty() - @ApiProperty({ example: 'password' }) password!: string; + @ApiProperty({ example: 'password', description: 'New password (min 8 characters)' }) @IsString() @IsNotEmpty() @MinLength(8) - @ApiProperty({ example: 'password' }) newPassword!: string; - @ValidateBoolean({ optional: true, default: false }) + @ValidateBoolean({ optional: true, default: false, description: 'Invalidate all other sessions' }) invalidateSessions?: boolean; } export class PinCodeSetupDto { + @ApiProperty({ description: 'PIN code (4-6 digits)' }) @PinCode() pinCode!: string; } export class PinCodeResetDto { + @ApiPropertyOptional({ description: 'New PIN code (4-6 digits)' }) @PinCode({ optional: true }) pinCode?: string; + @ApiPropertyOptional({ description: 'User password (required if PIN code is not provided)' }) @Optional() @IsString() @IsNotEmpty() @@ -106,51 +123,64 @@ export class PinCodeResetDto { export class SessionUnlockDto extends PinCodeResetDto {} export class PinCodeChangeDto extends PinCodeResetDto { + @ApiProperty({ description: 'New PIN code (4-6 digits)' }) @PinCode() newPinCode!: string; } export class ValidateAccessTokenResponseDto { + @ApiProperty({ description: 'Authentication status' }) authStatus!: boolean; } export class OAuthCallbackDto { + @ApiProperty({ description: 'OAuth callback URL' }) @IsNotEmpty() @IsString() - @ApiProperty() url!: string; + @ApiPropertyOptional({ description: 'OAuth state parameter' }) @Optional() @IsString() state?: string; + @ApiPropertyOptional({ description: 'OAuth code verifier (PKCE)' }) @Optional() @IsString() codeVerifier?: string; } export class OAuthConfigDto { + @ApiProperty({ description: 'OAuth redirect URI' }) @IsNotEmpty() @IsString() redirectUri!: string; + @ApiPropertyOptional({ description: 'OAuth state parameter' }) @Optional() @IsString() state?: string; + @ApiPropertyOptional({ description: 'OAuth code challenge (PKCE)' }) @Optional() @IsString() codeChallenge?: string; } export class OAuthAuthorizeResponseDto { + @ApiProperty({ description: 'OAuth authorization URL' }) url!: string; } export class AuthStatusResponseDto { + @ApiProperty({ description: 'Has PIN code set' }) pinCode!: boolean; + @ApiProperty({ description: 'Has password set' }) password!: boolean; + @ApiProperty({ description: 'Is elevated session' }) isElevated!: boolean; + @ApiPropertyOptional({ description: 'Session expiration date' }) expiresAt?: string; + @ApiPropertyOptional({ description: 'PIN expiration date' }) pinExpiresAt?: string; } diff --git a/server/src/dtos/download.dto.ts b/server/src/dtos/download.dto.ts index e6588a994..2f877e3c0 100644 --- a/server/src/dtos/download.dto.ts +++ b/server/src/dtos/download.dto.ts @@ -1,32 +1,34 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { IsInt, IsPositive } from 'class-validator'; import { Optional, ValidateUUID } from 'src/validation'; export class DownloadInfoDto { - @ValidateUUID({ each: true, optional: true }) + @ValidateUUID({ each: true, optional: true, description: 'Asset IDs to download' }) assetIds?: string[]; - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Album ID to download' }) albumId?: string; - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'User ID to download assets from' }) userId?: string; + @ApiPropertyOptional({ type: 'integer', description: 'Archive size limit in bytes' }) @IsInt() @IsPositive() @Optional() - @ApiProperty({ type: 'integer' }) archiveSize?: number; } export class DownloadResponseDto { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Total size in bytes' }) totalSize!: number; + @ApiProperty({ description: 'Archive information' }) archives!: DownloadArchiveInfo[]; } export class DownloadArchiveInfo { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Archive size in bytes' }) size!: number; + @ApiProperty({ description: 'Asset IDs in this archive' }) assetIds!: string[]; } diff --git a/server/src/dtos/duplicate.dto.ts b/server/src/dtos/duplicate.dto.ts index 166f18ce8..9cd9147ec 100644 --- a/server/src/dtos/duplicate.dto.ts +++ b/server/src/dtos/duplicate.dto.ts @@ -1,6 +1,9 @@ +import { ApiProperty } from '@nestjs/swagger'; import { AssetResponseDto } from 'src/dtos/asset-response.dto'; export class DuplicateResponseDto { + @ApiProperty({ description: 'Duplicate group ID' }) duplicateId!: string; + @ApiProperty({ description: 'Duplicate assets' }) assets!: AssetResponseDto[]; } diff --git a/server/src/dtos/editing.dto.ts b/server/src/dtos/editing.dto.ts index 56bd09f3e..8bb1eef47 100644 --- a/server/src/dtos/editing.dto.ts +++ b/server/src/dtos/editing.dto.ts @@ -50,28 +50,31 @@ export class MirrorParameters { class AssetEditActionBase { @IsEnum(AssetEditAction) - @ApiProperty({ enum: AssetEditAction, enumName: 'AssetEditAction' }) + @ApiProperty({ enum: AssetEditAction, enumName: 'AssetEditAction', description: 'Type of edit action to perform' }) action!: AssetEditAction; } export class AssetEditActionCrop extends AssetEditActionBase { @ValidateNested() @Type(() => CropParameters) - @ApiProperty({ type: CropParameters }) + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) parameters!: CropParameters; } export class AssetEditActionRotate extends AssetEditActionBase { @ValidateNested() @Type(() => RotateParameters) - @ApiProperty({ type: RotateParameters }) + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) parameters!: RotateParameters; } export class AssetEditActionMirror extends AssetEditActionBase { @ValidateNested() @Type(() => MirrorParameters) - @ApiProperty({ type: MirrorParameters }) + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) parameters!: MirrorParameters; } @@ -114,12 +117,14 @@ export class AssetEditActionListDto { @Transform(({ value: edits }) => Array.isArray(edits) ? edits.map((item) => plainToInstance(getActionClass(item), item)) : edits, ) - @ApiProperty({ anyOf: Object.values(actionToClass).map((target) => ({ $ref: getSchemaPath(target) })) }) + @ApiProperty({ + anyOf: Object.values(actionToClass).map((target) => ({ $ref: getSchemaPath(target) })), + description: 'List of edit actions to apply (crop, rotate, or mirror)', + }) edits!: AssetEditActionItem[]; } export class AssetEditsDto extends AssetEditActionListDto { - @ValidateUUID() - @ApiProperty() + @ValidateUUID({ description: 'Asset ID to apply edits to' }) assetId!: string; } diff --git a/server/src/dtos/exif.dto.ts b/server/src/dtos/exif.dto.ts index 9fa61d93c..0052b95b6 100644 --- a/server/src/dtos/exif.dto.ts +++ b/server/src/dtos/exif.dto.ts @@ -1,30 +1,51 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Exif } from 'src/database'; export class ExifResponseDto { + @ApiPropertyOptional({ description: 'Camera make' }) make?: string | null = null; + @ApiPropertyOptional({ description: 'Camera model' }) model?: string | null = null; + @ApiPropertyOptional({ type: 'number', description: 'Image width in pixels' }) exifImageWidth?: number | null = null; + @ApiPropertyOptional({ type: 'number', description: 'Image height in pixels' }) exifImageHeight?: number | null = null; - @ApiProperty({ type: 'integer', format: 'int64' }) + @ApiProperty({ type: 'integer', format: 'int64', description: 'File size in bytes' }) fileSizeInByte?: number | null = null; + @ApiPropertyOptional({ description: 'Image orientation' }) orientation?: string | null = null; + @ApiPropertyOptional({ description: 'Original date/time', format: 'date-time' }) dateTimeOriginal?: Date | null = null; + @ApiPropertyOptional({ description: 'Modification date/time', format: 'date-time' }) modifyDate?: Date | null = null; + @ApiPropertyOptional({ description: 'Time zone' }) timeZone?: string | null = null; + @ApiPropertyOptional({ description: 'Lens model' }) lensModel?: string | null = null; + @ApiPropertyOptional({ type: 'number', description: 'F-number (aperture)' }) fNumber?: number | null = null; + @ApiPropertyOptional({ type: 'number', description: 'Focal length in mm' }) focalLength?: number | null = null; + @ApiPropertyOptional({ type: 'number', description: 'ISO sensitivity' }) iso?: number | null = null; + @ApiPropertyOptional({ description: 'Exposure time' }) exposureTime?: string | null = null; + @ApiPropertyOptional({ type: 'number', description: 'GPS latitude' }) latitude?: number | null = null; + @ApiPropertyOptional({ type: 'number', description: 'GPS longitude' }) longitude?: number | null = null; + @ApiPropertyOptional({ description: 'City name' }) city?: string | null = null; + @ApiPropertyOptional({ description: 'State/province name' }) state?: string | null = null; + @ApiPropertyOptional({ description: 'Country name' }) country?: string | null = null; + @ApiPropertyOptional({ description: 'Image description' }) description?: string | null = null; + @ApiPropertyOptional({ description: 'Projection type' }) projectionType?: string | null = null; + @ApiPropertyOptional({ type: 'number', description: 'Rating' }) rating?: number | null = null; } diff --git a/server/src/dtos/job.dto.ts b/server/src/dtos/job.dto.ts index 794af6e5e..ef34a4172 100644 --- a/server/src/dtos/job.dto.ts +++ b/server/src/dtos/job.dto.ts @@ -2,6 +2,6 @@ import { ManualJobName } from 'src/enum'; import { ValidateEnum } from 'src/validation'; export class JobCreateDto { - @ValidateEnum({ enum: ManualJobName, name: 'ManualJobName' }) + @ValidateEnum({ enum: ManualJobName, name: 'ManualJobName', description: 'Job name' }) name!: ManualJobName; } diff --git a/server/src/dtos/library.dto.ts b/server/src/dtos/library.dto.ts index a0aaace13..3f71b8a0e 100644 --- a/server/src/dtos/library.dto.ts +++ b/server/src/dtos/library.dto.ts @@ -1,17 +1,19 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { ArrayMaxSize, ArrayUnique, IsNotEmpty, IsString } from 'class-validator'; import { Library } from 'src/database'; import { Optional, ValidateUUID } from 'src/validation'; export class CreateLibraryDto { - @ValidateUUID() + @ValidateUUID({ description: 'Owner user ID' }) ownerId!: string; + @ApiPropertyOptional({ description: 'Library name' }) @IsString() @Optional() @IsNotEmpty() name?: string; + @ApiPropertyOptional({ description: 'Import paths (max 128)' }) @Optional() @IsString({ each: true }) @IsNotEmpty({ each: true }) @@ -19,6 +21,7 @@ export class CreateLibraryDto { @ArrayMaxSize(128) importPaths?: string[]; + @ApiPropertyOptional({ description: 'Exclusion patterns (max 128)' }) @Optional() @IsString({ each: true }) @IsNotEmpty({ each: true }) @@ -28,11 +31,13 @@ export class CreateLibraryDto { } export class UpdateLibraryDto { + @ApiPropertyOptional({ description: 'Library name' }) @Optional() @IsString() @IsNotEmpty() name?: string; + @ApiPropertyOptional({ description: 'Import paths (max 128)' }) @Optional() @IsString({ each: true }) @IsNotEmpty({ each: true }) @@ -40,6 +45,7 @@ export class UpdateLibraryDto { @ArrayMaxSize(128) importPaths?: string[]; + @ApiPropertyOptional({ description: 'Exclusion patterns (max 128)' }) @Optional() @IsNotEmpty({ each: true }) @IsString({ each: true }) @@ -59,6 +65,7 @@ export interface WalkOptionsDto extends CrawlOptionsDto { } export class ValidateLibraryDto { + @ApiPropertyOptional({ description: 'Import paths to validate (max 128)' }) @Optional() @IsString({ each: true }) @IsNotEmpty({ each: true }) @@ -66,6 +73,7 @@ export class ValidateLibraryDto { @ArrayMaxSize(128) importPaths?: string[]; + @ApiPropertyOptional({ description: 'Exclusion patterns (max 128)' }) @Optional() @IsNotEmpty({ each: true }) @IsString({ each: true }) @@ -75,48 +83,60 @@ export class ValidateLibraryDto { } export class ValidateLibraryResponseDto { + @ApiPropertyOptional({ description: 'Validation results for import paths' }) importPaths?: ValidateLibraryImportPathResponseDto[]; } export class ValidateLibraryImportPathResponseDto { + @ApiProperty({ description: 'Import path' }) importPath!: string; + @ApiProperty({ description: 'Is valid' }) isValid: boolean = false; + @ApiPropertyOptional({ description: 'Validation message' }) message?: string; } export class LibrarySearchDto { - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Filter by user ID' }) userId?: string; } export class LibraryResponseDto { + @ApiProperty({ description: 'Library ID' }) id!: string; + @ApiProperty({ description: 'Owner user ID' }) ownerId!: string; + @ApiProperty({ description: 'Library name' }) name!: string; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of assets' }) assetCount!: number; + @ApiProperty({ description: 'Import paths' }) importPaths!: string[]; + @ApiProperty({ description: 'Exclusion patterns' }) exclusionPatterns!: string[]; + @ApiProperty({ description: 'Creation date' }) createdAt!: Date; + @ApiProperty({ description: 'Last update date' }) updatedAt!: Date; + @ApiProperty({ description: 'Last refresh date' }) refreshedAt!: Date | null; } export class LibraryStatsResponseDto { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of photos' }) photos = 0; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of videos' }) videos = 0; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Total number of assets' }) total = 0; - @ApiProperty({ type: 'integer', format: 'int64' }) + @ApiProperty({ type: 'integer', format: 'int64', description: 'Storage usage in bytes' }) usage = 0; } diff --git a/server/src/dtos/license.dto.ts b/server/src/dtos/license.dto.ts index 6020d06b6..14232940b 100644 --- a/server/src/dtos/license.dto.ts +++ b/server/src/dtos/license.dto.ts @@ -1,16 +1,20 @@ +import { ApiProperty } from '@nestjs/swagger'; import { IsNotEmpty, IsString, Matches } from 'class-validator'; export class LicenseKeyDto { + @ApiProperty({ description: 'License key (format: IM(SV|CL)(-XXXX){8})' }) @IsString() @IsNotEmpty() @Matches(/IM(SV|CL)(-[\dA-Za-z]{4}){8}/) licenseKey!: string; + @ApiProperty({ description: 'Activation key' }) @IsString() @IsNotEmpty() activationKey!: string; } export class LicenseResponseDto extends LicenseKeyDto { + @ApiProperty({ description: 'Activation date' }) activatedAt!: Date; } diff --git a/server/src/dtos/maintenance.dto.ts b/server/src/dtos/maintenance.dto.ts index 4b8c39c55..f31d9ffa2 100644 --- a/server/src/dtos/maintenance.dto.ts +++ b/server/src/dtos/maintenance.dto.ts @@ -1,29 +1,31 @@ +import { ApiProperty } from '@nestjs/swagger'; import { ValidateIf } from 'class-validator'; import { MaintenanceAction, StorageFolder } from 'src/enum'; -import { ValidateEnum, ValidateString } from 'src/validation'; +import { ValidateBoolean, ValidateEnum, ValidateString } from 'src/validation'; export class SetMaintenanceModeDto { - @ValidateEnum({ enum: MaintenanceAction, name: 'MaintenanceAction' }) + @ValidateEnum({ enum: MaintenanceAction, name: 'MaintenanceAction', description: 'Maintenance action' }) action!: MaintenanceAction; @ValidateIf((o) => o.action === MaintenanceAction.RestoreDatabase) - @ValidateString() + @ValidateString({ description: 'Restore backup filename' }) restoreBackupFilename?: string; } export class MaintenanceLoginDto { - @ValidateString({ optional: true }) + @ValidateString({ optional: true, description: 'Maintenance token' }) token?: string; } export class MaintenanceAuthDto { + @ApiProperty({ description: 'Maintenance username' }) username!: string; } export class MaintenanceStatusResponseDto { active!: boolean; - @ValidateEnum({ enum: MaintenanceAction, name: 'MaintenanceAction' }) + @ValidateEnum({ enum: MaintenanceAction, name: 'MaintenanceAction', description: 'Maintenance action' }) action!: MaintenanceAction; progress?: number; @@ -32,10 +34,13 @@ export class MaintenanceStatusResponseDto { } export class MaintenanceDetectInstallStorageFolderDto { - @ValidateEnum({ enum: StorageFolder, name: 'StorageFolder' }) + @ValidateEnum({ enum: StorageFolder, name: 'StorageFolder', description: 'Storage folder' }) folder!: StorageFolder; + @ValidateBoolean({ description: 'Whether the folder is readable' }) readable!: boolean; + @ValidateBoolean({ description: 'Whether the folder is writable' }) writable!: boolean; + @ApiProperty({ description: 'Number of files in the folder' }) files!: number; } diff --git a/server/src/dtos/map.dto.ts b/server/src/dtos/map.dto.ts index 1d0b84a4d..d8db175c2 100644 --- a/server/src/dtos/map.dto.ts +++ b/server/src/dtos/map.dto.ts @@ -4,64 +4,64 @@ import { IsLatitude, IsLongitude } from 'class-validator'; import { ValidateBoolean, ValidateDate } from 'src/validation'; export class MapReverseGeocodeDto { - @ApiProperty({ format: 'double' }) + @ApiProperty({ format: 'double', description: 'Latitude (-90 to 90)' }) @Type(() => Number) @IsLatitude({ message: ({ property }) => `${property} must be a number between -90 and 90` }) lat!: number; - @ApiProperty({ format: 'double' }) + @ApiProperty({ format: 'double', description: 'Longitude (-180 to 180)' }) @Type(() => Number) @IsLongitude({ message: ({ property }) => `${property} must be a number between -180 and 180` }) lon!: number; } export class MapReverseGeocodeResponseDto { - @ApiProperty() + @ApiProperty({ description: 'City name' }) city!: string | null; - @ApiProperty() + @ApiProperty({ description: 'State/Province name' }) state!: string | null; - @ApiProperty() + @ApiProperty({ description: 'Country name' }) country!: string | null; } export class MapMarkerDto { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Filter by archived status' }) isArchived?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Filter by favorite status' }) isFavorite?: boolean; - @ValidateDate({ optional: true }) + @ValidateDate({ optional: true, description: 'Filter assets created after this date' }) fileCreatedAfter?: Date; - @ValidateDate({ optional: true }) + @ValidateDate({ optional: true, description: 'Filter assets created before this date' }) fileCreatedBefore?: Date; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Include partner assets' }) withPartners?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Include shared album assets' }) withSharedAlbums?: boolean; } export class MapMarkerResponseDto { - @ApiProperty() + @ApiProperty({ description: 'Asset ID' }) id!: string; - @ApiProperty({ format: 'double' }) + @ApiProperty({ format: 'double', description: 'Latitude' }) lat!: number; - @ApiProperty({ format: 'double' }) + @ApiProperty({ format: 'double', description: 'Longitude' }) lon!: number; - @ApiProperty() + @ApiProperty({ description: 'City name' }) city!: string | null; - @ApiProperty() + @ApiProperty({ description: 'State/Province name' }) state!: string | null; - @ApiProperty() + @ApiProperty({ description: 'Country name' }) country!: string | null; } diff --git a/server/src/dtos/memory.dto.ts b/server/src/dtos/memory.dto.ts index 8e7320f83..0d73c19b2 100644 --- a/server/src/dtos/memory.dto.ts +++ b/server/src/dtos/memory.dto.ts @@ -8,24 +8,24 @@ import { AssetOrderWithRandom, MemoryType } from 'src/enum'; import { Optional, ValidateBoolean, ValidateDate, ValidateEnum, ValidateUUID } from 'src/validation'; class MemoryBaseDto { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Is memory saved' }) isSaved?: boolean; - @ValidateDate({ optional: true }) + @ValidateDate({ optional: true, description: 'Date when memory was seen' }) seenAt?: Date; } export class MemorySearchDto { - @ValidateEnum({ enum: MemoryType, name: 'MemoryType', optional: true }) + @ValidateEnum({ enum: MemoryType, name: 'MemoryType', description: 'Memory type', optional: true }) type?: MemoryType; - @ValidateDate({ optional: true }) + @ValidateDate({ optional: true, description: 'Filter by date' }) for?: Date; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Include trashed memories' }) isTrashed?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Filter by saved status' }) isSaved?: boolean; @IsInt() @@ -35,11 +35,12 @@ export class MemorySearchDto { @ApiProperty({ type: 'integer', description: 'Number of memories to return' }) size?: number; - @ValidateEnum({ enum: AssetOrderWithRandom, name: 'MemorySearchOrder', optional: true }) + @ValidateEnum({ enum: AssetOrderWithRandom, name: 'MemorySearchOrder', description: 'Sort order', optional: true }) order?: AssetOrderWithRandom; } class OnThisDayDto { + @ApiProperty({ type: 'number', description: 'Year for on this day memory', minimum: 1 }) @IsInt() @IsPositive() year!: number; @@ -48,14 +49,16 @@ class OnThisDayDto { type MemoryData = OnThisDayDto; export class MemoryUpdateDto extends MemoryBaseDto { - @ValidateDate({ optional: true }) + @ValidateDate({ optional: true, description: 'Memory date' }) memoryAt?: Date; } export class MemoryCreateDto extends MemoryBaseDto { - @ValidateEnum({ enum: MemoryType, name: 'MemoryType' }) + @ValidateEnum({ enum: MemoryType, name: 'MemoryType', description: 'Memory type' }) type!: MemoryType; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @IsObject() @ValidateNested() @Type((options) => { @@ -71,32 +74,46 @@ export class MemoryCreateDto extends MemoryBaseDto { }) data!: MemoryData; - @ValidateDate() + @ValidateDate({ description: 'Memory date' }) memoryAt!: Date; - @ValidateUUID({ optional: true, each: true }) + @ValidateUUID({ optional: true, each: true, description: 'Asset IDs to associate with memory' }) assetIds?: string[]; } export class MemoryStatisticsResponseDto { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Total number of memories' }) total!: number; } export class MemoryResponseDto { + @ApiProperty({ description: 'Memory ID' }) id!: string; + @ValidateDate({ description: 'Creation date' }) createdAt!: Date; + @ValidateDate({ description: 'Last update date' }) updatedAt!: Date; + @ValidateDate({ optional: true, description: 'Deletion date' }) deletedAt?: Date; + @ValidateDate({ description: 'Memory date' }) memoryAt!: Date; + @ValidateDate({ optional: true, description: 'Date when memory was seen' }) seenAt?: Date; + @ValidateDate({ optional: true, description: 'Date when memory should be shown' }) showAt?: Date; + @ValidateDate({ optional: true, description: 'Date when memory should be hidden' }) hideAt?: Date; + @ApiProperty({ description: 'Owner user ID' }) ownerId!: string; - @ValidateEnum({ enum: MemoryType, name: 'MemoryType' }) + @ValidateEnum({ enum: MemoryType, name: 'MemoryType', description: 'Memory type' }) type!: MemoryType; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) data!: MemoryData; + @ApiProperty({ description: 'Is memory saved' }) isSaved!: boolean; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) assets!: AssetResponseDto[]; } diff --git a/server/src/dtos/model-config.dto.ts b/server/src/dtos/model-config.dto.ts index 527317346..a75808f95 100644 --- a/server/src/dtos/model-config.dto.ts +++ b/server/src/dtos/model-config.dto.ts @@ -4,11 +4,12 @@ import { IsNotEmpty, IsNumber, IsString, Max, Min } from 'class-validator'; import { ValidateBoolean } from 'src/validation'; export class TaskConfig { - @ValidateBoolean() + @ValidateBoolean({ description: 'Whether the task is enabled' }) enabled!: boolean; } export class ModelConfig extends TaskConfig { + @ApiProperty({ description: 'Name of the model to use' }) @IsString() @IsNotEmpty() modelName!: string; @@ -21,7 +22,11 @@ export class DuplicateDetectionConfig extends TaskConfig { @Min(0.001) @Max(0.1) @Type(() => Number) - @ApiProperty({ type: 'number', format: 'double' }) + @ApiProperty({ + type: 'number', + format: 'double', + description: 'Maximum distance threshold for duplicate detection', + }) maxDistance!: number; } @@ -30,20 +35,24 @@ export class FacialRecognitionConfig extends ModelConfig { @Min(0.1) @Max(1) @Type(() => Number) - @ApiProperty({ type: 'number', format: 'double' }) + @ApiProperty({ type: 'number', format: 'double', description: 'Minimum confidence score for face detection' }) minScore!: number; @IsNumber() @Min(0.1) @Max(2) @Type(() => Number) - @ApiProperty({ type: 'number', format: 'double' }) + @ApiProperty({ + type: 'number', + format: 'double', + description: 'Maximum distance threshold for face recognition', + }) maxDistance!: number; @IsNumber() @Min(1) @Type(() => Number) - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Minimum number of faces required for recognition' }) minFaces!: number; } @@ -51,20 +60,24 @@ export class OcrConfig extends ModelConfig { @IsNumber() @Min(1) @Type(() => Number) - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Maximum resolution for OCR processing' }) maxResolution!: number; @IsNumber() @Min(0.1) @Max(1) @Type(() => Number) - @ApiProperty({ type: 'number', format: 'double' }) + @ApiProperty({ type: 'number', format: 'double', description: 'Minimum confidence score for text detection' }) minDetectionScore!: number; @IsNumber() @Min(0.1) @Max(1) @Type(() => Number) - @ApiProperty({ type: 'number', format: 'double' }) + @ApiProperty({ + type: 'number', + format: 'double', + description: 'Minimum confidence score for text recognition', + }) minRecognitionScore!: number; } diff --git a/server/src/dtos/notification.dto.ts b/server/src/dtos/notification.dto.ts index e83ba7315..5331db4e8 100644 --- a/server/src/dtos/notification.dto.ts +++ b/server/src/dtos/notification.dto.ts @@ -1,86 +1,115 @@ +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { IsString } from 'class-validator'; import { NotificationLevel, NotificationType } from 'src/enum'; import { Optional, ValidateBoolean, ValidateDate, ValidateEnum, ValidateUUID } from 'src/validation'; export class TestEmailResponseDto { + @ApiProperty({ description: 'Email message ID' }) messageId!: string; } export class TemplateResponseDto { + @ApiProperty({ description: 'Template name' }) name!: string; + @ApiProperty({ description: 'Template HTML content' }) html!: string; } + export class TemplateDto { + @ApiProperty({ description: 'Template name' }) @IsString() template!: string; } export class NotificationDto { + @ApiProperty({ description: 'Notification ID' }) id!: string; - @ValidateDate() + @ValidateDate({ description: 'Creation date' }) createdAt!: Date; - @ValidateEnum({ enum: NotificationLevel, name: 'NotificationLevel' }) + @ValidateEnum({ enum: NotificationLevel, name: 'NotificationLevel', description: 'Notification level' }) level!: NotificationLevel; - @ValidateEnum({ enum: NotificationType, name: 'NotificationType' }) + @ValidateEnum({ enum: NotificationType, name: 'NotificationType', description: 'Notification type' }) type!: NotificationType; + @ApiProperty({ description: 'Notification title' }) title!: string; + @ApiPropertyOptional({ description: 'Notification description' }) description?: string; + @ApiPropertyOptional({ description: 'Additional notification data' }) data?: any; + @ApiPropertyOptional({ description: 'Date when notification was read', format: 'date-time' }) readAt?: Date; } export class NotificationSearchDto { - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Filter by notification ID' }) id?: string; - @ValidateEnum({ enum: NotificationLevel, name: 'NotificationLevel', optional: true }) + @ValidateEnum({ + enum: NotificationLevel, + name: 'NotificationLevel', + optional: true, + description: 'Filter by notification level', + }) level?: NotificationLevel; - @ValidateEnum({ enum: NotificationType, name: 'NotificationType', optional: true }) + @ValidateEnum({ + enum: NotificationType, + name: 'NotificationType', + optional: true, + description: 'Filter by notification type', + }) type?: NotificationType; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Filter by unread status' }) unread?: boolean; } export class NotificationCreateDto { - @ValidateEnum({ enum: NotificationLevel, name: 'NotificationLevel', optional: true }) + @ValidateEnum({ + enum: NotificationLevel, + name: 'NotificationLevel', + optional: true, + description: 'Notification level', + }) level?: NotificationLevel; - @ValidateEnum({ enum: NotificationType, name: 'NotificationType', optional: true }) + @ValidateEnum({ enum: NotificationType, name: 'NotificationType', optional: true, description: 'Notification type' }) type?: NotificationType; + @ApiProperty({ description: 'Notification title' }) @IsString() title!: string; + @ApiPropertyOptional({ description: 'Notification description' }) @IsString() @Optional({ nullable: true }) description?: string | null; + @ApiPropertyOptional({ description: 'Additional notification data' }) @Optional({ nullable: true }) data?: any; - @ValidateDate({ optional: true, nullable: true }) + @ValidateDate({ optional: true, description: 'Date when notification was read' }) readAt?: Date | null; - @ValidateUUID() + @ValidateUUID({ description: 'User ID to send notification to' }) userId!: string; } export class NotificationUpdateDto { - @ValidateDate({ optional: true, nullable: true }) + @ValidateDate({ optional: true, description: 'Date when notification was read' }) readAt?: Date | null; } export class NotificationUpdateAllDto { - @ValidateUUID({ each: true, optional: true }) + @ValidateUUID({ each: true, optional: true, description: 'Notification IDs to update' }) ids!: string[]; - @ValidateDate({ optional: true, nullable: true }) + @ValidateDate({ optional: true, description: 'Date when notifications were read' }) readAt?: Date | null; } export class NotificationDeleteAllDto { - @ValidateUUID({ each: true }) + @ValidateUUID({ each: true, description: 'Notification IDs to delete' }) ids!: string[]; } diff --git a/server/src/dtos/onboarding.dto.ts b/server/src/dtos/onboarding.dto.ts index 47a399278..d2781c6b9 100644 --- a/server/src/dtos/onboarding.dto.ts +++ b/server/src/dtos/onboarding.dto.ts @@ -1,7 +1,7 @@ import { ValidateBoolean } from 'src/validation'; export class OnboardingDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Is user onboarded' }) isOnboarded!: boolean; } diff --git a/server/src/dtos/partner.dto.ts b/server/src/dtos/partner.dto.ts index 599213f66..5b949326a 100644 --- a/server/src/dtos/partner.dto.ts +++ b/server/src/dtos/partner.dto.ts @@ -1,23 +1,26 @@ +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { IsNotEmpty } from 'class-validator'; import { UserResponseDto } from 'src/dtos/user.dto'; import { PartnerDirection } from 'src/repositories/partner.repository'; import { ValidateEnum, ValidateUUID } from 'src/validation'; export class PartnerCreateDto { - @ValidateUUID() + @ValidateUUID({ description: 'User ID to share with' }) sharedWithId!: string; } export class PartnerUpdateDto { + @ApiProperty({ description: 'Show partner assets in timeline' }) @IsNotEmpty() inTimeline!: boolean; } export class PartnerSearchDto { - @ValidateEnum({ enum: PartnerDirection, name: 'PartnerDirection' }) + @ValidateEnum({ enum: PartnerDirection, name: 'PartnerDirection', description: 'Partner direction' }) direction!: PartnerDirection; } export class PartnerResponseDto extends UserResponseDto { + @ApiPropertyOptional({ description: 'Show in timeline' }) inTimeline?: boolean; } diff --git a/server/src/dtos/person.dto.ts b/server/src/dtos/person.dto.ts index 5bf6854d3..983062afc 100644 --- a/server/src/dtos/person.dto.ts +++ b/server/src/dtos/person.dto.ts @@ -23,46 +23,37 @@ import { } from 'src/validation'; export class PersonCreateDto { - /** - * Person name. - */ + @ApiPropertyOptional({ description: 'Person name' }) @Optional() @IsString() name?: string; - /** - * Person date of birth. - * Note: the mobile app cannot currently set the birth date to null. - */ - @ApiProperty({ format: 'date' }) + // Note: the mobile app cannot currently set the birth date to null. + @ApiProperty({ format: 'date', description: 'Person date of birth', required: false }) @MaxDateString(() => DateTime.now(), { message: 'Birth date cannot be in the future' }) @IsDateStringFormat('yyyy-MM-dd') @Optional({ nullable: true, emptyToNull: true }) birthDate?: Date | null; - /** - * Person visibility - */ - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Person visibility (hidden)' }) isHidden?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Mark as favorite' }) isFavorite?: boolean; + @ApiPropertyOptional({ description: 'Person color (hex)' }) @Optional({ emptyToNull: true, nullable: true }) @ValidateHexColor() color?: string | null; } export class PersonUpdateDto extends PersonCreateDto { - /** - * Asset is used to get the feature face thumbnail. - */ - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Asset ID used for feature face thumbnail' }) featureFaceAssetId?: string; } export class PeopleUpdateDto { + @ApiProperty({ description: 'People to update' }) @IsArray() @ValidateNested({ each: true }) @Type(() => PeopleUpdateItem) @@ -70,36 +61,32 @@ export class PeopleUpdateDto { } export class PeopleUpdateItem extends PersonUpdateDto { - /** - * Person id. - */ + @ApiProperty({ description: 'Person ID' }) @IsString() @IsNotEmpty() id!: string; } export class MergePersonDto { - @ValidateUUID({ each: true }) + @ValidateUUID({ each: true, description: 'Person IDs to merge' }) ids!: string[]; } export class PersonSearchDto { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Include hidden people' }) withHidden?: boolean; - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Closest person ID for similarity search' }) closestPersonId?: string; - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Closest asset ID for similarity search' }) closestAssetId?: string; - /** Page number for pagination */ - @ApiPropertyOptional() + @ApiPropertyOptional({ description: 'Page number for pagination', default: 1 }) @IsInt() @Min(1) @Type(() => Number) page: number = 1; - /** Number of items per page */ - @ApiPropertyOptional() + @ApiPropertyOptional({ description: 'Number of items per page', default: 500 }) @IsInt() @Min(1) @Max(1000) @@ -108,48 +95,55 @@ export class PersonSearchDto { } export class PersonResponseDto { + @ApiProperty({ description: 'Person ID' }) id!: string; + @ApiProperty({ description: 'Person name' }) name!: string; - @ApiProperty({ format: 'date' }) + @ApiProperty({ format: 'date', description: 'Person date of birth' }) birthDate!: string | null; + @ApiProperty({ description: 'Thumbnail path' }) thumbnailPath!: string; + @ApiProperty({ description: 'Is hidden' }) isHidden!: boolean; - @Property({ history: new HistoryBuilder().added('v1.107.0').stable('v2') }) + @Property({ description: 'Last update date', history: new HistoryBuilder().added('v1.107.0').stable('v2') }) updatedAt?: Date; - @Property({ history: new HistoryBuilder().added('v1.126.0').stable('v2') }) + @Property({ description: 'Is favorite', history: new HistoryBuilder().added('v1.126.0').stable('v2') }) isFavorite?: boolean; - @Property({ history: new HistoryBuilder().added('v1.126.0').stable('v2') }) + @Property({ description: 'Person color (hex)', history: new HistoryBuilder().added('v1.126.0').stable('v2') }) color?: string; } export class PersonWithFacesResponseDto extends PersonResponseDto { + @ApiProperty({ description: 'Face detections' }) faces!: AssetFaceWithoutPersonResponseDto[]; } export class AssetFaceWithoutPersonResponseDto { - @ValidateUUID() + @ValidateUUID({ description: 'Face ID' }) id!: string; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Image height in pixels' }) imageHeight!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Image width in pixels' }) imageWidth!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Bounding box X1 coordinate' }) boundingBoxX1!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Bounding box X2 coordinate' }) boundingBoxX2!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Bounding box Y1 coordinate' }) boundingBoxY1!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Bounding box Y2 coordinate' }) boundingBoxY2!: number; - @ValidateEnum({ enum: SourceType, name: 'SourceType' }) + @ValidateEnum({ enum: SourceType, name: 'SourceType', optional: true, description: 'Face detection source type' }) sourceType?: SourceType; } export class AssetFaceResponseDto extends AssetFaceWithoutPersonResponseDto { + @ApiProperty({ description: 'Person associated with face' }) person!: PersonResponseDto | null; } export class AssetFaceUpdateDto { + @ApiProperty({ description: 'Face update items' }) @IsArray() @ValidateNested({ each: true }) @Type(() => AssetFaceUpdateItem) @@ -157,69 +151,74 @@ export class AssetFaceUpdateDto { } export class FaceDto { - @ValidateUUID() + @ValidateUUID({ description: 'Face ID' }) id!: string; } export class AssetFaceUpdateItem { - @ValidateUUID() + @ValidateUUID({ description: 'Person ID' }) personId!: string; - @ValidateUUID() + @ValidateUUID({ description: 'Asset ID' }) assetId!: string; } export class AssetFaceCreateDto extends AssetFaceUpdateItem { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Image width in pixels' }) @IsNotEmpty() @IsNumber() imageWidth!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Image height in pixels' }) @IsNotEmpty() @IsNumber() imageHeight!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Face bounding box X coordinate' }) @IsNotEmpty() @IsNumber() x!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Face bounding box Y coordinate' }) @IsNotEmpty() @IsNumber() y!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Face bounding box width' }) @IsNotEmpty() @IsNumber() width!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Face bounding box height' }) @IsNotEmpty() @IsNumber() height!: number; } export class AssetFaceDeleteDto { + @ApiProperty({ description: 'Force delete even if person has other faces' }) @IsNotEmpty() force!: boolean; } export class PersonStatisticsResponseDto { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of assets' }) assets!: number; } export class PeopleResponseDto { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Total number of people' }) total!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of hidden people' }) hidden!: number; + @ApiProperty({ description: 'List of people' }) people!: PersonResponseDto[]; // TODO: make required after a few versions - @Property({ history: new HistoryBuilder().added('v1.110.0').stable('v2') }) + @Property({ + description: 'Whether there are more pages', + history: new HistoryBuilder().added('v1.110.0').stable('v2'), + }) hasNextPage?: boolean; } diff --git a/server/src/dtos/plugin-manifest.dto.ts b/server/src/dtos/plugin-manifest.dto.ts index fcb3ad4a2..d5d1c5299 100644 --- a/server/src/dtos/plugin-manifest.dto.ts +++ b/server/src/dtos/plugin-manifest.dto.ts @@ -1,3 +1,4 @@ +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; import { ArrayMinSize, @@ -16,58 +17,68 @@ import { JSONSchema } from 'src/types/plugin-schema.types'; import { ValidateEnum } from 'src/validation'; class PluginManifestWasmDto { + @ApiProperty({ description: 'WASM file path' }) @IsString() @IsNotEmpty() path!: string; } class PluginManifestFilterDto { + @ApiProperty({ description: 'Filter method name' }) @IsString() @IsNotEmpty() methodName!: string; + @ApiProperty({ description: 'Filter title' }) @IsString() @IsNotEmpty() title!: string; + @ApiProperty({ description: 'Filter description' }) @IsString() @IsNotEmpty() description!: string; + @ApiProperty({ description: 'Supported contexts', enum: PluginContext, isArray: true }) @IsArray() @ArrayMinSize(1) @IsEnum(PluginContext, { each: true }) supportedContexts!: PluginContext[]; + @ApiPropertyOptional({ description: 'Filter schema' }) @IsObject() @IsOptional() schema?: JSONSchema; } class PluginManifestActionDto { + @ApiProperty({ description: 'Action method name' }) @IsString() @IsNotEmpty() methodName!: string; + @ApiProperty({ description: 'Action title' }) @IsString() @IsNotEmpty() title!: string; + @ApiProperty({ description: 'Action description' }) @IsString() @IsNotEmpty() description!: string; - @IsArray() @ArrayMinSize(1) - @ValidateEnum({ enum: PluginContext, name: 'PluginContext', each: true }) + @ValidateEnum({ enum: PluginContext, name: 'PluginContext', each: true, description: 'Supported contexts' }) supportedContexts!: PluginContext[]; + @ApiPropertyOptional({ description: 'Action schema' }) @IsObject() @IsOptional() schema?: JSONSchema; } export class PluginManifestDto { + @ApiProperty({ description: 'Plugin name (lowercase, numbers, hyphens only)' }) @IsString() @IsNotEmpty() @Matches(/^[a-z0-9-]+[a-z0-9]$/, { @@ -75,33 +86,40 @@ export class PluginManifestDto { }) name!: string; + @ApiProperty({ description: 'Plugin version (semver)' }) @IsString() @IsNotEmpty() @IsSemVer() version!: string; + @ApiProperty({ description: 'Plugin title' }) @IsString() @IsNotEmpty() title!: string; + @ApiProperty({ description: 'Plugin description' }) @IsString() @IsNotEmpty() description!: string; + @ApiProperty({ description: 'Plugin author' }) @IsString() @IsNotEmpty() author!: string; + @ApiProperty({ description: 'WASM configuration' }) @ValidateNested() @Type(() => PluginManifestWasmDto) wasm!: PluginManifestWasmDto; + @ApiPropertyOptional({ description: 'Plugin filters' }) @IsArray() @ValidateNested({ each: true }) @Type(() => PluginManifestFilterDto) @IsOptional() filters?: PluginManifestFilterDto[]; + @ApiPropertyOptional({ description: 'Plugin actions' }) @IsArray() @ValidateNested({ each: true }) @Type(() => PluginManifestActionDto) diff --git a/server/src/dtos/plugin.dto.ts b/server/src/dtos/plugin.dto.ts index a802bb120..de1f1b28d 100644 --- a/server/src/dtos/plugin.dto.ts +++ b/server/src/dtos/plugin.dto.ts @@ -1,3 +1,4 @@ +import { ApiProperty } from '@nestjs/swagger'; import { IsNotEmpty, IsString } from 'class-validator'; import { PluginAction, PluginFilter } from 'src/database'; import { PluginContext as PluginContextType, PluginTriggerType } from 'src/enum'; @@ -5,50 +6,73 @@ import type { JSONSchema } from 'src/types/plugin-schema.types'; import { ValidateEnum } from 'src/validation'; export class PluginTriggerResponseDto { - @ValidateEnum({ enum: PluginTriggerType, name: 'PluginTriggerType' }) + @ValidateEnum({ enum: PluginTriggerType, name: 'PluginTriggerType', description: 'Trigger type' }) type!: PluginTriggerType; - @ValidateEnum({ enum: PluginContextType, name: 'PluginContextType' }) + @ValidateEnum({ enum: PluginContextType, name: 'PluginContextType', description: 'Context type' }) contextType!: PluginContextType; } export class PluginResponseDto { + @ApiProperty({ description: 'Plugin ID' }) id!: string; + @ApiProperty({ description: 'Plugin name' }) name!: string; + @ApiProperty({ description: 'Plugin title' }) title!: string; + @ApiProperty({ description: 'Plugin description' }) description!: string; + @ApiProperty({ description: 'Plugin author' }) author!: string; + @ApiProperty({ description: 'Plugin version' }) version!: string; + @ApiProperty({ description: 'Creation date' }) createdAt!: string; + @ApiProperty({ description: 'Last update date' }) updatedAt!: string; + @ApiProperty({ description: 'Plugin filters' }) filters!: PluginFilterResponseDto[]; + @ApiProperty({ description: 'Plugin actions' }) actions!: PluginActionResponseDto[]; } export class PluginFilterResponseDto { + @ApiProperty({ description: 'Filter ID' }) id!: string; + @ApiProperty({ description: 'Plugin ID' }) pluginId!: string; + @ApiProperty({ description: 'Method name' }) methodName!: string; + @ApiProperty({ description: 'Filter title' }) title!: string; + @ApiProperty({ description: 'Filter description' }) description!: string; - @ValidateEnum({ enum: PluginContextType, name: 'PluginContextType' }) + @ValidateEnum({ enum: PluginContextType, name: 'PluginContextType', each: true, description: 'Supported contexts' }) supportedContexts!: PluginContextType[]; + @ApiProperty({ description: 'Filter schema' }) schema!: JSONSchema | null; } export class PluginActionResponseDto { + @ApiProperty({ description: 'Action ID' }) id!: string; + @ApiProperty({ description: 'Plugin ID' }) pluginId!: string; + @ApiProperty({ description: 'Method name' }) methodName!: string; + @ApiProperty({ description: 'Action title' }) title!: string; + @ApiProperty({ description: 'Action description' }) description!: string; - @ValidateEnum({ enum: PluginContextType, name: 'PluginContextType' }) + @ValidateEnum({ enum: PluginContextType, name: 'PluginContextType', each: true, description: 'Supported contexts' }) supportedContexts!: PluginContextType[]; + @ApiProperty({ description: 'Action schema' }) schema!: JSONSchema | null; } export class PluginInstallDto { + @ApiProperty({ description: 'Path to plugin manifest file' }) @IsString() @IsNotEmpty() manifestPath!: string; diff --git a/server/src/dtos/queue-legacy.dto.ts b/server/src/dtos/queue-legacy.dto.ts index e3b48fa86..993160a03 100644 --- a/server/src/dtos/queue-legacy.dto.ts +++ b/server/src/dtos/queue-legacy.dto.ts @@ -3,15 +3,19 @@ import { QueueResponseDto, QueueStatisticsDto } from 'src/dtos/queue.dto'; import { QueueName } from 'src/enum'; export class QueueStatusLegacyDto { + @ApiProperty({ description: 'Whether the queue is currently active (has running jobs)' }) isActive!: boolean; + @ApiProperty({ description: 'Whether the queue is paused' }) isPaused!: boolean; } export class QueueResponseLegacyDto { - @ApiProperty({ type: QueueStatusLegacyDto }) + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) queueStatus!: QueueStatusLegacyDto; - @ApiProperty({ type: QueueStatisticsDto }) + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) jobCounts!: QueueStatisticsDto; } diff --git a/server/src/dtos/queue.dto.ts b/server/src/dtos/queue.dto.ts index 38a4a4ac6..789358144 100644 --- a/server/src/dtos/queue.dto.ts +++ b/server/src/dtos/queue.dto.ts @@ -1,29 +1,29 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { HistoryBuilder, Property } from 'src/decorators'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { HistoryBuilder } from 'src/decorators'; import { JobName, QueueCommand, QueueJobStatus, QueueName } from 'src/enum'; import { ValidateBoolean, ValidateEnum } from 'src/validation'; export class QueueNameParamDto { - @ValidateEnum({ enum: QueueName, name: 'QueueName' }) + @ValidateEnum({ enum: QueueName, name: 'QueueName', description: 'Queue name' }) name!: QueueName; } export class QueueCommandDto { - @ValidateEnum({ enum: QueueCommand, name: 'QueueCommand' }) + @ValidateEnum({ enum: QueueCommand, name: 'QueueCommand', description: 'Queue command to execute' }) command!: QueueCommand; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Force the command execution (if applicable)' }) force?: boolean; // TODO: this uses undefined as a third state, which should be refactored to be more explicit } export class QueueUpdateDto { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Whether to pause the queue' }) isPaused?: boolean; } export class QueueDeleteDto { - @ValidateBoolean({ optional: true }) - @Property({ + @ValidateBoolean({ + optional: true, description: 'If true, will also remove failed jobs from the queue.', history: new HistoryBuilder().added('v2.4.0').alpha('v2.4.0'), }) @@ -31,42 +31,52 @@ export class QueueDeleteDto { } export class QueueJobSearchDto { - @ValidateEnum({ enum: QueueJobStatus, name: 'QueueJobStatus', optional: true, each: true }) + @ValidateEnum({ + enum: QueueJobStatus, + name: 'QueueJobStatus', + optional: true, + each: true, + description: 'Filter jobs by status', + }) status?: QueueJobStatus[]; } export class QueueJobResponseDto { + @ApiPropertyOptional({ description: 'Job ID' }) id?: string; - @ValidateEnum({ enum: JobName, name: 'JobName' }) + @ValidateEnum({ enum: JobName, name: 'JobName', description: 'Job name' }) name!: JobName; + @ApiProperty({ description: 'Job data payload', type: Object }) data!: object; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Job creation timestamp' }) timestamp!: number; } -export class QueueResponseDto { - @ValidateEnum({ enum: QueueName, name: 'QueueName' }) - name!: QueueName; - - @ValidateBoolean() - isPaused!: boolean; - - statistics!: QueueStatisticsDto; -} - export class QueueStatisticsDto { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of active jobs' }) active!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of completed jobs' }) completed!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of failed jobs' }) failed!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of delayed jobs' }) delayed!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of waiting jobs' }) waiting!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of paused jobs' }) paused!: number; } + +export class QueueResponseDto { + @ValidateEnum({ enum: QueueName, name: 'QueueName', description: 'Queue name' }) + name!: QueueName; + + @ValidateBoolean({ description: 'Whether the queue is paused' }) + isPaused!: boolean; + + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) + statistics!: QueueStatisticsDto; +} diff --git a/server/src/dtos/search.dto.ts b/server/src/dtos/search.dto.ts index 068cd6630..59fddcc71 100644 --- a/server/src/dtos/search.dto.ts +++ b/server/src/dtos/search.dto.ts @@ -1,107 +1,116 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; import { IsInt, IsNotEmpty, IsString, Max, Min } from 'class-validator'; import { Place } from 'src/database'; -import { HistoryBuilder, Property } from 'src/decorators'; +import { HistoryBuilder } from 'src/decorators'; import { AlbumResponseDto } from 'src/dtos/album.dto'; import { AssetResponseDto } from 'src/dtos/asset-response.dto'; import { AssetOrder, AssetType, AssetVisibility } from 'src/enum'; import { Optional, ValidateBoolean, ValidateDate, ValidateEnum, ValidateString, ValidateUUID } from 'src/validation'; class BaseSearchDto { - @ValidateUUID({ optional: true, nullable: true }) + @ValidateUUID({ optional: true, nullable: true, description: 'Library ID to filter by' }) libraryId?: string | null; + @ApiPropertyOptional({ description: 'Device ID to filter by' }) @IsString() @IsNotEmpty() @Optional() deviceId?: string; - @ValidateEnum({ enum: AssetType, name: 'AssetTypeEnum', optional: true }) + @ValidateEnum({ enum: AssetType, name: 'AssetTypeEnum', optional: true, description: 'Asset type filter' }) type?: AssetType; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Filter by encoded status' }) isEncoded?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Filter by favorite status' }) isFavorite?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Filter by motion photo status' }) isMotion?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Filter by offline status' }) isOffline?: boolean; - @ValidateEnum({ enum: AssetVisibility, name: 'AssetVisibility', optional: true }) + @ValidateEnum({ enum: AssetVisibility, name: 'AssetVisibility', optional: true, description: 'Filter by visibility' }) visibility?: AssetVisibility; - @ValidateDate({ optional: true }) + @ValidateDate({ optional: true, description: 'Filter by creation date (before)' }) createdBefore?: Date; - @ValidateDate({ optional: true }) + @ValidateDate({ optional: true, description: 'Filter by creation date (after)' }) createdAfter?: Date; - @ValidateDate({ optional: true }) + @ValidateDate({ optional: true, description: 'Filter by update date (before)' }) updatedBefore?: Date; - @ValidateDate({ optional: true }) + @ValidateDate({ optional: true, description: 'Filter by update date (after)' }) updatedAfter?: Date; - @ValidateDate({ optional: true }) + @ValidateDate({ optional: true, description: 'Filter by trash date (before)' }) trashedBefore?: Date; - @ValidateDate({ optional: true }) + @ValidateDate({ optional: true, description: 'Filter by trash date (after)' }) trashedAfter?: Date; - @ValidateDate({ optional: true }) + @ValidateDate({ optional: true, description: 'Filter by taken date (before)' }) takenBefore?: Date; - @ValidateDate({ optional: true }) + @ValidateDate({ optional: true, description: 'Filter by taken date (after)' }) takenAfter?: Date; + @ApiPropertyOptional({ description: 'Filter by city name' }) @IsString() @Optional({ nullable: true, emptyToNull: true }) city?: string | null; + @ApiPropertyOptional({ description: 'Filter by state/province name' }) @IsString() @Optional({ nullable: true, emptyToNull: true }) state?: string | null; + @ApiPropertyOptional({ description: 'Filter by country name' }) @IsString() @IsNotEmpty() @Optional({ nullable: true, emptyToNull: true }) country?: string | null; + @ApiPropertyOptional({ description: 'Filter by camera make' }) @IsString() @Optional({ nullable: true, emptyToNull: true }) make?: string; + @ApiPropertyOptional({ description: 'Filter by camera model' }) @IsString() @Optional({ nullable: true, emptyToNull: true }) model?: string | null; + @ApiPropertyOptional({ description: 'Filter by lens model' }) @IsString() @Optional({ nullable: true, emptyToNull: true }) lensModel?: string | null; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Filter assets not in any album' }) isNotInAlbum?: boolean; - @ValidateUUID({ each: true, optional: true }) + @ValidateUUID({ each: true, optional: true, description: 'Filter by person IDs' }) personIds?: string[]; - @ValidateUUID({ each: true, optional: true, nullable: true }) + @ValidateUUID({ each: true, optional: true, description: 'Filter by tag IDs' }) tagIds?: string[] | null; - @ValidateUUID({ each: true, optional: true }) + @ValidateUUID({ each: true, optional: true, description: 'Filter by album IDs' }) albumIds?: string[]; + @ApiPropertyOptional({ type: 'number', description: 'Filter by rating', minimum: -1, maximum: 5 }) @Optional() @IsInt() @Max(5) @Min(-1) rating?: number; + @ApiPropertyOptional({ description: 'Filter by OCR text content' }) @IsString() @IsNotEmpty() @Optional() @@ -109,12 +118,13 @@ class BaseSearchDto { } class BaseSearchWithResultsDto extends BaseSearchDto { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Include deleted assets' }) withDeleted?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Include EXIF data in response' }) withExif?: boolean; + @ApiPropertyOptional({ type: 'number', description: 'Number of results to return', minimum: 1, maximum: 1000 }) @IsInt() @Min(1) @Max(1000) @@ -124,65 +134,78 @@ class BaseSearchWithResultsDto extends BaseSearchDto { } export class RandomSearchDto extends BaseSearchWithResultsDto { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Include stacked assets' }) withStacked?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Include assets with people' }) withPeople?: boolean; } export class LargeAssetSearchDto extends BaseSearchWithResultsDto { + @ApiPropertyOptional({ type: 'integer', description: 'Minimum file size in bytes', minimum: 0 }) @Optional() @IsInt() @Min(0) @Type(() => Number) - @ApiProperty({ type: 'integer' }) minFileSize?: number; } export class MetadataSearchDto extends RandomSearchDto { - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Filter by asset ID' }) id?: string; + @ApiPropertyOptional({ description: 'Filter by device asset ID' }) @IsString() @IsNotEmpty() @Optional() deviceAssetId?: string; - @ValidateString({ optional: true, trim: true }) + @ValidateString({ optional: true, trim: true, description: 'Filter by description text' }) description?: string; + @ApiPropertyOptional({ description: 'Filter by file checksum' }) @IsString() @IsNotEmpty() @Optional() checksum?: string; - @ValidateString({ optional: true, trim: true }) + @ValidateString({ optional: true, trim: true, description: 'Filter by original file name' }) originalFileName?: string; + @ApiPropertyOptional({ description: 'Filter by original file path' }) @IsString() @IsNotEmpty() @Optional() originalPath?: string; + @ApiPropertyOptional({ description: 'Filter by preview file path' }) @IsString() @IsNotEmpty() @Optional() previewPath?: string; + @ApiPropertyOptional({ description: 'Filter by thumbnail file path' }) @IsString() @IsNotEmpty() @Optional() thumbnailPath?: string; + @ApiPropertyOptional({ description: 'Filter by encoded video file path' }) @IsString() @IsNotEmpty() @Optional() encodedVideoPath?: string; - @ValidateEnum({ enum: AssetOrder, name: 'AssetOrder', optional: true, default: AssetOrder.Desc }) + @ValidateEnum({ + enum: AssetOrder, + name: 'AssetOrder', + optional: true, + default: AssetOrder.Desc, + description: 'Sort order', + }) order?: AssetOrder; + @ApiPropertyOptional({ type: 'number', description: 'Page number', minimum: 1 }) @IsInt() @Min(1) @Type(() => Number) @@ -191,23 +214,24 @@ export class MetadataSearchDto extends RandomSearchDto { } export class StatisticsSearchDto extends BaseSearchDto { - @ValidateString({ optional: true, trim: true }) + @ValidateString({ optional: true, trim: true, description: 'Filter by description text' }) description?: string; } export class SmartSearchDto extends BaseSearchWithResultsDto { - @ValidateString({ optional: true, trim: true }) + @ValidateString({ optional: true, trim: true, description: 'Natural language search query' }) query?: string; - @ValidateUUID({ optional: true }) - @Optional() + @ValidateUUID({ optional: true, description: 'Asset ID to use as search reference' }) queryAssetId?: string; + @ApiPropertyOptional({ description: 'Search language code' }) @IsString() @IsNotEmpty() @Optional() language?: string; + @ApiPropertyOptional({ type: 'number', description: 'Page number', minimum: 1 }) @IsInt() @Min(1) @Type(() => Number) @@ -216,25 +240,32 @@ export class SmartSearchDto extends BaseSearchWithResultsDto { } export class SearchPlacesDto { + @ApiProperty({ description: 'Place name to search for' }) @IsString() @IsNotEmpty() name!: string; } export class SearchPeopleDto { + @ApiProperty({ description: 'Person name to search for' }) @IsString() @IsNotEmpty() name!: string; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Include hidden people' }) withHidden?: boolean; } export class PlacesResponseDto { + @ApiProperty({ description: 'Place name' }) name!: string; + @ApiProperty({ type: 'number', description: 'Latitude coordinate' }) latitude!: number; + @ApiProperty({ type: 'number', description: 'Longitude coordinate' }) longitude!: number; + @ApiPropertyOptional({ description: 'Administrative level 1 name (state/province)' }) admin1name?: string; + @ApiPropertyOptional({ description: 'Administrative level 2 name (county/district)' }) admin2name?: string; } @@ -258,96 +289,126 @@ export enum SearchSuggestionType { } export class SearchSuggestionRequestDto { - @ValidateEnum({ enum: SearchSuggestionType, name: 'SearchSuggestionType' }) + @ValidateEnum({ enum: SearchSuggestionType, name: 'SearchSuggestionType', description: 'Suggestion type' }) type!: SearchSuggestionType; + @ApiPropertyOptional({ description: 'Filter by country' }) @IsString() @Optional() country?: string; + @ApiPropertyOptional({ description: 'Filter by state/province' }) @IsString() @Optional() state?: string; + @ApiPropertyOptional({ description: 'Filter by camera make' }) @IsString() @Optional() make?: string; + @ApiPropertyOptional({ description: 'Filter by camera model' }) @IsString() @Optional() model?: string; + @ApiPropertyOptional({ description: 'Filter by lens model' }) @IsString() @Optional() lensModel?: string; - @ValidateBoolean({ optional: true }) - @Property({ history: new HistoryBuilder().added('v1.111.0').stable('v2') }) + @ValidateBoolean({ + optional: true, + description: 'Include null values in suggestions', + history: new HistoryBuilder().added('v1.111.0').stable('v2'), + }) includeNull?: boolean; } class SearchFacetCountResponseDto { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of assets with this facet value' }) count!: number; + @ApiProperty({ description: 'Facet value' }) value!: string; } class SearchFacetResponseDto { + @ApiProperty({ description: 'Facet field name' }) fieldName!: string; + @ApiProperty({ description: 'Facet counts' }) counts!: SearchFacetCountResponseDto[]; } class SearchAlbumResponseDto { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Total number of matching albums' }) total!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of albums in this page' }) count!: number; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) items!: AlbumResponseDto[]; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) facets!: SearchFacetResponseDto[]; } class SearchAssetResponseDto { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Total number of matching assets' }) total!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of assets in this page' }) count!: number; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) items!: AssetResponseDto[]; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) facets!: SearchFacetResponseDto[]; + @ApiProperty({ description: 'Next page token' }) nextPage!: string | null; } export class SearchResponseDto { + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) albums!: SearchAlbumResponseDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) assets!: SearchAssetResponseDto; } export class SearchStatisticsResponseDto { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Total number of matching assets' }) total!: number; } class SearchExploreItem { + @ApiProperty({ description: 'Explore value' }) value!: string; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) data!: AssetResponseDto; } export class SearchExploreResponseDto { + @ApiProperty({ description: 'Explore field name' }) fieldName!: string; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) items!: SearchExploreItem[]; } export class MemoryLaneDto { + @ApiProperty({ type: 'integer', description: 'Day of month' }) @IsInt() @Type(() => Number) @Max(31) @Min(1) - @ApiProperty({ type: 'integer' }) day!: number; + @ApiProperty({ type: 'integer', description: 'Month' }) @IsInt() @Type(() => Number) @Max(12) @Min(1) - @ApiProperty({ type: 'integer' }) month!: number; } diff --git a/server/src/dtos/server.dto.ts b/server/src/dtos/server.dto.ts index e98cb2edf..626c94e40 100644 --- a/server/src/dtos/server.dto.ts +++ b/server/src/dtos/server.dto.ts @@ -1,4 +1,4 @@ -import { ApiProperty, ApiResponseProperty } from '@nestjs/swagger'; +import { ApiProperty, ApiPropertyOptional, ApiResponseProperty } from '@nestjs/swagger'; import { SemVer } from 'semver'; import { SystemConfigThemeDto } from 'src/dtos/system-config.dto'; @@ -8,66 +8,94 @@ export class ServerPingResponse { } export class ServerAboutResponseDto { + @ApiProperty({ description: 'Server version' }) version!: string; + @ApiProperty({ description: 'URL to version information' }) versionUrl!: string; + @ApiPropertyOptional({ description: 'Repository name' }) repository?: string; + @ApiPropertyOptional({ description: 'Repository URL' }) repositoryUrl?: string; + @ApiPropertyOptional({ description: 'Source reference (branch/tag)' }) sourceRef?: string; + @ApiPropertyOptional({ description: 'Source commit hash' }) sourceCommit?: string; + @ApiPropertyOptional({ description: 'Source URL' }) sourceUrl?: string; + @ApiPropertyOptional({ description: 'Build identifier' }) build?: string; + @ApiPropertyOptional({ description: 'Build URL' }) buildUrl?: string; + @ApiPropertyOptional({ description: 'Build image name' }) buildImage?: string; + @ApiPropertyOptional({ description: 'Build image URL' }) buildImageUrl?: string; + @ApiPropertyOptional({ description: 'Node.js version' }) nodejs?: string; + @ApiPropertyOptional({ description: 'FFmpeg version' }) ffmpeg?: string; + @ApiPropertyOptional({ description: 'ImageMagick version' }) imagemagick?: string; + @ApiPropertyOptional({ description: 'libvips version' }) libvips?: string; + @ApiPropertyOptional({ description: 'ExifTool version' }) exiftool?: string; + @ApiProperty({ description: 'Whether the server is licensed' }) licensed!: boolean; + @ApiPropertyOptional({ description: 'Third-party source URL' }) thirdPartySourceUrl?: string; + @ApiPropertyOptional({ description: 'Third-party bug/feature URL' }) thirdPartyBugFeatureUrl?: string; + @ApiPropertyOptional({ description: 'Third-party documentation URL' }) thirdPartyDocumentationUrl?: string; + @ApiPropertyOptional({ description: 'Third-party support URL' }) thirdPartySupportUrl?: string; } export class ServerApkLinksDto { + @ApiProperty({ description: 'APK download link for ARM64 v8a architecture' }) arm64v8a!: string; + @ApiProperty({ description: 'APK download link for ARM EABI v7a architecture' }) armeabiv7a!: string; + @ApiProperty({ description: 'APK download link for universal architecture' }) universal!: string; + @ApiProperty({ description: 'APK download link for x86_64 architecture' }) x86_64!: string; } export class ServerStorageResponseDto { + @ApiProperty({ description: 'Total disk size (human-readable format)' }) diskSize!: string; + @ApiProperty({ description: 'Used disk space (human-readable format)' }) diskUse!: string; + @ApiProperty({ description: 'Available disk space (human-readable format)' }) diskAvailable!: string; - @ApiProperty({ type: 'integer', format: 'int64' }) + @ApiProperty({ type: 'integer', format: 'int64', description: 'Total disk size in bytes' }) diskSizeRaw!: number; - @ApiProperty({ type: 'integer', format: 'int64' }) + @ApiProperty({ type: 'integer', format: 'int64', description: 'Used disk space in bytes' }) diskUseRaw!: number; - @ApiProperty({ type: 'integer', format: 'int64' }) + @ApiProperty({ type: 'integer', format: 'int64', description: 'Available disk space in bytes' }) diskAvailableRaw!: number; - @ApiProperty({ type: 'number', format: 'double' }) + @ApiProperty({ type: 'number', format: 'double', description: 'Disk usage percentage (0-100)' }) diskUsagePercentage!: number; } export class ServerVersionResponseDto { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Major version number' }) major!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Minor version number' }) minor!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Patch version number' }) patch!: number; static fromSemVer(value: SemVer) { @@ -76,44 +104,52 @@ export class ServerVersionResponseDto { } export class ServerVersionHistoryResponseDto { + @ApiProperty({ description: 'Version history entry ID' }) id!: string; + @ApiProperty({ description: 'When this version was first seen', format: 'date-time' }) createdAt!: Date; + @ApiProperty({ description: 'Version string' }) version!: string; } export class UsageByUserDto { - @ApiProperty({ type: 'string' }) + @ApiProperty({ type: 'string', description: 'User ID' }) userId!: string; - @ApiProperty({ type: 'string' }) + @ApiProperty({ type: 'string', description: 'User name' }) userName!: string; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of photos' }) photos!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of videos' }) videos!: number; - @ApiProperty({ type: 'integer', format: 'int64' }) + @ApiProperty({ type: 'integer', format: 'int64', description: 'Total storage usage in bytes' }) usage!: number; - @ApiProperty({ type: 'integer', format: 'int64' }) + @ApiProperty({ type: 'integer', format: 'int64', description: 'Storage usage for photos in bytes' }) usagePhotos!: number; - @ApiProperty({ type: 'integer', format: 'int64' }) + @ApiProperty({ type: 'integer', format: 'int64', description: 'Storage usage for videos in bytes' }) usageVideos!: number; - @ApiProperty({ type: 'integer', format: 'int64' }) + @ApiProperty({ + type: 'integer', + format: 'int64', + nullable: true, + description: 'User quota size in bytes (null if unlimited)', + }) quotaSizeInBytes!: number | null; } export class ServerStatsResponseDto { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Total number of photos' }) photos = 0; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Total number of videos' }) videos = 0; - @ApiProperty({ type: 'integer', format: 'int64' }) + @ApiProperty({ type: 'integer', format: 'int64', description: 'Total storage usage in bytes' }) usage = 0; - @ApiProperty({ type: 'integer', format: 'int64' }) + @ApiProperty({ type: 'integer', format: 'int64', description: 'Storage usage for photos in bytes' }) usagePhotos = 0; - @ApiProperty({ type: 'integer', format: 'int64' }) + @ApiProperty({ type: 'integer', format: 'int64', description: 'Storage usage for videos in bytes' }) usageVideos = 0; @ApiProperty({ @@ -134,44 +170,71 @@ export class ServerStatsResponseDto { } export class ServerMediaTypesResponseDto { + @ApiProperty({ description: 'Supported video MIME types' }) video!: string[]; + @ApiProperty({ description: 'Supported image MIME types' }) image!: string[]; + @ApiProperty({ description: 'Supported sidecar MIME types' }) sidecar!: string[]; } export class ServerThemeDto extends SystemConfigThemeDto {} export class ServerConfigDto { + @ApiProperty({ description: 'OAuth button text' }) oauthButtonText!: string; + @ApiProperty({ description: 'Login page message' }) loginPageMessage!: string; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of days before trashed assets are permanently deleted' }) trashDays!: number; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Delay in days before deleted users are permanently removed' }) userDeleteDelay!: number; + @ApiProperty({ description: 'Whether the server has been initialized' }) isInitialized!: boolean; + @ApiProperty({ description: 'Whether the admin has completed onboarding' }) isOnboarded!: boolean; + @ApiProperty({ description: 'External domain URL' }) externalDomain!: string; + @ApiProperty({ description: 'Whether public user registration is enabled' }) publicUsers!: boolean; + @ApiProperty({ description: 'Map dark style URL' }) mapDarkStyleUrl!: string; + @ApiProperty({ description: 'Map light style URL' }) mapLightStyleUrl!: string; + @ApiProperty({ description: 'Whether maintenance mode is active' }) maintenanceMode!: boolean; } export class ServerFeaturesDto { + @ApiProperty({ description: 'Whether smart search is enabled' }) smartSearch!: boolean; + @ApiProperty({ description: 'Whether duplicate detection is enabled' }) duplicateDetection!: boolean; + @ApiProperty({ description: 'Whether config file is available' }) configFile!: boolean; + @ApiProperty({ description: 'Whether facial recognition is enabled' }) facialRecognition!: boolean; + @ApiProperty({ description: 'Whether map feature is enabled' }) map!: boolean; + @ApiProperty({ description: 'Whether trash feature is enabled' }) trash!: boolean; + @ApiProperty({ description: 'Whether reverse geocoding is enabled' }) reverseGeocoding!: boolean; + @ApiProperty({ description: 'Whether face import is enabled' }) importFaces!: boolean; + @ApiProperty({ description: 'Whether OAuth is enabled' }) oauth!: boolean; + @ApiProperty({ description: 'Whether OAuth auto-launch is enabled' }) oauthAutoLaunch!: boolean; + @ApiProperty({ description: 'Whether password login is enabled' }) passwordLogin!: boolean; + @ApiProperty({ description: 'Whether sidecar files are supported' }) sidecar!: boolean; + @ApiProperty({ description: 'Whether search is enabled' }) search!: boolean; + @ApiProperty({ description: 'Whether email notifications are enabled' }) email!: boolean; + @ApiProperty({ description: 'Whether OCR is enabled' }) ocr!: boolean; } diff --git a/server/src/dtos/session.dto.ts b/server/src/dtos/session.dto.ts index 49351eda5..f918f0b3b 100644 --- a/server/src/dtos/session.dto.ts +++ b/server/src/dtos/session.dto.ts @@ -1,44 +1,55 @@ +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Equals, IsInt, IsPositive, IsString } from 'class-validator'; import { Session } from 'src/database'; import { Optional, ValidateBoolean } from 'src/validation'; export class SessionCreateDto { - /** - * session duration, in seconds - */ + @ApiPropertyOptional({ type: 'number', description: 'Session duration in seconds' }) @IsInt() @IsPositive() @Optional() duration?: number; + @ApiPropertyOptional({ description: 'Device type' }) @IsString() @Optional() deviceType?: string; + @ApiPropertyOptional({ description: 'Device OS' }) @IsString() @Optional() deviceOS?: string; } export class SessionUpdateDto { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Reset pending sync state' }) @Equals(true) isPendingSyncReset?: true; } export class SessionResponseDto { + @ApiProperty({ description: 'Session ID' }) id!: string; + @ApiProperty({ description: 'Creation date' }) createdAt!: string; + @ApiProperty({ description: 'Last update date' }) updatedAt!: string; + @ApiPropertyOptional({ description: 'Expiration date' }) expiresAt?: string; + @ApiProperty({ description: 'Is current session' }) current!: boolean; + @ApiProperty({ description: 'Device type' }) deviceType!: string; + @ApiProperty({ description: 'Device OS' }) deviceOS!: string; + @ApiProperty({ description: 'App version' }) appVersion!: string | null; + @ApiProperty({ description: 'Is pending sync reset' }) isPendingSyncReset!: boolean; } export class SessionCreateResponseDto extends SessionResponseDto { + @ApiProperty({ description: 'Session token' }) token!: string; } diff --git a/server/src/dtos/shared-link.dto.ts b/server/src/dtos/shared-link.dto.ts index 82698ebdd..7b92f48e2 100644 --- a/server/src/dtos/shared-link.dto.ts +++ b/server/src/dtos/shared-link.dto.ts @@ -1,119 +1,145 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { IsString } from 'class-validator'; import { SharedLink } from 'src/database'; -import { HistoryBuilder, Property } from 'src/decorators'; +import { HistoryBuilder } from 'src/decorators'; import { AlbumResponseDto, mapAlbumWithoutAssets } from 'src/dtos/album.dto'; import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto'; import { SharedLinkType } from 'src/enum'; import { Optional, ValidateBoolean, ValidateDate, ValidateEnum, ValidateUUID } from 'src/validation'; export class SharedLinkSearchDto { - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Filter by album ID' }) albumId?: string; - @ValidateUUID({ optional: true }) - @Property({ history: new HistoryBuilder().added('v2.5.0') }) + @ValidateUUID({ + optional: true, + description: 'Filter by shared link ID', + history: new HistoryBuilder().added('v2.5.0'), + }) id?: string; } export class SharedLinkCreateDto { - @ValidateEnum({ enum: SharedLinkType, name: 'SharedLinkType' }) + @ValidateEnum({ enum: SharedLinkType, name: 'SharedLinkType', description: 'Shared link type' }) type!: SharedLinkType; - @ValidateUUID({ each: true, optional: true }) + @ValidateUUID({ each: true, optional: true, description: 'Asset IDs (for individual assets)' }) assetIds?: string[]; - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Album ID (for album sharing)' }) albumId?: string; + @ApiPropertyOptional({ description: 'Link description' }) @Optional({ nullable: true, emptyToNull: true }) @IsString() description?: string | null; + @ApiPropertyOptional({ description: 'Link password' }) @Optional({ nullable: true, emptyToNull: true }) @IsString() password?: string | null; + @ApiPropertyOptional({ description: 'Custom URL slug' }) @Optional({ nullable: true, emptyToNull: true }) @IsString() slug?: string | null; - @ValidateDate({ optional: true, nullable: true }) + @ValidateDate({ optional: true, description: 'Expiration date' }) expiresAt?: Date | null = null; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Allow uploads' }) allowUpload?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Allow downloads', default: true }) allowDownload?: boolean = true; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Show metadata', default: true }) showMetadata?: boolean = true; } export class SharedLinkEditDto { + @ApiPropertyOptional({ description: 'Link description' }) @Optional({ nullable: true, emptyToNull: true }) @IsString() description?: string | null; + @ApiPropertyOptional({ description: 'Link password' }) @Optional({ nullable: true, emptyToNull: true }) @IsString() password?: string | null; + @ApiPropertyOptional({ description: 'Custom URL slug' }) @Optional({ nullable: true, emptyToNull: true }) @IsString() slug?: string | null; + @ApiPropertyOptional({ description: 'Expiration date' }) @Optional({ nullable: true }) expiresAt?: Date | null; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Allow uploads' }) allowUpload?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Allow downloads' }) allowDownload?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Show metadata' }) showMetadata?: boolean; - /** - * Few clients cannot send null to set the expiryTime to never. - * Setting this flag and not sending expiryAt is considered as null instead. - * Clients that can send null values can ignore this. - */ - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ + optional: true, + description: + 'Whether to change the expiry time. Few clients cannot send null to set the expiryTime to never. Setting this flag and not sending expiryAt is considered as null instead. Clients that can send null values can ignore this.', + }) changeExpiryTime?: boolean; } export class SharedLinkPasswordDto { + @ApiPropertyOptional({ example: 'password', description: 'Link password' }) @IsString() @Optional() - @ApiProperty({ example: 'password' }) password?: string; + @ApiPropertyOptional({ description: 'Access token' }) @IsString() @Optional() token?: string; } export class SharedLinkResponseDto { + @ApiProperty({ description: 'Shared link ID' }) id!: string; + @ApiProperty({ description: 'Link description' }) description!: string | null; + @ApiProperty({ description: 'Has password' }) password!: string | null; + @ApiPropertyOptional({ description: 'Access token' }) token?: string | null; + @ApiProperty({ description: 'Owner user ID' }) userId!: string; + @ApiProperty({ description: 'Encryption key (base64url)' }) key!: string; - @ValidateEnum({ enum: SharedLinkType, name: 'SharedLinkType' }) + @ValidateEnum({ enum: SharedLinkType, name: 'SharedLinkType', description: 'Shared link type' }) type!: SharedLinkType; + @ApiProperty({ description: 'Creation date' }) createdAt!: Date; + @ApiProperty({ description: 'Expiration date' }) expiresAt!: Date | null; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) assets!: AssetResponseDto[]; + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) album?: AlbumResponseDto; + @ApiProperty({ description: 'Allow uploads' }) allowUpload!: boolean; + @ApiProperty({ description: 'Allow downloads' }) allowDownload!: boolean; + @ApiProperty({ description: 'Show metadata' }) showMetadata!: boolean; + @ApiProperty({ description: 'Custom URL slug' }) slug!: string | null; } diff --git a/server/src/dtos/stack.dto.ts b/server/src/dtos/stack.dto.ts index 17037dd89..a76b35e08 100644 --- a/server/src/dtos/stack.dto.ts +++ b/server/src/dtos/stack.dto.ts @@ -1,3 +1,4 @@ +import { ApiProperty } from '@nestjs/swagger'; import { ArrayMinSize } from 'class-validator'; import { Stack } from 'src/database'; import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto'; @@ -5,25 +6,27 @@ import { AuthDto } from 'src/dtos/auth.dto'; import { ValidateUUID } from 'src/validation'; export class StackCreateDto { - /** first asset becomes the primary */ - @ValidateUUID({ each: true }) + @ValidateUUID({ each: true, description: 'Asset IDs (first becomes primary, min 2)' }) @ArrayMinSize(2) assetIds!: string[]; } export class StackSearchDto { - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Filter by primary asset ID' }) primaryAssetId?: string; } export class StackUpdateDto { - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Primary asset ID' }) primaryAssetId?: string; } export class StackResponseDto { + @ApiProperty({ description: 'Stack ID' }) id!: string; + @ApiProperty({ description: 'Primary asset ID' }) primaryAssetId!: string; + @ApiProperty({ description: 'Stack assets' }) assets!: AssetResponseDto[]; } diff --git a/server/src/dtos/sync.dto.ts b/server/src/dtos/sync.dto.ts index 0d1ab0e74..59d7d373f 100644 --- a/server/src/dtos/sync.dto.ts +++ b/server/src/dtos/sync.dto.ts @@ -17,32 +17,35 @@ import { UserMetadata } from 'src/types'; import { ValidateBoolean, ValidateDate, ValidateEnum, ValidateUUID } from 'src/validation'; export class AssetFullSyncDto { - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Last asset ID (pagination)' }) lastId?: string; - @ValidateDate() + @ValidateDate({ description: 'Sync assets updated until this date' }) updatedUntil!: Date; + @ApiProperty({ type: 'integer', description: 'Maximum number of assets to return' }) @IsInt() @IsPositive() - @ApiProperty({ type: 'integer' }) limit!: number; - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'Filter by user ID' }) userId?: string; } export class AssetDeltaSyncDto { - @ValidateDate() + @ValidateDate({ description: 'Sync assets updated after this date' }) updatedAfter!: Date; - @ValidateUUID({ each: true }) + @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[]; } @@ -57,21 +60,31 @@ export const ExtraModel = (): ClassDecorator => { @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', nullable: true }) + @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; } @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; @@ -81,135 +94,189 @@ export class SyncAuthUserV1 extends SyncUserV1 { @ExtraModel() export class SyncUserDeleteV1 { + @ApiProperty({ description: 'User ID' }) userId!: string; } @ExtraModel() export class SyncPartnerV1 { + @ApiProperty({ description: 'Shared by ID' }) sharedById!: string; + @ApiProperty({ description: 'Shared with ID' }) sharedWithId!: string; + @ApiProperty({ description: 'In timeline' }) inTimeline!: boolean; } @ExtraModel() export class SyncPartnerDeleteV1 { + @ApiProperty({ description: 'Shared by ID' }) sharedById!: string; + @ApiProperty({ description: 'Shared with ID' }) sharedWithId!: string; } @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' }) + @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' }) + @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' }) + @ApiProperty({ type: 'integer', description: 'Asset width' }) width!: number | null; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Asset height' }) height!: number | null; - @ApiProperty({ type: 'boolean' }) + @ApiProperty({ description: 'Is edited' }) isEdited!: boolean; } @ExtraModel() export class SyncAssetDeleteV1 { + @ApiProperty({ description: 'Asset ID' }) assetId!: string; } @ExtraModel() export class SyncAssetExifV1 { + @ApiProperty({ description: 'Asset ID' }) assetId!: string; + @ApiProperty({ description: 'Description' }) description!: string | null; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Exif image width' }) exifImageWidth!: number | null; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Exif image height' }) exifImageHeight!: number | null; - @ApiProperty({ type: 'integer' }) + @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' }) + @ApiProperty({ type: 'number', format: 'double', description: 'Latitude' }) latitude!: number | null; - @ApiProperty({ type: 'number', format: 'double' }) + @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' }) + @ApiProperty({ type: 'number', format: 'double', description: 'F number' }) fNumber!: number | null; - @ApiProperty({ type: 'number', format: 'double' }) + @ApiProperty({ type: 'number', format: 'double', description: 'Focal length' }) focalLength!: number | null; - @ApiProperty({ type: 'integer' }) + @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' }) + @ApiProperty({ type: 'integer', description: 'Rating' }) rating!: number | null; - @ApiProperty({ type: 'number', format: 'double' }) + @ApiProperty({ type: 'number', format: 'double', description: 'FPS' }) fps!: number | null; } @ExtraModel() export class SyncAssetMetadataV1 { + @ApiProperty({ description: 'Asset ID' }) assetId!: string; + @ApiProperty({ description: 'Key' }) key!: string; + @ApiProperty({ description: 'Value' }) value!: object; } @ExtraModel() export class SyncAssetMetadataDeleteV1 { + @ApiProperty({ description: 'Asset ID' }) assetId!: string; + @ApiProperty({ description: 'Key' }) key!: string; } @ExtraModel() export class SyncAlbumDeleteV1 { + @ApiProperty({ description: 'Album ID' }) albumId!: string; } @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' }) + @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; @@ -217,87 +284,127 @@ export class SyncAlbumV1 { @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' }) + @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; @@ -311,26 +418,31 @@ export class SyncAssetFaceV1 { boundingBoxX2!: number; @ApiProperty({ type: 'integer' }) boundingBoxY2!: number; + @ApiProperty({ description: 'Source type' }) sourceType!: string; } @ExtraModel() export class SyncAssetFaceDeleteV1 { + @ApiProperty({ description: 'Asset face ID' }) assetFaceId!: string; } @ExtraModel() export class SyncUserMetadataV1 { + @ApiProperty({ description: 'User ID' }) userId!: string; - @ValidateEnum({ enum: UserMetadataKey, name: 'UserMetadataKey' }) + @ValidateEnum({ enum: UserMetadataKey, name: 'UserMetadataKey', description: 'User metadata key' }) key!: UserMetadataKey; + @ApiProperty({ description: 'User metadata value' }) value!: UserMetadata[UserMetadataKey]; } @ExtraModel() export class SyncUserMetadataDeleteV1 { + @ApiProperty({ description: 'User ID' }) userId!: string; - @ValidateEnum({ enum: UserMetadataKey, name: 'UserMetadataKey' }) + @ValidateEnum({ enum: UserMetadataKey, name: 'UserMetadataKey', description: 'User metadata key' }) key!: UserMetadataKey; } @@ -394,26 +506,34 @@ export type SyncItem = { }; export class SyncStreamDto { - @ValidateEnum({ enum: SyncRequestType, name: 'SyncRequestType', each: true }) + @ValidateEnum({ enum: SyncRequestType, name: 'SyncRequestType', each: true, description: 'Sync request types' }) types!: SyncRequestType[]; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Reset sync state' }) reset?: boolean; } export class SyncAckDto { - @ValidateEnum({ enum: SyncEntityType, name: 'SyncEntityType' }) + @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 }) + @ValidateEnum({ + enum: SyncEntityType, + name: 'SyncEntityType', + optional: true, + each: true, + description: 'Sync entity types to delete acks for', + }) types?: SyncEntityType[]; } diff --git a/server/src/dtos/system-config.dto.ts b/server/src/dtos/system-config.dto.ts index b0d5a0646..7a0dcb6f3 100644 --- a/server/src/dtos/system-config.dto.ts +++ b/server/src/dtos/system-config.dto.ts @@ -40,18 +40,20 @@ const isEmailNotificationEnabled = (config: SystemConfigSmtpDto) => config.enabl const isDatabaseBackupEnabled = (config: DatabaseBackupConfig) => config.enabled; export class DatabaseBackupConfig { - @ValidateBoolean() + @ValidateBoolean({ description: 'Enabled' }) enabled!: boolean; @ValidateIf(isDatabaseBackupEnabled) @IsNotEmpty() @IsCronExpression() @IsString() + @ApiProperty({ description: 'Cron expression' }) cronExpression!: string; @IsInt() @IsPositive() @IsNotEmpty() + @ApiProperty({ description: 'Keep last amount' }) keepLastAmount!: number; } @@ -67,171 +69,179 @@ export class SystemConfigFFmpegDto { @Min(0) @Max(51) @Type(() => Number) - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'CRF' }) crf!: number; @IsInt() @Min(0) @Type(() => Number) - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Threads' }) threads!: number; @IsString() + @ApiProperty({ description: 'Preset' }) preset!: string; - @ValidateEnum({ enum: VideoCodec, name: 'VideoCodec' }) + @ValidateEnum({ enum: VideoCodec, name: 'VideoCodec', description: 'Target video codec' }) targetVideoCodec!: VideoCodec; - @ValidateEnum({ enum: VideoCodec, name: 'VideoCodec', each: true }) + @ValidateEnum({ enum: VideoCodec, name: 'VideoCodec', each: true, description: 'Accepted video codecs' }) acceptedVideoCodecs!: VideoCodec[]; - @ValidateEnum({ enum: AudioCodec, name: 'AudioCodec' }) + @ValidateEnum({ enum: AudioCodec, name: 'AudioCodec', description: 'Target audio codec' }) targetAudioCodec!: AudioCodec; - @ValidateEnum({ enum: AudioCodec, name: 'AudioCodec', each: true }) + @ValidateEnum({ enum: AudioCodec, name: 'AudioCodec', each: true, description: 'Accepted audio codecs' }) acceptedAudioCodecs!: AudioCodec[]; - @ValidateEnum({ enum: VideoContainer, name: 'VideoContainer', each: true }) + @ValidateEnum({ enum: VideoContainer, name: 'VideoContainer', each: true, description: 'Accepted containers' }) acceptedContainers!: VideoContainer[]; @IsString() + @ApiProperty({ description: 'Target resolution' }) targetResolution!: string; @IsString() + @ApiProperty({ description: 'Max bitrate' }) maxBitrate!: string; @IsInt() @Min(-1) @Max(16) @Type(() => Number) - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'B-frames' }) bframes!: number; @IsInt() @Min(0) @Max(6) @Type(() => Number) - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'References' }) refs!: number; @IsInt() @Min(0) @Type(() => Number) - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'GOP size' }) gopSize!: number; - @ValidateBoolean() + @ValidateBoolean({ description: 'Temporal AQ' }) temporalAQ!: boolean; - @ValidateEnum({ enum: CQMode, name: 'CQMode' }) + @ValidateEnum({ enum: CQMode, name: 'CQMode', description: 'CQ mode' }) cqMode!: CQMode; - @ValidateBoolean() + @ValidateBoolean({ description: 'Two pass' }) twoPass!: boolean; + @ApiProperty({ description: 'Preferred hardware device' }) @IsString() preferredHwDevice!: string; - @ValidateEnum({ enum: TranscodePolicy, name: 'TranscodePolicy' }) + @ValidateEnum({ enum: TranscodePolicy, name: 'TranscodePolicy', description: 'Transcode policy' }) transcode!: TranscodePolicy; - @ValidateEnum({ enum: TranscodeHardwareAcceleration, name: 'TranscodeHWAccel' }) + @ValidateEnum({ + enum: TranscodeHardwareAcceleration, + name: 'TranscodeHWAccel', + description: 'Transcode hardware acceleration', + }) accel!: TranscodeHardwareAcceleration; - @ValidateBoolean() + @ValidateBoolean({ description: 'Accelerated decode' }) accelDecode!: boolean; - @ValidateEnum({ enum: ToneMapping, name: 'ToneMapping' }) + @ValidateEnum({ enum: ToneMapping, name: 'ToneMapping', description: 'Tone mapping' }) tonemap!: ToneMapping; } class JobSettingsDto { @IsInt() @IsPositive() - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Concurrency' }) concurrency!: number; } class SystemConfigJobDto implements Record { - @ApiProperty({ type: JobSettingsDto }) + @ApiProperty({ type: JobSettingsDto, description: undefined }) @ValidateNested() @IsObject() @Type(() => JobSettingsDto) [QueueName.ThumbnailGeneration]!: JobSettingsDto; - @ApiProperty({ type: JobSettingsDto }) + @ApiProperty({ type: JobSettingsDto, description: undefined }) @ValidateNested() @IsObject() @Type(() => JobSettingsDto) [QueueName.MetadataExtraction]!: JobSettingsDto; - @ApiProperty({ type: JobSettingsDto }) + @ApiProperty({ type: JobSettingsDto, description: undefined }) @ValidateNested() @IsObject() @Type(() => JobSettingsDto) [QueueName.VideoConversion]!: JobSettingsDto; - @ApiProperty({ type: JobSettingsDto }) + @ApiProperty({ type: JobSettingsDto, description: undefined }) @ValidateNested() @IsObject() @Type(() => JobSettingsDto) [QueueName.SmartSearch]!: JobSettingsDto; - @ApiProperty({ type: JobSettingsDto }) + @ApiProperty({ type: JobSettingsDto, description: undefined }) @ValidateNested() @IsObject() @Type(() => JobSettingsDto) [QueueName.Migration]!: JobSettingsDto; - @ApiProperty({ type: JobSettingsDto }) + @ApiProperty({ type: JobSettingsDto, description: undefined }) @ValidateNested() @IsObject() @Type(() => JobSettingsDto) [QueueName.BackgroundTask]!: JobSettingsDto; - @ApiProperty({ type: JobSettingsDto }) + @ApiProperty({ type: JobSettingsDto, description: undefined }) @ValidateNested() @IsObject() @Type(() => JobSettingsDto) [QueueName.Search]!: JobSettingsDto; - @ApiProperty({ type: JobSettingsDto }) + @ApiProperty({ type: JobSettingsDto, description: undefined }) @ValidateNested() @IsObject() @Type(() => JobSettingsDto) [QueueName.FaceDetection]!: JobSettingsDto; - @ApiProperty({ type: JobSettingsDto }) + @ApiProperty({ type: JobSettingsDto, description: undefined }) @ValidateNested() @IsObject() @Type(() => JobSettingsDto) [QueueName.Ocr]!: JobSettingsDto; - @ApiProperty({ type: JobSettingsDto }) + @ApiProperty({ type: JobSettingsDto, description: undefined }) @ValidateNested() @IsObject() @Type(() => JobSettingsDto) [QueueName.Sidecar]!: JobSettingsDto; - @ApiProperty({ type: JobSettingsDto }) + @ApiProperty({ type: JobSettingsDto, description: undefined }) @ValidateNested() @IsObject() @Type(() => JobSettingsDto) [QueueName.Library]!: JobSettingsDto; - @ApiProperty({ type: JobSettingsDto }) + @ApiProperty({ type: JobSettingsDto, description: undefined }) @ValidateNested() @IsObject() @Type(() => JobSettingsDto) [QueueName.Notification]!: JobSettingsDto; - @ApiProperty({ type: JobSettingsDto }) + @ApiProperty({ type: JobSettingsDto, description: undefined }) @ValidateNested() @IsObject() @Type(() => JobSettingsDto) [QueueName.Workflow]!: JobSettingsDto; - @ApiProperty({ type: JobSettingsDto }) + @ApiProperty({ type: JobSettingsDto, description: undefined }) @ValidateNested() @IsObject() @Type(() => JobSettingsDto) @@ -239,7 +249,7 @@ class SystemConfigJobDto implements Record } class SystemConfigLibraryScanDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Enabled' }) enabled!: boolean; @ValidateIf(isLibraryScanEnabled) @@ -250,7 +260,7 @@ class SystemConfigLibraryScanDto { } class SystemConfigLibraryWatchDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Enabled' }) enabled!: boolean; } @@ -267,7 +277,7 @@ class SystemConfigLibraryDto { } class SystemConfigLoggingDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Enabled' }) enabled!: boolean; @ValidateEnum({ enum: LogLevel, name: 'LogLevel' }) @@ -275,7 +285,7 @@ class SystemConfigLoggingDto { } class MachineLearningAvailabilityChecksDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Enabled' }) enabled!: boolean; @IsInt() @@ -286,7 +296,7 @@ class MachineLearningAvailabilityChecksDto { } class SystemConfigMachineLearningDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Enabled' }) enabled!: boolean; @IsUrl({ require_tld: false, allow_underscores: true }, { each: true }) @@ -332,7 +342,7 @@ export class MapThemeDto { } class SystemConfigMapDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Enabled' }) enabled!: boolean; @IsNotEmpty() @@ -345,7 +355,7 @@ class SystemConfigMapDto { } class SystemConfigNewVersionCheckDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Enabled' }) enabled!: boolean; } @@ -353,72 +363,82 @@ class SystemConfigNightlyTasksDto { @IsDateStringFormat('HH:mm', { message: 'startTime must be in HH:mm format' }) startTime!: string; - @ValidateBoolean() + @ValidateBoolean({ description: 'Database cleanup' }) databaseCleanup!: boolean; - @ValidateBoolean() + @ValidateBoolean({ description: 'Missing thumbnails' }) missingThumbnails!: boolean; - @ValidateBoolean() + @ValidateBoolean({ description: 'Cluster new faces' }) clusterNewFaces!: boolean; - @ValidateBoolean() + @ValidateBoolean({ description: 'Generate memories' }) generateMemories!: boolean; - @ValidateBoolean() + @ValidateBoolean({ description: 'Sync quota usage' }) syncQuotaUsage!: boolean; } class SystemConfigOAuthDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Auto launch' }) autoLaunch!: boolean; - @ValidateBoolean() + @ValidateBoolean({ description: 'Auto register' }) autoRegister!: boolean; @IsString() + @ApiProperty({ description: 'Button text' }) buttonText!: string; @ValidateIf(isOAuthEnabled) @IsNotEmpty() @IsString() + @ApiProperty({ description: 'Client ID' }) clientId!: string; @ValidateIf(isOAuthEnabled) @IsString() + @ApiProperty({ description: 'Client secret' }) clientSecret!: string; - @ValidateEnum({ enum: OAuthTokenEndpointAuthMethod, name: 'OAuthTokenEndpointAuthMethod' }) + @ValidateEnum({ + enum: OAuthTokenEndpointAuthMethod, + name: 'OAuthTokenEndpointAuthMethod', + description: 'Token endpoint auth method', + }) tokenEndpointAuthMethod!: OAuthTokenEndpointAuthMethod; @IsInt() @IsPositive() @Optional() - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Timeout' }) timeout!: number; @IsNumber() @Min(0) @Optional({ nullable: true }) - @ApiProperty({ type: 'integer', format: 'int64' }) + @ApiProperty({ type: 'integer', format: 'int64', description: 'Default storage quota' }) defaultStorageQuota!: number | null; - @ValidateBoolean() + @ValidateBoolean({ description: 'Enabled' }) enabled!: boolean; @ValidateIf(isOAuthEnabled) @IsNotEmpty() @IsString() + @ApiProperty({ description: 'Issuer URL' }) issuerUrl!: string; - @ValidateBoolean() + @ValidateBoolean({ description: 'Mobile override enabled' }) mobileOverrideEnabled!: boolean; @ValidateIf(isOAuthOverrideEnabled) @IsUrl() + @ApiProperty({ description: 'Mobile redirect URI' }) mobileRedirectUri!: string; @IsString() + @ApiProperty({ description: 'Scope' }) scope!: string; @IsString() @@ -427,30 +447,34 @@ class SystemConfigOAuthDto { @IsString() @IsNotEmpty() + @ApiProperty({ description: 'Profile signing algorithm' }) profileSigningAlgorithm!: string; @IsString() + @ApiProperty({ description: 'Storage label claim' }) storageLabelClaim!: string; @IsString() + @ApiProperty({ description: 'Storage quota claim' }) storageQuotaClaim!: string; @IsString() + @ApiProperty({ description: 'Role claim' }) roleClaim!: string; } class SystemConfigPasswordLoginDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Enabled' }) enabled!: boolean; } class SystemConfigReverseGeocodingDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Enabled' }) enabled!: boolean; } class SystemConfigFacesDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Import' }) import!: boolean; } @@ -464,51 +488,61 @@ class SystemConfigMetadataDto { class SystemConfigServerDto { @ValidateIf((_, value: string) => value !== '') @IsUrl({ require_tld: false, require_protocol: true, protocols: ['http', 'https'] }) + @ApiProperty({ description: 'External domain' }) externalDomain!: string; @IsString() + @ApiProperty({ description: 'Login page message' }) loginPageMessage!: string; - @ValidateBoolean() + @ValidateBoolean({ description: 'Public users' }) publicUsers!: boolean; } class SystemConfigSmtpTransportDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Whether to ignore SSL certificate errors' }) ignoreCert!: boolean; + @ApiProperty({ description: 'SMTP server hostname' }) @IsNotEmpty() @IsString() host!: string; + @ApiProperty({ description: 'SMTP server port', type: Number, minimum: 0, maximum: 65_535 }) @IsNumber() @Min(0) @Max(65_535) port!: number; - @ValidateBoolean() + @ValidateBoolean({ description: 'Whether to use secure connection (TLS/SSL)' }) secure!: boolean; + @ApiProperty({ description: 'SMTP username' }) @IsString() username!: string; + @ApiProperty({ description: 'SMTP password' }) @IsString() password!: string; } export class SystemConfigSmtpDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Whether SMTP email notifications are enabled' }) enabled!: boolean; + @ApiProperty({ description: 'Email address to send from' }) @ValidateIf(isEmailNotificationEnabled) @IsNotEmpty() @IsString() @IsNotEmpty() from!: string; + @ApiProperty({ description: 'Email address for replies' }) @IsString() replyTo!: string; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @ValidateIf(isEmailNotificationEnabled) @Type(() => SystemConfigSmtpTransportDto) @ValidateNested() @@ -542,48 +576,58 @@ class SystemConfigTemplatesDto { } class SystemConfigStorageTemplateDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Enabled' }) enabled!: boolean; - @ValidateBoolean() + @ValidateBoolean({ description: 'Hash verification enabled' }) hashVerificationEnabled!: boolean; @IsNotEmpty() @IsString() + @ApiProperty({ description: 'Template' }) template!: string; } export class SystemConfigTemplateStorageOptionDto { + @ApiProperty({ description: 'Available year format options for storage template' }) yearOptions!: string[]; + @ApiProperty({ description: 'Available month format options for storage template' }) monthOptions!: string[]; + @ApiProperty({ description: 'Available week format options for storage template' }) weekOptions!: string[]; + @ApiProperty({ description: 'Available day format options for storage template' }) dayOptions!: string[]; + @ApiProperty({ description: 'Available hour format options for storage template' }) hourOptions!: string[]; + @ApiProperty({ description: 'Available minute format options for storage template' }) minuteOptions!: string[]; + @ApiProperty({ description: 'Available second format options for storage template' }) secondOptions!: string[]; + @ApiProperty({ description: 'Available preset template options' }) presetOptions!: string[]; } export class SystemConfigThemeDto { + @ApiProperty({ description: 'Custom CSS for theming' }) @IsString() customCss!: string; } class SystemConfigGeneratedImageDto { - @ValidateEnum({ enum: ImageFormat, name: 'ImageFormat' }) + @ValidateEnum({ enum: ImageFormat, name: 'ImageFormat', description: 'Image format' }) format!: ImageFormat; @IsInt() @Min(1) @Max(100) @Type(() => Number) - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Quality' }) quality!: number; @IsInt() @Min(1) @Type(() => Number) - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Size' }) size!: number; @ValidateBoolean({ optional: true, default: false }) @@ -591,20 +635,20 @@ class SystemConfigGeneratedImageDto { } class SystemConfigGeneratedFullsizeImageDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Enabled' }) enabled!: boolean; - @ValidateEnum({ enum: ImageFormat, name: 'ImageFormat' }) + @ValidateEnum({ enum: ImageFormat, name: 'ImageFormat', description: 'Image format' }) format!: ImageFormat; @IsInt() @Min(1) @Max(100) @Type(() => Number) - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Quality' }) quality!: number; - @ValidateBoolean({ optional: true, default: false }) + @ValidateBoolean({ optional: true, default: false, description: 'Progressive' }) progressive?: boolean; } @@ -612,33 +656,39 @@ export class SystemConfigImageDto { @Type(() => SystemConfigGeneratedImageDto) @ValidateNested() @IsObject() + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) thumbnail!: SystemConfigGeneratedImageDto; @Type(() => SystemConfigGeneratedImageDto) @ValidateNested() @IsObject() + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) preview!: SystemConfigGeneratedImageDto; @Type(() => SystemConfigGeneratedFullsizeImageDto) @ValidateNested() @IsObject() + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) fullsize!: SystemConfigGeneratedFullsizeImageDto; - @ValidateEnum({ enum: Colorspace, name: 'Colorspace' }) + @ValidateEnum({ enum: Colorspace, name: 'Colorspace', description: 'Colorspace' }) colorspace!: Colorspace; - @ValidateBoolean() + @ValidateBoolean({ description: 'Extract embedded' }) extractEmbedded!: boolean; } class SystemConfigTrashDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Enabled' }) enabled!: boolean; @IsInt() @Min(0) @Type(() => Number) - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Days' }) days!: number; } @@ -646,111 +696,153 @@ class SystemConfigUserDto { @IsInt() @Min(1) @Type(() => Number) - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Delete delay' }) deleteDelay!: number; } export class SystemConfigDto implements SystemConfig { + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigBackupsDto) @ValidateNested() @IsObject() backup!: SystemConfigBackupsDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigFFmpegDto) @ValidateNested() @IsObject() ffmpeg!: SystemConfigFFmpegDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigLoggingDto) @ValidateNested() @IsObject() logging!: SystemConfigLoggingDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigMachineLearningDto) @ValidateNested() @IsObject() machineLearning!: SystemConfigMachineLearningDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigMapDto) @ValidateNested() @IsObject() map!: SystemConfigMapDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigNewVersionCheckDto) @ValidateNested() @IsObject() newVersionCheck!: SystemConfigNewVersionCheckDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigNightlyTasksDto) @ValidateNested() @IsObject() nightlyTasks!: SystemConfigNightlyTasksDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigOAuthDto) @ValidateNested() @IsObject() oauth!: SystemConfigOAuthDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigPasswordLoginDto) @ValidateNested() @IsObject() passwordLogin!: SystemConfigPasswordLoginDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigReverseGeocodingDto) @ValidateNested() @IsObject() reverseGeocoding!: SystemConfigReverseGeocodingDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigMetadataDto) @ValidateNested() @IsObject() metadata!: SystemConfigMetadataDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigStorageTemplateDto) @ValidateNested() @IsObject() storageTemplate!: SystemConfigStorageTemplateDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigJobDto) @ValidateNested() @IsObject() job!: SystemConfigJobDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigImageDto) @ValidateNested() @IsObject() image!: SystemConfigImageDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigTrashDto) @ValidateNested() @IsObject() trash!: SystemConfigTrashDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigThemeDto) @ValidateNested() @IsObject() theme!: SystemConfigThemeDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigLibraryDto) @ValidateNested() @IsObject() library!: SystemConfigLibraryDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigNotificationsDto) @ValidateNested() @IsObject() notifications!: SystemConfigNotificationsDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigTemplatesDto) @ValidateNested() @IsObject() templates!: SystemConfigTemplatesDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigServerDto) @ValidateNested() @IsObject() server!: SystemConfigServerDto; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) @Type(() => SystemConfigUserDto) @ValidateNested() @IsObject() diff --git a/server/src/dtos/system-metadata.dto.ts b/server/src/dtos/system-metadata.dto.ts index 0005aee7e..0a4d55c97 100644 --- a/server/src/dtos/system-metadata.dto.ts +++ b/server/src/dtos/system-metadata.dto.ts @@ -1,21 +1,26 @@ +import { ApiProperty } from '@nestjs/swagger'; import { ValidateBoolean } from 'src/validation'; export class AdminOnboardingUpdateDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Is admin onboarded' }) isOnboarded!: boolean; } export class AdminOnboardingResponseDto { - @ValidateBoolean() + @ValidateBoolean({ description: 'Is admin onboarded' }) isOnboarded!: boolean; } export class ReverseGeocodingStateResponseDto { + @ApiProperty({ description: 'Last update timestamp' }) lastUpdate!: string | null; + @ApiProperty({ description: 'Last import file name' }) lastImportFileName!: string | null; } export class VersionCheckStateResponseDto { + @ApiProperty({ description: 'Last check timestamp' }) checkedAt!: string | null; + @ApiProperty({ description: 'Release version' }) releaseVersion!: string | null; } diff --git a/server/src/dtos/tag.dto.ts b/server/src/dtos/tag.dto.ts index a35801d07..231e6cc50 100644 --- a/server/src/dtos/tag.dto.ts +++ b/server/src/dtos/tag.dto.ts @@ -1,53 +1,64 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { IsHexColor, IsNotEmpty, IsString } from 'class-validator'; import { Tag } from 'src/database'; import { Optional, ValidateHexColor, ValidateUUID } from 'src/validation'; export class TagCreateDto { + @ApiProperty({ description: 'Tag name' }) @IsString() @IsNotEmpty() name!: string; - @ValidateUUID({ optional: true, nullable: true }) + @ValidateUUID({ optional: true, description: 'Parent tag ID' }) parentId?: string | null; + @ApiPropertyOptional({ description: 'Tag color (hex)' }) @IsHexColor() @Optional({ nullable: true, emptyToNull: true }) color?: string; } export class TagUpdateDto { - @Optional({ emptyToNull: true, nullable: true }) + @ApiPropertyOptional({ description: 'Tag color (hex)' }) + @Optional({ emptyToNull: true }) @ValidateHexColor() color?: string | null; } export class TagUpsertDto { + @ApiProperty({ description: 'Tag names to upsert' }) @IsString({ each: true }) @IsNotEmpty({ each: true }) tags!: string[]; } export class TagBulkAssetsDto { - @ValidateUUID({ each: true }) + @ValidateUUID({ each: true, description: 'Tag IDs' }) tagIds!: string[]; - @ValidateUUID({ each: true }) + @ValidateUUID({ each: true, description: 'Asset IDs' }) assetIds!: string[]; } export class TagBulkAssetsResponseDto { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of assets tagged' }) count!: number; } export class TagResponseDto { + @ApiProperty({ description: 'Tag ID' }) id!: string; + @ApiPropertyOptional({ description: 'Parent tag ID' }) parentId?: string; + @ApiProperty({ description: 'Tag name' }) name!: string; + @ApiProperty({ description: 'Tag value (full path)' }) value!: string; + @ApiProperty({ description: 'Creation date' }) createdAt!: Date; + @ApiProperty({ description: 'Last update date' }) updatedAt!: Date; + @ApiPropertyOptional({ description: 'Tag color (hex)' }) color?: string; } diff --git a/server/src/dtos/time-bucket.dto.ts b/server/src/dtos/time-bucket.dto.ts index 58772da00..dfd474d88 100644 --- a/server/src/dtos/time-bucket.dto.ts +++ b/server/src/dtos/time-bucket.dto.ts @@ -132,7 +132,7 @@ export class TimeBucketAssetResponseDto { @ApiProperty({ type: 'array', items: { type: 'string' }, - description: 'Array of file creation timestamps in UTC (ISO 8601 format, without timezone)', + description: 'Array of file creation timestamps in UTC', }) fileCreatedAt!: string[]; diff --git a/server/src/dtos/trash.dto.ts b/server/src/dtos/trash.dto.ts index d8e139bff..f1d1f109f 100644 --- a/server/src/dtos/trash.dto.ts +++ b/server/src/dtos/trash.dto.ts @@ -1,6 +1,6 @@ import { ApiProperty } from '@nestjs/swagger'; export class TrashResponseDto { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Number of items in trash' }) count!: number; } diff --git a/server/src/dtos/user-preferences.dto.ts b/server/src/dtos/user-preferences.dto.ts index 452384b42..cce199400 100644 --- a/server/src/dtos/user-preferences.dto.ts +++ b/server/src/dtos/user-preferences.dto.ts @@ -1,4 +1,4 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { ApiProperty, ApiPropertyOptional, ApiSchema } from '@nestjs/swagger'; import { Type } from 'class-transformer'; import { IsDateString, IsInt, IsPositive, ValidateNested } from 'class-validator'; import { AssetOrder, UserAvatarColor } from 'src/enum'; @@ -6,71 +6,72 @@ import { UserPreferences } from 'src/types'; import { Optional, ValidateBoolean, ValidateEnum } from 'src/validation'; class AvatarUpdate { - @ValidateEnum({ enum: UserAvatarColor, name: 'UserAvatarColor', optional: true }) + @ValidateEnum({ enum: UserAvatarColor, name: 'UserAvatarColor', optional: true, description: 'Avatar color' }) color?: UserAvatarColor; } class MemoriesUpdate { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Whether memories are enabled' }) enabled?: boolean; @Optional() @IsInt() @IsPositive() - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Memory duration in seconds' }) duration?: number; } class RatingsUpdate { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Whether ratings are enabled' }) enabled?: boolean; } +@ApiSchema({ description: 'Album preferences' }) class AlbumsUpdate { - @ValidateEnum({ enum: AssetOrder, name: 'AssetOrder', optional: true }) + @ValidateEnum({ enum: AssetOrder, name: 'AssetOrder', optional: true, description: 'Default asset order for albums' }) defaultAssetOrder?: AssetOrder; } class FoldersUpdate { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Whether folders are enabled' }) enabled?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Whether folders appear in web sidebar' }) sidebarWeb?: boolean; } class PeopleUpdate { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Whether people are enabled' }) enabled?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Whether people appear in web sidebar' }) sidebarWeb?: boolean; } class SharedLinksUpdate { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Whether shared links are enabled' }) enabled?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Whether shared links appear in web sidebar' }) sidebarWeb?: boolean; } class TagsUpdate { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Whether tags are enabled' }) enabled?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Whether tags appear in web sidebar' }) sidebarWeb?: boolean; } class EmailNotificationsUpdate { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Whether email notifications are enabled' }) enabled?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Whether to receive email notifications for album invites' }) albumInvite?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Whether to receive email notifications for album updates' }) albumUpdate?: boolean; } @@ -78,83 +79,108 @@ class DownloadUpdate implements Partial { @Optional() @IsInt() @IsPositive() - @ApiProperty({ type: 'integer' }) + @ApiPropertyOptional({ type: 'integer', description: 'Maximum archive size in bytes' }) archiveSize?: number; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Whether to include embedded videos in downloads' }) includeEmbeddedVideos?: boolean; } class PurchaseUpdate { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Whether to show support badge' }) showSupportBadge?: boolean; + @ApiPropertyOptional({ description: 'Date until which to hide buy button' }) @IsDateString() @Optional() hideBuyButtonUntil?: string; } class CastUpdate { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Whether Google Cast is enabled' }) gCastEnabled?: boolean; } export class UserPreferencesUpdateDto { + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) @Optional() @ValidateNested() @Type(() => AlbumsUpdate) albums?: AlbumsUpdate; + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) @Optional() @ValidateNested() @Type(() => FoldersUpdate) folders?: FoldersUpdate; + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) @Optional() @ValidateNested() @Type(() => MemoriesUpdate) memories?: MemoriesUpdate; + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) @Optional() @ValidateNested() @Type(() => PeopleUpdate) people?: PeopleUpdate; + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) @Optional() @ValidateNested() @Type(() => RatingsUpdate) ratings?: RatingsUpdate; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined, required: false }) @Optional() @ValidateNested() @Type(() => SharedLinksUpdate) sharedLinks?: SharedLinksUpdate; + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) @Optional() @ValidateNested() @Type(() => TagsUpdate) tags?: TagsUpdate; + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) @Optional() @ValidateNested() @Type(() => AvatarUpdate) avatar?: AvatarUpdate; + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) @Optional() @ValidateNested() @Type(() => EmailNotificationsUpdate) emailNotifications?: EmailNotificationsUpdate; + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) @Optional() @ValidateNested() @Type(() => DownloadUpdate) download?: DownloadUpdate; + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) @Optional() @ValidateNested() @Type(() => PurchaseUpdate) purchase?: PurchaseUpdate; + // Description lives on schema to avoid duplication + @ApiPropertyOptional({ description: undefined }) @Optional() @ValidateNested() @Type(() => CastUpdate) @@ -162,74 +188,113 @@ export class UserPreferencesUpdateDto { } class AlbumsResponse { - @ValidateEnum({ enum: AssetOrder, name: 'AssetOrder' }) + @ValidateEnum({ enum: AssetOrder, name: 'AssetOrder', description: 'Default asset order for albums' }) defaultAssetOrder: AssetOrder = AssetOrder.Desc; } class RatingsResponse { + @ApiProperty({ description: 'Whether ratings are enabled' }) enabled: boolean = false; } class MemoriesResponse { + @ApiProperty({ description: 'Whether memories are enabled' }) enabled: boolean = true; - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Memory duration in seconds' }) duration: number = 5; } class FoldersResponse { + @ApiProperty({ description: 'Whether folders are enabled' }) enabled: boolean = false; + @ApiProperty({ description: 'Whether folders appear in web sidebar' }) sidebarWeb: boolean = false; } class PeopleResponse { + @ApiProperty({ description: 'Whether people are enabled' }) enabled: boolean = true; + @ApiProperty({ description: 'Whether people appear in web sidebar' }) sidebarWeb: boolean = false; } class TagsResponse { + @ApiProperty({ description: 'Whether tags are enabled' }) enabled: boolean = true; + @ApiProperty({ description: 'Whether tags appear in web sidebar' }) sidebarWeb: boolean = true; } class SharedLinksResponse { + @ApiProperty({ description: 'Whether shared links are enabled' }) enabled: boolean = true; + @ApiProperty({ description: 'Whether shared links appear in web sidebar' }) sidebarWeb: boolean = false; } class EmailNotificationsResponse { + @ApiProperty({ description: 'Whether email notifications are enabled' }) enabled!: boolean; + @ApiProperty({ description: 'Whether to receive email notifications for album invites' }) albumInvite!: boolean; + @ApiProperty({ description: 'Whether to receive email notifications for album updates' }) albumUpdate!: boolean; } class DownloadResponse { - @ApiProperty({ type: 'integer' }) + @ApiProperty({ type: 'integer', description: 'Maximum archive size in bytes' }) archiveSize!: number; + @ApiProperty({ description: 'Whether to include embedded videos in downloads' }) includeEmbeddedVideos: boolean = false; } class PurchaseResponse { + @ApiProperty({ description: 'Whether to show support badge' }) showSupportBadge!: boolean; + @ApiProperty({ description: 'Date until which to hide buy button' }) hideBuyButtonUntil!: string; } class CastResponse { + @ApiProperty({ description: 'Whether Google Cast is enabled' }) gCastEnabled: boolean = false; } export class UserPreferencesResponseDto implements UserPreferences { + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) albums!: AlbumsResponse; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) folders!: FoldersResponse; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) memories!: MemoriesResponse; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) people!: PeopleResponse; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) ratings!: RatingsResponse; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) sharedLinks!: SharedLinksResponse; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) tags!: TagsResponse; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) emailNotifications!: EmailNotificationsResponse; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) download!: DownloadResponse; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) purchase!: PurchaseResponse; + // Description lives on schema to avoid duplication + @ApiProperty({ description: undefined }) cast!: CastResponse; } diff --git a/server/src/dtos/user-profile.dto.ts b/server/src/dtos/user-profile.dto.ts index 16eea373e..6559dd052 100644 --- a/server/src/dtos/user-profile.dto.ts +++ b/server/src/dtos/user-profile.dto.ts @@ -2,12 +2,15 @@ import { ApiProperty } from '@nestjs/swagger'; import { UploadFieldName } from 'src/dtos/asset-media.dto'; export class CreateProfileImageDto { - @ApiProperty({ type: 'string', format: 'binary' }) + @ApiProperty({ type: 'string', format: 'binary', description: 'Profile image file' }) [UploadFieldName.PROFILE_DATA]!: Express.Multer.File; } export class CreateProfileImageResponseDto { + @ApiProperty({ description: 'User ID' }) userId!: string; + @ApiProperty({ description: 'Profile image change date', format: 'date-time' }) profileChangedAt!: Date; + @ApiProperty({ description: 'Profile image file path' }) profileImagePath!: string; } diff --git a/server/src/dtos/user.dto.ts b/server/src/dtos/user.dto.ts index c5067f3e8..598798dc4 100644 --- a/server/src/dtos/user.dto.ts +++ b/server/src/dtos/user.dto.ts @@ -1,4 +1,4 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Transform } from 'class-transformer'; import { IsEmail, IsInt, IsNotEmpty, IsString, Min } from 'class-validator'; import { User, UserAdmin } from 'src/database'; @@ -7,39 +7,50 @@ import { UserMetadataItem } from 'src/types'; import { Optional, PinCode, ValidateBoolean, ValidateEnum, ValidateUUID, toEmail, toSanitized } from 'src/validation'; export class UserUpdateMeDto { + @ApiPropertyOptional({ description: 'User email' }) @Optional() @IsEmail({ require_tld: false }) @Transform(toEmail) email?: string; // TODO: migrate to the other change password endpoint + @ApiPropertyOptional({ description: 'User password (deprecated, use change password endpoint)' }) @Optional() @IsNotEmpty() @IsString() password?: string; + @ApiPropertyOptional({ description: 'User name' }) @Optional() @IsString() @IsNotEmpty() name?: string; - @ValidateEnum({ enum: UserAvatarColor, name: 'UserAvatarColor', optional: true, nullable: true }) + @ValidateEnum({ enum: UserAvatarColor, name: 'UserAvatarColor', optional: true, description: 'Avatar color' }) avatarColor?: UserAvatarColor | null; } export class UserResponseDto { + @ApiProperty({ description: 'User ID' }) id!: string; + @ApiProperty({ description: 'User name' }) name!: string; + @ApiProperty({ description: 'User email' }) email!: string; + @ApiProperty({ description: 'Profile image path' }) profileImagePath!: string; - @ValidateEnum({ enum: UserAvatarColor, name: 'UserAvatarColor' }) + @ValidateEnum({ enum: UserAvatarColor, name: 'UserAvatarColor', description: 'Avatar color' }) avatarColor!: UserAvatarColor; + @ApiProperty({ description: 'Profile change date' }) profileChangedAt!: Date; } export class UserLicense { + @ApiProperty({ description: 'License key' }) licenseKey!: string; + @ApiProperty({ description: 'Activation key' }) activationKey!: string; + @ApiProperty({ description: 'Activation date' }) activatedAt!: Date; } @@ -63,108 +74,125 @@ export const mapUser = (entity: User | UserAdmin): UserResponseDto => { }; export class UserAdminSearchDto { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Include deleted users' }) withDeleted?: boolean; - @ValidateUUID({ optional: true }) + @ValidateUUID({ optional: true, description: 'User ID filter' }) id?: string; } export class UserAdminCreateDto { + @ApiProperty({ description: 'User email' }) @IsEmail({ require_tld: false }) @Transform(toEmail) email!: string; + @ApiProperty({ description: 'User password' }) @IsString() password!: string; + @ApiProperty({ description: 'User name' }) @IsNotEmpty() @IsString() name!: string; - @ValidateEnum({ enum: UserAvatarColor, name: 'UserAvatarColor', optional: true, nullable: true }) + @ValidateEnum({ enum: UserAvatarColor, name: 'UserAvatarColor', optional: true, description: 'Avatar color' }) avatarColor?: UserAvatarColor | null; + @ApiPropertyOptional({ description: 'Storage label' }) @Optional({ nullable: true }) @IsString() @Transform(toSanitized) storageLabel?: string | null; + @ApiPropertyOptional({ type: 'integer', format: 'int64', description: 'Storage quota in bytes' }) @Optional({ nullable: true }) @IsInt() @Min(0) - @ApiProperty({ type: 'integer', format: 'int64' }) quotaSizeInBytes?: number | null; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Require password change on next login' }) shouldChangePassword?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Send notification email' }) notify?: boolean; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Grant admin privileges' }) isAdmin?: boolean; } export class UserAdminUpdateDto { + @ApiPropertyOptional({ description: 'User email' }) @Optional() @IsEmail({ require_tld: false }) @Transform(toEmail) email?: string; + @ApiPropertyOptional({ description: 'User password' }) @Optional() @IsNotEmpty() @IsString() password?: string; - @PinCode({ optional: true, nullable: true, emptyToNull: true }) + @ApiPropertyOptional({ description: 'PIN code' }) + @PinCode({ optional: true, emptyToNull: true }) pinCode?: string | null; + @ApiPropertyOptional({ description: 'User name' }) @Optional() @IsString() @IsNotEmpty() name?: string; - @ValidateEnum({ enum: UserAvatarColor, name: 'UserAvatarColor', optional: true, nullable: true }) + @ValidateEnum({ enum: UserAvatarColor, name: 'UserAvatarColor', optional: true, description: 'Avatar color' }) avatarColor?: UserAvatarColor | null; + @ApiPropertyOptional({ description: 'Storage label' }) @Optional({ nullable: true }) @IsString() @Transform(toSanitized) storageLabel?: string | null; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Require password change on next login' }) shouldChangePassword?: boolean; + @ApiPropertyOptional({ type: 'integer', format: 'int64', description: 'Storage quota in bytes' }) @Optional({ nullable: true }) @IsInt() @Min(0) - @ApiProperty({ type: 'integer', format: 'int64' }) quotaSizeInBytes?: number | null; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Grant admin privileges' }) isAdmin?: boolean; } export class UserAdminDeleteDto { - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Force delete even if user has assets' }) force?: boolean; } export class UserAdminResponseDto extends UserResponseDto { + @ApiProperty({ description: 'Storage label' }) storageLabel!: string | null; + @ApiProperty({ description: 'Require password change on next login' }) shouldChangePassword!: boolean; + @ApiProperty({ description: 'Is admin user' }) isAdmin!: boolean; + @ApiProperty({ description: 'Creation date' }) createdAt!: Date; + @ApiProperty({ description: 'Deletion date' }) deletedAt!: Date | null; + @ApiProperty({ description: 'Last update date' }) updatedAt!: Date; + @ApiProperty({ description: 'OAuth ID' }) oauthId!: string; - @ApiProperty({ type: 'integer', format: 'int64' }) + @ApiProperty({ type: 'integer', format: 'int64', description: 'Storage quota in bytes' }) quotaSizeInBytes!: number | null; - @ApiProperty({ type: 'integer', format: 'int64' }) + @ApiProperty({ type: 'integer', format: 'int64', description: 'Storage usage in bytes' }) quotaUsageInBytes!: number | null; - @ValidateEnum({ enum: UserStatus, name: 'UserStatus' }) + @ValidateEnum({ enum: UserStatus, name: 'UserStatus', description: 'User status' }) status!: string; + @ApiProperty({ description: 'User license' }) license!: UserLicense | null; } diff --git a/server/src/dtos/workflow.dto.ts b/server/src/dtos/workflow.dto.ts index 2dbff3b5e..c4e5ac9c4 100644 --- a/server/src/dtos/workflow.dto.ts +++ b/server/src/dtos/workflow.dto.ts @@ -1,3 +1,4 @@ +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; import { IsNotEmpty, IsObject, IsString, IsUUID, ValidateNested } from 'class-validator'; import { WorkflowAction, WorkflowFilter } from 'src/database'; @@ -6,68 +7,85 @@ import type { ActionConfig, FilterConfig } from 'src/types/plugin-schema.types'; import { Optional, ValidateBoolean, ValidateEnum } from 'src/validation'; export class WorkflowFilterItemDto { + @ApiProperty({ description: 'Plugin filter ID' }) @IsUUID() pluginFilterId!: string; + @ApiPropertyOptional({ description: 'Filter configuration' }) @IsObject() @Optional() filterConfig?: FilterConfig; } export class WorkflowActionItemDto { + @ApiProperty({ description: 'Plugin action ID' }) @IsUUID() pluginActionId!: string; + @ApiPropertyOptional({ description: 'Action configuration' }) @IsObject() @Optional() actionConfig?: ActionConfig; } export class WorkflowCreateDto { - @ValidateEnum({ enum: PluginTriggerType, name: 'PluginTriggerType' }) + @ValidateEnum({ enum: PluginTriggerType, name: 'PluginTriggerType', description: 'Workflow trigger type' }) triggerType!: PluginTriggerType; + @ApiProperty({ description: 'Workflow name' }) @IsString() @IsNotEmpty() name!: string; + @ApiPropertyOptional({ description: 'Workflow description' }) @IsString() @Optional() description?: string; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Workflow enabled' }) enabled?: boolean; + @ApiProperty({ description: 'Workflow filters' }) @ValidateNested({ each: true }) @Type(() => WorkflowFilterItemDto) filters!: WorkflowFilterItemDto[]; + @ApiProperty({ description: 'Workflow actions' }) @ValidateNested({ each: true }) @Type(() => WorkflowActionItemDto) actions!: WorkflowActionItemDto[]; } export class WorkflowUpdateDto { - @ValidateEnum({ enum: PluginTriggerType, name: 'PluginTriggerType', optional: true }) + @ValidateEnum({ + enum: PluginTriggerType, + name: 'PluginTriggerType', + optional: true, + description: 'Workflow trigger type', + }) triggerType?: PluginTriggerType; + @ApiPropertyOptional({ description: 'Workflow name' }) @IsString() @IsNotEmpty() @Optional() name?: string; + @ApiPropertyOptional({ description: 'Workflow description' }) @IsString() @Optional() description?: string; - @ValidateBoolean({ optional: true }) + @ValidateBoolean({ optional: true, description: 'Workflow enabled' }) enabled?: boolean; + @ApiPropertyOptional({ description: 'Workflow filters' }) @ValidateNested({ each: true }) @Type(() => WorkflowFilterItemDto) @Optional() filters?: WorkflowFilterItemDto[]; + @ApiPropertyOptional({ description: 'Workflow actions' }) @ValidateNested({ each: true }) @Type(() => WorkflowActionItemDto) @Optional() @@ -75,31 +93,49 @@ export class WorkflowUpdateDto { } export class WorkflowResponseDto { + @ApiProperty({ description: 'Workflow ID' }) id!: string; + @ApiProperty({ description: 'Owner user ID' }) ownerId!: string; - @ValidateEnum({ enum: PluginTriggerType, name: 'PluginTriggerType' }) + @ValidateEnum({ enum: PluginTriggerType, name: 'PluginTriggerType', description: 'Workflow trigger type' }) triggerType!: PluginTriggerType; + @ApiProperty({ description: 'Workflow name' }) name!: string | null; + @ApiProperty({ description: 'Workflow description' }) description!: string; + @ApiProperty({ description: 'Creation date' }) createdAt!: string; + @ApiProperty({ description: 'Workflow enabled' }) enabled!: boolean; + @ApiProperty({ description: 'Workflow filters' }) filters!: WorkflowFilterResponseDto[]; + @ApiProperty({ description: 'Workflow actions' }) actions!: WorkflowActionResponseDto[]; } export class WorkflowFilterResponseDto { + @ApiProperty({ description: 'Filter ID' }) id!: string; + @ApiProperty({ description: 'Workflow ID' }) workflowId!: string; + @ApiProperty({ description: 'Plugin filter ID' }) pluginFilterId!: string; + @ApiProperty({ description: 'Filter configuration' }) filterConfig!: FilterConfig | null; + @ApiProperty({ description: 'Filter order', type: 'number' }) order!: number; } export class WorkflowActionResponseDto { + @ApiProperty({ description: 'Action ID' }) id!: string; + @ApiProperty({ description: 'Workflow ID' }) workflowId!: string; + @ApiProperty({ description: 'Plugin action ID' }) pluginActionId!: string; + @ApiProperty({ description: 'Action configuration' }) actionConfig!: ActionConfig | null; + @ApiProperty({ description: 'Action order', type: 'number' }) order!: number; } diff --git a/server/src/validation.ts b/server/src/validation.ts index 0a53e09ca..724c01ffe 100644 --- a/server/src/validation.ts +++ b/server/src/validation.ts @@ -33,6 +33,7 @@ import { import { CronJob } from 'cron'; import { DateTime } from 'luxon'; import sanitize from 'sanitize-filename'; +import { Property, PropertyOptions } from 'src/decorators'; import { isIP, isIPRange } from 'validator'; @Injectable() @@ -66,7 +67,7 @@ export class FileNotEmptyValidator extends FileValidator { } type UUIDOptions = { optional?: boolean; each?: boolean; nullable?: boolean }; -export const ValidateUUID = (options?: UUIDOptions & ApiPropertyOptions) => { +export const ValidateUUID = (options?: UUIDOptions & PropertyOptions) => { const { optional, each, nullable, ...apiPropertyOptions } = { optional: false, each: false, @@ -75,7 +76,7 @@ export const ValidateUUID = (options?: UUIDOptions & ApiPropertyOptions) => { }; return applyDecorators( IsUUID('4', { each }), - ApiProperty({ format: 'uuid', ...apiPropertyOptions }), + Property({ format: 'uuid', ...apiPropertyOptions }), optional ? Optional({ nullable }) : IsNotEmpty(), each ? IsArray() : IsString(), ); @@ -277,10 +278,10 @@ export const ValidateString = (options?: StringOptions & ApiPropertyOptions) => }; type BooleanOptions = { optional?: boolean; nullable?: boolean }; -export const ValidateBoolean = (options?: BooleanOptions & ApiPropertyOptions) => { +export const ValidateBoolean = (options?: BooleanOptions & PropertyOptions) => { const { optional, nullable, ...apiPropertyOptions } = options || {}; const decorators = [ - ApiProperty(apiPropertyOptions), + Property(apiPropertyOptions), IsBoolean(), Transform(({ value }) => { if (value == 'true') {