The babel-plugin-istanbul coverage plugin was only wired into the retired karma.conf.js; Vitest measures coverage via @vitest/coverage-v8 (.babelrc has no plugins). Dropping it removes the orphaned @istanbuljs/load-nyc-config -> js-yaml@3 subtree and clears the GHSA-h67p-54hq-rp68 DoS advisory; npm audit now reports 0 vulnerabilities.
* Lightbox: Add 360° photo and video sphere viewer support
Wires Photo Sphere Viewer v5 into the lightbox for equirectangular
media. Backend detects UsePanoramaViewer and IsPhotosphere markers
alongside ProjectionType, and exposes Panorama + Projection in the
viewer / search result DTOs so the frontend can dispatch on the
projection type. The renderer (ThreeJS + PSV core + video plugin +
equirectangular video adapter) is lazy-loaded into a dedicated
webpack chunk so the base bundle is unchanged for users with no
360° media. PhotoPrism's existing lightbox controls drive the
underlying HTMLVideoElement that the PSV adapter creates for 360°
videos. Includes Vitest coverage for the sphere helper and the
lightbox dispatch, plus a TestCafe smoke spec and three new
ExifTool metadata fixtures.
* Lightbox: Fix 360° controls leak, hide zoom button, add sidebar icon
* Lightbox: Fix 360° touch panning and navigation arrows
* Lightbox: Fix fast swipe switching photos on 360° slides
Suppress PhotoSwipe swipe/drag navigation at its source via the dispatched pointer hook while a sphere slide is active, since the per-element gesture trap is outrun by a fast swipe whose pointer leaves the sphere container (touch-capable Windows). UI controls stay excluded so buttons and arrows still navigate.
* Lightbox: Route only equirectangular media to the 360° viewer
Routing was based on the loose photo_panorama flag for videos, which is also
true for cubemap and merely-wide (aspect > 1.9) videos, so non-equirectangular
media wrongly opened, distorted, in the sphere viewer. Route strictly on the
equirectangular projection for both photos and videos. Surface the video file's
projection in the viewer DTO via Photo.MediaProjection() (the primary search row
is a poster JPEG with no projection). Add an MP4 metadata-detection test.
* Lightbox: Open tagless 2:1 360° videos in the sphere viewer
Many 360° videos carry no projection tag PhotoPrism can read, so strict
equirectangular-projection routing left them in the flat player. Fall back to
equirectangular's defining 2:1 frame for panorama-flagged videos without a
projection, via is360Equirectangular() in common/sphere.js, while cubemap and
ultrawide (~2.35:1) clips stay flat.
* Tests: Make the 360° sphere video test assert instead of skipping
Bump abema/go-mp4 to v1.7.1 (only outdated direct dependency) and tidy
go.sum, pruning stale checksums left by the XMP sidecar merge. Regenerate
the license NOTICE for the updated dependency.
Use US-English spelling in the new XMP sidecar comments and tests, and
drop a specs/ reference from internal/meta/README.md so the public package
doc has no link into the private subrepo. Regenerate dialect_mysql.go from
SQL.
Bumps the go.mod toolchain directive and the dummy OIDC fixture to
go1.26.4, clearing the GO-2026-5037/5038/5039 stdlib advisories. Updates
golang.org/x/net to v0.56.0 (NOTICE regenerated) and the fixture's
golang.org/x/sys to v0.46.0. osv-scanner --recursive returns zero
advisories and the full Go suite passes.
- Refactor `meta.css` face-marker palette to consume theme tokens (Path A):
default rect → `on-surface`; named-marker stroke → `primary`; draft →
`accent`; hover → `primary-darken-1`; handle → `primary-darken-1` fill +
`primary` stroke; Confirm pill → `primary-darken-2`; Cancel pill →
`highlight-lighten-1`; Remove pill → `remove`; Back button → `surface`.
- Retune the `lightbox` theme block to support the rebind: `primary
#F2F3F3 → #9E8FC9` (muted purple), `accent #2D2E2E → #BDAFE4` (lavender),
`surface #151515 → #181818`, `surface-bright → #1c1c1c`, `button →
#242424`, `highlight #424041 → #3c3c3c`, `remove → #cd4645`. Effectively
reverts the `surface-variant ↔ on-surface-variant` swap and re-introduces
an explicit `.v-tooltip.v-theme--lightbox` override in `lightbox.css`.
- Bump `variations.darken` to 2 so `--v-theme-primary-darken-2` resolves.
- Swap the in-template button order in `markers.vue` to Cancel-left /
Confirm-right for both the pending-add and remove-confirm popovers.
- Add inline comments to the `default.add` and updated `lightbox`
entries so each color's purpose stays documented at the source.
- Drop `eslint-plugin-prettier` (its `prettier/prettier` rule was already
`"off"`, making the plugin inert). Replace `plugin:prettier/recommended`
with a direct `eslint-config-prettier` extend; keep ESLint's own
`indent` / `quotes` / `brace-style` rules as the JS formatter.
- Tell ESLint to ignore `*.{css,scss,sass}` so Prettier owns CSS
unambiguously; wire `npm run fmt-css` / `npm run lint-css` Prettier
passes into `npm run fmt` / `npm run lint` so `make fmt-js` and
`make lint-js` cover stylesheets too.
- Drop `eslint-plugin-prettier` from the dev-container global install
list and the `frontend/tests/README.md` dependency table; regenerate
`NOTICE` files.
Removes the top-level "escape-string-regexp" dependency, which has no
direct consumer in our source. The v4 line lives on as a transitive
dep of "eslint" and "sanitize-html"; "webpack-bundle-analyzer" keeps
its nested v5 copy. Net dep-tree shape is unchanged.
Also bumps "@vue/language-server" to ^3.3.0, adds "vuln" and "tools"
phony aliases in the Makefile, and aligns the frontend "audit" target
with the root one (--no-fund --no-audit).
Signed-off-by: Michael Mayer <michael@photoprism.app>
Both were added during the Vitest framework integration (#4990) but
never referenced in any source file or test config — npm ls confirms
zero transitive consumers. PhotoPrism is Vue, so the React testing
library is not applicable; @testing-library/jest-dom (the actually
used helper) stays. The TS-paths resolver was speculatively added
when the Vite config was first stubbed and was never wired up.
README's "Known Unused" table is replaced with a short "Auditing for
Orphaned Dependencies" section so the sweep pattern (rg + npm ls)
is documented for future cleanups.
Cheerio was originally pulled in alongside easygettext@2.17.0 in May
2022 (commit d600d5faf), where easygettext declared cheerio@^1.0.0-rc.3
as a runtime dep for HTML parsing in the gettext-extract flow. When
easygettext was replaced by vue3-gettext / vue-gettext-extract in
October 2025 (commit ab9a0a969 / #1152), cheerio was overlooked and
left as a top-level dep with no consumers.
The exact pin to 1.0.0-rc.12 was set in September 2024 (commit
ab9e156c9, bundled into an unrelated UX commit) after an August 2024
bump to ^1.0.0 broke easygettext's ^1.0.0-rc.3 peer constraint. That
rationale evaporated when easygettext was removed; the lockfile
reverse-search confirms zero current consumers.
npm ls cheerio --all returns only the direct top-level entry; no
source files import it. make audit, make build-js, make test-js
(1055 passed / 13 skipped) all stay clean after removal.
Removes two stale dependencies that have no code references in any
frontend/, plus/frontend/, pro/frontend/, or portal/frontend/ tree.
postcss-url was a 2019 leftover and is the only consumer of the
unpatched minimatch <=3.1.3 ReDoS chain (GHSA-3ppc-4f35-3m26,
GHSA-7r86-cg39-jmmj, GHSA-23c5-xmqv-rm74); npm audit now reports
zero vulnerabilities.
Bumps:
- github.com/go-sql-driver/mysql v1.9.3 -> v1.10.0
- github.com/modelcontextprotocol/go-sdk v1.5.0 -> v1.6.0
- github.com/yalue/onnxruntime_go v1.28.0 -> v1.30.0
go-sdk v1.6.0 dropped the implicit default that previously rejected
cross-origin requests when StreamableHTTPOptions.CrossOriginProtection
was nil (modelcontextprotocol/go-sdk#906). internal/api/mcp.go now
sets the field explicitly so that /api/v1/mcp keeps verifying the
Origin header on the streamable HTTP transport.
onnxruntime_go v1.30.0 stays at ORT_API_VERSION 25, so the bundled
native runtime does not need to change for this bump alone.
Negotiates zstd alongside gzip via PHOTOPRISM_HTTP_COMPRESSION as a
comma-separated preference list (e.g. "zstd,gzip"); legacy "gzip",
"none", and the empty string keep behaving as before. Bypasses
Connection: Upgrade, predicate-excluded paths, HEAD (with Vary kept),
4xx/5xx, 206, 204, and 304. Weakens strong ETags on the encoding path
so caches don't reuse a compressed body for a different coding.