Commit Graph

463 Commits

Author SHA1 Message Date
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
dependabot[bot] 38e901f3af chore(deps): bump brace-expansion from 1.1.13 to 5.0.6 (#40)
Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.13 to 5.0.6.
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.13...v5.0.6)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 5.0.6
  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-18 15:40:21 -06:00
dependabot[bot] df52eee23e chore(deps): bump brace-expansion from 1.1.13 to 5.0.5 (#38)
* chore(deps): bump brace-expansion from 1.1.13 to 5.0.5

Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 1.1.13 to 5.0.5.
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.13...v5.0.5)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 5.0.5
  dependency-type: indirect
...

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

* chore(deps): skip dependabot branch and issue checks

---------

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-18 15:13:19 -06:00
neon 8b70c55604 fix(collections): restore add-to-collection from quick view (#39)
Close the quick-view sheet before dispatching add or delete actions.
Ensure the collection sheet opens reliably from the side panel.

Add regression tests for quick-view and table-shell action flow.
Expand collection controller and service edge-case coverage for this path.

Fixes #36
2026-05-18 15:00:22 -06:00
neon 4cb0149380 feat(settings): add series number badge to book cover card overlay (#37)
Series position badge (#N) rendered in the top-right corner of cover
cards, sharing a flex-column container with the existing lock-status
badge. Shown only when seriesIndex is non-null. Whole numbers strip the
decimal (3.0 -> #3); fractional values display as-is (1.5 -> #1.5).
Hovering the badge shows a tooltip with the full series name and position.
Enabled by default in Appearance -> Card Overlays.

Closes #32
2026-05-18 13:48:38 -06:00
neon 5524cd9d0d fix(email): add skip-TLS-verification option and surface provider delete errors (#35)
Node.js inside Docker validates the full TLS certificate chain against its bundled
CA store. When the chain cannot be verified (e.g. outdated CA bundle, self-signed
cert, or Let's Encrypt chain not trusted), nodemailer reports a misleading error
like "certificate has expired". Add a per-provider tlsRejectUnauthorized flag
(default: true) that passes tls.rejectUnauthorized=false to nodemailer when
disabled, letting self-hosted SMTP servers opt out of cert verification. A visible
warning is shown in the provider form whenever the flag is turned off.

The delete provider API already returned a clear 400 message explaining that the
system designation must be removed first, but the frontend threw a hardcoded
"Failed to delete provider" string and never read the response body. Fix the
composable to parse and rethrow the actual API error message. Also disable the
delete button for system providers with a tooltip stating the constraint, so users
cannot trigger the error in the first place.

Adds tlsRejectUnauthorized boolean column (NOT NULL DEFAULT true) to
email_providers via Drizzle migration 0004.

Closes #26
2026-05-18 12:38:22 -06:00
neon 54fa317441 chore: remove legacy markdown issue templates
Keep only YAML issue forms so GitHub does not show duplicate Bug and Feature entries.
2026-05-18 00:17:54 -06:00
neon 2dea6915d4 chore(server): increase currently reading widget limit to 10
Adjust the currently reading cap to tune dashboard density without changing feature scope.
2026-05-18 04:26:39 +00:00
neon 69f69febb2 feat(book): add highlights tab with filters, export, and pagination 2026-05-18 03:52:17 +00:00
neon e89f4ce0e4 ci: enforce PR issue references and branch conventions
Validate BO-<issue>-<slug> branch names and lint PR titles and commit headers in CI and release workflows.

Require GitHub closing-keyword issue references and verify referenced issues exist. Align contributing, release, commit, testing, and policy docs with the enforced behavior and tone.
2026-05-17 13:10:32 -06:00
neon 9f15d0955a feat(reading-log): implement end-to-end reading log feature 2026-05-17 01:42:41 -06:00
neon 8d535c2617 fix(metadata): use Goodreads autocomplete before HTML search 2026-05-16 23:35:31 -06:00
neon eb9b714ecb feat: add full-stack achievements system
- add achievement schema, migrations, evaluators, APIs, and backfill support on the server
- add achievements UI, composables, toast utilities, and tests on the client
- add shared achievement/auth/notification type updates
2026-05-16 15:50:42 +00:00
neon 9fdb3f46bb chore(book): unify rating star colors across views 2026-05-15 12:20:09 -06:00