Commit Graph

476 Commits

Author SHA1 Message Date
neon 3f32d8e828 fix(docker): fail fast on CPUs that lack SSE4.2 support (#118)
On old hardware (e.g. AMD Turion/Phenom, Intel Core 2), sharp's musl binary
crashes with SIGILL during NestJS module init. Combined with bufferLogs: true
and restart: unless-stopped, this produces a silent infinite restart loop -
only the migration success message is ever visible.

Add check_cpu_sse42 to entrypoint.sh: greps /proc/cpuinfo for sse4_2, exits
with a clear error if absent, no-op when /proc/cpuinfo is unavailable. Also
add a System Requirements section to README documenting the SSE4.2 minimum.

Closes #116
2026-05-27 14:27:12 -06:00
neon 419f634e5c feat(auth): add opt-in private oidc issuer override (#113)
Allow self-hosted deployments to explicitly trust private/local OIDC issuer hosts while keeping production defaults locked down.

Keep SSRF protections unchanged outside OIDC issuer and discovery validation paths.

Closes #107
2026-05-27 14:26:57 -06:00
neon 3a72ece26d fix(settings): gate integration tabs by integration permissions
Prevent unauthorized users from seeing integrations they cannot use and keep settings routing consistent with API authorization behavior. Add hardcover_sync and enforce it server-side so tab visibility and endpoint access stay aligned.
2026-05-26 19:52:32 +00:00
neon 78b99d0b78 fix(settings): accept socket postgres urls in DATABASE_URL validation
Validate DATABASE_URL with pg's connection-string parser so unix-socket DSNs with empty authority hosts pass while malformed/non-postgres values are rejected.

Closes #106
2026-05-26 01:48:24 +00:00
neon 39bb872f7c fix(client): show actual achievement description when all tiers are complete instead of redundant text 2026-05-25 05:40:51 +00:00
neon 1be2abe36a fix(scanner): clamp precision-unsafe inodes to avoid lossy matching (#90)
* fix(scanner): clamp precision-unsafe inodes to avoid lossy matching

Clamp inode values above Number.MAX_SAFE_INTEGER to 0 before scanner, upload,
and file-event matching paths consume them.

Add regression tests for Unraid-style inodes so precision-unsafe values
cannot collapse file detection during scans.

Lower server coverage thresholds from 85 to 80 as requested for this branch.

Closes #84

* fix(scanner): reuse existing book for same-library folder renames

Keep the original book id when a folder path changes so scan does not create a duplicate entry with no files. Use inode first and hash fallback for precision-unsafe inode values while keeping book_per_file behavior unchanged.
2026-05-24 23:24:41 -06:00
neon 1479989f74 feat(settings): add cross-platform path sanitization option
Book titles and author names can contain characters that are invalid on Windows,
SMB/NFS shares, or cloud sync platforms (e.g., `:`, `?`, `*`, `"`). Without
sanitization these characters appear verbatim in generated file and folder names,
which causes failures on Windows filesystems, broken NFS/SMB mounts, and sync issues.

Add a toggleable app setting that, when enabled, sanitizes illegal filesystem
characters in all pattern-resolved paths (upload, rename, book-dock finalize, and
download). Each token value is sanitized before substitution: invalid chars are
replaced with `_`, trailing dots and spaces are stripped, and Windows reserved names
(CON, AUX, NUL, COM1-COM9, LPT1-LPT9) get a suffix to avoid conflicts. The setting
defaults to off to preserve existing behavior.

Closes #103
2026-05-25 05:17:17 +00:00
neon c481304e0d fix(settings): clarify koreader sync accuracy expectations
document cross-reader sync limitations in the KOReader settings panel.
set clear expectations for direction-specific accuracy so users understand why resume location can differ between KOReader and the web reader.
2026-05-25 04:23:53 +00:00
neon 7fe5b9133a fix(cover): prevent series badge clicks from opening reader
treat the series-position badge as a non-open interactive target and
exclude those clicks from card-open handling.

add regression tests for hover hit-testing and badge-click behavior.

type vitest mock functions in the series detail spec to satisfy
the repository pre-push lint checks.

Closes #99
2026-05-24 16:31:44 +00:00
neon 989c16313f fix(series): open add-to-collection sheet from book actions
Handle add-to-collection actions in the series detail view so the collection sheet opens with the selected book id. Add regression tests for grid and table actions plus sheet close state reset.

Closes #102
2026-05-24 16:13:25 +00:00
neon afeff2566d refactor(stats): extract caching logic to StatsCache
Extracts the in-memory caching logic previously duplicated across
UserStatisticsService and StatisticsService into a new shared
StatsCache class. This standardizes cache keys, improves invalidation
by scope (such as userId), and makes the dashboard widget and
statistics caching more robust.
2026-05-23 21:48:01 +00:00
neon de9d3a9d86 fix(book): resolve series collapse query issues
The previous SQL query used a LATERAL join and complex aggregations that caused series collapsing to fail. This refactors the query to use a unified base_rows CTE and explicit window functions for fetching series covers, ensuring that series are correctly grouped and displayed.

Closes #87
2026-05-23 04:51:17 +00:00
neon d43b97dc85 fix(server): check for app updates dynamically with 10-minute cache
The backend previously only checked for new releases from GitHub
during application bootstrap. If the server stayed up for a long time,
the UI would never be notified of new releases.

The AppInfoService now re-checks GitHub when the frontend requests
app info, using a 10-minute cache TTL to balance freshness with
API rate limits.
2026-05-23 02:39:53 +00:00
neon 738a8709c4 ci: fetch github usernames via API for release notes
The previous hardcoded AUTHOR_MAP was incomplete and caused missing authors
in the generated release notes. The config now attempts to fetch actual
GitHub usernames associated with commit SHAs using the GitHub API,
falling back to local git log author names if the API request fails.
2026-05-23 02:37:22 +00:00
neon f651039535 build: remove legacy release config and fix hash-based attribution
Use a single semantic-release config to avoid diverging behavior, and update the release notes context logic to map authors with full commit hashes and stable issue URLs.
2026-05-23 01:49:45 +00:00
neon 3e837c4fb9 fix(opds): stable sort tiebreaker, unique feed IDs, remove dead code (#94)
Add books.id ASC tiebreaker to all 7 OPDS_SORT_MAP sort orders so
pagination is deterministic even when books share identical addedAt
timestamps (e.g. after a bulk library scan). Without a tiebreaker,
PostgreSQL returns equal-valued rows in an undefined order, causing
books to appear on multiple pages or not at all.

Make catalog feed IDs context-specific: filtered views (by library,
collection, smartScope, author, series, or search query) now produce
distinct URNs instead of all sharing urn:bookorbit:catalog. This
aligns with the OPDS spec requirement that <id> uniquely identify
the logical feed.

Remove the dead idQuery.$dynamic() block from paginatedBookQuery
that was built and conditionally mutated but never awaited.

Closes #93
2026-05-22 19:11:54 -06:00
neon 45135fa157 feat(collections): allow removing books from collections in details
support toggling membership in the collection sheet so users can remove books without leaving the details and quick-view flow.

cover add/remove paths plus access edge cases with frontend and backend tests.

Closes #85
2026-05-23 00:15:17 +00:00
neon 1f77d11701 fix(email): fix recipient loading when send dialog opens (#92)
Run recipient fetch on initial open state so dialogs mounted with open=true load data immediately. Add dialog and recipient composable unit tests to lock in the regression behavior and error paths.

Closes #89
2026-05-22 16:48:49 -06:00
neon 513dfa21a7 feat(client): add docs and github star actions to app header
improve header discoverability with quick access to documentation and
community support actions. keep the github prompt in a dismissible
popover to avoid adding noise to the main navigation.
2026-05-22 17:10:22 +00:00
Chris Mansell 956a7a5e9a feat(users): add per-user tag/genre content restrictions (#83)
* feat(users): tag/genre content filters for per-user access control

Add granular per-user content filtering by tags and genres, allowing admins to set include/exclude filter rules that are enforced across all book-serving surfaces.

- Implement DB schema, repository, and SQL helpers for content filters

- Wire enforcement across core domains (Books, Collections, OPDS, Kobo sync)

- Add REST endpoints for managing filter rules

- Redesign UserFormDrawer to support configuring content restrictions

- Add read-only Restrictions tab in account settings and user list badges

- Add comprehensive unit tests and fix existing fixtures

Closes #68

* test(client): update account tab expectations for restrictions
2026-05-22 11:01:11 -06:00
neon a3a4edfc0b fix: align tiered achievement copy with current tiers
Use each group's displayed tier description instead of the next tier description so titles and copy stay consistent across all tiered cards. Refresh achievement seed names for books, pages, hours, long-book, and library ladders, and adjust books_finished_3 to a 35-book threshold to match the new progression.
2026-05-22 07:07:40 +00:00
neon 7f488ac673 feat(authors): add manual author image upload and removal
Enable author image upload and removal from the author detail edit panel.
Persist author photos with generated thumbnails and enforce server-side validation plus access-scoped API routes.
Cover the new controller and service behavior with author module tests.
2026-05-22 06:04:07 +00:00
dependabot[bot] b141af2bf3 chore(deps): bump js-cookie from 3.0.5 to 3.0.7 (#82)
Bumps [js-cookie](https://github.com/js-cookie/js-cookie) from 3.0.5 to 3.0.7.
- [Release notes](https://github.com/js-cookie/js-cookie/releases)
- [Commits](https://github.com/js-cookie/js-cookie/compare/v3.0.5...v3.0.7)

---
updated-dependencies:
- dependency-name: js-cookie
  dependency-version: 3.0.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-21 22:56:45 -06:00
neon 7f0e63d4a8 fix(authors): gate enrichment matches by name confidence
Prevent enrichment from applying unrelated author records when provider search returns low-signal names.
Rank multiple candidates and require strong name compatibility before accepting a match.
Treat lookup failures as provider failures instead of silently falling back to raw search hits.
2026-05-22 04:52:16 +00:00
dependabot[bot] 81a1691939 chore(deps): bump the production-dependencies group with 12 updates (#80)
Bumps the production-dependencies group with 12 updates:

| Package | From | To |
| --- | --- | --- |
| [@embedpdf/vue-pdf-viewer](https://github.com/embedpdf/embed-pdf-viewer/tree/HEAD/viewers/vue) | `2.14.2` | `2.14.3` |
| [@tanstack/vue-virtual](https://github.com/TanStack/virtual/tree/HEAD/packages/vue-virtual) | `3.13.24` | `3.13.25` |
| [@types/howler](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/howler) | `2.2.12` | `2.2.13` |
| [dompurify](https://github.com/cure53/DOMPurify) | `3.4.3` | `3.4.5` |
| [echarts](https://github.com/apache/echarts) | `6.0.0` | `6.1.0` |
| [vue-virtual-scroller](https://github.com/Akryum/vue-virtual-scroller) | `3.0.3` | `3.0.4` |
| [@nestjs/common](https://github.com/nestjs/nest/tree/HEAD/packages/common) | `11.1.21` | `11.1.23` |
| [@nestjs/core](https://github.com/nestjs/nest/tree/HEAD/packages/core) | `11.1.21` | `11.1.23` |
| [@nestjs/platform-fastify](https://github.com/nestjs/nest/tree/HEAD/packages/platform-fastify) | `11.1.21` | `11.1.23` |
| [@nestjs/platform-socket.io](https://github.com/nestjs/nest/tree/HEAD/packages/platform-socket.io) | `11.1.21` | `11.1.23` |
| [@nestjs/websockets](https://github.com/nestjs/nest/tree/HEAD/packages/websockets) | `11.1.21` | `11.1.23` |
| [pg](https://github.com/brianc/node-postgres/tree/HEAD/packages/pg) | `8.20.0` | `8.21.0` |


Updates `@embedpdf/vue-pdf-viewer` from 2.14.2 to 2.14.3
- [Release notes](https://github.com/embedpdf/embed-pdf-viewer/releases)
- [Changelog](https://github.com/embedpdf/embed-pdf-viewer/blob/main/viewers/vue/CHANGELOG.md)
- [Commits](https://github.com/embedpdf/embed-pdf-viewer/commits/v2.14.3/viewers/vue)

Updates `@tanstack/vue-virtual` from 3.13.24 to 3.13.25
- [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.25/packages/vue-virtual)

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

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

Updates `echarts` from 6.0.0 to 6.1.0
- [Release notes](https://github.com/apache/echarts/releases)
- [Commits](https://github.com/apache/echarts/compare/6.0.0...6.1.0)

Updates `vue-virtual-scroller` from 3.0.3 to 3.0.4
- [Release notes](https://github.com/Akryum/vue-virtual-scroller/releases)
- [Changelog](https://github.com/Akryum/vue-virtual-scroller/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Akryum/vue-virtual-scroller/compare/v3.0.3...v3.0.4)

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

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

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

Updates `@nestjs/platform-socket.io` from 11.1.21 to 11.1.23
- [Release notes](https://github.com/nestjs/nest/releases)
- [Commits](https://github.com/nestjs/nest/commits/v11.1.23/packages/platform-socket.io)

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

Updates `pg` from 8.20.0 to 8.21.0
- [Changelog](https://github.com/brianc/node-postgres/blob/master/CHANGELOG.md)
- [Commits](https://github.com/brianc/node-postgres/commits/pg@8.21.0/packages/pg)

---
updated-dependencies:
- dependency-name: "@embedpdf/vue-pdf-viewer"
  dependency-version: 2.14.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: "@tanstack/vue-virtual"
  dependency-version: 3.13.25
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: "@types/howler"
  dependency-version: 2.2.13
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: dompurify
  dependency-version: 3.4.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: echarts
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-dependencies
- dependency-name: vue-virtual-scroller
  dependency-version: 3.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: "@nestjs/common"
  dependency-version: 11.1.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: "@nestjs/core"
  dependency-version: 11.1.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: "@nestjs/platform-fastify"
  dependency-version: 11.1.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: "@nestjs/platform-socket.io"
  dependency-version: 11.1.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: "@nestjs/websockets"
  dependency-version: 11.1.23
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: pg
  dependency-version: 8.21.0
  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-05-21 22:41:37 -06:00
dependabot[bot] ca1f123785 chore(deps): bump the github-actions group with 2 updates (#79)
Bumps the github-actions group with 2 updates: [docker/build-push-action](https://github.com/docker/build-push-action) and [actions/stale](https://github.com/actions/stale).


Updates `docker/build-push-action` from 7.1.0 to 7.2.0
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/bcafcacb16a39f128d818304e6c9c0c18556b85f...f9f3042f7e2789586610d6e8b85c8f03e5195baf)

Updates `actions/stale` from 10.2.0 to 10.3.0
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/b5d41d4e1d5dceea10e7104786b73624c18a190f...eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 7.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: actions/stale
  dependency-version: 10.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-21 22:30:37 -06:00
neon 53736a95b5 fix(server): deduplicate migration user-state upsert batches (#81)
* fix(server): deduplicate migration user-state upsert batches

Prevent migration failures when source data contains duplicate user-state rows for the same target keys. Keep the latest row per upsert key and prefer richer reading progress signals on timestamp ties, then cover the behavior with focused unit and e2e tests.

Closes #71

* ci: raise commitlint body line limit to 500 chars

Allow longer commit body lines so convention checks do not fail on detailed but still concise commit explanations in this repository.
2026-05-21 22:30:13 -06:00
adams79 aeedecc5ce fix(opds): search catalog by author, series, and ISBN (#78) 2026-05-21 20:11:55 -06:00
neon 302300e053 feat(settings): redesign library settings card with status badges
Introduce status badges for library capabilities such as file write, file rename, and watching. Add cronstrue to format the auto-scan cron expression into human-readable text. Increase the layout max-width for the library settings page to accommodate the new cards.
2026-05-21 18:03:40 +00:00
neon 75d9161962 feat(library): rename files on metadata update (#76)
Add file rename feature that renames physical book files on disk when
naming-relevant metadata fields are updated (title, authors, series,
seriesIndex, publishedYear).

Closes #69
2026-05-21 11:15:22 -06:00
neon b50c820804 feat(achievements): move achievements to dedicated /achievements route
Extract the achievements page out of /statistics?tab=achievements into its
own /achievements route. Add a page header with a Trophy icon and subtitle
to match the app visual style (consistent with BookDockView pattern).

Add a beforeEnter redirect on the statistics route so ?tab=achievements links
continue to work. Update AppHeader navigation and active state checks to use
the new route name. Remove the achievements tab conditional from StatisticsPage.
2026-05-20 21:45:17 -06:00
neon 40bdd661a5 feat(books): add started/finished reading date support
Add per-user startedAt and finishedAt filtering, sorting, and timezone-safe date normalization.

Surface compact read-date editing in Details and return canonical date-only status payloads.

Preserve manual dates across status updates and reject null status patches.

Closes #66
2026-05-21 03:39:13 +00:00
neon 9e891f609f feat(client): add configurable spine and shadow effects for book covers (#65)
Unify cover rendering with a reusable surface wrapper so cover styling stays consistent across grid, list, table, and dashboard views.
Expose spine overlay and shadow strength controls in appearance settings and fit spine overlays to cropped cover frames to avoid visual bleed.
Add tests for the cover surface component and aspect-ratio fitting helpers.

closes #62
2026-05-20 14:38:52 -06:00
neon 0b9027c275 feat(book-dock): expose Book Dock folder as a configurable drop zone (#64)
* feat(docker): expose Book Dock folder as a configurable drop zone

Add support for an external book drop folder that users can bind-mount
into the container via the BOOK_DROP_HOST_PATH env var. Files copied or
moved into this folder are automatically picked up and ingested by the
existing Book Dock file watcher.

- docker-compose.yml: add BOOK_DROP_HOST_PATH volume override so the
  book-dock path is separately bind-mountable
- .env.example: document BOOK_DROP_HOST_PATH with an example NAS path
- AppInfoResponse: add bookDockPath so the UI can show the
  container-internal path admins need to bind-mount
- AppInfoService: compute and return bookDockPath from storage config
- BookDockSettings: display drop folder path with BOOK_DROP_HOST_PATH hint
- useAppInfo: expose bookDockPath ref from the app-info API response
- README: document the optional drop folder in the quickstart section

When BOOK_DROP_HOST_PATH is unset, the volume defaults to
./data/app/book-dock, preserving full backward compatibility.
No watcher code changes required - the watcher already watches
the correct container-internal path.

Closes #58

* fix(book-dock): resolve symlink paths so rescan stays idempotent

BookDockWatcherService and BookDockIngestService were building
bookDockPath with path.join(), which preserves symlinks. `@parcel/watcher`
resolves symlinks internally when reporting events (using realpath), so the
absolutePath values stored by watcher events and the paths computed by
walkAndIngest during rescan never matched. This caused findByAbsolutePath
to always return undefined on rescan, creating duplicate DB records for
every file already tracked via a watcher event.

Fix: both services now call `realpath(bookDockPath)` in
onApplicationBootstrap (after mkdir), updating the stored path to the
canonical real path that the watcher also uses. Rescan is now idempotent
regardless of symlinks in the data directory.

Verified by E2E test: 3 consecutive rescans produce zero new records.
2026-05-20 13:00:56 -06:00
neon e11b22f2b0 fix(books): switch progress reset to per-file controls (#63)
* fix(books): switch progress reset to per-file controls

Remove the book-level reset action and endpoint, and keep reset scoped to each file row to avoid accidental bulk clears.

Add tests for per-file reset behavior and progress formatting edge cases while keeping migration import filters aligned with the new progress expectations.

closes #57

* ci: increase commitlint body line limit to 250

Allow longer explanatory commit bodies so CI accepts existing project commit patterns without forcing manual hard wraps at 100 characters.
2026-05-20 12:40:24 -06:00
neon bb11fc2abc feat(auth): allow 25 active magic links per user
Raise the shared-account link ceiling so admins can provision more concurrent demo or shared login URLs without revoking existing active links.
2026-05-19 13:15:21 -06:00
neon e0686181d6 refactor(settings): consolidate 17 settings tabs into 10 grouped subtab containers (#56)
Reduce the settings navigation bar from 17 flat tabs to 10 by grouping
related settings into subtab containers, following the existing ?tab=
query-param pattern used by Reader and Metadata.

New groups:
- Integrations (/settings/integrations): Kobo, KOReader, Hardcover
- Admin (/settings/admin): Users, OIDC/SSO (permission-filtered)
- System (/settings/system): File Naming, Book Dock, Maintenance, Audit Log (permission-filtered)
- Account (/settings/account): Profile, Notifications (merged from standalone tabs)

All old routes redirect to their new grouped equivalents for backward
compatibility. Admin and System containers filter available tabs based on
user permissions. Demo-restricted accounts hide the Notifications tab.

New files:
- IntegrationsAllSettings.vue, AdminAllSettings.vue, SystemAllSettings.vue, AccountAllSettings.vue
- lib/integrations-tabs.ts, lib/admin-tabs.ts, lib/system-tabs.ts, lib/account-tabs.ts
- Unit tests for all new containers and tab-lib files (SettingsHeader included)

Closes #55
2026-05-19 13:10:24 -06:00
neon e4f6ddfb9b fix(metadata): require google books api key
Block Google Books from being enabled without credentials because unauthenticated API calls now fail quota checks. Normalize legacy enabled configs without keys to disabled.
2026-05-19 11:35:31 -06:00
neon 4fbcb48341 style(settings): unpin file naming mobile preview
Let the mobile preview panel scroll with the rest of the settings page so it no longer covers form content while editing.
2026-05-19 11:35:18 -06:00
neon e5c7d4a962 fix(stats): format session archetype tooltip values
Format fractional session start times as clock labels so tooltips do not expose raw decimal hours. Round minute durations to keep the chart readable.
2026-05-19 11:19:30 -06:00
Chris Mansell 418314352e feat: hardcover sync for per user reading status progress and rating (#53)
* feat(server): sync reading progress with Hardcover

* fix(server): update Hardcover sync pending state

* test(server): cover Hardcover admin and repository
2026-05-19 10:49:15 -06:00
neon 402d1cde5d fix(smart-scope): preserve draft filters while editing (#54)
Keep incomplete root filters visible in the SmartScope editor.

This lets users choose a field before setting an operator or value.

Fixes #52
2026-05-19 10:26:29 -06:00
neon 9d9461640b fix(scanner): clamp oversized inodes in upload and file event flows (#49)
Use BigInt stat reads for upload and file-event paths to preserve 64-bit inode values. Clamp inodes that exceed PostgreSQL bigint range to 0 before persistence and inode lookups, and add regression coverage for insert, upsert, restore, and move-detection paths.

Fixes #48
2026-05-18 23:00:34 -06:00
neon 8abde907d8 feat(reader): add footer modes, wake lock, keyboard shortcuts, and go-to input
- Add tap-to-cycle footer modes (pages, time/session, chapter) along with elapsed reading time and chapter progress on the slider
- Prevent screen dimming during reading using the Wake Lock API
- Add keyboard shortcuts (t/s/b/f/Esc/?/Home/End) with an integrated help modal
- Add go-to-location support (page number or percentage) and a resume-reading toast on book open
2026-05-18 22:02:49 -06:00
neon 25117e3d0b fix(download): enforce real file extension in pattern resolver 2026-05-18 17:46:20 -06:00
neon fabd1747d3 fix: add per-org upload pattern defaults for book_per_folder mode (#33)
* fix(settings): add per-org upload defaults for book_per_folder mode

* ci: add maintainer-gated PR GHCR image publish

---------

Signed-off-by: neon <18559658+neonsolstice@users.noreply.github.com>
2026-05-18 17:12:13 -06:00
neon 8786a18f04 fix(scanner): clamp oversized MergerFS inodes before storage (#30)
* fix(scanner): clamp oversized MergerFS inodes before storage

MergerFS generates synthetic unsigned 64-bit inodes by hashing file paths.
Values above 2^63-1 overflow PostgreSQL's signed bigint column, crashing
the scanner with 'value out of range for type bigint'.

Switch all file stat() calls to stat(path, { bigint: true }) to read
inodes as precise BigInt values instead of lossy JS numbers. Introduce
clampIno(ino: bigint): number which returns 0 for any inode exceeding
PostgreSQL's bigint max - 0 is the existing sentinel meaning 'rename
detection disabled', so no other code needs to change.

The fix covers all four code paths that write ino to a FileStat:
statFilesIntoAcc and buildSingleBookCandidate in walk.ts, plus the two
targeted-scan paths in scanner.service.ts.

Fixes #19

* ci: add maintainer-gated PR GHCR image publish

---------

Signed-off-by: neon <18559658+neonsolstice@users.noreply.github.com>
2026-05-18 17:11:28 -06:00
neon ab2af020a4 chore: set open-pull-requests-limit = 1 2026-05-18 16:49:18 -06:00
dependabot[bot] 02c563b8fa chore(deps): bump @semantic-release/github from 11.0.6 to 12.0.8 (#47)
Bumps [@semantic-release/github](https://github.com/semantic-release/github) from 11.0.6 to 12.0.8.
- [Release notes](https://github.com/semantic-release/github/releases)
- [Commits](https://github.com/semantic-release/github/compare/v11.0.6...v12.0.8)

---
updated-dependencies:
- dependency-name: "@semantic-release/github"
  dependency-version: 12.0.8
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 16:13:00 -06:00
neon 1fc04f8af6 fix(books): downgrade archiver to v7 to restore zip export (#41)
archiver v8 switched to pure ESM with no default export and a
   completely different API, breaking every zip export request with
   TypeError: (0 , _archiver.default) is not a function. The NestJS
   SWC build produces CJS output, which cannot import the new ESM-only
   package at runtime.

   Downgrade to ~7.0.1 (the last CJS release) and add a Dependabot
   ignore rule for archiver major bumps so this cannot recur silently.

   Fixes #31
2026-05-18 15:48:46 -06:00