Commit Graph

740 Commits

Author SHA1 Message Date
neon 7a203a03d7 fix(client): add missing icon tooltips
Make icon-only controls discoverable to mouse and keyboard users with localized tooltips and accessible names.

Fixes #588
2026-09-12 09:24:32 +00:00
neon ceda7428b0 feat(reader): add dedicated audiobook playback API 2026-09-11 05:41:29 +00:00
dependabot[bot] 7ecc52ee30 chore(deps): bump the production-dependencies group with 12 updates (#1368)
Bumps the production-dependencies group with 12 updates:

| Package | From | To |
| --- | --- | --- |
| [@lucide/vue](https://github.com/lucide-icons/lucide/tree/HEAD/packages/vue) | `1.39.0` | `1.42.0` |
| [@tanstack/vue-virtual](https://github.com/TanStack/virtual/tree/HEAD/packages/vue-virtual) | `3.13.36` | `3.13.37` |
| [@tiptap/extension-link](https://github.com/ueberdosis/tiptap/tree/HEAD/packages/extension-link) | `3.31.0` | `3.31.3` |
| [@tiptap/pm](https://github.com/ueberdosis/tiptap/tree/HEAD/packages/pm) | `3.31.0` | `3.31.3` |
| [@tiptap/starter-kit](https://github.com/ueberdosis/tiptap/tree/HEAD/packages/starter-kit) | `3.31.0` | `3.31.3` |
| [@tiptap/vue-3](https://github.com/ueberdosis/tiptap/tree/HEAD/packages/vue-3) | `3.31.0` | `3.31.3` |
| [dompurify](https://github.com/cure53/DOMPurify) | `3.4.14` | `3.4.15` |
| [vue-echarts](https://github.com/ecomfe/vue-echarts) | `8.2.0` | `8.3.0` |
| [vue-router](https://github.com/vuejs/router) | `5.3.0` | `5.3.1` |
| [fastify](https://github.com/fastify/fastify) | `5.12.1` | `5.12.3` |
| [jose](https://github.com/panva/jose) | `6.2.10` | `6.2.12` |
| [undici](https://github.com/nodejs/undici) | `8.10.1` | `8.10.2` |


Updates `@lucide/vue` from 1.39.0 to 1.42.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.42.0/packages/vue)

Updates `@tanstack/vue-virtual` from 3.13.36 to 3.13.37
- [Release notes](https://github.com/TanStack/virtual/releases)
- [Changelog](https://github.com/TanStack/virtual/blob/main/packages/vue-virtual/CHANGELOG.md)
- [Commits](https://github.com/TanStack/virtual/commits/@tanstack/vue-virtual@3.13.37/packages/vue-virtual)

Updates `@tiptap/extension-link` from 3.31.0 to 3.31.3
- [Release notes](https://github.com/ueberdosis/tiptap/releases)
- [Changelog](https://github.com/ueberdosis/tiptap/blob/v3.31.3/packages/extension-link/CHANGELOG.md)
- [Commits](https://github.com/ueberdosis/tiptap/commits/v3.31.3/packages/extension-link)

Updates `@tiptap/pm` from 3.31.0 to 3.31.3
- [Release notes](https://github.com/ueberdosis/tiptap/releases)
- [Changelog](https://github.com/ueberdosis/tiptap/blob/v3.31.3/packages/pm/CHANGELOG.md)
- [Commits](https://github.com/ueberdosis/tiptap/commits/v3.31.3/packages/pm)

Updates `@tiptap/starter-kit` from 3.31.0 to 3.31.3
- [Release notes](https://github.com/ueberdosis/tiptap/releases)
- [Changelog](https://github.com/ueberdosis/tiptap/blob/v3.31.3/packages/starter-kit/CHANGELOG.md)
- [Commits](https://github.com/ueberdosis/tiptap/commits/v3.31.3/packages/starter-kit)

Updates `@tiptap/vue-3` from 3.31.0 to 3.31.3
- [Release notes](https://github.com/ueberdosis/tiptap/releases)
- [Changelog](https://github.com/ueberdosis/tiptap/blob/v3.31.3/packages/vue-3/CHANGELOG.md)
- [Commits](https://github.com/ueberdosis/tiptap/commits/v3.31.3/packages/vue-3)

Updates `dompurify` from 3.4.14 to 3.4.15
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.4.14...3.4.15)

Updates `vue-echarts` from 8.2.0 to 8.3.0
- [Release notes](https://github.com/ecomfe/vue-echarts/releases)
- [Changelog](https://github.com/ecomfe/vue-echarts/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ecomfe/vue-echarts/compare/v8.2.0...v8.3.0)

Updates `vue-router` from 5.3.0 to 5.3.1
- [Release notes](https://github.com/vuejs/router/releases)
- [Commits](https://github.com/vuejs/router/compare/v5.3.0...v5.3.1)

Updates `fastify` from 5.12.1 to 5.12.3
- [Release notes](https://github.com/fastify/fastify/releases)
- [Commits](https://github.com/fastify/fastify/commits)

Updates `jose` from 6.2.10 to 6.2.12
- [Release notes](https://github.com/panva/jose/releases)
- [Changelog](https://github.com/panva/jose/blob/main/CHANGELOG.md)
- [Commits](https://github.com/panva/jose/compare/v6.2.10...v6.2.12)

Updates `undici` from 8.10.1 to 8.10.2
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v8.10.1...v8.10.2)

---
updated-dependencies:
- dependency-name: "@lucide/vue"
  dependency-version: 1.42.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-dependencies
- dependency-name: "@tanstack/vue-virtual"
  dependency-version: 3.13.37
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: "@tiptap/extension-link"
  dependency-version: 3.31.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: "@tiptap/pm"
  dependency-version: 3.31.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: "@tiptap/starter-kit"
  dependency-version: 3.31.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: "@tiptap/vue-3"
  dependency-version: 3.31.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: dompurify
  dependency-version: 3.4.15
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: vue-echarts
  dependency-version: 8.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-dependencies
- dependency-name: vue-router
  dependency-version: 5.3.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: fastify
  dependency-version: 5.12.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: jose
  dependency-version: 6.2.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: undici
  dependency-version: 8.10.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-10 21:21:47 -06:00
SergeiAK 73ac0bb722 feat(authors): collapse series on author pages (#1271)
Reduce large author listings to one card per series while preserving book counts, scoped visibility, and row-based pagination. Compute both totals in the collapsed query so deep pages remain consistent without a second author-wide scan.

Closes #301

Co-authored-by: neon <18559658+neonsolstice@users.noreply.github.com>
2026-09-10 12:39:14 -06:00
neon b7e1e21d07 i18n(client): sync translations from Crowdin (#1307)
Keep sparse translated catalogs synchronized with reviewed Crowdin content.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-09-10 12:07:31 -06:00
neon d9ea13ba45 feat: add BookOrbit attribution requirements
Define AGPLv3 additional terms and expose attribution, source, and license details through unobtrusive About surfaces.
2026-09-10 18:03:11 +00:00
neon 5a5337bb31 chore: merge origin/main into main
Preserve both divergent commits while reconciling the local and remote histories.
2026-09-10 16:45:53 +00:00
bobberb 17aa7425f8 feat(library): per-library added_at source (imported/file_modified/file_created) (#1239)
* feat(scanner): set book added_at from earliest on-disk file mtime

A book's "date added" now reflects when its content files first landed on
disk (the earliest mtime across its content-role files) instead of the
moment BookOrbit imported it. Cover/metadata/supplement sidecars are
excluded. When no content file has a usable mtime, addedAt is left unset so
the DB defaultNow() fallback (import time) still applies. Only set at
initial book creation; re-scan/restore paths do not touch it.

* feat(library): add per-library added_at source with recompute

Add an addedAtSource setting to libraries so "date added" can follow the
book's files on disk rather than the moment the scanner happened to see
them. The setting takes imported (unchanged default), file_modified, or
file_created, guarded by a check constraint on the column.

Expose a recompute action so the chosen source can be applied to books
that are already imported. file_modified runs as a single set-based
update over the stored mtimes; file_created has to stat the files, since
birthtime is not persisted, so it batches those reads.

Leave every existing library on imported so behavior is unchanged unless
a user opts in.

* feat(library): add added_at source control to the library editor

Surface the new addedAtSource setting in the library editor as a radio
group, alongside a button that triggers the recompute for the library
being edited.

Keep the recompute out of the save path so changing the setting stays
cheap: the setting alone only affects books imported from then on, and
applying it to existing books is an explicit choice.

* i18n(library): translate added_at source strings (de/nl/pt/sl)

* fix(library): correct create payload, recompute floor and failure logging

The library creator posts its whole form, so omitting addedAtSource from
CreateLibraryDto made the global whitelist reject every create request
with a 400. Declare the field, validate it against the same source list
as the update DTO, and persist it so the initial scan uses the requested
source rather than silently falling back to imported.

Apply the scanner's usable-time floor to the mtime recompute query too.
It previously excluded only NULL, so a filesystem reporting epoch 0 would
rewrite added_at to 1970 instead of leaving the import time in place. The
floor now lives in library.constants rather than being spelled out twice.

Wrap the recompute in try/catch so a database or stat failure emits the
[fail] log the logging conventions require instead of propagating with
only a [start] line recorded.

* fix(library): gate recompute on the saved source and label the radios

The recompute button stayed enabled while the selected source differed
from the stored one. Because the request carries no source, clicking it
recomputed against the old stored value while the UI showed the new
selection. A hint already said to save first; disable the control as well
so the mismatch is not actionable.

Give the source list radiogroup semantics with aria-checked so screen
readers can tell which option is active, since selection was conveyed by
styling alone.

* test(library): assert the create DTO under the real validation options

The previous comment claimed the case exercised whitelist and
forbidNonWhitelisted, but the shared helper calls validate without them,
so it only proved @IsIn rejects an unknown value.

Drop the misleading comment and add a case that validates with the same
options main.ts gives ValidationPipe, so an undeclared addedAtSource
fails the way it would in a real request.

* docs(library): remove redundant date-added documentation

---------

Co-authored-by: Bob Bobber <user@example.com>
Co-authored-by: neon <18559658+neonsolstice@users.noreply.github.com>
2026-09-10 10:43:47 -06:00
neon 72871fad65 fix(client): preserve synced reading calendar dates
Treat exact UTC-midnight lifecycle projections as calendar dates while preserving local conversion for real timestamps.

Fixes #1322
2026-09-10 15:35:06 +00:00
neon 33c7260f18 fix(auth): explain untrusted OIDC certificate failures
Classify private trust-chain failures with a stable error code and direct administrators to a mounted CA bundle without weakening TLS verification.

Fixes #1346
2026-09-10 11:47:56 +00:00
neon e514be151a fix(library): ignore current library during folder prescan
Prevent an edited library from treating its own persisted folders as conflicts while preserving overlap warnings for other libraries.

Fixes #1340
2026-09-10 11:02:32 +00:00
neon 6c65c393b5 fix(reader): honor line spacing over publisher styles
Ensure explicit reader spacing overrides higher-specificity EPUB typography and cover the cascade with a regression test.

Fixes #1302
2026-09-09 03:20:08 +00:00
neon 7978ab0230 test(settings): cover fill-crop preference sync payload
Guard against the display preference mismatch reported in #1290 by checking author fields in cover-mode saves and verifying server acceptance of the complete payload.

Ref #1290
2026-09-09 03:12:16 +00:00
neon b9609b198e fix(annotations): preserve source highlight timestamps
Use KOReader highlight times for annotation history while retaining ingestion times for diagnostics. Export all stored location representations and backfill existing rows during sync.

Fixes #1300
2026-09-08 16:52:36 +00:00
neon cf40058cb6 fix(users): select exact content restriction matches
Prioritize exact genre and tag results within bounded catalog searches. Resolve Enter presses against existing IDs and ignore stale lookup responses.

Fixes #1295
2026-09-08 15:43:27 +00:00
neon 5d0c2e6e14 i18n(client): sync translations from Crowdin (#1236)
Keep sparse translated catalogs synchronized with reviewed Crowdin content.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-09-06 23:38:35 -06:00
dependabot[bot] 3833f85bad chore(deps): bump the production-dependencies group across 1 directory with 10 updates (#1289)
Bumps the production-dependencies group with 10 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [@lucide/vue](https://github.com/lucide-icons/lucide/tree/HEAD/packages/vue) | `1.35.0` | `1.39.0` |
| [@tiptap/extension-link](https://github.com/ueberdosis/tiptap/tree/HEAD/packages/extension-link) | `3.30.5` | `3.31.0` |
| [@tiptap/pm](https://github.com/ueberdosis/tiptap/tree/HEAD/packages/pm) | `3.30.5` | `3.31.0` |
| [@tiptap/starter-kit](https://github.com/ueberdosis/tiptap/tree/HEAD/packages/starter-kit) | `3.30.5` | `3.31.0` |
| [@tiptap/vue-3](https://github.com/ueberdosis/tiptap/tree/HEAD/packages/vue-3) | `3.30.5` | `3.31.0` |
| [vue-echarts](https://github.com/ecomfe/vue-echarts) | `8.1.0` | `8.2.0` |
| [mysql2](https://github.com/sidorares/node-mysql2) | `3.24.2` | `3.24.3` |
| [nodemailer](https://github.com/nodemailer/nodemailer) | `9.0.6` | `9.1.1` |
| [undici](https://github.com/nodejs/undici) | `8.10.0` | `8.10.1` |
| [zod](https://github.com/colinhacks/zod) | `4.4.3` | `4.5.4` |



Updates `@lucide/vue` from 1.35.0 to 1.39.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.39.0/packages/vue)

Updates `@tiptap/extension-link` from 3.30.5 to 3.31.0
- [Release notes](https://github.com/ueberdosis/tiptap/releases)
- [Changelog](https://github.com/ueberdosis/tiptap/blob/v3.31.0/packages/extension-link/CHANGELOG.md)
- [Commits](https://github.com/ueberdosis/tiptap/commits/v3.31.0/packages/extension-link)

Updates `@tiptap/pm` from 3.30.5 to 3.31.0
- [Release notes](https://github.com/ueberdosis/tiptap/releases)
- [Changelog](https://github.com/ueberdosis/tiptap/blob/v3.31.0/packages/pm/CHANGELOG.md)
- [Commits](https://github.com/ueberdosis/tiptap/commits/v3.31.0/packages/pm)

Updates `@tiptap/starter-kit` from 3.30.5 to 3.31.0
- [Release notes](https://github.com/ueberdosis/tiptap/releases)
- [Changelog](https://github.com/ueberdosis/tiptap/blob/v3.31.0/packages/starter-kit/CHANGELOG.md)
- [Commits](https://github.com/ueberdosis/tiptap/commits/v3.31.0/packages/starter-kit)

Updates `@tiptap/vue-3` from 3.30.5 to 3.31.0
- [Release notes](https://github.com/ueberdosis/tiptap/releases)
- [Changelog](https://github.com/ueberdosis/tiptap/blob/v3.31.0/packages/vue-3/CHANGELOG.md)
- [Commits](https://github.com/ueberdosis/tiptap/commits/v3.31.0/packages/vue-3)

Updates `vue-echarts` from 8.1.0 to 8.2.0
- [Release notes](https://github.com/ecomfe/vue-echarts/releases)
- [Changelog](https://github.com/ecomfe/vue-echarts/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ecomfe/vue-echarts/compare/v8.1.0...v8.2.0)

Updates `mysql2` from 3.24.2 to 3.24.3
- [Release notes](https://github.com/sidorares/node-mysql2/releases)
- [Changelog](https://github.com/sidorares/node-mysql2/blob/master/Changelog.md)
- [Commits](https://github.com/sidorares/node-mysql2/compare/v3.24.2...v3.24.3)

Updates `nodemailer` from 9.0.6 to 9.1.1
- [Release notes](https://github.com/nodemailer/nodemailer/releases)
- [Changelog](https://github.com/nodemailer/nodemailer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodemailer/nodemailer/compare/v9.0.6...v9.1.1)

Updates `undici` from 8.10.0 to 8.10.1
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v8.10.0...v8.10.1)

Updates `zod` from 4.4.3 to 4.5.4
- [Release notes](https://github.com/colinhacks/zod/releases)
- [Commits](https://github.com/colinhacks/zod/compare/v4.4.3...v4.5.4)

---
updated-dependencies:
- dependency-name: "@lucide/vue"
  dependency-version: 1.39.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-dependencies
- dependency-name: "@tiptap/extension-link"
  dependency-version: 3.31.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-dependencies
- dependency-name: "@tiptap/pm"
  dependency-version: 3.31.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-dependencies
- dependency-name: "@tiptap/starter-kit"
  dependency-version: 3.31.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-dependencies
- dependency-name: "@tiptap/vue-3"
  dependency-version: 3.31.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-dependencies
- dependency-name: vue-echarts
  dependency-version: 8.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-dependencies
- dependency-name: mysql2
  dependency-version: 3.24.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: nodemailer
  dependency-version: 9.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-dependencies
- dependency-name: undici
  dependency-version: 8.10.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: zod
  dependency-version: 4.5.4
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: neon <18559658+neonsolstice@users.noreply.github.com>
2026-09-06 23:38:21 -06:00
neon 028d4287b4 fix(client): stabilize book detail layout across screen sizes
Keep cover actions and discovery content adjacent to their related sections, and scale the synopsis preview for taller viewports.

Fixes #1259
2026-09-06 15:39:31 +00:00
neon d8f87d8dd1 fix(client): keep cover controls within their column
Size the cover editor from its assigned container so narrow metadata grids stack controls below the artwork without overlap.

Fixes #1280
2026-09-05 10:05:58 +00:00
neon 978ef8ac2f fix(client): stop compact detail covers shrinking
Keep the observer-derived width cap scoped to the fixed-height wide layout so compact covers cannot feed their own height back into width.

Fixes #1279
2026-09-05 10:04:39 +00:00
neon e63c4b3685 fix(client): keep reading activity text inside card
Preserve the card's intrinsic minimum height when the detail column needs to scroll so empty-state copy remains within its border.

Fixes #1262
2026-09-05 09:30:20 +00:00
neon f5bb88f996 fix(client): restore titles for cached views
Restore the resolved entity title whenever a kept-alive view becomes active.
Prevent inactive cached views from replacing the current page title.

Fixes #1261
2026-09-05 09:15:16 +00:00
neon 9165dbed1d feat(auth): add SSO-only authentication mode
Require an enabled OIDC-linked superuser before disabling password flows. Track session authentication methods and fail closed across the API, web client, WebSockets, and administrative mutations.

Closes #1002
2026-09-02 05:04:18 +00:00
neon e3779c1d7e feat(metadata): restrict autofill to stored provider ids
Prevent automatic metadata refreshes from searching alternate identities when a book already has trusted provider IDs. Preserve discovery and manual search behavior, and avoid dirtying descriptions on empty refreshes.

Closes #1222
2026-09-01 20:55:36 +00:00
neon eb60744494 feat(reader): improve PDF sidebar navigation
Keep the active PDF outline location visible while providing responsive navigation layouts and focused panels across screen sizes.

Closes #1235
2026-09-01 18:34:05 +00:00
wmTJc9IK0Q 04ec495c25 feat(reader): add PDF highlights and annotations on web only (#1213)
* feat(reader): add PDF highlights and annotations

Persist and render PDF highlights through the same annotation system as
EPUB. The annotation_positions table already supported a 'pdf' format, so
this wires the web create path, response, and reader UI to it.

Backend:
- create-annotation DTO accepts a pdf position (page + segment rects) as an
  alternative to a cfi; exactly one is required
- repository createPdf() persists a format='pdf' position (geometry in pos0,
  pageno in extras); selectWithCfi exposes the pdf geometry and status
- response DTO parses the pdf position and derives positionStatus

Frontend (pdf-v4 reader):
- usePdfAnnotations REST store and usePdfHighlights orchestration render
  persisted highlights via the EmbedPDF annotation plugin (autoCommit off,
  DB stays source of truth)
- selection popup (colour/style/note/copy/delete), note dialog, and a
  Highlights sidebar tab with search/colour/notes filters, navigate, delete
- NoteDialog relocated to reader/shared for reuse by both readers

Shared types gain AnnotationRect/AnnotationPdfPosition and an optional pdf
field on AnnotationItem.

* fix(reader): preserve input on failed PDF annotation save; convert mixed PDF+CFI for KOReader

- usePdfHighlights: createFromSelection/restyleExisting now return success;
  applyHighlight and saveNote only clear the selection, dismiss the popup, and
  close the note dialog on success. On failure the mark, popup, and typed note
  are preserved so the user can retry without losing input.
- koreader annotation exchange: the PDF push-down guard now skips only PDF-only
  annotations (no EPUB anchor). A mixed PDF+CFI annotation still converts its CFI
  to xpointer instead of being dropped.
- Tests for both paths.

* fix(reader): label PDF selection buttons and dedupe multi-page highlight retries

- PdfSelectionPopup: add aria-labels to the copy, highlight, note, and delete
  icon-only buttons so screen readers can identify them.
- usePdfHighlights: createFromSelection keeps only the pages that failed, so a
  retry after a partial multi-page failure never duplicates already-saved pages.
- Test for the multi-page partial-failure retry path.

* fix(reader): harden PDF annotation store, validation, and create logging

- usePdfAnnotations: catch rejected api() calls (session expiry / network) so
  load() sets loadError and mutations return null/false instead of rejecting.
- create-annotation DTO: require positive rect width/height so degenerate PDF
  geometry is rejected; tests for zero/negative dimensions.
- annotation.service: add [annotation.create] start/end/fail lifecycle logs with
  IDs, durationMs, and sanitized error for the multi-step create.

* test(reader): cover PDF annotations in the hub and add missing docstrings

Adds a real-DB e2e proving a PDF highlight persists as a pdf position and surfaces in the library-wide Annotations hub with the exact fields the page deep link needs (jumpFileFormat=pdf, cfi=null, pageno). Adds a hub-service unit test for the pdf row mapping. Documents the PDF render helpers, the annotation deep-link builder, and the createPdf repository method.

* fix(annotations): make PDF highlights reliable across reloads

Reconcile persisted highlights after EmbedPDF finishes loading its annotation state. Keep file-scoped pagination bounded and prevent PDF-only positions from starving device sync.

Ref #1195

* fix(annotations): keep pdf annotations stable during reload

Use authenticated native pagination fetches and discard responses that overlap successful mutations. Align shared dialog styling and annotation tests with project conventions.

Ref #1195

---------

Co-authored-by: neon <18559658+neonsolstice@users.noreply.github.com>
2026-09-01 09:16:01 -06:00
neon 2912429ca6 feat(reader): add epub typography controls
Preserve publisher typography by default while allowing explicit spacing and indentation overrides across reader clients.

Ref #1206
2026-09-01 00:15:28 +00:00
neon 53cfe16b04 feat(reader): add epub paragraph spacing
Preserve publisher spacing at the minimum while allowing synchronized
format defaults and per-book overrides.

Closes #1206
2026-08-31 23:04:55 +00:00
neon 7057d350fd feat(reader): show book titles in reader tabs
Use library metadata so browser history and time tracking identify the book being read.

Closes #1147
2026-08-31 22:52:28 +00:00
neon 6583fd696e i18n(client): sync translations from Crowdin (#1225)
Keep sparse translated catalogs synchronized with reviewed Crowdin content.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-31 11:07:55 -06:00
neon fc6e6f03d5 feat(book-requests): add automated request fulfillment
Let users request books, route approvals, search configured sources, and import fulfilled releases through the Book Dock. Include scoped permissions, automation, download-client integrations, plugin support, requester visibility, and one consolidated schema migration.

Closes #248
Ref #1115
2026-08-31 16:52:43 +00:00
neon 0f5429131a feat(smart-scope): filter by community review count
Allow provider-aware review count criteria so rating thresholds can be qualified by community review volume.

Closes #1041
2026-08-31 04:54:00 +00:00
neon 79b02e5b35 test(books): cover same-day reading completion
Protect equal manual start and finish dates through the client and status API.

Closes #1097
2026-08-31 02:15:34 +00:00
neon cc1b767264 fix: align Book Dock ready filter with filing readiness
Use the destination-complete predicate for the Ready chip and select-all operations so counts and filtered results remain consistent.

Fixes #1215
2026-08-30 17:21:35 +00:00
neon 9391555859 fix(books): fully expand book synopsis
Keep expanded synopsis content in the existing page or column flow so touch users do not encounter an undiscoverable nested scroll area. Expose the toggle state to assistive technology.

Fixes #1202
2026-08-30 17:00:33 +00:00
neon 26503bc9e6 fix(books): open personal review editor from summary
Reveal the collapsible review panel before entering edit mode so the summary action works on every responsive layout.

Fixes #1211
2026-08-30 16:04:52 +00:00
neon 3196454944 fix(settings): persist complete display preferences
Accept the author display fields already emitted by the client and include them in automatic account sync. Keep older payloads compatible with defaults and cover the client-server contract with regression tests.

Fixes #1209
2026-08-30 05:59:19 +00:00
neon 3a0f8915ec i18n(client): sync translations from Crowdin (#1191)
Keep sparse translated catalogs synchronized with reviewed Crowdin content.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-29 23:48:18 -06:00
neon 3ea6063f31 fix(users): add safe superuser management
Expose promotion and demotion to existing superusers while keeping shared and self targets blocked. Serialize role lifecycle changes, preserve one active superuser, and invalidate stale credentials.

Closes #1208
2026-08-30 05:44:37 +00:00
neon 3561d5ddd6 fix(client): keep book detail layouts responsive
Size book detail layouts from usable pane width so sidebar width and browser zoom do not force inappropriate compact layouts. Keep metadata save actions reachable while secondary controls overflow safely.

Fixes #1192
2026-08-30 04:20:12 +00:00
neon f8ce9f58f1 i18n(client): sync translations from Crowdin (#1185)
Keep sparse translated catalogs synchronized with reviewed Crowdin content.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-28 12:26:31 -06:00
neon 5a668b0015 feat(collections): add public collections with shared read access
Add an isPublic flag to collections allowing users to share collections across the instance. Public collections are readable by all authenticated users while write, edit, reorder, and delete operations remain restricted to the owner.
2026-08-28 16:13:28 +00:00
neon 1dd39bf0eb feat(books): add primary file size filter rule
Add fileSize as a filterable rule field resolved against the book's primary file size in bytes. In the filter builder UI, allow operators to input sizes in megabytes with automatic serialization to bytes for queries.
2026-08-28 15:32:28 +00:00
neon 3b44fa5d7e build(deps): update server and client dependencies
Keep both workspaces current within their existing major versions and normalize virtual row keys for the updated type definitions.
2026-08-28 14:44:06 +00:00
neon a51122237d feat(library): rebuild the bulk rename tool
Redesign the bulk rename UI with change-type grouping, inline character diffs, and tree previews. Add two-mode selection for large libraries, virtualize the queue, and move search to the server. Optimize execution by pausing the library watcher instead of tearing it down, and improve SSE progress reporting and run error handling.

Share one path-resolution routine between the preview and the rename so the preview cannot offer a rename the executor refuses: multi-track audiobooks whose parts collapse onto one filename, and renumbering that would overwrite the book's own files.
2026-08-28 04:11:06 +00:00
neon 21a7f897b9 feat(client): rebuild duplicate cluster review in entity manager
Replace the inline cluster cards with a dedicated side-by-side duplicate comparison interface, cluster navigation list, threshold selector menu, and review controls. Introduce the useDuplicateReview composable to manage active review state and merge decisions across clusters.
2026-08-27 23:21:08 +00:00
neon 4bd90b865c feat(client): modernize the entity manager browse interface
Split the monolithic browse table into focused components for the toolbar, data grid, sortable headers, and pager. Add support for compact and comfortable row densities, improve pagination navigation, and refine the entity type selector layout.
2026-08-27 22:45:31 +00:00
neon ddb296cade fix(books): show read status on the book detail discovery shelf
The series, author and similar endpoints never selected a read status, so
every cover in the detail shelf rendered bare. Attach the requesting user's
status in one bulk lookup per lane, and draw the badge in BookCarousel using
the same icons and placement as the library grid, plus an sr-only label.
BookRepository has no user in scope, so it now returns UnscopedBookRecommendation
and the type system forces the status on where the user exists.

Also adds the untracked scanner overlap repro for issue 1094.

Closes #1163
2026-08-27 21:56:17 +00:00
neon 58c3ef8b95 feat(books): rebuild the Files tab around the file list
Replace the tree-plus-inspector split with a hero strip, one Files card and a
rail holding only the selected file and a write-back summary. The nine stacked
bands stated a file's format five times and its role three, and the 28-row
metadata dump was the largest block on a tab about files; that table now lives
behind a link to Edit Metadata. The tab reflows on its own width via container
queries, so a collapsed sidebar and a narrow window behave alike, and the rail
becomes a bottom sheet on a phone.
2026-08-27 20:57:09 +00:00
neon 9652e985d7 i18n(client): sync translations from Crowdin (#1169)
Keep sparse translated catalogs synchronized with reviewed Crowdin content.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-27 13:05:53 -06:00