Skip to content

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

Merged
enoch85 merged 10 commits into
developmentfrom
streamystats-integration
May 19, 2026
Merged

feat(streamystats): add Jellyfin-only Streamystats integration#2923
enoch85 merged 10 commits into
developmentfrom
streamystats-integration

Conversation

@enoch85

@enoch85 enoch85 commented May 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • New Streamystats settings tab, gated to Jellyfin (Streamystats does not support Emby upstream).
  • "View on Streamystats" link in the media modal + inline per-user stats panel powered by /api/get-item-details/[itemId] (per-user table, completion %, last watched, series episode coverage).
  • Authentication reuses the existing jellyfin_api_key — no separate credential field.

Bundled refactor

  • ExternalServiceSettingsPage now takes a declarative fields prop; Seerr, Tautulli, Streamystats all migrated. Removes service-specific branching from the shared component.

Out-of-scope fixes bundled in this PR

These weren't part of the Streamystats integration plan, but were either triggered by it or noticed during development and small enough not to warrant a separate PR:

  • Media-server switch transition race (f2e0f27b): MediaServerFactory.getService() now throws ServiceUnavailableException when the configured server type has no credentials yet (the brief window between a switch and saving new credentials). NotificationService.transformMessageContent catches this specific exception at DEBUG instead of ERROR, eliminating the scary log cascade users saw mid-switch. Same behavior existed on development before this branch — flagged by a real user log.
  • Drive-by TS errors from the upstream Emby PR (50cd8c75): one-line fixes to MediaModal/index.spec.tsx (missing isEmby on the useMediaServerType mock) and EmbyLoginButton.tsx (missing name on two InputGroup calls). Both exist on development without this branch.

Verification

Quality gate green: lint clean, 1332 server + 52 UI test files (206 tests) pass.

End-to-end verified against a live dev server (Playwright + curl):

  • Tab visibility: Streamystats tab present under Jellyfin, hidden under Plex/Emby
  • Direct navigation /settings/streamystats under Plex/Emby → redirects to /settings/main, zero leaked API calls
  • Server-side guard: all six Streamystats endpoints (settings GET/POST/DELETE/test + info + items/:itemId) return 403 Forbidden when the active server is not Jellyfin
  • Settings form: renders correctly under Jellyfin (URL-only mode), test connection surfaces inline errors, save and delete both round-trip the persisted value
  • Switch cleanup: streamystats_url is nulled when the active server switches away from Jellyfin
  • No console errors / hydration warnings on the settings page

Media-modal badge link + per-user stats panel were verified manually by the maintainer against a live Jellyfin + Streamystats instance earlier in development.

Upstream blockers (tracked separately)

  1. API-key auth on authenticateMediaBrowser — unblocks future rule sources (recommendations / watchlists).
  2. Emby support in Streamystats.
  3. LICENSE file on the Streamystats repo.

enoch85 added 6 commits May 19, 2026 18:15
Settings tab gated to Jellyfin, "View on Streamystats" link plus an
inline per-user stats panel in the media modal. Auth reuses the existing
jellyfin_api_key. Refactors ExternalServiceSettingsPage to a declarative
fields prop (Seerr/Tautulli/Streamystats all migrated) so the shared
component no longer carries service-specific branching.
Pairs with the existing error header so the actual diagnosis (timeout,
ECONNREFUSED, 404, etc.) is visible in DEBUG logs without changing the
user-facing alert text.
After a media-server switch the system enters a brief window where
media_server_type is set but credentials aren't yet saved. Background
jobs (rule executor → notification cascade) hitting MediaServerFactory
in this state threw a generic Error, which NotificationService logged
at ERROR level.

Detect this transition state explicitly in getService() and throw a
typed ServiceUnavailableException. NotificationService treats this
exception as transient and logs at DEBUG, keeping the user-facing log
quiet while the user finishes configuring the new server.
- Item link format is /servers/<serverId>/library/<itemId>, not
  /library/<itemId>. Resolve serverId via /api/servers and cache.
- Add GET /api/streamystats/info endpoint exposing { url, serverId }
  so the UI can build correct links from a single source.
- Replace ad-hoc Tailwind tones with Maintainerr brand tokens:
  bg-zinc-900/70 card, text-white title, text-error-400, BrandLink
  for the panel link.
- Vendor upstream favicon.svg as the badge image (replaces the text
  fallback and the temporary PNG).
- Helper text on the settings page now splits example URLs onto
  separate lines under the input.
- Drop dead streamystats_url field from the UI ISettings interface;
  modal reads /streamystats/info instead.
Verified against upstream apps/nextjs-app/lib/db/items.ts: several
aggregation fields in /api/get-item-details are returned as PostgreSQL
COUNT/EXTRACT strings on the wire, even though Streamystats's
TypeScript interface declares them as number. Confirmed cases:

  watchCountByMonth[].{month,year,watchCount,uniqueUsers}  (items.ts:675-678)
  totalViews                                                (items.ts:232)
  usersWatched[].watchCount                                 (items.ts:530)

Only fields explicitly wrapped in Number(...) (totalWatchTime,
completionRate) arrive as numbers. The user's ZodError ("expected
number, received string" on month/year/uniqueUsers) maps directly to
the un-coerced columns.

Switch the affected schema fields to z.coerce.number() so the shared
schema stays robust without depending on upstream patching every
aggregation. The change is a no-op for fields that already arrive as
numbers.
@enoch85 enoch85 marked this pull request as ready for review May 19, 2026 19:25
@enoch85 enoch85 changed the title feat(streamystats): add Jellyfin-only Streamystats integration [WIP] feat(streamystats): add Jellyfin-only Streamystats integration May 19, 2026
enoch85 added 4 commits May 19, 2026 19:43
… enforcement

Three review findings from the previous round, all addressed:

HIGH — Streamystats client lifecycle
- StreamystatsApiService.init() now always clears `api` and
  `resolvedServerId` before the early-return guard, so removing the
  Streamystats URL actually deactivates /api/streamystats endpoints
  in-process (controller's `if (!api)` check now matches).
- SettingsService.saveJellyfinSettings/removeJellyfinSettings now
  re-init Streamystats so rotating Jellyfin credentials or wiping
  Jellyfin propagates to the Streamystats client cache.
- removeJellyfinSettings also nulls streamystats_url, since
  Streamystats can't authenticate without Jellyfin.

MEDIUM — Jellyfin-only enforcement is now real, not cosmetic
- Settings controller's four Streamystats endpoints (GET/POST/DELETE/
  test) and the Streamystats info/items endpoints all assert
  media_server_type === JELLYFIN; otherwise 403 Forbidden.
- Streamystats settings page redirects to /settings/main when the
  active media server isn't Jellyfin.

MEDIUM — Server resolution prefers URL over name
- resolveServerId now matches by URL first (trailing-slash-normalised)
  and falls back to name only when no URL match exists. Avoids the
  ambiguity where two Streamystats-registered servers share a display
  name but point at different Jellyfin URLs.

Adds four focused tests:
- init() clears cached api when settings are removed
- URL-first matching beats name-only when both candidates share a name
- saveJellyfinSettings re-initialises Streamystats
- removeJellyfinSettings clears streamystats_url and re-inits Streamystats
…TS errors

- streamystats-api.service.ts: simplify the serverId resolver to compare
  jellyfin_url against Streamystats's stored url directly. jellyfin_url is
  already canonicalised by serviceUrlSchema, so the per-service strip was
  unnecessary scope for this PR. A unified URL-normalization pass across
  all server-side services can land separately.
- MediaModal/index.spec.tsx + EmbyLoginButton.tsx: drive-by fixes for two
  TypeScript errors the upstream Emby PR left behind (isEmby missing from
  the useMediaServerType mock, name missing on two InputGroup calls).
Adds Settings/Streamystats/index.spec.tsx with four cases that exercise
the Jellyfin-only redirect on direct navigation to /settings/streamystats:

- returns null while settings are still loading (no API call fires)
- redirects to /settings/main when Plex is active (no API call fires)
- redirects to /settings/main when Emby is active (no API call fires)
- mounts the form and loads its defaults only when Jellyfin is active

The third case directly covers the reviewer-flagged path: a Plex/Emby
user typing /settings/streamystats does not leak a 403-backed GET, save
or test request — ExternalServiceSettingsPage never mounts.

Also restores the trailing-slash strip on the Streamystats serverId
resolver so URL matching stays reliable when /api/servers reports a
slash-suffixed URL. A broader manual-string-ops refactor of URL trims
across the server can land separately.
The Streamystats settings page rendered <div> children inside
ExternalServiceSettingsPage's <p id="url-help">, triggering a React
hydration warning ("<div> cannot be a descendant of <p>"). Replaced
the inner <div>s with text + <br /> + <span> wrappers so the markup
stays phrasing-content only. Visual layout is unchanged.

Verified end-to-end against a live dev server:
- 0 console errors after the fix on /settings/streamystats
- form mounts, GET /api/settings/streamystats returns 200
- test/save/delete flows all behave as expected
@enoch85 enoch85 merged commit 04f8f1f into development May 19, 2026
13 checks passed
@enoch85 enoch85 deleted the streamystats-integration branch May 19, 2026 20:26
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant