1
0
forked from Cutlery/immich

Merge remote-tracking branch 'origin' into feat/offline-files-job

This commit is contained in:
Jonathan Jogenfors 2024-03-20 21:55:46 +01:00
commit 94b9b4d68a
400 changed files with 3381 additions and 3519 deletions

View File

@ -4,16 +4,16 @@ on:
workflow_dispatch:
inputs:
serverBump:
description: "Bump server version"
description: 'Bump server version'
required: true
default: "false"
default: 'false'
type: choice
options:
- "false"
- 'false'
- minor
- patch
mobileBump:
description: "Bump mobile build number"
description: 'Bump mobile build number'
required: false
type: boolean
@ -46,8 +46,8 @@ jobs:
with:
author_name: Alex The Bot
author_email: alex.tran1502@gmail.com
default_author: user_info
message: "Version ${{ env.IMMICH_VERSION }}"
default_author: user_info
message: 'Version ${{ env.IMMICH_VERSION }}'
tag: ${{ env.IMMICH_VERSION }}
push: true
@ -85,4 +85,5 @@ jobs:
docker/example.env
docker/hwaccel.ml.yml
docker/hwaccel.transcoding.yml
docker/prometheus.yml
*.apk

30
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,30 @@
{
"editor.formatOnSave": true,
"[javascript][typescript][css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.tabSize": 2,
"editor.formatOnSave": true
},
"[svelte]": {
"editor.defaultFormatter": "svelte.svelte-vscode",
"editor.tabSize": 2
},
"svelte.enable-ts-plugin": true,
"eslint.validate": [
"javascript",
"svelte"
],
"typescript.preferences.importModuleSpecifier": "non-relative",
"[dart]": {
"editor.formatOnSave": true,
"editor.selectionHighlight": false,
"editor.suggest.snippetsPreventQuickSuggestions": false,
"editor.suggestSelection": "first",
"editor.tabCompletion": "onlySnippets",
"editor.wordBasedSuggestions": "off",
"editor.defaultFormatter": "Dart-Code.dart-code"
},
"cSpell.words": [
"immich"
],
}

View File

@ -1,4 +1,4 @@
FROM node:20-alpine3.19@sha256:c0a3badbd8a0a760de903e00cedbca94588e609299820557e72cba2a53dbaa2c as core
FROM node:20-alpine3.19@sha256:bf77dc26e48ea95fca9d1aceb5acfa69d2e546b765ec2abfb502975f1a2d4def as core
WORKDIR /usr/src/open-api/typescript-sdk
COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./

2
cli/package-lock.json generated
View File

@ -47,7 +47,7 @@
},
"../open-api/typescript-sdk": {
"name": "@immich/sdk",
"version": "1.98.2",
"version": "1.99.0",
"dev": true,
"license": "GNU Affero General Public License version 3",
"dependencies": {

View File

@ -99,7 +99,7 @@ services:
redis:
container_name: immich_redis
image: redis:6.2-alpine@sha256:51d6c56749a4243096327e3fb964a48ed92254357108449cb6e23999c37773c5
image: redis:6.2-alpine@sha256:fd3535746075ba01b73c3602c0704bc944dd064c0a4ac46341a4a351bec69db8
database:
container_name: immich_postgres

View File

@ -56,7 +56,7 @@ services:
redis:
container_name: immich_redis
image: redis:6.2-alpine@sha256:51d6c56749a4243096327e3fb964a48ed92254357108449cb6e23999c37773c5
image: redis:6.2-alpine@sha256:fd3535746075ba01b73c3602c0704bc944dd064c0a4ac46341a4a351bec69db8
restart: always
database:
@ -78,7 +78,7 @@ services:
container_name: immich_prometheus
ports:
- 9090:9090
image: prom/prometheus@sha256:bc1794e85c9e00293351b967efa267ce6af1c824ac875a9d0c7ac84700a8b53e
image: prom/prometheus@sha256:5ccad477d0057e62a7cd1981ffcc43785ac10c5a35522dc207466ff7e7ec845f
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus

View File

@ -0,0 +1,113 @@
# Monitoring
## Overview
Immich provides a variety of performance metrics to allow for local monitoring and insights. This integration is primarily in the form of Prometheus metrics. However, exporting traces is also possible due to the use of OpenTelemetry instrumentation.
:::note
This is an opt-in feature intended for you to monitor immich's performance. This data isn't sent anywhere beyond what you've configured.
:::
## Prometheus
Prometheus is a tool that collects metrics from a number of sources you configure. It operates in a "pull" strategy - that is, it periodically requests metrics from each defined source. This means that the source doesn't send anything until it's requested. It also means that the source -- immich, in this case -- has to expose an endpoint for Prometheus to target when it requests metrics.
### Metrics
These metrics come in a variety of forms:
- Counters, which can only increase. Example: the number of times an endpoint has been called.
- Gauges, which can increase or decrease within a certain range. Example: CPU utilization.
- Histograms, where each observation is assigned to a certain number of "buckets". Example: response time, where each bucket is a number of milliseconds. This one is a bit more complicated.
- Buckets in this case are _cumulative_; that is, an observation is placed not only into the smallest bucket that contains it, but also to all buckets larger than this. For example, if a histogram has three buckets for 1ms, 5ms and 10ms, an observation of 3ms will be bucketed into both 5ms and 10ms.
The metrics in immich are grouped into API (endpoint calls and response times), host (memory and CPU utilization), and IO (internal database queries, image processing, and so on). Each group of metrics can be enabled or disabled independently.
### Configuration
Immich will not expose an endpoint for metrics by default. To enable this endpoint, you can add the `IMMICH_METRICS=true` environmental variable to your `.env` file. Note that only the server and microservices containers currently use this variable.
:::note
`IMMICH_METRICS` is equivalent to enabling the following three environmental variables: `IMMICH_API_METRICS`, `IMMICH_HOST_METRICS`, and `IMMICH_IO_METRICS`. If you would like to only expose certain kinds of metrics, you can set only those environmental variables to `true`. Explicitly setting the environmental variable for a metric group overrides `IMMICH_METRICS` for that group.
:::
The next step is to configure a new or existing Prometheus instance to scrape this endpoint. The following steps assume that you do not have an existing Prometheus instance, but the steps will be similar either way.
You can start by defining a Prometheus service in the Compose file:
```yaml
immich-prometheus:
container_name: immich_prometheus
ports:
# this exposes the default port for Prometheus so you can interact with it
- 9090:9090
image: prom/prometheus
volumes:
# the Prometheus configuration file - a barebones one is provided to get started
- ./prometheus.yml:/etc/prometheus/prometheus.yml
# a named volume defined in the bottom of the Compose file; it can also be a mounted folder
- prometheus-data:/prometheus
```
You will also need to add `prometheus-data` to the list of volumes in the bottom of the Compose file:
```yaml
volumes:
model-cache:
prometheus-data:
```
The last piece is the [configuration file][prom-file]. This file defines (among other things) the sources Prometheus should target. Download it and place it in the same folder as the Compose file.
:::tip
The provided file is just a starting point. There are a ton of ways to configure Prometheus, so feel free to experiment!
:::
After bringing down the containers with `docker compose down` and back up with `docker compose up -d`, a Prometheus instance will now collect metrics from the immich server and microservices containers. Note that we didn't need to expose any new ports for these containers - the communication is handled in the internal Docker network.
:::note
To see exactly what metrics are made available, you can additionally add `8081:8081` to the server container's ports and `8082:8081` to the microservices container's ports. Visiting the `/metrics` endpoint for these services will show the same raw data that Prometheus collects.
:::
### Usage
So after setting up Prometheus, how do you actually view the metrics? The simplest way is to use Prometheus directly. Visiting Prometheus will show you a web UI where you can search for and visualize metrics. You can also view the status of your data sources and configure settings, but this is beyond the scope of this guide.
## Grafana
For a dedicated tool with nice presentation, you can use Grafana instead. This connects to Prometheus (and possibly other sources) for sophisticated data visualization.
Setting up Grafana is similar to Prometheus. You can add a service for it:
```yaml
immich-grafana:
container_name: immich_grafana
command: ['./run.sh', '-disable-reporting'] # this is to disable Grafana's telemetry
ports:
- 3000:3000
image: grafana/grafana
volumes:
# stores your pretty dashboards and panels
- grafana-data:/var/lib/grafana
```
And add another volume for it:
```yaml
volumes:
model-cache:
prometheus-data:
grafana-data:
```
After bringing down the services and back up again, you can now visit Grafana to view your metrics. On the first login, enter `admin` for both username and password and update your password. You can then go to the settings and add a data source with `http://immich-prometheus:9090` to point Grafana to your Prometheus instance.
### Usage
You can make your first dashboard to get started. Don't forget to save it frequently, or you'll lose all your progress!
You can then make a new panel, specifying Prometheus as the data source for it.
-- TODO: add images and more details here
[prom-file]: https://github.com/immich-app/immich/releases/latest/download/prometheus.yml

View File

@ -36,7 +36,7 @@ services:
<<: *server-common
redis:
image: redis:6.2-alpine@sha256:51d6c56749a4243096327e3fb964a48ed92254357108449cb6e23999c37773c5
image: redis:6.2-alpine@sha256:fd3535746075ba01b73c3602c0704bc944dd064c0a4ac46341a4a351bec69db8
database:
image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0

444
e2e/package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "immich-e2e",
"version": "1.98.2",
"version": "1.99.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "immich-e2e",
"version": "1.98.2",
"version": "1.99.0",
"license": "GNU Affero General Public License version 3",
"devDependencies": {
"@immich/cli": "file:../cli",
@ -80,7 +80,7 @@
},
"../open-api/typescript-sdk": {
"name": "@immich/sdk",
"version": "1.98.2",
"version": "1.99.0",
"dev": true,
"license": "GNU Affero General Public License version 3",
"dependencies": {
@ -339,9 +339,9 @@
"dev": true
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz",
"integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz",
"integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==",
"cpu": [
"ppc64"
],
@ -355,9 +355,9 @@
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz",
"integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz",
"integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==",
"cpu": [
"arm"
],
@ -371,9 +371,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz",
"integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz",
"integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==",
"cpu": [
"arm64"
],
@ -387,9 +387,9 @@
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz",
"integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz",
"integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==",
"cpu": [
"x64"
],
@ -403,9 +403,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz",
"integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz",
"integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==",
"cpu": [
"arm64"
],
@ -419,9 +419,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz",
"integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz",
"integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==",
"cpu": [
"x64"
],
@ -435,9 +435,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz",
"integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz",
"integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==",
"cpu": [
"arm64"
],
@ -451,9 +451,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz",
"integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz",
"integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==",
"cpu": [
"x64"
],
@ -467,9 +467,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz",
"integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz",
"integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==",
"cpu": [
"arm"
],
@ -483,9 +483,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz",
"integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz",
"integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==",
"cpu": [
"arm64"
],
@ -499,9 +499,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz",
"integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz",
"integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==",
"cpu": [
"ia32"
],
@ -515,9 +515,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz",
"integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz",
"integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==",
"cpu": [
"loong64"
],
@ -531,9 +531,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz",
"integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz",
"integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==",
"cpu": [
"mips64el"
],
@ -547,9 +547,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz",
"integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz",
"integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==",
"cpu": [
"ppc64"
],
@ -563,9 +563,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz",
"integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz",
"integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==",
"cpu": [
"riscv64"
],
@ -579,9 +579,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz",
"integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz",
"integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==",
"cpu": [
"s390x"
],
@ -595,9 +595,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz",
"integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz",
"integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==",
"cpu": [
"x64"
],
@ -611,9 +611,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz",
"integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz",
"integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==",
"cpu": [
"x64"
],
@ -627,9 +627,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz",
"integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz",
"integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==",
"cpu": [
"x64"
],
@ -643,9 +643,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz",
"integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz",
"integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==",
"cpu": [
"x64"
],
@ -659,9 +659,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz",
"integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz",
"integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==",
"cpu": [
"arm64"
],
@ -675,9 +675,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz",
"integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz",
"integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==",
"cpu": [
"ia32"
],
@ -691,9 +691,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz",
"integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz",
"integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==",
"cpu": [
"x64"
],
@ -863,9 +863,9 @@
"dev": true
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.22",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz",
"integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==",
"version": "0.3.25",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dev": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
@ -941,9 +941,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz",
"integrity": "sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz",
"integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==",
"cpu": [
"arm"
],
@ -954,9 +954,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.0.tgz",
"integrity": "sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz",
"integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==",
"cpu": [
"arm64"
],
@ -967,9 +967,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.0.tgz",
"integrity": "sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz",
"integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==",
"cpu": [
"arm64"
],
@ -980,9 +980,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.0.tgz",
"integrity": "sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz",
"integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==",
"cpu": [
"x64"
],
@ -993,9 +993,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.0.tgz",
"integrity": "sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz",
"integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==",
"cpu": [
"arm"
],
@ -1006,9 +1006,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.0.tgz",
"integrity": "sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz",
"integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==",
"cpu": [
"arm64"
],
@ -1019,9 +1019,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.0.tgz",
"integrity": "sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz",
"integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==",
"cpu": [
"arm64"
],
@ -1032,9 +1032,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.0.tgz",
"integrity": "sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz",
"integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==",
"cpu": [
"riscv64"
],
@ -1045,9 +1045,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.0.tgz",
"integrity": "sha512-TenQhZVOtw/3qKOPa7d+QgkeM6xY0LtwzR8OplmyL5LrgTWIXpTQg2Q2ycBf8jm+SFW2Wt/DTn1gf7nFp3ssVA==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz",
"integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==",
"cpu": [
"x64"
],
@ -1058,9 +1058,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.12.0.tgz",
"integrity": "sha512-LfFdRhNnW0zdMvdCb5FNuWlls2WbbSridJvxOvYWgSBOYZtgBfW9UGNJG//rwMqTX1xQE9BAodvMH9tAusKDUw==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz",
"integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==",
"cpu": [
"x64"
],
@ -1071,9 +1071,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.0.tgz",
"integrity": "sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz",
"integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==",
"cpu": [
"arm64"
],
@ -1084,9 +1084,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.0.tgz",
"integrity": "sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz",
"integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==",
"cpu": [
"ia32"
],
@ -1097,9 +1097,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.0.tgz",
"integrity": "sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz",
"integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==",
"cpu": [
"x64"
],
@ -1158,9 +1158,9 @@
"dev": true
},
"node_modules/@types/node": {
"version": "20.11.27",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.27.tgz",
"integrity": "sha512-qyUZfMnCg1KEz57r7pzFtSGt49f6RPkPBis3Vo4PbS7roQEDn22hiHzl/Lo1q4i4hDEgBJmBF/NTNg2XR0HbFg==",
"version": "20.11.28",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.28.tgz",
"integrity": "sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
@ -1497,9 +1497,9 @@
"dev": true
},
"node_modules/@vitest/coverage-v8": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.3.1.tgz",
"integrity": "sha512-UuBnkSJUNE9rdHjDCPyJ4fYuMkoMtnghes1XohYa4At0MS3OQSAo97FrbwSLRshYsXThMZy1+ybD/byK5llyIg==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.4.0.tgz",
"integrity": "sha512-4hDGyH1SvKpgZnIByr9LhGgCEuF9DKM34IBLCC/fVfy24Z3+PZ+Ii9hsVBsHvY1umM1aGPEjceRkzxCfcQ10wg==",
"dev": true,
"dependencies": {
"@ampproject/remapping": "^2.2.1",
@ -1507,12 +1507,13 @@
"debug": "^4.3.4",
"istanbul-lib-coverage": "^3.2.2",
"istanbul-lib-report": "^3.0.1",
"istanbul-lib-source-maps": "^4.0.1",
"istanbul-lib-source-maps": "^5.0.4",
"istanbul-reports": "^3.1.6",
"magic-string": "^0.30.5",
"magicast": "^0.3.3",
"picocolors": "^1.0.0",
"std-env": "^3.5.0",
"strip-literal": "^2.0.0",
"test-exclude": "^6.0.0",
"v8-to-istanbul": "^9.2.0"
},
@ -1520,17 +1521,17 @@
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
"vitest": "1.3.1"
"vitest": "1.4.0"
}
},
"node_modules/@vitest/expect": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.1.tgz",
"integrity": "sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.4.0.tgz",
"integrity": "sha512-Jths0sWCJZ8BxjKe+p+eKsoqev1/T8lYcrjavEaz8auEJ4jAVY0GwW3JKmdVU4mmNPLPHixh4GNXP7GFtAiDHA==",
"dev": true,
"dependencies": {
"@vitest/spy": "1.3.1",
"@vitest/utils": "1.3.1",
"@vitest/spy": "1.4.0",
"@vitest/utils": "1.4.0",
"chai": "^4.3.10"
},
"funding": {
@ -1538,12 +1539,12 @@
}
},
"node_modules/@vitest/runner": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.3.1.tgz",
"integrity": "sha512-5FzF9c3jG/z5bgCnjr8j9LNq/9OxV2uEBAITOXfoe3rdZJTdO7jzThth7FXv/6b+kdY65tpRQB7WaKhNZwX+Kg==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.4.0.tgz",
"integrity": "sha512-EDYVSmesqlQ4RD2VvWo3hQgTJ7ZrFQ2VSJdfiJiArkCerDAGeyF1i6dHkmySqk573jLp6d/cfqCN+7wUB5tLgg==",
"dev": true,
"dependencies": {
"@vitest/utils": "1.3.1",
"@vitest/utils": "1.4.0",
"p-limit": "^5.0.0",
"pathe": "^1.1.1"
},
@ -1552,9 +1553,9 @@
}
},
"node_modules/@vitest/snapshot": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.3.1.tgz",
"integrity": "sha512-EF++BZbt6RZmOlE3SuTPu/NfwBF6q4ABS37HHXzs2LUVPBLx2QoY/K0fKpRChSo8eLiuxcbCVfqKgx/dplCDuQ==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.4.0.tgz",
"integrity": "sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A==",
"dev": true,
"dependencies": {
"magic-string": "^0.30.5",
@ -1566,9 +1567,9 @@
}
},
"node_modules/@vitest/spy": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.3.1.tgz",
"integrity": "sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.4.0.tgz",
"integrity": "sha512-Ywau/Qs1DzM/8Uc+yA77CwSegizMlcgTJuYGAi0jujOteJOUf1ujunHThYo243KG9nAyWT3L9ifPYZ5+As/+6Q==",
"dev": true,
"dependencies": {
"tinyspy": "^2.2.0"
@ -1578,9 +1579,9 @@
}
},
"node_modules/@vitest/utils": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.3.1.tgz",
"integrity": "sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.4.0.tgz",
"integrity": "sha512-mx3Yd1/6e2Vt/PUC98DcqTirtfxUyAZ32uK82r8rZzbtBeBo+nqgnjx/LvqQdWsrvNtm14VmurNgcf4nqY5gJg==",
"dev": true,
"dependencies": {
"diff-sequences": "^29.6.3",
@ -2186,9 +2187,9 @@
}
},
"node_modules/esbuild": {
"version": "0.19.12",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz",
"integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==",
"version": "0.20.2",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz",
"integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==",
"dev": true,
"hasInstallScript": true,
"bin": {
@ -2198,29 +2199,29 @@
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.19.12",
"@esbuild/android-arm": "0.19.12",
"@esbuild/android-arm64": "0.19.12",
"@esbuild/android-x64": "0.19.12",
"@esbuild/darwin-arm64": "0.19.12",
"@esbuild/darwin-x64": "0.19.12",
"@esbuild/freebsd-arm64": "0.19.12",
"@esbuild/freebsd-x64": "0.19.12",
"@esbuild/linux-arm": "0.19.12",
"@esbuild/linux-arm64": "0.19.12",
"@esbuild/linux-ia32": "0.19.12",
"@esbuild/linux-loong64": "0.19.12",
"@esbuild/linux-mips64el": "0.19.12",
"@esbuild/linux-ppc64": "0.19.12",
"@esbuild/linux-riscv64": "0.19.12",
"@esbuild/linux-s390x": "0.19.12",
"@esbuild/linux-x64": "0.19.12",
"@esbuild/netbsd-x64": "0.19.12",
"@esbuild/openbsd-x64": "0.19.12",
"@esbuild/sunos-x64": "0.19.12",
"@esbuild/win32-arm64": "0.19.12",
"@esbuild/win32-ia32": "0.19.12",
"@esbuild/win32-x64": "0.19.12"
"@esbuild/aix-ppc64": "0.20.2",
"@esbuild/android-arm": "0.20.2",
"@esbuild/android-arm64": "0.20.2",
"@esbuild/android-x64": "0.20.2",
"@esbuild/darwin-arm64": "0.20.2",
"@esbuild/darwin-x64": "0.20.2",
"@esbuild/freebsd-arm64": "0.20.2",
"@esbuild/freebsd-x64": "0.20.2",
"@esbuild/linux-arm": "0.20.2",
"@esbuild/linux-arm64": "0.20.2",
"@esbuild/linux-ia32": "0.20.2",
"@esbuild/linux-loong64": "0.20.2",
"@esbuild/linux-mips64el": "0.20.2",
"@esbuild/linux-ppc64": "0.20.2",
"@esbuild/linux-riscv64": "0.20.2",
"@esbuild/linux-s390x": "0.20.2",
"@esbuild/linux-x64": "0.20.2",
"@esbuild/netbsd-x64": "0.20.2",
"@esbuild/openbsd-x64": "0.20.2",
"@esbuild/sunos-x64": "0.20.2",
"@esbuild/win32-arm64": "0.20.2",
"@esbuild/win32-ia32": "0.20.2",
"@esbuild/win32-x64": "0.20.2"
}
},
"node_modules/escalade": {
@ -3109,14 +3110,14 @@
}
},
"node_modules/istanbul-lib-source-maps": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
"integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.4.tgz",
"integrity": "sha512-wHOoEsNJTVltaJp8eVkm8w+GVkVNHT2YDYo53YdzQEL2gWm1hBX5cGFR9hQJtuGLebidVX7et3+dmDZrmclduw==",
"dev": true,
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.23",
"debug": "^4.1.1",
"istanbul-lib-coverage": "^3.0.0",
"source-map": "^0.6.1"
"istanbul-lib-coverage": "^3.0.0"
},
"engines": {
"node": ">=10"
@ -3920,9 +3921,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.35",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
"integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==",
"version": "8.4.37",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.37.tgz",
"integrity": "sha512-7iB/v/r7Woof0glKLH8b1SPHrsX7uhdO+Geb41QpF/+mWZHU3uxxSlN+UXGVit1PawOYDToO+AbZzhBzWRDwbQ==",
"dev": true,
"funding": [
{
@ -3941,7 +3942,7 @@
"dependencies": {
"nanoid": "^3.3.7",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
"source-map-js": "^1.2.0"
},
"engines": {
"node": "^10 || ^12 || >=14"
@ -4296,9 +4297,9 @@
}
},
"node_modules/rollup": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.12.0.tgz",
"integrity": "sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz",
"integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==",
"dev": true,
"dependencies": {
"@types/estree": "1.0.5"
@ -4311,19 +4312,19 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.12.0",
"@rollup/rollup-android-arm64": "4.12.0",
"@rollup/rollup-darwin-arm64": "4.12.0",
"@rollup/rollup-darwin-x64": "4.12.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.12.0",
"@rollup/rollup-linux-arm64-gnu": "4.12.0",
"@rollup/rollup-linux-arm64-musl": "4.12.0",
"@rollup/rollup-linux-riscv64-gnu": "4.12.0",
"@rollup/rollup-linux-x64-gnu": "4.12.0",
"@rollup/rollup-linux-x64-musl": "4.12.0",
"@rollup/rollup-win32-arm64-msvc": "4.12.0",
"@rollup/rollup-win32-ia32-msvc": "4.12.0",
"@rollup/rollup-win32-x64-msvc": "4.12.0",
"@rollup/rollup-android-arm-eabi": "4.13.0",
"@rollup/rollup-android-arm64": "4.13.0",
"@rollup/rollup-darwin-arm64": "4.13.0",
"@rollup/rollup-darwin-x64": "4.13.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.13.0",
"@rollup/rollup-linux-arm64-gnu": "4.13.0",
"@rollup/rollup-linux-arm64-musl": "4.13.0",
"@rollup/rollup-linux-riscv64-gnu": "4.13.0",
"@rollup/rollup-linux-x64-gnu": "4.13.0",
"@rollup/rollup-linux-x64-musl": "4.13.0",
"@rollup/rollup-win32-arm64-msvc": "4.13.0",
"@rollup/rollup-win32-ia32-msvc": "4.13.0",
"@rollup/rollup-win32-x64-msvc": "4.13.0",
"fsevents": "~2.3.2"
}
},
@ -4449,9 +4450,9 @@
}
},
"node_modules/socket.io-client": {
"version": "4.7.4",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz",
"integrity": "sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==",
"version": "4.7.5",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz",
"integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==",
"dev": true,
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
@ -4476,19 +4477,10 @@
"node": ">=10.0.0"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
"integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
@ -4886,14 +4878,14 @@
}
},
"node_modules/vite": {
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.1.4.tgz",
"integrity": "sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg==",
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.2.tgz",
"integrity": "sha512-FWZbz0oSdLq5snUI0b6sULbz58iXFXdvkZfZWR/F0ZJuKTSPO7v72QPXt6KqYeMFb0yytNp6kZosxJ96Nr/wDQ==",
"dev": true,
"dependencies": {
"esbuild": "^0.19.3",
"postcss": "^8.4.35",
"rollup": "^4.2.0"
"esbuild": "^0.20.1",
"postcss": "^8.4.36",
"rollup": "^4.13.0"
},
"bin": {
"vite": "bin/vite.js"
@ -4941,9 +4933,9 @@
}
},
"node_modules/vite-node": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.3.1.tgz",
"integrity": "sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.4.0.tgz",
"integrity": "sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==",
"dev": true,
"dependencies": {
"cac": "^6.7.14",
@ -4977,16 +4969,16 @@
}
},
"node_modules/vitest": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/vitest/-/vitest-1.3.1.tgz",
"integrity": "sha512-/1QJqXs8YbCrfv/GPQ05wAZf2eakUPLPa18vkJAKE7RXOKfVHqMZZ1WlTjiwl6Gcn65M5vpNUB6EFLnEdRdEXQ==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/vitest/-/vitest-1.4.0.tgz",
"integrity": "sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==",
"dev": true,
"dependencies": {
"@vitest/expect": "1.3.1",
"@vitest/runner": "1.3.1",
"@vitest/snapshot": "1.3.1",
"@vitest/spy": "1.3.1",
"@vitest/utils": "1.3.1",
"@vitest/expect": "1.4.0",
"@vitest/runner": "1.4.0",
"@vitest/snapshot": "1.4.0",
"@vitest/spy": "1.4.0",
"@vitest/utils": "1.4.0",
"acorn-walk": "^8.3.2",
"chai": "^4.3.10",
"debug": "^4.3.4",
@ -5000,7 +4992,7 @@
"tinybench": "^2.5.1",
"tinypool": "^0.8.2",
"vite": "^5.0.0",
"vite-node": "1.3.1",
"vite-node": "1.4.0",
"why-is-node-running": "^2.2.2"
},
"bin": {
@ -5015,8 +5007,8 @@
"peerDependencies": {
"@edge-runtime/vm": "*",
"@types/node": "^18.0.0 || >=20.0.0",
"@vitest/browser": "1.3.1",
"@vitest/ui": "1.3.1",
"@vitest/browser": "1.4.0",
"@vitest/ui": "1.4.0",
"happy-dom": "*",
"jsdom": "*"
},

View File

@ -1,6 +1,6 @@
{
"name": "immich-e2e",
"version": "1.98.2",
"version": "1.99.0",
"description": "",
"main": "index.js",
"type": "module",

View File

@ -12,7 +12,8 @@ describe('/audit', () => {
admin = await utils.adminSetup();
});
describe('GET :/file-report', () => {
// TODO: Enable these tests again once #7436 is resolved as these were flaky
describe.skip('GET :/file-report', () => {
it('excludes assets without issues from report', async () => {
const [trashedAsset, archivedAsset] = await Promise.all([
utils.createAsset(admin.accessToken),

View File

@ -1,6 +1,6 @@
[tool.poetry]
name = "machine-learning"
version = "1.98.2"
version = "1.99.0"
description = ""
authors = ["Hau Tran <alex.tran1502@gmail.com>"]
readme = "README.md"

View File

@ -35,8 +35,8 @@ platform :android do
task: 'bundle',
build_type: 'Release',
properties: {
"android.injected.version.code" => 128,
"android.injected.version.name" => "1.98.2",
"android.injected.version.code" => 129,
"android.injected.version.name" => "1.99.0",
}
)
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')

View File

@ -5,17 +5,17 @@
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000208">
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.00024">
</testcase>
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="76.932126">
<testcase classname="fastlane.lanes" name="1: bundleRelease" time="81.32752">
</testcase>
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="33.616364">
<testcase classname="fastlane.lanes" name="2: upload_to_play_store" time="26.041597">
</testcase>

View File

@ -190,6 +190,7 @@
"exif_bottom_sheet_location": "LOCATION",
"exif_bottom_sheet_location_add": "Add a location",
"exif_bottom_sheet_people": "PEOPLE",
"exif_bottom_sheet_person_add_person": "Add name",
"experimental_settings_new_asset_list_subtitle": "Work in progress",
"experimental_settings_new_asset_list_title": "Enable experimental photo grid",
"experimental_settings_subtitle": "Use at your own risk!",

View File

@ -383,7 +383,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 144;
CURRENT_PROJECT_VERSION = 145;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@ -525,7 +525,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 144;
CURRENT_PROJECT_VERSION = 145;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@ -553,7 +553,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 144;
CURRENT_PROJECT_VERSION = 145;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;

View File

@ -55,11 +55,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.98.2</string>
<string>1.99.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>144</string>
<string>145</string>
<key>FLTEnableImpeller</key>
<true/>
<key>ITSAppUsesNonExemptEncryption</key>

View File

@ -19,7 +19,7 @@ platform :ios do
desc "iOS Beta"
lane :beta do
increment_version_number(
version_number: "1.98.2"
version_number: "1.99.0"
)
increment_build_number(
build_number: latest_testflight_build_number + 1,

View File

@ -5,32 +5,32 @@
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000232">
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000246">
</testcase>
<testcase classname="fastlane.lanes" name="1: increment_version_number" time="0.745911">
<testcase classname="fastlane.lanes" name="1: increment_version_number" time="0.175843">
</testcase>
<testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="4.672711">
<testcase classname="fastlane.lanes" name="2: latest_testflight_build_number" time="6.871371">
</testcase>
<testcase classname="fastlane.lanes" name="3: increment_build_number" time="0.171883">
<testcase classname="fastlane.lanes" name="3: increment_build_number" time="0.189451">
</testcase>
<testcase classname="fastlane.lanes" name="4: build_app" time="112.172167">
<testcase classname="fastlane.lanes" name="4: build_app" time="142.078248">
</testcase>
<testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="98.918418">
<testcase classname="fastlane.lanes" name="5: upload_to_testflight" time="78.774821">
</testcase>

View File

@ -64,7 +64,7 @@ class ExifMap extends StatelessWidget {
}
return Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: LayoutBuilder(
builder: (context, constraints) {
return MapThumbnail(

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/modules/search/models/curated_content.dart';
import 'package:immich_mobile/modules/search/ui/thumbnail_with_info.dart';
@ -23,7 +24,7 @@ class CuratedPeopleRow extends StatelessWidget {
@override
Widget build(BuildContext context) {
const imageSize = 80.0;
const imageSize = 70.0;
// Guard empty [content]
if (content.isEmpty) {
@ -82,11 +83,11 @@ class CuratedPeopleRow extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
"Add name",
"exif_bottom_sheet_person_add_person",
style: context.textTheme.labelLarge?.copyWith(
color: context.primaryColor,
),
),
).tr(),
),
)
else

View File

@ -3,7 +3,7 @@ Immich API
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
- API version: 1.98.2
- API version: 1.99.0
- Build package: org.openapitools.codegen.languages.DartClientCodegen
## Requirements

View File

@ -2,7 +2,7 @@ name: immich_mobile
description: Immich - selfhosted backup media file on mobile phone
publish_to: 'none'
version: 1.98.2+128
version: 1.99.0+129
isar_version: &isar_version 3.1.0+1
environment:

View File

@ -6538,7 +6538,7 @@
"info": {
"title": "Immich",
"description": "Immich API",
"version": "1.98.2",
"version": "1.99.0",
"contact": {}
},
"tags": [],

View File

@ -1,12 +1,12 @@
{
"name": "@immich/sdk",
"version": "1.98.2",
"version": "1.99.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@immich/sdk",
"version": "1.98.2",
"version": "1.99.0",
"license": "GNU Affero General Public License version 3",
"dependencies": {
"@oazapfts/runtime": "^1.0.2"
@ -22,9 +22,9 @@
"integrity": "sha512-V33FjR6V+AkGRWYQW3XPm5BLn2loGl2ujSeja1TzdjjEn2zjGgl3ve0dcFf/jEwPZEOqQZl6YwIgIB/clXVqWw=="
},
"node_modules/@types/node": {
"version": "20.11.25",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz",
"integrity": "sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==",
"version": "20.11.28",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.28.tgz",
"integrity": "sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"

View File

@ -1,6 +1,6 @@
{
"name": "@immich/sdk",
"version": "1.98.2",
"version": "1.99.0",
"description": "Auto-generated TypeScript SDK for the Immich API",
"type": "module",
"main": "./build/index.js",

View File

@ -1,6 +1,6 @@
/**
* Immich
* 1.98.2
* 1.99.0
* DO NOT MODIFY - This file has been generated using oazapfts.
* See https://www.npmjs.com/package/oazapfts
*/

View File

@ -4,33 +4,28 @@
"minimumReleaseAge": "5 days",
"packageRules": [
{
"matchFileNames": ["cli/**"],
"groupName": "@immich/cli",
"matchUpdateTypes": ["minor", "patch"],
"schedule": "on tuesday"
},
{
"matchFileNames": ["docs/**"],
"groupName": "docs",
"matchUpdateTypes": ["minor", "patch"],
"schedule": "on tuesday"
},
{
"matchFileNames": ["mobile/**"],
"groupName": "mobile",
"matchUpdateTypes": ["minor", "patch"],
"schedule": "on tuesday"
},
{
"matchFileNames": ["server/**"],
"groupName": "server",
"matchFileNames": [
"cli/**",
"docs/**",
"e2e/**",
"open-api/**",
"server/**",
"web/**"
],
"groupName": "typescript-projects",
"matchUpdateTypes": ["minor", "patch"],
"excludePackagePrefixes": ["exiftool", "reflect-metadata"],
"schedule": "on tuesday"
},
{
"matchFileNames": ["open-api/**"],
"groupName": "open-api",
"matchFileNames": ["machine-learning/**"],
"groupName": "machine-learning",
"rangeStrategy": "in-range-only",
"schedule": "on tuesday"
},
{
"matchFileNames": ["mobile/**"],
"groupName": "mobile",
"matchUpdateTypes": ["minor", "patch"],
"schedule": "on tuesday"
},
@ -45,18 +40,6 @@
"matchPackagePrefixes": ["@sveltejs"],
"schedule": "on tuesday"
},
{
"matchFileNames": ["web/**"],
"groupName": "web",
"matchUpdateTypes": ["minor", "patch"],
"schedule": "on tuesday"
},
{
"matchFileNames": ["machine-learning/**"],
"groupName": "machine-learning",
"rangeStrategy": "in-range-only",
"schedule": "on tuesday"
},
{
"matchFileNames": [".github/**"],
"groupName": "github-actions",
@ -81,9 +64,6 @@
}
],
"ignorePaths": ["mobile/openapi/pubspec.yaml"],
"ignoreDeps": [
"http",
"intl"
],
"ignoreDeps": ["http", "intl"],
"labels": ["dependencies", "renovate"]
}

View File

@ -33,5 +33,6 @@ module.exports = {
'@typescript-eslint/require-await': 'error',
curly: 2,
'prettier/prettier': 0,
'no-restricted-imports': ['error', { patterns: [{ group: ['.*'], message: 'Relative imports are not allowed.' }] }],
},
};

View File

@ -1,5 +1,5 @@
# dev build
FROM ghcr.io/immich-app/base-server-dev:20240312@sha256:3cb168dd87a2b412b25c512ec638a1e7f362e1d3eb8dd19a38d92d4a7c47999c as dev
FROM ghcr.io/immich-app/base-server-dev:20240319@sha256:9c9492d59b51a0c340ea3f61a1c9a483122b86b008c7fbe1759d7b858c5e6af5 as dev
RUN apt-get install --no-install-recommends -yqq tini
WORKDIR /usr/src/app
@ -24,7 +24,7 @@ RUN npm prune --omit=dev --omit=optional
COPY --from=dev /usr/src/app/node_modules/@img ./node_modules/@img
# web build
FROM node:iron-alpine3.18@sha256:a02826c7340c37a29179152723190bcc3044f933c925f3c2d78abb20f794de3f as web
FROM node:iron-alpine3.18@sha256:876514790dabd49fae7d9c4dfbba027954bd91d8e7d36da76334466533bc6b0c as web
WORKDIR /usr/src/open-api/typescript-sdk
COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./
@ -40,7 +40,7 @@ RUN npm run build
# prod build
FROM ghcr.io/immich-app/base-server-prod:20240312@sha256:8359fb1acc56580f2b4835e273293fdaa99d273b210892e1485fc6f1e47cf2bb
FROM ghcr.io/immich-app/base-server-prod:20240319@sha256:6bfcb2f2b84d3070be95ab09ba614e2ff3e832e566a283f516a276a8ae6a147b
WORKDIR /usr/src/app
ENV NODE_ENV=production \

View File

@ -1,4 +1,4 @@
import { AssetResponseDto } from '@app/domain';
import { AssetResponseDto } from 'src/domain/asset/response-dto/asset-response.dto';
import request from 'supertest';
export const assetApi = {

View File

@ -1,6 +1,7 @@
import { LoginResponseDto, UserResponseDto } from '@app/domain';
import { adminSignupStub, loginResponseStub, loginStub } from '@test';
import { LoginResponseDto } from 'src/domain/auth/auth.dto';
import { UserResponseDto } from 'src/domain/user/response-dto/user-response.dto';
import request from 'supertest';
import { adminSignupStub, loginResponseStub, loginStub } from 'test/fixtures/auth.stub';
export const authApi = {
adminSignUp: async (server: any) => {

View File

@ -1,6 +1,6 @@
import { assetApi } from './asset-api';
import { authApi } from './auth-api';
import { libraryApi } from './library-api';
import { assetApi } from 'e2e/client/asset-api';
import { authApi } from 'e2e/client/auth-api';
import { libraryApi } from 'e2e/client/library-api';
export const api = {
authApi,

View File

@ -1,4 +1,4 @@
import { CreateLibraryDto, LibraryResponseDto, ScanLibraryDto } from '@app/domain';
import { CreateLibraryDto, LibraryResponseDto, ScanLibraryDto } from 'src/domain/library/library.dto';
import request from 'supertest';
export const libraryApi = {

View File

@ -16,9 +16,7 @@
],
"coverageDirectory": "./coverage",
"moduleNameMapper": {
"^@test(|/.*)$": "<rootDir>/test/$1",
"^@app/immich(|/.*)$": "<rootDir>/src/immich/$1",
"^@app/infra(|/.*)$": "<rootDir>/src/infra/$1",
"^@app/domain(|/.*)$": "<rootDir>/src/domain/$1"
"^test(|/.*)$": "<rootDir>/test/$1",
"^src(|/.*)$": "<rootDir>/src/$1"
}
}

View File

@ -1,15 +1,19 @@
import { LibraryResponseDto, LibraryService, LoginResponseDto, StorageEventType } from '@app/domain';
import { AssetType, LibraryType } from '@app/infra/entities';
import { api } from 'e2e/client';
import fs from 'node:fs/promises';
import path from 'node:path';
import { LoginResponseDto } from 'src/domain/auth/auth.dto';
import { LibraryResponseDto } from 'src/domain/library/library.dto';
import { LibraryService } from 'src/domain/library/library.service';
import { AssetType } from 'src/infra/entities/asset.entity';
import { LibraryType } from 'src/infra/entities/library.entity';
import { StorageEventType } from 'src/interfaces/storage.repository';
import {
IMMICH_TEST_ASSET_PATH,
IMMICH_TEST_ASSET_TEMP_PATH,
restoreTempFolder,
testApp,
waitForEvent,
} from '../../../src/test-utils/utils';
import { api } from '../../client';
} from 'src/test-utils/utils';
describe(`Library watcher (e2e)`, () => {
let server: any;

View File

@ -1,17 +1,13 @@
import { LoginResponseDto } from '@app/domain';
import { LibraryController } from '@app/immich';
import { LibraryType } from '@app/infra/entities';
import { errorStub, uuidStub } from '@test/fixtures';
import * as fs from 'node:fs';
import { api } from 'e2e/client';
import fs from 'node:fs';
import { LibraryController } from 'src/controllers/library.controller';
import { LoginResponseDto } from 'src/domain/auth/auth.dto';
import { LibraryType } from 'src/infra/entities/library.entity';
import { IMMICH_TEST_ASSET_PATH, IMMICH_TEST_ASSET_TEMP_PATH, restoreTempFolder, testApp } from 'src/test-utils/utils';
import request from 'supertest';
import { errorStub } from 'test/fixtures/error.stub';
import { uuidStub } from 'test/fixtures/uuid.stub';
import { utimes } from 'utimes';
import {
IMMICH_TEST_ASSET_PATH,
IMMICH_TEST_ASSET_TEMP_PATH,
restoreTempFolder,
testApp,
} from '../../../src/test-utils/utils';
import { api } from '../../client';
describe(`${LibraryController.name} (e2e)`, () => {
let server: any;

430
server/package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "immich",
"version": "1.98.2",
"version": "1.99.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "immich",
"version": "1.98.2",
"version": "1.99.0",
"license": "GNU Affero General Public License version 3",
"dependencies": {
"@babel/runtime": "^7.22.11",
@ -22,7 +22,7 @@
"@nestjs/swagger": "^7.1.8",
"@nestjs/typeorm": "^10.0.0",
"@nestjs/websockets": "^10.2.2",
"@opentelemetry/auto-instrumentations-node": "^0.42.0",
"@opentelemetry/auto-instrumentations-node": "^0.43.0",
"@opentelemetry/exporter-prometheus": "^0.49.0",
"@opentelemetry/sdk-node": "^0.49.0",
"@socket.io/postgres-adapter": "^0.3.1",
@ -81,7 +81,7 @@
"@types/mock-fs": "^4.13.1",
"@types/multer": "^1.4.7",
"@types/node": "^20.5.7",
"@types/sharp": "^0.31.1",
"@types/sharp": "^0.32.0",
"@types/supertest": "^6.0.0",
"@types/ua-parser-js": "^0.7.36",
"@typescript-eslint/eslint-plugin": "^7.0.0",
@ -1719,9 +1719,12 @@
}
},
"node_modules/@immich/cli": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@immich/cli/-/cli-2.0.7.tgz",
"integrity": "sha512-36bpL7SCnbWuaHwuvVmV0iw2dgxX6umk3DhQ5rThJ6C9vOVZs8WY2zMU0voTATlEPoJkpwcQTOMLKFLTPL5OJw==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@immich/cli/-/cli-2.1.0.tgz",
"integrity": "sha512-3s/8+Js1dAwibzgaRtZ+bsAL9nOtvoEX/qMlOTgbgLf/lT96M88QScqhb+YrU2l3WBugtts6xW76XQTrWGXcmw==",
"dependencies": {
"lodash-es": "^4.17.21"
},
"bin": {
"immich": "dist/index.js"
},
@ -2909,25 +2912,25 @@
}
},
"node_modules/@opentelemetry/auto-instrumentations-node": {
"version": "0.42.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.42.0.tgz",
"integrity": "sha512-fxcB7My5QTVfX6kBH4r5OFduGSxdpROgyIu7CqClp1psFHfVaBMQd4lbK2u+39K5kbjzJT2OaUP8yQuAvKJqBg==",
"version": "0.43.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.43.0.tgz",
"integrity": "sha512-2WvHUSi/QVeVG8ObPD0Ls6WevfIbQjspxIQRuHaQFWXhmEwy/MsEcoQUjbNKXwO5516aS04GTydKEoRKsMwhdA==",
"dependencies": {
"@opentelemetry/instrumentation": "^0.49.1",
"@opentelemetry/instrumentation-amqplib": "^0.35.0",
"@opentelemetry/instrumentation-aws-lambda": "^0.39.0",
"@opentelemetry/instrumentation-aws-sdk": "^0.39.0",
"@opentelemetry/instrumentation-aws-sdk": "^0.39.1",
"@opentelemetry/instrumentation-bunyan": "^0.36.0",
"@opentelemetry/instrumentation-cassandra-driver": "^0.36.0",
"@opentelemetry/instrumentation-connect": "^0.34.0",
"@opentelemetry/instrumentation-cucumber": "^0.4.0",
"@opentelemetry/instrumentation-dataloader": "^0.7.0",
"@opentelemetry/instrumentation-dns": "^0.34.0",
"@opentelemetry/instrumentation-express": "^0.36.0",
"@opentelemetry/instrumentation-express": "^0.36.1",
"@opentelemetry/instrumentation-fastify": "^0.34.0",
"@opentelemetry/instrumentation-fs": "^0.10.0",
"@opentelemetry/instrumentation-generic-pool": "^0.34.0",
"@opentelemetry/instrumentation-graphql": "^0.38.0",
"@opentelemetry/instrumentation-graphql": "^0.38.1",
"@opentelemetry/instrumentation-grpc": "^0.49.1",
"@opentelemetry/instrumentation-hapi": "^0.35.0",
"@opentelemetry/instrumentation-http": "^0.49.1",
@ -2936,13 +2939,13 @@
"@opentelemetry/instrumentation-koa": "^0.38.0",
"@opentelemetry/instrumentation-lru-memoizer": "^0.35.0",
"@opentelemetry/instrumentation-memcached": "^0.34.0",
"@opentelemetry/instrumentation-mongodb": "^0.40.0",
"@opentelemetry/instrumentation-mongodb": "^0.41.0",
"@opentelemetry/instrumentation-mongoose": "^0.36.0",
"@opentelemetry/instrumentation-mysql": "^0.36.0",
"@opentelemetry/instrumentation-mysql2": "^0.36.0",
"@opentelemetry/instrumentation-nestjs-core": "^0.35.0",
"@opentelemetry/instrumentation-net": "^0.34.0",
"@opentelemetry/instrumentation-pg": "^0.39.0",
"@opentelemetry/instrumentation-pg": "^0.39.1",
"@opentelemetry/instrumentation-pino": "^0.36.0",
"@opentelemetry/instrumentation-redis": "^0.37.0",
"@opentelemetry/instrumentation-redis-4": "^0.37.0",
@ -3464,9 +3467,9 @@
}
},
"node_modules/@opentelemetry/instrumentation-mongodb": {
"version": "0.40.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.40.0.tgz",
"integrity": "sha512-ldlJUW/1UlnGtIWBt7fIUl+7+TGOKxIU+0Js5ukpXfQc07ENYFeck5TdbFjvYtF8GppPErnsZJiFiRdYm6Pv/Q==",
"version": "0.41.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.41.0.tgz",
"integrity": "sha512-DlSH0oyEuTW5gprCUppb0Qe3pK3cpUUFW5eTmayWNyICI1LFunwtcrULTNv6UiThD/V5ykAf/GGGEa7KFAmkog==",
"dependencies": {
"@opentelemetry/instrumentation": "^0.49.1",
"@opentelemetry/sdk-metrics": "^1.9.1",
@ -4644,9 +4647,9 @@
}
},
"node_modules/@types/lodash": {
"version": "4.14.202",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz",
"integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==",
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz",
"integrity": "sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==",
"dev": true
},
"node_modules/@types/luxon": {
@ -4705,9 +4708,9 @@
}
},
"node_modules/@types/node": {
"version": "20.11.25",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz",
"integrity": "sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==",
"version": "20.11.28",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.28.tgz",
"integrity": "sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==",
"dependencies": {
"undici-types": "~5.26.4"
}
@ -4838,12 +4841,13 @@
}
},
"node_modules/@types/sharp": {
"version": "0.31.1",
"resolved": "https://registry.npmjs.org/@types/sharp/-/sharp-0.31.1.tgz",
"integrity": "sha512-5nWwamN9ZFHXaYEincMSuza8nNfOof8nmO+mcI+Agx1uMUk4/pQnNIcix+9rLPXzKrm1pS34+6WRDbDV0Jn7ag==",
"version": "0.32.0",
"resolved": "https://registry.npmjs.org/@types/sharp/-/sharp-0.32.0.tgz",
"integrity": "sha512-OOi3kL+FZDnPhVzsfD37J88FNeZh6gQsGcLc95NbeURRGvmSjeXiDcyWzF2o3yh/gQAUn2uhh/e+CPCa5nwAxw==",
"deprecated": "This is a stub types definition. sharp provides its own type definitions, so you do not need this installed.",
"dev": true,
"dependencies": {
"@types/node": "*"
"sharp": "*"
}
},
"node_modules/@types/shimmer": {
@ -4941,16 +4945,16 @@
"dev": true
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.1.tgz",
"integrity": "sha512-zioDz623d0RHNhvx0eesUmGfIjzrk18nSBC8xewepKXbBvN/7c1qImV7Hg8TI1URTxKax7/zxfxj3Uph8Chcuw==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.2.0.tgz",
"integrity": "sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw==",
"dev": true,
"dependencies": {
"@eslint-community/regexpp": "^4.5.1",
"@typescript-eslint/scope-manager": "7.1.1",
"@typescript-eslint/type-utils": "7.1.1",
"@typescript-eslint/utils": "7.1.1",
"@typescript-eslint/visitor-keys": "7.1.1",
"@typescript-eslint/scope-manager": "7.2.0",
"@typescript-eslint/type-utils": "7.2.0",
"@typescript-eslint/utils": "7.2.0",
"@typescript-eslint/visitor-keys": "7.2.0",
"debug": "^4.3.4",
"graphemer": "^1.4.0",
"ignore": "^5.2.4",
@ -4976,15 +4980,15 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.1.tgz",
"integrity": "sha512-ZWUFyL0z04R1nAEgr9e79YtV5LbafdOtN7yapNbn1ansMyaegl2D4bL7vHoJ4HPSc4CaLwuCVas8CVuneKzplQ==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz",
"integrity": "sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==",
"dev": true,
"dependencies": {
"@typescript-eslint/scope-manager": "7.1.1",
"@typescript-eslint/types": "7.1.1",
"@typescript-eslint/typescript-estree": "7.1.1",
"@typescript-eslint/visitor-keys": "7.1.1",
"@typescript-eslint/scope-manager": "7.2.0",
"@typescript-eslint/types": "7.2.0",
"@typescript-eslint/typescript-estree": "7.2.0",
"@typescript-eslint/visitor-keys": "7.2.0",
"debug": "^4.3.4"
},
"engines": {
@ -5004,13 +5008,13 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.1.tgz",
"integrity": "sha512-cirZpA8bJMRb4WZ+rO6+mnOJrGFDd38WoXCEI57+CYBqta8Yc8aJym2i7vyqLL1vVYljgw0X27axkUXz32T8TA==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz",
"integrity": "sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "7.1.1",
"@typescript-eslint/visitor-keys": "7.1.1"
"@typescript-eslint/types": "7.2.0",
"@typescript-eslint/visitor-keys": "7.2.0"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
@ -5021,13 +5025,13 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.1.tgz",
"integrity": "sha512-5r4RKze6XHEEhlZnJtR3GYeCh1IueUHdbrukV2KSlLXaTjuSfeVF8mZUVPLovidCuZfbVjfhi4c0DNSa/Rdg5g==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.2.0.tgz",
"integrity": "sha512-xHi51adBHo9O9330J8GQYQwrKBqbIPJGZZVQTHHmy200hvkLZFWJIFtAG/7IYTWUyun6DE6w5InDReePJYJlJA==",
"dev": true,
"dependencies": {
"@typescript-eslint/typescript-estree": "7.1.1",
"@typescript-eslint/utils": "7.1.1",
"@typescript-eslint/typescript-estree": "7.2.0",
"@typescript-eslint/utils": "7.2.0",
"debug": "^4.3.4",
"ts-api-utils": "^1.0.1"
},
@ -5048,9 +5052,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.1.tgz",
"integrity": "sha512-KhewzrlRMrgeKm1U9bh2z5aoL4s7K3tK5DwHDn8MHv0yQfWFz/0ZR6trrIHHa5CsF83j/GgHqzdbzCXJ3crx0Q==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.2.0.tgz",
"integrity": "sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==",
"dev": true,
"engines": {
"node": "^16.0.0 || >=18.0.0"
@ -5061,13 +5065,13 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.1.tgz",
"integrity": "sha512-9ZOncVSfr+sMXVxxca2OJOPagRwT0u/UHikM2Rd6L/aB+kL/QAuTnsv6MeXtjzCJYb8PzrXarypSGIPx3Jemxw==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz",
"integrity": "sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "7.1.1",
"@typescript-eslint/visitor-keys": "7.1.1",
"@typescript-eslint/types": "7.2.0",
"@typescript-eslint/visitor-keys": "7.2.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -5113,17 +5117,17 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.1.tgz",
"integrity": "sha512-thOXM89xA03xAE0lW7alstvnyoBUbBX38YtY+zAUcpRPcq9EIhXPuJ0YTv948MbzmKh6e1AUszn5cBFK49Umqg==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.2.0.tgz",
"integrity": "sha512-YfHpnMAGb1Eekpm3XRK8hcMwGLGsnT6L+7b2XyRv6ouDuJU1tZir1GS2i0+VXRatMwSI1/UfcyPe53ADkU+IuA==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
"@types/json-schema": "^7.0.12",
"@types/semver": "^7.5.0",
"@typescript-eslint/scope-manager": "7.1.1",
"@typescript-eslint/types": "7.1.1",
"@typescript-eslint/typescript-estree": "7.1.1",
"@typescript-eslint/scope-manager": "7.2.0",
"@typescript-eslint/types": "7.2.0",
"@typescript-eslint/typescript-estree": "7.2.0",
"semver": "^7.5.4"
},
"engines": {
@ -5138,12 +5142,12 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.1.tgz",
"integrity": "sha512-yTdHDQxY7cSoCcAtiBzVzxleJhkGB9NncSIyMYe2+OGON1ZsP9zOPws/Pqgopa65jvknOjlk/w7ulPlZ78PiLQ==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz",
"integrity": "sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "7.1.1",
"@typescript-eslint/types": "7.2.0",
"eslint-visitor-keys": "^3.4.1"
},
"engines": {
@ -5530,38 +5534,77 @@
"integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ=="
},
"node_modules/archiver": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.0.tgz",
"integrity": "sha512-R9HM9egs8FfktSqUqyjlKmvF4U+CWNqm/2tlROV+lOFg79MLdT67ae1l3hU47pGy8twSXxHoiefMCh43w0BriQ==",
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz",
"integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==",
"dependencies": {
"archiver-utils": "^5.0.0",
"archiver-utils": "^5.0.2",
"async": "^3.2.4",
"buffer-crc32": "^1.0.0",
"readable-stream": "^4.0.0",
"readdir-glob": "^1.1.2",
"tar-stream": "^3.0.0",
"zip-stream": "^6.0.0"
"zip-stream": "^6.0.1"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/archiver-utils": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.1.tgz",
"integrity": "sha512-MMAoLdMvT/nckofX1tCLrf7uJce4jTNkiT6smA2u57AOImc1nce7mR3EDujxL5yv6/MnILuQH4sAsPtDS8kTvg==",
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz",
"integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==",
"dependencies": {
"glob": "^10.0.0",
"graceful-fs": "^4.2.0",
"is-stream": "^2.0.1",
"lazystream": "^1.0.0",
"lodash": "^4.17.15",
"normalize-path": "^3.0.0",
"readable-stream": "^3.6.0"
"readable-stream": "^4.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/archiver-utils/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/archiver-utils/node_modules/readable-stream": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
"integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
"dependencies": {
"abort-controller": "^3.0.0",
"buffer": "^6.0.3",
"events": "^3.3.0",
"process": "^0.11.10",
"string_decoder": "^1.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/archiver/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
@ -6586,12 +6629,13 @@
"dev": true
},
"node_modules/compress-commons": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.1.tgz",
"integrity": "sha512-l7occIJn8YwlCEbWUCrG6gPms9qnJTCZSaznCa5HaV+yJMH4kM8BDc7q9NyoQuoiB2O6jKgTcTeY462qw6MyHw==",
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz",
"integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==",
"dependencies": {
"crc-32": "^1.2.0",
"crc32-stream": "^6.0.0",
"is-stream": "^2.0.1",
"normalize-path": "^3.0.0",
"readable-stream": "^4.0.0"
},
@ -8369,9 +8413,9 @@
}
},
"node_modules/geo-tz": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/geo-tz/-/geo-tz-8.0.1.tgz",
"integrity": "sha512-hpFbw3NKFOVy461NrWIt6Z6JQpGnMpYvNpvDunIrixbHsBPOnDcrfao0p+o/7gsMJnkhSYnTJ9DkyV2tXBLI8w==",
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/geo-tz/-/geo-tz-8.0.2.tgz",
"integrity": "sha512-NjEzJBzaMhO9C7lFZIsWDkVED7aLxcES3iEZOWJ97dhnDUGhEB8vhW7MaWR+2y4aWvtFV/VyuDi8Y0rUHvm4tw==",
"dependencies": {
"@turf/boolean-point-in-polygon": "^6.5.0",
"@turf/helpers": "^6.5.0",
@ -10118,6 +10162,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
},
"node_modules/lodash.camelcase": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
@ -14473,12 +14522,12 @@
}
},
"node_modules/zip-stream": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.0.tgz",
"integrity": "sha512-X0WFquRRDtL9HR9hc1OrabOP/VKJEX7gAr2geayt3b7dLgXgSXI6ucC4CphLQP/aQt2GyHIYgmXxtC+dVdghAQ==",
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz",
"integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==",
"dependencies": {
"archiver-utils": "^5.0.0",
"compress-commons": "^6.0.0",
"compress-commons": "^6.0.2",
"readable-stream": "^4.0.0"
},
"engines": {
@ -15553,9 +15602,12 @@
"optional": true
},
"@immich/cli": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@immich/cli/-/cli-2.0.7.tgz",
"integrity": "sha512-36bpL7SCnbWuaHwuvVmV0iw2dgxX6umk3DhQ5rThJ6C9vOVZs8WY2zMU0voTATlEPoJkpwcQTOMLKFLTPL5OJw=="
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@immich/cli/-/cli-2.1.0.tgz",
"integrity": "sha512-3s/8+Js1dAwibzgaRtZ+bsAL9nOtvoEX/qMlOTgbgLf/lT96M88QScqhb+YrU2l3WBugtts6xW76XQTrWGXcmw==",
"requires": {
"lodash-es": "^4.17.21"
}
},
"@ioredis/commands": {
"version": "1.2.0",
@ -16357,25 +16409,25 @@
}
},
"@opentelemetry/auto-instrumentations-node": {
"version": "0.42.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.42.0.tgz",
"integrity": "sha512-fxcB7My5QTVfX6kBH4r5OFduGSxdpROgyIu7CqClp1psFHfVaBMQd4lbK2u+39K5kbjzJT2OaUP8yQuAvKJqBg==",
"version": "0.43.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.43.0.tgz",
"integrity": "sha512-2WvHUSi/QVeVG8ObPD0Ls6WevfIbQjspxIQRuHaQFWXhmEwy/MsEcoQUjbNKXwO5516aS04GTydKEoRKsMwhdA==",
"requires": {
"@opentelemetry/instrumentation": "^0.49.1",
"@opentelemetry/instrumentation-amqplib": "^0.35.0",
"@opentelemetry/instrumentation-aws-lambda": "^0.39.0",
"@opentelemetry/instrumentation-aws-sdk": "^0.39.0",
"@opentelemetry/instrumentation-aws-sdk": "^0.39.1",
"@opentelemetry/instrumentation-bunyan": "^0.36.0",
"@opentelemetry/instrumentation-cassandra-driver": "^0.36.0",
"@opentelemetry/instrumentation-connect": "^0.34.0",
"@opentelemetry/instrumentation-cucumber": "^0.4.0",
"@opentelemetry/instrumentation-dataloader": "^0.7.0",
"@opentelemetry/instrumentation-dns": "^0.34.0",
"@opentelemetry/instrumentation-express": "^0.36.0",
"@opentelemetry/instrumentation-express": "^0.36.1",
"@opentelemetry/instrumentation-fastify": "^0.34.0",
"@opentelemetry/instrumentation-fs": "^0.10.0",
"@opentelemetry/instrumentation-generic-pool": "^0.34.0",
"@opentelemetry/instrumentation-graphql": "^0.38.0",
"@opentelemetry/instrumentation-graphql": "^0.38.1",
"@opentelemetry/instrumentation-grpc": "^0.49.1",
"@opentelemetry/instrumentation-hapi": "^0.35.0",
"@opentelemetry/instrumentation-http": "^0.49.1",
@ -16384,13 +16436,13 @@
"@opentelemetry/instrumentation-koa": "^0.38.0",
"@opentelemetry/instrumentation-lru-memoizer": "^0.35.0",
"@opentelemetry/instrumentation-memcached": "^0.34.0",
"@opentelemetry/instrumentation-mongodb": "^0.40.0",
"@opentelemetry/instrumentation-mongodb": "^0.41.0",
"@opentelemetry/instrumentation-mongoose": "^0.36.0",
"@opentelemetry/instrumentation-mysql": "^0.36.0",
"@opentelemetry/instrumentation-mysql2": "^0.36.0",
"@opentelemetry/instrumentation-nestjs-core": "^0.35.0",
"@opentelemetry/instrumentation-net": "^0.34.0",
"@opentelemetry/instrumentation-pg": "^0.39.0",
"@opentelemetry/instrumentation-pg": "^0.39.1",
"@opentelemetry/instrumentation-pino": "^0.36.0",
"@opentelemetry/instrumentation-redis": "^0.37.0",
"@opentelemetry/instrumentation-redis-4": "^0.37.0",
@ -16721,9 +16773,9 @@
}
},
"@opentelemetry/instrumentation-mongodb": {
"version": "0.40.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.40.0.tgz",
"integrity": "sha512-ldlJUW/1UlnGtIWBt7fIUl+7+TGOKxIU+0Js5ukpXfQc07ENYFeck5TdbFjvYtF8GppPErnsZJiFiRdYm6Pv/Q==",
"version": "0.41.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.41.0.tgz",
"integrity": "sha512-DlSH0oyEuTW5gprCUppb0Qe3pK3cpUUFW5eTmayWNyICI1LFunwtcrULTNv6UiThD/V5ykAf/GGGEa7KFAmkog==",
"requires": {
"@opentelemetry/instrumentation": "^0.49.1",
"@opentelemetry/sdk-metrics": "^1.9.1",
@ -17668,9 +17720,9 @@
}
},
"@types/lodash": {
"version": "4.14.202",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz",
"integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==",
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz",
"integrity": "sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==",
"dev": true
},
"@types/luxon": {
@ -17729,9 +17781,9 @@
}
},
"@types/node": {
"version": "20.11.25",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz",
"integrity": "sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==",
"version": "20.11.28",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.28.tgz",
"integrity": "sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==",
"requires": {
"undici-types": "~5.26.4"
}
@ -17849,12 +17901,12 @@
}
},
"@types/sharp": {
"version": "0.31.1",
"resolved": "https://registry.npmjs.org/@types/sharp/-/sharp-0.31.1.tgz",
"integrity": "sha512-5nWwamN9ZFHXaYEincMSuza8nNfOof8nmO+mcI+Agx1uMUk4/pQnNIcix+9rLPXzKrm1pS34+6WRDbDV0Jn7ag==",
"version": "0.32.0",
"resolved": "https://registry.npmjs.org/@types/sharp/-/sharp-0.32.0.tgz",
"integrity": "sha512-OOi3kL+FZDnPhVzsfD37J88FNeZh6gQsGcLc95NbeURRGvmSjeXiDcyWzF2o3yh/gQAUn2uhh/e+CPCa5nwAxw==",
"dev": true,
"requires": {
"@types/node": "*"
"sharp": "*"
}
},
"@types/shimmer": {
@ -17952,16 +18004,16 @@
"dev": true
},
"@typescript-eslint/eslint-plugin": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.1.tgz",
"integrity": "sha512-zioDz623d0RHNhvx0eesUmGfIjzrk18nSBC8xewepKXbBvN/7c1qImV7Hg8TI1URTxKax7/zxfxj3Uph8Chcuw==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.2.0.tgz",
"integrity": "sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw==",
"dev": true,
"requires": {
"@eslint-community/regexpp": "^4.5.1",
"@typescript-eslint/scope-manager": "7.1.1",
"@typescript-eslint/type-utils": "7.1.1",
"@typescript-eslint/utils": "7.1.1",
"@typescript-eslint/visitor-keys": "7.1.1",
"@typescript-eslint/scope-manager": "7.2.0",
"@typescript-eslint/type-utils": "7.2.0",
"@typescript-eslint/utils": "7.2.0",
"@typescript-eslint/visitor-keys": "7.2.0",
"debug": "^4.3.4",
"graphemer": "^1.4.0",
"ignore": "^5.2.4",
@ -17971,54 +18023,54 @@
}
},
"@typescript-eslint/parser": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.1.tgz",
"integrity": "sha512-ZWUFyL0z04R1nAEgr9e79YtV5LbafdOtN7yapNbn1ansMyaegl2D4bL7vHoJ4HPSc4CaLwuCVas8CVuneKzplQ==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz",
"integrity": "sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "7.1.1",
"@typescript-eslint/types": "7.1.1",
"@typescript-eslint/typescript-estree": "7.1.1",
"@typescript-eslint/visitor-keys": "7.1.1",
"@typescript-eslint/scope-manager": "7.2.0",
"@typescript-eslint/types": "7.2.0",
"@typescript-eslint/typescript-estree": "7.2.0",
"@typescript-eslint/visitor-keys": "7.2.0",
"debug": "^4.3.4"
}
},
"@typescript-eslint/scope-manager": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.1.tgz",
"integrity": "sha512-cirZpA8bJMRb4WZ+rO6+mnOJrGFDd38WoXCEI57+CYBqta8Yc8aJym2i7vyqLL1vVYljgw0X27axkUXz32T8TA==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz",
"integrity": "sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==",
"dev": true,
"requires": {
"@typescript-eslint/types": "7.1.1",
"@typescript-eslint/visitor-keys": "7.1.1"
"@typescript-eslint/types": "7.2.0",
"@typescript-eslint/visitor-keys": "7.2.0"
}
},
"@typescript-eslint/type-utils": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.1.tgz",
"integrity": "sha512-5r4RKze6XHEEhlZnJtR3GYeCh1IueUHdbrukV2KSlLXaTjuSfeVF8mZUVPLovidCuZfbVjfhi4c0DNSa/Rdg5g==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.2.0.tgz",
"integrity": "sha512-xHi51adBHo9O9330J8GQYQwrKBqbIPJGZZVQTHHmy200hvkLZFWJIFtAG/7IYTWUyun6DE6w5InDReePJYJlJA==",
"dev": true,
"requires": {
"@typescript-eslint/typescript-estree": "7.1.1",
"@typescript-eslint/utils": "7.1.1",
"@typescript-eslint/typescript-estree": "7.2.0",
"@typescript-eslint/utils": "7.2.0",
"debug": "^4.3.4",
"ts-api-utils": "^1.0.1"
}
},
"@typescript-eslint/types": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.1.tgz",
"integrity": "sha512-KhewzrlRMrgeKm1U9bh2z5aoL4s7K3tK5DwHDn8MHv0yQfWFz/0ZR6trrIHHa5CsF83j/GgHqzdbzCXJ3crx0Q==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.2.0.tgz",
"integrity": "sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.1.tgz",
"integrity": "sha512-9ZOncVSfr+sMXVxxca2OJOPagRwT0u/UHikM2Rd6L/aB+kL/QAuTnsv6MeXtjzCJYb8PzrXarypSGIPx3Jemxw==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz",
"integrity": "sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==",
"dev": true,
"requires": {
"@typescript-eslint/types": "7.1.1",
"@typescript-eslint/visitor-keys": "7.1.1",
"@typescript-eslint/types": "7.2.0",
"@typescript-eslint/visitor-keys": "7.2.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -18048,27 +18100,27 @@
}
},
"@typescript-eslint/utils": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.1.tgz",
"integrity": "sha512-thOXM89xA03xAE0lW7alstvnyoBUbBX38YtY+zAUcpRPcq9EIhXPuJ0YTv948MbzmKh6e1AUszn5cBFK49Umqg==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.2.0.tgz",
"integrity": "sha512-YfHpnMAGb1Eekpm3XRK8hcMwGLGsnT6L+7b2XyRv6ouDuJU1tZir1GS2i0+VXRatMwSI1/UfcyPe53ADkU+IuA==",
"dev": true,
"requires": {
"@eslint-community/eslint-utils": "^4.4.0",
"@types/json-schema": "^7.0.12",
"@types/semver": "^7.5.0",
"@typescript-eslint/scope-manager": "7.1.1",
"@typescript-eslint/types": "7.1.1",
"@typescript-eslint/typescript-estree": "7.1.1",
"@typescript-eslint/scope-manager": "7.2.0",
"@typescript-eslint/types": "7.2.0",
"@typescript-eslint/typescript-estree": "7.2.0",
"semver": "^7.5.4"
}
},
"@typescript-eslint/visitor-keys": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.1.tgz",
"integrity": "sha512-yTdHDQxY7cSoCcAtiBzVzxleJhkGB9NncSIyMYe2+OGON1ZsP9zOPws/Pqgopa65jvknOjlk/w7ulPlZ78PiLQ==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz",
"integrity": "sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==",
"dev": true,
"requires": {
"@typescript-eslint/types": "7.1.1",
"@typescript-eslint/types": "7.2.0",
"eslint-visitor-keys": "^3.4.1"
}
},
@ -18382,17 +18434,17 @@
"integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ=="
},
"archiver": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.0.tgz",
"integrity": "sha512-R9HM9egs8FfktSqUqyjlKmvF4U+CWNqm/2tlROV+lOFg79MLdT67ae1l3hU47pGy8twSXxHoiefMCh43w0BriQ==",
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz",
"integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==",
"requires": {
"archiver-utils": "^5.0.0",
"archiver-utils": "^5.0.2",
"async": "^3.2.4",
"buffer-crc32": "^1.0.0",
"readable-stream": "^4.0.0",
"readdir-glob": "^1.1.2",
"tar-stream": "^3.0.0",
"zip-stream": "^6.0.0"
"zip-stream": "^6.0.1"
},
"dependencies": {
"buffer": {
@ -18424,16 +18476,40 @@
}
},
"archiver-utils": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.1.tgz",
"integrity": "sha512-MMAoLdMvT/nckofX1tCLrf7uJce4jTNkiT6smA2u57AOImc1nce7mR3EDujxL5yv6/MnILuQH4sAsPtDS8kTvg==",
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz",
"integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==",
"requires": {
"glob": "^10.0.0",
"graceful-fs": "^4.2.0",
"is-stream": "^2.0.1",
"lazystream": "^1.0.0",
"lodash": "^4.17.15",
"normalize-path": "^3.0.0",
"readable-stream": "^3.6.0"
"readable-stream": "^4.0.0"
},
"dependencies": {
"buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"requires": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"readable-stream": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
"integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
"requires": {
"abort-controller": "^3.0.0",
"buffer": "^6.0.3",
"events": "^3.3.0",
"process": "^0.11.10",
"string_decoder": "^1.3.0"
}
}
}
},
"are-we-there-yet": {
@ -19164,12 +19240,13 @@
"dev": true
},
"compress-commons": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.1.tgz",
"integrity": "sha512-l7occIJn8YwlCEbWUCrG6gPms9qnJTCZSaznCa5HaV+yJMH4kM8BDc7q9NyoQuoiB2O6jKgTcTeY462qw6MyHw==",
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz",
"integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==",
"requires": {
"crc-32": "^1.2.0",
"crc32-stream": "^6.0.0",
"is-stream": "^2.0.1",
"normalize-path": "^3.0.0",
"readable-stream": "^4.0.0"
},
@ -20512,9 +20589,9 @@
"dev": true
},
"geo-tz": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/geo-tz/-/geo-tz-8.0.1.tgz",
"integrity": "sha512-hpFbw3NKFOVy461NrWIt6Z6JQpGnMpYvNpvDunIrixbHsBPOnDcrfao0p+o/7gsMJnkhSYnTJ9DkyV2tXBLI8w==",
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/geo-tz/-/geo-tz-8.0.2.tgz",
"integrity": "sha512-NjEzJBzaMhO9C7lFZIsWDkVED7aLxcES3iEZOWJ97dhnDUGhEB8vhW7MaWR+2y4aWvtFV/VyuDi8Y0rUHvm4tw==",
"requires": {
"@turf/boolean-point-in-polygon": "^6.5.0",
"@turf/helpers": "^6.5.0",
@ -21806,6 +21883,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
},
"lodash.camelcase": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
@ -24991,12 +25073,12 @@
"dev": true
},
"zip-stream": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.0.tgz",
"integrity": "sha512-X0WFquRRDtL9HR9hc1OrabOP/VKJEX7gAr2geayt3b7dLgXgSXI6ucC4CphLQP/aQt2GyHIYgmXxtC+dVdghAQ==",
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz",
"integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==",
"requires": {
"archiver-utils": "^5.0.0",
"compress-commons": "^6.0.0",
"compress-commons": "^6.0.2",
"readable-stream": "^4.0.0"
},
"dependencies": {

View File

@ -1,6 +1,6 @@
{
"name": "immich",
"version": "1.98.2",
"version": "1.99.0",
"description": "",
"author": "",
"private": true,
@ -46,7 +46,7 @@
"@nestjs/swagger": "^7.1.8",
"@nestjs/typeorm": "^10.0.0",
"@nestjs/websockets": "^10.2.2",
"@opentelemetry/auto-instrumentations-node": "^0.42.0",
"@opentelemetry/auto-instrumentations-node": "^0.43.0",
"@opentelemetry/exporter-prometheus": "^0.49.0",
"@opentelemetry/sdk-node": "^0.49.0",
"@socket.io/postgres-adapter": "^0.3.1",
@ -105,7 +105,7 @@
"@types/mock-fs": "^4.13.1",
"@types/multer": "^1.4.7",
"@types/node": "^20.5.7",
"@types/sharp": "^0.31.1",
"@types/sharp": "^0.32.0",
"@types/supertest": "^6.0.0",
"@types/ua-parser-js": "^0.7.36",
"@typescript-eslint/eslint-plugin": "^7.0.0",
@ -154,16 +154,14 @@
"./src/domain/": {
"branches": 75,
"functions": 80,
"lines": 90,
"statements": 90
"lines": 85,
"statements": 85
}
},
"testEnvironment": "node",
"moduleNameMapper": {
"^@test(|/.*)$": "<rootDir>/test/$1",
"^@app/immich(|/.*)$": "<rootDir>/src/immich/$1",
"^@app/infra(|/.*)$": "<rootDir>/src/infra/$1",
"^@app/domain(|/.*)$": "<rootDir>/src/domain/$1"
"^test(|/.*)$": "<rootDir>/test/$1",
"^src(|/.*)$": "<rootDir>/src/$1"
},
"globalSetup": "<rootDir>/test/global-setup.js"
},

View File

@ -1,6 +1,6 @@
import { UserService } from '@app/domain';
import { Command, CommandRunner } from 'nest-commander';
import { CLI_USER } from '../constants';
import { UserService } from 'src/domain/user/user.service';
import { UserEntity } from 'src/infra/entities/user.entity';
@Command({
name: 'list-users',
@ -13,7 +13,16 @@ export class ListUsersCommand extends CommandRunner {
async run(): Promise<void> {
try {
const users = await this.userService.getAll(CLI_USER, true);
const users = await this.userService.getAll(
{
user: {
id: 'cli',
email: 'cli@immich.app',
isAdmin: true,
} as UserEntity,
},
true,
);
console.dir(users);
} catch (error) {
console.error(error);

View File

@ -1,5 +1,5 @@
import { SystemConfigService } from '@app/domain';
import { Command, CommandRunner } from 'nest-commander';
import { SystemConfigService } from 'src/domain/system-config/system-config.service';
@Command({
name: 'enable-oauth-login',

View File

@ -1,5 +1,5 @@
import { SystemConfigService } from '@app/domain';
import { Command, CommandRunner } from 'nest-commander';
import { SystemConfigService } from 'src/domain/system-config/system-config.service';
@Command({
name: 'enable-password-login',

View File

@ -1,5 +1,6 @@
import { UserResponseDto, UserService } from '@app/domain';
import { Command, CommandRunner, InquirerService, Question, QuestionSet } from 'nest-commander';
import { UserResponseDto } from 'src/domain/user/response-dto/user-response.dto';
import { UserService } from 'src/domain/user/user.service';
@Command({
name: 'reset-admin-password',

73
server/src/config.ts Normal file
View File

@ -0,0 +1,73 @@
import { RegisterQueueOptions } from '@nestjs/bullmq';
import { ConfigModuleOptions } from '@nestjs/config';
import { QueueOptions } from 'bullmq';
import { RedisOptions } from 'ioredis';
import Joi from 'joi';
import { QueueName } from 'src/domain/job/job.constants';
import { LogLevel } from 'src/infra/entities/system-config.entity';
const WHEN_DB_URL_SET = Joi.when('DB_URL', {
is: Joi.exist(),
then: Joi.string().optional(),
otherwise: Joi.string().required(),
});
export const immichAppConfig: ConfigModuleOptions = {
envFilePath: '.env',
isGlobal: true,
validationSchema: Joi.object({
NODE_ENV: Joi.string().optional().valid('development', 'production', 'staging').default('development'),
LOG_LEVEL: Joi.string()
.optional()
.valid(...Object.values(LogLevel)),
DB_USERNAME: WHEN_DB_URL_SET,
DB_PASSWORD: WHEN_DB_URL_SET,
DB_DATABASE_NAME: WHEN_DB_URL_SET,
DB_URL: Joi.string().optional(),
DB_VECTOR_EXTENSION: Joi.string().optional().valid('pgvector', 'pgvecto.rs').default('pgvecto.rs'),
MACHINE_LEARNING_PORT: Joi.number().optional(),
MICROSERVICES_PORT: Joi.number().optional(),
IMMICH_METRICS_PORT: Joi.number().optional(),
IMMICH_METRICS: Joi.boolean().optional().default(false),
IMMICH_HOST_METRICS: Joi.boolean().optional().default(false),
IMMICH_API_METRICS: Joi.boolean().optional().default(false),
IMMICH_IO_METRICS: Joi.boolean().optional().default(false),
}),
};
function parseRedisConfig(): RedisOptions {
const redisUrl = process.env.REDIS_URL;
if (redisUrl && redisUrl.startsWith('ioredis://')) {
try {
const decodedString = Buffer.from(redisUrl.slice(10), 'base64').toString();
return JSON.parse(decodedString);
} catch (error) {
throw new Error(`Failed to decode redis options: ${error}`);
}
}
return {
host: process.env.REDIS_HOSTNAME || 'immich_redis',
port: Number.parseInt(process.env.REDIS_PORT || '6379'),
db: Number.parseInt(process.env.REDIS_DBINDEX || '0'),
username: process.env.REDIS_USERNAME || undefined,
password: process.env.REDIS_PASSWORD || undefined,
path: process.env.REDIS_SOCKET || undefined,
};
}
export const bullConfig: QueueOptions = {
prefix: 'immich_bull',
connection: parseRedisConfig(),
defaultJobOptions: {
attempts: 3,
removeOnComplete: true,
removeOnFail: false,
},
};
export const bullQueues: RegisterQueueOptions[] = Object.values(QueueName).map((name) => ({ name }));
export const excludePaths = ['/.well-known/immich', '/custom.css', '/favicon.ico'];

View File

@ -1,17 +1,17 @@
import { AuthDto } from '@app/domain';
import {
ActivityDto,
ActivitySearchDto,
ActivityService,
ActivityCreateDto as CreateDto,
ActivityResponseDto as ResponseDto,
ActivityStatisticsResponseDto as StatsResponseDto,
} from '@app/domain/activity';
import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Query, Res } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Response } from 'express';
import { Auth, Authenticated } from '../app.guard';
import { UUIDParamDto } from './dto/uuid-param.dto';
import {
ActivityCreateDto,
ActivityDto,
ActivityResponseDto,
ActivitySearchDto,
ActivityStatisticsResponseDto,
} from 'src/domain/activity/activity.dto';
import { ActivityService } from 'src/domain/activity/activity.service';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { Auth, Authenticated } from 'src/middleware/auth.guard';
import { UUIDParamDto } from 'src/validation';
@ApiTags('Activity')
@Controller('activity')
@ -20,21 +20,21 @@ export class ActivityController {
constructor(private service: ActivityService) {}
@Get()
getActivities(@Auth() auth: AuthDto, @Query() dto: ActivitySearchDto): Promise<ResponseDto[]> {
getActivities(@Auth() auth: AuthDto, @Query() dto: ActivitySearchDto): Promise<ActivityResponseDto[]> {
return this.service.getAll(auth, dto);
}
@Get('statistics')
getActivityStatistics(@Auth() auth: AuthDto, @Query() dto: ActivityDto): Promise<StatsResponseDto> {
getActivityStatistics(@Auth() auth: AuthDto, @Query() dto: ActivityDto): Promise<ActivityStatisticsResponseDto> {
return this.service.getStatistics(auth, dto);
}
@Post()
async createActivity(
@Auth() auth: AuthDto,
@Body() dto: CreateDto,
@Body() dto: ActivityCreateDto,
@Res({ passthrough: true }) res: Response,
): Promise<ResponseDto> {
): Promise<ActivityResponseDto> {
const { duplicate, value } = await this.service.create(auth, dto);
if (duplicate) {
res.status(HttpStatus.OK);

View File

@ -1,21 +1,16 @@
import {
AddUsersDto,
AlbumCountResponseDto,
AlbumInfoDto,
AlbumResponseDto,
AlbumService,
AuthDto,
BulkIdResponseDto,
BulkIdsDto,
CreateAlbumDto as CreateDto,
GetAlbumsDto,
UpdateAlbumDto as UpdateDto,
} from '@app/domain';
import { Body, Controller, Delete, Get, Param, Patch, Post, Put, Query } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { ParseMeUUIDPipe } from '../api-v1/validation/parse-me-uuid-pipe';
import { Auth, Authenticated, SharedLinkRoute } from '../app.guard';
import { UUIDParamDto } from './dto/uuid-param.dto';
import { AlbumCountResponseDto, AlbumResponseDto } from 'src/domain/album/album-response.dto';
import { AlbumService } from 'src/domain/album/album.service';
import { AddUsersDto } from 'src/domain/album/dto/album-add-users.dto';
import { CreateAlbumDto } from 'src/domain/album/dto/album-create.dto';
import { UpdateAlbumDto } from 'src/domain/album/dto/album-update.dto';
import { AlbumInfoDto } from 'src/domain/album/dto/album.dto';
import { GetAlbumsDto } from 'src/domain/album/dto/get-albums.dto';
import { BulkIdResponseDto, BulkIdsDto } from 'src/domain/asset/response-dto/asset-ids-response.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { Auth, Authenticated, SharedLinkRoute } from 'src/middleware/auth.guard';
import { ParseMeUUIDPipe, UUIDParamDto } from 'src/validation';
@ApiTags('Album')
@Controller('album')
@ -34,7 +29,7 @@ export class AlbumController {
}
@Post()
createAlbum(@Auth() auth: AuthDto, @Body() dto: CreateDto): Promise<AlbumResponseDto> {
createAlbum(@Auth() auth: AuthDto, @Body() dto: CreateAlbumDto): Promise<AlbumResponseDto> {
return this.service.create(auth, dto);
}
@ -52,7 +47,7 @@ export class AlbumController {
updateAlbumInfo(
@Auth() auth: AuthDto,
@Param() { id }: UUIDParamDto,
@Body() dto: UpdateDto,
@Body() dto: UpdateAlbumDto,
): Promise<AlbumResponseDto> {
return this.service.update(auth, id, dto);
}

View File

@ -1,15 +1,15 @@
import { Body, Controller, Delete, Get, Param, Post, Put } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import {
APIKeyCreateDto,
APIKeyCreateResponseDto,
APIKeyResponseDto,
APIKeyService,
APIKeyUpdateDto,
AuthDto,
} from '@app/domain';
import { Body, Controller, Delete, Get, Param, Post, Put } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Auth, Authenticated } from '../app.guard';
import { UUIDParamDto } from './dto/uuid-param.dto';
} from 'src/domain/api-key/api-key.dto';
import { APIKeyService } from 'src/domain/api-key/api-key.service';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { Auth, Authenticated } from 'src/middleware/auth.guard';
import { UUIDParamDto } from 'src/validation';
@ApiTags('API Key')
@Controller('api-key')

View File

@ -1,7 +1,7 @@
import { SystemConfigService } from '@app/domain';
import { Controller, Get, Header } from '@nestjs/common';
import { ApiExcludeEndpoint } from '@nestjs/swagger';
import { PublicRoute } from '../app.guard';
import { SystemConfigService } from 'src/domain/system-config/system-config.service';
import { PublicRoute } from 'src/middleware/auth.guard';
@Controller()
export class AppController {

View File

@ -1,31 +1,28 @@
import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put, Query } from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { AssetService } from 'src/domain/asset/asset.service';
import { AssetJobsDto } from 'src/domain/asset/dto/asset-ids.dto';
import { UpdateStackParentDto } from 'src/domain/asset/dto/asset-stack.dto';
import { AssetStatsDto, AssetStatsResponseDto } from 'src/domain/asset/dto/asset-statistics.dto';
import {
AssetBulkDeleteDto,
AssetBulkUpdateDto,
AssetJobsDto,
AssetResponseDto,
AssetService,
AssetStatsDto,
AssetStatsResponseDto,
AuthDto,
DeviceIdDto,
MapMarkerDto,
MapMarkerResponseDto,
MemoryLaneDto,
MemoryLaneResponseDto,
MetadataSearchDto,
RandomAssetsDto,
SearchService,
TimeBucketAssetDto,
TimeBucketDto,
TimeBucketResponseDto,
UpdateAssetDto as UpdateDto,
UpdateStackParentDto,
} from '@app/domain';
import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put, Query } from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { Auth, Authenticated, SharedLinkRoute } from '../app.guard';
import { Route } from '../interceptors';
import { UUIDParamDto } from './dto/uuid-param.dto';
UpdateAssetDto,
} from 'src/domain/asset/dto/asset.dto';
import { MapMarkerDto } from 'src/domain/asset/dto/map-marker.dto';
import { MemoryLaneDto } from 'src/domain/asset/dto/memory-lane.dto';
import { TimeBucketAssetDto, TimeBucketDto } from 'src/domain/asset/dto/time-bucket.dto';
import { AssetResponseDto, MemoryLaneResponseDto } from 'src/domain/asset/response-dto/asset-response.dto';
import { MapMarkerResponseDto } from 'src/domain/asset/response-dto/map-marker-response.dto';
import { TimeBucketResponseDto } from 'src/domain/asset/response-dto/time-bucket-response.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { MetadataSearchDto } from 'src/domain/search/dto/search.dto';
import { SearchService } from 'src/domain/search/search.service';
import { Auth, Authenticated, SharedLinkRoute } from 'src/middleware/auth.guard';
import { Route } from 'src/middleware/file-upload.interceptor';
import { UUIDParamDto } from 'src/validation';
@ApiTags('Asset')
@Controller('assets')
@ -120,7 +117,11 @@ export class AssetController {
}
@Put(':id')
updateAsset(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto, @Body() dto: UpdateDto): Promise<AssetResponseDto> {
updateAsset(
@Auth() auth: AuthDto,
@Param() { id }: UUIDParamDto,
@Body() dto: UpdateAssetDto,
): Promise<AssetResponseDto> {
return this.service.update(auth, id, dto);
}
}

View File

@ -1,16 +1,16 @@
import { Body, Controller, Get, Post, Query } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import {
AuditDeletesDto,
AuditDeletesResponseDto,
AuditService,
AuthDto,
FileChecksumDto,
FileChecksumResponseDto,
FileReportDto,
FileReportFixDto,
} from '@app/domain';
import { Body, Controller, Get, Post, Query } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { AdminRoute, Auth, Authenticated } from '../app.guard';
} from 'src/domain/audit/audit.dto';
import { AuditService } from 'src/domain/audit/audit.service';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { AdminRoute, Auth, Authenticated } from 'src/middleware/auth.guard';
@ApiTags('Audit')
@Controller('audit')

View File

@ -1,25 +1,21 @@
import {
AuthDeviceResponseDto,
AuthDto,
AuthService,
ChangePasswordDto,
IMMICH_ACCESS_COOKIE,
IMMICH_AUTH_TYPE_COOKIE,
IMMICH_IS_AUTHENTICATED,
LoginCredentialDto,
LoginDetails,
LoginResponseDto,
LogoutResponseDto,
SignUpDto,
UserResponseDto,
ValidateAccessTokenResponseDto,
mapUser,
} from '@app/domain';
import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Req, Res } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Request, Response } from 'express';
import { Auth, Authenticated, GetLoginDetails, PublicRoute } from '../app.guard';
import { UUIDParamDto } from './dto/uuid-param.dto';
import { IMMICH_ACCESS_COOKIE, IMMICH_AUTH_TYPE_COOKIE, IMMICH_IS_AUTHENTICATED } from 'src/domain/auth/auth.constant';
import {
AuthDeviceResponseDto,
AuthDto,
ChangePasswordDto,
LoginCredentialDto,
LoginResponseDto,
LogoutResponseDto,
SignUpDto,
ValidateAccessTokenResponseDto,
} from 'src/domain/auth/auth.dto';
import { AuthService, LoginDetails } from 'src/domain/auth/auth.service';
import { UserResponseDto, mapUser } from 'src/domain/user/response-dto/user-response.dto';
import { Auth, Authenticated, GetLoginDetails, PublicRoute } from 'src/middleware/auth.guard';
import { UUIDParamDto } from 'src/validation';
@ApiTags('Authentication')
@Controller('auth')

View File

@ -1,10 +1,13 @@
import { AssetIdsDto, AuthDto, DownloadInfoDto, DownloadResponseDto, DownloadService } from '@app/domain';
import { Body, Controller, HttpCode, HttpStatus, Next, Param, Post, Res, StreamableFile } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { NextFunction, Response } from 'express';
import { Auth, Authenticated, FileResponse, SharedLinkRoute } from '../app.guard';
import { asStreamableFile, sendFile } from '../app.utils';
import { UUIDParamDto } from './dto/uuid-param.dto';
import { AssetIdsDto } from 'src/domain/asset/dto/asset-ids.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { DownloadInfoDto, DownloadResponseDto } from 'src/domain/download/download.dto';
import { DownloadService } from 'src/domain/download/download.service';
import { asStreamableFile, sendFile } from 'src/immich/app.utils';
import { Auth, Authenticated, FileResponse, SharedLinkRoute } from 'src/middleware/auth.guard';
import { UUIDParamDto } from 'src/validation';
@ApiTags('Download')
@Controller('download')

View File

@ -1,8 +1,10 @@
import { AssetFaceResponseDto, AuthDto, FaceDto, PersonResponseDto, PersonService } from '@app/domain';
import { Body, Controller, Get, Param, Put, Query } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Auth, Authenticated } from '../app.guard';
import { UUIDParamDto } from './dto/uuid-param.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { AssetFaceResponseDto, FaceDto, PersonResponseDto } from 'src/domain/person/person.dto';
import { PersonService } from 'src/domain/person/person.service';
import { Auth, Authenticated } from 'src/middleware/auth.guard';
import { UUIDParamDto } from 'src/validation';
@ApiTags('Face')
@Controller('face')

View File

@ -1,7 +1,8 @@
import { AllJobStatusResponseDto, JobCommandDto, JobIdParamDto, JobService, JobStatusDto } from '@app/domain';
import { Body, Controller, Get, Param, Put } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Authenticated } from '../app.guard';
import { AllJobStatusResponseDto, JobCommandDto, JobIdParamDto, JobStatusDto } from 'src/domain/job/job.dto';
import { JobService } from 'src/domain/job/job.service';
import { Authenticated } from 'src/middleware/auth.guard';
@ApiTags('Job')
@Controller('jobs')

View File

@ -1,18 +1,18 @@
import {
CreateLibraryDto as CreateDto,
LibraryService,
LibraryStatsResponseDto,
LibraryResponseDto as ResponseDto,
ScanLibraryDto,
SearchLibraryDto,
UpdateLibraryDto as UpdateDto,
ValidateLibraryDto,
ValidateLibraryResponseDto,
} from '@app/domain';
import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put, Query } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { AdminRoute, Authenticated } from '../app.guard';
import { UUIDParamDto } from './dto/uuid-param.dto';
import {
CreateLibraryDto,
LibraryResponseDto,
LibraryStatsResponseDto,
ScanLibraryDto,
SearchLibraryDto,
UpdateLibraryDto,
ValidateLibraryDto,
ValidateLibraryResponseDto,
} from 'src/domain/library/library.dto';
import { LibraryService } from 'src/domain/library/library.service';
import { AdminRoute, Authenticated } from 'src/middleware/auth.guard';
import { UUIDParamDto } from 'src/validation';
@ApiTags('Library')
@Controller('library')
@ -22,22 +22,22 @@ export class LibraryController {
constructor(private service: LibraryService) {}
@Get()
getAllLibraries(@Query() dto: SearchLibraryDto): Promise<ResponseDto[]> {
getAllLibraries(@Query() dto: SearchLibraryDto): Promise<LibraryResponseDto[]> {
return this.service.getAll(dto);
}
@Post()
createLibrary(@Body() dto: CreateDto): Promise<ResponseDto> {
createLibrary(@Body() dto: CreateLibraryDto): Promise<LibraryResponseDto> {
return this.service.create(dto);
}
@Put(':id')
updateLibrary(@Param() { id }: UUIDParamDto, @Body() dto: UpdateDto): Promise<ResponseDto> {
updateLibrary(@Param() { id }: UUIDParamDto, @Body() dto: UpdateLibraryDto): Promise<LibraryResponseDto> {
return this.service.update(id, dto);
}
@Get(':id')
getLibrary(@Param() { id }: UUIDParamDto): Promise<ResponseDto> {
getLibrary(@Param() { id }: UUIDParamDto): Promise<LibraryResponseDto> {
return this.service.get(id);
}

View File

@ -1,17 +1,16 @@
import { Body, Controller, Get, HttpStatus, Post, Redirect, Req, Res } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Request, Response } from 'express';
import {
AuthDto,
AuthService,
LoginDetails,
LoginResponseDto,
OAuthAuthorizeResponseDto,
OAuthCallbackDto,
OAuthConfigDto,
UserResponseDto,
} from '@app/domain';
import { Body, Controller, Get, HttpStatus, Post, Redirect, Req, Res } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Request, Response } from 'express';
import { Auth, Authenticated, GetLoginDetails, PublicRoute } from '../app.guard';
} from 'src/domain/auth/auth.dto';
import { AuthService, LoginDetails } from 'src/domain/auth/auth.service';
import { UserResponseDto } from 'src/domain/user/response-dto/user-response.dto';
import { Auth, Authenticated, GetLoginDetails, PublicRoute } from 'src/middleware/auth.guard';
@ApiTags('OAuth')
@Controller('oauth')

View File

@ -1,9 +1,11 @@
import { AuthDto, PartnerDirection, PartnerService } from '@app/domain';
import { PartnerResponseDto, UpdatePartnerDto } from '@app/domain/partner/partner.dto';
import { Body, Controller, Delete, Get, Param, Post, Put, Query } from '@nestjs/common';
import { ApiQuery, ApiTags } from '@nestjs/swagger';
import { Auth, Authenticated } from '../app.guard';
import { UUIDParamDto } from './dto/uuid-param.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { PartnerResponseDto, UpdatePartnerDto } from 'src/domain/partner/partner.dto';
import { PartnerService } from 'src/domain/partner/partner.service';
import { PartnerDirection } from 'src/interfaces/partner.repository';
import { Auth, Authenticated } from 'src/middleware/auth.guard';
import { UUIDParamDto } from 'src/validation';
@ApiTags('Partner')
@Controller('partner')

View File

@ -1,24 +1,24 @@
import { Body, Controller, Get, Next, Param, Post, Put, Query, Res } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { NextFunction, Response } from 'express';
import { BulkIdResponseDto } from 'src/domain/asset/response-dto/asset-ids-response.dto';
import { AssetResponseDto } from 'src/domain/asset/response-dto/asset-response.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import {
AssetFaceUpdateDto,
AssetResponseDto,
AuthDto,
BulkIdResponseDto,
MergePersonDto,
PeopleResponseDto,
PeopleUpdateDto,
PersonCreateDto,
PersonResponseDto,
PersonSearchDto,
PersonService,
PersonStatisticsResponseDto,
PersonUpdateDto,
} from '@app/domain';
import { Body, Controller, Get, Next, Param, Post, Put, Query, Res } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { NextFunction, Response } from 'express';
import { Auth, Authenticated, FileResponse } from '../app.guard';
import { sendFile } from '../app.utils';
import { UUIDParamDto } from './dto/uuid-param.dto';
} from 'src/domain/person/person.dto';
import { PersonService } from 'src/domain/person/person.service';
import { sendFile } from 'src/immich/app.utils';
import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard';
import { UUIDParamDto } from 'src/validation';
@ApiTags('Person')
@Controller('person')

View File

@ -1,21 +1,21 @@
import {
AssetResponseDto,
AuthDto,
MetadataSearchDto,
PersonResponseDto,
PlacesResponseDto,
SearchDto,
SearchExploreResponseDto,
SearchPeopleDto,
SearchPlacesDto,
SearchResponseDto,
SearchService,
SmartSearchDto,
} from '@app/domain';
import { SearchSuggestionRequestDto } from '@app/domain/search/dto/search-suggestion.dto';
import { Body, Controller, Get, HttpCode, HttpStatus, Post, Query } from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { Auth, Authenticated } from '../app.guard';
import { AssetResponseDto } from 'src/domain/asset/response-dto/asset-response.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { PersonResponseDto } from 'src/domain/person/person.dto';
import { SearchSuggestionRequestDto } from 'src/domain/search/dto/search-suggestion.dto';
import {
MetadataSearchDto,
PlacesResponseDto,
SearchDto,
SearchPeopleDto,
SearchPlacesDto,
SmartSearchDto,
} from 'src/domain/search/dto/search.dto';
import { SearchExploreResponseDto } from 'src/domain/search/response-dto/search-explore.response.dto';
import { SearchResponseDto } from 'src/domain/search/response-dto/search-response.dto';
import { SearchService } from 'src/domain/search/search.service';
import { Auth, Authenticated } from 'src/middleware/auth.guard';
@ApiTags('Search')
@Controller('search')

View File

@ -1,17 +1,17 @@
import { Controller, Get, HttpCode, HttpStatus, Post } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import {
ServerConfigDto,
ServerFeaturesDto,
ServerInfoResponseDto,
ServerInfoService,
ServerMediaTypesResponseDto,
ServerPingResponse,
ServerStatsResponseDto,
ServerThemeDto,
ServerVersionResponseDto,
} from '@app/domain';
import { Controller, Get, HttpCode, HttpStatus, Post } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { AdminRoute, Authenticated, PublicRoute } from '../app.guard';
} from 'src/domain/server-info/server-info.dto';
import { ServerInfoService } from 'src/domain/server-info/server-info.service';
import { AdminRoute, Authenticated, PublicRoute } from 'src/middleware/auth.guard';
@ApiTags('Server Info')
@Controller('server-info')

View File

@ -1,19 +1,15 @@
import {
AssetIdsDto,
AssetIdsResponseDto,
AuthDto,
IMMICH_SHARED_LINK_ACCESS_COOKIE,
SharedLinkCreateDto,
SharedLinkEditDto,
SharedLinkPasswordDto,
SharedLinkResponseDto,
SharedLinkService,
} from '@app/domain';
import { Body, Controller, Delete, Get, Param, Patch, Post, Put, Query, Req, Res } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Request, Response } from 'express';
import { Auth, Authenticated, SharedLinkRoute } from '../app.guard';
import { UUIDParamDto } from './dto/uuid-param.dto';
import { AssetIdsDto } from 'src/domain/asset/dto/asset-ids.dto';
import { AssetIdsResponseDto } from 'src/domain/asset/response-dto/asset-ids-response.dto';
import { IMMICH_SHARED_LINK_ACCESS_COOKIE } from 'src/domain/auth/auth.constant';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { SharedLinkResponseDto } from 'src/domain/shared-link/shared-link-response.dto';
import { SharedLinkCreateDto, SharedLinkEditDto, SharedLinkPasswordDto } from 'src/domain/shared-link/shared-link.dto';
import { SharedLinkService } from 'src/domain/shared-link/shared-link.service';
import { Auth, Authenticated, SharedLinkRoute } from 'src/middleware/auth.guard';
import { UUIDParamDto } from 'src/validation';
@ApiTags('Shared Link')
@Controller('shared-link')

View File

@ -1,8 +1,10 @@
import { SystemConfigDto, SystemConfigService, SystemConfigTemplateStorageOptionDto } from '@app/domain';
import { MapThemeDto } from '@app/domain/system-config/system-config-map-theme.dto';
import { Body, Controller, Get, Put, Query } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { AdminRoute, Authenticated } from '../app.guard';
import { SystemConfigDto } from 'src/domain/system-config/dto/system-config.dto';
import { SystemConfigTemplateStorageOptionDto } from 'src/domain/system-config/response-dto/system-config-template-storage-option.dto';
import { MapThemeDto } from 'src/domain/system-config/system-config-map-theme.dto';
import { SystemConfigService } from 'src/domain/system-config/system-config.service';
import { AdminRoute, Authenticated } from 'src/middleware/auth.guard';
@ApiTags('System Config')
@Controller('system-config')

View File

@ -1,17 +1,14 @@
import {
AssetIdsDto,
AssetIdsResponseDto,
AssetResponseDto,
AuthDto,
CreateTagDto,
TagResponseDto,
TagService,
UpdateTagDto,
} from '@app/domain';
import { Body, Controller, Delete, Get, Param, Patch, Post, Put } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Auth, Authenticated } from '../app.guard';
import { UUIDParamDto } from './dto/uuid-param.dto';
import { AssetIdsDto } from 'src/domain/asset/dto/asset-ids.dto';
import { AssetIdsResponseDto } from 'src/domain/asset/response-dto/asset-ids-response.dto';
import { AssetResponseDto } from 'src/domain/asset/response-dto/asset-response.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { TagResponseDto } from 'src/domain/tag/tag-response.dto';
import { CreateTagDto, UpdateTagDto } from 'src/domain/tag/tag.dto';
import { TagService } from 'src/domain/tag/tag.service';
import { Auth, Authenticated } from 'src/middleware/auth.guard';
import { UUIDParamDto } from 'src/validation';
@ApiTags('Tag')
@Controller('tag')

View File

@ -1,7 +1,9 @@
import { AuthDto, BulkIdsDto, TrashService } from '@app/domain';
import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Auth, Authenticated } from '../app.guard';
import { BulkIdsDto } from 'src/domain/asset/response-dto/asset-ids-response.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { TrashService } from 'src/domain/trash/trash.service';
import { Auth, Authenticated } from 'src/middleware/auth.guard';
@ApiTags('Trash')
@Controller('trash')

View File

@ -1,13 +1,3 @@
import {
AuthDto,
CreateUserDto as CreateDto,
CreateProfileImageDto,
CreateProfileImageResponseDto,
DeleteUserDto,
UpdateUserDto as UpdateDto,
UserResponseDto,
UserService,
} from '@app/domain';
import {
Body,
Controller,
@ -26,10 +16,18 @@ import {
} from '@nestjs/common';
import { ApiBody, ApiConsumes, ApiTags } from '@nestjs/swagger';
import { NextFunction, Response } from 'express';
import { AdminRoute, Auth, Authenticated, FileResponse } from '../app.guard';
import { sendFile } from '../app.utils';
import { FileUploadInterceptor, Route } from '../interceptors';
import { UUIDParamDto } from './dto/uuid-param.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { CreateProfileImageDto } from 'src/domain/user/dto/create-profile-image.dto';
import { CreateUserDto } from 'src/domain/user/dto/create-user.dto';
import { DeleteUserDto } from 'src/domain/user/dto/delete-user.dto';
import { UpdateUserDto } from 'src/domain/user/dto/update-user.dto';
import { CreateProfileImageResponseDto } from 'src/domain/user/response-dto/create-profile-image-response.dto';
import { UserResponseDto } from 'src/domain/user/response-dto/user-response.dto';
import { UserService } from 'src/domain/user/user.service';
import { sendFile } from 'src/immich/app.utils';
import { AdminRoute, Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard';
import { FileUploadInterceptor, Route } from 'src/middleware/file-upload.interceptor';
import { UUIDParamDto } from 'src/validation';
@ApiTags('User')
@Controller(Route.USER)
@ -54,7 +52,7 @@ export class UserController {
@AdminRoute()
@Post()
createUser(@Body() createUserDto: CreateDto): Promise<UserResponseDto> {
createUser(@Body() createUserDto: CreateUserDto): Promise<UserResponseDto> {
return this.service.create(createUserDto);
}
@ -82,7 +80,7 @@ export class UserController {
// TODO: replace with @Put(':id')
@Put()
updateUser(@Auth() auth: AuthDto, @Body() updateUserDto: UpdateDto): Promise<UserResponseDto> {
updateUser(@Auth() auth: AuthDto, @Body() updateUserDto: UpdateUserDto): Promise<UserResponseDto> {
return this.service.update(auth, updateUserDto);
}

View File

@ -1,8 +1,8 @@
import { BadRequestException, UnauthorizedException } from '@nestjs/common';
import { SharedLinkEntity } from '../../infra/entities';
import { AuthDto } from '../auth';
import { setDifference, setIsEqual, setUnion } from '../domain.util';
import { IAccessRepository } from '../repositories';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { SharedLinkEntity } from 'src/infra/entities/shared-link.entity';
import { IAccessRepository } from 'src/interfaces/access.repository';
import { setDifference, setIsEqual, setUnion } from 'src/utils';
export enum Permission {
ACTIVITY_CREATE = 'activity.create',

View File

@ -1,16 +1,16 @@
import { SystemConfigCore } from '@app/domain/system-config';
import { AssetEntity, AssetPathType, PathType, PersonEntity, PersonPathType } from '@app/infra/entities';
import { ImmichLogger } from '@app/infra/logger';
import { dirname, join, resolve } from 'node:path';
import { APP_MEDIA_LOCATION } from '../domain.constant';
import {
IAssetRepository,
ICryptoRepository,
IMoveRepository,
IPersonRepository,
IStorageRepository,
ISystemConfigRepository,
} from '../repositories';
import { SystemConfigCore } from 'src/cores/system-config.core';
import { APP_MEDIA_LOCATION } from 'src/domain/domain.constant';
import { AssetEntity } from 'src/infra/entities/asset.entity';
import { AssetPathType, PathType, PersonPathType } from 'src/infra/entities/move.entity';
import { PersonEntity } from 'src/infra/entities/person.entity';
import { ImmichLogger } from 'src/infra/logger';
import { IAssetRepository } from 'src/interfaces/asset.repository';
import { ICryptoRepository } from 'src/interfaces/crypto.repository';
import { IMoveRepository } from 'src/interfaces/move.repository';
import { IPersonRepository } from 'src/interfaces/person.repository';
import { IStorageRepository } from 'src/interfaces/storage.repository';
import { ISystemConfigRepository } from 'src/interfaces/system-config.repository';
export enum StorageFolder {
ENCODED_VIDEO = 'encoded-video',
@ -46,8 +46,8 @@ export class StorageCore {
private moveRepository: IMoveRepository,
private personRepository: IPersonRepository,
private cryptoRepository: ICryptoRepository,
private systemConfigRepository: ISystemConfigRepository,
private repository: IStorageRepository,
systemConfigRepository: ISystemConfigRepository,
) {
this.configCore = SystemConfigCore.create(systemConfigRepository);
}
@ -66,8 +66,8 @@ export class StorageCore {
moveRepository,
personRepository,
cryptoRepository,
configRepository,
repository,
configRepository,
);
}

View File

@ -1,7 +1,16 @@
import { BadRequestException, ForbiddenException, Injectable } from '@nestjs/common';
import { CronExpression } from '@nestjs/schedule';
import { plainToInstance } from 'class-transformer';
import { validate } from 'class-validator';
import { load as loadYaml } from 'js-yaml';
import * as _ from 'lodash';
import { Subject } from 'rxjs';
import { QueueName } from 'src/domain/job/job.constants';
import { SystemConfigDto } from 'src/domain/system-config/dto/system-config.dto';
import {
AudioCodec,
Colorspace,
CQMode,
Colorspace,
LogLevel,
SystemConfig,
SystemConfigEntity,
@ -11,18 +20,9 @@ import {
TranscodeHWAccel,
TranscodePolicy,
VideoCodec,
} from '@app/infra/entities';
import { ImmichLogger } from '@app/infra/logger';
import { BadRequestException, ForbiddenException, Injectable } from '@nestjs/common';
import { CronExpression } from '@nestjs/schedule';
import { plainToInstance } from 'class-transformer';
import { validate } from 'class-validator';
import { load as loadYaml } from 'js-yaml';
import * as _ from 'lodash';
import { Subject } from 'rxjs';
import { QueueName } from '../job/job.constants';
import { ISystemConfigRepository } from '../repositories';
import { SystemConfigDto } from './dto';
} from 'src/infra/entities/system-config.entity';
import { ImmichLogger } from 'src/infra/logger';
import { ISystemConfigRepository } from 'src/interfaces/system-config.repository';
export type SystemConfigValidator = (config: SystemConfig, newConfig: SystemConfig) => void | Promise<void>;

View File

@ -1,8 +1,11 @@
import { LibraryType, UserEntity } from '@app/infra/entities';
import { BadRequestException, ForbiddenException } from '@nestjs/common';
import sanitize from 'sanitize-filename';
import { ICryptoRepository, ILibraryRepository, IUserRepository } from '../repositories';
import { UserResponseDto } from './response-dto';
import { UserResponseDto } from 'src/domain/user/response-dto/user-response.dto';
import { LibraryType } from 'src/infra/entities/library.entity';
import { UserEntity } from 'src/infra/entities/user.entity';
import { ICryptoRepository } from 'src/interfaces/crypto.repository';
import { ILibraryRepository } from 'src/interfaces/library.repository';
import { IUserRepository } from 'src/interfaces/user.repository';
const SALT_ROUNDS = 10;

124
server/src/decorators.ts Normal file
View File

@ -0,0 +1,124 @@
import { SetMetadata } from '@nestjs/common';
import _ from 'lodash';
import { setUnion } from 'src/utils';
// PostgreSQL uses a 16-bit integer to indicate the number of bound parameters. This means that the
// maximum number of parameters is 65535. Any query that tries to bind more than that (e.g. searching
// by a list of IDs) requires splitting the query into multiple chunks.
// We are rounding down this limit, as queries commonly include other filters and parameters.
export const DATABASE_PARAMETER_CHUNK_SIZE = 65_500;
/**
* Chunks an array or set into smaller collections of the same type and specified size.
*
* @param collection The collection to chunk.
* @param size The size of each chunk.
*/
function chunks<T>(collection: Array<T>, size: number): Array<Array<T>>;
function chunks<T>(collection: Set<T>, size: number): Array<Set<T>>;
function chunks<T>(collection: Array<T> | Set<T>, size: number): Array<Array<T>> | Array<Set<T>> {
if (collection instanceof Set) {
const result = [];
let chunk = new Set<T>();
for (const element of collection) {
chunk.add(element);
if (chunk.size === size) {
result.push(chunk);
chunk = new Set<T>();
}
}
if (chunk.size > 0) {
result.push(chunk);
}
return result;
} else {
return _.chunk(collection, size);
}
}
/**
* Wraps a method that takes a collection of parameters and sequentially calls it with chunks of the collection,
* to overcome the maximum number of parameters allowed by the database driver.
*
* @param options.paramIndex The index of the function parameter to chunk. Defaults to 0.
* @param options.flatten Whether to flatten the results. Defaults to false.
*/
export function Chunked(options: { paramIndex?: number; mergeFn?: (results: any) => any } = {}): MethodDecorator {
return (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
const originalMethod = descriptor.value;
const parameterIndex = options.paramIndex ?? 0;
descriptor.value = async function (...arguments_: any[]) {
const argument = arguments_[parameterIndex];
// Early return if argument length is less than or equal to the chunk size.
if (
(Array.isArray(argument) && argument.length <= DATABASE_PARAMETER_CHUNK_SIZE) ||
(argument instanceof Set && argument.size <= DATABASE_PARAMETER_CHUNK_SIZE)
) {
return await originalMethod.apply(this, arguments_);
}
return Promise.all(
chunks(argument, DATABASE_PARAMETER_CHUNK_SIZE).map(async (chunk) => {
await Reflect.apply(originalMethod, this, [
...arguments_.slice(0, parameterIndex),
chunk,
...arguments_.slice(parameterIndex + 1),
]);
}),
).then((results) => (options.mergeFn ? options.mergeFn(results) : results));
};
};
}
export function ChunkedArray(options?: { paramIndex?: number }): MethodDecorator {
return Chunked({ ...options, mergeFn: _.flatten });
}
export function ChunkedSet(options?: { paramIndex?: number }): MethodDecorator {
return Chunked({ ...options, mergeFn: setUnion });
}
// https://stackoverflow.com/a/74898678
export function DecorateAll(
decorator: <T>(
target: any,
propertyKey: string,
descriptor: TypedPropertyDescriptor<T>,
) => TypedPropertyDescriptor<T> | void,
) {
return (target: any) => {
const descriptors = Object.getOwnPropertyDescriptors(target.prototype);
for (const [propName, descriptor] of Object.entries(descriptors)) {
const isMethod = typeof descriptor.value == 'function' && propName !== 'constructor';
if (!isMethod) {
continue;
}
decorator({ ...target, constructor: { ...target.constructor, name: target.name } as any }, propName, descriptor);
Object.defineProperty(target.prototype, propName, descriptor);
}
};
}
const UUID = '00000000-0000-4000-a000-000000000000';
export const DummyValue = {
UUID,
UUID_SET: new Set([UUID]),
PAGINATION: { take: 10, skip: 0 },
EMAIL: 'user@immich.app',
STRING: 'abcdefghi',
BUFFER: Buffer.from('abcdefghi'),
DATE: new Date(),
TIME_BUCKET: '2024-01-01T00:00:00.000Z',
};
export const GENERATE_SQL_KEY = 'generate-sql-key';
export interface GenerateSqlQueries {
name?: string;
params: unknown[];
}
/** Decorator to enable versioning/tracking of generated Sql */
export const GenerateSql = (...options: GenerateSqlQueries[]) => SetMetadata(GENERATE_SQL_KEY, options);

View File

@ -1 +0,0 @@
export * from './access.core';

View File

@ -1,8 +1,8 @@
import { ActivityEntity } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger';
import { IsEnum, IsNotEmpty, IsString, ValidateIf } from 'class-validator';
import { Optional, ValidateUUID } from '../domain.util';
import { UserDto, mapSimpleUser } from '../user/response-dto';
import { UserDto, mapSimpleUser } from 'src/domain/user/response-dto/user-response.dto';
import { ActivityEntity } from 'src/infra/entities/activity.entity';
import { Optional, ValidateUUID } from 'src/validation';
export enum ReactionType {
COMMENT = 'comment',

View File

@ -1,8 +1,5 @@
import { ActivityEntity } from '@app/infra/entities';
import { Inject, Injectable } from '@nestjs/common';
import { AccessCore, Permission } from '../access';
import { AuthDto } from '../auth';
import { IAccessRepository, IActivityRepository } from '../repositories';
import { AccessCore, Permission } from 'src/cores/access.core';
import {
ActivityCreateDto,
ActivityDto,
@ -13,7 +10,11 @@ import {
ReactionLevel,
ReactionType,
mapActivity,
} from './activity.dto';
} from 'src/domain/activity/activity.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { ActivityEntity } from 'src/infra/entities/activity.entity';
import { IAccessRepository } from 'src/interfaces/access.repository';
import { IActivityRepository } from 'src/interfaces/activity.repository';
@Injectable()
export class ActivityService {

View File

@ -1,10 +1,11 @@
import { BadRequestException } from '@nestjs/common';
import { authStub, IAccessRepositoryMock, newAccessRepositoryMock } from '@test';
import { activityStub } from '@test/fixtures/activity.stub';
import { newActivityRepositoryMock } from '@test/repositories/activity.repository.mock';
import { IActivityRepository } from '../repositories';
import { ReactionType } from './activity.dto';
import { ActivityService } from './activity.service';
import { ReactionType } from 'src/domain/activity/activity.dto';
import { ActivityService } from 'src/domain/activity/activity.service';
import { IActivityRepository } from 'src/interfaces/activity.repository';
import { activityStub } from 'test/fixtures/activity.stub';
import { authStub } from 'test/fixtures/auth.stub';
import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
import { newActivityRepositoryMock } from 'test/repositories/activity.repository.mock';
describe(ActivityService.name, () => {
let sut: ActivityService;

View File

@ -1,2 +0,0 @@
export * from './activity.dto';
export * from './activity.service';

View File

@ -1,5 +1,5 @@
import { albumStub } from '@test';
import { mapAlbum } from './album-response.dto';
import { mapAlbum } from 'src/domain/album/album-response.dto';
import { albumStub } from 'test/fixtures/album.stub';
describe('mapAlbum', () => {
it('should set start and end dates', () => {

View File

@ -1,9 +1,9 @@
import { AlbumEntity, AssetOrder } from '@app/infra/entities';
import { Optional } from '@nestjs/common';
import { ApiProperty } from '@nestjs/swagger';
import { AssetResponseDto, mapAsset } from '../asset';
import { AuthDto } from '../auth/auth.dto';
import { UserResponseDto, mapUser } from '../user';
import { AssetResponseDto, mapAsset } from 'src/domain/asset/response-dto/asset-response.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { UserResponseDto, mapUser } from 'src/domain/user/response-dto/user-response.dto';
import { AlbumEntity, AssetOrder } from 'src/infra/entities/album.entity';
import { Optional } from 'src/validation';
export class AlbumResponseDto {
id!: string;

View File

@ -1,36 +1,32 @@
import { BadRequestException } from '@nestjs/common';
import {
albumStub,
authStub,
IAccessRepositoryMock,
newAccessRepositoryMock,
newAlbumRepositoryMock,
newAssetRepositoryMock,
newJobRepositoryMock,
newUserRepositoryMock,
userStub,
} from '@test';
import _ from 'lodash';
import { BulkIdErrorReason } from '../asset';
import { IAlbumRepository, IAssetRepository, IJobRepository, IUserRepository } from '../repositories';
import { AlbumService } from './album.service';
import { AlbumService } from 'src/domain/album/album.service';
import { BulkIdErrorReason } from 'src/domain/asset/response-dto/asset-ids-response.dto';
import { IAlbumRepository } from 'src/interfaces/album.repository';
import { IAssetRepository } from 'src/interfaces/asset.repository';
import { IUserRepository } from 'src/interfaces/user.repository';
import { albumStub } from 'test/fixtures/album.stub';
import { authStub } from 'test/fixtures/auth.stub';
import { userStub } from 'test/fixtures/user.stub';
import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
import { newAlbumRepositoryMock } from 'test/repositories/album.repository.mock';
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
import { newUserRepositoryMock } from 'test/repositories/user.repository.mock';
describe(AlbumService.name, () => {
let sut: AlbumService;
let accessMock: IAccessRepositoryMock;
let albumMock: jest.Mocked<IAlbumRepository>;
let assetMock: jest.Mocked<IAssetRepository>;
let jobMock: jest.Mocked<IJobRepository>;
let userMock: jest.Mocked<IUserRepository>;
beforeEach(() => {
accessMock = newAccessRepositoryMock();
albumMock = newAlbumRepositoryMock();
assetMock = newAssetRepositoryMock();
jobMock = newJobRepositoryMock();
userMock = newUserRepositoryMock();
sut = new AlbumService(accessMock, albumMock, assetMock, jobMock, userMock);
sut = new AlbumService(accessMock, albumMock, assetMock, userMock);
});
it('should work', () => {

View File

@ -1,26 +1,27 @@
import { AlbumEntity, AssetEntity, UserEntity } from '@app/infra/entities';
import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { AccessCore, Permission } from '../access';
import { BulkIdErrorReason, BulkIdResponseDto, BulkIdsDto } from '../asset';
import { AuthDto } from '../auth';
import { setUnion } from '../domain.util';
import {
AlbumAssetCount,
AlbumInfoOptions,
IAccessRepository,
IAlbumRepository,
IAssetRepository,
IJobRepository,
IUserRepository,
} from '../repositories';
import { AccessCore, Permission } from 'src/cores/access.core';
import {
AlbumCountResponseDto,
AlbumResponseDto,
mapAlbum,
mapAlbumWithAssets,
mapAlbumWithoutAssets,
} from './album-response.dto';
import { AddUsersDto, AlbumInfoDto, CreateAlbumDto, GetAlbumsDto, UpdateAlbumDto } from './dto';
} from 'src/domain/album/album-response.dto';
import { AddUsersDto } from 'src/domain/album/dto/album-add-users.dto';
import { CreateAlbumDto } from 'src/domain/album/dto/album-create.dto';
import { UpdateAlbumDto } from 'src/domain/album/dto/album-update.dto';
import { AlbumInfoDto } from 'src/domain/album/dto/album.dto';
import { GetAlbumsDto } from 'src/domain/album/dto/get-albums.dto';
import { BulkIdErrorReason, BulkIdResponseDto, BulkIdsDto } from 'src/domain/asset/response-dto/asset-ids-response.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { AlbumEntity } from 'src/infra/entities/album.entity';
import { AssetEntity } from 'src/infra/entities/asset.entity';
import { UserEntity } from 'src/infra/entities/user.entity';
import { IAccessRepository } from 'src/interfaces/access.repository';
import { AlbumAssetCount, AlbumInfoOptions, IAlbumRepository } from 'src/interfaces/album.repository';
import { IAssetRepository } from 'src/interfaces/asset.repository';
import { IUserRepository } from 'src/interfaces/user.repository';
import { setUnion } from 'src/utils';
@Injectable()
export class AlbumService {
@ -29,7 +30,6 @@ export class AlbumService {
@Inject(IAccessRepository) accessRepository: IAccessRepository,
@Inject(IAlbumRepository) private albumRepository: IAlbumRepository,
@Inject(IAssetRepository) private assetRepository: IAssetRepository,
@Inject(IJobRepository) private jobRepository: IJobRepository,
@Inject(IUserRepository) private userRepository: IUserRepository,
) {
this.access = AccessCore.create(accessRepository);

View File

@ -1,5 +1,5 @@
import { ArrayNotEmpty } from 'class-validator';
import { ValidateUUID } from '../../domain.util';
import { ValidateUUID } from 'src/validation';
export class AddUsersDto {
@ValidateUUID({ each: true })

View File

@ -1,6 +1,6 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';
import { Optional, ValidateUUID } from '../../domain.util';
import { Optional, ValidateUUID } from 'src/validation';
export class CreateAlbumDto {
@IsString()

View File

@ -1,7 +1,7 @@
import { AssetOrder } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger';
import { IsEnum, IsString } from 'class-validator';
import { Optional, ValidateBoolean, ValidateUUID } from '../../domain.util';
import { AssetOrder } from 'src/infra/entities/album.entity';
import { Optional, ValidateBoolean, ValidateUUID } from 'src/validation';
export class UpdateAlbumDto {
@Optional()

View File

@ -1,4 +1,4 @@
import { ValidateBoolean } from '../../domain.util';
import { ValidateBoolean } from 'src/validation';
export class AlbumInfoDto {
@ValidateBoolean({ optional: true })

View File

@ -1,4 +1,4 @@
import { ValidateBoolean, ValidateUUID } from '../../domain.util';
import { ValidateBoolean, ValidateUUID } from 'src/validation';
export class GetAlbumsDto {
@ValidateBoolean({ optional: true })

View File

@ -1,5 +0,0 @@
export * from './album-add-users.dto';
export * from './album-create.dto';
export * from './album-update.dto';
export * from './album.dto';
export * from './get-albums.dto';

View File

@ -1,3 +0,0 @@
export * from './album-response.dto';
export * from './album.service';
export * from './dto';

View File

@ -1,5 +1,5 @@
import { IsNotEmpty, IsString } from 'class-validator';
import { Optional } from '../domain.util';
import { Optional } from 'src/validation';
export class APIKeyCreateDto {
@IsString()
@IsNotEmpty()

View File

@ -1,7 +1,11 @@
import { BadRequestException } from '@nestjs/common';
import { authStub, keyStub, newCryptoRepositoryMock, newKeyRepositoryMock } from '@test';
import { ICryptoRepository, IKeyRepository } from '../repositories';
import { APIKeyService } from './api-key.service';
import { APIKeyService } from 'src/domain/api-key/api-key.service';
import { IKeyRepository } from 'src/interfaces/api-key.repository';
import { ICryptoRepository } from 'src/interfaces/crypto.repository';
import { keyStub } from 'test/fixtures/api-key.stub';
import { authStub } from 'test/fixtures/auth.stub';
import { newKeyRepositoryMock } from 'test/repositories/api-key.repository.mock';
import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock';
describe(APIKeyService.name, () => {
let sut: APIKeyService;

View File

@ -1,8 +1,9 @@
import { APIKeyEntity } from '@app/infra/entities';
import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { AuthDto } from '../auth';
import { ICryptoRepository, IKeyRepository } from '../repositories';
import { APIKeyCreateDto, APIKeyCreateResponseDto, APIKeyResponseDto } from './api-key.dto';
import { APIKeyCreateDto, APIKeyCreateResponseDto, APIKeyResponseDto } from 'src/domain/api-key/api-key.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { APIKeyEntity } from 'src/infra/entities/api-key.entity';
import { IKeyRepository } from 'src/interfaces/api-key.repository';
import { ICryptoRepository } from 'src/interfaces/crypto.repository';
@Injectable()
export class APIKeyService {

View File

@ -1,2 +0,0 @@
export * from './api-key.dto';
export * from './api-key.service';

View File

@ -1,42 +1,33 @@
import { AssetEntity, AssetType } from '@app/infra/entities';
import { BadRequestException, UnauthorizedException } from '@nestjs/common';
import {
IAccessRepositoryMock,
assetStackStub,
assetStub,
authStub,
faceStub,
newAccessRepositoryMock,
newAssetRepositoryMock,
newAssetStackRepositoryMock,
newCommunicationRepositoryMock,
newJobRepositoryMock,
newPartnerRepositoryMock,
newStorageRepositoryMock,
newSystemConfigRepositoryMock,
newUserRepositoryMock,
partnerStub,
userStub,
} from '@test';
import { when } from 'jest-when';
import { JobName } from '../job';
import {
AssetStats,
ClientEvent,
IAssetRepository,
IAssetStackRepository,
ICommunicationRepository,
IJobRepository,
IPartnerRepository,
IStorageRepository,
ISystemConfigRepository,
IUserRepository,
JobItem,
TimeBucketSize,
} from '../repositories';
import { AssetService, UploadFieldName } from './asset.service';
import { AssetJobName, AssetStatsResponseDto } from './dto';
import { mapAsset } from './response-dto';
import { AssetService, UploadFieldName } from 'src/domain/asset/asset.service';
import { AssetJobName } from 'src/domain/asset/dto/asset-ids.dto';
import { AssetStatsResponseDto } from 'src/domain/asset/dto/asset-statistics.dto';
import { mapAsset } from 'src/domain/asset/response-dto/asset-response.dto';
import { JobName } from 'src/domain/job/job.constants';
import { AssetEntity, AssetType } from 'src/infra/entities/asset.entity';
import { IAssetStackRepository } from 'src/interfaces/asset-stack.repository';
import { AssetStats, IAssetRepository, TimeBucketSize } from 'src/interfaces/asset.repository';
import { ClientEvent, ICommunicationRepository } from 'src/interfaces/communication.repository';
import { IJobRepository, JobItem } from 'src/interfaces/job.repository';
import { IPartnerRepository } from 'src/interfaces/partner.repository';
import { IStorageRepository } from 'src/interfaces/storage.repository';
import { ISystemConfigRepository } from 'src/interfaces/system-config.repository';
import { IUserRepository } from 'src/interfaces/user.repository';
import { assetStackStub, assetStub } from 'test/fixtures/asset.stub';
import { authStub } from 'test/fixtures/auth.stub';
import { faceStub } from 'test/fixtures/face.stub';
import { partnerStub } from 'test/fixtures/partner.stub';
import { userStub } from 'test/fixtures/user.stub';
import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
import { newAssetStackRepositoryMock } from 'test/repositories/asset-stack.repository.mock';
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
import { newCommunicationRepositoryMock } from 'test/repositories/communication.repository.mock';
import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
import { newPartnerRepositoryMock } from 'test/repositories/partner.repository.mock';
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
import { newUserRepositoryMock } from 'test/repositories/user.repository.mock';
const stats: AssetStats = {
[AssetType.IMAGE]: 10,

View File

@ -1,54 +1,43 @@
import { AssetEntity, LibraryType } from '@app/infra/entities';
import { ImmichLogger } from '@app/infra/logger';
import { BadRequestException, Inject } from '@nestjs/common';
import _ from 'lodash';
import { DateTime, Duration } from 'luxon';
import { extname } from 'node:path';
import sanitize from 'sanitize-filename';
import { AccessCore, Permission } from '../access';
import { AuthDto } from '../auth';
import { mimeTypes } from '../domain.constant';
import { usePagination } from '../domain.util';
import { IAssetDeletionJob, ISidecarWriteJob, JOBS_ASSET_PAGINATION_SIZE, JobName } from '../job';
import {
ClientEvent,
IAccessRepository,
IAssetRepository,
IAssetStackRepository,
ICommunicationRepository,
IJobRepository,
IPartnerRepository,
IStorageRepository,
ISystemConfigRepository,
IUserRepository,
JobItem,
JobStatus,
TimeBucketOptions,
} from '../repositories';
import { StorageCore, StorageFolder } from '../storage';
import { SystemConfigCore } from '../system-config';
import {
AssetBulkDeleteDto,
AssetBulkUpdateDto,
AssetJobName,
AssetJobsDto,
AssetStatsDto,
MapMarkerDto,
MemoryLaneDto,
TimeBucketAssetDto,
TimeBucketDto,
UpdateAssetDto,
UpdateStackParentDto,
mapStats,
} from './dto';
import { AccessCore, Permission } from 'src/cores/access.core';
import { StorageCore, StorageFolder } from 'src/cores/storage.core';
import { SystemConfigCore } from 'src/cores/system-config.core';
import { AssetJobName, AssetJobsDto } from 'src/domain/asset/dto/asset-ids.dto';
import { UpdateStackParentDto } from 'src/domain/asset/dto/asset-stack.dto';
import { AssetStatsDto, mapStats } from 'src/domain/asset/dto/asset-statistics.dto';
import { AssetBulkDeleteDto, AssetBulkUpdateDto, UpdateAssetDto } from 'src/domain/asset/dto/asset.dto';
import { MapMarkerDto } from 'src/domain/asset/dto/map-marker.dto';
import { MemoryLaneDto } from 'src/domain/asset/dto/memory-lane.dto';
import { TimeBucketAssetDto, TimeBucketDto } from 'src/domain/asset/dto/time-bucket.dto';
import {
AssetResponseDto,
MapMarkerResponseDto,
MemoryLaneResponseDto,
SanitizedAssetResponseDto,
TimeBucketResponseDto,
mapAsset,
} from './response-dto';
} from 'src/domain/asset/response-dto/asset-response.dto';
import { MapMarkerResponseDto } from 'src/domain/asset/response-dto/map-marker-response.dto';
import { TimeBucketResponseDto } from 'src/domain/asset/response-dto/time-bucket-response.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { mimeTypes } from 'src/domain/domain.constant';
import { JOBS_ASSET_PAGINATION_SIZE, JobName } from 'src/domain/job/job.constants';
import { IAssetDeletionJob, ISidecarWriteJob } from 'src/domain/job/job.interface';
import { AssetEntity } from 'src/infra/entities/asset.entity';
import { LibraryType } from 'src/infra/entities/library.entity';
import { ImmichLogger } from 'src/infra/logger';
import { IAccessRepository } from 'src/interfaces/access.repository';
import { IAssetStackRepository } from 'src/interfaces/asset-stack.repository';
import { IAssetRepository, TimeBucketOptions } from 'src/interfaces/asset.repository';
import { ClientEvent, ICommunicationRepository } from 'src/interfaces/communication.repository';
import { IJobRepository, JobItem, JobStatus } from 'src/interfaces/job.repository';
import { IPartnerRepository } from 'src/interfaces/partner.repository';
import { IStorageRepository } from 'src/interfaces/storage.repository';
import { ISystemConfigRepository } from 'src/interfaces/system-config.repository';
import { IUserRepository } from 'src/interfaces/user.repository';
import { usePagination } from 'src/utils';
export enum UploadFieldName {
ASSET_DATA = 'assetData',

View File

@ -1,6 +1,6 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsEnum } from 'class-validator';
import { ValidateUUID } from '../../domain.util';
import { ValidateUUID } from 'src/validation';
export class AssetIdsDto {
@ValidateUUID({ each: true })

View File

@ -1,4 +1,4 @@
import { ValidateUUID } from '../../domain.util';
import { ValidateUUID } from 'src/validation';
export class UpdateStackParentDto {
@ValidateUUID()

View File

@ -1,7 +1,7 @@
import { AssetType } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger';
import { ValidateBoolean } from '../../domain.util';
import { AssetStats } from '../../repositories';
import { AssetType } from 'src/infra/entities/asset.entity';
import { AssetStats } from 'src/interfaces/asset.repository';
import { ValidateBoolean } from 'src/validation';
export class AssetStatsDto {
@ValidateBoolean({ optional: true })

View File

@ -9,8 +9,8 @@ import {
IsString,
ValidateIf,
} from 'class-validator';
import { Optional, ValidateBoolean, ValidateUUID } from '../../domain.util';
import { BulkIdsDto } from '../response-dto';
import { BulkIdsDto } from 'src/domain/asset/response-dto/asset-ids-response.dto';
import { Optional, ValidateBoolean, ValidateUUID } from 'src/validation';
export class DeviceIdDto {
@IsNotEmpty()

View File

@ -1,7 +0,0 @@
export * from './asset-ids.dto';
export * from './asset-stack.dto';
export * from './asset-statistics.dto';
export * from './asset.dto';
export * from './map-marker.dto';
export * from './memory-lane.dto';
export * from './time-bucket.dto';

View File

@ -1,4 +1,4 @@
import { ValidateBoolean, ValidateDate } from '../../domain.util';
import { ValidateBoolean, ValidateDate } from 'src/validation';
export class MapMarkerDto {
@ValidateBoolean({ optional: true })

View File

@ -1,8 +1,8 @@
import { AssetOrder } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger';
import { IsEnum, IsNotEmpty, IsString } from 'class-validator';
import { Optional, ValidateBoolean, ValidateUUID } from '../../domain.util';
import { TimeBucketSize } from '../../repositories';
import { AssetOrder } from 'src/infra/entities/album.entity';
import { TimeBucketSize } from 'src/interfaces/asset.repository';
import { Optional, ValidateBoolean, ValidateUUID } from 'src/validation';
export class TimeBucketDto {
@IsNotEmpty()

View File

@ -1,3 +0,0 @@
export * from './asset.service';
export * from './dto';
export * from './response-dto';

Some files were not shown because too many files have changed in this diff Show More