bruno: regenerate collection from canonical docs + permanent docs↔Bruno parity gate

WO4. The old collection was the drifted artifact AGENTS.md warned about:
bodies pre-truncated at their first {{var}}, routes renamed server-side
but not here (/api/notes/:media_id, /api/book-matching/search,
/api/collections/:id/rules/test), an orphan universal-progress suite for
routes that no longer exist.

scripts/gen_bruno_from_docs.py emits one OpenCollection request per
frontmatter'd endpoint doc (191 requests): gate-verified example-request
JSON as body, {{env}} params per the environment file, device-token
routes get an explicit Bearer {{device_token}} header, login/register/
refresh keep the token-capture after-response scripts that chain the
collection. Old 1:1 mirrors deleted (128); hand-authored NewDevDBSetup,
environments, and edge-case suites kept. 30 scenario files with
truncated bodies (the documented corruption) deleted — they could not
run.

internal/docs/drift_test.go gains TestBrunoMirrorsDocs: every
frontmatter'd doc must have a Bruno request with matching method+URL
shape — the collection can never silently drift from the docs again.
opencollection.yml README block replaced with the real run instructions.

make test green (9 pkgs, parity test included in internal/docs).
This commit is contained in:
John O'Keefe committed 2026-10-24 18:35:51 -04:00
1 parent 6fc501b35a
commit acd82fff0a
353 files changed
+5165 -5293

No files matched your search

+29
View File
@@ -0,0 +1,29 @@
info:
name: Add to Shelf
type: http
seq: 1
http:
method: POST
url: '{{base_url}}/api/devices/{{device_id}}/shelves'
auth: inherit
body:
type: json
data: |-
{
"media_item_ids": ["550e8400-e29b-41d4-a716-446655440001"],
"shelf_name": "Default",
"shelf_position": 0
}
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# Add to Shelf
`POST /api/devices/:id/shelves` — auth: jwt.
Canonical reference: `docs/developer/api/devices/add_to_shelf.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
@@ -0,0 +1,21 @@
info:
name: Approve Device Registration
type: http
seq: 2
http:
method: GET
url: '{{base_url}}/api/devices/approve/{{registration_id}}'
auth: inherit
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# Approve Device Registration
`GET /api/devices/approve/:registration_id` — auth: jwt.
Canonical reference: `docs/developer/api/devices/approve_device_registration.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
+21
View File
@@ -0,0 +1,21 @@
info:
name: Clear Shelf
type: http
seq: 3
http:
method: DELETE
url: '{{base_url}}/api/devices/{{device_id}}/shelves/clear'
auth: inherit
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# Clear Shelf
`DELETE /api/devices/:id/shelves/clear` — auth: jwt.
Canonical reference: `docs/developer/api/devices/clear_shelf.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
+21
View File
@@ -0,0 +1,21 @@
info:
name: Delete Device
type: http
seq: 4
http:
method: DELETE
url: '{{base_url}}/api/devices/{{device_id}}'
auth: inherit
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# Delete Device
`DELETE /api/devices/:id` — auth: jwt.
Canonical reference: `docs/developer/api/devices/delete_device.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
+21
View File
@@ -0,0 +1,21 @@
info:
name: Download Sidecar Config
type: http
seq: 5
http:
method: GET
url: '{{base_url}}/api/devices/{{device_id}}/sidecar/download'
auth: inherit
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# Download Sidecar Config
`GET /api/devices/:id/sidecar/download` — auth: jwt.
Canonical reference: `docs/developer/api/devices/download_sidecar_config.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
+21
View File
@@ -0,0 +1,21 @@
info:
name: Get Device
type: http
seq: 6
http:
method: GET
url: '{{base_url}}/api/devices/{{device_id}}'
auth: inherit
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# Get Device
`GET /api/devices/:id` — auth: jwt.
Canonical reference: `docs/developer/api/devices/get_device.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
+21
View File
@@ -0,0 +1,21 @@
info:
name: Get Device Collection Mappings
type: http
seq: 7
http:
method: GET
url: '{{base_url}}/api/devices/{{device_id}}/collections'
auth: inherit
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# Get Device Collection Mappings
`GET /api/devices/:id/collections` — auth: jwt.
Canonical reference: `docs/developer/api/devices/get_device_mappings.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
+27
View File
@@ -0,0 +1,27 @@
info:
name: Get Device / Check Registration Status
type: http
seq: 8
http:
method: POST
url: '{{base_url}}/api/devices/register/status'
auth: inherit
body:
type: json
data: |-
{
"registration_id": "registration-uuid"
}
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# Get Device / Check Registration Status
`POST /api/devices/register/status` — auth: none.
Canonical reference: `docs/developer/api/devices/get_devices.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
+21
View File
@@ -0,0 +1,21 @@
info:
name: Get Shelf
type: http
seq: 9
http:
method: GET
url: '{{base_url}}/api/devices/{{device_id}}/shelves'
auth: inherit
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# Get Shelf
`GET /api/devices/:id/shelves` — auth: jwt.
Canonical reference: `docs/developer/api/devices/get_shelf.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
+21
View File
@@ -0,0 +1,21 @@
info:
name: Get Device Sidecar Config
type: http
seq: 10
http:
method: GET
url: '{{base_url}}/api/devices/{{device_id}}/sidecar'
auth: inherit
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# Get Device Sidecar Config
`GET /api/devices/:id/sidecar` — auth: jwt.
Canonical reference: `docs/developer/api/devices/get_sidecar_config.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
@@ -1,17 +0,0 @@
info:
name: Get Analytics Tests
type: http
seq: 7
http:
method: POST
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/v1/analytics/gettests'
auth: inherit
headers:
- key: Content-Type
value: application/json
body:
type: json
data: "{\n \"platform\": \"android\",\n \"firmware_version\": \"4.30.19023\"\n}"
docs: "## Get Kobo Analytics Tests\n\nRetrieves A/B testing configuration and feature flags for Kobo device.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/kobo/v1/analytics/gettests\n\n**Authentication:** Bearer token\n\n**Request Body:**\n- `platform` (string): Device platform\n - `android`: Kobo Android app\n - `kobo`: Native Kobo firmware\n- `firmware_version` (string): Firmware version (e.g., \"4.30.19023\")\n- `device_model` (string, optional): Device model identifier\n- `locale` (string, optional): Device locale (e.g., \"en_US\")\n\n**Response:**\n- `tests` (array): Active A/B tests\n - `test_name` (string): Test identifier\n - `variant` (string): Assigned variant (A, B, C, etc.)\n - `enabled` (boolean): Whether test is active\n - `parameters` (object): Test-specific parameters\n- `features` (object): Feature flags\n - `feature_name` (boolean/string): Feature state\n- `configuration` (object): Device configuration\n - `sync_interval_minutes` (integer): Recommended sync frequency\n\
\ - `batch_size` (integer): Max items per batch sync\n - `timeout_seconds` (integer): Request timeout\n- `version` (string): Configuration version\n\n**Status Codes:**\n- 200: Success\n- 401: Unauthorized\n- 400: Invalid request parameters\n\n**Analytics Testing Purpose:**\n- Kobo uses A/B testing for UX features\n- Feature flags for gradual rollout\n- Performance monitoring configuration\n- Sync behavior optimization\n- Device-specific tuning\n\n**Common Tests:**\n- Sync frequency optimization\n- UI/UX variations\n- Network usage patterns\n- Battery life improvements\n- Feature set variations by model\n\n**Feature Flags:**\n- New sync features\n- Beta functionality\n- Platform-specific capabilities\n- Experimental features\n\n**Configuration Parameters:**\n- Optimal sync intervals for device\n- Batch size limits based on device capabilities\n- Timeout values for network conditions\n- Retry logic configuration\n- Cache policy settings\n\n**Usage:**\n- Called during device initialization\n\
- Refreshed daily or weekly\n- Cached on device\n- Affects sync behavior\n- Can be overridden by server\n\n**Use Cases:**\n- Device initialization\n- Feature rollout testing\n- Performance optimization\n- UX experiment participation\n- Configuration management"
-81
View File
@@ -1,81 +0,0 @@
info:
name: Get Kobo Library
type: http
seq: 6
http:
method: GET
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/v1/initialization'
auth: inherit
docs: |-
## Get Kobo Library
Retrieves the user's Kobo library metadata for device sync.
**Method:** GET
**Endpoint:** /api/sync/kobo/library
**Authentication:** Bearer token
**Query Parameters:**
None (returns entire library)
**Response:**
- `books` (array): Library items
- `ContentId` (string): Unique book identifier
- `Title` (string): Book title
- `Author` (string): Author name
- `Publisher` (string): Publisher name
- `Description` (string): Book description
- `ISBN` (string, optional): ISBN-13
- `PublicationDate` (string): Release date
- `EntitlementId` (string): Kobo entitlement ID
- `CrossRevisionId` (string): Revision identifier
- `MimeType` (string): Content type (application/epub+zip)
- `FileSize` (integer): File size in bytes
- `CoverImageId` (string): Cover image identifier
- `DownloadUrls` (object): Download URLs
- `download_url` (string): Direct download link
- `download_acquisition_url` (string): OPDS acquisition URL
- `sync_metadata` (object):
- `last_sync` (string): Last library sync timestamp
- `total_books` (integer): Total book count
- `has_updates` (boolean): Whether updates are available
**Status Codes:**
- 200: Success
- 401: Unauthorized
- 403: Device not approved
**Library Sync Purpose:**
- Kobo device needs to know available books
- Enables download via device browser
- Provides metadata for device display
- Supports Kobo's "My Books" feature
- Enables on-device purchasing integration
**Kobo Device Usage:**
- Device fetches library on registration
- Refreshed daily or on manual sync
- User can browse library on device
- Books downloaded wirelessly to device
- Supports "Buy on Kobo, read on device" workflow
**Authentication Methods:**
This endpoint uses **Bearer token authentication** (token in Authorization header).
Alternative: Use `/sync/kobo/{token}/library` with token in URL path.
**Performance:**
- Typical response: 50-200KB for 100 books
- Processing time: 200-800ms
- Cache duration: 5 minutes
- Pagination available for large libraries (>500 books)
**Use Cases:**
- Initial device registration
- Library refresh on device
- Book discovery on device
- Download link generation
- Metadata sync for OPDS
@@ -1,22 +0,0 @@
info:
name: Get Unlinked Book Suggestions
type: http
seq: 1
http:
method: GET
url: '{{base_url}}/api/sync/unlinked-books/{{unlinkedBookId}}/suggestions'
auth: inherit
body:
type: none
headers:
- key: Authorization
value: Bearer {{authToken
docs: |-
## Get Unlinked Book Suggestions
Retrieves suggested media items from the library that match an unlinked book, enabling manual linking.
**Method:** GET
**Endpoint:** /sync/unlinked-books/{unlinkedBookId
@@ -1,17 +0,0 @@
info:
name: Auto-Link Unlinked Books
type: http
seq: 1
http:
method: POST
url: '{{base_url}}/api/sync/auto-link-books'
auth: inherit
body:
type: json
data: "{\n \"confidence_threshold\": 0.8,\n \"limit\": 50"
headers:
- key: Content-Type
value: application/json
- key: Authorization
value: Bearer {{authToken
docs: "## Auto-Link Unlinked Books\n\n Automatically links unlinked books to media items based on title and author matching with a configurable confidence threshold.\n\n **Method:** POST\n\n **Endpoint:** /sync/auto-link-books\n\n **Authentication:** Bearer token\n\n **Request Body:**\n - `confidence_threshold` (number, optional): Minimum confidence score for auto-linking (0-1, default: 0.8)\n - `limit` (number, optional): Maximum number of books to auto-link (default: 50)\n\n **Response:**\n - `results` (array): Results for each auto-link attempt\n - `total` (number): Total number of books processed\n - `success` (number): Number of successful links\n - `failed` (number): Number of failed links\n\n **Status Codes:**\n - 200: Success\n - 400: Invalid request data\n - 401: Unauthorized\n - 500: Internal server error\n\n **Note:** Higher confidence thresholds produce fewer but more accurate matches. Consider the tradeoff between automation and accuracy."
@@ -1,17 +0,0 @@
info:
name: Bulk Link Unlinked Books
type: http
seq: 1
http:
method: POST
url: '{{base_url}}/api/sync/bulk-link-books'
auth: inherit
body:
type: json
data: "{\n \"links\": [\n {\n \"unlinked_book_id\": \"{{unlinkedBookId1"
headers:
- key: Content-Type
value: application/json
- key: Authorization
value: Bearer {{authToken
docs: "## Bulk Link Unlinked Books\n\n Links multiple unlinked books to media items in a single request.\n\n **Method:** POST\n\n **Endpoint:** /sync/bulk-link-books\n\n **Authentication:** Bearer token\n\n **Request Body:**\n - `links` (array): Array of link objects\n - `unlinked_book_id` (string): Unlinked book UUID\n - `media_item_id` (string): Media item UUID to link to\n - `confidence_score` (number): Match confidence (0-1)\n\n **Response:**\n - `results` (array): Results for each link attempt\n - `total` (number): Total number of links processed\n - `success` (number): Number of successful links\n - `failed` (number): Number of failed links\n\n **Status Codes:**\n - 200: Success\n - 400: Invalid request data\n - 401: Unauthorized\n - 500: Internal server error\n\n **Note:** Use this endpoint after reviewing suggestions from the Get Unlinked Book Suggestions endpoint."
@@ -1,16 +0,0 @@
info:
name: Sync from Bookhoard to Kobo
type: http
seq: 1
http:
method: POST
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/sync-from-server'
auth: inherit
body:
type: json
data: "[\n {\n \"ContentId\": \"{{bookUUID"
headers:
- key: Authorization
value: Bearer {{koboToken
docs: "## Sync from Bookhoard to Kobo\n\n Server-initiated sync pushing progress, bookmarks, and highlights from Bookhoard to Kobo device. Two-way sync endpoint.\n\n **Method:** POST\n\n **Endpoint:** /api/sync/kobo/sync-from-server\n\n **Authentication:** Bearer token with Kobo device identification\n\n **Headers:**\n - `x-kobo-device` (string): JSON string containing Kobo device info\n - `DeviceId`: Kobo device ID\n - `Model`: Kobo device model\n - `SerialNumber`: Kobo device serial number\n\n **Request Body:** Array of sync data objects\n - `ContentId` (string): Book UUID\n - `PercentRead` (number): Reading progress percentage (0-100)\n - `LastModified` (string): ISO 8601 timestamp\n - `Bookmarks` (array, optional): Array of bookmark objects\n - `BookmarkId`: Unique bookmark ID\n - `ContentId`: Book UUID\n - `BookmarkText`: Bookmark text/note\n - `BookmarkType`: Type (bookmark, annotation, etc.)\n - `BookmarkTitle`: Bookmark title\n - `Highlights` (array,\
\ optional): Array of highlight objects (same structure as bookmarks)\n\n **Response:**\n - Sync result confirmation\n\n **Status Codes:**\n - 200: Success\n - 401: Unauthorized\n - 500: Internal server error\n\n **Note:** Allows Bookhoard server to push updates to Kobo device, including reading progress, bookmarks, and highlights."
@@ -1,15 +0,0 @@
info:
name: Kobo Bookmark Sync
type: http
seq: 3
http:
method: POST
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/bookmark'
auth: inherit
body:
type: json
data: "{\n \"BookmarkSync\": [\n {\n \"BookmarkId\": \"bookmark_2\",\n \"ContentId\": \"kobo_xyz789\",\n \"BookmarkText\": \"Important note\",\n \"BookmarkType\": \"bookmark\",\n \"DateCreated\": \"2026-01-31T12:00:00Z\""
headers:
- key: Authorization
value: Bearer {{device_token
docs: "## Kobo Bookmark Sync\n\n Synchronizes bookmarks from a Kobo device to the Bookhoard server.\n\n **Method:** POST\n\n **Endpoint:** /api/v1/kobo/bookmark\n\n **Authentication:** Bearer token (device token)\n\n **Request Body:**\n - `BookmarkSync` (array): Array of bookmark objects\n - `BookmarkId` (string): Unique bookmark ID\n - `ContentId` (string): Book/content ID\n - `BookmarkText` (string): Bookmark text or note\n - `BookmarkType` (string): Type (bookmark, highlight, note)\n - `DateCreated` (string): ISO 8601 timestamp\n\n **Response:**\n - `Status` (string): Sync status (Success, Partial)\n - `BookmarksSynced` (number): Number of bookmarks synced\n\n **Status Codes:**\n - 200: Success\n - 401: Unauthorized\n - 500: Internal server error"
@@ -1,39 +0,0 @@
info:
name: Get Unlinked Books - User View
type: http
seq: 4
http:
method: GET
url: '{{base_url}}/api/devices/{{device_id}}/sync/unlinked-books'
auth: inherit
body:
type: none
headers:
- key: Authorization
value: Bearer {{user_token
docs: |-
## Get Unlinked Books - User View
Retrieves all unlinked books for the authenticated user that need manual linking.
**Method:** GET
**Endpoint:** /api/sync/unlinked-books
**Authentication:** Bearer token
**Response:**
- `unlinked` (array): Array of unlinked book objects
- `id` (string): Unlinked book UUID
- `title` (string): Book title
- `author` (string): Book author
- `device_id` (string): Source device ID
- `device_name` (string): Source device name
- `detected_at` (string): Detection timestamp
- `total` (number): Total count of unlinked books
**Status Codes:**
- 200: Success
- 401: Unauthorized
- 500: Internal server error
@@ -1,15 +0,0 @@
info:
name: Link Unlinked Book - Manual Resolution
type: http
seq: 5
http:
method: POST
url: '{{base_url}}/api/devices/{{device_id}}/sync/link-book'
auth: inherit
body:
type: json
data: "{\n \"unlinked_book_id\": \"{{unlinked_book_id"
headers:
- key: Authorization
value: Bearer {{user_token
docs: "## Link Unlinked Book - Manual Resolution\n\n Manually links an unlinked book to a media item in the library.\n\n **Method:** POST\n\n **Endpoint:** /api/sync/link-book\n\n **Authentication:** Bearer token\n\n **Request Body:**\n - `unlinked_book_id` (string): Unlinked book UUID\n - `media_item_id` (string): Media item UUID to link to\n - `confidence_score` (number): Match confidence (0-1, 1.0 for manual)\n\n **Response:**\n - `status` (string): Link status (linked)\n - `unlinked_book_id` (string): Unlinked book UUID\n - `media_item_id` (string): Media item UUID\n - `message` (string): Success message\n\n **Status Codes:**\n - 200: Success - book linked\n - 400: Invalid request\n - 401: Unauthorized\n - 404: Book or media item not found\n - 500: Internal server error"
@@ -1,15 +0,0 @@
info:
name: Sync Bookmark - URL Path Token
type: http
seq: 2
http:
method: POST
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/bookmark'
auth: none
body:
type: json
data: "{\n \"ContentId\": \"book-uuid\",\n \"BookmarkText\": \"Highlighted text\",\n \"BookmarkType\": \"annotation\",\n \"BookmarkTitle\": \"Chapter 3\""
headers:
- key: Content-Type
value: application/json
docs: "## Sync Bookmark - URL Path Token\n\n Synchronizes bookmarks and annotations from Kobo device using token in URL path.\n\n **Method:** POST\n\n **Endpoint:** /sync/kobo/{kobo_device_token"
@@ -1,15 +0,0 @@
info:
name: Sync Markup - URL Path Token
type: http
seq: 1
http:
method: POST
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/markup'
auth: none
body:
type: json
data: "{\n \"ReadingSync\": [\n {\n \"ContentId\": \"book-uuid\",\n \"PercentRead\": 45.6,\n \"EntitlementId\": \"entitlement-id\",\n \"RemainingTimeMinutes\": 120,\n \"FirstReadTime\": \"2026-01-25T10:00:00Z\",\n \"LastModified\": \"2026-01-30T20:00:00Z\""
headers:
- key: Content-Type
value: application/json
docs: "## Sync Reading Progress - URL Path Token\n\n Synchronizes reading progress from Kobo device using token in URL path.\n\n **Method:** POST\n\n **Endpoint:** /sync/kobo/{kobo_device_token"
@@ -1,14 +0,0 @@
docs: "## Get KOReader Book Metadata\n\nRetrieves metadata for a specific book from the server.\n\n**Method:** GET\n\n**Endpoint:** /api/sync/koreader/metadata/:book_uuid\n\n**Authentication:** Bearer token\n\n**Path Parameters:**\n- `book_uuid` (string): SHA-256 based book identifier\n\n**Response:**\n- `uuid` (string): Book UUID (SHA-256)\n- `title` (string): Book title\n- `authors` (array): Author names\n- `series` (string, optional): Series name\n- `series_index` (number, optional): Position in series\n- `publisher` (string, optional): Publisher name\n- `publication_date` (string, optional): Release date\n- `language` (string, optional): ISO 639-1 language code\n- `description` (string, optional): Book description\n- `cover_url` (string, optional): Cover image URL\n- `cover_thumbnail_url` (string, optional): Thumbnail URL\n- `identifiers` (object): Various identifiers\n - `isbn` (string, optional): ISBN-13\n - `asin` (string, optional): Amazon ASIN\n - `goodreads` (string, optional):\
\ Goodreads ID\n - `google_books` (string, optional): Google Books ID\n- `metadata_sources` (array): Sources metadata was pulled from\n- `last_synced` (string): Last metadata sync timestamp\n- `file_metadata` (object):\n - `file_size` (integer): File size in bytes\n - `format` (string): File format (epub, pdf, mobi, etc.)\n - `pages` (integer, optional): Page count\n - `word_count` (integer, optional): Estimated words\n\n**Status Codes:**\n- 200: Success\n- 401: Unauthorized\n- 404: Book not found\n\n**Metadata Purpose:**\n- Enrich book information on device\n- Improve book organization\n- Enable better search\n- Support series sorting\n- Provide cover images\n- Link to external sources\n\n**KOReader Usage:**\n- Display in book info dialog\n- Used for library sorting\n- Shown in file browser\n- Series grouping\n- Cover display\n- Search optimization\n\n**SHA-256 Book ID:**\n- Primary identifier in KOReader\n- Universal across devices\n- Format-independent\n- Generated from file content\n\
- Survives metadata changes\n\n**Metadata Sources:**\n- Google Books API\n- Open Library\n- Goodreads API\n- ISBN database lookup\n- Publisher metadata\n- User-provided metadata\n\n**Use Cases:**\n- Initial book import\n- Metadata refresh\n- Cover image download\n- Series organization\n- Duplicate detection\n- Library management"
http:
headers: []
method: GET
url: '{{base_url}}/api/sync/koreader/metadata/{{book_uuid}}'
auth:
type: bearer
token: '{{koreader_device_token}}'
info:
name: Get Book Metadata
seq: 8
type: http
-14
View File
@@ -1,14 +0,0 @@
docs: "## KOReader Get Library\n\n Retrieves the user's library for KOReader sync operations.\n\n **Method:** GET\n\n **Endpoint:** /api/sync/koreader/library\n\n **Authentication:** Bearer token (device token)\n\n **Response:**\n - `library_sync` (object): Library sync data\n - `total_books` (number): Total number of books\n - `books` (array): Array of book objects\n\n **Status Codes:**\n - 200: Success\n - 401: Unauthorized\n - 500: Internal server error"
http:
body:
type: none
headers: []
method: GET
url: '{{base_url}}/api/sync/koreader/library'
auth:
type: bearer
token: '{{koreader_device_token}}'
info:
name: KOReader Get Library
seq: 3
type: http
@@ -1,15 +0,0 @@
docs: "## Get KOReader User Library\n\nRetrieves the user's book library for KOReader device sync.\n\n**Method:** GET\n\n**Endpoint:** /api/sync/koreader/library\n\n**Authentication:** Bearer token (koreader_device_token)\n\n**Query Parameters:**\nNone (returns entire library)\n\n**Response:**\n- `books` (array): Library items\n - `uuid` (string): SHA-256 based book identifier\n - `title` (string): Book title\n - `authors` (array): Author names\n - `series` (string, optional): Series name\n - `series_index` (number, optional): Series position\n - `publisher` (string, optional): Publisher\n - `publication_date` (string, optional): Release date\n - `language` (string, optional): Language code\n - `description` (string, optional): Description\n - `cover_url` (string, optional): Cover image URL\n - `cover_thumbnail_url` (string, optional): Thumbnail URL\n - `file_metadata` (object):\n - `format` (string): File format\n - `file_size` (integer): Size in bytes\n - `pages` (integer,\
\ optional): Page count\n - `progress` (object, optional): Reading progress\n - `percentage` (number): Progress 0-100\n - `last_read` (string): Last read timestamp\n - `epubcfi` (string): Current position\n - `annotations_count` (object, optional): Annotation stats\n - `highlights` (integer): Highlight count\n - `notes` (integer): Note count\n - `bookmarks` (integer): Bookmark count\n- `library_info` (object):\n - `total_books` (integer): Total book count\n - `last_sync` (string): Last library sync timestamp\n - `has_updates` (boolean): Updates available\n- `user_info` (object):\n - `user_id` (string): User identifier\n - `email` (string): Email (masked)\n - `libraries` (array): Available library IDs\n\n**Status Codes:**\n- 200: Success\n- 401: Unauthorized\n- 403: Device not approved\n\n**Library Purpose for KOReader:**\n- Discover books available for download\n- Browse catalog on device\n- Sync reading progress across books\n- Download covers/metadata\n- Series-based\
\ organization\n- Cloud library access\n\n**KOReader Device Features:**\n- **OPDS catalog**: Native OPDS client\n- **File browser**: See server books\n- **Cloud download**: Download books on-demand\n- **Metadata sync**: Automatic metadata fetching\n- **Cover images**: Display in library view\n- **Progress sync**: See progress across all books\n- **Search**: Search library by title/author\n\n**KOReader-Specific Features:**\n- SHA-256 based book IDs\n- Multi-format support (EPUB, FB2, PDF, DJVU, MOBI, etc.)\n- Series sorting and grouping\n- Language filtering\n- Cover image caching\n- Metadata for file browser enhancement\n- Integration with KOReader's OPDS client\n\n**Performance:**\n- Typical response: 100-500KB for 100 books\n- Processing time: 300ms-1s\n- Cache duration: 5 minutes\n- Pagination support for libraries >500 books\n\n**Use Cases:**\n- Initial device setup\n- Library browsing on device\n- Book download\n- Metadata refresh\n- Cover image sync\n- Progress overview\n- Series-based\
\ reading"
http:
headers: []
method: GET
url: '{{base_url}}/api/sync/koreader/library'
auth:
type: bearer
token: '{{koreader_device_token}}'
info:
name: Get User Library for KOReader
seq: 9
type: http
+33
View File
@@ -0,0 +1,33 @@
info:
name: Link Book
type: http
seq: 11
http:
method: POST
url: '{{base_url}}/api/devices/{{device_id}}/sync/link-book'
auth: inherit
body:
type: json
data: |-
{
"device_file": {
"file_path": "/books/1984.epub",
"sha256": "abc123...",
"title": "1984"
},
"media_item_id": "550e8400-e29b-41d4-a716-446655440000",
"confidence_score": 0.95
}
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# Link Book
`POST /api/devices/:deviceId/sync/link-book` — auth: jwt.
Canonical reference: `docs/developer/api/devices/link_book.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
+21
View File
@@ -0,0 +1,21 @@
info:
name: List User Devices
type: http
seq: 12
http:
method: GET
url: '{{base_url}}/api/devices'
auth: inherit
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# List User Devices
`GET /api/devices` — auth: jwt.
Canonical reference: `docs/developer/api/devices/list_devices.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
@@ -0,0 +1,21 @@
info:
name: List Pending Device Registrations:<|end|><|start|><|start|>assistant to=edit<|channel|>analysis <|constrain|>xml<|message|><rfl:parameter name="path">
type: http
seq: 13
http:
method: GET
url: '{{base_url}}/api/devices/pending'
auth: inherit
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# List Pending Device Registrations:<|end|><|start|><|start|>assistant to=edit<|channel|>analysis <|constrain|>xml<|message|><rfl:parameter name="path">
`GET /api/devices/pending` — auth: jwt.
Canonical reference: `docs/developer/api/devices/list_pending_registrations.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
+21
View File
@@ -0,0 +1,21 @@
info:
name: Regenerate Device Token
type: http
seq: 14
http:
method: PUT
url: '{{base_url}}/api/devices/{{device_id}}/regenerate-token'
auth: inherit
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# Regenerate Device Token
`PUT /api/devices/:id/regenerate-token` — auth: jwt.
Canonical reference: `docs/developer/api/devices/regenerate_device_token.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
+29
View File
@@ -0,0 +1,29 @@
info:
name: Register Device
type: http
seq: 15
http:
method: POST
url: '{{base_url}}/api/devices/register'
auth: inherit
body:
type: json
data: |-
{
"device_name": "My Kobo Clara",
"device_type": "kobo",
"device_identifier": "hardware-specific-id"
}
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# Register Device
`POST /api/devices/register` — auth: none.
Canonical reference: `docs/developer/api/devices/register_device.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
@@ -0,0 +1,21 @@
info:
name: Reject Device Registration
type: http
seq: 16
http:
method: POST
url: '{{base_url}}/api/devices/reject/{{registration_id}}'
auth: inherit
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# Reject Device Registration
`POST /api/devices/reject/:registration_id` — auth: jwt.
Canonical reference: `docs/developer/api/devices/reject_device_registration.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
+21
View File
@@ -0,0 +1,21 @@
info:
name: Remove from Shelf
type: http
seq: 17
http:
method: DELETE
url: '{{base_url}}/api/devices/{{device_id}}/shelves'
auth: inherit
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# Remove from Shelf
`DELETE /api/devices/:id/shelves` — auth: jwt.
Canonical reference: `docs/developer/api/devices/remove_from_shelf.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
@@ -1,15 +0,0 @@
info:
name: Add Books to Kobo Shelf
type: http
seq: 1
http:
method: POST
url: '{{baseURL}}/api/devices/{{deviceID}}/shelves'
auth: inherit
body:
type: json
data: "{\n \"media_item_ids\": [\n \"{{bookUUID1"
headers:
- key: Authorization
value: Bearer {{userToken
docs: "## Add Books to Kobo Shelf\n\n Add one or more books to a Kobo device shelf. Manages which books should be synced to a specific Kobo device. Supports multiple shelves for organization.\n\n **Method:** POST\n\n **Endpoint:** /api/devices/{deviceID"
@@ -1,12 +0,0 @@
info:
name: Check Registration Status
type: http
seq: 2
http:
method: POST
url: '{{base_url}}/api/devices/register/status'
auth: none
body:
type: json
data: "{\n \"registration_id\": \"{{registrationId}}"
docs: "## Check Registration Status\n\n Checks the current status of a device registration request.\n\n **Method:** POST\n\n **Endpoint:** /api/devices/register/status\n\n **Authentication:** None\n\n **Request Body:**\n - `registration_id` (string, required): Registration request ID\n\n **Response:**\n - `status` (string): Registration status (pending, approved, rejected, expired)\n - `device_name` (string): Device name\n - `device_type` (string): Device type\n - `created_at` (string): Request timestamp\n - `expires_at` (string): Expiration timestamp\n\n **Status Codes:**\n - 200: Success\n - 404: Registration ID not found\n - 410: Registration expired"
@@ -1,22 +0,0 @@
info:
name: Clear Kobo Shelf
type: http
seq: 1
http:
method: DELETE
url: '{{baseURL}}/api/devices/{{deviceID}}/shelves/clear?shelf={{shelfName}}'
auth: inherit
body:
type: none
headers:
- key: Authorization
value: Bearer {{userToken
docs: |-
## Clear Kobo Shelf
Clear all books from a Kobo device shelf, or all shelves if no shelf name is specified.
**Method:** DELETE
**Endpoint:** /api/devices/{deviceID
@@ -1,19 +0,0 @@
info:
name: Create Device File Alias
type: http
seq: 1
http:
method: POST
url: '{{base_url}}/api/devices/{{device_id}}/file-aliases'
auth: inherit
body:
type: json
data: "{\n \"file_path\": \"/mnt/sd/books/my-book.kepub.epub\",\n \"media_item_id\": \"{{media_item_id"
headers:
- key: Content-Type
value: application/json
runtime:
scripts:
- type: tests
code: "test_create_device_file_alias_success(status, headers, body) {\n if (status !== 201 && status !== 200) {\n throw new Error(\"Expected status 201 or 200, got \" + status);"
docs: "## Create Device File Alias\n\n Creates a new file alias for a device. File aliases map device-specific file paths to media items.\n\n **Method:** POST\n\n **Endpoint:** /api/devices/:id/file-aliases\n\n **Authentication:** Required (Bearer token)\n\n **Path Parameters:**\n - `id` (string, required): Device UUID\n\n **Request Body:**\n - `file_path` (string, required): Device-specific file path\n - `media_item_id` (string, required): Media item UUID to link to\n\n **Response:** Created file alias object\n - `id` (string): Alias UUID\n - `device_id` (string): Device UUID\n - `file_path` (string): Device-specific file path\n - `media_item_id` (string): Associated media item UUID\n - `created_at` (string): Creation timestamp\n - `updated_at` (string): Last update timestamp\n\n **Status Codes:**\n - 201: Created\n - 200: Success\n - 400: Invalid request body\n - 401: Unauthorized\n - 404: Device not found\n - 500: Internal server error"
-22
View File
@@ -1,22 +0,0 @@
info:
name: Delete Device
type: http
seq: 6
http:
method: DELETE
url: '{{base_url}}/api/devices/{{device_id}}'
auth: inherit
body:
type: none
headers:
- key: Authorization
value: Bearer {{token
docs: |-
## Delete Device
Deletes a device and unregisters it from the user's account.
**Method:** DELETE
**Endpoint:** /api/devices/{deviceId
@@ -1,22 +0,0 @@
info:
name: Get Kobo Shelf Books
type: http
seq: 1
http:
method: GET
url: '{{baseURL}}/api/devices/{{deviceID}}/shelves?shelf={{shelfName}}'
auth: inherit
body:
type: none
headers:
- key: Authorization
value: Bearer {{userToken
docs: |-
## Get Kobo Shelf Books
Get all books on a Kobo device shelf, optionally filter by shelf name.
**Method:** GET
**Endpoint:** /api/devices/{deviceID
@@ -1,12 +0,0 @@
info:
name: Initiate Device Registration
type: http
seq: 1
http:
method: POST
url: '{{base_url}}/api/devices/register'
auth: none
body:
type: json
data: "{\n \"device_name\": \"My Kindle Paperwhite\",\n \"device_type\": \"koreader\",\n \"device_identifier\": \"kindle-pw5-hardware-id-12345\""
docs: "## Initiate Device Registration\n\n Initiates a new device registration request that requires admin approval.\n\n **Method:** POST\n\n **Endpoint:** /api/devices/register\n\n **Authentication:** None (open endpoint)\n\n **Request Body:**\n - `device_name` (string, required): Human-readable device name (max 100 chars)\n - `device_type` (string, required): Device type (kobo, koreader, kindle, etc.)\n - `device_identifier` (string, required): Unique hardware ID (max 200 chars)\n\n **Response:**\n - `registration_id` (string): Unique registration request ID\n - `status` (string): Initial status (pending)\n - `expires_at` (string): Expiration timestamp (usually 24 hours)\n - `message` (string): Informational message\n\n **Status Codes:**\n - 201: Registration initiated\n - 400: Invalid request\n - 409: Device already registered"
@@ -1,22 +0,0 @@
info:
name: Remove Book from Kobo Shelf
type: http
seq: 1
http:
method: DELETE
url: '{{baseURL}}/api/devices/{{deviceID}}/shelves?media_item_id={{bookUUID}}'
auth: inherit
body:
type: none
headers:
- key: Authorization
value: Bearer {{userToken
docs: |-
## Remove Book from Kobo Shelf
Remove a specific book from a Kobo device shelf, preventing it from syncing to that device.
**Method:** DELETE
**Endpoint:** /api/devices/{deviceID
-12
View File
@@ -1,12 +0,0 @@
info:
name: Update Device
type: http
seq: 5
http:
method: PUT
url: '{{base_url}}/api/devices/{{device_id}}'
auth: inherit
body:
type: json
data: "{\n \"device_name\": \"My Updated Kindle\",\n \"sync_enabled\": true,\n \"auto_sync\": true,\n \"sync_frequency_minutes\": 10"
docs: "## Update Device\n\n Updates device settings and synchronization preferences.\n\n **Method:** PUT\n\n **Endpoint:** /api/devices/{device_id}\n\n **Authentication:** Required (Bearer token, admin or device owner)\n\n **Path Parameters:**\n - `device_id` (string): Device ID\n\n **Request Body:**\n - `device_name` (string, optional): New device name (max 100 chars)\n - `sync_enabled` (boolean, optional): Enable/disable synchronization\n - `auto_sync` (boolean, optional): Enable automatic synchronization\n - `sync_frequency_minutes` (integer, optional): Sync frequency in minutes (5-1440)\n\n **Response:**\n - Updated device object\n\n **Status Codes:**\n - 200: Success\n - 400: Invalid request\n - 401: Unauthorized\n - 403: Forbidden (not device owner)\n - 404: Device not found"
+30
View File
@@ -0,0 +1,30 @@
info:
name: Update Device
type: http
seq: 18
http:
method: PUT
url: '{{base_url}}/api/devices/{{device_id}}'
auth: inherit
body:
type: json
data: |-
{
"device_name": "My Kobo Clara",
"sync_enabled": true,
"auto_sync": true,
"sync_frequency_minutes": 60
}
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# Update Device
`PUT /api/devices/:id` — auth: jwt.
Canonical reference: `docs/developer/api/devices/update_device.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.
+28
View File
@@ -0,0 +1,28 @@
info:
name: Update Device Collection Mapping
type: http
seq: 19
http:
method: PUT
url: '{{base_url}}/api/devices/{{device_id}}/collections/{{collection_id}}'
auth: inherit
body:
type: json
data: |-
{
"device_shelf_name": "Kobo",
"sync_direction": "bidirectional"
}
settings:
encodeUrl: true
timeout: 0
followRedirects: true
maxRedirects: 5
docs: |-
# Update Device Collection Mapping
`PUT /api/devices/:id/collections/:collectionId` — auth: jwt.
Canonical reference: `docs/developer/api/devices/update_device_mapping.md` (docs site → Developer → API). This request is GENERATED from that doc; edit the doc, not this file.