From ef9db0967c7071d0b59104d6972e1014a40f55b0 Mon Sep 17 00:00:00 2001 From: Jason Rasmussen Date: Tue, 31 Mar 2026 15:57:05 -0400 Subject: [PATCH] feat: march recap (#419) --- apps/root.immich.app/example.env | 8 + apps/root.immich.app/package.json | 6 +- .../routes/blog/2025-november-recap/+page.md | 4 +- .../routes/blog/2025-year-in-review/+page.md | 7 +- .../routes/blog/2026-february-recap/+page.md | 6 +- .../src/routes/blog/2026-march-recap/+page.md | 156 ++++++++++++++++++ .../src/routes/blog/immich-editor/+page.md | 2 +- import-post.py | 3 +- pnpm-lock.yaml | 74 ++++++++- 9 files changed, 249 insertions(+), 17 deletions(-) create mode 100644 apps/root.immich.app/example.env create mode 100644 apps/root.immich.app/src/routes/blog/2026-march-recap/+page.md diff --git a/apps/root.immich.app/example.env b/apps/root.immich.app/example.env new file mode 100644 index 00000000..e9dc242b --- /dev/null +++ b/apps/root.immich.app/example.env @@ -0,0 +1,8 @@ +# outline sync stuff +OUTLINE_POST_URL=https://outline.immich.cloud/doc/march-recap-XXXXXXXXXX +OUTLINE_API_KEY= +R2_BUCKET_NAME=static +R2_ENDPOINT_URL= +R2_ACCESS_KEY_ID= +R2_SECRET_ACCESS_KEY= +R2_PUBLIC_URL=https://static.immich.cloud diff --git a/apps/root.immich.app/package.json b/apps/root.immich.app/package.json index 9505e075..45432378 100644 --- a/apps/root.immich.app/package.json +++ b/apps/root.immich.app/package.json @@ -7,6 +7,7 @@ "start": "vite dev", "build": "npm run sync && vite build && node ../../bin/postbuild.js", "preview": "vite preview", + "import-post": "dotenv -- uv run ../../import-post.py", "check": "npm run sync && svelte-check --tsconfig ./tsconfig.json", "uuid": "npx -y uuid v7", "sync": "svelte-kit sync", @@ -19,7 +20,7 @@ "devDependencies": { "@eslint/compat": "^2.0.0", "@eslint/js": "^10.0.0", - "@immich/svelte-markdown-preprocess": "^0.2.1", + "@immich/svelte-markdown-preprocess": "^0.3.0", "@sveltejs/adapter-static": "^3.0.9", "@sveltejs/kit": "^2.55.0", "@sveltejs/vite-plugin-svelte": "^7.0.0", @@ -28,6 +29,7 @@ "@types/node": "^24.12.0", "@vitest/browser": "^4.1.0", "dotenv": "^17.2.3", + "dotenv-cli": "^11.0.0", "eslint": "^10.0.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-svelte": "^3.12.4", @@ -49,7 +51,7 @@ "vitest-browser-svelte": "^2.0.0" }, "dependencies": { - "@immich/ui": "^0.67.0", + "@immich/ui": "^0.70.0", "@mdi/js": "^7.4.47", "feed": "^5.1.0", "front-matter": "^4.0.2", diff --git a/apps/root.immich.app/src/routes/blog/2025-november-recap/+page.md b/apps/root.immich.app/src/routes/blog/2025-november-recap/+page.md index 89ccd15e..d5f1d88b 100644 --- a/apps/root.immich.app/src/routes/blog/2025-november-recap/+page.md +++ b/apps/root.immich.app/src/routes/blog/2025-november-recap/+page.md @@ -30,13 +30,13 @@ Alex has been hard at work building out the feature. The initial backend work wa Each workflow will run in response to a triggering event, like asset upload. -![Workflow trigger](https://static.immich.cloud/blog/b5734354-7296-4289-b26a-2d8cfe402ef3/a045ca1e4befbcebb7a37143b48425a5.webp ' =1042x349') +![Workflow trigger](https://static.immich.cloud/blog/b5734354-7296-4289-b26a-2d8cfe402ef3/a045ca1e4befbcebb7a37143b48425a5.webp) ### Filter Each workflow can include one of more filters, which can decide if the event should be processed or skipped. -![Workflow filter](https://static.immich.cloud/blog/b5734354-7296-4289-b26a-2d8cfe402ef3/396dfe40a3b7e157c3a907f2f6324afe.webp ' =1045x850') +![Workflow filter](https://static.immich.cloud/blog/b5734354-7296-4289-b26a-2d8cfe402ef3/396dfe40a3b7e157c3a907f2f6324afe.webp) ### Action diff --git a/apps/root.immich.app/src/routes/blog/2025-year-in-review/+page.md b/apps/root.immich.app/src/routes/blog/2025-year-in-review/+page.md index 63ff6108..ef496949 100644 --- a/apps/root.immich.app/src/routes/blog/2025-year-in-review/+page.md +++ b/apps/root.immich.app/src/routes/blog/2025-year-in-review/+page.md @@ -13,8 +13,7 @@ We crossed the 1.5-year mark since becoming FUTOnians, and we still feel incredi This year, we brought on more people full-time, some from within the Immich core team and others from outside the community. The team is growing, and so is the project's scope as we work to make it the best self-hosted photo management system out there. -![Immich Team (Chris, Zack, Jason, Alex, Paul, Daniel, Ganka, Mert, missing the Boet and the intern, Brandon :P)](https://static.immich.cloud/blog/153e5050-88b9-43e7-8b7b-ef0c0438057d/3bd14c69eb2d20ea68a1b4d15325716e.webp 'Immich Team (Chris, Zack, Jason, Alex, Paul, Daniel, Ganka, Mert, missing the Boet and the intern, Brandon)') -Immich Team (LTR: Chris, Zack, Jason, Alex, Paul, Daniel, Ganka, Mert, missing the Boet and the intern, Brandon :P) +![Immich Team (Chris, Zack, Jason, Alex, Paul, Daniel, Ganka, Mert, missing the Boet and the intern, Brandon :P)](https://static.immich.cloud/blog/153e5050-88b9-43e7-8b7b-ef0c0438057d/3bd14c69eb2d20ea68a1b4d15325716e.webp) So let us walk you through what "three years in one" actually looked like. @@ -91,11 +90,11 @@ Here is a list of websites that we launched throughout the year: - https://data.immich.app/ — Data website with fancy charts - https://api.immich.app/ — New API documentation - ![api page](https://static.immich.cloud/blog/153e5050-88b9-43e7-8b7b-ef0c0438057d/a10bde6c0546fd82843a08b003978d7e.webp ' api page') + ![API endpoints](https://static.immich.cloud/blog/153e5050-88b9-43e7-8b7b-ef0c0438057d/a10bde6c0546fd82843a08b003978d7e.webp) - https://ui.immich.app/ — Svelte UI component library - ![immich ui library page](https://static.immich.cloud/blog/153e5050-88b9-43e7-8b7b-ef0c0438057d/1a7ef7f4f4c322182d56bfd5a6b14ce5.webp 'immich ui library page') + ![Immich UI library](https://static.immich.cloud/blog/153e5050-88b9-43e7-8b7b-ef0c0438057d/1a7ef7f4f4c322182d56bfd5a6b14ce5.webp) - https://awesome.immich.app/ — A list of awesome apps, integrations, tools, distributions, and guides diff --git a/apps/root.immich.app/src/routes/blog/2026-february-recap/+page.md b/apps/root.immich.app/src/routes/blog/2026-february-recap/+page.md index c580a445..cb0cf66a 100644 --- a/apps/root.immich.app/src/routes/blog/2026-february-recap/+page.md +++ b/apps/root.immich.app/src/routes/blog/2026-february-recap/+page.md @@ -19,19 +19,19 @@ It's time for another project update. February was all about pull requests, bug Open pull requests on GitHub reached nearly 200 in early February. Since then, we have been (slowly) making our way through them. We know some of the pull requests have been sitting there _for months_, and for that we apologize. We are doing our best though and will hopefully get to them soon. We are a pretty small team after all. We do have this fancy graph however, which shows an overall downward trend. -![](https://static.immich.cloud/blog/dd9fd7aa-2635-49ef-98ff-5f9b157c5a40/c00fce4ec02a2ed0a524c1f61120895f.webp) +![Pull requests over time](https://static.immich.cloud/blog/dd9fd7aa-2635-49ef-98ff-5f9b157c5a40/c00fce4ec02a2ed0a524c1f61120895f.webp) ## Issues Similarly, open issues on GitHub was getting pretty close to 600, but the last half of February has seen some major work in that area as well. -![](https://static.immich.cloud/blog/dd9fd7aa-2635-49ef-98ff-5f9b157c5a40/bdedc7e6b32df758d954303776a59cc8.webp) +![Issues over time](https://static.immich.cloud/blog/dd9fd7aa-2635-49ef-98ff-5f9b157c5a40/bdedc7e6b32df758d954303776a59cc8.webp) ## Releases In beginning of February, we had 3 patch releases, bringing the latest version to `v2.5.6`. Since then, there have been over 200 commits on main, and the team is gearing up for another release in the next week or two. Here is a sneak peek of one of the shiny new features: map side panel/timeline (thanks to [michelheusschen](https://github.com/michelheusschen)!) -![](https://static.immich.cloud/blog/dd9fd7aa-2635-49ef-98ff-5f9b157c5a40/a624f8ea59c33ad3d91c222f624ba586.webp) +![Immich map side panel](https://static.immich.cloud/blog/dd9fd7aa-2635-49ef-98ff-5f9b157c5a40/a624f8ea59c33ad3d91c222f624ba586.webp) ## New blog post: Building the Immich editor diff --git a/apps/root.immich.app/src/routes/blog/2026-march-recap/+page.md b/apps/root.immich.app/src/routes/blog/2026-march-recap/+page.md new file mode 100644 index 00000000..76c27dd9 --- /dev/null +++ b/apps/root.immich.app/src/routes/blog/2026-march-recap/+page.md @@ -0,0 +1,156 @@ +--- +authors: [Immich Team] +coverAlt: '' +coverAttribution: Photo by Arno + Smit on Unsplash +coverUrl: https://static.immich.cloud/blog/5b54d5d9-ee80-4d49-b9a9-63b99269bc89/e958c4d0e338f0447c75f2e08d2369b4.webp +description: A recap of March, 2026, including an update on upcoming features, releases, + developer updates, and more. +id: 5b54d5d9-ee80-4d49-b9a9-63b99269bc89 +publishedAt: 2026-03-31 +slug: 2026-march-recap +title: March recap +--- + +Hello everyone! + +March was a great month for the team. Most of us were able to fly out to Austin, Texas, for FUTO's [Don't Be Evil](https://futo.tech/blog/dont-be-evil-conference-2026) conference during [SXSW](https://sxsw.com/). It's always fun to meet together in person, and we did some fun team-building activities. Besides the conference, we also had a few releases and continued working on some upcoming features. Continue below to read the full recap. + +## FUTO backups survey + +FUTO started building an encrypted backup service this year and they plan to integrate it directly into Immich. They are currently running a [survey](https://futo-backups-survey.immich.app/) to gather information about setups, library sizes, hardware & network capabilities, etc. Please fill out the survey if you haven't already. Also, if you are interested in joining the closed beta later this year there is a place to leave your email address. + +## Don't Be Evil + +At the Don't Be Evil FUTO conference Alex used Immich to give a presentation about Immich, which included what's changed since last year, and what's planned for this year. The presentation was recorded and should be available soon™️ on FUTO's [Youtube channel](https://www.youtube.com/@FUTOTECH). You can also find the slides [here](https://immich.futo.org/s/sxsw26-slides), on our public Immich instance. One take away from the presentation was that Immich is where it is today because of the awesome community and external contributors, so thank YOU! + +![Alex presenting at Don't Be Evil](https://static.immich.cloud/blog/5b54d5d9-ee80-4d49-b9a9-63b99269bc89/249afd36d04b9e0d1c7a7112e67a6615.webp) + +## Releases + +We published 1 minor release this month: + +- [v2.6.0](https://github.com/immich-app/immich/releases/tag/v2.6.0) - Album covers, shared link slugs, and native HTTP clients on mobile, `schema-check` command, and OAuth claims in `idToken` + +## Developers update - from the labyrinth + +_Our team members' unfiltered thoughts on the good, the bad, and the frustration about the current tasks they are working on._ + +### @alextran1502 + +Recently, I've seen an increase in vibe-code projects trying to implement some features or mechanisms that the team hasn't gotten to yet. While those projects seem interesting, after looking at the code, many shortcomings and questions arose for vibe-code implementation that I don't think an LLM agent can understand correctly, which could degrade the experience or rack up huge billing costs for users from those external integrations. + +As someone who cares so much about the experience and the feeling about using the app as a whole, from every pixel and alignment, how the font size and the colors should look for the project, seeing those projects get implemented is like witnessing something close and personal to me get butchered into Frankenstein style. + +### @jrasm91 + +This month I spent a decent amount of time going through bug reports and was able to fix a handful of items, worked on adding [CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP) support, and made some progress on workflows and plugins. + +#### Bug fixes + +I fixed one [issue](https://github.com/immich-app/immich/issues/25193), which I thought was pretty interesting. A user was getting this strange error message when trying to use the CLI: + +```typescript +TypeError: image is not iterable +``` + +It turns out the error was caused by the Immich server returning `HTML` where `JSON` was expected and then the client basically coerced it to a `string` for _reasons_, eventually leading to this runtime error. Once I had figured out what was happening the solution was pretty straightforward: return a [406 Not Acceptable](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/406) response, instead of a [200 OK](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/200). Basically, if the client is _requesting_ `application/json`, don't response with `text/html`. In hindsight, it seemed so obvious :smile:. + +#### Helmet + +I also worked on making it possible to configure the Immich server with [helmet](https://github.com/helmetjs/helmet), a library for managing security headers, such as `Content-Security-Policy` , `Strict-Transport-Security`, etc. There will be more information about this feature in `v2.7.0`. + +#### Workflows & plugins + +This is turning out to be a pretty big feature to build. I made a lot of progress this month on dynamic configuration, which means that we can generate entire forms from JSON configuration, which is important because configuration options are defined on a per plugin method basis. + +```typescript +{ + "name": "immich-plugin-core", + "version": "2.0.1", + "title": "Immich Core Plugin", + "description": "Core workflow capabilities for Immich", + "author": "Immich Team", + "wasmPath": "dist/plugin.wasm", + "methods": [ + { + "name": "filterFileName", + "title": "Filter by filename", + "description": "Filter assets by filename pattern using text matching or regular expressions", + "types": ["AssetV1"], + "schema": { + "type": "object", + "properties": { + "pattern": { + "type": "string", + "title": "Filename pattern", + "description": "Text or regex pattern to match against filename" + }, + "matchType": { + "type": "string", + "title": "Match type", + "enum": ["contains", "regex", "exact"], + "default": "contains", + "description": "Type of pattern matching to perform" + }, + "caseSensitive": { + "type": "boolean", + "default": false, + "title": "Case sensitive", + "description": "Whether matching should be case-sensitive" + } + }, + "required": ["pattern"] + } + }, + ... +} +``` + +This configuration, for example, generates something like this in the web application now: +Dynamic configuration modal + +Now that dynamic configuration exists, I'll be moving on to writing tests for the core plugin, and looking into additional triggers, like `PersonRecognized`. + +### @danieldietzler + +For me, besides flying out to Austin for a week, March has been mostly around chores. Briefly peaking at >200 open PRs, I had (and still have :sweat_smile:) lots of review work to do. But don't get me wrong; I strongly appreciate every single contribution, and I love that so many people find joy in working on the Immich code base. Barely being able to keep up with contributions is definitely one of the better problems to have! :P + +Other than that, I fixed some bugs and updated a bunch of packages. + +Notably, I was finally upgrade Kysely, our SQL query builder of choice, to its latest version. Hidden behind a small `fix(helpers)`, [0.28.3](https://github.com/kysely-org/kysely/releases/tag/v0.28.3) changed the return types of nested queries. Now, for a selected JSON column (e.g., from a sub-select), the fields in that object can only be strings, numbers, objects, arrays, or booleans. After all, that's the types JSON supports. For instance, there is no concept of something like a JavaScript `Date`. + +However, both our previous ORM as well as [Kysely](https://kysely.dev/) on versions `<= 0.28.2` did type those fields based on their actual types. This resulted in our code base relying on wrong types forever basically, causing it to be deeply spread within all of Immich server. After a bunch of prior refactoring to untangle our types, primarily in unit tests (which led me down a path of refactoring most of our unit tests in fact), I was finally able to upgrade Kysely in [#26744](https://github.com/immich-app/immich/pull/26744) with a somewhat reasonable diff (it's still not the prettiest, but prior attempts were horrible in comparison lol). We didn't have to give up any type safety, and I didn't have to elude to any ugly casts. :tada: + +### @bwees + +This month I made some more progress on the editing experience in Immich. My goal for the past 2 months has been to fix some of the limitations in the editing feature. + +#### Mobile editing + +The new mobile editing experience is in its final stages of review and should be coming soon to a phone near you :tm:. We merged the majority of underlying requirements for mobile editing (websocket events, sync entities, API changes) for `v2.6.0`. The only part that remains in the new user interface. + +#### Live Photo editing + +I made some significant headway on bringing editing support to Live Photos. This will allow you to edit an image that includes a live video portion and have the edits apply to both parts (photo and video). The changes in the PR also lay the groundwork for full video editing support in the future. + +#### Retro DVD source release + +![Retro DVD](https://static.immich.cloud/blog/5b54d5d9-ee80-4d49-b9a9-63b99269bc89/0ae9786ad8bd154cb0500bd1f1fa8b1a.webp) + +We recently sold the remaining retro DVDs from our [stable release](https://immich.app/blog/stable-release) back in October. As such, we have released the source code for building the Alpine Linux based ISO that was burned onto the DVDs. You can check out the source code at ! + +I worked on this project all the way back in August of 2025. It was the last week of my summer internship with Immich and originally started as a "Wouldn't it be funny if…." joke. I did some digging on how to make a bootable live DVD and I had a working image by the end of the week! + +Huge shoutout to Zack for setting up the fulfillment pipeline to take orders from our [merch store](https://immich.store/) and forwarding them on to the DVD vendors in both the US and Europe. In addition we gave the option to purchase a product key with your DVD. + +![While the team was at FOSDEM 2026, we met Daniel Stenberg (creator of curl) and gave him a retro DVD! ](https://static.immich.cloud/blog/5b54d5d9-ee80-4d49-b9a9-63b99269bc89/1d2f3ad99eacc9f4ab53414ab2093e0c.webp) + +We sold over 500 DVDs since they were released! This was a super fun project to work on and now I, along with many others in the community, have a cool piece of Immich history! + +## Upcoming goals + +Looking forward into April, we hope to have a final `v2.7.0` release, and then start work on `v3`, which will include a handful of API breaking changes, and:crossed_fingers: hopefully an initial release of workflows! + +Well, that's it for this month. As always, if you find the project helpful, you can support us at diff --git a/apps/root.immich.app/src/routes/blog/immich-editor/+page.md b/apps/root.immich.app/src/routes/blog/immich-editor/+page.md index 4eab38aa..ab843586 100644 --- a/apps/root.immich.app/src/routes/blog/immich-editor/+page.md +++ b/apps/root.immich.app/src/routes/blog/immich-editor/+page.md @@ -69,7 +69,7 @@ The client editors had a few requirements: 2. Have a real time preview of what the resulting image would look like 3. Be able to load existing edits in a deterministic way, regardless of the ordering of the edits. -![Crop a picture of a bird](https://static.immich.cloud/blog/87058112-8de7-4143-9dc2-feac8f944e51/b197ae170bd7355f8a4468b17abcf730.webp 'testing') +![Crop a picture of a bird](https://static.immich.cloud/blog/87058112-8de7-4143-9dc2-feac8f944e51/b197ae170bd7355f8a4468b17abcf730.webp) ### Editor experience diff --git a/import-post.py b/import-post.py index 18e6f782..becf36fd 100644 --- a/import-post.py +++ b/import-post.py @@ -28,7 +28,8 @@ from PIL import Image WEBP_QUALITY = 85 BLOG_PREFIX = "blog" -OUTPUT_BASE = Path("apps/root.immich.app/src/routes/blog") +SCRIPT_DIR = Path(__file__).resolve().parent +OUTPUT_BASE = SCRIPT_DIR / "apps/root.immich.app/src/routes/blog" def slugify(text: str) -> str: diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 83d56b8f..996bc0bf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -711,8 +711,8 @@ importers: apps/root.immich.app: dependencies: '@immich/ui': - specifier: ^0.67.0 - version: 0.67.2(@sveltejs/kit@2.55.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.0)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(esbuild@0.27.3)(jiti@2.6.1)))(svelte@5.55.0)(typescript@6.0.2)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(esbuild@0.27.3)(jiti@2.6.1)))(svelte@5.55.0)(tailwindcss@4.2.2) + specifier: ^0.70.0 + version: 0.70.0(@sveltejs/kit@2.55.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.0)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(esbuild@0.27.3)(jiti@2.6.1)))(svelte@5.55.0)(typescript@6.0.2)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(esbuild@0.27.3)(jiti@2.6.1)))(svelte@5.55.0)(tailwindcss@4.2.2) '@mdi/js': specifier: ^7.4.47 version: 7.4.47 @@ -733,8 +733,8 @@ importers: specifier: ^10.0.0 version: 10.0.1(eslint@10.1.0(jiti@2.6.1)) '@immich/svelte-markdown-preprocess': - specifier: ^0.2.1 - version: 0.2.1(svelte@5.55.0) + specifier: ^0.3.0 + version: 0.3.0(svelte@5.55.0) '@sveltejs/adapter-static': specifier: ^3.0.9 version: 3.0.10(@sveltejs/kit@2.55.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.0)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(esbuild@0.27.3)(jiti@2.6.1)))(svelte@5.55.0)(typescript@6.0.2)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(esbuild@0.27.3)(jiti@2.6.1))) @@ -759,6 +759,9 @@ importers: dotenv: specifier: ^17.2.3 version: 17.3.1 + dotenv-cli: + specifier: ^11.0.0 + version: 11.0.0 eslint: specifier: ^10.0.0 version: 10.1.0(jiti@2.6.1) @@ -1272,11 +1275,21 @@ packages: peerDependencies: svelte: ^5.0.0 + '@immich/svelte-markdown-preprocess@0.3.0': + resolution: {integrity: sha512-6xspWnOgaTi+TasteJgI6DjOGjBQQI30mOYiY/FnyEjczNbrV6r5SFWjNbR+JY+Umn7MsPcZf5yzomK+q5AThg==} + peerDependencies: + svelte: ^5.0.0 + '@immich/ui@0.67.2': resolution: {integrity: sha512-GsaoJRiRORJ34CT+W3pAOdhbLr61nNlgFaOzDcnVnSWFonu7+HR3CXdCxbSdyU4+r3xEmcawwo6rMuLgRplHfw==} peerDependencies: svelte: ^5.0.0 + '@immich/ui@0.70.0': + resolution: {integrity: sha512-sToSa5hRH7bCfxO9GQ1M9Gaq0jOiKlPdjoRj1wba1u8KU4381k+luvSXbiAydtdYI1wmS5lTfHpDOBDOjlRUeQ==} + peerDependencies: + svelte: ^5.0.0 + '@internationalized/date@3.12.0': resolution: {integrity: sha512-/PyIMzK29jtXaGU23qTvNZxvBXRtKbNnGDFD+PY6CZw/Y8Ex8pFUzkuCJCG9aOqmShjqhS9mPqP6Dk5onQY8rQ==} @@ -1838,6 +1851,18 @@ packages: devalue@5.6.4: resolution: {integrity: sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==} + dotenv-cli@11.0.0: + resolution: {integrity: sha512-r5pA8idbk7GFWuHEU7trSTflWcdBpQEK+Aw17UrSHjS6CReuhrrPcyC3zcQBPQvhArRHnBo/h6eLH1fkCvNlww==} + hasBin: true + + dotenv-expand@12.0.3: + resolution: {integrity: sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==} + engines: {node: '>=12'} + + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + dotenv@17.3.1: resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} engines: {node: '>=12'} @@ -2203,6 +2228,9 @@ packages: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -3074,6 +3102,13 @@ snapshots: node-emoji: 2.2.0 svelte: 5.55.0 + '@immich/svelte-markdown-preprocess@0.3.0(svelte@5.55.0)': + dependencies: + front-matter: 4.0.2 + marked: 17.0.5 + node-emoji: 2.2.0 + svelte: 5.55.0 + '@immich/ui@0.67.2(@sveltejs/kit@2.55.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.0)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(esbuild@0.27.3)(jiti@2.6.1)))(svelte@5.55.0)(typescript@6.0.2)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(esbuild@0.27.3)(jiti@2.6.1)))(svelte@5.55.0)(tailwindcss@4.2.2)': dependencies: '@immich/svelte-markdown-preprocess': 0.2.1(svelte@5.55.0) @@ -3090,6 +3125,22 @@ snapshots: - '@sveltejs/kit' - tailwindcss + '@immich/ui@0.70.0(@sveltejs/kit@2.55.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.0)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(esbuild@0.27.3)(jiti@2.6.1)))(svelte@5.55.0)(typescript@6.0.2)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(esbuild@0.27.3)(jiti@2.6.1)))(svelte@5.55.0)(tailwindcss@4.2.2)': + dependencies: + '@immich/svelte-markdown-preprocess': 0.3.0(svelte@5.55.0) + '@internationalized/date': 3.12.0 + '@mdi/js': 7.4.47 + bits-ui: 2.16.3(@internationalized/date@3.12.0)(@sveltejs/kit@2.55.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.0)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(esbuild@0.27.3)(jiti@2.6.1)))(svelte@5.55.0)(typescript@6.0.2)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@24.12.0)(esbuild@0.27.3)(jiti@2.6.1)))(svelte@5.55.0) + luxon: 3.7.2 + simple-icons: 16.13.0 + svelte: 5.55.0 + svelte-highlight: 7.9.0 + tailwind-merge: 3.5.0 + tailwind-variants: 3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.2) + transitivePeerDependencies: + - '@sveltejs/kit' + - tailwindcss + '@internationalized/date@3.12.0': dependencies: '@swc/helpers': 0.5.19 @@ -3604,6 +3655,19 @@ snapshots: devalue@5.6.4: {} + dotenv-cli@11.0.0: + dependencies: + cross-spawn: 7.0.6 + dotenv: 17.3.1 + dotenv-expand: 12.0.3 + minimist: 1.2.8 + + dotenv-expand@12.0.3: + dependencies: + dotenv: 16.6.1 + + dotenv@16.6.1: {} + dotenv@17.3.1: {} emojilib@2.4.0: {} @@ -3958,6 +4022,8 @@ snapshots: dependencies: brace-expansion: 5.0.5 + minimist@1.2.8: {} + mri@1.2.0: {} mrmime@2.0.1: {}