Skip to content

feat(media-server): add Emby as a third supported media server#2911

Merged
enoch85 merged 23 commits into
developmentfrom
emby-support
May 19, 2026
Merged

feat(media-server): add Emby as a third supported media server#2911
enoch85 merged 23 commits into
developmentfrom
emby-support

Conversation

@enoch85

@enoch85 enoch85 commented May 17, 2026

Copy link
Copy Markdown
Collaborator

Adds Emby alongside Plex and Jellyfin via the existing IMediaServerService abstraction. Architecture, contracts, settings, rules, and UI integration are wired throughout per the guardrails in .claude/rules/implementation.md. ARCHITECTURE.md updated to reflect the third adapter.

Screenshots

Media-server selector with all three servers on one row, Emby selected
Settings → media-server selector (3-up)
Emby settings page after a successful connection test
Emby settings page after Test Connection
Sign in with Emby modal (admin username/password)
“Sign in with Emby” credentials modal
Switch preview modal showing Emby → Jellyfin migration
Media-server switch preview (Emby → Jellyfin)
Rule creator showing an Emby property selected
Rule creator with an Emby-app property (“Last view date”) selected

⚠️ Bugs are expected — please help test

What is verified against a real Emby server (Emby Server 4.9.x, via local setup + beta-tester logs):

  • Connection test (POST /api/settings/emby/test) → server name + version + admin user list
  • Credentials login (POST /api/settings/emby/loginPOST /Users/AuthenticateByName) → access token + libraries + users
  • Settings save + persistence (emby_url, emby_api_key, emby_user_id, emby_server_name columns)
  • Media-server endpoints with Emby active: /libraries, /users, / (status), /library/:id/content (real Shows library returned mapped items)
  • Rule creation + end-to-end execution against an Emby library, including cross-server matchers (Sonarr tags + Emby watch counts AND'd in one rule)
  • Date-based rules — Emby.lastViewedAt AFTER 30 days verified live by @Nomsplease (218-item show rule, Active)
  • createCollection + addToCollection + getCollection — auto-link path: empty collection → rule run → 78 items added → BoxSet 458472 created on the server → childCount=76 after dedupe
  • Watch-history fan-out paths — sw_episodes / sw_viewedEpisodes returning real numbers in production rules (covers getWatchState, per-user iteration, favoritedBy)
  • Overlay rendering path — downloadImage + image upload — confirmed live by @Nomsplease (51 applied) and @MrLinford (34 processed / 0 errors). Posters are written to the targeted level only (season rule → season poster), matching Emby's per-item image model
  • Media-server switch: Emby ↔ Jellyfin in both directions, rule migration [7, X][6, X], DB state verified
  • Full UI walkthrough — 0 console errors with Emby configured

Scaffolded but not yet exercised end-to-end:

  • removeFromCollection / removeBatchFromCollection / updateCollection / deleteFromDisk / refreshItemMetadata / computeLibraryStorageSizes / getAllIdsForContextAction (show ↔ episode traversal)
  • Custom poster upload via the collection-image controller (the overlay write path uses the same POST /Items/{id}/Images/Primary endpoint — confirmed working — but the explicit "upload poster" UI flow hasn't been exercised)

Feature matrix:

  • supportsFeature() is conservative, mirroring Jellyfin.
  • COLLECTION_SORT is off because Emby has no item-move/reorder endpoint on a BoxSet (verified against Emby.ApiClient.Javascript). This is a permanent gap, not a deferred follow-up. reorderCollectionItems throws if reached.
  • WATCHLIST / CENTRAL_WATCH_HISTORY / COLLECTION_VISIBILITY are off for the same reasons as Jellyfin (no public APIs / per-user iteration only).

Remaining unverified paths are marked TODO(emby-server-test): in the code (3 sites). Expect endpoint-shape bugs (wrong field names, wrong query parameters, missing required fields) on the unexercised paths.

🙏 Testers wanted — Emby Premiere AND free tier

I don't run Emby, so this branch still benefits from hands-on testing from people who do. Both server tiers matter because the feature surface differs at the edges:

  • Free Emby Server — covers the bulk of the adapter (libraries, items, collections, BoxSet writes, watch history, deep links). If you're on the free tier, please verify the basics work against your library.
  • Emby Premiere — needed mainly to confirm image uploads and per-user watch-state aggregation behave correctly under Premiere's expanded API surface. (Smart collections and collection-sort were ruled out — Emby has neither, regardless of tier.)

The PR image is ready to pull: ghcr.io/maintainerr/maintainerr:pr-2911.

The easiest way to try it without disturbing your normal Maintainerr setup is to change the image tag in your existing docker-compose.yml from :latest to :pr-2911 and restart the container. If you'd rather keep the two side-by-side, point the test container at a fresh data folder and a different port.

Once it's up, open Maintainerr in your browser and:

  1. Pick Emby on the welcome screen.
  2. Go to Settings → Emby. Enter your Emby URL and API key, or click Sign in with Emby and enter your admin username/password — either way should connect.
  3. Check that your Emby libraries and admin users show up.
  4. Create a rule group bound to one of your Emby libraries, save it, and click Run Rules.
  5. Try switching from Emby to Jellyfin (or Plex) and back in the media-server selector — Maintainerr should show a preview of what will happen and migrate your rules.

Then poke around the parts of Maintainerr you actually use day-to-day with Emby, especially:

  • Collections — does Maintainerr create/update/delete Emby collections correctly?
  • Watch-state rules (e.g. "not watched in 90 days") — do they pick up the right items?
  • Posters and overlays — do they apply to the collection in Emby?
  • The "open in Emby" link on a media item — does it actually open in your Emby web client?
  • Show/season/episode rules on TV libraries — do the show-level conditions evaluate sensibly?

File issues with [emby] in the title for anything that looks off — even "this worked" reports are useful since most of these paths haven't been exercised.

Emby Connect is intentionally not included. The original plan named it as MVP, citing a Jellyseerr embyconnect.ts reference implementation — that file does not exist (verified via the GitHub API against both Seerr and Jellyseerr). Rather than ship guessed api.emby.media code as if it were verified, the Connect flow has been left out entirely. It can be added in a follow-up once the endpoints are confirmed against a Premiere-enabled, Connect-linked server.

Design choices

  • Separate emby/ adapter mirroring jellyfin/'s layout. Some duplication with the Jellyfin adapter is accepted as a deliberate trade rather than refactoring both into a shared client (which would change working code).
  • Separate apps/server/src/modules/api/emby-api/emby-api.helper.ts holds the axios.create({baseURL}) call, matching the plex-api/ and tautulli-api/ layering. The EmbyAdapterService instantiates EmbyApi and reads .axios instead of constructing the client inline.
  • Application.EMBY = 7 added to the rules Application enum, with the Emby app's props[] shared with Jellyfin's at runtime via RuleConstants' constructor so rule migration between Jellyfin and Emby is a property-ID no-op.
  • Emby's empty-children sync-lag workaround in rule-executor.service.ts (previously Jellyfin-only) now also covers Emby — both share the same .NET BoxSet backend.
  • UI: new apps/ui/src/components/Login/Emby/EmbyLoginButton.tsx follows the existing Login/Plex/PlexLoginButton pattern. The Emby settings page is 367 LOC; the Jellyfin equivalent is 355 LOC.
  • Migration generated via the TypeORM workflow (typeorm_instructions.txt). Adds four nullable varchar columns to the settings table via TypeORM's standard SQLite temporary-table rename pattern. No data loss path.
  • Logo: apps/ui/public/icons_logos/emby.png, cropped from the Wikimedia Commons Emby-logo.png which is CC BY-SA 4.0 (same license as the existing Jellyfin logo). Attribution + license terms recorded next to it in emby.png.LICENSE.txt.

CodeQL alerts

The CodeQL gate flags SSRF on axios.create({baseURL: userUrl}) in emby-api.helper.ts. These are false positives for this codebase: the URL is operator-supplied in a self-hosted application, identical data flow to the Plex and Jellyfin adapters (where the URL crosses an external SDK boundary so CodeQL doesn't trace it). The alerts will be dismissed in the Security UI as "Won't fix — by design" rather than papering over them with a hostname blocklist (which would break the documented LAN use case).

Test gaps (deliberately not filled)

A full emby-adapter.service.spec.ts and emby-getter.service.spec.ts were not written, because synthetic test fixtures against unverified endpoint shapes would just codify assumptions. The existing factory spec was extended to cover the third adapter, and the impacted suites (rule-migration, switch, settings, cache, media-server-id) all pass and now cover Emby cases where applicable. Add focused specs once the live endpoints have been confirmed and the actual response shapes are known.

How to verify locally

  1. Run a local Emby Server (the .deb install pattern works in a Codespace)
  2. Complete the first-run wizard, create an admin, add a library, generate an API key
  3. yarn dev and pick Emby in the media-server selector
  4. Enter URL + API key (or use Sign in with Emby for credentials login)
  5. Confirm libraries appear, then create a rule group against an Emby library

Quality gates

  • yarn lint — clean across all three workspaces
  • yarn build — clean (server + UI)
  • yarn test — 1,239 server tests pass, 196 UI tests pass

enoch85 added 2 commits May 17, 2026 14:34
Adds an Emby adapter alongside the existing Plex and Jellyfin adapters,
wired through the IMediaServerService abstraction. URL + API key flow
and POST /Users/AuthenticateByName credentials login are verified
end-to-end against a real Emby Server (v4.9.3). Higher-order features
(per-property rule evaluation, overlays, watch-history) are scaffolded
but unverified — see PR description.
Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
enoch85 added 3 commits May 17, 2026 14:49
- yarn format on the 9 files flagged by Formatting check.
- Replace inline `replace(/\/+$/, '')` with the codebase's
  `while + endsWith + slice` pattern (see PR #2526 normalizeDiskPath)
  to avoid the polynomial-regex CodeQL alert.
- Match the existing rule-executor variable name (`isJellyfin`) when
  extending the BoxSet sync-lag workaround to also cover Emby — same
  shape as the original two-server check.
Keep the two server types as distinct booleans rather than folding both
into a single combined flag. Matches how feature-flagging is read
elsewhere in this file and leaves room for the two servers' boxset
behaviour to diverge later.
Extract `axios.create` calls from the EmbyAdapterService into a small
EmbyApi helper at apps/server/src/modules/api/emby-api/, matching the
layering used for plex-api/ and tautulli-api/. The adapter now
instantiates EmbyApi and reads `.axios` instead of constructing the
client inline, which keeps URL-construction concerns out of the
media-server abstraction.
github-advanced-security[bot]

This comment was marked as resolved.

Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
@enoch85

This comment was marked as resolved.

@github-actions

This comment was marked as outdated.

@MrLinford

Copy link
Copy Markdown
Collaborator

@enoch85 I have an EMBY licence I can test with.

@SmolSoftBoi SmolSoftBoi added the enhancement New feature or request label May 18, 2026
Implements every rule property the Jellyfin getter supports against the
Emby adapter. Fixes the reported bug where `Emby - Amount of watched
episodes` and `Emby - Amount of available episodes` returned null
("not available for this item") — those properties are part of the
`sw_*` show-level family and were previously falling through to a TODO
stub in EmbyGetterService.

EmbyAdapterService gains five methods that mirror the equivalents on
JellyfinAdapterService:
- getChildrenMetadata(parentId, kind?) — adds optional kind filter,
  routes through /Shows/{id}/Seasons for season kind to match Jellyfin
- getItemFavoritedBy(itemId) — per-user fan-out over UserData.IsFavorite
- getTotalPlayCount(itemId) — per-user fan-out summing UserData.PlayCount
- getDescendantEpisodeWatchers(parentId) — per-user IsPlayed=true probe
- getPlaylistItems(playlistId) — GET /Playlists/{id}/Items

EmbyGetterService is now a near-line-for-line port of the Jellyfin
getter, sharing the same private helpers and cache semantics.
Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
enoch85 added 4 commits May 18, 2026 13:28
The ported getter inherited a handful of comments that referenced
Jellyfin directly even though the file is now Emby's. Most are accurate
about the shared .NET BoxSet backend, but reading them in an Emby file
was misleading. Replaced the six that asserted Jellyfin-only behaviour
with what's actually true for Emby — notably the smart-collection note,
which had it inverted (Emby Premiere does have smart collections; the
adapter just doesn't differentiate them yet).
Verified against emby.media docs and forum threads:
- Emby has no native smart collections. Manual BoxSets and TheMovieDb
  franchise auto-grouping are the only mechanisms; "smart collections
  variation" was a 2018 feature request that closed unimplemented.
- Emby has no item-move/reorder endpoint for BoxSets. DisplayOrder
  accepts PremiereDate | SortName only — that's an ordering hint, not
  an explicit ordered list. Maintainerr's COLLECTION_SORT contract
  (push a specific item-id sequence) isn't satisfiable.

Three sites had wrong commentary or code:
- features.ts: COLLECTION_SORT note claimed Emby retained pre-fork move
  endpoints. It doesn't.
- emby.mapper.ts: smart collection TODO claimed Emby Premiere supports
  smart collections. It doesn't.
- emby-adapter.service.ts: reorderCollectionItems had a fabricated
  /Items/.../Move?NewIndex= call. Removed; method now throws an explicit
  "not supported" error (it was already gated behind supportsFeature
  which returns false, so unreachable in practice).
Adds focused specs for the in-process Maintainerr code that branches
on MediaServerType.EMBY. None of these call out to a live Emby server
— they pin Maintainerr's own dispatch, settings, migration, and
mapper logic.

- factory spec: EMBY routing, configured-type inference, uninit
  dispatch; replaces a stale 'EMBY'-as-unsupported test that pre-dated
  Emby support
- switch service spec: four Emby switch directions clear the right
  column sets
- rule-migration spec: Emby <-> Plex migration, Emby <-> Jellyfin
  no-op remap (shared props[]), incompatible skip+delete, community
  import detection, getApplicationId(EMBY)
- rules.service.cacheReset spec (new): EMBY flushes the 'emby' cache,
  with peer Plex/Jellyfin assertions for full dispatch-table coverage
- emby.mapper spec (new): pure synthetic-fixture transforms covering
  parent/grandparent semantics, RunTimeTicks->ms, AspectRatio parse,
  Tags->labels, and the "Emby has no smart collections" invariant
- Settings.spec.tsx: EMBY render path produces an "Emby" tab linking
  to /settings/emby
…cope

Adds a "Tests landed in this PR" section enumerating the six pure-logic
spec additions (factory routing, switch column-clearing, rule-migration
ID remap, cache-reset routing, mapper transforms, UI tab render).

Narrows the "Known gaps" entry from "no Emby test specs" to specifically
the three server-dependent specs (adapter, getter, overlay provider)
that need live Emby HTTP responses to be meaningful.
@enoch85

This comment was marked as resolved.

@github-actions

This comment was marked as outdated.

enoch85 added 4 commits May 18, 2026 14:48
Matches the Jellyfin adapter's collection-create behavior. Emby uses the
IsLocked flag to opt in to composite image generation from member items;
without it the auto-cover step is skipped on some servers.
…erified facts

Earlier note claimed Emby's playlist Move endpoint needed an int64 internal-ID
mapping we couldn't obtain. Re-checking the decompiled source and the official
web client showed the real path: BaseItemDto.PlaylistItemId is a string that
ServiceStack auto-converts at the path-binding layer. The reason to defer is
not the API — it's that IMediaServerService has no reorderPlaylistItems and
no caller anywhere in Maintainerr that would invoke one.
Followups from PR review and reverse-engineering against a real Emby 4.9.3.0
server (decompiled Emby.Api.dll + the server's own /openapi spec).

Bulk collection-create — unified across all three servers
- Plex: append &uri=<server-URI of comma-joined ratingKeys> on POST
  /library/collections, reusing the canonical buildCollectionItemsUri()
  shape already used for bulk-add. Matches python-plexapi's
  Collection.create().
- Jellyfin: forward params.initialItemIds as the SDK's existing ids arg.
- Emby: pass IsLocked=true on createCollection so Emby generates the
  composite cover image, matching the Jellyfin adapter's behavior.
- Rename COLLECTION_CREATE_WITH_ITEMS -> BULK_COLLECTION_CREATE now that
  the semantics are uniform (adapter takes items in one call).

Emby adapter follow-ups
- H5: dedicated overlay itemExists probe that returns false only on a
  confirmed 404 and rethrows transient failures, preventing transient
  outages from deleting original-poster backups.
- M1: write ForcedSortName on updateCollection and run the metadata
  follow-up when summary or sortTitle is provided.
- DTO additions for SortName/ForcedSortName/IsLocked.

Settings / UI
- L4: validate the Emby login payload with a shared Zod schema and
  ZodValidationPipe instead of raw @Body().
- L5: drop the 'Plex or Jellyfin' onboarding copy; the welcome screen
  no longer hard-codes the two-server list, and the spec pins the new
  copy.
- L6: assign the generated key to APIKEY in the verification script
  so the next step actually has a token to use.
Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
@enoch85

This comment was marked as resolved.

@github-actions

Copy link
Copy Markdown
Contributor

Released to maintainerr/maintainerr:pr-2911 🚀

enoch85 added 2 commits May 18, 2026 18:09
EmbyOverlayProvider.downloadImage was a TODO returning null, causing
every overlay run to log "No poster artwork available for item X,
skipping" and reach the processor as 0 applied / N errors. Adds
EmbyAdapterService.getItemImageBuffer (GET /Items/{id}/Images/{type},
arraybuffer, 404 → null) mirroring the Jellyfin adapter, and wires it
into the provider. Verified path against Emby.ApiClient.Javascript.
Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
@enoch85

enoch85 commented May 19, 2026

Copy link
Copy Markdown
Collaborator Author

/release-pr

@github-actions

Copy link
Copy Markdown
Contributor

Released to maintainerr/maintainerr:pr-2911 🚀

enoch85 added 2 commits May 19, 2026 15:45
Ran `npx update-browserslist-db@latest`; no target browser changes.
Ports JellyfinAdapterService.findRandomItem / findRandomEpisode to the
Emby adapter (`GET /Items?Recursive&SortBy=Random&Limit=1`, with Virtual
location exclusion so episode previews never land on placeholders), and
wires them into EmbyOverlayProvider. The overlay-template editor's
"random library poster" preview now works on Emby, parity with Plex and
Jellyfin.

enoch85 commented May 19, 2026

Copy link
Copy Markdown
Collaborator Author

Two follow-up fixes landed in this branch:

  • 930c9de5 — implemented EmbyAdapterService.getItemImageBuffer and wired it into EmbyOverlayProvider.downloadImage. The overlay run previously logged "No poster artwork available" for every item because the provider always returned null; it now does GET /Items/{id}/Images/Primary and returns the bytes. Confirmed live by @Nomsplease (51 applied where it was 0 before) and @MrLinford (34 processed / 0 errors).
  • 806b9f98 — ported findRandomItem / findRandomEpisode to the Emby adapter so the Overlay Template Editor's "random library poster" preview works on Emby, parity with Plex and Jellyfin. Uses Emby's native SortBy=Random with ExcludeLocationTypes=Virtual, mirroring the Jellyfin shape.

Expected behaviour after these: overlay processing writes to the targeted item's Primary image only — for a Season rule that means the season poster gets the "X days left" pill; the show and episode posters are not touched. That's Emby's design (each item carries its own primary image), and it matches Maintainerr's contract.

Comment thread apps/server/src/modules/api/media-server/emby/emby-adapter.service.ts Dismissed
@enoch85 enoch85 enabled auto-merge (squash) May 19, 2026 16:30
@enoch85 enoch85 disabled auto-merge May 19, 2026 16:31
@enoch85

enoch85 commented May 19, 2026

Copy link
Copy Markdown
Collaborator Author

/release-pr

@github-actions

Copy link
Copy Markdown
Contributor

Released to maintainerr/maintainerr:pr-2911 🚀

@enoch85 enoch85 merged commit 36dc409 into development May 19, 2026
16 checks passed
@enoch85 enoch85 deleted the emby-support branch May 19, 2026 17:01
maintainerr-automation Bot added a commit that referenced this pull request May 20, 2026
* build(deps): bump the nestjs group with 5 updates (#2899)

Bumps the nestjs group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [@nestjs/common](https://github.com/nestjs/nest/tree/HEAD/packages/common) | `11.1.20` | `11.1.21` |
| [@nestjs/core](https://github.com/nestjs/nest/tree/HEAD/packages/core) | `11.1.20` | `11.1.21` |
| [@nestjs/platform-express](https://github.com/nestjs/nest/tree/HEAD/packages/platform-express) | `11.1.20` | `11.1.21` |
| [@nestjs/swagger](https://github.com/nestjs/swagger) | `11.4.2` | `11.4.3` |
| [@nestjs/testing](https://github.com/nestjs/nest/tree/HEAD/packages/testing) | `11.1.20` | `11.1.21` |


Updates `@nestjs/common` from 11.1.20 to 11.1.21
- [Release notes](https://github.com/nestjs/nest/releases)
- [Commits](https://github.com/nestjs/nest/commits/v11.1.21/packages/common)

Updates `@nestjs/core` from 11.1.20 to 11.1.21
- [Release notes](https://github.com/nestjs/nest/releases)
- [Commits](https://github.com/nestjs/nest/commits/v11.1.21/packages/core)

Updates `@nestjs/platform-express` from 11.1.20 to 11.1.21
- [Release notes](https://github.com/nestjs/nest/releases)
- [Commits](https://github.com/nestjs/nest/commits/v11.1.21/packages/platform-express)

Updates `@nestjs/swagger` from 11.4.2 to 11.4.3
- [Release notes](https://github.com/nestjs/swagger/releases)
- [Commits](nestjs/swagger@11.4.2...11.4.3)

Updates `@nestjs/testing` from 11.1.20 to 11.1.21
- [Release notes](https://github.com/nestjs/nest/releases)
- [Commits](https://github.com/nestjs/nest/commits/v11.1.21/packages/testing)

---
updated-dependencies:
- dependency-name: "@nestjs/common"
  dependency-version: 11.1.21
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: nestjs
- dependency-name: "@nestjs/core"
  dependency-version: 11.1.21
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: nestjs
- dependency-name: "@nestjs/platform-express"
  dependency-version: 11.1.21
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: nestjs
- dependency-name: "@nestjs/swagger"
  dependency-version: 11.4.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: nestjs
- dependency-name: "@nestjs/testing"
  dependency-version: 11.1.21
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: nestjs
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump typescript-eslint from 8.59.2 to 8.59.3 (#2900)

Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.59.2 to 8.59.3.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.59.3/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.59.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump turbo from 2.9.6 to 2.9.12 (#2901)

Bumps [turbo](https://github.com/vercel/turborepo) from 2.9.6 to 2.9.12.
- [Release notes](https://github.com/vercel/turborepo/releases)
- [Changelog](https://github.com/vercel/turborepo/blob/main/RELEASE.md)
- [Commits](vercel/turborepo@v2.9.6...v2.9.12)

---
updated-dependencies:
- dependency-name: turbo
  dependency-version: 2.9.12
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @typescript-eslint/parser from 8.59.2 to 8.59.3 (#2902)

Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 8.59.2 to 8.59.3.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.59.3/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.59.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* ci(docs-drift): broaden fix scanner and surface documentation-labeled items

Replace the behavioral-fix path allowlist with a denylist so every UI and
server-module fix is flagged except internal-only events/logging. Add a
section listing merged PRs and open issues carrying the `documentation`
label, and pass GH_TOKEN to the report step so it can query them.

* Revert PR 2879 (#2904)

* Initial plan

* fix(ci): revert PR 2879

Agent-Logs-Url: https://github.com/Maintainerr/Maintainerr/sessions/49aef6e5-0ff3-477b-aa59-e6d25d283693

Co-authored-by: enoch85 <4511254+enoch85@users.noreply.github.com>

* fix(ci): add missing yaml newline

Agent-Logs-Url: https://github.com/Maintainerr/Maintainerr/sessions/bdecdc93-4aa4-467f-89bd-080b8a9e67f0

Co-authored-by: enoch85 <4511254+enoch85@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: enoch85 <4511254+enoch85@users.noreply.github.com>

* build(deps): bump better-sqlite3 from 12.9.0 to 12.10.0 (#2908)

Bumps [better-sqlite3](https://github.com/WiseLibs/better-sqlite3) from 12.9.0 to 12.10.0.
- [Release notes](https://github.com/WiseLibs/better-sqlite3/releases)
- [Commits](WiseLibs/better-sqlite3@v12.9.0...v12.10.0)

---
updated-dependencies:
- dependency-name: better-sqlite3
  dependency-version: 12.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @suites/di.nestjs from 3.0.1 to 3.1.0 (#2907)

Bumps [@suites/di.nestjs](https://github.com/suites-dev/suites/tree/HEAD/packages/di/nestjs) from 3.0.1 to 3.1.0.
- [Release notes](https://github.com/suites-dev/suites/releases)
- [Changelog](https://github.com/suites-dev/suites/blob/master/packages/di/nestjs/CHANGELOG.md)
- [Commits](https://github.com/suites-dev/suites/commits/@suites/di.nestjs@3.1.0/packages/di/nestjs)

---
updated-dependencies:
- dependency-name: "@suites/di.nestjs"
  dependency-version: 3.1.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump axios from 1.16.0 to 1.16.1 (#2910)

Bumps [axios](https://github.com/axios/axios) from 1.16.0 to 1.16.1.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](axios/axios@v1.16.0...v1.16.1)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.16.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @types/node from 22.19.17 to 22.19.19 (#2909)

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.19.17 to 22.19.19.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 22.19.19
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Document GitHub CI workflow commands (#2912)

* Document CI workflow commands

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Clarify CI workflow commands

---------

Co-authored-by: enoch85 <mailto@danielhansson.nu>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* build(deps): bump react-hook-form from 7.75.0 to 7.76.0 (#2916)

Bumps [react-hook-form](https://github.com/react-hook-form/react-hook-form) from 7.75.0 to 7.76.0.
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](react-hook-form/react-hook-form@v7.75.0...v7.76.0)

---
updated-dependencies:
- dependency-name: react-hook-form
  dependency-version: 7.76.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump knip from 6.13.1 to 6.14.1 (#2915)

Bumps [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) from 6.13.1 to 6.14.1.
- [Release notes](https://github.com/webpro-nl/knip/releases)
- [Commits](https://github.com/webpro-nl/knip/commits/knip@6.14.1/packages/knip)

---
updated-dependencies:
- dependency-name: knip
  dependency-version: 6.14.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @typescript-eslint/eslint-plugin (#2917)

Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 8.59.3 to 8.59.4.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.59.4/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.59.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump vite from 8.0.12 to 8.0.13 (#2918)

Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 8.0.12 to 8.0.13.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.0.13/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 8.0.13
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump nestjs-zod from 5.3.0 to 5.4.0 (#2920)

Bumps [nestjs-zod](https://github.com/BenLorantfy/nestjs-zod/tree/HEAD/packages/nestjs-zod) from 5.3.0 to 5.4.0.
- [Release notes](https://github.com/BenLorantfy/nestjs-zod/releases)
- [Commits](https://github.com/BenLorantfy/nestjs-zod/commits/v5.4.0/packages/nestjs-zod)

---
updated-dependencies:
- dependency-name: nestjs-zod
  dependency-version: 5.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump rolldown from 1.0.0-rc.18 to 1.0.1 (#2919)

Bumps [rolldown](https://github.com/rolldown/rolldown/tree/HEAD/packages/rolldown) from 1.0.0-rc.18 to 1.0.1.
- [Release notes](https://github.com/rolldown/rolldown/releases)
- [Changelog](https://github.com/rolldown/rolldown/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rolldown/rolldown/commits/v1.0.1/packages/rolldown)

---
updated-dependencies:
- dependency-name: rolldown
  dependency-version: 1.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump date-fns from 4.1.0 to 4.2.1 (#2921)

Bumps [date-fns](https://github.com/date-fns/date-fns) from 4.1.0 to 4.2.1.
- [Release notes](https://github.com/date-fns/date-fns/releases)
- [Changelog](https://github.com/date-fns/date-fns/blob/main/CHANGELOG.md)
- [Commits](date-fns/date-fns@v4.1.0...v4.2.1)

---
updated-dependencies:
- dependency-name: date-fns
  dependency-version: 4.2.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Replace partial-cast query mocks in CollectionDetailPage spec (#2914)

* Use typed query helpers in CollectionDetailPage spec

* Format CollectionDetailPage spec

---------

* feat(media-server): add Emby as a third supported media server (#2911)

* fix(ci): make docs drift PR request resilient

* feat(streamystats): add Jellyfin-only Streamystats integration (#2923)

* fix: tighten emby storage and icon handling

* chore: format emby followup changes

* fix: tighten emby storage and icon handling (#2924)

* fix: tighten emby storage and icon handling

* chore: format emby followup changes

* fix(streamystats): don't send stored Jellyfin API key on connection test (#2925)

* fix: align emby login error styling

* fix(emby): request MediaSources field when computing library sizes

computeLibraryStorageSizes queried /Items without a Fields parameter,
so Emby returned items with no MediaSources (and no top-level Size).
Every item summed to 0, so no library was ever added to the result
map and the storage-metrics endpoint reported sizeBytesByLibrary: {}.

#2924 added pagination and an item.Size ?? MediaSources fallback but
dropped the original `Fields: 'MediaSources'`, and its test mocked
responses that already contained the size fields — so the regression
passed CI while real Emby servers returned empty sizes.

Request `Fields: 'MediaSources'` on the paginated query and add a
regression test asserting the field is present.

* build(deps-dev): bump @types/react in the react group (#2926)

Bumps the react group with 1 update: [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react).


Updates `@types/react` from 19.2.14 to 19.2.15
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-version: 19.2.15
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: react
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump postcss from 8.5.14 to 8.5.15 (#2927)

Bumps [postcss](https://github.com/postcss/postcss) from 8.5.14 to 8.5.15.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](postcss/postcss@8.5.14...8.5.15)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.15
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @typescript-eslint/parser from 8.59.3 to 8.59.4 (#2928)

Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 8.59.3 to 8.59.4.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.59.4/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.59.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @tanstack/eslint-plugin-query (#2929)

Bumps [@tanstack/eslint-plugin-query](https://github.com/TanStack/query/tree/HEAD/packages/eslint-plugin-query) from 5.100.10 to 5.100.11.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/eslint-plugin-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/eslint-plugin-query@5.100.11/packages/eslint-plugin-query)

---
updated-dependencies:
- dependency-name: "@tanstack/eslint-plugin-query"
  dependency-version: 5.100.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump turbo from 2.9.12 to 2.9.14 (#2930)

Bumps [turbo](https://github.com/vercel/turborepo) from 2.9.12 to 2.9.14.
- [Release notes](https://github.com/vercel/turborepo/releases)
- [Changelog](https://github.com/vercel/turborepo/blob/main/RELEASE.md)
- [Commits](vercel/turborepo@v2.9.12...v2.9.14)

---
updated-dependencies:
- dependency-name: turbo
  dependency-version: 2.9.14
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump glob from 7.2.3 to 13.0.6

Bumps [glob](https://github.com/isaacs/node-glob) from 7.2.3 to 13.0.6.
- [Changelog](https://github.com/isaacs/node-glob/blob/main/changelog.md)
- [Commits](isaacs/node-glob@v7.2.3...v13.0.6)

---
updated-dependencies:
- dependency-name: glob
  dependency-version: 13.0.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): bump undici from 5.29.0 to 7.25.0

Bumps [undici](https://github.com/nodejs/undici) from 5.29.0 to 7.25.0.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](nodejs/undici@v5.29.0...v7.25.0)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 7.25.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): bump ajv from 6.15.0 to 8.20.0

Bumps [ajv](https://github.com/ajv-validator/ajv) from 6.15.0 to 8.20.0.
- [Release notes](https://github.com/ajv-validator/ajv/releases)
- [Commits](ajv-validator/ajv@v6.15.0...v8.20.0)

---
updated-dependencies:
- dependency-name: ajv
  dependency-version: 8.20.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): bump tar from 6.2.1 to 7.5.15

Bumps [tar](https://github.com/isaacs/node-tar) from 6.2.1 to 7.5.15.
- [Release notes](https://github.com/isaacs/node-tar/releases)
- [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md)
- [Commits](isaacs/node-tar@v6.2.1...v7.5.15)

---
updated-dependencies:
- dependency-name: tar
  dependency-version: 7.5.15
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): bump minimatch from 3.1.5 to 10.2.5

Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.1.5 to 10.2.5.
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](isaacs/minimatch@v3.1.5...v10.2.5)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-version: 10.2.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(overlays): keep ellipse anchored on drag and resize (#2938)

* fix(deps): resolve transitive security advisories

Force patched versions of transitive-only dependencies flagged by
Dependabot. All direct runtime deps were already patched; these
overrides clear the nested copies pulled by build/dev tooling.

- node-gyp 11.2.0: replaces tar 6.2.1 with patched 7.5.15
  (GHSA-r6q2-hw4h-h46w, -8qq5-rm4j-mr97, -34x7-hfp2-rc4v,
   -83g3-92jg-28cx, -qffp-2rhf-9h96, -9ppj-qmqm-q256)
- minimatch 9.0.9: ReDoS fixes (GHSA-7r86-cg39-jmmj and related)
- yaml 1.10.3: stack overflow (GHSA-48c2-rrv3-qjmp)
- ajv 8.20.0: $data ReDoS (GHSA-2g4f-4pwh-qvx6)
- undici 6.25.0: WebSocket/smuggling/decompression fixes via cheerio
  (GHSA-f269-vfmq-vjvj, -2mjp-6q6p-2qxm, -vrm6-8vpv-qv8q,
   -v9p9-hfj2-hcw8, -4992-7rv2-5pvq, -g9mf-h72j-4rw9)

* chore(deps): dedupe @typescript-eslint to clear TypeScript peer warning

eslint-plugin-jest pulled a stale @typescript-eslint/utils@8.46.4
(peer typescript <6.0.0) alongside the toolchain's 8.59.4 (peer
<6.1.0), so the intersected range excluded the project's TS 6.0.3 and
emitted YN0060/YN0086 on install. Deduping aligns all
@typescript-eslint/* copies on 8.59.4. Dev-tooling only.

* chore: apply staged updates

* build(deps): bump react-router-dom from 7.15.0 to 7.15.1

Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 7.15.0 to 7.15.1.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@7.15.1/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-version: 7.15.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps-dev): bump vitest from 4.1.6 to 4.1.7

Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 4.1.6 to 4.1.7.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.7/packages/vitest)

---
updated-dependencies:
- dependency-name: vitest
  dependency-version: 4.1.7
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps-dev): bump @vitejs/plugin-react from 6.0.1 to 6.0.2

Bumps [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@6.0.2/packages/plugin-react)

---
updated-dependencies:
- dependency-name: "@vitejs/plugin-react"
  dependency-version: 6.0.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(ui): sync settings forms via react-hook-form values to stop render loop

The Emby, Jellyfin and Servarr settings forms reset the form from loaded
settings inside a useEffect keyed on the query result. When that data
reference is unstable, the effect re-fires every render and loops until the
vitest worker exhausts memory and is SIGTERM'd — which is what was failing
the test job. Use react-hook-form's `values` option instead: it deep-compares
and keeps the form in sync without an effect.

Also stop ts-jest from re-transforming the prebuilt @maintainerr/contracts
dist output, removing the compiler warning flood on every server test run.

* build(deps): bump @tanstack/react-query from 5.100.10 to 5.100.11 (#2945)

Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.100.10 to 5.100.11.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.100.11/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.100.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* test(ui): wait for Run Now to enable before clicking in overlay pass test

The "Run Now" button stays disabled until the server's enabled state finishes
loading. The test clicked as soon as the button rendered, so under CI load the
click could land while it was still disabled (a no-op), leaving
processAllOverlays uncalled and failing intermittently. Wait for the button to
enable before clicking.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: maintainerr-automation[bot] <261505141+maintainerr-automation[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: enoch85 <mailto@danielhansson.nu>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: enoch85 <4511254+enoch85@users.noreply.github.com>
Co-authored-by: Kristian Matthews-Kennington <kristian@matthews-kennington.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@enoch85 enoch85 added this to the 3.12.0 milestone May 20, 2026 — with GitHub Codespaces
@maintainerr-automation

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 3.12.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

doonga pushed a commit to greyrock-labs/home-ops that referenced this pull request May 21, 2026
…12.0 ) (#101)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/maintainerr/maintainerr](https://github.com/Maintainerr/Maintainerr) | minor | `3.11.2` → `3.12.0` |

---

> ⚠️ **Warning**
>
> Some dependencies could not be looked up. Check the [Dependency Dashboard](issues/34) for more information.

---

### Release Notes

<details>
<summary>Maintainerr/Maintainerr (ghcr.io/maintainerr/maintainerr)</summary>

### [`v3.12.0`](https://github.com/Maintainerr/Maintainerr/releases/tag/v3.12.0)

[Compare Source](Maintainerr/Maintainerr@v3.11.2...v3.12.0)

##### Highlights

- Added Emby as a third supported media server alongside Plex and Jellyfin ([#&#8203;2911](Maintainerr/Maintainerr#2911)).
- Introduced Jellyfin-only Streamystats integration, including a new settings tab and per-user stats panel ([#&#8203;2923](Maintainerr/Maintainerr#2923)).
- Fixed Emby library size computation and metadata updates to align with documented API behavior ([#&#8203;2924](Maintainerr/Maintainerr#2924)).

##### Breaking Changes

- None.

##### Features

- Added Emby as a third supported media server ([#&#8203;2911](Maintainerr/Maintainerr#2911)).
- Introduced Jellyfin-only Streamystats integration, including a new settings tab and per-user stats panel ([#&#8203;2923](Maintainerr/Maintainerr#2923)).

##### Fixes

- Fixed Emby library size computation and metadata updates to align with documented API behavior ([#&#8203;2924](Maintainerr/Maintainerr#2924)).
- Resolved transitive security advisories by forcing patched versions of dependencies.
- Fixed issue with Emby login error styling.
- Prevented Jellyfin API key from being sent during Streamystats connection tests ([#&#8203;2925](Maintainerr/Maintainerr#2925)).
- Fixed overlay ellipse anchoring during drag and resize ([#&#8203;2938](Maintainerr/Maintainerr#2938)).
- Synced settings forms via react-hook-form values to stop render loops.

##### Performance

- None.

##### Database migrations

- Added support for Emby by introducing new columns: `emby_url`, `emby_api_key`, `emby_user_id`, and `emby_server_name` to the `settings` table.
- Added support for Streamystats by introducing a new column: `streamystats_url` to the `settings` table.

##### Internal

- Updated test for overlay "Run Now" button to wait for enabled state before clicking.
- Replaced partial query mocks in `CollectionDetailPage` spec with typed helpers ([#&#8203;2914](Maintainerr/Maintainerr#2914)).
- Documented GitHub CI workflow commands ([#&#8203;2912](Maintainerr/Maintainerr#2912)).
- Improved CI docs drift scanner to surface documentation-labeled items.

##### Dependencies

- Updated 29 dependencies, including [@&#8203;tanstack/react-query](https://github.com/tanstack/react-query), [@&#8203;vitejs/plugin-react](https://github.com/vitejs/plugin-react), vitest, react-router-dom, and tar.

</details>

---

### Configuration

📅 **Schedule**: (in timezone America/New_York)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xODIuMiIsInVwZGF0ZWRJblZlciI6IjQzLjE4Mi4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL21pbm9yIl19-->

Reviewed-on: https://git.greyrock.io/greyrock-labs/home-ops/pulls/101
enoch85 added a commit that referenced this pull request May 27, 2026
…P 414) (#3001)

Creating a new collection from a large rule seeded every item id into the
create request's query string (BULK_COLLECTION_CREATE, #2911), overflowing
the URL and failing with "Failed to create collection" / HTTP 414 URI Too
Long. Item ids can only travel in the query string on Plex/Jellyfin/Emby
(no request body), so the seed is unbounded.

Revert to the pre-#2911 / 2.x behaviour: create the collection empty and
populate it via the existing batched add path (addBatchToCollection), for
all media servers. Removes the now-unused BULK_COLLECTION_CREATE capability
and the initialItemIds plumbing.
maintainerr-automation Bot added a commit that referenced this pull request May 27, 2026
* feat(ui): migrate to Tailwind CSS v4 (CSS-first) + dev DB seed

- CSS-first theme: @theme + @plugin in globals.css; remove tailwind.config.js
- Use @tailwindcss/vite; drop postcss, autoprefixer, @tailwindcss/aspect-ratio
- Fix v4 regressions: @tailwindcss/forms .form-input collision (strategy: base),
  dead bg-opacity-* -> slash syntax, checkbox focus ring + single .checkbox class,
  translucent backgrounds, unlayered prose colors
- Standardize Plex checkboxes, Manual badge, and input-action button states;
  delay the overlay-schedule loading hint
- Add dev/seed-db.mjs to seed collections/rules/storage for local testing

* feat(ui): adopt Tailwind v4.x features

- color-scheme: dark so native controls render dark
- container query for the media-card grid (sizes to container, not viewport)
- field-sizing-content on the rule description and overlay text textareas
- text-shadow on poster-overlaid title/year/summary
- drop the v3->v4 border-color compat shim (one implicit border made explicit)

Closes #2970

* refactor(ui): single source for form field styling

- Move the field base style into the global input/select/textarea rule so it
  is the single source of truth; Forms/Input and Forms/Select keep deltas only
  (adornments, join, error, select chevron). One edit now restyles every field.
- SearchBar uses the shared field style (drops the pill override; fixes the
  clipped icon and the blue focus ring).
- Include input[type=search] in the shared rule; maintainerr focus app-wide.
- Keep the v4 field-sizing auto-grow on the rule description + overlay text,
  with min-h so the textareas no longer collapse when empty.
- Uniform rule-form row spacing; blank the log filter's default option (was '-').

* Document Codex MCP config and media integration coverage (#2974)

* perf: cache hygiene for external API and metadata responses (#2972)

- ExternalApiService: skip caching Buffer/null/non-object responses, so binary
  blobs and empty bodies can't poison the shared NodeCaches.
- cache: exempt tmdb/tvdb (immutable external metadata, 6h TTL) from the per-run
  flushAll(), so rule runs don't needlessly re-fetch them.
- tmdb metadata provider: ignore non-object records.

* fix(release): emit changelog version header and correct breaking-change classification

- Pass NEXT_RELEASE_VERSION/LAST_RELEASE_GITTAG/NEXT_RELEASE_GITHEAD into
  the notes generator via generateNotesCmd. semantic-release does not export
  these to plugin commands, so buildHeader() always saw an empty version and
  emitted no '# [x.y.z](compare) (date)' header for v3.11.2..v3.12.1.
- Tell the model to net out the commit range: an identifier introduced and
  renamed/removed within one release never shipped, so it is not breaking.
- Backfill the missing v3.11.2/v3.12.0/v3.12.1 headers and drop the false
  'Breaking Changes' (an internal settings-service rename) from v3.12.1.

* fix: OR rule sections incorrectly evaluated as AND due to operator coercion (#2971)

* fix: treat unset rule section operator as OR instead of AND

An unset section operator (null) was coerced to AND by `+null === 0`, so
sections meant to OR together were evaluated as AND. The coercion is now
null-guarded, resolving an unset operator to OR — consistent with how a
null operator is already treated within a section.

Also require an explicit operator on non-first rules in the rule editor,
backfill existing unset operators to OR, and stop dropping a numeric AND
section operator on YAML export.

Co-Authored-By: James Nobes <github@stormshaker.com>

* fix(rules): normalize legacy section operators

---------

Co-authored-by: enoch85 <mailto@danielhansson.nu>
Co-authored-by: Kristian Matthews-Kennington <kristian@matthews-kennington.com>

* fix(rules): robust community/YAML rule import across media servers (#2976)

Imports could silently break when a rule's properties don't all map to
the configured media server:

- Migrate firstVal and lastVal independently by each field's own app, so a
  media-server property compared against a Seerr/Tautulli value is no longer
  stranded on the source server (Plex/Emby) and rendered blank. Covers
  Plex/Jellyfin/Emby.
- Surface rules dropped on import (no equivalent on the target server) via a
  toast on both the community and YAML paths; keep the warn log.
- YAML export no longer writes `App.undefined` for an unknown property, and
  import skips an unresolved rule (reported as a skipped count) instead of
  rejecting the whole document.
- validateRule returns a clean status instead of throwing on a missing
  application/property; rule-group create no longer fails when notifications
  is omitted.

* chore(dev): add offline mock Jellyfin server

Dev-only HTTP stub answering the Jellyfin endpoints the server's adapter
calls (connection, users, libraries, item metadata, item images). Pairs
with dev/seed-db.mjs so the editor library list, rule-group save,
collection grids and rule evaluation work without a real Jellyfin.
Invented data only; not referenced by application code.

* feat(rules): add Plex "Amount of episodes marked as watched" rule (#2975)

Adds a show/season rule property (sw_markedWatchedEpisodes) backed by
Plex's viewedLeafCount (watched state) instead of play history.

Unlike "Amount of watched episodes" (sw_viewedEpisodes), which counts
episodes that have a play-history entry, this counts episodes Plex
considers watched -- including those manually marked as watched, since
Plex sets viewedLeafCount for manual marks but writes no play history.

* Refactor shared media getter rule helpers (#2922)


Co-authored-by: enoch85 <mailto@danielhansson.nu>

* feat(rules): add Streamystats watchlist rule properties for Jellyfin (#2977)

Adds a Jellyfin-only Streamystats rule Application (the Jellyfin analog of
Tautulli) with two watchlist-backed properties: "Is in a watchlist" and
"[list] In watchlist of (username)". Upstream Streamystats now accepts
Jellyfin API-key auth on its watchlist endpoints, so Maintainerr can reach
them via the MediaBrowser token scheme.

Only public Streamystats watchlists are visible to the API key. The
membership snapshot is cached in the shared Streamystats NodeCache (flushed
between rule-group runs). The Application is removed from the rule constants
unless Streamystats is configured, and the UI hides it on non-Jellyfin
servers. Username resolution failures surface as a transient skip rather
than an empty list.

* fix: Test Media search styling (Tailwind v4) + unary-rule comparison crash (#2978)

* docs: unify agent instructions into a single index, add handoff notes (#2980)

- AGENTS.md is the single documentation index; the Claude, Copilot, Cursor,
  and Codex entrypoints route to it and name the standing rules directly so
  they can't be missed.
- Split standing rules (read every session) from task-specific docs (read on
  demand); scope release-review's Copilot applyTo to release artifacts so it
  no longer loads on every interaction.
- Add project-notes.instructions.md (non-obvious project knowledge and
  conventions for handoff) and README_AGENTS.md (the wiring map).
- Move dev mocks + DB seed to tools/dev/ (fix seed-db repo-root resolution);
  add the seeded-DB + Playwright step to the release-review checklist.

* docs: strengthen migration rule and fix release-review SQL guidance

- implementation rule 8: demand TypeORM + typeorm_instructions.txt workflow,
  require migrations be tested end-to-end before considered working
- release-review: fix broken typeorm_instructions.txt path (root, not
  .github/instructions/); clarify that generated schema migrations may contain
  raw DDL while hand-written data migrations must use QueryBuilder

* docs: add YAML import/export + community-rule testing guide to project notes

How to exercise both import paths (YAML encode/decode vs community-rule
/migrate), why they don't share code, and quick checks for the #2971/#2976
behaviours and v2.0.0+ community-rule import.

* build(deps): bump the nestjs group with 4 updates (#2981)

Bumps the nestjs group with 4 updates: [@nestjs/common](https://github.com/nestjs/nest/tree/HEAD/packages/common), [@nestjs/core](https://github.com/nestjs/nest/tree/HEAD/packages/core), [@nestjs/platform-express](https://github.com/nestjs/nest/tree/HEAD/packages/platform-express) and [@nestjs/testing](https://github.com/nestjs/nest/tree/HEAD/packages/testing).


Updates `@nestjs/common` from 11.1.23 to 11.1.24
- [Release notes](https://github.com/nestjs/nest/releases)
- [Commits](https://github.com/nestjs/nest/commits/v11.1.24/packages/common)

Updates `@nestjs/core` from 11.1.23 to 11.1.24
- [Release notes](https://github.com/nestjs/nest/releases)
- [Commits](https://github.com/nestjs/nest/commits/v11.1.24/packages/core)

Updates `@nestjs/platform-express` from 11.1.23 to 11.1.24
- [Release notes](https://github.com/nestjs/nest/releases)
- [Commits](https://github.com/nestjs/nest/commits/v11.1.24/packages/platform-express)

Updates `@nestjs/testing` from 11.1.23 to 11.1.24
- [Release notes](https://github.com/nestjs/nest/releases)
- [Commits](https://github.com/nestjs/nest/commits/v11.1.24/packages/testing)

---
updated-dependencies:
- dependency-name: "@nestjs/common"
  dependency-version: 11.1.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: nestjs
- dependency-name: "@nestjs/core"
  dependency-version: 11.1.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: nestjs
- dependency-name: "@nestjs/platform-express"
  dependency-version: 11.1.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: nestjs
- dependency-name: "@nestjs/testing"
  dependency-version: 11.1.24
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: nestjs
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump date-fns from 4.2.1 to 4.3.0 (#2982)

Bumps [date-fns](https://github.com/date-fns/date-fns) from 4.2.1 to 4.3.0.
- [Release notes](https://github.com/date-fns/date-fns/releases)
- [Commits](date-fns/date-fns@v4.2.1...v4.3.0)

---
updated-dependencies:
- dependency-name: date-fns
  dependency-version: 4.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump typescript-eslint from 8.59.4 to 8.60.0 (#2984)

Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.59.4 to 8.60.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.60.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.60.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @swc/core from 1.15.33 to 1.15.40 (#2985)

Bumps [@swc/core](https://github.com/swc-project/swc/tree/HEAD/packages/core) from 1.15.33 to 1.15.40.
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/commits/v1.15.40/packages/core)

---
updated-dependencies:
- dependency-name: "@swc/core"
  dependency-version: 1.15.40
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump knip from 6.14.1 to 6.14.2 (#2987)

Bumps [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) from 6.14.1 to 6.14.2.
- [Release notes](https://github.com/webpro-nl/knip/releases)
- [Commits](https://github.com/webpro-nl/knip/commits/knip@6.14.2/packages/knip)

---
updated-dependencies:
- dependency-name: knip
  dependency-version: 6.14.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix(rules): harden rule import (TEXT_LIST YAML decode + community-import operator backfill) (#2986)

* fix(rules): resolve TEXT_LIST custom value on YAML import

The encoder serialises a custom value's type as the RuleType humanName, so
TEXT_LIST becomes "text list" (with a space). The decoder's switch only matched
'TEXT_LIST', so the spaced key fell through, left ruleType undefined, and threw
on the return's .toString() — failing the entire YAML import. Normalise spaces
to underscores before matching.

* style: run yarn format on rules constants spec

Agent-Logs-Url: https://github.com/Maintainerr/Maintainerr/sessions/38e8bea3-daf7-4de0-aeac-a61c2d3e5fa2

Co-authored-by: enoch85 <4511254+enoch85@users.noreply.github.com>

* fix(rules): backfill unset within-section operator on community import

migrateImportedRuleDtos remapped apps and reasserted section-boundary operators
but left within-section unset operators as null. A pre-explicit-operator
community rule (e.g. one authored before #2971) could therefore carry a null
operator on a non-first rule, which the new "operator is required for every rule
after the first" save validation rejects on import. Backfill those to OR after
the boundary pass — the same default the comparator and the
NormalizeRuleSectionOperators migration apply.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>

* build(deps): bump typeorm from 0.3.29 to 1.0.0 (#2983)

* build(deps): bump typeorm from 0.3.29 to 1.0.0

Bumps [typeorm](https://github.com/typeorm/typeorm) from 0.3.29 to 1.0.0.
- [Release notes](https://github.com/typeorm/typeorm/releases)
- [Changelog](https://github.com/typeorm/typeorm/blob/master/CHANGELOG.md)
- [Commits](typeorm/typeorm@0.3.29...1.0.0)

---
updated-dependencies:
- dependency-name: typeorm
  dependency-version: 1.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(server): use object-form find relations for typeorm 1.0.0

TypeORM 1.0.0 removed string-based relations from find methods (#12215).
Convert the six affected findOne/find calls to the object form, which is
valid in both 0.3.x and 1.0.0.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: enoch85 <mailto@danielhansson.nu>

* build(deps-dev): bump @tanstack/eslint-plugin-query (#2992)

Bumps [@tanstack/eslint-plugin-query](https://github.com/TanStack/query/tree/HEAD/packages/eslint-plugin-query) from 5.100.11 to 5.100.14.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/eslint-plugin-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/eslint-plugin-query@5.100.14/packages/eslint-plugin-query)

---
updated-dependencies:
- dependency-name: "@tanstack/eslint-plugin-query"
  dependency-version: 5.100.14
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump react-hook-form from 7.76.0 to 7.76.1 (#2993)

Bumps [react-hook-form](https://github.com/react-hook-form/react-hook-form) from 7.76.0 to 7.76.1.
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](react-hook-form/react-hook-form@v7.76.0...v7.76.1)

---
updated-dependencies:
- dependency-name: react-hook-form
  dependency-version: 7.76.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump nodemailer from 8.0.8 to 8.0.9 (#2994)

Bumps [nodemailer](https://github.com/nodemailer/nodemailer) from 8.0.8 to 8.0.9.
- [Release notes](https://github.com/nodemailer/nodemailer/releases)
- [Changelog](https://github.com/nodemailer/nodemailer/blob/master/CHANGELOG.md)
- [Commits](nodemailer/nodemailer@v8.0.8...v8.0.9)

---
updated-dependencies:
- dependency-name: nodemailer
  dependency-version: 8.0.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump @tanstack/react-query from 5.100.11 to 5.100.14 (#2995)

Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.100.11 to 5.100.14.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.100.14/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.100.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix(notifications): omit empty Discord embed thumbnail

Discord rejects webhook payloads with 400 Invalid Form Body when an
embed contains an empty thumbnail object. Imageless notifications (e.g.
media-removed / rule-handling events) always sent thumbnail.url=undefined,
which serialized to an empty thumbnail and silently failed. Only attach
the thumbnail when an image is present.

* build(deps-dev): bump turbo from 2.9.14 to 2.9.15 (#2997)

Bumps [turbo](https://github.com/vercel/turborepo) from 2.9.14 to 2.9.15.
- [Release notes](https://github.com/vercel/turborepo/releases)
- [Changelog](https://github.com/vercel/turborepo/blob/main/RELEASE.md)
- [Commits](vercel/turborepo@v2.9.14...v2.9.15)

---
updated-dependencies:
- dependency-name: turbo
  dependency-version: 2.9.15
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @typescript-eslint/parser from 8.59.4 to 8.60.0 (#2998)

Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 8.59.4 to 8.60.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.60.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.60.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump rolldown from 1.0.2 to 1.0.3 (#2999)

Bumps [rolldown](https://github.com/rolldown/rolldown/tree/HEAD/packages/rolldown) from 1.0.2 to 1.0.3.
- [Release notes](https://github.com/rolldown/rolldown/releases)
- [Changelog](https://github.com/rolldown/rolldown/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rolldown/rolldown/commits/v1.0.3/packages/rolldown)

---
updated-dependencies:
- dependency-name: rolldown
  dependency-version: 1.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @typescript-eslint/eslint-plugin (#3000)

Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 8.59.4 to 8.60.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.60.0/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.60.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix(collections): create collections empty, then batch-add (avoid HTTP 414) (#3001)

Creating a new collection from a large rule seeded every item id into the
create request's query string (BULK_COLLECTION_CREATE, #2911), overflowing
the URL and failing with "Failed to create collection" / HTTP 414 URI Too
Long. Item ids can only travel in the query string on Plex/Jellyfin/Emby
(no request body), so the seed is unbounded.

Revert to the pre-#2911 / 2.x behaviour: create the collection empty and
populate it via the existing batched add path (addBatchToCollection), for
all media servers. Removes the now-unused BULK_COLLECTION_CREATE capability
and the initialItemIds plumbing.

* fix(rules): scope exclusions to their rule group under TypeORM 1.0 (#2991)

* fix(rules): scope exclusions to their rule group under TypeORM 1.0

Adopt TypeORM 1.0 where-clause null semantics (default throw; IsNull() to
match NULL) instead of 0.3.x's silent-ignore footgun, fixing latent exclusion
bugs surfaced by the typeorm 1.0.0 bump (#2983):

- getExclusions: a group-scoped exclusion no longer leaks into other rule
  groups (and no longer returns duplicates); global exclusions still apply
  everywhere.
- setExclusion: global exclusions subsume scoped ones — an item is global or
  scoped, never both.
- removeExclusion: removing a global exclusion no longer writes a spurious
  collection-log entry; logs media + ownership.
- getCollection: a null/blank id returns undefined instead of an arbitrary
  first collection.

Bumps engines.node to TypeORM 1.0's floor and adds getter-property and
exclusion-scoping regression coverage.

* feat(ui): warn before a global exclusion replaces rule-group exclusions

When adding a global exclusion for an item that already has rule-group
exclusions, show a confirmation listing each "<item> — <rule group>" (the
group links to its collection, reusing the backdrop's maintainerr-status data
so labels/links match and stay fresh) before proceeding, since going global
removes those scoped exclusions. Only triggers on the Add action, never on
Remove.

* test(ui): cover the global-exclusion warning in AddModal

* fix(ui): clarify Add/Remove action labels in the media modal

* fix(ui): don't block global exclusion when warning prefetch fails

* fix(plex): don't drop auth when plex.tv is unreachable (#2996)

* fix(plex): don't drop auth when plex.tv is unreachable

A plex.tv timeout was reported as an invalid token, so the Plex settings
page declared stored credentials invalid and demanded re-authentication
even when the saved token was fine. Distinguish a genuine rejection
(401/403) from a connectivity failure: on unreachable, keep the account
authenticated, warn, and auto-retry until plex.tv responds.

* fix(ui): clear stale Plex auth warning

* fix(ui): navigate client-side from global-exclusion warning links

The rule-group links in the AddModal global-exclusion warning used a raw
<a href>, which forced a full page reload and ignored the router basename
(404 under BASE_PATH subpath installs). Use useNavigate instead, and clear
the maintainerr-status cache + invalidate collection queries first so the
destination still fetches fresh — what the full reload did implicitly.

* test(server): add 1.x upgrade-path and all-rules comparator regression coverage

- upgrade-from-1x.spec.ts: reconstructs the v1.7.1 schema, seeds 1.x-era
  data (rules with null operators), applies every post-1.7.1 migration and
  asserts the operator backfill + late-migration schema survive.
- rules-test-matrix.e2e.ts: generated matrix covering every RuleType x
  RulePossibility (value/missing/present/absent), for cross-version diffing.

* docs: correct Yarn linker note in project-notes (node-modules, not PnP)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: maintainerr-automation[bot] <261505141+maintainerr-automation[bot]@users.noreply.github.com>
Co-authored-by: enoch85 <mailto@danielhansson.nu>
Co-authored-by: Kristian Matthews-Kennington <kristian@matthews-kennington.com>
Co-authored-by: James Nobes <github@stormshaker.com>
Co-authored-by: CampbellMG <40409896+CampbellMG@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants