Compare commits

...

14 Commits

Author SHA1 Message Date
github-actions
599b489f81 chore: version v1.120.1 2024-11-07 15:31:19 +00:00
Jason Rasmussen
0b98c5e3c4 fix(web): time zone dependent test (#13859) 2024-11-07 10:05:55 -05:00
Alex
b238b69689 fix(mobile): video player not playing in full size on Android (#13986) 2024-11-07 15:04:20 +00:00
Jason Rasmussen
decbc741e2 docs: update roadmap (#13984) 2024-11-07 09:24:21 -05:00
Sefa Eyeoglu
564449a555 fix(server): database backups compatible with deduplication (#13965)
gzip --rsyncable has a slightly worse compression ratio, but allows for
efficient deduplication and, as the name implies, faster rsync
operations.

Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2024-11-07 12:36:17 +00:00
Robert Schütz
f4741c70f3 fix(server): allow starting backup through API and fix pg_dumpall args when using database URLs (#13970)
* fix(server): allow starting backup through API

* fix(server): fix pg_dumpall args when using database URLs

The database has to be specified using `-d`, unlike for pg_dump.
2024-11-07 11:57:36 +00:00
yodatak
be2b76be8c docs: add backups to startup folders list (#13967)
Add the check of backups that is done on immich microservice of backups folder presence
2024-11-07 04:18:14 +00:00
Alex
cff0b95f4c chore(mobile): post release task (#13954) 2024-11-06 17:57:45 -05:00
Daniel Dietzler
1321a393c1 docs: 50k stars (#13964) 2024-11-06 22:49:18 +01:00
bo0tzz
a9fc840d65 chore: tidy up backup-and-restore.md (#13961) 2024-11-06 22:18:55 +01:00
Alex
ebf06dc12e fix(server): cannot render email template (#13957) 2024-11-06 22:14:11 +01:00
Thariq Shanavas
8d8becd0f7 docs: Added a note about avoiding redundant database backups (#13958)
* Add note about built-in backups

* npm run format:fix
2024-11-06 15:09:53 -06:00
slamp
3b5f5ec57a docs: improve custom-locations wording to be easier to read (#13849)
* Improve wording to make it easier to read custom-locations.md

It's only grammatical change

* Update docs/docs/guides/custom-locations.md

Co-authored-by: bo0tzz <git@bo0tzz.me>

* Update custom-locations.md

Revert to 'because of' and remove 'hard drive'

---------

Co-authored-by: bo0tzz <git@bo0tzz.me>
2024-11-06 19:49:23 +00:00
Daniel Dietzler
b29e4ec39f fix: docker link (#13956) 2024-11-06 13:45:52 -06:00
33 changed files with 294 additions and 195 deletions

6
cli/package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@immich/cli",
"version": "2.2.29",
"version": "2.2.30",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@immich/cli",
"version": "2.2.29",
"version": "2.2.30",
"license": "GNU Affero General Public License version 3",
"dependencies": {
"fast-glob": "^3.3.2",
@@ -52,7 +52,7 @@
},
"../open-api/typescript-sdk": {
"name": "@immich/sdk",
"version": "1.120.0",
"version": "1.120.1",
"dev": true,
"license": "GNU Affero General Public License version 3",
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@immich/cli",
"version": "2.2.29",
"version": "2.2.30",
"description": "Command Line Interface (CLI) for Immich",
"type": "module",
"exports": "./dist/index.js",

View File

@@ -15,8 +15,6 @@ Immich saves [file paths in the database](https://github.com/immich-app/immich/d
Refer to the official [postgres documentation](https://www.postgresql.org/docs/current/backup.html) for details about backing up and restoring a postgres database.
:::
The recommended way to backup and restore the Immich database is to use the `pg_dumpall` command. When restoring, you need to delete the `DB_DATA_LOCATION` folder (if it exists) to reset the database.
:::caution
It is not recommended to directly backup the `DB_DATA_LOCATION` folder. Doing so while the database is running can lead to a corrupted backup that cannot be restored.
:::
@@ -79,53 +77,10 @@ docker compose up -d # Start remainder of Immich apps
</TabItem>
</Tabs>
Note that for the database restore to proceed properly, it requires a completely fresh install (i.e. the Immich server has never run since creating the Docker containers). If the Immich app has run, Postgres conflicts may be encountered upon database restoration (relation already exists, violated foreign key constraints, multiple primary keys, etc.).
Note that for the database restore to proceed properly, it requires a completely fresh install (i.e. the Immich server has never run since creating the Docker containers). If the Immich app has run, Postgres conflicts may be encountered upon database restoration (relation already exists, violated foreign key constraints, multiple primary keys, etc.), in which case you need to delete the `DB_DATA_LOCATION` folder to reset the database.
:::tip
Some deployment methods make it difficult to start the database without also starting the server or microservices. In these cases, you may set the environmental variable `DB_SKIP_MIGRATIONS=true` before starting the services. This will prevent the server from running migrations that interfere with the restore process. Note that both the server and microservices must have this variable set to prevent the migrations from running. Be sure to remove this variable and restart the services after the database is restored.
:::
### Automatic Database Backups
The database dumps can also be automated (using [this image](https://github.com/prodrigestivill/docker-postgres-backup-local)) by editing the docker compose file to match the following:
```yaml
services:
...
backup:
container_name: immich_db_dumper
image: prodrigestivill/postgres-backup-local:14
restart: always
env_file:
- .env
environment:
POSTGRES_HOST: database
POSTGRES_CLUSTER: 'TRUE'
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_DATABASE_NAME}
SCHEDULE: "@daily"
POSTGRES_EXTRA_OPTS: '--clean --if-exists'
BACKUP_DIR: /db_dumps
volumes:
- ./db_dumps:/db_dumps
depends_on:
- database
```
Then you can restore with the same command but pointed at the latest dump.
```bash title='Automated Restore'
# Be sure to check the username if you changed it from default
gunzip < db_dumps/last/immich-latest.sql.gz \
| sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" \
| docker exec -i immich_postgres psql --username=postgres
```
:::note
If you see the error `ERROR: type "earth" does not exist`, or you have problems with Reverse Geocoding after a restore, add the following `sed` fragment to your restore command.
Example: `gunzip < "/path/to/backup/dump.sql.gz" | sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" | docker exec -i immich_postgres psql --username=postgres`
Some deployment methods make it difficult to start the database without also starting the server. In these cases, you may set the environment variable `DB_SKIP_MIGRATIONS=true` before starting the services. This will prevent the server from running migrations that interfere with the restore process. Be sure to remove this variable and restart the services after the database is restored.
:::
## Filesystem

View File

@@ -3,7 +3,7 @@
## Folder checks
:::info
The folders considered for these checks include: `upload/`, `library/`, `thumbs/`, `encoded-video/`, `profile/`
The folders considered for these checks include: `upload/`, `library/`, `thumbs/`, `encoded-video/`, `profile/`, `backups/`
:::
When Immich starts, it performs a series of checks in order to validate that it can read and write files to the volume mounts used by the storage system. If it cannot perform all the required operations, it will fail to start. The checks include:

View File

@@ -1,15 +1,15 @@
# Files Custom Locations
This guide explains storing generated and raw files with docker's volume mount in different locations.
This guide explains how to store generated and raw files with docker's volume mount in different locations.
:::caution Backup
It is important to remember to update the backup settings after following the guide to back up the new backup paths if using automatic backup tools, especially `profile/`.
:::
In our `.env` file, we will define variables that will help us in the future when we want to move to a more advanced server in the future
In our `.env` file, we will define variables that will help us in the future when we want to move to a more advanced server
```diff title=".env"
# You can find documentation for all the supported env variables [here](/docs/install/environment-variables)
# You can find documentation for all the supported environment variables [here](/docs/install/environment-variables)
# Custom location where your uploaded, thumbnails, and transcoded video files are stored
- UPLOAD_LOCATION=./library
@@ -20,7 +20,7 @@ In our `.env` file, we will define variables that will help us in the future whe
...
```
After defining the locations for these files, we will edit the `docker-compose.yml` file accordingly and add the new variables to the `immich-server` container.
After defining the locations of these files, we will edit the `docker-compose.yml` file accordingly and add the new variables to the `immich-server` container.
```diff title="docker-compose.yml"
services:
@@ -41,12 +41,11 @@ docker compose up -d
:::note
Because of the underlying properties of docker bind mounts, it is not recommended to mount the `upload/` and `library/` folders as separate bind mounts if they are on the same device.
For this reason, we mount the HDD or network storage to `/usr/src/app/upload` and then mount the folders we want quick access to below this folder.
For this reason, we mount the HDD or the network storage (NAS) to `/usr/src/app/upload` and then mount the folders we want to access under that folder.
The `thumbs/` folder contains both the small thumbnails shown in the timeline, and the larger previews shown when clicking into an image. These cannot be split up.
The `thumbs/` folder contains both the small thumbnails displayed in the timeline and the larger previews shown when clicking into an image. These cannot be separated.
The storage metrics of the Immich server will track the storage available at `UPLOAD_LOCATION`,
so the administrator should setup some kind of monitoring to make sure the SSD does not run out of space. The `profile/` folder is much smaller, typically less than 1 MB.
The storage metrics of the Immich server will track available storage at `UPLOAD_LOCATION`, so the administrator must set up some sort of monitoring to ensure the storage does not run out of space. The `profile/` folder is much smaller, usually less than 1 MB.
:::
Thanks to [Jrasm91](https://github.com/immich-app/immich/discussions/2110#discussioncomment-5477767) for writing the guide.

View File

@@ -6,6 +6,15 @@ This script assumes you have a second hard drive connected to your server for on
The database is saved to your Immich upload folder in the `database-backup` subdirectory. The database is then backed up and versioned with your assets by Borg. This ensures that the database backup is in sync with your assets in every snapshot.
:::info
This script makes backups of your database along with your photo/video library. This is redundant with the [automatic database backup tool](https://immich.app/docs/administration/backup-and-restore#automatic-database-backups) built into Immich. Using this script to backup your database has two advantages over the built-in backup tool:
- This script uses storage more efficiently by versioning your backups instead of making multiple copies.
- The database backups are performed at the same time as the library backup, ensuring that the backups of your database and the library are always in sync.
If you are using this script, it is therefore safe to turn off the built-in automatic database backups from your admin panel to save storage space.
:::
### Prerequisites
- Borg needs to be installed on your server as well as the remote machine. You can find instructions to install Borg [here](https://borgbackup.readthedocs.io/en/latest/installation.html).

View File

@@ -8,7 +8,7 @@ Hardware and software requirements for Immich:
## Software
- [Docker](https://docs.docker.com/get-docker/)
- [Docker](https://docs.docker.com/engine/install/)
- [Docker Compose](https://docs.docker.com/compose/install/)
:::note

View File

@@ -49,7 +49,7 @@ export function Timeline({ items }: Props): JSX.Element {
<div className="flex flex-col flex-grow justify-between gap-2">
<div className="flex gap-2 items-center">
{cardIcon === 'immich' ? (
<img src="img/immich-logo.svg" height="30" className="rounded-none" />
<img src="/img/immich-logo.svg" height="30" className="rounded-none" />
) : (
<Icon path={cardIcon} size={1} color={item.iconColor} />
)}

View File

@@ -74,12 +74,15 @@ import {
mdiFaceRecognition,
mdiVideo,
mdiWeb,
mdiDatabase,
mdiDatabaseOutline,
} from '@mdi/js';
import Layout from '@theme/Layout';
import React from 'react';
import { Item, Timeline } from '../components/timeline';
const releases = {
'v1.120.0': new Date(2024, 10, 6),
'v1.114.0': new Date(2024, 8, 6),
'v1.113.0': new Date(2024, 7, 30),
'v1.112.0': new Date(2024, 7, 14),
@@ -175,6 +178,38 @@ const withRelease = ({
};
const roadmap: Item[] = [
{
done: false,
icon: mdiFlash,
iconColor: 'gold',
title: 'Workflows',
description: 'Automate tasks with workflows',
getDateLabel: () => 'Planned for 2025',
},
{
done: false,
icon: mdiTableKey,
iconColor: 'gray',
title: 'Fine grained access controls',
description: 'Granular access controls for users and api keys',
getDateLabel: () => 'Planned for 2025',
},
{
done: false,
icon: mdiImageEdit,
iconColor: 'rebeccapurple',
title: 'Basic editor',
description: 'Basic photo editing capabilities',
getDateLabel: () => 'Planned for 2025',
},
{
done: false,
icon: mdiRocketLaunch,
iconColor: 'indianred',
title: 'Stable release',
description: 'Immich goes stable',
getDateLabel: () => 'Planned for early 2025',
},
{
done: false,
icon: mdiLockOutline,
@@ -183,14 +218,6 @@ const roadmap: Item[] = [
description: 'Private assets with extra protections',
getDateLabel: () => 'Planned for 2024',
},
{
done: false,
icon: mdiRocketLaunch,
iconColor: 'indianred',
title: 'Stable release',
description: 'Immich goes stable',
getDateLabel: () => 'Planned for 2024',
},
{
done: false,
icon: mdiCloudUploadOutline,
@@ -199,30 +226,6 @@ const roadmap: Item[] = [
description: 'Rework background backups to be more reliable',
getDateLabel: () => 'Planned for 2024',
},
{
done: false,
icon: mdiImageEdit,
iconColor: 'rebeccapurple',
title: 'Basic editor',
description: 'Basic photo editing capabilities',
getDateLabel: () => 'Planned for 2024',
},
{
done: false,
icon: mdiFlash,
iconColor: 'gold',
title: 'Workflows',
description: 'Automate tasks with workflows',
getDateLabel: () => 'Planned for 2024',
},
{
done: false,
icon: mdiTableKey,
iconColor: 'gray',
title: 'Fine grained access controls',
description: 'Granular access controls for users and api keys',
getDateLabel: () => 'Planned for 2024',
},
{
done: false,
icon: mdiCameraBurst,
@@ -234,6 +237,20 @@ const roadmap: Item[] = [
];
const milestones: Item[] = [
withRelease({
icon: mdiDatabaseOutline,
iconColor: 'brown',
title: 'Automatic database backups',
description: 'Database backups are now integrated into the Immich server',
release: 'v1.120.0',
}),
{
icon: mdiStar,
iconColor: 'gold',
title: '50,000 Stars',
description: 'Reached 50K Stars on GitHub!',
getDateLabel: withLanguage(new Date(2024, 10, 1)),
},
withRelease({
icon: mdiFaceRecognition,
title: 'Metadata Face Import',

View File

@@ -1,4 +1,8 @@
[
{
"label": "v1.120.1",
"url": "https://v1.120.1.archive.immich.app"
},
{
"label": "v1.120.0",
"url": "https://v1.120.0.archive.immich.app"

8
e2e/package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "immich-e2e",
"version": "1.120.0",
"version": "1.120.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "immich-e2e",
"version": "1.120.0",
"version": "1.120.1",
"license": "GNU Affero General Public License version 3",
"devDependencies": {
"@eslint/eslintrc": "^3.1.0",
@@ -45,7 +45,7 @@
},
"../cli": {
"name": "@immich/cli",
"version": "2.2.29",
"version": "2.2.30",
"dev": true,
"license": "GNU Affero General Public License version 3",
"dependencies": {
@@ -92,7 +92,7 @@
},
"../open-api/typescript-sdk": {
"name": "@immich/sdk",
"version": "1.120.0",
"version": "1.120.1",
"dev": true,
"license": "GNU Affero General Public License version 3",
"dependencies": {

View File

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

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "machine-learning"
version = "1.120.0"
version = "1.120.1"
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" => 165,
"android.injected.version.name" => "1.120.0",
"android.injected.version.code" => 166,
"android.injected.version.name" => "1.120.1",
}
)
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

@@ -207,7 +207,7 @@ SPEC CHECKSUMS:
geolocator_apple: 6cbaf322953988e009e5ecb481f07efece75c450
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073
isar_flutter_libs: fdf730ca925d05687f36d7f1d355e482529ed097
MapLibre: 620fc933c1d6029b33738c905c1490d024e5d4ef
maplibre_gl: a2efec727dd340e4c65e26d2b03b584f14881fd9
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c

View File

@@ -401,7 +401,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/RunnerProfile.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 181;
CURRENT_PROJECT_VERSION = 182;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -543,7 +543,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 181;
CURRENT_PROJECT_VERSION = 182;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@@ -571,7 +571,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 181;
CURRENT_PROJECT_VERSION = 182;
DEVELOPMENT_TEAM = 2F67MQ8R79;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;

View File

@@ -58,11 +58,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.119.0</string>
<string>1.120.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>181</string>
<string>182</string>
<key>FLTEnableImpeller</key>
<true/>
<key>ITSAppUsesNonExemptEncryption</key>

View File

@@ -19,7 +19,7 @@ platform :ios do
desc "iOS Release"
lane :release do
increment_version_number(
version_number: "1.120.0"
version_number: "1.120.1"
)
increment_build_number(
build_number: latest_testflight_build_number + 1,

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.120.0
- API version: 1.120.1
- Generator version: 7.8.0
- Build package: org.openapitools.codegen.languages.DartClientCodegen

View File

@@ -1717,13 +1717,13 @@ packages:
source: hosted
version: "2.9.2"
video_player_android:
dependency: transitive
dependency: "direct main"
description:
name: video_player_android
sha256: "391e092ba4abe2f93b3e625bd6b6a6ec7d7414279462c1c0ee42b5ab8d0a0898"
sha256: "4de50df9ee786f5891d3281e1e633d7b142ef1acf47392592eb91cba5d355849"
url: "https://pub.dev"
source: hosted
version: "2.7.16"
version: "2.6.0"
video_player_avfoundation:
dependency: transitive
description:

View File

@@ -2,7 +2,7 @@ name: immich_mobile
description: Immich - selfhosted backup media file on mobile phone
publish_to: 'none'
version: 1.120.0+165
version: 1.120.1+166
environment:
sdk: '>=3.3.0 <4.0.0'
@@ -26,6 +26,7 @@ dependencies:
auto_route: ^9.2.0
fluttertoast: ^8.2.4
video_player: ^2.9.2
video_player_android: 2.6.0
chewie: ^1.7.4
socket_io_client: ^2.0.3+1
maplibre_gl: 0.19.0+2

View File

@@ -7385,7 +7385,7 @@
"info": {
"title": "Immich",
"description": "Immich API",
"version": "1.120.0",
"version": "1.120.1",
"contact": {}
},
"tags": [],

View File

@@ -1,12 +1,12 @@
{
"name": "@immich/sdk",
"version": "1.120.0",
"version": "1.120.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@immich/sdk",
"version": "1.120.0",
"version": "1.120.1",
"license": "GNU Affero General Public License version 3",
"dependencies": {
"@oazapfts/runtime": "^1.0.2"

View File

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

View File

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

169
server/package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "immich",
"version": "1.120.0",
"version": "1.120.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "immich",
"version": "1.120.0",
"version": "1.120.1",
"license": "GNU Affero General Public License version 3",
"dependencies": {
"@nestjs/bullmq": "^10.0.1",
@@ -23,7 +23,7 @@
"@opentelemetry/context-async-hooks": "^1.24.0",
"@opentelemetry/exporter-prometheus": "^0.54.0",
"@opentelemetry/sdk-node": "^0.54.0",
"@react-email/components": "^0.0.26",
"@react-email/components": "^0.0.25",
"@socket.io/redis-adapter": "^8.3.0",
"archiver": "^7.0.0",
"async-lock": "^1.4.0",
@@ -2643,7 +2643,8 @@
"node_modules/@one-ini/wasm": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz",
"integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw=="
"integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==",
"license": "MIT"
},
"node_modules/@opentelemetry/api": {
"version": "1.8.0",
@@ -3966,9 +3967,10 @@
}
},
"node_modules/@react-email/button": {
"version": "0.0.18",
"resolved": "https://registry.npmjs.org/@react-email/button/-/button-0.0.18.tgz",
"integrity": "sha512-uNUnpeDzz1o9HAky47JSTsUN/Ih0A3Az165AAOgAy8XOVzQJPrltUBRzHkScSVJTwRqKLASkie1yZbtNGIcRdA==",
"version": "0.0.17",
"resolved": "https://registry.npmjs.org/@react-email/button/-/button-0.0.17.tgz",
"integrity": "sha512-ioHdsk+BpGS/PqjU6JS7tUrVy9yvbUx92Z+Cem2+MbYp55oEwQ9VHf7u4f5NoM0gdhfKSehBwRdYlHt/frEMcg==",
"license": "MIT",
"engines": {
"node": ">=18.0.0"
},
@@ -4013,12 +4015,13 @@
}
},
"node_modules/@react-email/components": {
"version": "0.0.26",
"resolved": "https://registry.npmjs.org/@react-email/components/-/components-0.0.26.tgz",
"integrity": "sha512-FqxCGnQiI4zztEBAXPfjovIQ9e1l7NJNMgE8hSaH7slWySFn/PpPRQFYpxyCFNr9DqPVHtKYtpo8xvUYx2LdTg==",
"version": "0.0.25",
"resolved": "https://registry.npmjs.org/@react-email/components/-/components-0.0.25.tgz",
"integrity": "sha512-lnfVVrThEcET5NPoeaXvrz9UxtWpGRcut2a07dLbyKgNbP7vj/cXTI5TuHtanCvhCddFpMDnElNRghDOfPzwUg==",
"license": "MIT",
"dependencies": {
"@react-email/body": "0.0.10",
"@react-email/button": "0.0.18",
"@react-email/button": "0.0.17",
"@react-email/code-block": "0.0.9",
"@react-email/code-inline": "0.0.4",
"@react-email/column": "0.0.12",
@@ -4029,13 +4032,13 @@
"@react-email/hr": "0.0.10",
"@react-email/html": "0.0.10",
"@react-email/img": "0.0.10",
"@react-email/link": "0.0.11",
"@react-email/link": "0.0.10",
"@react-email/markdown": "0.0.12",
"@react-email/preview": "0.0.11",
"@react-email/render": "1.0.2",
"@react-email/row": "0.0.11",
"@react-email/section": "0.0.15",
"@react-email/tailwind": "1.0.0",
"@react-email/render": "1.0.1",
"@react-email/row": "0.0.10",
"@react-email/section": "0.0.14",
"@react-email/tailwind": "0.1.0",
"@react-email/text": "0.0.10"
},
"engines": {
@@ -4120,9 +4123,10 @@
}
},
"node_modules/@react-email/link": {
"version": "0.0.11",
"resolved": "https://registry.npmjs.org/@react-email/link/-/link-0.0.11.tgz",
"integrity": "sha512-o1/BgPn2Fi+bN4Nh+P64t4tulaOyPhkBNSpNmiYL1Ar+ilw8q0BmUAqM+lvHy8Qr/4K7BjkgFoc4GoYkoEjOig==",
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/@react-email/link/-/link-0.0.10.tgz",
"integrity": "sha512-tva3wvAWSR10lMJa9fVA09yRn7pbEki0ZZpHE6GD1jKbFhmzt38VgLO9B797/prqoDZdAr4rVK7LJFcdPx3GwA==",
"license": "MIT",
"engines": {
"node": ">=18.0.0"
},
@@ -4156,9 +4160,10 @@
}
},
"node_modules/@react-email/render": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@react-email/render/-/render-1.0.2.tgz",
"integrity": "sha512-q82eBd39TepzA/xjlm8szqJlrQk/gh7mgtxXMGlJ4dcdx89go1m9YBDpZY98SFy+2r2KAOd5A1mxvUbsPwoATg==",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@react-email/render/-/render-1.0.1.tgz",
"integrity": "sha512-W3gTrcmLOVYnG80QuUp22ReIT/xfLsVJ+n7ghSlG2BITB8evNABn1AO2rGQoXuK84zKtDAlxCdm3hRyIpZdGSA==",
"license": "MIT",
"dependencies": {
"html-to-text": "9.0.5",
"js-beautify": "^1.14.11",
@@ -4173,9 +4178,10 @@
}
},
"node_modules/@react-email/row": {
"version": "0.0.11",
"resolved": "https://registry.npmjs.org/@react-email/row/-/row-0.0.11.tgz",
"integrity": "sha512-ra09h7BMoGa14ds3vh7KVuj1N3astTstEC1YbMdCiHcx/nxylglNaT7qJXU74ZTzyHiGabyiNuyabTS+HLoMCA==",
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/@react-email/row/-/row-0.0.10.tgz",
"integrity": "sha512-jPyEhG3gsLX+Eb9U+A30fh0gK6hXJwF4ghJ+ZtFQtlKAKqHX+eCpWlqB3Xschd/ARJLod8WAswg0FB+JD9d0/A==",
"license": "MIT",
"engines": {
"node": ">=18.0.0"
},
@@ -4184,9 +4190,10 @@
}
},
"node_modules/@react-email/section": {
"version": "0.0.15",
"resolved": "https://registry.npmjs.org/@react-email/section/-/section-0.0.15.tgz",
"integrity": "sha512-xfM3Qy5eU7fbkwvktlTeQgad7uo+1Z7YVh1aowSZaRBvKbkEXgoH/XssRYQmQL8ZrZGXbEJMujwtf4fsQL6vrg==",
"version": "0.0.14",
"resolved": "https://registry.npmjs.org/@react-email/section/-/section-0.0.14.tgz",
"integrity": "sha512-+fYWLb4tPU1A/+GE5J1+SEMA7/wR3V30lQ+OR9t2kAJqNrARDbMx0bLnYnR1QL5TiFRz0pCF05SQUobk6gHEDQ==",
"license": "MIT",
"engines": {
"node": ">=18.0.0"
},
@@ -4195,9 +4202,10 @@
}
},
"node_modules/@react-email/tailwind": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@react-email/tailwind/-/tailwind-1.0.0.tgz",
"integrity": "sha512-LV0SflR0aI5Sjxyp8upyPL8Ctwj+7aqwTgCDO9yZuOI6KpXbBGaYz8bSofe8oaVc/BmymZ5O3+/7FjQexbW+Yg==",
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@react-email/tailwind/-/tailwind-0.1.0.tgz",
"integrity": "sha512-qysVUEY+M3SKUvu35XDpzn7yokhqFOT3tPU6Mj/pgc62TL5tQFj6msEbBtwoKs2qO3WZvai0DIHdLhaOxBQSow==",
"license": "MIT",
"engines": {
"node": ">=18.0.0"
},
@@ -4468,6 +4476,7 @@
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
"integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==",
"license": "MIT",
"dependencies": {
"domhandler": "^5.0.3",
"selderee": "^0.11.0"
@@ -7059,6 +7068,7 @@
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
"integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==",
"license": "MIT",
"dependencies": {
"ini": "^1.3.4",
"proto-list": "~1.2.1"
@@ -7553,6 +7563,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"license": "MIT",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
@@ -7571,12 +7582,14 @@
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
]
],
"license": "BSD-2-Clause"
},
"node_modules/domhandler": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"license": "BSD-2-Clause",
"dependencies": {
"domelementtype": "^2.3.0"
},
@@ -7591,6 +7604,7 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
"license": "BSD-2-Clause",
"dependencies": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
@@ -7620,6 +7634,7 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz",
"integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==",
"license": "MIT",
"dependencies": {
"@one-ini/wasm": "0.1.1",
"commander": "^10.0.0",
@@ -7637,6 +7652,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
@@ -7645,6 +7661,7 @@
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
"license": "MIT",
"engines": {
"node": ">=14"
}
@@ -7653,6 +7670,7 @@
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz",
"integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
@@ -7740,6 +7758,7 @@
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
},
@@ -9072,6 +9091,7 @@
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz",
"integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==",
"license": "MIT",
"dependencies": {
"@selderee/plugin-htmlparser2": "^0.11.0",
"deepmerge": "^4.3.1",
@@ -9094,6 +9114,7 @@
"url": "https://github.com/sponsors/fb55"
}
],
"license": "MIT",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3",
@@ -9239,7 +9260,8 @@
"node_modules/ini": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
"license": "ISC"
},
"node_modules/inquirer": {
"version": "8.2.6",
@@ -9537,6 +9559,7 @@
"version": "1.15.1",
"resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.1.tgz",
"integrity": "sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==",
"license": "MIT",
"dependencies": {
"config-chain": "^1.1.13",
"editorconfig": "^1.0.4",
@@ -9557,14 +9580,16 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",
"integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==",
"license": "ISC",
"engines": {
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
},
"node_modules/js-beautify/node_modules/nopt": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz",
"integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==",
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz",
"integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==",
"license": "ISC",
"dependencies": {
"abbrev": "^2.0.0"
},
@@ -9579,6 +9604,7 @@
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
"integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
"license": "MIT",
"engines": {
"node": ">=14"
}
@@ -9722,6 +9748,7 @@
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz",
"integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==",
"license": "MIT",
"funding": {
"url": "https://ko-fi.com/killymxi"
}
@@ -10873,6 +10900,7 @@
"version": "0.12.1",
"resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz",
"integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==",
"license": "MIT",
"dependencies": {
"leac": "^0.6.0",
"peberminta": "^0.9.0"
@@ -10995,6 +11023,7 @@
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz",
"integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==",
"license": "MIT",
"funding": {
"url": "https://ko-fi.com/killymxi"
}
@@ -11455,7 +11484,8 @@
"node_modules/proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
"integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="
"integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==",
"license": "ISC"
},
"node_modules/protobufjs": {
"version": "7.4.0",
@@ -12118,6 +12148,7 @@
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/react-promise-suspense/-/react-promise-suspense-0.3.4.tgz",
"integrity": "sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^2.0.1"
}
@@ -12125,7 +12156,8 @@
"node_modules/react-promise-suspense/node_modules/fast-deep-equal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
"integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w=="
"integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==",
"license": "MIT"
},
"node_modules/read-cache": {
"version": "1.0.0",
@@ -12765,6 +12797,7 @@
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz",
"integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==",
"license": "MIT",
"dependencies": {
"parseley": "^0.12.0"
},
@@ -17450,9 +17483,9 @@
"requires": {}
},
"@react-email/button": {
"version": "0.0.18",
"resolved": "https://registry.npmjs.org/@react-email/button/-/button-0.0.18.tgz",
"integrity": "sha512-uNUnpeDzz1o9HAky47JSTsUN/Ih0A3Az165AAOgAy8XOVzQJPrltUBRzHkScSVJTwRqKLASkie1yZbtNGIcRdA==",
"version": "0.0.17",
"resolved": "https://registry.npmjs.org/@react-email/button/-/button-0.0.17.tgz",
"integrity": "sha512-ioHdsk+BpGS/PqjU6JS7tUrVy9yvbUx92Z+Cem2+MbYp55oEwQ9VHf7u4f5NoM0gdhfKSehBwRdYlHt/frEMcg==",
"requires": {}
},
"@react-email/code-block": {
@@ -17476,12 +17509,12 @@
"requires": {}
},
"@react-email/components": {
"version": "0.0.26",
"resolved": "https://registry.npmjs.org/@react-email/components/-/components-0.0.26.tgz",
"integrity": "sha512-FqxCGnQiI4zztEBAXPfjovIQ9e1l7NJNMgE8hSaH7slWySFn/PpPRQFYpxyCFNr9DqPVHtKYtpo8xvUYx2LdTg==",
"version": "0.0.25",
"resolved": "https://registry.npmjs.org/@react-email/components/-/components-0.0.25.tgz",
"integrity": "sha512-lnfVVrThEcET5NPoeaXvrz9UxtWpGRcut2a07dLbyKgNbP7vj/cXTI5TuHtanCvhCddFpMDnElNRghDOfPzwUg==",
"requires": {
"@react-email/body": "0.0.10",
"@react-email/button": "0.0.18",
"@react-email/button": "0.0.17",
"@react-email/code-block": "0.0.9",
"@react-email/code-inline": "0.0.4",
"@react-email/column": "0.0.12",
@@ -17492,13 +17525,13 @@
"@react-email/hr": "0.0.10",
"@react-email/html": "0.0.10",
"@react-email/img": "0.0.10",
"@react-email/link": "0.0.11",
"@react-email/link": "0.0.10",
"@react-email/markdown": "0.0.12",
"@react-email/preview": "0.0.11",
"@react-email/render": "1.0.2",
"@react-email/row": "0.0.11",
"@react-email/section": "0.0.15",
"@react-email/tailwind": "1.0.0",
"@react-email/render": "1.0.1",
"@react-email/row": "0.0.10",
"@react-email/section": "0.0.14",
"@react-email/tailwind": "0.1.0",
"@react-email/text": "0.0.10"
}
},
@@ -17545,9 +17578,9 @@
"requires": {}
},
"@react-email/link": {
"version": "0.0.11",
"resolved": "https://registry.npmjs.org/@react-email/link/-/link-0.0.11.tgz",
"integrity": "sha512-o1/BgPn2Fi+bN4Nh+P64t4tulaOyPhkBNSpNmiYL1Ar+ilw8q0BmUAqM+lvHy8Qr/4K7BjkgFoc4GoYkoEjOig==",
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/@react-email/link/-/link-0.0.10.tgz",
"integrity": "sha512-tva3wvAWSR10lMJa9fVA09yRn7pbEki0ZZpHE6GD1jKbFhmzt38VgLO9B797/prqoDZdAr4rVK7LJFcdPx3GwA==",
"requires": {}
},
"@react-email/markdown": {
@@ -17565,9 +17598,9 @@
"requires": {}
},
"@react-email/render": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@react-email/render/-/render-1.0.2.tgz",
"integrity": "sha512-q82eBd39TepzA/xjlm8szqJlrQk/gh7mgtxXMGlJ4dcdx89go1m9YBDpZY98SFy+2r2KAOd5A1mxvUbsPwoATg==",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@react-email/render/-/render-1.0.1.tgz",
"integrity": "sha512-W3gTrcmLOVYnG80QuUp22ReIT/xfLsVJ+n7ghSlG2BITB8evNABn1AO2rGQoXuK84zKtDAlxCdm3hRyIpZdGSA==",
"requires": {
"html-to-text": "9.0.5",
"js-beautify": "^1.14.11",
@@ -17575,21 +17608,21 @@
}
},
"@react-email/row": {
"version": "0.0.11",
"resolved": "https://registry.npmjs.org/@react-email/row/-/row-0.0.11.tgz",
"integrity": "sha512-ra09h7BMoGa14ds3vh7KVuj1N3astTstEC1YbMdCiHcx/nxylglNaT7qJXU74ZTzyHiGabyiNuyabTS+HLoMCA==",
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/@react-email/row/-/row-0.0.10.tgz",
"integrity": "sha512-jPyEhG3gsLX+Eb9U+A30fh0gK6hXJwF4ghJ+ZtFQtlKAKqHX+eCpWlqB3Xschd/ARJLod8WAswg0FB+JD9d0/A==",
"requires": {}
},
"@react-email/section": {
"version": "0.0.15",
"resolved": "https://registry.npmjs.org/@react-email/section/-/section-0.0.15.tgz",
"integrity": "sha512-xfM3Qy5eU7fbkwvktlTeQgad7uo+1Z7YVh1aowSZaRBvKbkEXgoH/XssRYQmQL8ZrZGXbEJMujwtf4fsQL6vrg==",
"version": "0.0.14",
"resolved": "https://registry.npmjs.org/@react-email/section/-/section-0.0.14.tgz",
"integrity": "sha512-+fYWLb4tPU1A/+GE5J1+SEMA7/wR3V30lQ+OR9t2kAJqNrARDbMx0bLnYnR1QL5TiFRz0pCF05SQUobk6gHEDQ==",
"requires": {}
},
"@react-email/tailwind": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@react-email/tailwind/-/tailwind-1.0.0.tgz",
"integrity": "sha512-LV0SflR0aI5Sjxyp8upyPL8Ctwj+7aqwTgCDO9yZuOI6KpXbBGaYz8bSofe8oaVc/BmymZ5O3+/7FjQexbW+Yg==",
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@react-email/tailwind/-/tailwind-0.1.0.tgz",
"integrity": "sha512-qysVUEY+M3SKUvu35XDpzn7yokhqFOT3tPU6Mj/pgc62TL5tQFj6msEbBtwoKs2qO3WZvai0DIHdLhaOxBQSow==",
"requires": {}
},
"@react-email/text": {
@@ -21551,9 +21584,9 @@
"integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ=="
},
"nopt": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz",
"integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==",
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz",
"integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==",
"requires": {
"abbrev": "^2.0.0"
}

View File

@@ -1,6 +1,6 @@
{
"name": "immich",
"version": "1.120.0",
"version": "1.120.1",
"description": "",
"author": "",
"private": true,
@@ -48,7 +48,7 @@
"@opentelemetry/context-async-hooks": "^1.24.0",
"@opentelemetry/exporter-prometheus": "^0.54.0",
"@opentelemetry/sdk-node": "^0.54.0",
"@react-email/components": "^0.0.26",
"@react-email/components": "^0.0.25",
"@socket.io/redis-adapter": "^8.3.0",
"archiver": "^7.0.0",
"async-lock": "^1.4.0",

View File

@@ -0,0 +1,74 @@
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { EmailRenderRequest, EmailTemplate } from 'src/interfaces/notification.interface';
import { NotificationRepository } from 'src/repositories/notification.repository';
import { Mocked } from 'vitest';
describe(NotificationRepository.name, () => {
let sut: NotificationRepository;
let loggerMock: Mocked<ILoggerRepository>;
beforeEach(() => {
loggerMock = {
setContext: vitest.fn(),
debug: vitest.fn(),
} as unknown as Mocked<ILoggerRepository>;
sut = new NotificationRepository(loggerMock);
});
describe('renderEmail', () => {
it('should render the email correctly for TEST_EMAIL template', async () => {
const request: EmailRenderRequest = {
template: EmailTemplate.TEST_EMAIL,
data: { displayName: 'Alen Turing', baseUrl: 'http://localhost' },
};
const result = await sut.renderEmail(request);
expect(result.html).toContain('<!DOCTYPE html PUBLIC');
expect(result.text).toContain('test email');
});
it('should render the email correctly for WELCOME template', async () => {
const request: EmailRenderRequest = {
template: EmailTemplate.WELCOME,
data: { displayName: 'Alen Turing', username: 'turing', baseUrl: 'http://localhost' },
};
const result = await sut.renderEmail(request);
expect(result.html).toContain('<!DOCTYPE html PUBLIC');
expect(result.text).toContain('A new account has been created for you');
});
it('should render the email correctly for ALBUM_INVITE template', async () => {
const request: EmailRenderRequest = {
template: EmailTemplate.ALBUM_INVITE,
data: {
albumName: 'Vacation',
albumId: '123',
senderName: 'John',
recipientName: 'Jane',
baseUrl: 'http://localhost',
},
};
const result = await sut.renderEmail(request);
expect(result.html).toContain('<!DOCTYPE html PUBLIC');
expect(result.text).toContain('Vacation');
});
it('should render the email correctly for ALBUM_UPDATE template', async () => {
const request: EmailRenderRequest = {
template: EmailTemplate.ALBUM_UPDATE,
data: { albumName: 'Holiday', albumId: '123', recipientName: 'Jane', baseUrl: 'http://localhost' },
};
const result = await sut.renderEmail(request);
expect(result.html).toContain('<!DOCTYPE html PUBLIC');
expect(result.text).toContain('Holiday');
});
});
});

View File

@@ -85,7 +85,7 @@ export class BackupService extends BaseService {
} = this.configRepository.getEnv();
const isUrlConnection = config.connectionType === 'url';
const databaseParams = isUrlConnection ? [config.url] : ['-U', config.username, '-h', config.host];
const databaseParams = isUrlConnection ? ['-d', config.url] : ['-U', config.username, '-h', config.host];
const backupFilePath = path.join(
StorageCore.getBaseFolder(StorageFolder.BACKUPS),
`immich-db-backup-${Date.now()}.sql.gz.tmp`,
@@ -97,7 +97,8 @@ export class BackupService extends BaseService {
env: { PATH: process.env.PATH, PGPASSWORD: isUrlConnection ? undefined : config.password },
});
const gzip = this.processRepository.spawn(`gzip`, []);
// NOTE: `--rsyncable` is only supported in GNU gzip
const gzip = this.processRepository.spawn(`gzip`, ['--rsyncable']);
pgdump.stdout.pipe(gzip.stdin);
const fileStream = this.storageRepository.createWriteStream(backupFilePath);

View File

@@ -164,6 +164,10 @@ export class JobService extends BaseService {
return this.jobRepository.queue({ name: JobName.LIBRARY_QUEUE_SYNC_ALL, data: { force } });
}
case QueueName.BACKUP_DATABASE: {
return this.jobRepository.queue({ name: JobName.BACKUP_DATABASE, data: { force } });
}
default: {
throw new BadRequestException(`Invalid job name: ${name}`);
}

6
web/package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "immich-web",
"version": "1.120.0",
"version": "1.120.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "immich-web",
"version": "1.120.0",
"version": "1.120.1",
"license": "GNU Affero General Public License version 3",
"dependencies": {
"@formatjs/icu-messageformat-parser": "^2.7.8",
@@ -74,7 +74,7 @@
},
"../open-api/typescript-sdk": {
"name": "@immich/sdk",
"version": "1.120.0",
"version": "1.120.1",
"license": "GNU Affero General Public License version 3",
"dependencies": {
"@oazapfts/runtime": "^1.0.2"

View File

@@ -1,6 +1,6 @@
{
"name": "immich-web",
"version": "1.120.0",
"version": "1.120.1",
"license": "GNU Affero General Public License version 3",
"scripts": {
"dev": "vite dev --host 0.0.0.0 --port 3000",

View File

@@ -5,11 +5,13 @@ import { DateTime } from 'luxon';
describe('formatGroupTitle', () => {
beforeAll(() => {
vi.useFakeTimers();
process.env.TZ = 'UTC';
vi.setSystemTime(new Date('2024-07-27T12:00:00Z'));
});
afterAll(() => {
vi.useRealTimers();
delete process.env.TZ;
});
it('formats today', () => {