diff --git a/docs/developer/api/authentication/login.md b/docs/developer/api/authentication/login.md index e81866b..95145f6 100644 --- a/docs/developer/api/authentication/login.md +++ b/docs/developer/api/authentication/login.md @@ -26,7 +26,7 @@ Authenticate with email and password. ```json { - "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "d4f5g6h7...", "token_type": "Bearer", "expires_in": 604800, @@ -41,6 +41,8 @@ Authenticate with email and password. } ``` +Note: the access token field is `access_token` (not `token`). Nullable profile fields (`first_name`, `last_name`) may be empty strings. + **Set-Cookie Header**: ``` diff --git a/docs/developer/api/devices/get_devices.md b/docs/developer/api/devices/get_devices.md index 92b1531..bf75e1c 100644 --- a/docs/developer/api/devices/get_devices.md +++ b/docs/developer/api/devices/get_devices.md @@ -24,7 +24,9 @@ Check device registration status or get device details. ```json { - "status": "pending|approved|expired", + "status": "pending|approved", + "message": "awaiting user approval", + "expires_in": 123, "auth_token": "device-bearer-token...", "device_id": "uuid", "sync_endpoints": { @@ -35,24 +37,16 @@ Check device registration status or get device details. } ``` -## Response (200 OK) - Device Details +`status` is `pending` or `approved`. While pending, the response includes `message` and `expires_in` (seconds remaining). Once approved, the response includes `auth_token`, `device_id`, and `sync_endpoints`; `auth_token` fields are empty when pending. -```json -{ - "id": "uuid", - "device_name": "My Kobo Clara", - "device_type": "kobo", - "last_sync": "2026-01-31T10:00:00Z", - "last_seen": "2026-01-31T10:05:00Z", - "sync_enabled": true, - "auto_sync": true, - "sync_frequency_minutes": 5 -} -``` +**The approved response is single-use**: the registration is deleted from the pending map once returned, so store the `auth_token` immediately. A repeat status check for the same `registration_id` returns 404. ## Error Responses -| Code | Description | -| ---- | --------------------------------------------- | -| 401 | Invalid or expired token (for device details) | -| 404 | Device or registration not found | +| Code | Description | +| ---- | -------------------------------------------------- | +| 400 | Invalid or missing `registration_id` | +| 404 | Registration not found (unknown or already issued) | +| 410 | Registration expired (`{"error": "registration expired"}`) | + +Note: expiration is signaled by HTTP 410 Gone, not a `"status": "expired"` value. Pending registrations are held in server memory, so a server restart also invalidates them (subsequent checks return 404). diff --git a/docs/developer/api/libraries/get_visible_libraries.md b/docs/developer/api/libraries/get_visible_libraries.md index bd85f02..6c30ab5 100644 --- a/docs/developer/api/libraries/get_visible_libraries.md +++ b/docs/developer/api/libraries/get_visible_libraries.md @@ -2,7 +2,7 @@ Retrieve all libraries visible to the current user. -**Endpoint**: `GET /api/libraries/visible` +**Endpoint**: `GET /api/libraries/visibility` **Auth**: Required ## Request Headers @@ -14,26 +14,33 @@ Retrieve all libraries visible to the current user. ### Example Request ```http -GET /api/libraries/visible +GET /api/libraries/visibility Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ``` ## Response (200 OK) +A top-level JSON **array** of library rows: + ```json -{ - "libraries": [ - { - "id": "uuid", - "name": "My Ebooks", - "description": "Ebook collection", - "type_name": "ebooks", - "is_visible": true - } - ] -} +[ + { + "id": "uuid", + "name": "My Ebooks", + "description": "Ebook collection", + "library_type_id": "uuid", + "created_by_admin_id": "uuid", + "created_at": "2026-01-31T10:00:00Z", + "updated_at": "2026-01-31T10:00:00Z", + "type_name": "ebooks", + "type_description": "Ebook libraries", + "is_visible": true + } +] ``` +Nullable columns (`description`, `type_description`) serialize as `null` when unset. Timestamps are RFC 3339. + ## Error Responses | Code | Description | diff --git a/docs/developer/api/media-items/list_media_items.md b/docs/developer/api/media-items/list_media_items.md index fbc5ff1..23ac03f 100644 --- a/docs/developer/api/media-items/list_media_items.md +++ b/docs/developer/api/media-items/list_media_items.md @@ -1,17 +1,22 @@ # List Media Items -Retrieve a paginated list of media items from a library. +Retrieve a paginated list of media items, scoped to a library or across all libraries. **Endpoint**: `GET /api/media-items` **Auth**: Required ## Query Parameters -| Parameter | Type | Required | Description | -| ---------- | ------- | -------- | ----------------------------------------------- | -| library_id | string | Yes | Library UUID | -| limit | integer | No | Number of items to return (max 100, default 20) | -| offset | integer | No | Number of items to skip | +| Parameter | Type | Required | Description | +| ---------- | ------ | -------- | ------------------------------------------------------ | +| library_id | string | No | Library UUID. If omitted, items from all libraries are returned | +| limit | int | No | Items to return (default 50, max 1000) | +| offset | int | No | Items to skip (must be >= 0) | +| sort | string | No | Sort expression, default `created_at DESC` | + +### Allowed sort expressions + +`created_at`, `title`, `author`, `series`, `date_published`, `copyright_year`, `page_count`, `genre` — each with ` ASC` or ` DESC` (e.g. `title ASC`). Any other value silently falls back to `created_at DESC`. ## Request Headers @@ -22,46 +27,121 @@ Retrieve a paginated list of media items from a library. ### Example Request ```http -GET /api/media-items?library_id=uuid&limit=20&offset=0 +GET /api/media-items?library_id=uuid&limit=20&offset=0&sort=title%20ASC Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ``` ## Response (200 OK) +The response body is `{"data": [...]}` in both modes. The item shape differs by mode. + +**No total is returned** — page until fewer items than `limit` come back. + +### With `library_id` — full database rows + +Nullable columns serialize as `null`. + ```json { - "media_items": [ + "data": [ { "id": "uuid", "library_id": "uuid", "title": "Book Title", "author": "Author Name", + "isbn": "978-...", "description": "Book description", - "file_path": "/path/to/book.epub", + "file_path": "relative/path/book.epub", "file_size": 1024000, "mime_type": "application/epub+zip", - "cover_image_path": "/path/to/cover.jpg", + "cover_image_path": "relative/path/cover.jpg", "series": "Series Name", "series_number": 1, - "tags": ["sci-fi", "space opera"], - "tags_search": ["sci fi", "space opera"], - "contributors": ["Author Name", "ACME CORP."], - "contributors_search": ["author name", "acme corp"], + "tags": ["sci-fi"], + "asin": null, + "date_published": "2023-06-01", + "publisher": null, + "contributors": ["Author Name"], "language": "en", + "edition": null, "page_count": 350, "genre": "Science Fiction", "copyright_year": 2023, - "created_at": "2026-01-31T10:00:00Z" + "goodreads_id": null, + "openlibrary_id": null, + "google_books_id": null, + "added_by_admin_id": "uuid", + "created_at": "2026-01-31T10:00:00Z", + "imported_at": "2026-01-31T10:00:00Z", + "updated_at": "2026-01-31T10:00:00Z", + "format_group": "epub", + "format_mimetype": "application/epub+zip", + "is_reflowable": true, + "has_fixed_layout": false, + "total_characters": 480000, + "chapter_count": 24 } - ], - "total": 100 + ] +} +``` + +Note: in this mode `file_path` and `cover_image_path` are the raw relative storage paths, not URLs. + +### Without `library_id` — curated items with resolved URLs + +Across all libraries; file and cover paths are resolved to fetchable URL paths (`/uploads/...` or library-scoped paths): + +```json +{ + "data": [ + { + "id": "uuid", + "library_id": "uuid", + "title": "Book Title", + "author": "Author Name", + "isbn": "978-...", + "description": "Book description", + "file_path": "/api/libraries//files/...", + "file_size": 1024000, + "mime_type": "application/epub+zip", + "cover_image_path": "/api/libraries//files/.../cover.jpg", + "series": "Series Name", + "series_number": 1, + "tags": ["sci-fi"], + "asin": null, + "date_published": "2023-06-01", + "publisher": null, + "contributors": ["Author Name"], + "language": "en", + "edition": null, + "page_count": 350, + "genre": "Science Fiction", + "created_at": "2026-01-31T10:00:00Z", + "updated_at": "2026-01-31T10:00:00Z", + "format_group": "epub", + "manga_type": null, + "reading_direction": null, + "series_count": null, + "volume": null, + "imprint": null, + "age_rating": null, + "web_url": null, + "metadata_notes": null, + "community_rating": null, + "story_arc": null, + "is_black_and_white": false, + "alternate_info": null, + "scan_information": null, + "summary": null + } + ] } ``` ## Error Responses -| Code | Description | -| ---- | ----------------------------------------- | -| 400 | Invalid query parameters | -| 401 | Invalid or expired token | -| 403 | User does not have access to this library | +| Code | Description | +| ---- | ------------------------------------------ | +| 400 | Invalid `library_id`, `offset` < 0 | +| 401 | Invalid or expired token | +| 500 | Query failure (returned as `{"error": …}`) |