immich/server/src/constants.ts

206 lines
12 KiB
TypeScript
Raw Normal View History

2024-03-20 22:15:09 -05:00
import { readFileSync } from 'node:fs';
chore: use pnpm for builds (#19752) * Migrate from npm to pnpm across entire project • Update all GitHub workflow files to use pnpm instead of npm • Replace npm commands with pnpm equivalents in devcontainer scripts • Remove package-lock.json files and update to use pnpm-lock.yaml • Consolidate node version references to use server/.nvmrc * Refine pnpm migration based on review feedback • Replace SKIP_SHARP_FILTERING with SHARP_IGNORE_GLOBAL_LIBVIPS environment variable • Improve Sharp package filtering to include specific Linux architectures for Docker builds • Optimize Dockerfile dependency caching with improved layer structure • Clean up workspace configuration and remove redundant settings * Address additional review feedback for pnpm migration • Fix node-version-file paths in GitHub workflow configurations • Refactor .pnpmfile.cjs to use switch statement for better code organization • Correct cache type typo in fix-format workflow • Simplify Vite configuration by merging configs inline • Update package description for consistency * Use 'server/.nvmrc' for fix-format.yml GHA * Delete npm locks * Remove Docker volume isolation for node_modules directories • Remove volume mounts for node_modules and related directories • Allow shared access between host and container filesystem • Update init container to handle file ownership with conditional existence check * Remove unused Docker volumes and volume mounts • Remove node_modules volume mounts from devcontainer configuration • Remove unused named volumes for pnpm-store, node_modules, and cache directories • Clean up Docker Compose configuration after removing volume isolation * Fix typescript-sdk package issues • Remove unknown "build" dependency that was incorrectly added to package.json • Update pnpm-lock.yaml to reflect dependency removal * Add pnpm setup to mobile workflow for translation formatting • Add pnpm action setup step to mobile unit tests workflow • Required for translation file formatting and sorting operations --------- Co-authored-by: Jason Rasmussen <jason@rasm.me>
2025-08-19 05:55:24 -07:00
import { dirname, join } from 'node:path';
import { SemVer } from 'semver';
import { ApiTag, AudioCodec, DatabaseExtension, ExifOrientation, VectorIndex } from 'src/enum';
export const IMMICH_SERVER_START = 'Immich Server is listening';
2026-02-12 17:59:00 -05:00
export const ErrorMessages = {
InconsistentMediaLocation:
'Detected an inconsistent media location. For more information, see https://docs.immich.app/errors#inconsistent-media-location',
SchemaDrift: `Detected schema drift. For more information, see https://docs.immich.app/errors#schema-drift`,
TypeOrmUpgrade: 'Invalid upgrade path. For more information, see https://docs.immich.app/errors/#typeorm-upgrade',
};
export const POSTGRES_VERSION_RANGE = '>=14.0.0';
export const VECTORCHORD_VERSION_RANGE = '>=0.3 <2';
export const VECTOR_VERSION_RANGE = '>=0.5 <1';
2024-03-20 22:15:09 -05:00
2025-02-11 17:15:56 -05:00
export const JOBS_ASSET_PAGINATION_SIZE = 1000;
export const JOBS_LIBRARY_PAGINATION_SIZE = 10_000;
export const EXTENSION_NAMES: Record<DatabaseExtension, string> = {
cube: 'cube',
earthdistance: 'earthdistance',
vector: 'pgvector',
vchord: 'VectorChord',
2025-02-11 17:15:56 -05:00
} as const;
export const VECTOR_EXTENSIONS = [DatabaseExtension.VectorChord, DatabaseExtension.Vector] as const;
export const VECTOR_INDEX_TABLES = {
2025-07-15 14:50:13 -04:00
[VectorIndex.Clip]: 'smart_search',
[VectorIndex.Face]: 'face_search',
} as const;
export const VECTORCHORD_LIST_SLACK_FACTOR = 1.2;
export const SALT_ROUNDS = 10;
refactor(server)!: sanitize error messages to avoid leaking resource details (#28154) * refactor(server)!: sanitize error messages to avoid leaking resource and permission details * fix e2e tests * fix(server): prevent login timing oracle by always running bcrypt Always call compareBcrypt in the login path regardless of whether the email is registered. When no user is found, a dummy hash is used so the bcrypt KDF still runs and response latency is constant, making it impossible to enumerate valid email addresses by measuring response time. * fix(server): collapse OAuth callback messages to prevent email-existence oracle Two distinct error messages in the OAuth callback endpoint revealed whether an email address was already registered in the database. An attacker controlling the OAuth provider's email claim could probe the user table without authentication. Both cases now return the same generic message. * fix(server): replace email-in-use messages to prevent user-existence oracle Error messages on registration and profile-update that named whether an email address was already taken allowed callers to enumerate registered accounts. All three sites now return the same generic message regardless of whether the address is in use. * fix(server): hide slug uniqueness constraint to prevent shared-link probe Surfacing the Postgres unique-constraint name in the error response let any authenticated user brute-force whether a custom slug was already in use by another user's shared link, leaking the existence of other links. * fix(server): unify profile image errors to prevent user-existence oracle via status code GET /users/:id/profile-image returned HTTP 400 for an unknown user ID but HTTP 404 when the user existed without a photo, letting callers distinguish the two cases. Both now return 404 so the response is identical regardless of whether the UUID maps to an account. * fix(server): replace album user-not-found message to prevent UUID-existence oracle Album owners could probe arbitrary UUIDs via the add-user endpoint and determine whether they belonged to registered accounts by receiving 'User not found'. The message is now ambiguous about whether the ID was unrecognised or the user is inactive. * Revert "fix e2e tests" This reverts commit c1bd7a116b3f0fccf3d2530c8e34b13c1d862989. * Revert "refactor(server)!: sanitize error messages to avoid leaking resource and permission details" This reverts commit b96421a08387340fbb77913ca89b0717bcd9945d. * fix(server): use 403 instead of 400 for access-denied errors requireAccess threw BadRequestException which is incorrect HTTP semantics. Access denial is a client authorization problem (403 Forbidden), not a malformed request (400 Bad Request). Keep the descriptive permission name in the message since the full permission set is public API surface. * Revert "fix(server): use 403 instead of 400 for access-denied errors" This reverts commit bb069909571f4e514e7d050ddf588c017ee5a029. * shorten comment * add log messages * format * one more
2026-05-01 16:00:18 +02:00
// Syntactically valid bcrypt hash used in login() preventing timing-based user enumeration.
export const LOGIN_DUMMY_HASH = '$2b$10$abcdefghijklmnopqrstuuABCDEFGHIJKLMNOPQRSTUVWXYZabcde';
export const IWorker = 'IWorker';
chore: use pnpm for builds (#19752) * Migrate from npm to pnpm across entire project • Update all GitHub workflow files to use pnpm instead of npm • Replace npm commands with pnpm equivalents in devcontainer scripts • Remove package-lock.json files and update to use pnpm-lock.yaml • Consolidate node version references to use server/.nvmrc * Refine pnpm migration based on review feedback • Replace SKIP_SHARP_FILTERING with SHARP_IGNORE_GLOBAL_LIBVIPS environment variable • Improve Sharp package filtering to include specific Linux architectures for Docker builds • Optimize Dockerfile dependency caching with improved layer structure • Clean up workspace configuration and remove redundant settings * Address additional review feedback for pnpm migration • Fix node-version-file paths in GitHub workflow configurations • Refactor .pnpmfile.cjs to use switch statement for better code organization • Correct cache type typo in fix-format workflow • Simplify Vite configuration by merging configs inline • Update package description for consistency * Use 'server/.nvmrc' for fix-format.yml GHA * Delete npm locks * Remove Docker volume isolation for node_modules directories • Remove volume mounts for node_modules and related directories • Allow shared access between host and container filesystem • Update init container to handle file ownership with conditional existence check * Remove unused Docker volumes and volume mounts • Remove node_modules volume mounts from devcontainer configuration • Remove unused named volumes for pnpm-store, node_modules, and cache directories • Clean up Docker Compose configuration after removing volume isolation * Fix typescript-sdk package issues • Remove unknown "build" dependency that was incorrectly added to package.json • Update pnpm-lock.yaml to reflect dependency removal * Add pnpm setup to mobile workflow for translation formatting • Add pnpm action setup step to mobile unit tests workflow • Required for translation file formatting and sorting operations --------- Co-authored-by: Jason Rasmussen <jason@rasm.me>
2025-08-19 05:55:24 -07:00
// eslint-disable-next-line unicorn/prefer-module
const basePath = dirname(__filename);
const packageFile = join(basePath, '..', 'package.json');
const { version } = JSON.parse(readFileSync(packageFile, 'utf8'));
export const serverVersion = new SemVer(version);
2024-03-20 22:15:09 -05:00
export const citiesFile = 'cities500.txt';
export const reverseGeocodeMaxDistance = 25_000;
export const MOBILE_REDIRECT = 'app.immich:///oauth-callback';
2024-03-20 22:15:09 -05:00
export const LOGIN_URL = '/auth/login?autoLaunch=0';
2024-04-19 11:19:23 -04:00
2024-03-21 08:07:47 -05:00
export const excludePaths = ['/.well-known/immich', '/custom.css', '/favicon.ico'];
2024-03-20 22:15:09 -05:00
export const FACE_THUMBNAIL_SIZE = 250;
type ModelInfo = { dimSize: number };
export const CLIP_MODEL_INFO: Record<string, ModelInfo> = {
RN101__openai: { dimSize: 512 },
RN101__yfcc15m: { dimSize: 512 },
'ViT-B-16__laion400m_e31': { dimSize: 512 },
'ViT-B-16__laion400m_e32': { dimSize: 512 },
'ViT-B-16__openai': { dimSize: 512 },
'ViT-B-32__laion2b-s34b-b79k': { dimSize: 512 },
2024-03-20 22:15:09 -05:00
'ViT-B-32__laion2b_e16': { dimSize: 512 },
'ViT-B-32__laion400m_e31': { dimSize: 512 },
'ViT-B-32__laion400m_e32': { dimSize: 512 },
'ViT-B-32__openai': { dimSize: 512 },
'XLM-Roberta-Base-ViT-B-32__laion5b_s13b_b90k': { dimSize: 512 },
'XLM-Roberta-Large-Vit-B-32': { dimSize: 512 },
RN50x4__openai: { dimSize: 640 },
2024-03-20 22:15:09 -05:00
'ViT-B-16-plus-240__laion400m_e31': { dimSize: 640 },
'ViT-B-16-plus-240__laion400m_e32': { dimSize: 640 },
'XLM-Roberta-Large-Vit-B-16Plus': { dimSize: 640 },
'LABSE-Vit-L-14': { dimSize: 768 },
RN50x16__openai: { dimSize: 768 },
'ViT-B-16-SigLIP-256__webli': { dimSize: 768 },
'ViT-B-16-SigLIP-384__webli': { dimSize: 768 },
'ViT-B-16-SigLIP-512__webli': { dimSize: 768 },
'ViT-B-16-SigLIP-i18n-256__webli': { dimSize: 768 },
'ViT-B-16-SigLIP__webli': { dimSize: 768 },
2024-03-20 22:15:09 -05:00
'ViT-L-14-336__openai': { dimSize: 768 },
'ViT-L-14-quickgelu__dfn2b': { dimSize: 768 },
'ViT-L-14__laion2b-s32b-b82k': { dimSize: 768 },
'ViT-L-14__laion400m_e31': { dimSize: 768 },
'ViT-L-14__laion400m_e32': { dimSize: 768 },
'ViT-L-14__openai': { dimSize: 768 },
'XLM-Roberta-Large-Vit-L-14': { dimSize: 768 },
'nllb-clip-base-siglip__mrl': { dimSize: 768 },
'nllb-clip-base-siglip__v1': { dimSize: 768 },
RN50__cc12m: { dimSize: 1024 },
RN50__openai: { dimSize: 1024 },
RN50__yfcc15m: { dimSize: 1024 },
RN50x64__openai: { dimSize: 1024 },
2024-03-20 22:15:09 -05:00
'ViT-H-14-378-quickgelu__dfn5b': { dimSize: 1024 },
'ViT-H-14-quickgelu__dfn5b': { dimSize: 1024 },
'ViT-H-14__laion2b-s32b-b79k': { dimSize: 1024 },
'ViT-L-16-SigLIP-256__webli': { dimSize: 1024 },
'ViT-L-16-SigLIP-384__webli': { dimSize: 1024 },
2024-03-20 22:15:09 -05:00
'ViT-g-14__laion2b-s12b-b42k': { dimSize: 1024 },
'XLM-Roberta-Large-ViT-H-14__frozen_laion5b_s13b_b90k': { dimSize: 1024 },
'ViT-SO400M-14-SigLIP-384__webli': { dimSize: 1152 },
'nllb-clip-large-siglip__mrl': { dimSize: 1152 },
2024-03-20 22:15:09 -05:00
'nllb-clip-large-siglip__v1': { dimSize: 1152 },
2025-03-18 00:04:08 +08:00
'ViT-B-16-SigLIP2__webli': { dimSize: 768 },
'ViT-B-32-SigLIP2-256__webli': { dimSize: 768 },
'ViT-L-16-SigLIP2-256__webli': { dimSize: 1024 },
'ViT-L-16-SigLIP2-384__webli': { dimSize: 1024 },
'ViT-L-16-SigLIP2-512__webli': { dimSize: 1024 },
'ViT-SO400M-14-SigLIP2__webli': { dimSize: 1152 },
'ViT-SO400M-14-SigLIP2-378__webli': { dimSize: 1152 },
'ViT-SO400M-16-SigLIP2-256__webli': { dimSize: 1152 },
'ViT-SO400M-16-SigLIP2-384__webli': { dimSize: 1152 },
'ViT-SO400M-16-SigLIP2-512__webli': { dimSize: 1152 },
'ViT-gopt-16-SigLIP2-256__webli': { dimSize: 1536 },
'ViT-gopt-16-SigLIP2-384__webli': { dimSize: 1536 },
2024-03-20 22:15:09 -05:00
};
type SharpRotationData = {
angle?: number;
flip?: boolean;
flop?: boolean;
};
export const ORIENTATION_TO_SHARP_ROTATION: Record<ExifOrientation, SharpRotationData> = {
[ExifOrientation.Horizontal]: { angle: 0 },
[ExifOrientation.MirrorHorizontal]: { angle: 0, flop: true },
[ExifOrientation.Rotate180]: { angle: 180 },
[ExifOrientation.MirrorVertical]: { angle: 180, flop: true },
[ExifOrientation.MirrorHorizontalRotate270CW]: { angle: 270, flip: true },
[ExifOrientation.Rotate90CW]: { angle: 90 },
[ExifOrientation.MirrorHorizontalRotate90CW]: { angle: 90, flip: true },
[ExifOrientation.Rotate270CW]: { angle: 270 },
} as const;
2025-11-11 17:01:14 -05:00
export const endpointTags: Record<ApiTag, string> = {
[ApiTag.Activities]: 'An activity is a like or a comment made by a user on an asset or album.',
[ApiTag.Albums]: 'An album is a collection of assets that can be shared with other users or via shared links.',
[ApiTag.ApiKeys]: 'An api key can be used to programmatically access the Immich API.',
[ApiTag.Assets]: 'An asset is an image or video that has been uploaded to Immich.',
[ApiTag.Authentication]: 'Endpoints related to user authentication, including OAuth.',
[ApiTag.AuthenticationAdmin]: 'Administrative endpoints related to authentication.',
feat: restore database backups (#23978) * feat: ProcessRepository#createSpawnDuplexStream * test: write tests for ProcessRepository#createSpawnDuplexStream * feat: StorageRepository#createGzip,createGunzip,createPlainReadStream * feat: backups util (args, create, restore, progress) * feat: wait on maintenance operation lock on boot * chore: use backup util from backup.service.ts test: update backup.service.ts tests with new util * feat: list/delete backups (maintenance services) * chore: open api fix: missing action in cli.service.ts * chore: add missing repositories to MaintenanceModule * refactor: move logSecret into module init * feat: initialise StorageCore in maintenance mode * feat: authenticate websocket requests in maintenance mode * test: add mock for new storage fns * feat: add MaintenanceEphemeralStateRepository refactor: cache the secret in memory * test: update service worker tests * feat: add external maintenance mode status * feat: synchronised status, restore db action * test: backup restore service tests * refactor: DRY end maintenance * feat: list and delete backup routes * feat: start action on boot * fix: should set status on restore end * refactor: add maintenanceStore to hold writables * feat: sync status to web app * feat: web impl. * test: various utils for testings * test: web e2e tests * test: e2e maintenance spec * test: update cli spec * chore: e2e lint * chore: lint fixes * chore: lint fixes * feat: start restore flow route * test: update e2e tests * chore: remove neon lights on maintenance action pages * fix: use 'startRestoreFlow' on onboarding page * chore: ignore any library folder in `docker/` * fix: load status on boot * feat: upload backups * refactor: permit any .sql(.gz) to be listed/restored * feat: download backups from list * fix: permit uploading just .sql files * feat: restore just .sql files * fix: don't show backups list if logged out * feat: system integrity check in restore flow * test: not providing failed backups in API anymore * test: util should also not try to use failedBackups * fix: actually assign inputStream * test: correct test backup prep. * fix: ensure task is defined to show error * test: fix docker cp command * test: update e2e web spec to select next button * test: update e2e api tests * test: refactor timeouts * chore: remove `showDelete` from maint. settings * chore: lint * chore: lint * fix: make sure backups are correctly sorted for clean up * test: update service spec * test: adjust e2e timeout * test: increase web timeouts for ci * chore: move gitignore changes * chore: additional filename validation * refactor: better typings for integrity API * feat: higher accuracy progress tracking * chore: delay lock retry * refactor: remove old maintenance settings * refactor: clean up tailwind classes * refactor: use while loop rather than recursive calls * test: update service specs * chore: check canParse too * chore: lint * fix: logic error causing infinite loop * refactor: use <ProgressBar /> from ui library * fix: create or overwrite file * chore: i18n pass, update progress bar * fix: wrong translation string * chore: update colour variables * test: update web test for new maint. page * chore: format, fix key * test: update tests to be more linter complaint & use new routines * chore: update onClick -> onAction, title -> breadcrumbs * fix: use wrench icon in admin settings sidebar * chore: add translation strings to accordion * chore: lint * refactor: move maintenance worker init into service * refactor: `maintenanceStatus` -> `getMaintenanceStatus` refactor: `integrityCheck` -> `detectPriorInstall` chore: add `v2.4.0` version refactor: `/backups/list` -> `/backups` refactor: use sendFile in download route refactor: use separate backups permissions chore: correct descriptions refactor: permit handler that doesn't return promise for sendfile * refactor: move status impl into service refactor: add active flag to maintenance status * refactor: split into database backup controller * test: split api e2e tests and passing * fix: move end button into authed default maint page * fix: also show in restore flow * fix: import getMaintenanceStatus * test: split web e2e tests * refactor: ensure detect install is consistently named * chore: ensure admin for detect install while out of maint. * refactor: remove state repository * test: update maint. worker service spec * test: split backup service spec * refactor: rename db backup routes * refactor: instead of param, allow bulk backup deletion * test: update sdk use in e2e test * test: correct deleteBackup call * fix: correct type for serverinstall response dto * chore: validate filename for deletion * test: wip * test: backups no longer take path param * refactor: scope util to database-backups instead of backups * fix: update worker controller with new route * chore: use new admin page actions * chore: remove stray comment * test: rename outdated test * refactor: getter pattern for maintenance secret * refactor: `createSpawnDuplexStream` -> `spawnDuplexStream` * refactor: prefer `Object.assign` * refactor: remove useless try {} block * refactor: prefer `type Props` refactor: prefer arrow function * refactor: use luxon API for minutesAgo * chore: remove change to gitignore * refactor: prefer `type Props` * refactor: remove async from onMount * refactor: use luxon toRelative for relative time * refactor: duplicate logic check * chore: open api * refactor: begin moving code into web//services * refactor: don't use template string with $t * test: use dialog role to match prompt * refactor: split actions into flow/restore * test: fix action value * refactor: move more service calls into web//services * chore: should void fn return * chore: bump 2.4.0 to 2.5.0 in controller * chore: bump 2.4.0 to 2.5.0 in controller * refactor: use events for web//services * chore: open api * chore: open api * refactor: don't await returned promise * refactor: remove redundant check * refactor: add `type: command` to actions * refactor: split backup entries into own component * refactor: split restore flow into separate components * refactor(web): split BackupDelete event * chore: stylings * chore: stylings * fix: don't log query failure on first boot * feat: support pg_dumpall backups * feat: display information about each backup * chore: i18n * feat: rollback to restore point on migrations failure * feat: health check after restore * chore: format * refactor: split health check into separate function * refactor: split health into repository test: write tests covering rollbacks * fix: omit 'health' requirement from createDbBackup * test(e2e): rollback test * fix: wrap text in backup entry * fix: don't shrink context menu button * fix: correct CREATE DB syntax for postgres * test: rename backups generated by test * feat: add filesize to backup response dto * feat: restore list * feat: ui work * fix: e2e test * fix: e2e test * pr feedback * pr feedback --------- Co-authored-by: Alex <alex.tran1502@gmail.com> Co-authored-by: Jason Rasmussen <jason@rasm.me>
2026-01-20 15:22:28 +00:00
[ApiTag.DatabaseBackups]: 'Manage backups of the Immich database.',
2025-11-11 17:01:14 -05:00
[ApiTag.Deprecated]: 'Deprecated endpoints that are planned for removal in the next major release.',
[ApiTag.Download]: 'Endpoints for downloading assets or collections of assets.',
[ApiTag.Duplicates]: 'Endpoints for managing and identifying duplicate assets.',
[ApiTag.Faces]:
'A face is a detected human face within an asset, which can be associated with a person. Faces are normally detected via machine learning, but can also be created via manually.',
[ApiTag.Jobs]:
'Queues and background jobs are used for processing tasks asynchronously. Queues can be paused and resumed as needed.',
[ApiTag.Libraries]:
'An external library is made up of input file paths or expressions that are scanned for asset files. Discovered files are automatically imported. Assets much be unique within a library, but can be duplicated across libraries. Each user has a default upload library, and can have one or more external libraries.',
feat: maintenance mode (#23431) * feat: add a `maintenance.enabled` config flag * feat: implement graceful restart feat: restart when maintenance config is toggled * feat: boot a stripped down maintenance api if enabled * feat: cli command to toggle maintenance mode * chore: fallback IMMICH_SERVER_URL environment variable in process * chore: add additional routes to maintenance controller * fix: don't wait for nest application to close to finish request response * chore: add a failsafe on restart to prevent other exit codes from preventing restart * feat: redirect into/from maintenance page * refactor: use system metadata for maintenance status * refactor: wait on WebSocket connection to refresh * feat: broadcast websocket event on server restart refactor: listen to WS instead of polling * refactor: bubble up maintenance information instead of hijacking in fetch function feat: show modal when server is restarting * chore: increase timeout for ungraceful restart * refactor: deduplicate code between api/maintenance workers * fix: skip config check if database is not initialised * fix: add `maintenanceMode` field to system config test * refactor: move maintenance resolution code to static method in service * chore: clean up linter issues * chore: generate dart openapi * refactor: use try{} block for maintenance mode check * fix: logic error in server redirect * chore: include `maintenanceMode` key in e2e test * chore: add i18n entries for maintenance screens * chore: remove negated condition from hook * fix: should set default value not override in service * fix: minor error in page * feat: initial draft of maintenance module, repo., worker controller, worker service * refactor: move broadcast code into notification service * chore: connect websocket on client if in maintenance * chore: set maintenance module app name * refactor: rename repository to include worker chore: configure websocket adapter * feat: reimplement maintenance mode exit with new module * refactor: add a constant enum for ExitCode * refactor: remove redundant route for maintenance * refactor: only spin up kysely on boot (rather than a Nest app) * refactor(web): move redirect logic into +layout file where modal is setup * feat: add Maintenance permission * refactor: merge common code between api/maintenance * fix: propagate changes from the CLI to servers * feat: maintenance authentication guard * refactor: unify maintenance code into repository feat: add a step to generate maintenance mode token * feat: jwt auth for maintenance * refactor: switch from nest jwt to just jsonwebtokens * feat: log into maintenance mode from CLI command * refactor: use `secret` instead of `token` in jwt terminology chore: log maintenance mode login URL on boot chore: don't make CLI actions reload if already in target state * docs: initial draft for maintenance mode page * refactor: always validate the maintenance auth on the server * feat: add a link to maintenance mode documentation * feat: redirect users back to the last page they were on when exiting maintenance * refactor: provide closeFn in both maintenance repos. * refactor: ensure the user is also redirected by the server * chore: swap jsonwebtoken for jose * refactor: introduce AppRestartEvent w/o secret passing * refactor: use navigation goto * refactor: use `continue` instead of `next` * chore: lint fixes for server * chore: lint fixes for web * test: add mock for maintenance repository * test: add base service dependency to maintenance * chore: remove @types/jsonwebtoken * refactor: close database connection after startup check * refactor: use `request#auth` key * refactor: use service instead of repository chore: read token from cookie if possible chore: rename client event to AppRestartV1 * refactor: more concise redirect logic on web * refactor: move redirect check into utils refactor: update translation strings to be more sensible * refactor: always validate login (i.e. check cookie) * refactor: lint, open-api, remove old dto * refactor: encode at point of usage * refactor: remove business logic from repositories * chore: fix server/web lints * refactor: remove repository mock * chore: fix formatting * test: write service mocks for maintenance mode * test: write cli service tests * fix: catch errors when closing app * fix: always report no maintenance when usual API is available * test: api e2e maintenance spec * chore: add response builder * chore: add helper to set maint. auth cookie * feat: add SSR to maintenance API * test(e2e): write web spec for maintenance * chore: clean up lint issues * chore: format files * feat: perform 302 redirect at server level during maintenance * fix: keep trying to stop immich until it succeeds (CLI issue) * chore: lint/format * refactor: annotate references to other services in worker service * chore: lint * refactor: remove unnecessary await Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com> * refactor: move static methods into util * refactor: assert secret exists in maintenance worker * refactor: remove assertion which isn't necessary anymore * refactor: remove assertion * refactor: remove outer try {} catch block from loadMaintenanceAuth * refactor: undo earlier change to vite.config.ts * chore: update tests due to refactors * revert: vite.config.ts * test: expect string jwt * chore: move blanket exceptions into controllers * test: update tests according with last change * refactor: use respondWithCookie refactor: merge start/end into one route refactor: rename MaintenanceRepository to AppRepository chore: use new ApiTag/Endpoint refactor: apply other requested changes * chore: regenerate openapi * chore: lint/format * chore: remove secureOnly for maint. cookie * refactor: move maintenance worker code into src/maintenance\nfix: various test fixes * refactor: use `action` property for setting maint. mode * refactor: remove Websocket#restartApp in favour of individual methods * chore: incomplete commit * chore: remove stray log * fix: call exitApp from maintenance worker on exit * fix: add app repository mock * fix: ensure maintenance cookies are secure * fix: run playwright tests over secure context (localhost) * test: update other references to 127.0.0.1 * refactor: use serverSideEmitWithAck * chore: correct the logic in tryTerminate * test: juggle cookies ourselves * chore: fix lint error for e2e spec * chore: format e2e test * fix: set cookie secure/non-secure depending on context * chore: format files --------- Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>
2025-11-17 17:15:44 +00:00
[ApiTag.Maintenance]: 'Maintenance mode allows you to put Immich in a read-only state to perform various operations.',
2025-11-11 17:01:14 -05:00
[ApiTag.Map]:
'Map endpoints include supplemental functionality related to geolocation, such as reverse geocoding and retrieving map markers for assets with geolocation data.',
[ApiTag.Memories]:
'A memory is a specialized collection of assets with dedicated viewing implementations in the web and mobile clients. A memory includes fields related to visibility and are automatically generated per user via a background job.',
[ApiTag.Notifications]:
'A notification is a specialized message sent to users to inform them of important events. Currently, these notifications are only shown in the Immich web application.',
[ApiTag.NotificationsAdmin]: 'Notification administrative endpoints.',
[ApiTag.Partners]: 'A partner is a link with another user that allows sharing of assets between two users.',
[ApiTag.People]:
'A person is a collection of faces, which can be favorited and named. A person can also be merged into another person. People are automatically created via the face recognition job.',
feat: workflow foundation (#23621) * feat: plugins * feat: table definition * feat: type and migration * feat: add repositories * feat: validate manifest with class-validator and load manifest info to database * feat: workflow/plugin controller/service layer * feat: implement workflow logic * feat: make trigger static * feat: dynamical instantiate plugin instances * fix: access control and helper script * feat: it works * chore: simplify * refactor: refactor and use queue for workflow execution * refactor: remove unsused property in plugin-schema * build wasm in prod * feat: plugin loader in transaction * fix: docker build arm64 * generated files * shell check * fix tests * fix: waiting for migration to finish before loading plugin * remove context reassignment * feat: use mise to manage extism tools (#23760) * pr feedback * refactor: create workflow now including create filters and actions * feat: workflow medium tests * fix: broken medium test * feat: medium tests * chore: unify workflow job * sign user id with jwt * chore: query plugin with filters and action * chore: read manifest in repository * chore: load manifest from server configs * merge main * feat: endpoint documentation * pr feedback * load plugin from absolute path * refactor:handle trigger * throw error and return early * pr feedback * unify plugin services * fix: plugins code * clean up * remove triggerConfig * clean up * displayName and methodName --------- Co-authored-by: Jason Rasmussen <jason@rasm.me> Co-authored-by: bo0tzz <git@bo0tzz.me>
2025-11-14 14:05:05 -06:00
[ApiTag.Plugins]:
'A plugin is an installed module that makes filters and actions available for the workflow feature.',
2025-11-25 08:19:40 -05:00
[ApiTag.Queues]:
'Queues and background jobs are used for processing tasks asynchronously. Queues can be paused and resumed as needed.',
2025-11-11 17:01:14 -05:00
[ApiTag.Search]:
'Endpoints related to searching assets via text, smart search, optical character recognition (OCR), and other filters like person, album, and other metadata. Search endpoints usually support pagination and sorting.',
[ApiTag.Server]:
'Information about the current server deployment, including version and build information, available features, supported media types, and more.',
[ApiTag.Sessions]:
'A session represents an authenticated login session for a user. Sessions also appear in the web application as "Authorized devices".',
[ApiTag.SharedLinks]:
'A shared link is a public url that provides access to a specific album, asset, or collection of assets. A shared link can be protected with a password, include a specific slug, allow or disallow downloads, and optionally include an expiration date.',
[ApiTag.Stacks]:
'A stack is a group of related assets. One asset is the "primary" asset, and the rest are "child" assets. On the main timeline, stack parents are included by default, while child assets are hidden.',
[ApiTag.Sync]: 'A collection of endpoints for the new mobile synchronization implementation.',
[ApiTag.SystemConfig]: 'Endpoints to view, modify, and validate the system configuration settings.',
[ApiTag.SystemMetadata]:
'Endpoints to view, modify, and validate the system metadata, which includes information about things like admin onboarding status.',
[ApiTag.Tags]:
'A tag is a user-defined label that can be applied to assets for organizational purposes. Tags can also be hierarchical, allowing for parent-child relationships between tags.',
[ApiTag.Timeline]:
'Specialized endpoints related to the timeline implementation used in the web application. External applications or tools should not use or rely on these endpoints, as they are subject to change without notice.',
[ApiTag.Trash]:
'Endpoints for managing the trash can, which includes assets that have been discarded. Items in the trash are automatically deleted after a configured amount of time.',
[ApiTag.UsersAdmin]:
'Administrative endpoints for managing users, including creating, updating, deleting, and restoring users. Also includes endpoints for resetting passwords and PIN codes.',
[ApiTag.Users]:
'Endpoints for viewing and updating the current users, including product key information, profile picture data, onboarding progress, and more.',
[ApiTag.Views]: 'Endpoints for specialized views, such as the folder view.',
feat: workflow foundation (#23621) * feat: plugins * feat: table definition * feat: type and migration * feat: add repositories * feat: validate manifest with class-validator and load manifest info to database * feat: workflow/plugin controller/service layer * feat: implement workflow logic * feat: make trigger static * feat: dynamical instantiate plugin instances * fix: access control and helper script * feat: it works * chore: simplify * refactor: refactor and use queue for workflow execution * refactor: remove unsused property in plugin-schema * build wasm in prod * feat: plugin loader in transaction * fix: docker build arm64 * generated files * shell check * fix tests * fix: waiting for migration to finish before loading plugin * remove context reassignment * feat: use mise to manage extism tools (#23760) * pr feedback * refactor: create workflow now including create filters and actions * feat: workflow medium tests * fix: broken medium test * feat: medium tests * chore: unify workflow job * sign user id with jwt * chore: query plugin with filters and action * chore: read manifest in repository * chore: load manifest from server configs * merge main * feat: endpoint documentation * pr feedback * load plugin from absolute path * refactor:handle trigger * throw error and return early * pr feedback * unify plugin services * fix: plugins code * clean up * remove triggerConfig * clean up * displayName and methodName --------- Co-authored-by: Jason Rasmussen <jason@rasm.me> Co-authored-by: bo0tzz <git@bo0tzz.me>
2025-11-14 14:05:05 -06:00
[ApiTag.Workflows]:
'A workflow is a set of actions that run whenever a triggering event occurs. Workflows also can include filters to further limit execution.',
2025-11-11 17:01:14 -05:00
};
export const AUDIO_ENCODER: Record<AudioCodec, string> = {
[AudioCodec.Aac]: 'aac',
[AudioCodec.Mp3]: 'mp3',
[AudioCodec.Libopus]: 'libopus',
[AudioCodec.Opus]: 'libopus',
[AudioCodec.PcmS16le]: 'pcm_s16le',
};