mirror of
https://github.com/immich-app/immich.git
synced 2026-09-30 13:23:21 +08:00
chore(deps): update dependency eslint-plugin-unicorn to v73 (#30844)
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
This commit is contained in:
co-authored by
Daniel Dietzler
parent
225ca9ab8d
commit
11755e5a53
+1
-1
@@ -40,7 +40,7 @@
|
||||
"eslint": "^10.0.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^72.0.0",
|
||||
"eslint-plugin-unicorn": "^73.0.0",
|
||||
"exiftool-vendored": "^35.0.0",
|
||||
"globals": "^17.0.0",
|
||||
"luxon": "^3.4.4",
|
||||
|
||||
@@ -29,7 +29,9 @@ describe('/users', () => {
|
||||
});
|
||||
|
||||
describe('PUT /users/me', () => {
|
||||
/** @deprecated */
|
||||
/**
|
||||
@deprecated
|
||||
*/
|
||||
it('should allow a user to change their password (deprecated)', async () => {
|
||||
const user = await getMyUser({ headers: asBearerAuth(nonAdmin.accessToken) });
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
"eslint": "^10.0.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^72.0.0",
|
||||
"eslint-plugin-unicorn": "^73.0.0",
|
||||
"globals": "^17.0.0",
|
||||
"mock-fs": "^5.2.0",
|
||||
"prettier": "^3.7.4",
|
||||
|
||||
Generated
+11
-11
@@ -157,8 +157,8 @@ importers:
|
||||
specifier: ^5.1.3
|
||||
version: 5.5.6(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1)))(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))(prettier@3.9.6)
|
||||
eslint-plugin-unicorn:
|
||||
specifier: ^72.0.0
|
||||
version: 72.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
|
||||
specifier: ^73.0.0
|
||||
version: 73.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
|
||||
exiftool-vendored:
|
||||
specifier: ^35.0.0
|
||||
version: 35.21.0
|
||||
@@ -269,8 +269,8 @@ importers:
|
||||
specifier: ^5.1.3
|
||||
version: 5.5.6(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1)))(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))(prettier@3.9.6)
|
||||
eslint-plugin-unicorn:
|
||||
specifier: ^72.0.0
|
||||
version: 72.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
|
||||
specifier: ^73.0.0
|
||||
version: 73.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
|
||||
globals:
|
||||
specifier: ^17.0.0
|
||||
version: 17.9.0
|
||||
@@ -741,8 +741,8 @@ importers:
|
||||
specifier: ^5.1.3
|
||||
version: 5.5.6(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1)))(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))(prettier@3.9.6)
|
||||
eslint-plugin-unicorn:
|
||||
specifier: ^72.0.0
|
||||
version: 72.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
|
||||
specifier: ^73.0.0
|
||||
version: 73.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
|
||||
globals:
|
||||
specifier: ^17.0.0
|
||||
version: 17.9.0
|
||||
@@ -1006,8 +1006,8 @@ importers:
|
||||
specifier: ^3.12.4
|
||||
version: 3.22.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))(svelte@5.56.8(@typescript-eslint/types@8.66.0))
|
||||
eslint-plugin-unicorn:
|
||||
specifier: ^72.0.0
|
||||
version: 72.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
|
||||
specifier: ^73.0.0
|
||||
version: 73.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
|
||||
factory.ts:
|
||||
specifier: ^1.4.1
|
||||
version: 1.4.2
|
||||
@@ -7582,8 +7582,8 @@ packages:
|
||||
svelte:
|
||||
optional: true
|
||||
|
||||
eslint-plugin-unicorn@72.0.0:
|
||||
resolution: {integrity: sha512-hqO6ksoOHO+ZhdseTuKRVQbx9U7PRO/cv8qAR1mctwzdVO2hYud8uS9luAhp43RJgziYgHAph8eHyipT8GL0ng==}
|
||||
eslint-plugin-unicorn@73.0.0:
|
||||
resolution: {integrity: sha512-V0YatLe9nkGhXEXKe2Qljb1EY0sJHwDV0HUF1NKFwtsHh/fU7qGHDgv+6fchzZcgU2/7noHo2gdjnmo0P2uDPw==}
|
||||
engines: {node: '>=22'}
|
||||
peerDependencies:
|
||||
eslint: '>=10.4'
|
||||
@@ -20606,7 +20606,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- ts-node
|
||||
|
||||
eslint-plugin-unicorn@72.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1)):
|
||||
eslint-plugin-unicorn@73.0.0(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1)):
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.10.1(eslint@10.8.0(jiti@2.7.0)(supports-color@8.1.1))
|
||||
'@eslint/css-tree': 4.0.5
|
||||
|
||||
+1
-1
@@ -151,7 +151,7 @@
|
||||
"eslint": "^10.0.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^72.0.0",
|
||||
"eslint-plugin-unicorn": "^73.0.0",
|
||||
"globals": "^17.0.0",
|
||||
"mock-fs": "^5.2.0",
|
||||
"pngjs": "^7.0.0",
|
||||
|
||||
@@ -7,7 +7,9 @@ import request from 'supertest';
|
||||
import { errorDto } from 'test/medium/responses';
|
||||
import { ControllerContext, controllerSetup, mockBaseService } from 'test/utils';
|
||||
|
||||
/** Returns a full config that passes Zod validation (required URLs and min lengths). */
|
||||
/**
|
||||
Returns a full config that passes Zod validation (required URLs and min lengths).
|
||||
*/
|
||||
function validConfig() {
|
||||
const config = _.cloneDeep(defaults) as typeof defaults & {
|
||||
oauth: { mobileRedirectUri: string };
|
||||
|
||||
@@ -136,16 +136,24 @@ export interface GenerateSqlQueries {
|
||||
export const Telemetry = (options: { enabled?: boolean }) =>
|
||||
SetMetadata(MetadataKey.TelemetryEnabled, options?.enabled ?? true);
|
||||
|
||||
/** Decorator to enable versioning/tracking of generated Sql */
|
||||
/**
|
||||
Decorator to enable versioning/tracking of generated Sql
|
||||
*/
|
||||
export const GenerateSql = (...options: GenerateSqlQueries[]) => SetMetadata(GENERATE_SQL_KEY, options);
|
||||
|
||||
export type EventConfig = {
|
||||
name: EmitEvent;
|
||||
/** handle socket.io server events as well */
|
||||
/**
|
||||
handle socket.io server events as well
|
||||
*/
|
||||
server?: boolean;
|
||||
/** lower value has higher priority, defaults to 0 */
|
||||
/**
|
||||
lower value has higher priority, defaults to 0
|
||||
*/
|
||||
priority?: number;
|
||||
/** register events for these workers, defaults to all workers */
|
||||
/**
|
||||
register events for these workers, defaults to all workers
|
||||
*/
|
||||
workers?: ImmichWorker[];
|
||||
};
|
||||
export const OnEvent = (config: EventConfig) => SetMetadata(MetadataKey.EventConfig, config);
|
||||
@@ -183,7 +191,9 @@ type HistoryEntry = {
|
||||
};
|
||||
|
||||
type DeprecatedOptions = {
|
||||
/** replacement operationId */
|
||||
/**
|
||||
replacement operationId
|
||||
*/
|
||||
replacementId?: string;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { createZodDto } from 'nestjs-zod';
|
||||
import z from 'zod';
|
||||
|
||||
/** @deprecated Use `BulkIdResponseDto` instead */
|
||||
/**
|
||||
@deprecated Use `BulkIdResponseDto` instead
|
||||
*/
|
||||
export enum AssetIdErrorReason {
|
||||
DUPLICATE = 'duplicate',
|
||||
NO_PERMISSION = 'no_permission',
|
||||
@@ -13,7 +15,9 @@ const AssetIdErrorReasonSchema = z
|
||||
.describe('Error reason if failed')
|
||||
.meta({ id: 'AssetIdErrorReason' });
|
||||
|
||||
/** @deprecated Use `BulkIdResponseDto` instead */
|
||||
/**
|
||||
@deprecated Use `BulkIdResponseDto` instead
|
||||
*/
|
||||
const AssetIdsResponseSchema = z
|
||||
.object({
|
||||
assetId: z.uuidv4().describe('Asset ID'),
|
||||
@@ -50,7 +54,9 @@ const BulkIdResponseSchema = z
|
||||
})
|
||||
.meta({ id: 'BulkIdResponseDto' });
|
||||
|
||||
/** @deprecated Use `BulkIdResponseDto` instead */
|
||||
/**
|
||||
@deprecated Use `BulkIdResponseDto` instead
|
||||
*/
|
||||
export class AssetIdsResponseDto extends createZodDto(AssetIdsResponseSchema) {}
|
||||
export class BulkIdsDto extends createZodDto(BulkIdsSchema) {}
|
||||
export class BulkIdResponseDto extends createZodDto(BulkIdResponseSchema) {}
|
||||
|
||||
@@ -40,7 +40,9 @@ const AssetMediaBaseSchema = z.object({
|
||||
fileModifiedAt: isoDatetimeToDate.describe('File modification date'),
|
||||
duration: z.coerce.number().int().min(0).optional().describe('Duration in milliseconds (for videos)'),
|
||||
filename: z.string().optional().describe('Filename'),
|
||||
/** The properties below are added to correctly generate the API docs and client SDKs. Validation should be handled in the controller. */
|
||||
/**
|
||||
The properties below are added to correctly generate the API docs and client SDKs. Validation should be handled in the controller.
|
||||
*/
|
||||
[UploadFieldName.ASSET_DATA]: z.any().describe('Asset file data').meta({ type: 'string', format: 'binary' }),
|
||||
});
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ import {
|
||||
} from 'src/enum';
|
||||
import z from 'zod';
|
||||
|
||||
/** Coerces 'true'/'false' strings to boolean, but also allows booleans. */
|
||||
/**
|
||||
Coerces 'true'/'false' strings to boolean, but also allows booleans.
|
||||
*/
|
||||
const configBool = z
|
||||
.preprocess((val) => {
|
||||
if (val === 'true') {
|
||||
|
||||
+78
-26
@@ -45,9 +45,13 @@ export enum AssetType {
|
||||
export const AssetTypeSchema = z.enum(AssetType).describe('Asset type').meta({ id: 'AssetTypeEnum' });
|
||||
|
||||
export enum ChecksumAlgorithm {
|
||||
/** sha1 checksum of the whole file contents */
|
||||
/**
|
||||
sha1 checksum of the whole file contents
|
||||
*/
|
||||
sha1File = 'sha1',
|
||||
/** sha1 checksum of "path:" plus the file path, currently used in external libraries, deprecated */
|
||||
/**
|
||||
sha1 checksum of "path:" plus the file path, currently used in external libraries, deprecated
|
||||
*/
|
||||
sha1Path = 'sha1-path',
|
||||
}
|
||||
|
||||
@@ -85,7 +89,9 @@ export enum AssetOrderBy {
|
||||
export const AssetOrderBySchema = z.enum(AssetOrderBy).describe('Asset sorting property').meta({ id: 'AssetOrderBy' });
|
||||
|
||||
export enum MemoryType {
|
||||
/** pictures taken on this day X years ago */
|
||||
/**
|
||||
pictures taken on this day X years ago
|
||||
*/
|
||||
OnThisDay = 'on_this_day',
|
||||
}
|
||||
|
||||
@@ -95,7 +101,9 @@ export enum AssetOrderWithRandom {
|
||||
// Include existing values
|
||||
Asc = AssetOrder.Asc,
|
||||
Desc = AssetOrder.Desc,
|
||||
/** Randomly Ordered */
|
||||
/**
|
||||
Randomly Ordered
|
||||
*/
|
||||
Random = 'random',
|
||||
}
|
||||
|
||||
@@ -642,7 +650,9 @@ export enum ExifOrientation {
|
||||
Rotate270CW = 8,
|
||||
}
|
||||
|
||||
/** ITU-T H.273 colour primaries codes. */
|
||||
/**
|
||||
ITU-T H.273 colour primaries codes.
|
||||
*/
|
||||
export enum ColorPrimaries {
|
||||
Reserved = 0,
|
||||
Bt709 = 1,
|
||||
@@ -659,7 +669,9 @@ export enum ColorPrimaries {
|
||||
Ebu3213 = 22,
|
||||
}
|
||||
|
||||
/** ITU-T H.273 transfer characteristics codes. */
|
||||
/**
|
||||
ITU-T H.273 transfer characteristics codes.
|
||||
*/
|
||||
export enum ColorTransfer {
|
||||
Reserved = 0,
|
||||
Bt709 = 1,
|
||||
@@ -681,7 +693,9 @@ export enum ColorTransfer {
|
||||
AribStdB67 = 18,
|
||||
}
|
||||
|
||||
/** ITU-T H.273 matrix coefficients codes. */
|
||||
/**
|
||||
ITU-T H.273 matrix coefficients codes.
|
||||
*/
|
||||
export enum ColorMatrix {
|
||||
Gbr = 0,
|
||||
Bt709 = 1,
|
||||
@@ -700,7 +714,9 @@ export enum ColorMatrix {
|
||||
Ictcp = 14,
|
||||
}
|
||||
|
||||
/** H.264 `profile_idc` values. */
|
||||
/**
|
||||
H.264 `profile_idc` values.
|
||||
*/
|
||||
// H.264 has a few profiles that have the same value but different names, included so lookup by name works
|
||||
export enum H264Profile {
|
||||
ConstrainedBaseline = 66,
|
||||
@@ -718,7 +734,9 @@ export enum H264Profile {
|
||||
High444Predictive = 244,
|
||||
}
|
||||
|
||||
/** HEVC `profile_idc` values. */
|
||||
/**
|
||||
HEVC `profile_idc` values.
|
||||
*/
|
||||
export enum HevcProfile {
|
||||
Main = 1,
|
||||
Main10 = 2,
|
||||
@@ -726,14 +744,18 @@ export enum HevcProfile {
|
||||
Rext = 4,
|
||||
}
|
||||
|
||||
/** AV1 `seq_profile` values. */
|
||||
/**
|
||||
AV1 `seq_profile` values.
|
||||
*/
|
||||
export enum Av1Profile {
|
||||
Main = 0,
|
||||
High = 1,
|
||||
Professional = 2,
|
||||
}
|
||||
|
||||
/** MPEG-4 Audio Object Type values for AAC. */
|
||||
/**
|
||||
MPEG-4 Audio Object Type values for AAC.
|
||||
*/
|
||||
export enum AacProfile {
|
||||
Main = 1,
|
||||
Lc = 2,
|
||||
@@ -746,7 +768,9 @@ export enum AacProfile {
|
||||
XheAac = 42,
|
||||
}
|
||||
|
||||
/** Dolby Vision bitstream profile numbers from the DOVI configuration record. */
|
||||
/**
|
||||
Dolby Vision bitstream profile numbers from the DOVI configuration record.
|
||||
*/
|
||||
export enum DvProfile {
|
||||
Dvhe03 = 3,
|
||||
Dvhe04 = 4,
|
||||
@@ -922,13 +946,21 @@ export const JobNameSchema = z.enum(JobName).describe('Job name').meta({ id: 'Jo
|
||||
|
||||
export enum QueueCommand {
|
||||
Start = 'start',
|
||||
/** @deprecated Use `updateQueue` instead */
|
||||
/**
|
||||
@deprecated Use `updateQueue` instead
|
||||
*/
|
||||
Pause = 'pause',
|
||||
/** @deprecated Use `updateQueue` instead */
|
||||
/**
|
||||
@deprecated Use `updateQueue` instead
|
||||
*/
|
||||
Resume = 'resume',
|
||||
/** @deprecated Use `emptyQueue` instead */
|
||||
/**
|
||||
@deprecated Use `emptyQueue` instead
|
||||
*/
|
||||
Empty = 'empty',
|
||||
/** @deprecated Use `emptyQueue` instead */
|
||||
/**
|
||||
@deprecated Use `emptyQueue` instead
|
||||
*/
|
||||
ClearFailed = 'clear-failed',
|
||||
}
|
||||
|
||||
@@ -993,11 +1025,15 @@ export enum SyncRequestType {
|
||||
AlbumsV2 = 'AlbumsV2',
|
||||
AlbumUsersV1 = 'AlbumUsersV1',
|
||||
AlbumToAssetsV1 = 'AlbumToAssetsV1',
|
||||
/** @deprecated */
|
||||
/**
|
||||
@deprecated
|
||||
*/
|
||||
AlbumAssetsV1 = 'AlbumAssetsV1',
|
||||
AlbumAssetsV2 = 'AlbumAssetsV2',
|
||||
AlbumAssetExifsV1 = 'AlbumAssetExifsV1',
|
||||
/** @deprecated */
|
||||
/**
|
||||
@deprecated
|
||||
*/
|
||||
AssetsV1 = 'AssetsV1',
|
||||
AssetsV2 = 'AssetsV2',
|
||||
AssetExifsV1 = 'AssetExifsV1',
|
||||
@@ -1008,7 +1044,9 @@ export enum SyncRequestType {
|
||||
MemoriesV1 = 'MemoriesV1',
|
||||
MemoryToAssetsV1 = 'MemoryToAssetsV1',
|
||||
PartnersV1 = 'PartnersV1',
|
||||
/** @deprecated */
|
||||
/**
|
||||
@deprecated
|
||||
*/
|
||||
PartnerAssetsV1 = 'PartnerAssetsV1',
|
||||
PartnerAssetsV2 = 'PartnerAssetsV2',
|
||||
PartnerAssetExifsV1 = 'PartnerAssetExifsV1',
|
||||
@@ -1016,7 +1054,9 @@ export enum SyncRequestType {
|
||||
StacksV1 = 'StacksV1',
|
||||
UsersV1 = 'UsersV1',
|
||||
PeopleV1 = 'PeopleV1',
|
||||
/** @deprecated */
|
||||
/**
|
||||
@deprecated
|
||||
*/
|
||||
AssetFacesV1 = 'AssetFacesV1',
|
||||
AssetFacesV2 = 'AssetFacesV2',
|
||||
UserMetadataV1 = 'UserMetadataV1',
|
||||
@@ -1033,7 +1073,9 @@ export enum SyncEntityType {
|
||||
UserV1 = 'UserV1',
|
||||
UserDeleteV1 = 'UserDeleteV1',
|
||||
|
||||
/** @deprecated */
|
||||
/**
|
||||
@deprecated
|
||||
*/
|
||||
AssetV1 = 'AssetV1',
|
||||
AssetV2 = 'AssetV2',
|
||||
AssetDeleteV1 = 'AssetDeleteV1',
|
||||
@@ -1048,10 +1090,14 @@ export enum SyncEntityType {
|
||||
PartnerV1 = 'PartnerV1',
|
||||
PartnerDeleteV1 = 'PartnerDeleteV1',
|
||||
|
||||
/** @deprecated */
|
||||
/**
|
||||
@deprecated
|
||||
*/
|
||||
PartnerAssetV1 = 'PartnerAssetV1',
|
||||
PartnerAssetV2 = 'PartnerAssetV2',
|
||||
/** @deprecated */
|
||||
/**
|
||||
@deprecated
|
||||
*/
|
||||
PartnerAssetBackfillV1 = 'PartnerAssetBackfillV1',
|
||||
PartnerAssetBackfillV2 = 'PartnerAssetBackfillV2',
|
||||
PartnerAssetDeleteV1 = 'PartnerAssetDeleteV1',
|
||||
@@ -1069,13 +1115,19 @@ export enum SyncEntityType {
|
||||
AlbumUserBackfillV1 = 'AlbumUserBackfillV1',
|
||||
AlbumUserDeleteV1 = 'AlbumUserDeleteV1',
|
||||
|
||||
/** @deprecated */
|
||||
/**
|
||||
@deprecated
|
||||
*/
|
||||
AlbumAssetCreateV1 = 'AlbumAssetCreateV1',
|
||||
AlbumAssetCreateV2 = 'AlbumAssetCreateV2',
|
||||
/** @deprecated */
|
||||
/**
|
||||
@deprecated
|
||||
*/
|
||||
AlbumAssetUpdateV1 = 'AlbumAssetUpdateV1',
|
||||
AlbumAssetUpdateV2 = 'AlbumAssetUpdateV2',
|
||||
/** @deprecated */
|
||||
/**
|
||||
@deprecated
|
||||
*/
|
||||
AlbumAssetBackfillV1 = 'AlbumAssetBackfillV1',
|
||||
AlbumAssetBackfillV2 = 'AlbumAssetBackfillV2',
|
||||
AlbumAssetExifCreateV1 = 'AlbumAssetExifCreateV1',
|
||||
|
||||
@@ -25,7 +25,9 @@ export type AuthenticatedOptions = AuthorizedRoute | PublicRoute;
|
||||
|
||||
type ReflectorTarget = Parameters<Reflector['get']>[1];
|
||||
|
||||
/** Resolves the `@Authenticated()` options of a route handler, with the defaults applied. */
|
||||
/**
|
||||
Resolves the `@Authenticated()` options of a route handler, with the defaults applied.
|
||||
*/
|
||||
export const getAuthenticatedOptions = (reflector: Reflector, target: ReflectorTarget) => {
|
||||
const options = reflector.getAllAndOverride<AuthenticatedOptions | undefined>(MetadataKey.AuthRoute, [target]);
|
||||
return options && { sharedLink: false, admin: false, public: false, setup: false, ...options };
|
||||
|
||||
@@ -56,15 +56,25 @@ type EventMap = {
|
||||
AssetDeleteAll: [{ assetIds: string[]; userId: string }];
|
||||
AssetRestoreAll: [{ assetIds: string[]; userId: string }];
|
||||
|
||||
/** a worker receives a job and emits this event to run it */
|
||||
/**
|
||||
a worker receives a job and emits this event to run it
|
||||
*/
|
||||
JobRun: [QueueName, JobItem];
|
||||
/** job pre-hook */
|
||||
/**
|
||||
job pre-hook
|
||||
*/
|
||||
JobStart: [QueueName, JobItem];
|
||||
/** job post-hook */
|
||||
/**
|
||||
job post-hook
|
||||
*/
|
||||
JobComplete: [QueueName, JobItem];
|
||||
/** job finishes without error */
|
||||
/**
|
||||
job finishes without error
|
||||
*/
|
||||
JobSuccess: [JobSuccessEvent];
|
||||
/** job finishes with error */
|
||||
/**
|
||||
job finishes with error
|
||||
*/
|
||||
JobError: [JobErrorEvent];
|
||||
|
||||
// queue events
|
||||
@@ -84,9 +94,13 @@ type EventMap = {
|
||||
// user events
|
||||
UserSignup: [{ notify: boolean; id: string; password?: string }];
|
||||
UserCreate: [UserEvent];
|
||||
/** user is soft deleted */
|
||||
/**
|
||||
user is soft deleted
|
||||
*/
|
||||
UserTrash: [UserEvent];
|
||||
/** user is permanently deleted */
|
||||
/**
|
||||
user is permanently deleted
|
||||
*/
|
||||
UserDelete: [UserEvent];
|
||||
UserRestore: [UserEvent];
|
||||
|
||||
|
||||
@@ -287,7 +287,9 @@ export class JobRepository {
|
||||
return this.moduleRef.get<Queue>(getQueueToken(queue), { strict: false });
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
/**
|
||||
@deprecated
|
||||
*/
|
||||
// todo: remove this when asset notifications no longer need it.
|
||||
public async removeJob(name: JobName, jobID: string): Promise<void> {
|
||||
const existingJob = await this.getQueue(this.getQueueName(name)).getJob(jobID);
|
||||
|
||||
@@ -464,7 +464,9 @@ export class MediaRepository {
|
||||
return value ? ((enumObj[pascalCase(value)] as Extract<E[keyof E], number> | undefined) ?? null) : null;
|
||||
}
|
||||
|
||||
/** Parse a rational like "60000/1001" or "1/600" into `{ num, den }`. */
|
||||
/**
|
||||
Parse a rational like "60000/1001" or "1/600" into `{ num, den }`.
|
||||
*/
|
||||
private parseRational(value: string | undefined): { num: number; den: number } | null {
|
||||
if (value) {
|
||||
const [num, den = 1] = value.split('/').map(Number);
|
||||
|
||||
@@ -135,7 +135,9 @@ export type AssetSearchBuilderOptions = Omit<AssetSearchOptions, 'orderDirection
|
||||
|
||||
export interface AssetSearchBuilderV3Options {
|
||||
filter?: SearchFilter;
|
||||
/** Server-derived ownership scope. Never client-controlled. */
|
||||
/**
|
||||
Server-derived ownership scope. Never client-controlled.
|
||||
*/
|
||||
userIds?: string[];
|
||||
withExif?: boolean;
|
||||
withFaces?: boolean;
|
||||
|
||||
@@ -45,15 +45,21 @@ export class MemoryTable {
|
||||
@Column({ type: 'jsonb' })
|
||||
data!: Record<string, unknown>;
|
||||
|
||||
/** unless set to true, will be automatically deleted in the future */
|
||||
/**
|
||||
unless set to true, will be automatically deleted in the future
|
||||
*/
|
||||
@Column({ type: 'boolean', default: false })
|
||||
isSaved!: Generated<boolean>;
|
||||
|
||||
/** memories are sorted in ascending order by this value */
|
||||
/**
|
||||
memories are sorted in ascending order by this value
|
||||
*/
|
||||
@Column({ type: 'timestamp with time zone' })
|
||||
memoryAt!: Timestamp;
|
||||
|
||||
/** when the user last viewed the memory */
|
||||
/**
|
||||
when the user last viewed the memory
|
||||
*/
|
||||
@Column({ type: 'timestamp with time zone', nullable: true })
|
||||
seenAt!: Timestamp | null;
|
||||
|
||||
|
||||
@@ -48,7 +48,9 @@ export type ValidateRequest = {
|
||||
metadata: {
|
||||
sharedLinkRoute: boolean;
|
||||
adminRoute: boolean;
|
||||
/** `false` explicitly means no permission is required, which otherwise defaults to `all` */
|
||||
/**
|
||||
`false` explicitly means no permission is required, which otherwise defaults to `all`
|
||||
*/
|
||||
permission?: Permission | false;
|
||||
uri: string;
|
||||
};
|
||||
|
||||
@@ -42,7 +42,9 @@ import { Tasks } from 'src/utils/tasks';
|
||||
const POSTGRES_INT_MAX = 2_147_483_647;
|
||||
const POSTGRES_INT_MIN = -2_147_483_648;
|
||||
|
||||
/** look for a date from these tags (in order) */
|
||||
/**
|
||||
look for a date from these tags (in order)
|
||||
*/
|
||||
const EXIF_DATE_TAGS: Array<keyof ImmichTags> = [
|
||||
'SubSecDateTimeOriginal',
|
||||
'SubSecCreateDate',
|
||||
|
||||
+30
-10
@@ -105,19 +105,33 @@ export interface AudioStreamInfo {
|
||||
bitrate: number;
|
||||
}
|
||||
|
||||
/** Packet-derived video data needed for accurate HLS playlists. */
|
||||
/**
|
||||
Packet-derived video data needed for accurate HLS playlists.
|
||||
*/
|
||||
export interface VideoPacketInfo {
|
||||
/** Sum of source packet duration across all packets (includes discard). */
|
||||
/**
|
||||
Sum of source packet duration across all packets (includes discard).
|
||||
*/
|
||||
totalDuration: number;
|
||||
/** Post-discard packet count. */
|
||||
/**
|
||||
Post-discard packet count.
|
||||
*/
|
||||
packetCount: number;
|
||||
/** Output CFR frame count at `packetCount / format.duration`. */
|
||||
/**
|
||||
Output CFR frame count at `packetCount / format.duration`.
|
||||
*/
|
||||
outputFrames: number;
|
||||
/** All keyframe PTS in source ticks, including pre-roll discard keyframes. */
|
||||
/**
|
||||
All keyframe PTS in source ticks, including pre-roll discard keyframes.
|
||||
*/
|
||||
keyframePts: number[];
|
||||
/** Cumulative packet duration through each keyframe, inclusive. */
|
||||
/**
|
||||
Cumulative packet duration through each keyframe, inclusive.
|
||||
*/
|
||||
keyframeAccDuration: number[];
|
||||
/** Each keyframe's own packet duration (needed for VFR). */
|
||||
/**
|
||||
Each keyframe's own packet duration (needed for VFR).
|
||||
*/
|
||||
keyframeOwnDuration: number[];
|
||||
}
|
||||
|
||||
@@ -210,7 +224,9 @@ export interface IBaseJob {
|
||||
}
|
||||
|
||||
export interface IDelayedJob extends IBaseJob {
|
||||
/** The minimum time to wait to execute this job, in milliseconds. */
|
||||
/**
|
||||
The minimum time to wait to execute this job, in milliseconds.
|
||||
*/
|
||||
delay?: number;
|
||||
}
|
||||
|
||||
@@ -452,7 +468,9 @@ export interface ExtensionVersion {
|
||||
|
||||
export interface ImmichFile extends Express.Multer.File {
|
||||
uuid: string;
|
||||
/** sha1 hash of file */
|
||||
/**
|
||||
sha1 hash of file
|
||||
*/
|
||||
checksum: Buffer;
|
||||
}
|
||||
|
||||
@@ -522,7 +540,9 @@ export type SystemFlags = { mountChecks: Record<StorageFolder, boolean> };
|
||||
export type MaintenanceModeState =
|
||||
{ isMaintenanceMode: true; secret: string; action?: SetMaintenanceModeDto } | { isMaintenanceMode: false };
|
||||
export type MemoriesState = {
|
||||
/** memories have already been created through this date */
|
||||
/**
|
||||
memories have already been created through this date
|
||||
*/
|
||||
lastOnThisDayDate: string;
|
||||
};
|
||||
export type MediaLocation = { location: string };
|
||||
|
||||
@@ -113,7 +113,9 @@ export const removeAssets = async (
|
||||
export type PartnerIdOptions = {
|
||||
userId: string;
|
||||
repository: PartnerRepository;
|
||||
/** only include partners with `inTimeline: true` */
|
||||
/**
|
||||
only include partners with `inTimeline: true`
|
||||
*/
|
||||
timelineEnabled?: boolean;
|
||||
};
|
||||
export const getMyPartnerIds = async ({ userId, repository, timelineEnabled }: PartnerIdOptions) => {
|
||||
|
||||
@@ -391,7 +391,9 @@ export function withEdits(eb: ExpressionBuilder<DB, 'asset'>): AliasedEditAction
|
||||
}
|
||||
|
||||
const joinDeduplicationPlugin = new DeduplicateJoinsPlugin();
|
||||
/** TODO: This should only be used for search-related queries, not as a general purpose query builder */
|
||||
/**
|
||||
TODO: This should only be used for search-related queries, not as a general purpose query builder
|
||||
*/
|
||||
|
||||
export function searchAssetBuilderLegacy(kysely: Kysely<DB>, options: AssetSearchBuilderOptions) {
|
||||
options.withDeleted ||= !!(options.trashedAfter || options.trashedBefore || options.isOffline);
|
||||
|
||||
@@ -164,7 +164,9 @@ export const mimeTypes = {
|
||||
transparentCapableExtensions.has(getFilenameExtension(filename).toLowerCase()),
|
||||
isRaw: (filename: string) => isType(filename, raw),
|
||||
lookup,
|
||||
/** return an extension (including a leading `.`) for a mime-type */
|
||||
/**
|
||||
return an extension (including a leading `.`) for a mime-type
|
||||
*/
|
||||
toExtension,
|
||||
assetType: (filename: string) => {
|
||||
const contentType = lookup(filename);
|
||||
|
||||
@@ -12,7 +12,9 @@ export const triggerMap: Record<WorkflowTrigger, WorkflowType[]> = {
|
||||
export const getWorkflowTriggers = () =>
|
||||
Object.entries(triggerMap).map(([trigger, types]) => ({ trigger: trigger as WorkflowTrigger, types }));
|
||||
|
||||
/** some types extend other types and have implied compatibility */
|
||||
/**
|
||||
some types extend other types and have implied compatibility
|
||||
*/
|
||||
const inferredMap: Record<WorkflowType, WorkflowType[]> = {
|
||||
[WorkflowType.AssetV1]: [],
|
||||
// [WorkflowType.AssetPersonV1]: [WorkflowType.AssetV1],
|
||||
|
||||
Vendored
+3
-1
@@ -48,7 +48,9 @@ const probeStubDefault: VideoInfo = {
|
||||
audioStreams: probeStubDefaultAudioStream,
|
||||
};
|
||||
|
||||
/** Fixtures in the shape `mediaRepository.probe()` returns (arrays of streams, raw ffprobe format). */
|
||||
/**
|
||||
Fixtures in the shape `mediaRepository.probe()` returns (arrays of streams, raw ffprobe format).
|
||||
*/
|
||||
export const videoInfoStub = {
|
||||
noVideoStreams: Object.freeze<VideoInfo>({ ...probeStubDefault, videoStreams: [] }),
|
||||
noAudioStreams: Object.freeze<VideoInfo>({ ...probeStubDefault, audioStreams: [] }),
|
||||
|
||||
@@ -541,10 +541,8 @@ export const mockDuplex =
|
||||
if (error) {
|
||||
duplex.destroy(error as Error);
|
||||
} else if (exitCode === 0) {
|
||||
/* eslint-disable unicorn/prefer-single-call */
|
||||
duplex.push(stdout);
|
||||
duplex.push(null);
|
||||
/* eslint-enable unicorn/prefer-single-call */
|
||||
} else {
|
||||
duplex.destroy(new Error(`${command} non-zero exit code (${exitCode})\n${stderr}`));
|
||||
}
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@
|
||||
"eslint-plugin-better-tailwindcss": "^4.5.0",
|
||||
"eslint-plugin-compat": "^7.0.0",
|
||||
"eslint-plugin-svelte": "^3.12.4",
|
||||
"eslint-plugin-unicorn": "^72.0.0",
|
||||
"eslint-plugin-unicorn": "^73.0.0",
|
||||
"factory.ts": "^1.4.1",
|
||||
"globals": "^17.0.0",
|
||||
"happy-dom": "^20.0.0",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/** Focus the given element when it is mounted. */
|
||||
/**
|
||||
Focus the given element when it is mounted.
|
||||
*/
|
||||
export const initInput = (element: HTMLInputElement) => {
|
||||
element.focus();
|
||||
};
|
||||
|
||||
@@ -55,7 +55,9 @@
|
||||
}
|
||||
|
||||
const groupOptions: AlbumGroupOption = {
|
||||
/** No grouping */
|
||||
/**
|
||||
No grouping
|
||||
*/
|
||||
[AlbumGroupBy.None]: (order, albums): AlbumGroup[] => {
|
||||
return [
|
||||
{
|
||||
@@ -66,7 +68,9 @@
|
||||
];
|
||||
},
|
||||
|
||||
/** Group by year */
|
||||
/**
|
||||
Group by year
|
||||
*/
|
||||
[AlbumGroupBy.Year]: (order, albums): AlbumGroup[] => {
|
||||
const unknownYear = $t('unknown_year');
|
||||
const useStartDate = userSettings.sortBy === AlbumSortBy.OldestPhoto;
|
||||
@@ -92,7 +96,9 @@
|
||||
}));
|
||||
},
|
||||
|
||||
/** Group by owner */
|
||||
/**
|
||||
Group by owner
|
||||
*/
|
||||
[AlbumGroupBy.Owner]: (order, albums): AlbumGroup[] => {
|
||||
const currentUserId = authManager.user.id;
|
||||
const groupedByOwnerIds = groupBy(albums, (album) => album.albumUsers[0].user.id);
|
||||
|
||||
@@ -108,7 +108,9 @@
|
||||
updateOcrBoxes(ocrManager.showOverlay, ocrManager.data);
|
||||
});
|
||||
|
||||
/** Use updateOnly=true on zoom, pan, or resize. */
|
||||
/**
|
||||
Use updateOnly=true on zoom, pan, or resize.
|
||||
*/
|
||||
const updateOcrBoxes = (showOverlay: boolean, ocrData: OcrBoundingBox[], updateOnly = false) => {
|
||||
if (!viewer || !viewer.state.textureData || !viewer.getPlugin(MarkersPlugin)) {
|
||||
return;
|
||||
|
||||
@@ -11,30 +11,54 @@
|
||||
import { fade, fly } from 'svelte/transition';
|
||||
|
||||
interface Props {
|
||||
/** Offset from the top of the timeline (e.g., for headers) */
|
||||
/**
|
||||
Offset from the top of the timeline (e.g., for headers)
|
||||
*/
|
||||
timelineTopOffset?: number;
|
||||
/** Offset from the bottom of the timeline (e.g., for footers) */
|
||||
/**
|
||||
Offset from the bottom of the timeline (e.g., for footers)
|
||||
*/
|
||||
timelineBottomOffset?: number;
|
||||
/** Total height of the scrubber component */
|
||||
/**
|
||||
Total height of the scrubber component
|
||||
*/
|
||||
height?: number;
|
||||
/** Timeline manager instance that controls the timeline state */
|
||||
/**
|
||||
Timeline manager instance that controls the timeline state
|
||||
*/
|
||||
timelineManager: TimelineManager;
|
||||
/** Overall scroll percentage through the entire timeline (0-1), used when no specific month is targeted */
|
||||
/**
|
||||
Overall scroll percentage through the entire timeline (0-1), used when no specific month is targeted
|
||||
*/
|
||||
timelineScrollPercent?: number;
|
||||
/** The percentage of scroll through the month that is currently intersecting the top boundary of the viewport */
|
||||
/**
|
||||
The percentage of scroll through the month that is currently intersecting the top boundary of the viewport
|
||||
*/
|
||||
viewportTopMonthScrollPercent?: number;
|
||||
/** The year/month of the timeline month at the top of the viewport */
|
||||
/**
|
||||
The year/month of the timeline month at the top of the viewport
|
||||
*/
|
||||
viewportTopMonth?: ViewportTopMonth;
|
||||
|
||||
/** Width of the scrubber component in pixels (bindable for parent component margin adjustments) */
|
||||
/**
|
||||
Width of the scrubber component in pixels (bindable for parent component margin adjustments)
|
||||
*/
|
||||
scrubberWidth?: number;
|
||||
/** Callback fired when user interacts with the scrubber to navigate */
|
||||
/**
|
||||
Callback fired when user interacts with the scrubber to navigate
|
||||
*/
|
||||
onScrub?: ScrubberListener;
|
||||
/** Callback fired when keyboard events occur on the scrubber */
|
||||
/**
|
||||
Callback fired when keyboard events occur on the scrubber
|
||||
*/
|
||||
onScrubKeyDown?: (event: KeyboardEvent, element: HTMLElement) => void;
|
||||
/** Callback fired when scrubbing starts */
|
||||
/**
|
||||
Callback fired when scrubbing starts
|
||||
*/
|
||||
startScrub?: ScrubberListener;
|
||||
/** Callback fired when scrubbing stops */
|
||||
/**
|
||||
Callback fired when scrubbing stops
|
||||
*/
|
||||
stopScrub?: ScrubberListener;
|
||||
}
|
||||
|
||||
|
||||
@@ -223,34 +223,46 @@ export const stringToSortOrder = (order: string) => {
|
||||
};
|
||||
|
||||
const sortOptions: AlbumSortOption = {
|
||||
/** Sort by album title */
|
||||
/**
|
||||
Sort by album title
|
||||
*/
|
||||
[AlbumSortBy.Title]: (order, albums) => {
|
||||
const sortSign = order === SortOrder.Desc ? -1 : 1;
|
||||
return albums.slice().sort((a, b) => a.albumName.localeCompare(b.albumName, get(locale)) * sortSign);
|
||||
},
|
||||
|
||||
/** Sort by asset count */
|
||||
/**
|
||||
Sort by asset count
|
||||
*/
|
||||
[AlbumSortBy.ItemCount]: (order, albums) => {
|
||||
return orderBy(albums, 'assetCount', [order]);
|
||||
},
|
||||
|
||||
/** Sort by last modified */
|
||||
/**
|
||||
Sort by last modified
|
||||
*/
|
||||
[AlbumSortBy.DateModified]: (order, albums) => {
|
||||
return orderBy(albums, [({ updatedAt }) => new Date(updatedAt)], [order]);
|
||||
},
|
||||
|
||||
/** Sort by creation date */
|
||||
/**
|
||||
Sort by creation date
|
||||
*/
|
||||
[AlbumSortBy.DateCreated]: (order, albums) => {
|
||||
return orderBy(albums, [({ createdAt }) => new Date(createdAt)], [order]);
|
||||
},
|
||||
|
||||
/** Sort by the most recent photo date */
|
||||
/**
|
||||
Sort by the most recent photo date
|
||||
*/
|
||||
[AlbumSortBy.MostRecentPhoto]: (order, albums) => {
|
||||
albums = orderBy(albums, [({ endDate }) => (endDate ? new Date(endDate) : '')], [order]);
|
||||
return albums.sort(sortUnknownYearAlbums);
|
||||
},
|
||||
|
||||
/** Sort by the oldest photo date */
|
||||
/**
|
||||
Sort by the oldest photo date
|
||||
*/
|
||||
[AlbumSortBy.OldestPhoto]: (order, albums) => {
|
||||
albums = orderBy(albums, [({ startDate }) => (startDate ? new Date(startDate) : '')], [order]);
|
||||
return albums.sort(sortUnknownYearAlbums);
|
||||
|
||||
@@ -6,9 +6,13 @@ import { handleError } from '$lib/utils/handle-error';
|
||||
* and allowing operations to check if they're still valid.
|
||||
*/
|
||||
export class InvocationTracker {
|
||||
/** Counter for the number of invocations that have been started */
|
||||
/**
|
||||
Counter for the number of invocations that have been started
|
||||
*/
|
||||
invocationsStarted = 0;
|
||||
/** Counter for the number of invocations that have been completed */
|
||||
/**
|
||||
Counter for the number of invocations that have been completed
|
||||
*/
|
||||
invocationsEnded = 0;
|
||||
|
||||
constructor() {}
|
||||
|
||||
@@ -92,7 +92,9 @@ interface AssetGridRoute extends Route {
|
||||
type ImmichRoute = AssetRoute | AssetGridRoute;
|
||||
|
||||
type NavOptions = {
|
||||
/* navigate even if url is the same */
|
||||
/*
|
||||
navigate even if url is the same
|
||||
*/
|
||||
forceNavigate?: boolean | undefined;
|
||||
replaceState?: boolean | undefined;
|
||||
noScroll?: boolean | undefined;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import type { ParamMatcher } from '@sveltejs/kit';
|
||||
import { UUID_REGEX } from '$lib/constants';
|
||||
|
||||
/* Returns true if the given param matches UUID format */
|
||||
/*
|
||||
Returns true if the given param matches UUID format
|
||||
*/
|
||||
export const match: ParamMatcher = (param: string) => {
|
||||
return UUID_REGEX.test(param);
|
||||
};
|
||||
|
||||
@@ -33,7 +33,9 @@
|
||||
}
|
||||
|
||||
const groupOptions: PlacesGroupOption = {
|
||||
/** No grouping */
|
||||
/**
|
||||
No grouping
|
||||
*/
|
||||
[PlacesGroupBy.None]: (places): PlacesGroup[] => {
|
||||
return [
|
||||
{
|
||||
@@ -44,7 +46,9 @@
|
||||
];
|
||||
},
|
||||
|
||||
/** Group by year */
|
||||
/**
|
||||
Group by year
|
||||
*/
|
||||
[PlacesGroupBy.Country]: (places): PlacesGroup[] => {
|
||||
const unknownCountry = $t('unknown_country');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user