From a2d3fee4b813a1099373ae577e6195708ddaa808 Mon Sep 17 00:00:00 2001 From: Karolis Strazdas Date: Sun, 4 Oct 2026 00:22:44 +0300 Subject: [PATCH 1/2] docs: refresh architecture and generate a reproducible API reference --- .github/workflows/ci.yml | 36 + .github/workflows/deploy.yml | 8 +- Makefile | 15 +- README.md | 50 +- _static/api.html | 25 + _static/openapi.json | 14493 ++++++++++++++++++++++++++++++ _static/openapi.yaml | 5263 ----------- api/index.rst | 14 +- conf.py | 7 +- design/server-architecture.rst | 128 +- implementation/technologies.rst | 24 +- index.rst | 20 +- pyproject.toml | 1 - uv.lock | 1425 +++ 14 files changed, 16076 insertions(+), 5433 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 _static/api.html create mode 100644 _static/openapi.json delete mode 100644 _static/openapi.yaml create mode 100644 uv.lock diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..06eac26 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,36 @@ +name: Documentation checks + +on: + pull_request: + push: + branches: [master] + workflow_dispatch: + +permissions: + contents: read + +jobs: + documentation: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/checkout@v4 + with: + repository: PapyrusReader/server + ref: d01f2196c006824dd4be494b1ed43ff3223cd700 + path: .server + - uses: astral-sh/setup-uv@v6 + with: + python-version: '3.12' + enable-cache: true + - name: Install Graphviz + run: sudo apt-get update && sudo apt-get install -y graphviz + - name: Install locked documentation dependencies + run: uv sync --locked --extra dev + - name: Check API snapshot + working-directory: .server + run: | + uv sync --locked + uv run --locked python scripts/export_openapi.py ../_static/openapi.json --check + - name: Build documentation + run: make build diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a1a0619..8251a9b 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -20,16 +20,16 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: astral-sh/setup-uv@v6 with: python-version: "3.12" - cache: pip + enable-cache: true - name: Install dependencies - run: pip install -e . + run: uv sync --locked - name: Build site - run: sphinx-build -b html . _build/html + run: uv run --locked sphinx-build -W --keep-going -b html . _build/html - uses: actions/upload-pages-artifact@v3 with: diff --git a/Makefile b/Makefile index bace7b0..6682c73 100644 --- a/Makefile +++ b/Makefile @@ -1,20 +1,19 @@ -.PHONY: help install install-dev serve build clean lint +.PHONY: install install-dev serve build clean lint install: - pip install -e . + uv sync --locked install-dev: - pip install -e ".[dev]" + uv sync --locked --extra dev serve: - sphinx-autobuild . _build/html --port 8000 + uv run --locked sphinx-autobuild . _build/html --port 8000 build: - sphinx-build -b html . _build/html + uv run --locked sphinx-build -W --keep-going -b html . _build/html clean: rm -rf _build/ -lint: - sphinx-build -b html . _build/html - linkchecker _build/html/index.html --check-extern --no-warnings +lint: build + uv run --locked linkchecker _build/html/index.html --check-extern --no-warnings diff --git a/README.md b/README.md index 9a496ab..a24774f 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,41 @@ # Papyrus documentation -The documentation site is built with Sphinx. +Sphinx publishes the product requirements, current architecture, and API reference. +Requirements describe intended capabilities; the implementation chapters describe +current behavior. -## Setup +## Setup and preview -Use Python 3.12 to match the deployment workflow. Install Graphviz and ensure -its `dot` executable is on your `PATH` to render the requirement diagrams. +Install uv, Python 3.12, and Graphviz (`dot` must be on PATH), then run: ```bash -python3.12 -m venv .venv -source .venv/bin/activate -pip install -e ".[dev]" +uv sync --locked --extra dev --python 3.12 +make serve ``` -## Usage +Preview at . `make build` produces `_build/html/` and treats +Sphinx warnings as failures. `make lint` additionally checks external links. +The Deploy workflow builds with the same lock and publishes GitHub Pages on master. -Run these commands from the repository root with the virtual environment active. +## API snapshot -Live preview: +`_static/openapi.json` is generated from the server revision pinned in +[the CI workflow](.github/workflows/ci.yml). To refresh it from the corresponding +server checkout, run there: ```bash -make serve +uv sync --locked +uv run --locked python scripts/export_openapi.py ../docs/_static/openapi.json +uv run --locked python scripts/export_openapi.py ../docs/_static/openapi.json --check ``` -Build the static site: - -```bash -make build -``` - -The development server runs at **** by default. -The generated site is written to `_build/html/`. - -## Deployment +The exporter uses deterministic documentation settings and does not start the +application or connect to a database. Update the CI server revision alongside +intentional API snapshot changes; CI checks freshness against that revision. +Deployment-specific API prefixes and debug routes remain documented by each +server's runtime OpenAPI endpoint. -The [Deploy workflow](.github/workflows/deploy.yml) builds the site with Sphinx -and deploys `_build/html/` to GitHub Pages when changes are pushed to `master`. -It can also be run manually from GitHub Actions. +The [Swagger UI](https://swagger.io/docs/open-source-tools/swagger-ui/usage/installation/) +reference uses version-pinned CDN assets and needs network access. The JSON download +remains available without them. Request execution is disabled on the documentation +site; use a running server's API explorer to make requests. diff --git a/_static/api.html b/_static/api.html new file mode 100644 index 0000000..338f506 --- /dev/null +++ b/_static/api.html @@ -0,0 +1,25 @@ + + + + + + Papyrus REST API + + + +

Download the OpenAPI JSON

+
+ + + + diff --git a/_static/openapi.json b/_static/openapi.json new file mode 100644 index 0000000..3db959f --- /dev/null +++ b/_static/openapi.json @@ -0,0 +1,14493 @@ +{ + "components": { + "schemas": { + "AcquisitionCapabilities": { + "properties": { + "arr_commands": { + "additionalProperties": { + "items": { + "type": "string" + }, + "type": "array" + }, + "propertyNames": { + "$ref": "#/components/schemas/EndpointKind" + }, + "title": "Arr Commands", + "type": "object" + }, + "arr_kinds": { + "items": { + "$ref": "#/components/schemas/EndpointKind" + }, + "title": "Arr Kinds", + "type": "array" + }, + "download_client_kinds": { + "items": { + "$ref": "#/components/schemas/EndpointKind" + }, + "title": "Download Client Kinds", + "type": "array" + }, + "enabled": { + "default": true, + "title": "Enabled", + "type": "boolean" + }, + "endpoint_kinds": { + "items": { + "$ref": "#/components/schemas/EndpointKind" + }, + "title": "Endpoint Kinds", + "type": "array" + }, + "indexer_kinds": { + "items": { + "$ref": "#/components/schemas/EndpointKind" + }, + "title": "Indexer Kinds", + "type": "array" + }, + "managed_downloads_ready": { + "default": false, + "title": "Managed Downloads Ready", + "type": "boolean" + } + }, + "required": [ + "endpoint_kinds", + "indexer_kinds", + "download_client_kinds", + "arr_kinds", + "arr_commands" + ], + "title": "AcquisitionCapabilities", + "type": "object" + }, + "AcquisitionEndpoint": { + "properties": { + "base_url": { + "title": "Base Url", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Created At" + }, + "download_root": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Download Root" + }, + "enabled": { + "title": "Enabled", + "type": "boolean" + }, + "endpoint_id": { + "format": "uuid", + "title": "Endpoint Id", + "type": "string" + }, + "kind": { + "$ref": "#/components/schemas/EndpointKind" + }, + "name": { + "title": "Name", + "type": "string" + }, + "settings": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Settings" + } + }, + "required": [ + "endpoint_id", + "name", + "kind", + "base_url", + "enabled" + ], + "title": "AcquisitionEndpoint", + "type": "object" + }, + "AcquisitionEndpointCreate": { + "properties": { + "api_key": { + "anyOf": [ + { + "format": "password", + "type": "string", + "writeOnly": true + }, + { + "type": "null" + } + ], + "title": "Api Key" + }, + "base_url": { + "format": "uri", + "maxLength": 2083, + "minLength": 1, + "title": "Base Url", + "type": "string" + }, + "download_root": { + "anyOf": [ + { + "maxLength": 2048, + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Download Root" + }, + "kind": { + "$ref": "#/components/schemas/EndpointKind" + }, + "name": { + "maxLength": 120, + "minLength": 1, + "title": "Name", + "type": "string" + }, + "password": { + "anyOf": [ + { + "format": "password", + "type": "string", + "writeOnly": true + }, + { + "type": "null" + } + ], + "title": "Password" + }, + "settings": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Settings" + }, + "username": { + "anyOf": [ + { + "format": "password", + "type": "string", + "writeOnly": true + }, + { + "type": "null" + } + ], + "title": "Username" + } + }, + "required": [ + "name", + "kind", + "base_url" + ], + "title": "AcquisitionEndpointCreate", + "type": "object" + }, + "AcquisitionEndpointTest": { + "properties": { + "api_key": { + "anyOf": [ + { + "format": "password", + "type": "string", + "writeOnly": true + }, + { + "type": "null" + } + ], + "title": "Api Key" + }, + "base_url": { + "anyOf": [ + { + "format": "uri", + "maxLength": 2083, + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Base Url" + }, + "endpoint_id": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Endpoint Id" + }, + "kind": { + "anyOf": [ + { + "$ref": "#/components/schemas/EndpointKind" + }, + { + "type": "null" + } + ] + }, + "password": { + "anyOf": [ + { + "format": "password", + "type": "string", + "writeOnly": true + }, + { + "type": "null" + } + ], + "title": "Password" + }, + "username": { + "anyOf": [ + { + "format": "password", + "type": "string", + "writeOnly": true + }, + { + "type": "null" + } + ], + "title": "Username" + } + }, + "title": "AcquisitionEndpointTest", + "type": "object" + }, + "AcquisitionEndpointTestResult": { + "properties": { + "ok": { + "title": "Ok", + "type": "boolean" + } + }, + "required": [ + "ok" + ], + "title": "AcquisitionEndpointTestResult", + "type": "object" + }, + "AcquisitionEndpointUpdate": { + "properties": { + "api_key": { + "anyOf": [ + { + "format": "password", + "type": "string", + "writeOnly": true + }, + { + "type": "null" + } + ], + "title": "Api Key" + }, + "base_url": { + "anyOf": [ + { + "format": "uri", + "maxLength": 2083, + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Base Url" + }, + "download_root": { + "anyOf": [ + { + "maxLength": 2048, + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Download Root" + }, + "enabled": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Enabled" + }, + "name": { + "anyOf": [ + { + "maxLength": 120, + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Name" + }, + "password": { + "anyOf": [ + { + "format": "password", + "type": "string", + "writeOnly": true + }, + { + "type": "null" + } + ], + "title": "Password" + }, + "settings": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Settings" + }, + "username": { + "anyOf": [ + { + "format": "password", + "type": "string", + "writeOnly": true + }, + { + "type": "null" + } + ], + "title": "Username" + } + }, + "title": "AcquisitionEndpointUpdate", + "type": "object" + }, + "AcquisitionFileCandidate": { + "properties": { + "index": { + "title": "Index", + "type": "integer" + }, + "name": { + "title": "Name", + "type": "string" + }, + "priority": { + "title": "Priority", + "type": "integer" + }, + "progress_basis_points": { + "title": "Progress Basis Points", + "type": "integer" + }, + "size_bytes": { + "title": "Size Bytes", + "type": "integer" + }, + "supported": { + "title": "Supported", + "type": "boolean" + } + }, + "required": [ + "index", + "name", + "size_bytes", + "progress_basis_points", + "priority", + "supported" + ], + "title": "AcquisitionFileCandidate", + "type": "object" + }, + "AcquisitionFileSelectionRequest": { + "properties": { + "file_index": { + "minimum": 0.0, + "title": "File Index", + "type": "integer" + } + }, + "required": [ + "file_index" + ], + "title": "AcquisitionFileSelectionRequest", + "type": "object" + }, + "AcquisitionJob": { + "properties": { + "book_id": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Book Id" + }, + "cancelled_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Cancelled At" + }, + "client_hash": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Client Hash" + }, + "client_reference": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Client Reference" + }, + "client_state": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Client State" + }, + "completed_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Completed At" + }, + "created_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Created At" + }, + "download_speed_bytes_per_second": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Download Speed Bytes Per Second" + }, + "downloaded_bytes": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Downloaded Bytes" + }, + "endpoint_id": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Endpoint Id" + }, + "error": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Error" + }, + "eta_seconds": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Eta Seconds" + }, + "job_id": { + "format": "uuid", + "title": "Job Id", + "type": "string" + }, + "next_poll_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Next Poll At" + }, + "progress_basis_points": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Progress Basis Points" + }, + "retry_count": { + "default": 0, + "title": "Retry Count", + "type": "integer" + }, + "rule_id": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Rule Id" + }, + "selected_file_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Selected File Path" + }, + "started_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Started At" + }, + "status": { + "title": "Status", + "type": "string" + }, + "submitted_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Submitted At" + }, + "title": { + "title": "Title", + "type": "string" + }, + "total_bytes": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Total Bytes" + }, + "updated_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Updated At" + } + }, + "required": [ + "job_id", + "endpoint_id", + "rule_id", + "book_id", + "title", + "status" + ], + "title": "AcquisitionJob", + "type": "object" + }, + "AcquisitionJobPage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/AcquisitionJob" + }, + "title": "Items", + "type": "array" + }, + "limit": { + "title": "Limit", + "type": "integer" + }, + "offset": { + "title": "Offset", + "type": "integer" + }, + "total": { + "title": "Total", + "type": "integer" + } + }, + "required": [ + "items", + "total", + "limit", + "offset" + ], + "title": "AcquisitionJobPage", + "type": "object" + }, + "AcquisitionRule": { + "properties": { + "download_client_id": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Download Client Id" + }, + "enabled": { + "title": "Enabled", + "type": "boolean" + }, + "endpoint_ids": { + "anyOf": [ + { + "items": { + "format": "uuid", + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Endpoint Ids" + }, + "filters": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Filters" + }, + "last_run_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Last Run At" + }, + "name": { + "title": "Name", + "type": "string" + }, + "query": { + "title": "Query", + "type": "string" + }, + "rule_id": { + "format": "uuid", + "title": "Rule Id", + "type": "string" + } + }, + "required": [ + "rule_id", + "name", + "query", + "download_client_id", + "enabled" + ], + "title": "AcquisitionRule", + "type": "object" + }, + "AcquisitionRuleCreate": { + "properties": { + "download_client_id": { + "format": "uuid", + "title": "Download Client Id", + "type": "string" + }, + "enabled": { + "default": true, + "title": "Enabled", + "type": "boolean" + }, + "endpoint_ids": { + "anyOf": [ + { + "items": { + "format": "uuid", + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Endpoint Ids" + }, + "filters": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Filters" + }, + "name": { + "maxLength": 120, + "minLength": 1, + "title": "Name", + "type": "string" + }, + "query": { + "maxLength": 500, + "minLength": 1, + "title": "Query", + "type": "string" + } + }, + "required": [ + "name", + "query", + "download_client_id" + ], + "title": "AcquisitionRuleCreate", + "type": "object" + }, + "Annotation": { + "description": "Annotation response schema.", + "properties": { + "annotation_id": { + "format": "uuid", + "title": "Annotation Id", + "type": "string" + }, + "book_id": { + "format": "uuid", + "title": "Book Id", + "type": "string" + }, + "book_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Book Title" + }, + "chapter_index": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Chapter Index" + }, + "chapter_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Chapter Title" + }, + "created_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Created At" + }, + "end_position": { + "title": "End Position", + "type": "string" + }, + "highlight_color": { + "pattern": "^#[0-9A-Fa-f]{6}$", + "title": "Highlight Color", + "type": "string" + }, + "note": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Note" + }, + "page_number": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Page Number" + }, + "selected_text": { + "title": "Selected Text", + "type": "string" + }, + "start_position": { + "title": "Start Position", + "type": "string" + }, + "updated_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Updated At" + } + }, + "required": [ + "annotation_id", + "book_id", + "selected_text", + "highlight_color", + "start_position", + "end_position" + ], + "title": "Annotation", + "type": "object" + }, + "AnnotationList": { + "description": "Paginated annotation list response.", + "properties": { + "annotations": { + "items": { + "$ref": "#/components/schemas/Annotation" + }, + "title": "Annotations", + "type": "array" + }, + "pagination": { + "$ref": "#/components/schemas/Pagination" + } + }, + "required": [ + "annotations", + "pagination" + ], + "title": "AnnotationList", + "type": "object" + }, + "ArrCommandRequest": { + "description": "A Servarr command and the IDs scoped to that application's library.", + "properties": { + "command": { + "maxLength": 80, + "minLength": 1, + "title": "Command", + "type": "string" + }, + "ids": { + "items": { + "type": "integer" + }, + "maxItems": 100, + "title": "Ids", + "type": "array" + } + }, + "required": [ + "command" + ], + "title": "ArrCommandRequest", + "type": "object" + }, + "AuthTokens": { + "description": "Authentication tokens response.", + "properties": { + "access_token": { + "title": "Access Token", + "type": "string" + }, + "expires_in": { + "description": "Access token expiry in seconds", + "examples": [ + 3600 + ], + "title": "Expires In", + "type": "integer" + }, + "refresh_token": { + "title": "Refresh Token", + "type": "string" + }, + "token_type": { + "default": "Bearer", + "title": "Token Type", + "type": "string" + }, + "user": { + "$ref": "#/components/schemas/User" + } + }, + "required": [ + "access_token", + "refresh_token", + "expires_in", + "user" + ], + "title": "AuthTokens", + "type": "object" + }, + "AuthorizationUrlResponse": { + "description": "Authorization URL returned to the client for browser login.", + "properties": { + "authorization_url": { + "title": "Authorization Url", + "type": "string" + } + }, + "required": [ + "authorization_url" + ], + "title": "AuthorizationUrlResponse", + "type": "object" + }, + "BatchCreateRequest": { + "properties": { + "books": { + "items": { + "$ref": "#/components/schemas/BookCreate" + }, + "title": "Books", + "type": "array" + } + }, + "required": [ + "books" + ], + "title": "BatchCreateRequest", + "type": "object" + }, + "BatchCreateResponse": { + "properties": { + "created": { + "items": { + "$ref": "#/components/schemas/Book" + }, + "title": "Created", + "type": "array" + }, + "errors": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "title": "Errors", + "type": "array" + } + }, + "required": [ + "created", + "errors" + ], + "title": "BatchCreateResponse", + "type": "object" + }, + "BatchDeleteRequest": { + "properties": { + "book_ids": { + "items": { + "format": "uuid", + "type": "string" + }, + "title": "Book Ids", + "type": "array" + }, + "delete_files": { + "default": false, + "title": "Delete Files", + "type": "boolean" + } + }, + "required": [ + "book_ids" + ], + "title": "BatchDeleteRequest", + "type": "object" + }, + "BatchDeleteResponse": { + "properties": { + "deleted_count": { + "title": "Deleted Count", + "type": "integer" + }, + "errors": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "title": "Errors", + "type": "array" + } + }, + "required": [ + "deleted_count", + "errors" + ], + "title": "BatchDeleteResponse", + "type": "object" + }, + "BatchSubmissionItem": { + "properties": { + "error": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Error" + }, + "index": { + "title": "Index", + "type": "integer" + }, + "job": { + "anyOf": [ + { + "$ref": "#/components/schemas/AcquisitionJob" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "index" + ], + "title": "BatchSubmissionItem", + "type": "object" + }, + "BatchSubmissionResponse": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/BatchSubmissionItem" + }, + "title": "Items", + "type": "array" + } + }, + "required": [ + "items" + ], + "title": "BatchSubmissionResponse", + "type": "object" + }, + "BatchSubmitRequest": { + "properties": { + "endpoint_id": { + "format": "uuid", + "title": "Endpoint Id", + "type": "string" + }, + "release_tokens": { + "items": { + "type": "string" + }, + "maxItems": 100, + "minItems": 1, + "title": "Release Tokens", + "type": "array" + } + }, + "required": [ + "endpoint_id", + "release_tokens" + ], + "title": "BatchSubmitRequest", + "type": "object" + }, + "BatchUpdateRequest": { + "properties": { + "add_shelf_ids": { + "anyOf": [ + { + "items": { + "format": "uuid", + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Add Shelf Ids" + }, + "add_tag_ids": { + "anyOf": [ + { + "items": { + "format": "uuid", + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Add Tag Ids" + }, + "book_ids": { + "items": { + "format": "uuid", + "type": "string" + }, + "title": "Book Ids", + "type": "array" + }, + "remove_shelf_ids": { + "anyOf": [ + { + "items": { + "format": "uuid", + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Remove Shelf Ids" + }, + "remove_tag_ids": { + "anyOf": [ + { + "items": { + "format": "uuid", + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Remove Tag Ids" + }, + "updates": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Updates" + } + }, + "required": [ + "book_ids" + ], + "title": "BatchUpdateRequest", + "type": "object" + }, + "BatchUpdateResponse": { + "properties": { + "errors": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "title": "Errors", + "type": "array" + }, + "updated_count": { + "title": "Updated Count", + "type": "integer" + } + }, + "required": [ + "updated_count", + "errors" + ], + "title": "BatchUpdateResponse", + "type": "object" + }, + "Body_upload_book_cover_v1_books__book_id__cover_put": { + "properties": { + "file": { + "anyOf": [ + { + "contentMediaType": "application/octet-stream", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "File" + } + }, + "title": "Body_upload_book_cover_v1_books__book_id__cover_put", + "type": "object" + }, + "Body_upload_file_v1_files_upload_post": { + "properties": { + "file": { + "contentMediaType": "application/octet-stream", + "title": "File", + "type": "string" + } + }, + "required": [ + "file" + ], + "title": "Body_upload_file_v1_files_upload_post", + "type": "object" + }, + "Body_upload_media_v1_media_post": { + "properties": { + "book_id": { + "format": "uuid", + "title": "Book Id", + "type": "string" + }, + "file": { + "contentMediaType": "application/octet-stream", + "title": "File", + "type": "string" + }, + "kind": { + "title": "Kind", + "type": "string" + } + }, + "required": [ + "book_id", + "kind", + "file" + ], + "title": "Body_upload_media_v1_media_post", + "type": "object" + }, + "Book": { + "description": "Full book response schema.", + "properties": { + "added_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Added At" + }, + "author": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Author" + }, + "book_id": { + "format": "uuid", + "title": "Book Id", + "type": "string" + }, + "co_authors": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Co Authors" + }, + "completed_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Completed At" + }, + "cover_image_url": { + "anyOf": [ + { + "format": "uri", + "maxLength": 2083, + "minLength": 1, + "type": "string" + }, + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Cover Image Url" + }, + "current_cfi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Current Cfi" + }, + "current_page": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Current Page" + }, + "current_position": { + "anyOf": [ + { + "maximum": 1.0, + "minimum": 0.0, + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Current Position" + }, + "custom_metadata": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Custom Metadata" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "file_format": { + "anyOf": [ + { + "$ref": "#/components/schemas/FileFormat" + }, + { + "type": "null" + } + ] + }, + "file_hash": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "File Hash" + }, + "file_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "File Path" + }, + "file_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "File Size" + }, + "is_favorite": { + "default": false, + "title": "Is Favorite", + "type": "boolean" + }, + "is_ocr_processed": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Is Ocr Processed" + }, + "is_physical": { + "default": false, + "title": "Is Physical", + "type": "boolean" + }, + "isbn": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Isbn" + }, + "isbn13": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Isbn13" + }, + "language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "examples": [ + "en" + ], + "title": "Language" + }, + "last_read_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Last Read At" + }, + "lent_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Lent At" + }, + "lent_to": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Lent To" + }, + "ocr_confidence": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Ocr Confidence" + }, + "page_count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Page Count" + }, + "physical_location": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Physical Location" + }, + "publication_date": { + "anyOf": [ + { + "format": "date", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Publication Date" + }, + "publisher": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Publisher" + }, + "rating": { + "anyOf": [ + { + "maximum": 5.0, + "minimum": 1.0, + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Rating" + }, + "reading_status": { + "anyOf": [ + { + "$ref": "#/components/schemas/ReadingStatus" + }, + { + "type": "null" + } + ] + }, + "series_id": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Series Id" + }, + "series_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Series Name" + }, + "series_number": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Series Number" + }, + "shelves": { + "anyOf": [ + { + "items": { + "$ref": "#/components/schemas/ShelfSummary" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Shelves" + }, + "started_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Started At" + }, + "storage_backend_id": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Storage Backend Id" + }, + "subtitle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Subtitle" + }, + "tags": { + "anyOf": [ + { + "items": { + "$ref": "#/components/schemas/Tag" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Tags" + }, + "title": { + "title": "Title", + "type": "string" + }, + "updated_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Updated At" + } + }, + "required": [ + "book_id", + "title" + ], + "title": "Book", + "type": "object" + }, + "BookBreakdown": { + "description": "Per-book reading statistics.", + "properties": { + "book_id": { + "format": "uuid", + "title": "Book Id", + "type": "string" + }, + "pages_read": { + "title": "Pages Read", + "type": "integer" + }, + "reading_time_minutes": { + "title": "Reading Time Minutes", + "type": "integer" + }, + "sessions_count": { + "title": "Sessions Count", + "type": "integer" + }, + "title": { + "title": "Title", + "type": "string" + } + }, + "required": [ + "book_id", + "title", + "reading_time_minutes", + "pages_read", + "sessions_count" + ], + "title": "BookBreakdown", + "type": "object" + }, + "BookCreate": { + "description": "Book creation request.", + "properties": { + "author": { + "maxLength": 255, + "title": "Author", + "type": "string" + }, + "co_authors": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Co Authors" + }, + "cover_image_url": { + "anyOf": [ + { + "format": "uri", + "maxLength": 2083, + "minLength": 1, + "type": "string" + }, + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Cover Image Url" + }, + "custom_metadata": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Custom Metadata" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "file_format": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "File Format" + }, + "file_hash": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "File Hash" + }, + "file_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Path returned from file upload", + "title": "File Path" + }, + "file_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "File Size" + }, + "is_physical": { + "default": false, + "title": "Is Physical", + "type": "boolean" + }, + "isbn": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Isbn" + }, + "isbn13": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Isbn13" + }, + "language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": "en", + "title": "Language" + }, + "page_count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Page Count" + }, + "physical_location": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Physical Location" + }, + "publication_date": { + "anyOf": [ + { + "format": "date", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Publication Date" + }, + "publisher": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Publisher" + }, + "series_id": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Series Id" + }, + "series_number": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Series Number" + }, + "shelf_ids": { + "anyOf": [ + { + "items": { + "format": "uuid", + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Shelf Ids" + }, + "storage_backend_id": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Storage Backend Id" + }, + "subtitle": { + "anyOf": [ + { + "maxLength": 500, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Subtitle" + }, + "tag_ids": { + "anyOf": [ + { + "items": { + "format": "uuid", + "type": "string" + }, + "maxItems": 10, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Tag Ids" + }, + "title": { + "maxLength": 500, + "title": "Title", + "type": "string" + } + }, + "required": [ + "title", + "author" + ], + "title": "BookCreate", + "type": "object" + }, + "BookList": { + "description": "Paginated book list response.", + "properties": { + "books": { + "items": { + "$ref": "#/components/schemas/Book" + }, + "title": "Books", + "type": "array" + }, + "pagination": { + "$ref": "#/components/schemas/Pagination" + } + }, + "required": [ + "books", + "pagination" + ], + "title": "BookList", + "type": "object" + }, + "BookSummary": { + "description": "Minimal book information for lists.", + "properties": { + "author": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Author" + }, + "book_id": { + "format": "uuid", + "title": "Book Id", + "type": "string" + }, + "cover_image_url": { + "anyOf": [ + { + "format": "uri", + "maxLength": 2083, + "minLength": 1, + "type": "string" + }, + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Cover Image Url" + }, + "current_position": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Current Position" + }, + "is_favorite": { + "default": false, + "title": "Is Favorite", + "type": "boolean" + }, + "rating": { + "anyOf": [ + { + "maximum": 5.0, + "minimum": 1.0, + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Rating" + }, + "reading_status": { + "anyOf": [ + { + "$ref": "#/components/schemas/ReadingStatus" + }, + { + "type": "null" + } + ] + }, + "title": { + "title": "Title", + "type": "string" + } + }, + "required": [ + "book_id", + "title" + ], + "title": "BookSummary", + "type": "object" + }, + "BookUpdate": { + "description": "Book update request.", + "properties": { + "author": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Author" + }, + "co_authors": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Co Authors" + }, + "cover_image_url": { + "anyOf": [ + { + "format": "uri", + "maxLength": 2083, + "minLength": 1, + "type": "string" + }, + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Cover Image Url" + }, + "custom_metadata": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Custom Metadata" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "is_favorite": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Is Favorite" + }, + "is_physical": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Is Physical" + }, + "isbn": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Isbn" + }, + "isbn13": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Isbn13" + }, + "language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Language" + }, + "lent_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Lent At" + }, + "lent_to": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Lent To" + }, + "page_count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Page Count" + }, + "physical_location": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Physical Location" + }, + "publication_date": { + "anyOf": [ + { + "format": "date", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Publication Date" + }, + "publisher": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Publisher" + }, + "rating": { + "anyOf": [ + { + "maximum": 5.0, + "minimum": 1.0, + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Rating" + }, + "reading_status": { + "anyOf": [ + { + "$ref": "#/components/schemas/ReadingStatus" + }, + { + "type": "null" + } + ] + }, + "series_id": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Series Id" + }, + "series_number": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Series Number" + }, + "subtitle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Subtitle" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Title" + } + }, + "title": "BookUpdate", + "type": "object" + }, + "Bookmark": { + "description": "Bookmark response schema.", + "properties": { + "book_id": { + "format": "uuid", + "title": "Book Id", + "type": "string" + }, + "bookmark_id": { + "format": "uuid", + "title": "Bookmark Id", + "type": "string" + }, + "chapter_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Chapter Title" + }, + "color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Color" + }, + "created_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Created At" + }, + "note": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Note" + }, + "page_number": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Page Number" + }, + "position": { + "title": "Position", + "type": "string" + } + }, + "required": [ + "bookmark_id", + "book_id", + "position" + ], + "title": "Bookmark", + "type": "object" + }, + "BookmarkList": { + "description": "Bookmark list response.", + "properties": { + "bookmarks": { + "items": { + "$ref": "#/components/schemas/Bookmark" + }, + "title": "Bookmarks", + "type": "array" + } + }, + "required": [ + "bookmarks" + ], + "title": "BookmarkList", + "type": "object" + }, + "ChangePasswordRequest": { + "description": "Password change request.", + "properties": { + "current_password": { + "title": "Current Password", + "type": "string" + }, + "new_password": { + "minLength": 8, + "title": "New Password", + "type": "string" + } + }, + "required": [ + "current_password", + "new_password" + ], + "title": "ChangePasswordRequest", + "type": "object" + }, + "ConnectionStatus": { + "description": "Storage backend connection status.", + "enum": [ + "connected", + "disconnected", + "error" + ], + "title": "ConnectionStatus", + "type": "string" + }, + "CreateAnnotationRequest": { + "description": "Annotation creation request.", + "properties": { + "chapter_index": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Chapter Index" + }, + "chapter_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Chapter Title" + }, + "end_position": { + "title": "End Position", + "type": "string" + }, + "highlight_color": { + "default": "#FFEB3B", + "pattern": "^#[0-9A-Fa-f]{6}$", + "title": "Highlight Color", + "type": "string" + }, + "note": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Note" + }, + "page_number": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Page Number" + }, + "selected_text": { + "title": "Selected Text", + "type": "string" + }, + "start_position": { + "description": "CFI or offset", + "title": "Start Position", + "type": "string" + } + }, + "required": [ + "selected_text", + "start_position", + "end_position" + ], + "title": "CreateAnnotationRequest", + "type": "object" + }, + "CreateBookmarkRequest": { + "description": "Bookmark creation request.", + "properties": { + "chapter_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Chapter Title" + }, + "color": { + "default": "#FF5722", + "pattern": "^#[0-9A-Fa-f]{6}$", + "title": "Color", + "type": "string" + }, + "note": { + "anyOf": [ + { + "maxLength": 500, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Note" + }, + "page_number": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Page Number" + }, + "position": { + "description": "CFI, page number, or offset", + "title": "Position", + "type": "string" + } + }, + "required": [ + "position" + ], + "title": "CreateBookmarkRequest", + "type": "object" + }, + "CreateGoalRequest": { + "description": "Goal creation request.", + "properties": { + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "end_date": { + "format": "date", + "title": "End Date", + "type": "string" + }, + "goal_type": { + "$ref": "#/components/schemas/GoalType" + }, + "start_date": { + "format": "date", + "title": "Start Date", + "type": "string" + }, + "target_value": { + "minimum": 1.0, + "title": "Target Value", + "type": "integer" + }, + "time_period": { + "$ref": "#/components/schemas/TimePeriod" + }, + "title": { + "maxLength": 255, + "title": "Title", + "type": "string" + } + }, + "required": [ + "title", + "goal_type", + "target_value", + "time_period", + "start_date", + "end_date" + ], + "title": "CreateGoalRequest", + "type": "object" + }, + "CreateNoteRequest": { + "description": "Note creation request.", + "properties": { + "content": { + "title": "Content", + "type": "string" + }, + "is_pinned": { + "default": false, + "title": "Is Pinned", + "type": "boolean" + }, + "title": { + "maxLength": 255, + "title": "Title", + "type": "string" + } + }, + "required": [ + "title", + "content" + ], + "title": "CreateNoteRequest", + "type": "object" + }, + "CreateReadingProfileRequest": { + "description": "Reading profile creation request.", + "properties": { + "background_color": { + "default": "#FFFFFF", + "pattern": "^#[0-9A-Fa-f]{6}$", + "title": "Background Color", + "type": "string" + }, + "column_count": { + "default": 1, + "title": "Column Count", + "type": "integer" + }, + "font_family": { + "default": "Georgia", + "title": "Font Family", + "type": "string" + }, + "font_size": { + "default": 16, + "title": "Font Size", + "type": "integer" + }, + "font_weight": { + "default": 400, + "title": "Font Weight", + "type": "integer" + }, + "hyphenation": { + "default": true, + "title": "Hyphenation", + "type": "boolean" + }, + "is_default": { + "default": false, + "title": "Is Default", + "type": "boolean" + }, + "letter_spacing": { + "default": 0, + "title": "Letter Spacing", + "type": "number" + }, + "line_height": { + "default": 1.5, + "title": "Line Height", + "type": "number" + }, + "link_color": { + "default": "#0066CC", + "pattern": "^#[0-9A-Fa-f]{6}$", + "title": "Link Color", + "type": "string" + }, + "margin_horizontal": { + "default": 20, + "title": "Margin Horizontal", + "type": "integer" + }, + "margin_vertical": { + "default": 20, + "title": "Margin Vertical", + "type": "integer" + }, + "name": { + "maxLength": 100, + "title": "Name", + "type": "string" + }, + "page_turn_animation": { + "default": true, + "title": "Page Turn Animation", + "type": "boolean" + }, + "paragraph_spacing": { + "default": 1.0, + "title": "Paragraph Spacing", + "type": "number" + }, + "reading_mode": { + "anyOf": [ + { + "$ref": "#/components/schemas/ReadingMode" + }, + { + "type": "null" + } + ] + }, + "selection_color": { + "default": "#B3D4FC", + "pattern": "^#[0-9A-Fa-f]{6}$", + "title": "Selection Color", + "type": "string" + }, + "text_align": { + "anyOf": [ + { + "$ref": "#/components/schemas/TextAlign" + }, + { + "type": "null" + } + ] + }, + "text_color": { + "default": "#000000", + "pattern": "^#[0-9A-Fa-f]{6}$", + "title": "Text Color", + "type": "string" + }, + "theme_mode": { + "anyOf": [ + { + "$ref": "#/components/schemas/ThemeMode" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "name" + ], + "title": "CreateReadingProfileRequest", + "type": "object" + }, + "CreateReadingSessionRequest": { + "description": "Reading session creation request.", + "properties": { + "book_id": { + "format": "uuid", + "title": "Book Id", + "type": "string" + }, + "device_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Device Name" + }, + "device_type": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Device Type" + }, + "end_position": { + "anyOf": [ + { + "maximum": 1.0, + "minimum": 0.0, + "type": "number" + }, + { + "type": "null" + } + ], + "title": "End Position" + }, + "end_time": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "End Time" + }, + "pages_read": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Pages Read" + }, + "start_position": { + "anyOf": [ + { + "maximum": 1.0, + "minimum": 0.0, + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Start Position" + }, + "start_time": { + "format": "date-time", + "title": "Start Time", + "type": "string" + } + }, + "required": [ + "book_id", + "start_time" + ], + "title": "CreateReadingSessionRequest", + "type": "object" + }, + "CreateSavedFilterRequest": { + "description": "Saved filter creation request.", + "properties": { + "color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Color" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "filter_type": { + "anyOf": [ + { + "$ref": "#/components/schemas/FilterType" + }, + { + "type": "null" + } + ] + }, + "icon": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Icon" + }, + "is_pinned": { + "default": false, + "title": "Is Pinned", + "type": "boolean" + }, + "name": { + "maxLength": 100, + "title": "Name", + "type": "string" + }, + "query": { + "maxLength": 1000, + "title": "Query", + "type": "string" + } + }, + "required": [ + "name", + "query" + ], + "title": "CreateSavedFilterRequest", + "type": "object" + }, + "CreateSeriesRequest": { + "description": "Series creation request.", + "properties": { + "author": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Author" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "is_complete": { + "default": false, + "title": "Is Complete", + "type": "boolean" + }, + "name": { + "maxLength": 255, + "title": "Name", + "type": "string" + }, + "total_books": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Total Books" + } + }, + "required": [ + "name" + ], + "title": "CreateSeriesRequest", + "type": "object" + }, + "CreateShelfRequest": { + "description": "Shelf creation request.", + "properties": { + "color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Color" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "icon": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Icon" + }, + "is_smart": { + "default": false, + "title": "Is Smart", + "type": "boolean" + }, + "name": { + "maxLength": 100, + "title": "Name", + "type": "string" + }, + "parent_shelf_id": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Parent Shelf Id" + }, + "smart_query": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Smart Query" + }, + "sort_order": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Sort Order" + } + }, + "required": [ + "name" + ], + "title": "CreateShelfRequest", + "type": "object" + }, + "CreateStorageBackendRequest": { + "description": "Storage backend creation request.", + "properties": { + "backend_type": { + "$ref": "#/components/schemas/StorageBackendType" + }, + "base_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Base Path" + }, + "connection_config": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Type-specific connection settings", + "title": "Connection Config" + }, + "credentials": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "OAuth tokens or API keys", + "title": "Credentials" + }, + "is_primary": { + "default": false, + "title": "Is Primary", + "type": "boolean" + }, + "name": { + "maxLength": 100, + "title": "Name", + "type": "string" + } + }, + "required": [ + "backend_type", + "name" + ], + "title": "CreateStorageBackendRequest", + "type": "object" + }, + "CreateTagRequest": { + "description": "Tag creation request.", + "properties": { + "color": { + "pattern": "^#[0-9A-Fa-f]{6}$", + "title": "Color", + "type": "string" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "name": { + "maxLength": 50, + "title": "Name", + "type": "string" + } + }, + "required": [ + "name", + "color" + ], + "title": "CreateTagRequest", + "type": "object" + }, + "DailyBreakdown": { + "description": "Daily reading statistics.", + "properties": { + "date": { + "format": "date", + "title": "Date", + "type": "string" + }, + "pages_read": { + "title": "Pages Read", + "type": "integer" + }, + "reading_time_minutes": { + "title": "Reading Time Minutes", + "type": "integer" + }, + "sessions_count": { + "title": "Sessions Count", + "type": "integer" + } + }, + "required": [ + "date", + "reading_time_minutes", + "pages_read", + "sessions_count" + ], + "title": "DailyBreakdown", + "type": "object" + }, + "DataSyncSettingsResponse": { + "description": "Public sync settings used by clients for custom server discovery.", + "properties": { + "data_sync_url": { + "title": "Data Sync Url", + "type": "string" + }, + "file_storage": { + "$ref": "#/components/schemas/FileStorageSettings" + } + }, + "required": [ + "data_sync_url", + "file_storage" + ], + "title": "DataSyncSettingsResponse", + "type": "object" + }, + "DeleteAccountRequest": { + "description": "Account deletion request.", + "properties": { + "password": { + "description": "Current password for confirmation", + "title": "Password", + "type": "string" + } + }, + "required": [ + "password" + ], + "title": "DeleteAccountRequest", + "type": "object" + }, + "EndpointKind": { + "enum": [ + "qbittorrent", + "transmission", + "deluge", + "prowlarr", + "torznab", + "readarr", + "sonarr", + "radarr", + "lidarr", + "whisparr" + ], + "title": "EndpointKind", + "type": "string" + }, + "ExportAnnotationsRequest": { + "description": "Request for exporting annotations.", + "properties": { + "book_ids": { + "anyOf": [ + { + "items": { + "format": "uuid", + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Book Ids" + }, + "format": { + "$ref": "#/components/schemas/ExportFormat", + "default": "json" + }, + "include_bookmarks": { + "default": false, + "title": "Include Bookmarks", + "type": "boolean" + }, + "include_notes": { + "default": true, + "title": "Include Notes", + "type": "boolean" + } + }, + "title": "ExportAnnotationsRequest", + "type": "object" + }, + "ExportAnnotationsResponse": { + "description": "Response containing exported annotations.", + "properties": { + "content": { + "title": "Content", + "type": "string" + }, + "filename": { + "title": "Filename", + "type": "string" + }, + "format": { + "$ref": "#/components/schemas/ExportFormat" + } + }, + "required": [ + "format", + "content", + "filename" + ], + "title": "ExportAnnotationsResponse", + "type": "object" + }, + "ExportFormat": { + "description": "Annotation export formats.", + "enum": [ + "json", + "markdown", + "csv", + "html" + ], + "title": "ExportFormat", + "type": "string" + }, + "FileFormat": { + "description": "Supported ebook file formats.", + "enum": [ + "epub", + "pdf", + "mobi", + "azw3", + "txt", + "cbr", + "cbz" + ], + "title": "FileFormat", + "type": "string" + }, + "FileInfo": { + "description": "File information response schema.", + "properties": { + "file_format": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "File Format" + }, + "file_hash": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "SHA-256 checksum", + "title": "File Hash" + }, + "file_path": { + "description": "Relative path in storage", + "title": "File Path", + "type": "string" + }, + "file_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "File Size" + }, + "storage_backend_id": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Storage Backend Id" + }, + "uploaded_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Uploaded At" + } + }, + "required": [ + "file_path" + ], + "title": "FileInfo", + "type": "object" + }, + "FileStorageSettings": { + "description": "Public file storage capability advertised by this server.", + "properties": { + "quota_bytes": { + "title": "Quota Bytes", + "type": "integer" + }, + "supported": { + "title": "Supported", + "type": "boolean" + } + }, + "required": [ + "supported", + "quota_bytes" + ], + "title": "FileStorageSettings", + "type": "object" + }, + "FilterType": { + "description": "Filter type options.", + "enum": [ + "search", + "shelf", + "custom" + ], + "title": "FilterType", + "type": "string" + }, + "ForgotPasswordRequest": { + "description": "Password recovery request.", + "properties": { + "email": { + "format": "email", + "title": "Email", + "type": "string" + } + }, + "required": [ + "email" + ], + "title": "ForgotPasswordRequest", + "type": "object" + }, + "Goal": { + "description": "Goal response schema.", + "properties": { + "completed_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Completed At" + }, + "created_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Created At" + }, + "current_value": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Current Value" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "end_date": { + "format": "date", + "title": "End Date", + "type": "string" + }, + "goal_id": { + "format": "uuid", + "title": "Goal Id", + "type": "string" + }, + "goal_type": { + "$ref": "#/components/schemas/GoalType" + }, + "is_active": { + "default": true, + "title": "Is Active", + "type": "boolean" + }, + "is_completed": { + "default": false, + "title": "Is Completed", + "type": "boolean" + }, + "progress_percentage": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Progress Percentage" + }, + "start_date": { + "format": "date", + "title": "Start Date", + "type": "string" + }, + "target_value": { + "title": "Target Value", + "type": "integer" + }, + "time_period": { + "$ref": "#/components/schemas/TimePeriod" + }, + "title": { + "title": "Title", + "type": "string" + }, + "updated_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Updated At" + } + }, + "required": [ + "goal_id", + "title", + "goal_type", + "target_value", + "time_period", + "start_date", + "end_date" + ], + "title": "Goal", + "type": "object" + }, + "GoalList": { + "description": "Goal list response.", + "properties": { + "goals": { + "items": { + "$ref": "#/components/schemas/Goal" + }, + "title": "Goals", + "type": "array" + } + }, + "required": [ + "goals" + ], + "title": "GoalList", + "type": "object" + }, + "GoalType": { + "description": "Type of reading goal.", + "enum": [ + "books_count", + "pages_count", + "reading_time" + ], + "title": "GoalType", + "type": "string" + }, + "HTTPValidationError": { + "properties": { + "detail": { + "items": { + "$ref": "#/components/schemas/ValidationError" + }, + "title": "Detail", + "type": "array" + } + }, + "title": "HTTPValidationError", + "type": "object" + }, + "LoginRequest": { + "description": "User login request.", + "properties": { + "client_type": { + "default": "unknown", + "enum": [ + "mobile", + "desktop", + "web", + "unknown" + ], + "title": "Client Type", + "type": "string" + }, + "device_label": { + "anyOf": [ + { + "maxLength": 255, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Device Label" + }, + "email": { + "format": "email", + "title": "Email", + "type": "string" + }, + "password": { + "title": "Password", + "type": "string" + } + }, + "required": [ + "email", + "password" + ], + "title": "LoginRequest", + "type": "object" + }, + "LogoutRequest": { + "description": "Logout request.", + "properties": { + "all_devices": { + "default": false, + "description": "Logout from all devices", + "title": "All Devices", + "type": "boolean" + } + }, + "title": "LogoutRequest", + "type": "object" + }, + "MediaAssetResponse": { + "description": "Uploaded media asset metadata.", + "properties": { + "asset_id": { + "format": "uuid", + "title": "Asset Id", + "type": "string" + }, + "book_id": { + "format": "uuid", + "title": "Book Id", + "type": "string" + }, + "content_type": { + "title": "Content Type", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Created At" + }, + "extension": { + "title": "Extension", + "type": "string" + }, + "kind": { + "title": "Kind", + "type": "string" + }, + "original_filename": { + "title": "Original Filename", + "type": "string" + }, + "owner_user_id": { + "format": "uuid", + "title": "Owner User Id", + "type": "string" + }, + "sha256": { + "title": "Sha256", + "type": "string" + }, + "size_bytes": { + "title": "Size Bytes", + "type": "integer" + }, + "storage_path": { + "title": "Storage Path", + "type": "string" + }, + "updated_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Updated At" + } + }, + "required": [ + "asset_id", + "owner_user_id", + "book_id", + "kind", + "original_filename", + "content_type", + "extension", + "size_bytes", + "sha256", + "storage_path" + ], + "title": "MediaAssetResponse", + "type": "object" + }, + "MediaUsageResponse": { + "description": "User media storage quota usage.", + "properties": { + "available_bytes": { + "title": "Available Bytes", + "type": "integer" + }, + "quota_bytes": { + "title": "Quota Bytes", + "type": "integer" + }, + "used_bytes": { + "title": "Used Bytes", + "type": "integer" + } + }, + "required": [ + "used_bytes", + "quota_bytes", + "available_bytes" + ], + "title": "MediaUsageResponse", + "type": "object" + }, + "MessageResponse": { + "description": "Simple message response.", + "properties": { + "message": { + "title": "Message", + "type": "string" + } + }, + "required": [ + "message" + ], + "title": "MessageResponse", + "type": "object" + }, + "MetadataFetchRequest": { + "properties": { + "author": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Author" + }, + "isbn": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Isbn" + }, + "title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Title" + } + }, + "title": "MetadataFetchRequest", + "type": "object" + }, + "MetadataFetchResponse": { + "properties": { + "results": { + "items": { + "$ref": "#/components/schemas/MetadataSearchResult" + }, + "title": "Results", + "type": "array" + } + }, + "required": [ + "results" + ], + "title": "MetadataFetchResponse", + "type": "object" + }, + "MetadataSearchResult": { + "description": "Book metadata search result from external sources.", + "properties": { + "author": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Author" + }, + "cover_image_url": { + "anyOf": [ + { + "format": "uri", + "maxLength": 2083, + "minLength": 1, + "type": "string" + }, + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Cover Image Url" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "isbn": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Isbn" + }, + "isbn13": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Isbn13" + }, + "language": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Language" + }, + "page_count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Page Count" + }, + "publication_date": { + "anyOf": [ + { + "format": "date", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Publication Date" + }, + "publisher": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Publisher" + }, + "source": { + "examples": [ + "open_library", + "google_books" + ], + "title": "Source", + "type": "string" + }, + "title": { + "title": "Title", + "type": "string" + } + }, + "required": [ + "source", + "title" + ], + "title": "MetadataSearchResult", + "type": "object" + }, + "Note": { + "description": "Note response schema.", + "properties": { + "book_id": { + "format": "uuid", + "title": "Book Id", + "type": "string" + }, + "book_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Book Title" + }, + "content": { + "title": "Content", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Created At" + }, + "is_pinned": { + "default": false, + "title": "Is Pinned", + "type": "boolean" + }, + "note_id": { + "format": "uuid", + "title": "Note Id", + "type": "string" + }, + "title": { + "title": "Title", + "type": "string" + }, + "updated_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Updated At" + } + }, + "required": [ + "note_id", + "book_id", + "title", + "content" + ], + "title": "Note", + "type": "object" + }, + "NoteList": { + "description": "Paginated note list response.", + "properties": { + "notes": { + "items": { + "$ref": "#/components/schemas/Note" + }, + "title": "Notes", + "type": "array" + }, + "pagination": { + "$ref": "#/components/schemas/Pagination" + } + }, + "required": [ + "notes", + "pagination" + ], + "title": "NoteList", + "type": "object" + }, + "OAuthExchangeRequest": { + "description": "Exchange a one-time code for Papyrus tokens.", + "properties": { + "client_type": { + "default": "unknown", + "enum": [ + "mobile", + "desktop", + "web", + "unknown" + ], + "title": "Client Type", + "type": "string" + }, + "code": { + "description": "One-time exchange code returned from the browser callback", + "title": "Code", + "type": "string" + }, + "device_label": { + "anyOf": [ + { + "maxLength": 255, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Device Label" + } + }, + "required": [ + "code" + ], + "title": "OAuthExchangeRequest", + "type": "object" + }, + "OAuthLinkCompleteRequest": { + "description": "Consume a one-time exchange code to link a provider.", + "properties": { + "code": { + "description": "One-time exchange code returned from the browser callback", + "title": "Code", + "type": "string" + } + }, + "required": [ + "code" + ], + "title": "OAuthLinkCompleteRequest", + "type": "object" + }, + "OAuthStartRequest": { + "description": "OAuth flow bootstrap request.", + "properties": { + "redirect_uri": { + "description": "App callback URI for the browser flow", + "title": "Redirect Uri", + "type": "string" + } + }, + "required": [ + "redirect_uri" + ], + "title": "OAuthStartRequest", + "type": "object" + }, + "OpdsCredentials": { + "additionalProperties": false, + "properties": { + "password": { + "format": "password", + "maxLength": 4096, + "title": "Password", + "type": "string", + "writeOnly": true + }, + "username": { + "maxLength": 1024, + "pattern": "^[^:\\r\\n]*$", + "title": "Username", + "type": "string" + } + }, + "required": [ + "username", + "password" + ], + "title": "OpdsCredentials", + "type": "object" + }, + "OpdsRelayRequest": { + "additionalProperties": false, + "properties": { + "catalog_url": { + "maxLength": 8192, + "minLength": 1, + "title": "Catalog Url", + "type": "string" + }, + "credentials": { + "anyOf": [ + { + "$ref": "#/components/schemas/OpdsCredentials" + }, + { + "type": "null" + } + ] + }, + "max_bytes": { + "default": 8388608, + "maximum": 268435456.0, + "minimum": 1.0, + "title": "Max Bytes", + "type": "integer" + }, + "url": { + "maxLength": 8192, + "minLength": 1, + "title": "Url", + "type": "string" + } + }, + "required": [ + "url", + "catalog_url" + ], + "title": "OpdsRelayRequest", + "type": "object" + }, + "Pagination": { + "description": "Pagination metadata.", + "properties": { + "has_next": { + "examples": [ + true + ], + "title": "Has Next", + "type": "boolean" + }, + "has_prev": { + "examples": [ + false + ], + "title": "Has Prev", + "type": "boolean" + }, + "limit": { + "examples": [ + 20 + ], + "maximum": 100.0, + "minimum": 1.0, + "title": "Limit", + "type": "integer" + }, + "page": { + "examples": [ + 1 + ], + "minimum": 1.0, + "title": "Page", + "type": "integer" + }, + "total": { + "examples": [ + 150 + ], + "minimum": 0.0, + "title": "Total", + "type": "integer" + }, + "total_pages": { + "examples": [ + 8 + ], + "minimum": 0.0, + "title": "Total Pages", + "type": "integer" + } + }, + "required": [ + "page", + "limit", + "total", + "total_pages", + "has_next", + "has_prev" + ], + "title": "Pagination", + "type": "object" + }, + "PowerSyncCrudMutation": { + "description": "One owned library mutation uploaded from the PowerSync queue.", + "properties": { + "data": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Data" + }, + "id": { + "title": "Id", + "type": "string" + }, + "op": { + "enum": [ + "PUT", + "PATCH", + "DELETE", + "put", + "patch", + "delete" + ], + "title": "Op", + "type": "string" + }, + "op_id": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Op Id" + }, + "tx_id": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Tx Id" + }, + "type": { + "enum": [ + "books", + "shelves", + "tags", + "notes", + "annotations", + "bookmarks", + "book_shelves", + "book_tags" + ], + "title": "Type", + "type": "string" + } + }, + "required": [ + "type", + "op", + "id" + ], + "title": "PowerSyncCrudMutation", + "type": "object" + }, + "PowerSyncTokenResponse": { + "description": "Short-lived PowerSync token response.", + "properties": { + "expires_in": { + "title": "Expires In", + "type": "integer" + }, + "token": { + "title": "Token", + "type": "string" + } + }, + "required": [ + "token", + "expires_in" + ], + "title": "PowerSyncTokenResponse", + "type": "object" + }, + "PowerSyncUploadRequest": { + "description": "One PowerSync CRUD transaction.", + "properties": { + "batch": { + "items": { + "$ref": "#/components/schemas/PowerSyncCrudMutation" + }, + "title": "Batch", + "type": "array" + } + }, + "required": [ + "batch" + ], + "title": "PowerSyncUploadRequest", + "type": "object" + }, + "PowerSyncUploadResponse": { + "description": "Summary of an applied PowerSync upload transaction.", + "properties": { + "applied_count": { + "title": "Applied Count", + "type": "integer" + } + }, + "required": [ + "applied_count" + ], + "title": "PowerSyncUploadResponse", + "type": "object" + }, + "ReadingMode": { + "description": "Reading display modes.", + "enum": [ + "paginated", + "continuous" + ], + "title": "ReadingMode", + "type": "string" + }, + "ReadingProfile": { + "description": "Reading profile response schema.", + "properties": { + "background_color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Background Color" + }, + "column_count": { + "anyOf": [ + { + "maximum": 3.0, + "minimum": 1.0, + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Column Count" + }, + "created_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Created At" + }, + "font_family": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Font Family" + }, + "font_size": { + "anyOf": [ + { + "maximum": 72.0, + "minimum": 8.0, + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Font Size" + }, + "font_weight": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Font Weight" + }, + "hyphenation": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Hyphenation" + }, + "is_default": { + "default": false, + "title": "Is Default", + "type": "boolean" + }, + "letter_spacing": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Letter Spacing" + }, + "line_height": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Line Height" + }, + "link_color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Link Color" + }, + "margin_horizontal": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Margin Horizontal" + }, + "margin_vertical": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Margin Vertical" + }, + "name": { + "title": "Name", + "type": "string" + }, + "page_turn_animation": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Page Turn Animation" + }, + "paragraph_spacing": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Paragraph Spacing" + }, + "profile_id": { + "format": "uuid", + "title": "Profile Id", + "type": "string" + }, + "reading_mode": { + "anyOf": [ + { + "$ref": "#/components/schemas/ReadingMode" + }, + { + "type": "null" + } + ] + }, + "selection_color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Selection Color" + }, + "text_align": { + "anyOf": [ + { + "$ref": "#/components/schemas/TextAlign" + }, + { + "type": "null" + } + ] + }, + "text_color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Text Color" + }, + "theme_mode": { + "anyOf": [ + { + "$ref": "#/components/schemas/ThemeMode" + }, + { + "type": "null" + } + ] + }, + "updated_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Updated At" + } + }, + "required": [ + "profile_id", + "name" + ], + "title": "ReadingProfile", + "type": "object" + }, + "ReadingProfileList": { + "description": "Reading profile list response.", + "properties": { + "profiles": { + "items": { + "$ref": "#/components/schemas/ReadingProfile" + }, + "title": "Profiles", + "type": "array" + } + }, + "required": [ + "profiles" + ], + "title": "ReadingProfileList", + "type": "object" + }, + "ReadingProgress": { + "description": "Reading progress information.", + "properties": { + "book_id": { + "format": "uuid", + "title": "Book Id", + "type": "string" + }, + "completed_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Completed At" + }, + "current_cfi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Current Cfi" + }, + "current_page": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Current Page" + }, + "current_position": { + "anyOf": [ + { + "maximum": 1.0, + "minimum": 0.0, + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Current Position" + }, + "last_read_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Last Read At" + }, + "reading_status": { + "anyOf": [ + { + "$ref": "#/components/schemas/ReadingStatus" + }, + { + "type": "null" + } + ] + }, + "sessions_count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Sessions Count" + }, + "started_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Started At" + }, + "total_reading_time_minutes": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Total Reading Time Minutes" + } + }, + "required": [ + "book_id" + ], + "title": "ReadingProgress", + "type": "object" + }, + "ReadingSession": { + "description": "Reading session response schema.", + "properties": { + "book_id": { + "format": "uuid", + "title": "Book Id", + "type": "string" + }, + "book_title": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Book Title" + }, + "created_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Created At" + }, + "device_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Device Name" + }, + "device_type": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Device Type" + }, + "duration_minutes": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "description": "Calculated from start_time and end_time", + "title": "Duration Minutes" + }, + "end_position": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "End Position" + }, + "end_time": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "End Time" + }, + "pages_read": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Pages Read" + }, + "session_id": { + "format": "uuid", + "title": "Session Id", + "type": "string" + }, + "start_position": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Start Position" + }, + "start_time": { + "format": "date-time", + "title": "Start Time", + "type": "string" + } + }, + "required": [ + "session_id", + "book_id", + "start_time" + ], + "title": "ReadingSession", + "type": "object" + }, + "ReadingSessionList": { + "description": "Paginated reading session list response.", + "properties": { + "pagination": { + "$ref": "#/components/schemas/Pagination" + }, + "sessions": { + "items": { + "$ref": "#/components/schemas/ReadingSession" + }, + "title": "Sessions", + "type": "array" + } + }, + "required": [ + "sessions", + "pagination" + ], + "title": "ReadingSessionList", + "type": "object" + }, + "ReadingStatistics": { + "description": "Comprehensive reading statistics response.", + "properties": { + "books_breakdown": { + "items": { + "$ref": "#/components/schemas/BookBreakdown" + }, + "title": "Books Breakdown", + "type": "array" + }, + "daily_breakdown": { + "items": { + "$ref": "#/components/schemas/DailyBreakdown" + }, + "title": "Daily Breakdown", + "type": "array" + }, + "period": { + "$ref": "#/components/schemas/StatisticsPeriod" + }, + "totals": { + "$ref": "#/components/schemas/StatisticsTotals" + } + }, + "required": [ + "period", + "totals", + "daily_breakdown", + "books_breakdown" + ], + "title": "ReadingStatistics", + "type": "object" + }, + "ReadingStatus": { + "description": "Book reading status.", + "enum": [ + "not_started", + "in_progress", + "completed", + "paused", + "abandoned" + ], + "title": "ReadingStatus", + "type": "string" + }, + "RefreshTokenRequest": { + "description": "Token refresh request.", + "properties": { + "refresh_token": { + "description": "Refresh token from login", + "title": "Refresh Token", + "type": "string" + } + }, + "required": [ + "refresh_token" + ], + "title": "RefreshTokenRequest", + "type": "object" + }, + "RegisterRequest": { + "description": "User registration request.", + "properties": { + "client_type": { + "default": "unknown", + "enum": [ + "mobile", + "desktop", + "web", + "unknown" + ], + "title": "Client Type", + "type": "string" + }, + "device_label": { + "anyOf": [ + { + "maxLength": 255, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Device Label" + }, + "display_name": { + "examples": [ + "John Doe" + ], + "maxLength": 100, + "minLength": 1, + "title": "Display Name", + "type": "string" + }, + "email": { + "examples": [ + "user@example.com" + ], + "format": "email", + "title": "Email", + "type": "string" + }, + "password": { + "examples": [ + "SecureP@ss123" + ], + "minLength": 8, + "title": "Password", + "type": "string" + } + }, + "required": [ + "email", + "password", + "display_name" + ], + "title": "RegisterRequest", + "type": "object" + }, + "Release": { + "properties": { + "format_hints": { + "items": { + "type": "string" + }, + "title": "Format Hints", + "type": "array" + }, + "indexer": { + "title": "Indexer", + "type": "string" + }, + "protocol": { + "title": "Protocol", + "type": "string" + }, + "publish_date": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Publish Date" + }, + "release_token": { + "title": "Release Token", + "type": "string" + }, + "seeders": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Seeders" + }, + "size_bytes": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Size Bytes" + }, + "title": { + "title": "Title", + "type": "string" + } + }, + "required": [ + "title", + "release_token", + "protocol", + "indexer" + ], + "title": "Release", + "type": "object" + }, + "RemoveBooksRequest": { + "description": "Request to remove books from a shelf.", + "properties": { + "book_ids": { + "items": { + "format": "uuid", + "type": "string" + }, + "title": "Book Ids", + "type": "array" + } + }, + "required": [ + "book_ids" + ], + "title": "RemoveBooksRequest", + "type": "object" + }, + "RemoveBooksResponse": { + "description": "Response for removing books from a shelf.", + "properties": { + "removed_count": { + "title": "Removed Count", + "type": "integer" + } + }, + "required": [ + "removed_count" + ], + "title": "RemoveBooksResponse", + "type": "object" + }, + "ResendVerificationRequest": { + "description": "Resend verification email request.", + "properties": { + "email": { + "format": "email", + "title": "Email", + "type": "string" + } + }, + "required": [ + "email" + ], + "title": "ResendVerificationRequest", + "type": "object" + }, + "ResetPasswordRequest": { + "description": "Password reset request.", + "properties": { + "password": { + "description": "New password", + "minLength": 8, + "title": "Password", + "type": "string" + }, + "token": { + "description": "Password reset token", + "title": "Token", + "type": "string" + } + }, + "required": [ + "token", + "password" + ], + "title": "ResetPasswordRequest", + "type": "object" + }, + "SavedFilter": { + "description": "Saved filter response schema.", + "properties": { + "color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Color" + }, + "created_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Created At" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "filter_id": { + "format": "uuid", + "title": "Filter Id", + "type": "string" + }, + "filter_type": { + "anyOf": [ + { + "$ref": "#/components/schemas/FilterType" + }, + { + "type": "null" + } + ] + }, + "icon": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Icon" + }, + "is_pinned": { + "default": false, + "title": "Is Pinned", + "type": "boolean" + }, + "last_used_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Last Used At" + }, + "name": { + "title": "Name", + "type": "string" + }, + "query": { + "title": "Query", + "type": "string" + }, + "updated_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Updated At" + }, + "usage_count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Usage Count" + } + }, + "required": [ + "filter_id", + "name", + "query" + ], + "title": "SavedFilter", + "type": "object" + }, + "SavedFilterList": { + "description": "Saved filter list response.", + "properties": { + "filters": { + "items": { + "$ref": "#/components/schemas/SavedFilter" + }, + "title": "Filters", + "type": "array" + } + }, + "required": [ + "filters" + ], + "title": "SavedFilterList", + "type": "object" + }, + "SearchRequest": { + "properties": { + "endpoint_ids": { + "anyOf": [ + { + "items": { + "format": "uuid", + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Endpoint Ids" + }, + "query": { + "maxLength": 500, + "minLength": 1, + "title": "Query", + "type": "string" + } + }, + "required": [ + "query" + ], + "title": "SearchRequest", + "type": "object" + }, + "Series": { + "description": "Series response schema.", + "properties": { + "author": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Author" + }, + "book_count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Book Count" + }, + "created_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Created At" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "is_complete": { + "default": false, + "title": "Is Complete", + "type": "boolean" + }, + "name": { + "title": "Name", + "type": "string" + }, + "series_id": { + "format": "uuid", + "title": "Series Id", + "type": "string" + }, + "total_books": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Total Books" + }, + "updated_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Updated At" + } + }, + "required": [ + "series_id", + "name" + ], + "title": "Series", + "type": "object" + }, + "SeriesList": { + "description": "Series list response.", + "properties": { + "series": { + "items": { + "$ref": "#/components/schemas/Series" + }, + "title": "Series", + "type": "array" + } + }, + "required": [ + "series" + ], + "title": "SeriesList", + "type": "object" + }, + "SeriesWithBooks": { + "description": "Series with included books.", + "properties": { + "author": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Author" + }, + "book_count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Book Count" + }, + "books": { + "anyOf": [ + { + "items": { + "$ref": "#/components/schemas/BookSummary" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Books" + }, + "created_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Created At" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "is_complete": { + "default": false, + "title": "Is Complete", + "type": "boolean" + }, + "name": { + "title": "Name", + "type": "string" + }, + "series_id": { + "format": "uuid", + "title": "Series Id", + "type": "string" + }, + "total_books": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Total Books" + }, + "updated_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Updated At" + } + }, + "required": [ + "series_id", + "name" + ], + "title": "SeriesWithBooks", + "type": "object" + }, + "SetPrimaryRequest": { + "description": "Request to set a storage backend as primary.", + "properties": { + "backend_id": { + "format": "uuid", + "title": "Backend Id", + "type": "string" + } + }, + "required": [ + "backend_id" + ], + "title": "SetPrimaryRequest", + "type": "object" + }, + "Shelf": { + "description": "Full shelf response schema.", + "properties": { + "book_count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Book Count" + }, + "children": { + "anyOf": [ + { + "items": { + "$ref": "#/components/schemas/Shelf" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Children" + }, + "color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Color" + }, + "created_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Created At" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "icon": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Icon" + }, + "is_default": { + "default": false, + "title": "Is Default", + "type": "boolean" + }, + "is_smart": { + "default": false, + "title": "Is Smart", + "type": "boolean" + }, + "name": { + "title": "Name", + "type": "string" + }, + "parent_shelf_id": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Parent Shelf Id" + }, + "shelf_id": { + "format": "uuid", + "title": "Shelf Id", + "type": "string" + }, + "smart_query": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Smart Query" + }, + "sort_order": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Sort Order" + }, + "updated_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Updated At" + } + }, + "required": [ + "shelf_id", + "name" + ], + "title": "Shelf", + "type": "object" + }, + "ShelfIdsRequest": { + "properties": { + "shelf_ids": { + "items": { + "format": "uuid", + "type": "string" + }, + "title": "Shelf Ids", + "type": "array" + } + }, + "required": [ + "shelf_ids" + ], + "title": "ShelfIdsRequest", + "type": "object" + }, + "ShelfList": { + "description": "Shelf list response.", + "properties": { + "shelves": { + "items": { + "$ref": "#/components/schemas/Shelf" + }, + "title": "Shelves", + "type": "array" + } + }, + "required": [ + "shelves" + ], + "title": "ShelfList", + "type": "object" + }, + "ShelfSummary": { + "description": "Minimal shelf information.", + "properties": { + "color": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Color" + }, + "name": { + "title": "Name", + "type": "string" + }, + "shelf_id": { + "format": "uuid", + "title": "Shelf Id", + "type": "string" + } + }, + "required": [ + "shelf_id", + "name" + ], + "title": "ShelfSummary", + "type": "object" + }, + "ShelvesResponse": { + "properties": { + "shelves": { + "items": { + "$ref": "#/components/schemas/Shelf" + }, + "title": "Shelves", + "type": "array" + } + }, + "required": [ + "shelves" + ], + "title": "ShelvesResponse", + "type": "object" + }, + "StatisticsPeriod": { + "description": "Statistics period.", + "properties": { + "end_date": { + "format": "date", + "title": "End Date", + "type": "string" + }, + "start_date": { + "format": "date", + "title": "Start Date", + "type": "string" + } + }, + "required": [ + "start_date", + "end_date" + ], + "title": "StatisticsPeriod", + "type": "object" + }, + "StatisticsTotals": { + "description": "Total reading statistics.", + "properties": { + "average_session_minutes": { + "title": "Average Session Minutes", + "type": "number" + }, + "books_completed": { + "title": "Books Completed", + "type": "integer" + }, + "current_streak": { + "title": "Current Streak", + "type": "integer" + }, + "longest_streak": { + "title": "Longest Streak", + "type": "integer" + }, + "pages_read": { + "title": "Pages Read", + "type": "integer" + }, + "reading_days": { + "title": "Reading Days", + "type": "integer" + }, + "reading_time_minutes": { + "title": "Reading Time Minutes", + "type": "integer" + }, + "sessions_count": { + "title": "Sessions Count", + "type": "integer" + } + }, + "required": [ + "reading_time_minutes", + "pages_read", + "books_completed", + "sessions_count", + "average_session_minutes", + "reading_days", + "current_streak", + "longest_streak" + ], + "title": "StatisticsTotals", + "type": "object" + }, + "StorageBackend": { + "description": "Storage backend response schema.", + "properties": { + "backend_id": { + "format": "uuid", + "title": "Backend Id", + "type": "string" + }, + "backend_type": { + "$ref": "#/components/schemas/StorageBackendType" + }, + "base_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Base Path" + }, + "connection_status": { + "anyOf": [ + { + "$ref": "#/components/schemas/ConnectionStatus" + }, + { + "type": "null" + } + ] + }, + "created_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Created At" + }, + "error_message": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Error Message" + }, + "is_active": { + "default": true, + "title": "Is Active", + "type": "boolean" + }, + "is_primary": { + "default": false, + "title": "Is Primary", + "type": "boolean" + }, + "last_accessed_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Last Accessed At" + }, + "name": { + "title": "Name", + "type": "string" + }, + "storage_quota_bytes": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Storage Quota Bytes" + }, + "storage_used_bytes": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Storage Used Bytes" + }, + "updated_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Updated At" + } + }, + "required": [ + "backend_id", + "backend_type", + "name" + ], + "title": "StorageBackend", + "type": "object" + }, + "StorageBackendList": { + "description": "Storage backend list response.", + "properties": { + "backends": { + "items": { + "$ref": "#/components/schemas/StorageBackend" + }, + "title": "Backends", + "type": "array" + } + }, + "required": [ + "backends" + ], + "title": "StorageBackendList", + "type": "object" + }, + "StorageBackendType": { + "description": "Supported storage backend types.", + "enum": [ + "local", + "google_drive", + "onedrive", + "dropbox", + "webdav", + "minio", + "s3", + "papyrus_server" + ], + "title": "StorageBackendType", + "type": "string" + }, + "SubmitRequest": { + "properties": { + "endpoint_id": { + "format": "uuid", + "title": "Endpoint Id", + "type": "string" + }, + "release_token": { + "minLength": 1, + "title": "Release Token", + "type": "string" + } + }, + "required": [ + "endpoint_id", + "release_token" + ], + "title": "SubmitRequest", + "type": "object" + }, + "Tag": { + "description": "Tag response schema.", + "properties": { + "color": { + "pattern": "^#[0-9A-Fa-f]{6}$", + "title": "Color", + "type": "string" + }, + "created_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Created At" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "name": { + "title": "Name", + "type": "string" + }, + "tag_id": { + "format": "uuid", + "title": "Tag Id", + "type": "string" + }, + "usage_count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Usage Count" + } + }, + "required": [ + "tag_id", + "name", + "color" + ], + "title": "Tag", + "type": "object" + }, + "TagIdsRequest": { + "properties": { + "tag_ids": { + "items": { + "format": "uuid", + "type": "string" + }, + "title": "Tag Ids", + "type": "array" + } + }, + "required": [ + "tag_ids" + ], + "title": "TagIdsRequest", + "type": "object" + }, + "TagList": { + "description": "Tag list response.", + "properties": { + "tags": { + "items": { + "$ref": "#/components/schemas/Tag" + }, + "title": "Tags", + "type": "array" + } + }, + "required": [ + "tags" + ], + "title": "TagList", + "type": "object" + }, + "TagsResponse": { + "properties": { + "tags": { + "items": { + "$ref": "#/components/schemas/Tag" + }, + "title": "Tags", + "type": "array" + } + }, + "required": [ + "tags" + ], + "title": "TagsResponse", + "type": "object" + }, + "TextAlign": { + "description": "Text alignment options.", + "enum": [ + "left", + "right", + "center", + "justify" + ], + "title": "TextAlign", + "type": "string" + }, + "ThemeMode": { + "description": "Reader theme modes.", + "enum": [ + "light", + "dark", + "sepia", + "custom" + ], + "title": "ThemeMode", + "type": "string" + }, + "TimePeriod": { + "description": "Goal time period.", + "enum": [ + "daily", + "weekly", + "monthly", + "yearly", + "custom" + ], + "title": "TimePeriod", + "type": "string" + }, + "UpdateAnnotationRequest": { + "description": "Annotation update request.", + "properties": { + "highlight_color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Highlight Color" + }, + "note": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Note" + } + }, + "title": "UpdateAnnotationRequest", + "type": "object" + }, + "UpdateBookmarkRequest": { + "description": "Bookmark update request.", + "properties": { + "color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Color" + }, + "note": { + "anyOf": [ + { + "maxLength": 500, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Note" + } + }, + "title": "UpdateBookmarkRequest", + "type": "object" + }, + "UpdateGoalRequest": { + "description": "Goal update request.", + "properties": { + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "end_date": { + "anyOf": [ + { + "format": "date", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "End Date" + }, + "is_active": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Is Active" + }, + "target_value": { + "anyOf": [ + { + "minimum": 1.0, + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Target Value" + }, + "title": { + "anyOf": [ + { + "maxLength": 255, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Title" + } + }, + "title": "UpdateGoalRequest", + "type": "object" + }, + "UpdateNoteRequest": { + "description": "Note update request.", + "properties": { + "content": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Content" + }, + "is_pinned": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Is Pinned" + }, + "title": { + "anyOf": [ + { + "maxLength": 255, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Title" + } + }, + "title": "UpdateNoteRequest", + "type": "object" + }, + "UpdateProgressRequest": { + "description": "Update reading progress request.", + "properties": { + "current_cfi": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Current Cfi" + }, + "current_page": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Current Page" + }, + "current_position": { + "anyOf": [ + { + "maximum": 1.0, + "minimum": 0.0, + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Current Position" + }, + "reading_status": { + "anyOf": [ + { + "$ref": "#/components/schemas/ReadingStatus" + }, + { + "type": "null" + } + ] + } + }, + "title": "UpdateProgressRequest", + "type": "object" + }, + "UpdateReadingProfileRequest": { + "description": "Reading profile update request.", + "properties": { + "background_color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Background Color" + }, + "column_count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Column Count" + }, + "font_family": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Font Family" + }, + "font_size": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Font Size" + }, + "font_weight": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Font Weight" + }, + "hyphenation": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Hyphenation" + }, + "letter_spacing": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Letter Spacing" + }, + "line_height": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Line Height" + }, + "link_color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Link Color" + }, + "margin_horizontal": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Margin Horizontal" + }, + "margin_vertical": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Margin Vertical" + }, + "name": { + "anyOf": [ + { + "maxLength": 100, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Name" + }, + "page_turn_animation": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Page Turn Animation" + }, + "paragraph_spacing": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Paragraph Spacing" + }, + "reading_mode": { + "anyOf": [ + { + "$ref": "#/components/schemas/ReadingMode" + }, + { + "type": "null" + } + ] + }, + "selection_color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Selection Color" + }, + "text_align": { + "anyOf": [ + { + "$ref": "#/components/schemas/TextAlign" + }, + { + "type": "null" + } + ] + }, + "text_color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Text Color" + }, + "theme_mode": { + "anyOf": [ + { + "$ref": "#/components/schemas/ThemeMode" + }, + { + "type": "null" + } + ] + } + }, + "title": "UpdateReadingProfileRequest", + "type": "object" + }, + "UpdateSavedFilterRequest": { + "description": "Saved filter update request.", + "properties": { + "color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Color" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "filter_type": { + "anyOf": [ + { + "$ref": "#/components/schemas/FilterType" + }, + { + "type": "null" + } + ] + }, + "icon": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Icon" + }, + "is_pinned": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Is Pinned" + }, + "name": { + "anyOf": [ + { + "maxLength": 100, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Name" + }, + "query": { + "anyOf": [ + { + "maxLength": 1000, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Query" + } + }, + "title": "UpdateSavedFilterRequest", + "type": "object" + }, + "UpdateSeriesRequest": { + "description": "Series update request.", + "properties": { + "author": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Author" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "is_complete": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Is Complete" + }, + "name": { + "anyOf": [ + { + "maxLength": 255, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Name" + }, + "total_books": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Total Books" + } + }, + "title": "UpdateSeriesRequest", + "type": "object" + }, + "UpdateShelfRequest": { + "description": "Shelf update request.", + "properties": { + "color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Color" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "icon": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Icon" + }, + "is_smart": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Is Smart" + }, + "name": { + "anyOf": [ + { + "maxLength": 100, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Name" + }, + "parent_shelf_id": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Parent Shelf Id" + }, + "smart_query": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Smart Query" + }, + "sort_order": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Sort Order" + } + }, + "title": "UpdateShelfRequest", + "type": "object" + }, + "UpdateStorageBackendRequest": { + "description": "Storage backend update request.", + "properties": { + "base_path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Base Path" + }, + "connection_config": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Connection Config" + }, + "credentials": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Credentials" + }, + "is_active": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Is Active" + }, + "name": { + "anyOf": [ + { + "maxLength": 100, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Name" + } + }, + "title": "UpdateStorageBackendRequest", + "type": "object" + }, + "UpdateTagRequest": { + "description": "Tag update request.", + "properties": { + "color": { + "anyOf": [ + { + "pattern": "^#[0-9A-Fa-f]{6}$", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Color" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description" + }, + "name": { + "anyOf": [ + { + "maxLength": 50, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Name" + } + }, + "title": "UpdateTagRequest", + "type": "object" + }, + "UpdateUserRequest": { + "description": "User profile update request.", + "properties": { + "avatar_url": { + "anyOf": [ + { + "format": "uri", + "maxLength": 2083, + "minLength": 1, + "type": "string" + }, + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Avatar Url" + }, + "display_name": { + "anyOf": [ + { + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Display Name" + } + }, + "title": "UpdateUserRequest", + "type": "object" + }, + "User": { + "description": "User response schema.", + "properties": { + "avatar_url": { + "anyOf": [ + { + "format": "uri", + "maxLength": 2083, + "minLength": 1, + "type": "string" + }, + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Avatar Url" + }, + "created_at": { + "format": "date-time", + "title": "Created At", + "type": "string" + }, + "display_name": { + "title": "Display Name", + "type": "string" + }, + "email": { + "anyOf": [ + { + "format": "email", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Email" + }, + "email_verified": { + "default": false, + "title": "Email Verified", + "type": "boolean" + }, + "last_login_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Last Login At" + }, + "user_id": { + "format": "uuid", + "title": "User Id", + "type": "string" + } + }, + "required": [ + "user_id", + "display_name", + "created_at" + ], + "title": "User", + "type": "object" + }, + "UserPreferences": { + "additionalProperties": true, + "description": "User preferences (flexible structure).", + "properties": { + "default_shelf": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "examples": [ + "Currently Reading" + ], + "title": "Default Shelf" + }, + "notifications_enabled": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "examples": [ + true + ], + "title": "Notifications Enabled" + }, + "sync_wifi_only": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "examples": [ + false + ], + "title": "Sync Wifi Only" + }, + "theme": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "examples": [ + "dark" + ], + "title": "Theme" + } + }, + "title": "UserPreferences", + "type": "object" + }, + "ValidationError": { + "properties": { + "ctx": { + "title": "Context", + "type": "object" + }, + "input": { + "title": "Input" + }, + "loc": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ] + }, + "title": "Location", + "type": "array" + }, + "msg": { + "title": "Message", + "type": "string" + }, + "type": { + "title": "Error Type", + "type": "string" + } + }, + "required": [ + "loc", + "msg", + "type" + ], + "title": "ValidationError", + "type": "object" + }, + "VerifyEmailRequest": { + "description": "Email verification request.", + "properties": { + "token": { + "description": "Email verification token", + "title": "Token", + "type": "string" + } + }, + "required": [ + "token" + ], + "title": "VerifyEmailRequest", + "type": "object" + } + }, + "securitySchemes": { + "HTTPBearer": { + "scheme": "bearer", + "type": "http" + } + } + }, + "info": { + "contact": { + "name": "Papyrus Support", + "url": "https://github.com/PapyrusReader/papyrus" + }, + "description": "\nREST API for Papyrus - a cross-platform book management application.\n\n## Overview\n\nThe Papyrus Server handles metadata storage and synchronization for the Papyrus\ne-book reader application. It provides endpoints for:\n\n- **Authentication**: User registration, login, OAuth, and session management\n- **Books**: CRUD operations for book metadata and file references\n- **Organization**: Shelves, tags, and series management\n- **Annotations**: Highlights, notes, and bookmarks\n- **Progress**: Reading sessions and statistics\n- **Goals**: Reading goal tracking\n- **Sync**: Cross-device synchronization\n- **Storage**: File storage backend configuration\n- **Files**: File upload/download (when server is file backend)\n\n## Authentication\n\nMost endpoints require authentication via JWT Bearer token. Obtain tokens\nthrough the `/v1/auth/register`, `/v1/auth/login`, or the\nbrowser-based `/v1/auth/oauth/google/start` flow.\n\n```\nAuthorization: Bearer \n```\n\nAccess tokens expire after `60` minutes.\nUse the refresh token to obtain new access tokens via `/v1/auth/refresh`.\n\n## Rate Limiting\n\nRate limits are enforced per user:\n\n| Endpoint Category | Limit |\n|-------------------|-------|\n| Authentication | 5 requests/minute |\n| General API | 100 requests/minute |\n| File uploads | 10 requests/minute |\n| Batch operations | 20 requests/minute |\n", + "license": { + "name": "AGPL-3.0", + "url": "https://www.gnu.org/licenses/agpl-3.0.html" + }, + "title": "Papyrus Server API", + "version": "1.0.0" + }, + "openapi": "3.1.0", + "paths": { + "/": { + "get": { + "description": "Return the available page-style endpoints for this server.", + "operationId": "index__get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "additionalProperties": true, + "title": "Response Index Get", + "type": "object" + } + } + }, + "description": "Successful Response" + } + }, + "summary": "Index", + "tags": [ + "Index" + ] + } + }, + "/health": { + "get": { + "description": "Check API health status.", + "operationId": "health_check_health_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "additionalProperties": { + "type": "string" + }, + "title": "Response Health Check Health Get", + "type": "object" + } + } + }, + "description": "Successful Response" + } + }, + "summary": "Health Check", + "tags": [ + "Health" + ] + } + }, + "/v1/acquisition/arr/{endpoint_id}/commands": { + "post": { + "description": "Delegate a managed search/acquisition to Readarr or another Arr app.", + "operationId": "run_arr_command_v1_acquisition_arr__endpoint_id__commands_post", + "parameters": [ + { + "in": "path", + "name": "endpoint_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Endpoint Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ArrCommandRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcquisitionJob" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Run Arr Command", + "tags": [ + "Acquisition" + ] + } + }, + "/v1/acquisition/capabilities": { + "get": { + "operationId": "acquisition_capabilities_v1_acquisition_capabilities_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcquisitionCapabilities" + } + } + }, + "description": "Successful Response" + } + }, + "summary": "Acquisition Capabilities", + "tags": [ + "Acquisition" + ] + } + }, + "/v1/acquisition/endpoints": { + "get": { + "operationId": "list_endpoints_v1_acquisition_endpoints_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/AcquisitionEndpoint" + }, + "title": "Response List Endpoints V1 Acquisition Endpoints Get", + "type": "array" + } + } + }, + "description": "Successful Response" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List Endpoints", + "tags": [ + "Acquisition" + ] + }, + "post": { + "operationId": "create_endpoint_v1_acquisition_endpoints_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcquisitionEndpointCreate" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcquisitionEndpoint" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Create Endpoint", + "tags": [ + "Acquisition" + ] + } + }, + "/v1/acquisition/endpoints/test": { + "post": { + "operationId": "test_connection_v1_acquisition_endpoints_test_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcquisitionEndpointTest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcquisitionEndpointTestResult" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Test Connection", + "tags": [ + "Acquisition" + ] + } + }, + "/v1/acquisition/endpoints/{endpoint_id}": { + "delete": { + "operationId": "delete_endpoint_v1_acquisition_endpoints__endpoint_id__delete", + "parameters": [ + { + "in": "path", + "name": "endpoint_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Endpoint Id", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Delete Endpoint", + "tags": [ + "Acquisition" + ] + }, + "patch": { + "operationId": "update_endpoint_v1_acquisition_endpoints__endpoint_id__patch", + "parameters": [ + { + "in": "path", + "name": "endpoint_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Endpoint Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcquisitionEndpointUpdate" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcquisitionEndpoint" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Update Endpoint", + "tags": [ + "Acquisition" + ] + } + }, + "/v1/acquisition/jobs": { + "get": { + "operationId": "list_jobs_v1_acquisition_jobs_get", + "parameters": [ + { + "in": "query", + "name": "limit", + "required": false, + "schema": { + "default": 50, + "maximum": 100, + "minimum": 1, + "title": "Limit", + "type": "integer" + } + }, + { + "in": "query", + "name": "offset", + "required": false, + "schema": { + "default": 0, + "minimum": 0, + "title": "Offset", + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcquisitionJobPage" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List Jobs", + "tags": [ + "Acquisition" + ] + } + }, + "/v1/acquisition/jobs/{job_id}": { + "delete": { + "operationId": "delete_acquisition_job_v1_acquisition_jobs__job_id__delete", + "parameters": [ + { + "in": "path", + "name": "job_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Job Id", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Delete Acquisition Job", + "tags": [ + "Acquisition" + ] + }, + "get": { + "operationId": "get_job_v1_acquisition_jobs__job_id__get", + "parameters": [ + { + "in": "path", + "name": "job_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Job Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcquisitionJob" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get Job", + "tags": [ + "Acquisition" + ] + } + }, + "/v1/acquisition/jobs/{job_id}/cancel": { + "post": { + "operationId": "cancel_acquisition_job_v1_acquisition_jobs__job_id__cancel_post", + "parameters": [ + { + "in": "path", + "name": "job_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Job Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcquisitionJob" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Cancel Acquisition Job", + "tags": [ + "Acquisition" + ] + } + }, + "/v1/acquisition/jobs/{job_id}/file-selection": { + "post": { + "operationId": "choose_job_file_v1_acquisition_jobs__job_id__file_selection_post", + "parameters": [ + { + "in": "path", + "name": "job_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Job Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcquisitionFileSelectionRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcquisitionJob" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Choose Job File", + "tags": [ + "Acquisition" + ] + } + }, + "/v1/acquisition/jobs/{job_id}/files": { + "get": { + "operationId": "get_job_files_v1_acquisition_jobs__job_id__files_get", + "parameters": [ + { + "in": "path", + "name": "job_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Job Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/AcquisitionFileCandidate" + }, + "title": "Response Get Job Files V1 Acquisition Jobs Job Id Files Get", + "type": "array" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get Job Files", + "tags": [ + "Acquisition" + ] + } + }, + "/v1/acquisition/jobs/{job_id}/retry-import": { + "post": { + "operationId": "retry_acquisition_job_import_v1_acquisition_jobs__job_id__retry_import_post", + "parameters": [ + { + "in": "path", + "name": "job_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Job Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcquisitionJob" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Retry Acquisition Job Import", + "tags": [ + "Acquisition" + ] + } + }, + "/v1/acquisition/rules": { + "get": { + "operationId": "list_rules_v1_acquisition_rules_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/AcquisitionRule" + }, + "title": "Response List Rules V1 Acquisition Rules Get", + "type": "array" + } + } + }, + "description": "Successful Response" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List Rules", + "tags": [ + "Acquisition" + ] + }, + "post": { + "operationId": "create_rule_v1_acquisition_rules_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcquisitionRuleCreate" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcquisitionRule" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Create Rule", + "tags": [ + "Acquisition" + ] + } + }, + "/v1/acquisition/rules/{rule_id}/run": { + "post": { + "operationId": "run_acquisition_rule_v1_acquisition_rules__rule_id__run_post", + "parameters": [ + { + "in": "path", + "name": "rule_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Rule Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/AcquisitionJob" + }, + "title": "Response Run Acquisition Rule V1 Acquisition Rules Rule Id Run Post", + "type": "array" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Run Acquisition Rule", + "tags": [ + "Acquisition" + ] + } + }, + "/v1/acquisition/search": { + "post": { + "operationId": "search_releases_v1_acquisition_search_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SearchRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/Release" + }, + "title": "Response Search Releases V1 Acquisition Search Post", + "type": "array" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Search Releases", + "tags": [ + "Acquisition" + ] + } + }, + "/v1/acquisition/submissions": { + "post": { + "operationId": "submit_release_v1_acquisition_submissions_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubmitRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AcquisitionJob" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Submit Release", + "tags": [ + "Acquisition" + ] + } + }, + "/v1/acquisition/submissions/batch": { + "post": { + "operationId": "submit_release_batch_route_v1_acquisition_submissions_batch_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BatchSubmitRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BatchSubmissionResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Submit Release Batch Route", + "tags": [ + "Acquisition" + ] + } + }, + "/v1/annotations": { + "get": { + "description": "Return paginated list of annotations, optionally filtered by book.", + "operationId": "list_annotations_v1_annotations_get", + "parameters": [ + { + "in": "query", + "name": "book_id", + "required": false, + "schema": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Book Id" + } + }, + { + "in": "query", + "name": "color", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Color" + } + }, + { + "in": "query", + "name": "search", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Search" + } + }, + { + "description": "Page number", + "in": "query", + "name": "page", + "required": false, + "schema": { + "default": 1, + "description": "Page number", + "minimum": 1, + "title": "Page", + "type": "integer" + } + }, + { + "description": "Items per page", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "default": 20, + "description": "Items per page", + "maximum": 100, + "minimum": 1, + "title": "Limit", + "type": "integer" + } + }, + { + "description": "Sort field with optional - prefix for descending", + "in": "query", + "name": "sort", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Sort field with optional - prefix for descending", + "title": "Sort" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AnnotationList" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List all annotations", + "tags": [ + "Annotations" + ] + } + }, + "/v1/annotations/books/{book_id}": { + "get": { + "description": "Return paginated list of annotations for a specific book.", + "operationId": "list_book_annotations_v1_annotations_books__book_id__get", + "parameters": [ + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + }, + { + "description": "Page number", + "in": "query", + "name": "page", + "required": false, + "schema": { + "default": 1, + "description": "Page number", + "minimum": 1, + "title": "Page", + "type": "integer" + } + }, + { + "description": "Items per page", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "default": 20, + "description": "Items per page", + "maximum": 100, + "minimum": 1, + "title": "Limit", + "type": "integer" + } + }, + { + "description": "Sort field with optional - prefix for descending", + "in": "query", + "name": "sort", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Sort field with optional - prefix for descending", + "title": "Sort" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AnnotationList" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List book annotations", + "tags": [ + "Annotations" + ] + }, + "post": { + "description": "Create a new annotation for a book.", + "operationId": "create_annotation_v1_annotations_books__book_id__post", + "parameters": [ + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateAnnotationRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Annotation" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Create annotation", + "tags": [ + "Annotations" + ] + } + }, + "/v1/annotations/export": { + "post": { + "description": "Export annotations in various formats.", + "operationId": "export_annotations_v1_annotations_export_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExportAnnotationsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExportAnnotationsResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Export annotations", + "tags": [ + "Annotations" + ] + } + }, + "/v1/annotations/{annotation_id}": { + "delete": { + "description": "Delete an annotation.", + "operationId": "delete_annotation_v1_annotations__annotation_id__delete", + "parameters": [ + { + "in": "path", + "name": "annotation_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Annotation Id", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Delete annotation", + "tags": [ + "Annotations" + ] + }, + "get": { + "description": "Return detailed information about an annotation.", + "operationId": "get_annotation_v1_annotations__annotation_id__get", + "parameters": [ + { + "in": "path", + "name": "annotation_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Annotation Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Annotation" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get annotation details", + "tags": [ + "Annotations" + ] + }, + "patch": { + "description": "Update an annotation's note or color.", + "operationId": "update_annotation_v1_annotations__annotation_id__patch", + "parameters": [ + { + "in": "path", + "name": "annotation_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Annotation Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAnnotationRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Annotation" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Update annotation", + "tags": [ + "Annotations" + ] + } + }, + "/v1/auth/exchange-code": { + "post": { + "description": "Exchange a one-time OAuth handoff code for Papyrus tokens.", + "operationId": "exchange_code_v1_auth_exchange_code_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OAuthExchangeRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokens" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Exchange an OAuth browser code for Papyrus tokens", + "tags": [ + "Auth" + ] + } + }, + "/v1/auth/forgot-password": { + "post": { + "description": "Issue a password reset token when email delivery is enabled.", + "operationId": "forgot_password_v1_auth_forgot_password_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ForgotPasswordRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Request password reset", + "tags": [ + "Auth" + ] + } + }, + "/v1/auth/jwks": { + "get": { + "description": "Expose the PowerSync public signing keys.", + "operationId": "powersync_jwks_v1_auth_jwks_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "additionalProperties": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array" + }, + "title": "Response Powersync Jwks V1 Auth Jwks Get", + "type": "object" + } + } + }, + "description": "Successful Response" + } + }, + "summary": "Return the PowerSync signing JWKS", + "tags": [ + "Auth" + ] + } + }, + "/v1/auth/link/google/complete": { + "post": { + "description": "Consume a one-time code and link the Google identity to the authenticated user.", + "operationId": "complete_google_link_v1_auth_link_google_complete_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OAuthLinkCompleteRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Complete Google account linking", + "tags": [ + "Auth" + ] + } + }, + "/v1/auth/link/google/start": { + "post": { + "description": "Return the Google authorization URL for linking an account.", + "operationId": "start_google_link_v1_auth_link_google_start_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OAuthStartRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthorizationUrlResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Start Google account linking flow", + "tags": [ + "Auth" + ] + } + }, + "/v1/auth/login": { + "post": { + "description": "Authenticate a user with email and password credentials.", + "operationId": "login_user_v1_auth_login_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokens" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Login with email and password", + "tags": [ + "Auth" + ] + } + }, + "/v1/auth/logout": { + "post": { + "description": "Invalidate the current session or all sessions if requested.", + "operationId": "logout_user_v1_auth_logout_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/LogoutRequest" + }, + { + "type": "null" + } + ], + "title": "Request" + } + } + } + }, + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Logout and invalidate the current session", + "tags": [ + "Auth" + ] + } + }, + "/v1/auth/logout-all": { + "post": { + "description": "Invalidate all refresh-token backed sessions for the user.", + "operationId": "logout_all_v1_auth_logout_all_post", + "responses": { + "204": { + "description": "Successful Response" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Logout from all sessions", + "tags": [ + "Auth" + ] + } + }, + "/v1/auth/oauth/google/callback": { + "get": { + "description": "Handle the Google OAuth callback and redirect back to the app.", + "operationId": "google_oauth_callback_v1_auth_oauth_google_callback_get", + "parameters": [ + { + "in": "query", + "name": "code", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Code" + } + }, + { + "in": "query", + "name": "state", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "State" + } + }, + { + "in": "query", + "name": "error", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Error" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Complete the Google OAuth browser callback", + "tags": [ + "Auth" + ] + } + }, + "/v1/auth/oauth/google/start": { + "get": { + "description": "Redirect the user to Google for login.", + "operationId": "google_oauth_start_v1_auth_oauth_google_start_get", + "parameters": [ + { + "description": "App callback URI for the browser flow", + "in": "query", + "name": "redirect_uri", + "required": true, + "schema": { + "description": "App callback URI for the browser flow", + "title": "Redirect Uri", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Start Google OAuth login flow", + "tags": [ + "Auth" + ] + } + }, + "/v1/auth/powersync-token": { + "post": { + "description": "Mint a short-lived PowerSync JWT for the authenticated user.", + "operationId": "powersync_token_v1_auth_powersync_token_post", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PowerSyncTokenResponse" + } + } + }, + "description": "Successful Response" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Mint a short-lived PowerSync token", + "tags": [ + "Auth" + ] + } + }, + "/v1/auth/refresh": { + "post": { + "description": "Exchange a valid refresh token for a new access token.", + "operationId": "refresh_token_v1_auth_refresh_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RefreshTokenRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokens" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Refresh access token", + "tags": [ + "Auth" + ] + } + }, + "/v1/auth/register": { + "post": { + "description": "Create a new user account with email and password.", + "operationId": "register_user_v1_auth_register_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthTokens" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Register a new user account", + "tags": [ + "Auth" + ] + } + }, + "/v1/auth/resend-verification": { + "post": { + "description": "Issue a new verification token when email delivery is enabled.", + "operationId": "resend_verification_v1_auth_resend_verification_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResendVerificationRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Resend verification email", + "tags": [ + "Auth" + ] + } + }, + "/v1/auth/reset-password": { + "post": { + "description": "Reset the user's password using a one-time token.", + "operationId": "reset_password_v1_auth_reset_password_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResetPasswordRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Reset password with token", + "tags": [ + "Auth" + ] + } + }, + "/v1/auth/verify-email": { + "post": { + "description": "Verify the user's email address using a one-time token.", + "operationId": "verify_email_v1_auth_verify_email_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VerifyEmailRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Verify email address", + "tags": [ + "Auth" + ] + } + }, + "/v1/bookmarks": { + "get": { + "description": "Return list of bookmarks, optionally filtered by book.", + "operationId": "list_bookmarks_v1_bookmarks_get", + "parameters": [ + { + "in": "query", + "name": "book_id", + "required": false, + "schema": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Book Id" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookmarkList" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List all bookmarks", + "tags": [ + "Bookmarks" + ] + } + }, + "/v1/bookmarks/books/{book_id}": { + "get": { + "description": "Return list of bookmarks for a specific book.", + "operationId": "list_book_bookmarks_v1_bookmarks_books__book_id__get", + "parameters": [ + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookmarkList" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List book bookmarks", + "tags": [ + "Bookmarks" + ] + }, + "post": { + "description": "Create a new bookmark for a book.", + "operationId": "create_bookmark_v1_bookmarks_books__book_id__post", + "parameters": [ + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateBookmarkRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Bookmark" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Create bookmark", + "tags": [ + "Bookmarks" + ] + } + }, + "/v1/bookmarks/{bookmark_id}": { + "delete": { + "description": "Delete a bookmark.", + "operationId": "delete_bookmark_v1_bookmarks__bookmark_id__delete", + "parameters": [ + { + "in": "path", + "name": "bookmark_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Bookmark Id", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Delete bookmark", + "tags": [ + "Bookmarks" + ] + }, + "get": { + "description": "Return detailed information about a bookmark.", + "operationId": "get_bookmark_v1_bookmarks__bookmark_id__get", + "parameters": [ + { + "in": "path", + "name": "bookmark_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Bookmark Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Bookmark" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get bookmark details", + "tags": [ + "Bookmarks" + ] + }, + "patch": { + "description": "Update a bookmark's note or color.", + "operationId": "update_bookmark_v1_bookmarks__bookmark_id__patch", + "parameters": [ + { + "in": "path", + "name": "bookmark_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Bookmark Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateBookmarkRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Bookmark" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Update bookmark", + "tags": [ + "Bookmarks" + ] + } + }, + "/v1/books": { + "get": { + "description": "Return a paginated list of books in the user's library.", + "operationId": "list_books_v1_books_get", + "parameters": [ + { + "in": "query", + "name": "status", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/ReadingStatus" + }, + { + "type": "null" + } + ], + "title": "Status" + } + }, + { + "in": "query", + "name": "shelf_id", + "required": false, + "schema": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Shelf Id" + } + }, + { + "in": "query", + "name": "tag_id", + "required": false, + "schema": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Tag Id" + } + }, + { + "in": "query", + "name": "series_id", + "required": false, + "schema": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Series Id" + } + }, + { + "in": "query", + "name": "is_physical", + "required": false, + "schema": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Is Physical" + } + }, + { + "in": "query", + "name": "is_favorite", + "required": false, + "schema": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Is Favorite" + } + }, + { + "in": "query", + "name": "search", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Search" + } + }, + { + "in": "query", + "name": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Query" + } + }, + { + "description": "Page number", + "in": "query", + "name": "page", + "required": false, + "schema": { + "default": 1, + "description": "Page number", + "minimum": 1, + "title": "Page", + "type": "integer" + } + }, + { + "description": "Items per page", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "default": 20, + "description": "Items per page", + "maximum": 100, + "minimum": 1, + "title": "Limit", + "type": "integer" + } + }, + { + "description": "Sort field with optional - prefix for descending", + "in": "query", + "name": "sort", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Sort field with optional - prefix for descending", + "title": "Sort" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookList" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List user's books", + "tags": [ + "Books" + ] + }, + "post": { + "description": "Add a new book to the user's library.", + "operationId": "create_book_v1_books_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookCreate" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Book" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Create a new book", + "tags": [ + "Books" + ] + } + }, + "/v1/books/batch": { + "delete": { + "description": "Delete multiple books in a single request.", + "operationId": "batch_delete_books_v1_books_batch_delete", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BatchDeleteRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BatchDeleteResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Batch delete books", + "tags": [ + "Books" + ] + }, + "patch": { + "description": "Update multiple books in a single request.", + "operationId": "batch_update_books_v1_books_batch_patch", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BatchUpdateRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BatchUpdateResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Batch update books", + "tags": [ + "Books" + ] + }, + "post": { + "description": "Create multiple books in a single request.", + "operationId": "batch_create_books_v1_books_batch_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BatchCreateRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BatchCreateResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Batch create books", + "tags": [ + "Books" + ] + } + }, + "/v1/books/metadata/fetch": { + "post": { + "description": "Search online sources for book metadata.", + "operationId": "fetch_book_metadata_v1_books_metadata_fetch_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataFetchRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataFetchResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Fetch metadata from online sources", + "tags": [ + "Books" + ] + } + }, + "/v1/books/{book_id}": { + "delete": { + "description": "Remove a book from the library.", + "operationId": "delete_book_v1_books__book_id__delete", + "parameters": [ + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + }, + { + "in": "query", + "name": "delete_file", + "required": false, + "schema": { + "default": false, + "title": "Delete File", + "type": "boolean" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Delete a book", + "tags": [ + "Books" + ] + }, + "get": { + "description": "Return detailed information about a specific book.", + "operationId": "get_book_v1_books__book_id__get", + "parameters": [ + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Book" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get book details", + "tags": [ + "Books" + ] + }, + "patch": { + "description": "Update book metadata fields.", + "operationId": "update_book_v1_books__book_id__patch", + "parameters": [ + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookUpdate" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Book" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Update book metadata", + "tags": [ + "Books" + ] + } + }, + "/v1/books/{book_id}/cover": { + "get": { + "description": "Return the book's cover image.", + "operationId": "get_book_cover_v1_books__book_id__cover_get", + "parameters": [ + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get book cover image", + "tags": [ + "Books" + ] + }, + "put": { + "description": "Upload or replace the book's cover image.", + "operationId": "upload_book_cover_v1_books__book_id__cover_put", + "parameters": [ + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + }, + { + "in": "query", + "name": "url", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Url" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/Body_upload_book_cover_v1_books__book_id__cover_put" + } + } + } + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Book" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Upload book cover image", + "tags": [ + "Books" + ] + } + }, + "/v1/books/{book_id}/progress": { + "get": { + "description": "Return the current reading progress for a book.", + "operationId": "get_book_progress_v1_books__book_id__progress_get", + "parameters": [ + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReadingProgress" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get reading progress", + "tags": [ + "Books" + ] + }, + "put": { + "description": "Update the reading position and status for a book.", + "operationId": "update_book_progress_v1_books__book_id__progress_put", + "parameters": [ + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProgressRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReadingProgress" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Update reading progress", + "tags": [ + "Books" + ] + } + }, + "/v1/books/{book_id}/shelves": { + "get": { + "description": "Return the shelves this book belongs to.", + "operationId": "get_book_shelves_v1_books__book_id__shelves_get", + "parameters": [ + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ShelvesResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get book's shelves", + "tags": [ + "Books" + ] + }, + "put": { + "description": "Replace all shelf assignments for this book.", + "operationId": "set_book_shelves_v1_books__book_id__shelves_put", + "parameters": [ + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ShelfIdsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ShelvesResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Set book's shelves", + "tags": [ + "Books" + ] + } + }, + "/v1/books/{book_id}/tags": { + "get": { + "description": "Return the tags assigned to this book.", + "operationId": "get_book_tags_v1_books__book_id__tags_get", + "parameters": [ + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagsResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get book's tags", + "tags": [ + "Books" + ] + }, + "put": { + "description": "Replace all tag assignments for this book.", + "operationId": "set_book_tags_v1_books__book_id__tags_put", + "parameters": [ + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagIdsRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagsResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Set book's tags", + "tags": [ + "Books" + ] + } + }, + "/v1/files/download/{file_path}": { + "get": { + "description": "Download a book file from storage.", + "operationId": "download_file_v1_files_download__file_path__get", + "parameters": [ + { + "in": "path", + "name": "file_path", + "required": true, + "schema": { + "title": "File Path", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Download a book file", + "tags": [ + "Files" + ] + } + }, + "/v1/files/info/{file_path}": { + "get": { + "description": "Get information about a stored file.", + "operationId": "get_file_info_v1_files_info__file_path__get", + "parameters": [ + { + "in": "path", + "name": "file_path", + "required": true, + "schema": { + "title": "File Path", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FileInfo" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get file information", + "tags": [ + "Files" + ] + } + }, + "/v1/files/upload": { + "post": { + "description": "Upload a book file to storage.", + "operationId": "upload_file_v1_files_upload_post", + "parameters": [ + { + "in": "query", + "name": "storage_backend_id", + "required": false, + "schema": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Storage Backend Id" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/Body_upload_file_v1_files_upload_post" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FileInfo" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Upload a book file", + "tags": [ + "Files" + ] + } + }, + "/v1/files/{file_path}": { + "delete": { + "description": "Delete a file from storage.", + "operationId": "delete_file_v1_files__file_path__delete", + "parameters": [ + { + "in": "path", + "name": "file_path", + "required": true, + "schema": { + "title": "File Path", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Delete a file", + "tags": [ + "Files" + ] + } + }, + "/v1/goals": { + "get": { + "description": "Return all goals for the user.", + "operationId": "list_goals_v1_goals_get", + "parameters": [ + { + "in": "query", + "name": "is_active", + "required": false, + "schema": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Is Active" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GoalList" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List all goals", + "tags": [ + "Goals" + ] + }, + "post": { + "description": "Create a new reading goal.", + "operationId": "create_goal_v1_goals_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateGoalRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Goal" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Create a new goal", + "tags": [ + "Goals" + ] + } + }, + "/v1/goals/{goal_id}": { + "delete": { + "description": "Delete a goal.", + "operationId": "delete_goal_v1_goals__goal_id__delete", + "parameters": [ + { + "in": "path", + "name": "goal_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Goal Id", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Delete goal", + "tags": [ + "Goals" + ] + }, + "get": { + "description": "Return detailed information about a goal.", + "operationId": "get_goal_v1_goals__goal_id__get", + "parameters": [ + { + "in": "path", + "name": "goal_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Goal Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Goal" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get goal details", + "tags": [ + "Goals" + ] + }, + "patch": { + "description": "Update goal properties.", + "operationId": "update_goal_v1_goals__goal_id__patch", + "parameters": [ + { + "in": "path", + "name": "goal_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Goal Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateGoalRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Goal" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Update goal", + "tags": [ + "Goals" + ] + } + }, + "/v1/media": { + "post": { + "description": "Upload a book file or cover image for the authenticated user.", + "operationId": "upload_media_v1_media_post", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/Body_upload_media_v1_media_post" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaAssetResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Upload private media", + "tags": [ + "Media" + ] + } + }, + "/v1/media/usage": { + "get": { + "description": "Return authenticated user's file storage usage.", + "operationId": "get_media_usage_v1_media_usage_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaUsageResponse" + } + } + }, + "description": "Successful Response" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get media storage usage", + "tags": [ + "Media" + ] + } + }, + "/v1/media/{asset_id}": { + "delete": { + "description": "Delete an owned media asset.", + "operationId": "delete_media_v1_media__asset_id__delete", + "parameters": [ + { + "in": "path", + "name": "asset_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Asset Id", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Delete private media", + "tags": [ + "Media" + ] + }, + "get": { + "description": "Download an owned media asset.", + "operationId": "download_media_v1_media__asset_id__get", + "parameters": [ + { + "in": "path", + "name": "asset_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Asset Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Download private media", + "tags": [ + "Media" + ] + } + }, + "/v1/notes": { + "get": { + "description": "Return paginated list of notes, optionally filtered by book.", + "operationId": "list_notes_v1_notes_get", + "parameters": [ + { + "in": "query", + "name": "book_id", + "required": false, + "schema": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Book Id" + } + }, + { + "in": "query", + "name": "is_pinned", + "required": false, + "schema": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Is Pinned" + } + }, + { + "in": "query", + "name": "search", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Search" + } + }, + { + "description": "Page number", + "in": "query", + "name": "page", + "required": false, + "schema": { + "default": 1, + "description": "Page number", + "minimum": 1, + "title": "Page", + "type": "integer" + } + }, + { + "description": "Items per page", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "default": 20, + "description": "Items per page", + "maximum": 100, + "minimum": 1, + "title": "Limit", + "type": "integer" + } + }, + { + "description": "Sort field with optional - prefix for descending", + "in": "query", + "name": "sort", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Sort field with optional - prefix for descending", + "title": "Sort" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NoteList" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List all notes", + "tags": [ + "Notes" + ] + } + }, + "/v1/notes/books/{book_id}": { + "get": { + "description": "Return paginated list of notes for a specific book.", + "operationId": "list_book_notes_v1_notes_books__book_id__get", + "parameters": [ + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + }, + { + "description": "Page number", + "in": "query", + "name": "page", + "required": false, + "schema": { + "default": 1, + "description": "Page number", + "minimum": 1, + "title": "Page", + "type": "integer" + } + }, + { + "description": "Items per page", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "default": 20, + "description": "Items per page", + "maximum": 100, + "minimum": 1, + "title": "Limit", + "type": "integer" + } + }, + { + "description": "Sort field with optional - prefix for descending", + "in": "query", + "name": "sort", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Sort field with optional - prefix for descending", + "title": "Sort" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NoteList" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List book notes", + "tags": [ + "Notes" + ] + }, + "post": { + "description": "Create a new note for a book.", + "operationId": "create_note_v1_notes_books__book_id__post", + "parameters": [ + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateNoteRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Note" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Create note", + "tags": [ + "Notes" + ] + } + }, + "/v1/notes/{note_id}": { + "delete": { + "description": "Delete a note.", + "operationId": "delete_note_v1_notes__note_id__delete", + "parameters": [ + { + "in": "path", + "name": "note_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Note Id", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Delete note", + "tags": [ + "Notes" + ] + }, + "get": { + "description": "Return detailed information about a note.", + "operationId": "get_note_v1_notes__note_id__get", + "parameters": [ + { + "in": "path", + "name": "note_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Note Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Note" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get note details", + "tags": [ + "Notes" + ] + }, + "patch": { + "description": "Update a note's content.", + "operationId": "update_note_v1_notes__note_id__patch", + "parameters": [ + { + "in": "path", + "name": "note_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Note Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateNoteRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Note" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Update note", + "tags": [ + "Notes" + ] + } + }, + "/v1/opds/relay": { + "post": { + "description": "Stream a public catalog resource without requiring a Papyrus account.", + "operationId": "relay_resource_v1_opds_relay_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OpdsRelayRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Retrieve an OPDS resource", + "tags": [ + "OPDS" + ] + } + }, + "/v1/progress/sessions": { + "get": { + "description": "Return paginated list of reading sessions.", + "operationId": "list_reading_sessions_v1_progress_sessions_get", + "parameters": [ + { + "in": "query", + "name": "book_id", + "required": false, + "schema": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Book Id" + } + }, + { + "in": "query", + "name": "start_date", + "required": false, + "schema": { + "anyOf": [ + { + "format": "date", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Start Date" + } + }, + { + "in": "query", + "name": "end_date", + "required": false, + "schema": { + "anyOf": [ + { + "format": "date", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "End Date" + } + }, + { + "description": "Page number", + "in": "query", + "name": "page", + "required": false, + "schema": { + "default": 1, + "description": "Page number", + "minimum": 1, + "title": "Page", + "type": "integer" + } + }, + { + "description": "Items per page", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "default": 20, + "description": "Items per page", + "maximum": 100, + "minimum": 1, + "title": "Limit", + "type": "integer" + } + }, + { + "description": "Sort field with optional - prefix for descending", + "in": "query", + "name": "sort", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Sort field with optional - prefix for descending", + "title": "Sort" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReadingSessionList" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List reading sessions", + "tags": [ + "Progress" + ] + }, + "post": { + "description": "Record a new reading session.", + "operationId": "create_reading_session_v1_progress_sessions_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateReadingSessionRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReadingSession" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Record reading session", + "tags": [ + "Progress" + ] + } + }, + "/v1/progress/statistics": { + "get": { + "description": "Return reading statistics for the specified period.", + "operationId": "get_reading_statistics_v1_progress_statistics_get", + "parameters": [ + { + "description": "Start date for statistics period", + "in": "query", + "name": "start_date", + "required": false, + "schema": { + "anyOf": [ + { + "format": "date", + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Start date for statistics period", + "title": "Start Date" + } + }, + { + "description": "End date for statistics period", + "in": "query", + "name": "end_date", + "required": false, + "schema": { + "anyOf": [ + { + "format": "date", + "type": "string" + }, + { + "type": "null" + } + ], + "description": "End date for statistics period", + "title": "End Date" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReadingStatistics" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get reading statistics", + "tags": [ + "Progress" + ] + } + }, + "/v1/reading-profiles": { + "get": { + "description": "Return all reading profiles for the user.", + "operationId": "list_reading_profiles_v1_reading_profiles_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReadingProfileList" + } + } + }, + "description": "Successful Response" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List reading profiles", + "tags": [ + "Reading Profiles" + ] + }, + "post": { + "description": "Create a new reading profile.", + "operationId": "create_reading_profile_v1_reading_profiles_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateReadingProfileRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReadingProfile" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Create reading profile", + "tags": [ + "Reading Profiles" + ] + } + }, + "/v1/reading-profiles/{profile_id}": { + "delete": { + "description": "Delete a reading profile.", + "operationId": "delete_reading_profile_v1_reading_profiles__profile_id__delete", + "parameters": [ + { + "in": "path", + "name": "profile_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Profile Id", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Delete reading profile", + "tags": [ + "Reading Profiles" + ] + }, + "get": { + "description": "Return detailed information about a reading profile.", + "operationId": "get_reading_profile_v1_reading_profiles__profile_id__get", + "parameters": [ + { + "in": "path", + "name": "profile_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Profile Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReadingProfile" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get reading profile", + "tags": [ + "Reading Profiles" + ] + }, + "patch": { + "description": "Update a reading profile.", + "operationId": "update_reading_profile_v1_reading_profiles__profile_id__patch", + "parameters": [ + { + "in": "path", + "name": "profile_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Profile Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateReadingProfileRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReadingProfile" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Update reading profile", + "tags": [ + "Reading Profiles" + ] + } + }, + "/v1/reading-profiles/{profile_id}/set-default": { + "post": { + "description": "Set a reading profile as the default.", + "operationId": "set_default_reading_profile_v1_reading_profiles__profile_id__set_default_post", + "parameters": [ + { + "in": "path", + "name": "profile_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Profile Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReadingProfile" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Set as default profile", + "tags": [ + "Reading Profiles" + ] + } + }, + "/v1/saved-filters": { + "get": { + "description": "Return all saved filters for the user.", + "operationId": "list_saved_filters_v1_saved_filters_get", + "parameters": [ + { + "in": "query", + "name": "is_pinned", + "required": false, + "schema": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Is Pinned" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SavedFilterList" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List saved filters", + "tags": [ + "Saved Filters" + ] + }, + "post": { + "description": "Create a new saved filter.", + "operationId": "create_saved_filter_v1_saved_filters_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSavedFilterRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SavedFilter" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Create saved filter", + "tags": [ + "Saved Filters" + ] + } + }, + "/v1/saved-filters/{filter_id}": { + "delete": { + "description": "Delete a saved filter.", + "operationId": "delete_saved_filter_v1_saved_filters__filter_id__delete", + "parameters": [ + { + "in": "path", + "name": "filter_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Filter Id", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Delete saved filter", + "tags": [ + "Saved Filters" + ] + }, + "get": { + "description": "Return detailed information about a saved filter.", + "operationId": "get_saved_filter_v1_saved_filters__filter_id__get", + "parameters": [ + { + "in": "path", + "name": "filter_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Filter Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SavedFilter" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get saved filter", + "tags": [ + "Saved Filters" + ] + }, + "patch": { + "description": "Update a saved filter.", + "operationId": "update_saved_filter_v1_saved_filters__filter_id__patch", + "parameters": [ + { + "in": "path", + "name": "filter_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Filter Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSavedFilterRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SavedFilter" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Update saved filter", + "tags": [ + "Saved Filters" + ] + } + }, + "/v1/saved-filters/{filter_id}/use": { + "post": { + "description": "Mark a filter as used, updating usage count and last_used_at.", + "operationId": "use_saved_filter_v1_saved_filters__filter_id__use_post", + "parameters": [ + { + "in": "path", + "name": "filter_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Filter Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SavedFilter" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Mark filter as used", + "tags": [ + "Saved Filters" + ] + } + }, + "/v1/series": { + "get": { + "description": "Return all series for the user.", + "operationId": "list_series_v1_series_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SeriesList" + } + } + }, + "description": "Successful Response" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List all series", + "tags": [ + "Series" + ] + }, + "post": { + "description": "Create a new series.", + "operationId": "create_series_v1_series_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSeriesRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Series" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Create a new series", + "tags": [ + "Series" + ] + } + }, + "/v1/series/{series_id}": { + "delete": { + "description": "Delete a series. Books are not deleted.", + "operationId": "delete_series_v1_series__series_id__delete", + "parameters": [ + { + "in": "path", + "name": "series_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Series Id", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Delete series", + "tags": [ + "Series" + ] + }, + "get": { + "description": "Return detailed information about a series with its books.", + "operationId": "get_series_v1_series__series_id__get", + "parameters": [ + { + "in": "path", + "name": "series_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Series Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SeriesWithBooks" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get series details", + "tags": [ + "Series" + ] + }, + "patch": { + "description": "Update series properties.", + "operationId": "update_series_v1_series__series_id__patch", + "parameters": [ + { + "in": "path", + "name": "series_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Series Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSeriesRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Series" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Update series", + "tags": [ + "Series" + ] + } + }, + "/v1/shelves": { + "get": { + "description": "Return all shelves for the user, including nested structure.", + "operationId": "list_shelves_v1_shelves_get", + "parameters": [ + { + "in": "query", + "name": "include_books", + "required": false, + "schema": { + "default": false, + "title": "Include Books", + "type": "boolean" + } + }, + { + "in": "query", + "name": "flat", + "required": false, + "schema": { + "default": false, + "title": "Flat", + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ShelfList" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List all shelves", + "tags": [ + "Shelves" + ] + }, + "post": { + "description": "Create a new shelf or sub-shelf.", + "operationId": "create_shelf_v1_shelves_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateShelfRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Shelf" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Create a new shelf", + "tags": [ + "Shelves" + ] + } + }, + "/v1/shelves/{shelf_id}": { + "delete": { + "description": "Delete a shelf. Books are not deleted.", + "operationId": "delete_shelf_v1_shelves__shelf_id__delete", + "parameters": [ + { + "in": "path", + "name": "shelf_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Shelf Id", + "type": "string" + } + }, + { + "description": "Move books to this shelf", + "in": "query", + "name": "move_books_to", + "required": false, + "schema": { + "anyOf": [ + { + "format": "uuid", + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Move books to this shelf", + "title": "Move Books To" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Delete shelf", + "tags": [ + "Shelves" + ] + }, + "get": { + "description": "Return detailed information about a shelf.", + "operationId": "get_shelf_v1_shelves__shelf_id__get", + "parameters": [ + { + "in": "path", + "name": "shelf_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Shelf Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Shelf" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get shelf details", + "tags": [ + "Shelves" + ] + }, + "patch": { + "description": "Update shelf properties.", + "operationId": "update_shelf_v1_shelves__shelf_id__patch", + "parameters": [ + { + "in": "path", + "name": "shelf_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Shelf Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateShelfRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Shelf" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Update shelf", + "tags": [ + "Shelves" + ] + } + }, + "/v1/shelves/{shelf_id}/books": { + "get": { + "description": "Return paginated list of books in this shelf.", + "operationId": "list_shelf_books_v1_shelves__shelf_id__books_get", + "parameters": [ + { + "in": "path", + "name": "shelf_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Shelf Id", + "type": "string" + } + }, + { + "description": "Page number", + "in": "query", + "name": "page", + "required": false, + "schema": { + "default": 1, + "description": "Page number", + "minimum": 1, + "title": "Page", + "type": "integer" + } + }, + { + "description": "Items per page", + "in": "query", + "name": "limit", + "required": false, + "schema": { + "default": 20, + "description": "Items per page", + "maximum": 100, + "minimum": 1, + "title": "Limit", + "type": "integer" + } + }, + { + "description": "Sort field with optional - prefix for descending", + "in": "query", + "name": "sort", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Sort field with optional - prefix for descending", + "title": "Sort" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BookList" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List books in shelf", + "tags": [ + "Shelves" + ] + } + }, + "/v1/shelves/{shelf_id}/books/remove": { + "post": { + "description": "Remove multiple books from this shelf in one request.", + "operationId": "remove_books_from_shelf_v1_shelves__shelf_id__books_remove_post", + "parameters": [ + { + "in": "path", + "name": "shelf_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Shelf Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoveBooksRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RemoveBooksResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Remove multiple books from shelf", + "tags": [ + "Shelves" + ] + } + }, + "/v1/shelves/{shelf_id}/books/{book_id}": { + "delete": { + "description": "Remove a book from this shelf.", + "operationId": "remove_book_from_shelf_v1_shelves__shelf_id__books__book_id__delete", + "parameters": [ + { + "in": "path", + "name": "shelf_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Shelf Id", + "type": "string" + } + }, + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Remove book from shelf", + "tags": [ + "Shelves" + ] + }, + "post": { + "description": "Add a book to this shelf.", + "operationId": "add_book_to_shelf_v1_shelves__shelf_id__books__book_id__post", + "parameters": [ + { + "in": "path", + "name": "shelf_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Shelf Id", + "type": "string" + } + }, + { + "in": "path", + "name": "book_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Book Id", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Add book to shelf", + "tags": [ + "Shelves" + ] + } + }, + "/v1/storage/backends": { + "get": { + "description": "Return all configured storage backends for the user.", + "operationId": "list_storage_backends_v1_storage_backends_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageBackendList" + } + } + }, + "description": "Successful Response" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List storage backends", + "tags": [ + "Storage" + ] + }, + "post": { + "description": "Add a new storage backend configuration.", + "operationId": "create_storage_backend_v1_storage_backends_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateStorageBackendRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageBackend" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Add storage backend", + "tags": [ + "Storage" + ] + } + }, + "/v1/storage/backends/set-primary": { + "post": { + "description": "Set a storage backend as the primary.", + "operationId": "set_primary_storage_backend_v1_storage_backends_set_primary_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SetPrimaryRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageBackend" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Set primary storage backend", + "tags": [ + "Storage" + ] + } + }, + "/v1/storage/backends/{backend_id}": { + "delete": { + "description": "Remove a storage backend configuration.", + "operationId": "delete_storage_backend_v1_storage_backends__backend_id__delete", + "parameters": [ + { + "in": "path", + "name": "backend_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Backend Id", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Remove storage backend", + "tags": [ + "Storage" + ] + }, + "get": { + "description": "Return detailed information about a storage backend.", + "operationId": "get_storage_backend_v1_storage_backends__backend_id__get", + "parameters": [ + { + "in": "path", + "name": "backend_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Backend Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageBackend" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get storage backend details", + "tags": [ + "Storage" + ] + }, + "patch": { + "description": "Update storage backend configuration.", + "operationId": "update_storage_backend_v1_storage_backends__backend_id__patch", + "parameters": [ + { + "in": "path", + "name": "backend_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Backend Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateStorageBackendRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageBackend" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Update storage backend", + "tags": [ + "Storage" + ] + } + }, + "/v1/storage/backends/{backend_id}/test": { + "post": { + "description": "Test the connection to a storage backend.", + "operationId": "test_storage_backend_v1_storage_backends__backend_id__test_post", + "parameters": [ + { + "in": "path", + "name": "backend_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Backend Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageBackend" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Test storage backend connection", + "tags": [ + "Storage" + ] + } + }, + "/v1/sync/powersync-upload": { + "post": { + "description": "Apply one PowerSync CRUD transaction atomically.", + "operationId": "upload_powersync_changes_v1_sync_powersync_upload_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PowerSyncUploadRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PowerSyncUploadResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Upload PowerSync client-side mutations", + "tags": [ + "Sync" + ] + } + }, + "/v1/sync/settings": { + "get": { + "description": "Return public sync capabilities for client custom-server setup.", + "operationId": "get_data_sync_settings_v1_sync_settings_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DataSyncSettingsResponse" + } + } + }, + "description": "Successful Response" + } + }, + "summary": "Get public data sync settings", + "tags": [ + "Sync" + ] + } + }, + "/v1/tags": { + "get": { + "description": "Return all tags for the user.", + "operationId": "list_tags_v1_tags_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TagList" + } + } + }, + "description": "Successful Response" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "List all tags", + "tags": [ + "Tags" + ] + }, + "post": { + "description": "Create a new tag.", + "operationId": "create_tag_v1_tags_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateTagRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Tag" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Create a new tag", + "tags": [ + "Tags" + ] + } + }, + "/v1/tags/{tag_id}": { + "delete": { + "description": "Delete a tag. Removes from all books.", + "operationId": "delete_tag_v1_tags__tag_id__delete", + "parameters": [ + { + "in": "path", + "name": "tag_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Tag Id", + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Delete tag", + "tags": [ + "Tags" + ] + }, + "get": { + "description": "Return detailed information about a tag.", + "operationId": "get_tag_v1_tags__tag_id__get", + "parameters": [ + { + "in": "path", + "name": "tag_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Tag Id", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Tag" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get tag details", + "tags": [ + "Tags" + ] + }, + "patch": { + "description": "Update tag properties.", + "operationId": "update_tag_v1_tags__tag_id__patch", + "parameters": [ + { + "in": "path", + "name": "tag_id", + "required": true, + "schema": { + "format": "uuid", + "title": "Tag Id", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTagRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Tag" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Update tag", + "tags": [ + "Tags" + ] + } + }, + "/v1/users/me": { + "delete": { + "description": "Disable the user account and revoke active sessions.", + "operationId": "delete_current_user_v1_users_me_delete", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteAccountRequest" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Delete current user account", + "tags": [ + "Users" + ] + }, + "get": { + "description": "Return the authenticated user's profile information.", + "operationId": "get_current_user_v1_users_me_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "description": "Successful Response" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get current user profile", + "tags": [ + "Users" + ] + }, + "patch": { + "description": "Update the authenticated user's profile information.", + "operationId": "update_current_user_v1_users_me_patch", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateUserRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/User" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Update current user profile", + "tags": [ + "Users" + ] + } + }, + "/v1/users/me/change-password": { + "post": { + "description": "Change the user's password and revoke existing sessions.", + "operationId": "change_password_v1_users_me_change_password_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangePasswordRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MessageResponse" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Change password", + "tags": [ + "Users" + ] + } + }, + "/v1/users/me/preferences": { + "get": { + "description": "Return the user's application preferences.", + "operationId": "get_user_preferences_v1_users_me_preferences_get", + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserPreferences" + } + } + }, + "description": "Successful Response" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Get user preferences", + "tags": [ + "Users" + ] + }, + "put": { + "description": "Update the user's application preferences.", + "operationId": "update_user_preferences_v1_users_me_preferences_put", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserPreferences" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserPreferences" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "security": [ + { + "HTTPBearer": [] + } + ], + "summary": "Update user preferences", + "tags": [ + "Users" + ] + } + } + } +} diff --git a/_static/openapi.yaml b/_static/openapi.yaml deleted file mode 100644 index cafd39b..0000000 --- a/_static/openapi.yaml +++ /dev/null @@ -1,5263 +0,0 @@ -openapi: 3.0.3 -info: - title: Papyrus Server API - version: 1.0.0 - description: | - REST API for Papyrus - a cross-platform book management application. - - ## Overview - - The Papyrus Server handles metadata storage and synchronization for the Papyrus - e-book reader application. It provides endpoints for: - - - **Authentication**: User registration, login, OAuth, and session management - - **Books**: CRUD operations for book metadata and file references - - **Organization**: Shelves, tags, and series management - - **Annotations**: Highlights, notes, and bookmarks - - **Progress**: Reading sessions and statistics - - **Goals**: Reading goal tracking - - **Sync**: Cross-device synchronization - - **Storage**: File storage backend configuration - - **Files**: File upload/download (when server is file backend) - - ## Authentication - - Most endpoints require authentication via JWT Bearer token. Obtain tokens - through the `/auth/login` or `/auth/oauth/google` endpoints. - - ``` - Authorization: Bearer - ``` - - Access tokens expire after 1 hour. Use the refresh token to obtain new - access tokens via `/auth/refresh`. - - ## Rate Limiting - - Rate limits are enforced per user: - - | Endpoint Category | Limit | - |-------------------|-------| - | Authentication | 5 requests/minute | - | General API | 100 requests/minute | - | File uploads | 10 requests/minute | - | Batch operations | 20 requests/minute | - - Rate limit information is returned in response headers: - - ``` - X-RateLimit-Limit: 100 - X-RateLimit-Remaining: 95 - X-RateLimit-Reset: 1640000000 - ``` - - When rate limited, the API returns HTTP 429 with a `Retry-After` header. - - ## Error Handling - - All errors follow a consistent format: - - ```json - { - "error": { - "code": "VALIDATION_ERROR", - "message": "Human-readable error message", - "details": { ... } - } - } - ``` - - contact: - name: Papyrus Support - url: https://github.com/Eoic/Papyrus - license: - name: AGPL-3.0 - url: https://www.gnu.org/licenses/agpl-3.0.html - -servers: - - url: https://api.papyrus.app/v1 - description: Production server - - url: https://staging-api.papyrus.app/v1 - description: Staging server - - url: http://localhost:8080/v1 - description: Local development - -tags: - - name: Auth - description: Authentication and session management - - name: Users - description: User profile and preferences - - name: Books - description: Book metadata and file management - - name: Shelves - description: Book collection organization - - name: Tags - description: Color-coded book labels - - name: Series - description: Book series grouping - - name: Annotations - description: Text highlights with notes - - name: Notes - description: Free-form book notes - - name: Bookmarks - description: Saved reading positions - - name: Progress - description: Reading sessions and statistics - - name: Goals - description: Reading goal management - - name: Sync - description: Cross-device synchronization - - name: Storage - description: File storage backend configuration - - name: Files - description: File upload and download - -security: - - bearerAuth: [] - -paths: - # ============================================================================ - # Authentication - # ============================================================================ - /auth/register: - post: - tags: [Auth] - summary: Register a new user account - description: | - Creates a new user account with email and password. - A verification email is sent to the provided address. - The account remains inactive until email is verified. - operationId: registerUser - security: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/RegisterRequest' - responses: - '201': - description: User registered successfully - content: - application/json: - schema: - $ref: '#/components/schemas/RegisterResponse' - '400': - $ref: '#/components/responses/ValidationError' - '409': - description: Email already registered - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '429': - $ref: '#/components/responses/RateLimitError' - - /auth/login: - post: - tags: [Auth] - summary: Login with email and password - description: | - Authenticates a user with email and password credentials. - Returns access and refresh tokens on success. - operationId: loginUser - security: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/LoginRequest' - responses: - '200': - description: Login successful - content: - application/json: - schema: - $ref: '#/components/schemas/AuthTokens' - '400': - $ref: '#/components/responses/ValidationError' - '401': - description: Invalid credentials - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '403': - description: Account not verified or disabled - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '429': - $ref: '#/components/responses/RateLimitError' - - /auth/oauth/google: - post: - tags: [Auth] - summary: Login or register with Google OAuth - description: | - Authenticates a user via Google OAuth 2.0. - Creates a new account if the Google email is not registered. - Links Google account if email matches existing account. - operationId: googleOAuth - security: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/GoogleOAuthRequest' - responses: - '200': - description: Authentication successful - content: - application/json: - schema: - $ref: '#/components/schemas/AuthTokens' - '400': - $ref: '#/components/responses/ValidationError' - '401': - description: Invalid OAuth token - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /auth/refresh: - post: - tags: [Auth] - summary: Refresh access token - description: | - Exchanges a valid refresh token for a new access token. - The refresh token is rotated for security. - operationId: refreshToken - security: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/RefreshTokenRequest' - responses: - '200': - description: Token refreshed successfully - content: - application/json: - schema: - $ref: '#/components/schemas/AuthTokens' - '401': - description: Invalid or expired refresh token - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /auth/logout: - post: - tags: [Auth] - summary: Logout and invalidate tokens - description: | - Invalidates the current session and all associated tokens. - Optionally invalidates all sessions for the user. - operationId: logoutUser - requestBody: - content: - application/json: - schema: - type: object - properties: - all_devices: - type: boolean - description: Logout from all devices - default: false - responses: - '204': - description: Logout successful - '401': - $ref: '#/components/responses/UnauthorizedError' - - /auth/verify-email: - post: - tags: [Auth] - summary: Verify email address - description: | - Verifies the user's email address using the token sent via email. - Activates the account on successful verification. - operationId: verifyEmail - security: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [token] - properties: - token: - type: string - description: Email verification token - responses: - '200': - description: Email verified successfully - content: - application/json: - schema: - type: object - properties: - message: - type: string - example: Email verified successfully - '400': - description: Invalid or expired token - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /auth/resend-verification: - post: - tags: [Auth] - summary: Resend verification email - description: Sends a new verification email to the user's registered address. - operationId: resendVerification - security: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [email] - properties: - email: - type: string - format: email - responses: - '200': - description: Verification email sent (if account exists) - content: - application/json: - schema: - type: object - properties: - message: - type: string - example: If the email is registered, a verification link has been sent - '429': - $ref: '#/components/responses/RateLimitError' - - /auth/forgot-password: - post: - tags: [Auth] - summary: Request password reset - description: | - Sends a password reset link to the user's email. - For security, always returns success even if email doesn't exist. - operationId: forgotPassword - security: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [email] - properties: - email: - type: string - format: email - responses: - '200': - description: Password reset email sent (if account exists) - content: - application/json: - schema: - type: object - properties: - message: - type: string - example: If the email is registered, a reset link has been sent - '429': - $ref: '#/components/responses/RateLimitError' - - /auth/reset-password: - post: - tags: [Auth] - summary: Reset password with token - description: | - Resets the user's password using the token from the reset email. - Invalidates all existing sessions after password change. - operationId: resetPassword - security: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [token, password] - properties: - token: - type: string - description: Password reset token - password: - type: string - format: password - minLength: 8 - description: New password - responses: - '200': - description: Password reset successful - content: - application/json: - schema: - type: object - properties: - message: - type: string - example: Password has been reset successfully - '400': - description: Invalid or expired token, or weak password - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - # ============================================================================ - # Users - # ============================================================================ - /users/me: - get: - tags: [Users] - summary: Get current user profile - description: Returns the authenticated user's profile information. - operationId: getCurrentUser - responses: - '200': - description: User profile - content: - application/json: - schema: - $ref: '#/components/schemas/User' - '401': - $ref: '#/components/responses/UnauthorizedError' - - patch: - tags: [Users] - summary: Update current user profile - description: Updates the authenticated user's profile information. - operationId: updateCurrentUser - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateUserRequest' - responses: - '200': - description: Profile updated - content: - application/json: - schema: - $ref: '#/components/schemas/User' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - - delete: - tags: [Users] - summary: Delete current user account - description: | - Permanently deletes the user account and all associated data. - Requires password confirmation for security. - Data is scheduled for deletion within 30 days. - operationId: deleteCurrentUser - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [password] - properties: - password: - type: string - format: password - description: Current password for confirmation - responses: - '204': - description: Account scheduled for deletion - '401': - $ref: '#/components/responses/UnauthorizedError' - '403': - description: Invalid password - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /users/me/preferences: - get: - tags: [Users] - summary: Get user preferences - description: Returns the user's application preferences. - operationId: getUserPreferences - responses: - '200': - description: User preferences - content: - application/json: - schema: - $ref: '#/components/schemas/UserPreferences' - '401': - $ref: '#/components/responses/UnauthorizedError' - - put: - tags: [Users] - summary: Update user preferences - description: Updates the user's application preferences. - operationId: updateUserPreferences - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UserPreferences' - responses: - '200': - description: Preferences updated - content: - application/json: - schema: - $ref: '#/components/schemas/UserPreferences' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - - /users/me/change-password: - post: - tags: [Users] - summary: Change password - description: Changes the user's password. Requires current password verification. - operationId: changePassword - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [current_password, new_password] - properties: - current_password: - type: string - format: password - new_password: - type: string - format: password - minLength: 8 - responses: - '200': - description: Password changed successfully - content: - application/json: - schema: - type: object - properties: - message: - type: string - example: Password changed successfully - '400': - description: Weak password - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - $ref: '#/components/responses/UnauthorizedError' - '403': - description: Current password incorrect - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - # ============================================================================ - # Books - # ============================================================================ - /books: - get: - tags: [Books] - summary: List user's books - description: | - Returns a paginated list of books in the user's library. - Supports filtering, sorting, and search. - operationId: listBooks - parameters: - - $ref: '#/components/parameters/PageParam' - - $ref: '#/components/parameters/LimitParam' - - $ref: '#/components/parameters/SortParam' - - name: status - in: query - schema: - $ref: '#/components/schemas/ReadingStatus' - description: Filter by reading status - - name: shelf_id - in: query - schema: - type: string - format: uuid - description: Filter by shelf - - name: tag_id - in: query - schema: - type: string - format: uuid - description: Filter by tag - - name: series_id - in: query - schema: - type: string - format: uuid - description: Filter by series - - name: is_physical - in: query - schema: - type: boolean - description: Filter by physical/digital - - name: is_favorite - in: query - schema: - type: boolean - description: Filter favorites only - - name: search - in: query - schema: - type: string - description: Search in title, author, description - - name: query - in: query - schema: - type: string - description: Advanced query language filter - responses: - '200': - description: List of books - content: - application/json: - schema: - $ref: '#/components/schemas/BookList' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - - post: - tags: [Books] - summary: Create a new book - description: | - Adds a new book to the user's library. - For digital books, use the file upload endpoint first. - operationId: createBook - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateBookRequest' - responses: - '201': - description: Book created - content: - application/json: - schema: - $ref: '#/components/schemas/Book' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - - /books/{book_id}: - parameters: - - $ref: '#/components/parameters/BookIdParam' - - get: - tags: [Books] - summary: Get book details - description: Returns detailed information about a specific book. - operationId: getBook - responses: - '200': - description: Book details - content: - application/json: - schema: - $ref: '#/components/schemas/Book' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - patch: - tags: [Books] - summary: Update book metadata - description: Updates book metadata fields. - operationId: updateBook - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateBookRequest' - responses: - '200': - description: Book updated - content: - application/json: - schema: - $ref: '#/components/schemas/Book' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - delete: - tags: [Books] - summary: Delete a book - description: | - Removes a book from the library. - Optionally deletes the associated file from storage. - operationId: deleteBook - parameters: - - name: delete_file - in: query - schema: - type: boolean - default: false - description: Also delete the book file from storage - responses: - '204': - description: Book deleted - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - /books/{book_id}/cover: - parameters: - - $ref: '#/components/parameters/BookIdParam' - - get: - tags: [Books] - summary: Get book cover image - description: Returns the book's cover image. - operationId: getBookCover - responses: - '200': - description: Cover image - content: - image/jpeg: - schema: - type: string - format: binary - image/png: - schema: - type: string - format: binary - '302': - description: Redirect to cover URL - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - put: - tags: [Books] - summary: Upload book cover image - description: Uploads or replaces the book's cover image. - operationId: uploadBookCover - requestBody: - required: true - content: - multipart/form-data: - schema: - type: object - properties: - file: - type: string - format: binary - application/json: - schema: - type: object - properties: - url: - type: string - format: uri - description: URL to fetch cover from - responses: - '200': - description: Cover uploaded - content: - application/json: - schema: - $ref: '#/components/schemas/Book' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - /books/{book_id}/shelves: - parameters: - - $ref: '#/components/parameters/BookIdParam' - - get: - tags: [Books] - summary: Get book's shelves - description: Returns the shelves this book belongs to. - operationId: getBookShelves - responses: - '200': - description: List of shelves - content: - application/json: - schema: - type: object - properties: - shelves: - type: array - items: - $ref: '#/components/schemas/Shelf' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - put: - tags: [Books] - summary: Set book's shelves - description: Replaces all shelf assignments for this book. - operationId: setBookShelves - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [shelf_ids] - properties: - shelf_ids: - type: array - items: - type: string - format: uuid - responses: - '200': - description: Shelves updated - content: - application/json: - schema: - type: object - properties: - shelves: - type: array - items: - $ref: '#/components/schemas/Shelf' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - /books/{book_id}/tags: - parameters: - - $ref: '#/components/parameters/BookIdParam' - - get: - tags: [Books] - summary: Get book's tags - description: Returns the tags assigned to this book. - operationId: getBookTags - responses: - '200': - description: List of tags - content: - application/json: - schema: - type: object - properties: - tags: - type: array - items: - $ref: '#/components/schemas/Tag' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - put: - tags: [Books] - summary: Set book's tags - description: | - Replaces all tag assignments for this book. - Maximum 10 tags per book. - operationId: setBookTags - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [tag_ids] - properties: - tag_ids: - type: array - items: - type: string - format: uuid - maxItems: 10 - responses: - '200': - description: Tags updated - content: - application/json: - schema: - type: object - properties: - tags: - type: array - items: - $ref: '#/components/schemas/Tag' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - /books/{book_id}/progress: - parameters: - - $ref: '#/components/parameters/BookIdParam' - - get: - tags: [Books] - summary: Get reading progress - description: Returns the current reading progress for a book. - operationId: getBookProgress - responses: - '200': - description: Reading progress - content: - application/json: - schema: - $ref: '#/components/schemas/ReadingProgress' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - put: - tags: [Books] - summary: Update reading progress - description: Updates the reading position and status for a book. - operationId: updateBookProgress - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateProgressRequest' - responses: - '200': - description: Progress updated - content: - application/json: - schema: - $ref: '#/components/schemas/ReadingProgress' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - /books/batch: - post: - tags: [Books] - summary: Batch create books - description: | - Creates multiple books in a single request. - Useful for bulk imports. Maximum 50 books per request. - operationId: batchCreateBooks - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [books] - properties: - books: - type: array - items: - $ref: '#/components/schemas/CreateBookRequest' - maxItems: 50 - responses: - '201': - description: Books created - content: - application/json: - schema: - type: object - properties: - created: - type: array - items: - $ref: '#/components/schemas/Book' - errors: - type: array - items: - type: object - properties: - index: - type: integer - description: Index in the input array - error: - $ref: '#/components/schemas/Error' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - - patch: - tags: [Books] - summary: Batch update books - description: | - Updates multiple books in a single request. - Useful for bulk tagging, shelf assignment, or status changes. - operationId: batchUpdateBooks - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [book_ids] - properties: - book_ids: - type: array - items: - type: string - format: uuid - maxItems: 100 - description: Books to update - updates: - type: object - description: Fields to update on all books - properties: - reading_status: - $ref: '#/components/schemas/ReadingStatus' - is_favorite: - type: boolean - rating: - type: integer - minimum: 1 - maximum: 5 - add_tag_ids: - type: array - items: - type: string - format: uuid - description: Tags to add to all books - remove_tag_ids: - type: array - items: - type: string - format: uuid - description: Tags to remove from all books - add_shelf_ids: - type: array - items: - type: string - format: uuid - description: Shelves to add books to - remove_shelf_ids: - type: array - items: - type: string - format: uuid - description: Shelves to remove books from - responses: - '200': - description: Books updated - content: - application/json: - schema: - type: object - properties: - updated_count: - type: integer - errors: - type: array - items: - type: object - properties: - book_id: - type: string - format: uuid - error: - $ref: '#/components/schemas/Error' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - - delete: - tags: [Books] - summary: Batch delete books - description: | - Deletes multiple books in a single request. - Optionally deletes associated files from storage. - operationId: batchDeleteBooks - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [book_ids] - properties: - book_ids: - type: array - items: - type: string - format: uuid - maxItems: 100 - delete_files: - type: boolean - default: false - description: Also delete book files from storage - responses: - '200': - description: Books deleted - content: - application/json: - schema: - type: object - properties: - deleted_count: - type: integer - errors: - type: array - items: - type: object - properties: - book_id: - type: string - format: uuid - error: - $ref: '#/components/schemas/Error' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - - /books/metadata/fetch: - post: - tags: [Books] - summary: Fetch metadata from online sources - description: | - Searches online sources (Open Library, Google Books) for book metadata. - Returns multiple matches for user selection. - operationId: fetchBookMetadata - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - isbn: - type: string - description: ISBN-10 or ISBN-13 - title: - type: string - author: - type: string - responses: - '200': - description: Metadata search results - content: - application/json: - schema: - type: object - properties: - results: - type: array - items: - $ref: '#/components/schemas/MetadataSearchResult' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - - # ============================================================================ - # Shelves - # ============================================================================ - /shelves: - get: - tags: [Shelves] - summary: List all shelves - description: Returns all shelves for the user, including nested structure. - operationId: listShelves - parameters: - - name: include_books - in: query - schema: - type: boolean - default: false - description: Include book counts - - name: flat - in: query - schema: - type: boolean - default: false - description: Return flat list instead of tree - responses: - '200': - description: List of shelves - content: - application/json: - schema: - $ref: '#/components/schemas/ShelfList' - '401': - $ref: '#/components/responses/UnauthorizedError' - - post: - tags: [Shelves] - summary: Create a new shelf - description: Creates a new shelf or sub-shelf. - operationId: createShelf - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateShelfRequest' - responses: - '201': - description: Shelf created - content: - application/json: - schema: - $ref: '#/components/schemas/Shelf' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '409': - description: Shelf name already exists at this level - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /shelves/{shelf_id}: - parameters: - - $ref: '#/components/parameters/ShelfIdParam' - - get: - tags: [Shelves] - summary: Get shelf details - description: Returns detailed information about a shelf. - operationId: getShelf - responses: - '200': - description: Shelf details - content: - application/json: - schema: - $ref: '#/components/schemas/Shelf' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - patch: - tags: [Shelves] - summary: Update shelf - description: Updates shelf properties. - operationId: updateShelf - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateShelfRequest' - responses: - '200': - description: Shelf updated - content: - application/json: - schema: - $ref: '#/components/schemas/Shelf' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - delete: - tags: [Shelves] - summary: Delete shelf - description: | - Deletes a shelf. Books in the shelf are not deleted. - Cannot delete default shelves. - operationId: deleteShelf - responses: - '204': - description: Shelf deleted - '401': - $ref: '#/components/responses/UnauthorizedError' - '403': - description: Cannot delete default shelf - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - $ref: '#/components/responses/NotFoundError' - - /shelves/{shelf_id}/books: - parameters: - - $ref: '#/components/parameters/ShelfIdParam' - - get: - tags: [Shelves] - summary: List books in shelf - description: Returns books in this shelf with pagination. - operationId: listShelfBooks - parameters: - - $ref: '#/components/parameters/PageParam' - - $ref: '#/components/parameters/LimitParam' - - $ref: '#/components/parameters/SortParam' - responses: - '200': - description: List of books - content: - application/json: - schema: - $ref: '#/components/schemas/BookList' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - post: - tags: [Shelves] - summary: Add books to shelf - description: Adds one or more books to the shelf. - operationId: addBooksToShelf - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [book_ids] - properties: - book_ids: - type: array - items: - type: string - format: uuid - responses: - '200': - description: Books added - content: - application/json: - schema: - type: object - properties: - added_count: - type: integer - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - /shelves/{shelf_id}/books/remove: - parameters: - - $ref: '#/components/parameters/ShelfIdParam' - - post: - tags: [Shelves] - summary: Remove books from shelf - description: Removes one or more books from the shelf. - operationId: removeBooksFromShelf - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [book_ids] - properties: - book_ids: - type: array - items: - type: string - format: uuid - responses: - '200': - description: Books removed - content: - application/json: - schema: - type: object - properties: - removed_count: - type: integer - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - # ============================================================================ - # Tags - # ============================================================================ - /tags: - get: - tags: [Tags] - summary: List all tags - description: Returns all tags for the user. - operationId: listTags - parameters: - - name: include_counts - in: query - schema: - type: boolean - default: false - description: Include book counts for each tag - responses: - '200': - description: List of tags - content: - application/json: - schema: - $ref: '#/components/schemas/TagList' - '401': - $ref: '#/components/responses/UnauthorizedError' - - post: - tags: [Tags] - summary: Create a new tag - description: Creates a new tag with name and color. - operationId: createTag - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateTagRequest' - responses: - '201': - description: Tag created - content: - application/json: - schema: - $ref: '#/components/schemas/Tag' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '409': - description: Tag name already exists - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /tags/{tag_id}: - parameters: - - $ref: '#/components/parameters/TagIdParam' - - get: - tags: [Tags] - summary: Get tag details - description: Returns detailed information about a tag. - operationId: getTag - responses: - '200': - description: Tag details - content: - application/json: - schema: - $ref: '#/components/schemas/Tag' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - patch: - tags: [Tags] - summary: Update tag - description: Updates tag name or color. - operationId: updateTag - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateTagRequest' - responses: - '200': - description: Tag updated - content: - application/json: - schema: - $ref: '#/components/schemas/Tag' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - delete: - tags: [Tags] - summary: Delete tag - description: Deletes a tag and removes it from all books. - operationId: deleteTag - responses: - '204': - description: Tag deleted - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - /tags/{tag_id}/books: - parameters: - - $ref: '#/components/parameters/TagIdParam' - - get: - tags: [Tags] - summary: List books with tag - description: Returns books that have this tag. - operationId: listTagBooks - parameters: - - $ref: '#/components/parameters/PageParam' - - $ref: '#/components/parameters/LimitParam' - responses: - '200': - description: List of books - content: - application/json: - schema: - $ref: '#/components/schemas/BookList' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - # ============================================================================ - # Series - # ============================================================================ - /series: - get: - tags: [Series] - summary: List all series - description: Returns all series for the user. - operationId: listSeries - parameters: - - name: include_books - in: query - schema: - type: boolean - default: false - description: Include book counts - responses: - '200': - description: List of series - content: - application/json: - schema: - $ref: '#/components/schemas/SeriesList' - '401': - $ref: '#/components/responses/UnauthorizedError' - - post: - tags: [Series] - summary: Create a new series - description: Creates a new series. - operationId: createSeries - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateSeriesRequest' - responses: - '201': - description: Series created - content: - application/json: - schema: - $ref: '#/components/schemas/Series' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '409': - description: Series name already exists - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /series/{series_id}: - parameters: - - $ref: '#/components/parameters/SeriesIdParam' - - get: - tags: [Series] - summary: Get series details - description: Returns detailed information about a series including its books. - operationId: getSeries - responses: - '200': - description: Series details - content: - application/json: - schema: - $ref: '#/components/schemas/SeriesWithBooks' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - patch: - tags: [Series] - summary: Update series - description: Updates series information. - operationId: updateSeries - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateSeriesRequest' - responses: - '200': - description: Series updated - content: - application/json: - schema: - $ref: '#/components/schemas/Series' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - delete: - tags: [Series] - summary: Delete series - description: Deletes a series. Books in the series are not deleted. - operationId: deleteSeries - responses: - '204': - description: Series deleted - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - # ============================================================================ - # Annotations - # ============================================================================ - /annotations: - get: - tags: [Annotations] - summary: List all annotations - description: Returns all annotations across all books. - operationId: listAnnotations - parameters: - - $ref: '#/components/parameters/PageParam' - - $ref: '#/components/parameters/LimitParam' - - name: book_id - in: query - schema: - type: string - format: uuid - description: Filter by book - - name: color - in: query - schema: - type: string - description: Filter by highlight color - - name: search - in: query - schema: - type: string - description: Search in highlighted text and notes - responses: - '200': - description: List of annotations - content: - application/json: - schema: - $ref: '#/components/schemas/AnnotationList' - '401': - $ref: '#/components/responses/UnauthorizedError' - - /annotations/export: - post: - tags: [Annotations] - summary: Export annotations - description: | - Exports annotations to a structured file format. - Can export all annotations or filter by book/color. - operationId: exportAnnotations - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [format] - properties: - format: - type: string - enum: [markdown, pdf, txt, json, html] - description: Export file format - book_ids: - type: array - items: - type: string - format: uuid - description: Filter to specific books (all if empty) - colors: - type: array - items: - type: string - description: Filter by highlight colors - include_notes: - type: boolean - default: true - description: Include annotation notes - include_context: - type: boolean - default: false - description: Include surrounding text context - group_by: - type: string - enum: [book, chapter, color, date] - default: book - description: How to group annotations in export - responses: - '200': - description: Export file - content: - text/markdown: - schema: - type: string - format: binary - application/pdf: - schema: - type: string - format: binary - text/plain: - schema: - type: string - format: binary - application/json: - schema: - type: string - format: binary - text/html: - schema: - type: string - format: binary - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - - /books/{book_id}/annotations: - parameters: - - $ref: '#/components/parameters/BookIdParam' - - get: - tags: [Annotations] - summary: List book annotations - description: Returns all annotations for a specific book. - operationId: listBookAnnotations - parameters: - - $ref: '#/components/parameters/PageParam' - - $ref: '#/components/parameters/LimitParam' - responses: - '200': - description: List of annotations - content: - application/json: - schema: - $ref: '#/components/schemas/AnnotationList' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - post: - tags: [Annotations] - summary: Create annotation - description: Creates a new text highlight annotation. - operationId: createAnnotation - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateAnnotationRequest' - responses: - '201': - description: Annotation created - content: - application/json: - schema: - $ref: '#/components/schemas/Annotation' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - - /books/{book_id}/annotations/export: - parameters: - - $ref: '#/components/parameters/BookIdParam' - - get: - tags: [Annotations] - summary: Export book annotations - description: Exports all annotations for a specific book. - operationId: exportBookAnnotations - parameters: - - name: format - in: query - required: true - schema: - type: string - enum: [markdown, pdf, txt, json, html] - - name: include_notes - in: query - schema: - type: boolean - default: true - - name: include_context - in: query - schema: - type: boolean - default: false - responses: - '200': - description: Export file - content: - text/markdown: - schema: - type: string - format: binary - application/pdf: - schema: - type: string - format: binary - text/plain: - schema: - type: string - format: binary - application/json: - schema: - type: string - format: binary - text/html: - schema: - type: string - format: binary - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - /annotations/{annotation_id}: - parameters: - - $ref: '#/components/parameters/AnnotationIdParam' - - get: - tags: [Annotations] - summary: Get annotation details - description: Returns detailed information about an annotation. - operationId: getAnnotation - responses: - '200': - description: Annotation details - content: - application/json: - schema: - $ref: '#/components/schemas/Annotation' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - patch: - tags: [Annotations] - summary: Update annotation - description: Updates annotation color or note. - operationId: updateAnnotation - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateAnnotationRequest' - responses: - '200': - description: Annotation updated - content: - application/json: - schema: - $ref: '#/components/schemas/Annotation' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - delete: - tags: [Annotations] - summary: Delete annotation - description: Deletes an annotation. - operationId: deleteAnnotation - responses: - '204': - description: Annotation deleted - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - # ============================================================================ - # Notes - # ============================================================================ - /notes: - get: - tags: [Notes] - summary: List all notes - description: Returns all notes across all books. - operationId: listNotes - parameters: - - $ref: '#/components/parameters/PageParam' - - $ref: '#/components/parameters/LimitParam' - - name: book_id - in: query - schema: - type: string - format: uuid - description: Filter by book - - name: search - in: query - schema: - type: string - description: Search in note title and content - responses: - '200': - description: List of notes - content: - application/json: - schema: - $ref: '#/components/schemas/NoteList' - '401': - $ref: '#/components/responses/UnauthorizedError' - - /books/{book_id}/notes: - parameters: - - $ref: '#/components/parameters/BookIdParam' - - get: - tags: [Notes] - summary: List book notes - description: Returns all notes for a specific book. - operationId: listBookNotes - responses: - '200': - description: List of notes - content: - application/json: - schema: - $ref: '#/components/schemas/NoteList' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - post: - tags: [Notes] - summary: Create note - description: Creates a new free-form note for a book. - operationId: createNote - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateNoteRequest' - responses: - '201': - description: Note created - content: - application/json: - schema: - $ref: '#/components/schemas/Note' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - /notes/{note_id}: - parameters: - - $ref: '#/components/parameters/NoteIdParam' - - get: - tags: [Notes] - summary: Get note details - description: Returns detailed information about a note. - operationId: getNote - responses: - '200': - description: Note details - content: - application/json: - schema: - $ref: '#/components/schemas/Note' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - patch: - tags: [Notes] - summary: Update note - description: Updates note title or content. - operationId: updateNote - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateNoteRequest' - responses: - '200': - description: Note updated - content: - application/json: - schema: - $ref: '#/components/schemas/Note' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - delete: - tags: [Notes] - summary: Delete note - description: Deletes a note. - operationId: deleteNote - responses: - '204': - description: Note deleted - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - # ============================================================================ - # Bookmarks - # ============================================================================ - /books/{book_id}/bookmarks: - parameters: - - $ref: '#/components/parameters/BookIdParam' - - get: - tags: [Bookmarks] - summary: List book bookmarks - description: Returns all bookmarks for a specific book. - operationId: listBookBookmarks - responses: - '200': - description: List of bookmarks - content: - application/json: - schema: - $ref: '#/components/schemas/BookmarkList' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - post: - tags: [Bookmarks] - summary: Create bookmark - description: Creates a new bookmark at a specific position. - operationId: createBookmark - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateBookmarkRequest' - responses: - '201': - description: Bookmark created - content: - application/json: - schema: - $ref: '#/components/schemas/Bookmark' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - /bookmarks/{bookmark_id}: - parameters: - - $ref: '#/components/parameters/BookmarkIdParam' - - get: - tags: [Bookmarks] - summary: Get bookmark details - description: Returns detailed information about a bookmark. - operationId: getBookmark - responses: - '200': - description: Bookmark details - content: - application/json: - schema: - $ref: '#/components/schemas/Bookmark' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - patch: - tags: [Bookmarks] - summary: Update bookmark - description: Updates bookmark note or color. - operationId: updateBookmark - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateBookmarkRequest' - responses: - '200': - description: Bookmark updated - content: - application/json: - schema: - $ref: '#/components/schemas/Bookmark' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - delete: - tags: [Bookmarks] - summary: Delete bookmark - description: Deletes a bookmark. - operationId: deleteBookmark - responses: - '204': - description: Bookmark deleted - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - # ============================================================================ - # Progress & Statistics - # ============================================================================ - /progress/sessions: - get: - tags: [Progress] - summary: List reading sessions - description: Returns reading session history. - operationId: listReadingSessions - parameters: - - $ref: '#/components/parameters/PageParam' - - $ref: '#/components/parameters/LimitParam' - - name: book_id - in: query - schema: - type: string - format: uuid - description: Filter by book - - name: start_date - in: query - schema: - type: string - format: date - description: Filter sessions after this date - - name: end_date - in: query - schema: - type: string - format: date - description: Filter sessions before this date - responses: - '200': - description: List of reading sessions - content: - application/json: - schema: - $ref: '#/components/schemas/ReadingSessionList' - '401': - $ref: '#/components/responses/UnauthorizedError' - - post: - tags: [Progress] - summary: Record reading session - description: Records a completed reading session. - operationId: createReadingSession - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateReadingSessionRequest' - responses: - '201': - description: Session recorded - content: - application/json: - schema: - $ref: '#/components/schemas/ReadingSession' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - - /progress/sessions/{session_id}: - parameters: - - name: session_id - in: path - required: true - schema: - type: string - format: uuid - - get: - tags: [Progress] - summary: Get session details - description: Returns detailed information about a reading session. - operationId: getReadingSession - responses: - '200': - description: Session details - content: - application/json: - schema: - $ref: '#/components/schemas/ReadingSession' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - delete: - tags: [Progress] - summary: Delete session - description: Deletes a reading session record. - operationId: deleteReadingSession - responses: - '204': - description: Session deleted - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - /progress/statistics: - get: - tags: [Progress] - summary: Get reading statistics - description: Returns aggregated reading statistics. - operationId: getReadingStatistics - parameters: - - name: period - in: query - schema: - type: string - enum: [today, week, month, year, all, custom] - default: month - - name: start_date - in: query - schema: - type: string - format: date - description: Start date for custom period - - name: end_date - in: query - schema: - type: string - format: date - description: End date for custom period - - name: book_id - in: query - schema: - type: string - format: uuid - description: Statistics for specific book - - name: shelf_id - in: query - schema: - type: string - format: uuid - description: Statistics for books in shelf - responses: - '200': - description: Reading statistics - content: - application/json: - schema: - $ref: '#/components/schemas/ReadingStatistics' - '401': - $ref: '#/components/responses/UnauthorizedError' - - # ============================================================================ - # Goals - # ============================================================================ - /goals: - get: - tags: [Goals] - summary: List reading goals - description: Returns all reading goals for the user. - operationId: listGoals - parameters: - - name: is_active - in: query - schema: - type: boolean - description: Filter by active status - - name: is_completed - in: query - schema: - type: boolean - description: Filter by completion status - responses: - '200': - description: List of goals - content: - application/json: - schema: - $ref: '#/components/schemas/GoalList' - '401': - $ref: '#/components/responses/UnauthorizedError' - - post: - tags: [Goals] - summary: Create reading goal - description: Creates a new reading goal. - operationId: createGoal - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateGoalRequest' - responses: - '201': - description: Goal created - content: - application/json: - schema: - $ref: '#/components/schemas/Goal' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - - /goals/{goal_id}: - parameters: - - $ref: '#/components/parameters/GoalIdParam' - - get: - tags: [Goals] - summary: Get goal details - description: Returns detailed information about a goal. - operationId: getGoal - responses: - '200': - description: Goal details - content: - application/json: - schema: - $ref: '#/components/schemas/Goal' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - patch: - tags: [Goals] - summary: Update goal - description: Updates goal properties. - operationId: updateGoal - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateGoalRequest' - responses: - '200': - description: Goal updated - content: - application/json: - schema: - $ref: '#/components/schemas/Goal' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - delete: - tags: [Goals] - summary: Delete goal - description: Deletes a reading goal. - operationId: deleteGoal - responses: - '204': - description: Goal deleted - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - /goals/{goal_id}/progress: - parameters: - - $ref: '#/components/parameters/GoalIdParam' - - put: - tags: [Goals] - summary: Update goal progress - description: Manually updates the current progress value. - operationId: updateGoalProgress - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [current_value] - properties: - current_value: - type: integer - minimum: 0 - note: - type: string - description: Optional note for this update - responses: - '200': - description: Progress updated - content: - application/json: - schema: - $ref: '#/components/schemas/Goal' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - # ============================================================================ - # Sync - # ============================================================================ - /sync/changes: - get: - tags: [Sync] - summary: Get changes since timestamp - description: | - Returns all changes since the specified timestamp. - Used for incremental synchronization. - operationId: getChanges - parameters: - - name: since - in: query - required: true - schema: - type: string - format: date-time - description: Timestamp to get changes since - - name: entity_types - in: query - schema: - type: array - items: - type: string - enum: [book, shelf, tag, series, annotation, note, bookmark, reading_session, reading_goal, reading_profile] - description: Filter by entity types - responses: - '200': - description: List of changes - content: - application/json: - schema: - $ref: '#/components/schemas/SyncChanges' - '401': - $ref: '#/components/responses/UnauthorizedError' - - post: - tags: [Sync] - summary: Push local changes - description: | - Pushes local changes to the server. - Handles conflict resolution automatically. - operationId: pushChanges - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/SyncPushRequest' - responses: - '200': - description: Changes applied - content: - application/json: - schema: - $ref: '#/components/schemas/SyncPushResponse' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '409': - description: Conflict detected - content: - application/json: - schema: - $ref: '#/components/schemas/SyncConflictResponse' - - /sync/status: - get: - tags: [Sync] - summary: Get sync status - description: Returns the current synchronization status. - operationId: getSyncStatus - responses: - '200': - description: Sync status - content: - application/json: - schema: - $ref: '#/components/schemas/SyncStatus' - '401': - $ref: '#/components/responses/UnauthorizedError' - - # ============================================================================ - # Metadata Server Configuration - # ============================================================================ - /users/me/metadata-server: - get: - tags: [Sync] - summary: Get metadata server configuration - description: Returns the current metadata server connection configuration. - operationId: getMetadataServerConfig - responses: - '200': - description: Metadata server configuration - content: - application/json: - schema: - $ref: '#/components/schemas/MetadataServerConfig' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - description: No metadata server configured (local-only mode) - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - put: - tags: [Sync] - summary: Configure metadata server connection - description: | - Sets up connection to a metadata server for cross-device sync. - Replaces any existing configuration. - operationId: setMetadataServerConfig - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateMetadataServerConfigRequest' - responses: - '200': - description: Configuration saved - content: - application/json: - schema: - $ref: '#/components/schemas/MetadataServerConfig' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - - delete: - tags: [Sync] - summary: Disconnect from metadata server - description: | - Removes metadata server configuration and switches to local-only mode. - Local data is preserved but will no longer sync. - operationId: deleteMetadataServerConfig - responses: - '204': - description: Disconnected from metadata server - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - /users/me/metadata-server/test: - post: - tags: [Sync] - summary: Test metadata server connection - description: Tests connectivity to the configured metadata server. - operationId: testMetadataServerConnection - responses: - '200': - description: Connection test result - content: - application/json: - schema: - type: object - properties: - success: - type: boolean - message: - type: string - server_version: - type: string - latency_ms: - type: integer - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - description: No metadata server configured - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - # ============================================================================ - # Storage - # ============================================================================ - /storage/backends: - get: - tags: [Storage] - summary: List storage backends - description: Returns all configured file storage backends. - operationId: listStorageBackends - responses: - '200': - description: List of storage backends - content: - application/json: - schema: - $ref: '#/components/schemas/StorageBackendList' - '401': - $ref: '#/components/responses/UnauthorizedError' - - post: - tags: [Storage] - summary: Add storage backend - description: Configures a new file storage backend. - operationId: createStorageBackend - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateStorageBackendRequest' - responses: - '201': - description: Backend configured - content: - application/json: - schema: - $ref: '#/components/schemas/StorageBackend' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - - /storage/backends/{backend_id}: - parameters: - - name: backend_id - in: path - required: true - schema: - type: string - format: uuid - - get: - tags: [Storage] - summary: Get storage backend details - description: Returns information about a storage backend. - operationId: getStorageBackend - responses: - '200': - description: Backend details - content: - application/json: - schema: - $ref: '#/components/schemas/StorageBackend' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - patch: - tags: [Storage] - summary: Update storage backend - description: Updates storage backend configuration. - operationId: updateStorageBackend - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateStorageBackendRequest' - responses: - '200': - description: Backend updated - content: - application/json: - schema: - $ref: '#/components/schemas/StorageBackend' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - delete: - tags: [Storage] - summary: Remove storage backend - description: | - Removes a storage backend configuration. - Does not delete files from the backend. - operationId: deleteStorageBackend - responses: - '204': - description: Backend removed - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - /storage/backends/{backend_id}/test: - parameters: - - name: backend_id - in: path - required: true - schema: - type: string - format: uuid - - post: - tags: [Storage] - summary: Test storage backend connection - description: Tests connectivity to the storage backend. - operationId: testStorageBackend - responses: - '200': - description: Connection test result - content: - application/json: - schema: - type: object - properties: - success: - type: boolean - message: - type: string - storage_info: - type: object - properties: - used_bytes: - type: integer - format: int64 - quota_bytes: - type: integer - format: int64 - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - /storage/backends/{backend_id}/set-primary: - parameters: - - name: backend_id - in: path - required: true - schema: - type: string - format: uuid - - post: - tags: [Storage] - summary: Set as primary backend - description: Sets this backend as the primary for new uploads. - operationId: setPrimaryBackend - responses: - '200': - description: Primary backend set - content: - application/json: - schema: - $ref: '#/components/schemas/StorageBackend' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - # ============================================================================ - # Files - # ============================================================================ - /files/upload: - post: - tags: [Files] - summary: Upload a book file - description: | - Uploads a book file to the primary storage backend. - Returns file metadata after successful upload. - operationId: uploadFile - requestBody: - required: true - content: - multipart/form-data: - schema: - type: object - required: [file] - properties: - file: - type: string - format: binary - description: Book file (EPUB, PDF, MOBI, etc.) - responses: - '201': - description: File uploaded - content: - application/json: - schema: - $ref: '#/components/schemas/FileInfo' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '413': - description: File too large - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '415': - description: Unsupported file format - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /books/{book_id}/file: - parameters: - - $ref: '#/components/parameters/BookIdParam' - - get: - tags: [Files] - summary: Get book file download URL - description: | - Returns a signed URL to download the book file. - URL is valid for a limited time. - operationId: getBookFileUrl - responses: - '200': - description: Download URL - content: - application/json: - schema: - type: object - properties: - download_url: - type: string - format: uri - expires_at: - type: string - format: date-time - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - delete: - tags: [Files] - summary: Delete book file - description: Deletes the book file from storage. - operationId: deleteBookFile - responses: - '204': - description: File deleted - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - # ============================================================================ - # Reading Profiles - # ============================================================================ - /reading-profiles: - get: - tags: [Users] - summary: List reading profiles - description: Returns all reading profiles for the user. - operationId: listReadingProfiles - responses: - '200': - description: List of reading profiles - content: - application/json: - schema: - $ref: '#/components/schemas/ReadingProfileList' - '401': - $ref: '#/components/responses/UnauthorizedError' - - post: - tags: [Users] - summary: Create reading profile - description: Creates a new reading profile with viewer settings. - operationId: createReadingProfile - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateReadingProfileRequest' - responses: - '201': - description: Profile created - content: - application/json: - schema: - $ref: '#/components/schemas/ReadingProfile' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - - /reading-profiles/{profile_id}: - parameters: - - name: profile_id - in: path - required: true - schema: - type: string - format: uuid - - get: - tags: [Users] - summary: Get reading profile - description: Returns a specific reading profile. - operationId: getReadingProfile - responses: - '200': - description: Reading profile - content: - application/json: - schema: - $ref: '#/components/schemas/ReadingProfile' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - patch: - tags: [Users] - summary: Update reading profile - description: Updates reading profile settings. - operationId: updateReadingProfile - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateReadingProfileRequest' - responses: - '200': - description: Profile updated - content: - application/json: - schema: - $ref: '#/components/schemas/ReadingProfile' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - delete: - tags: [Users] - summary: Delete reading profile - description: Deletes a reading profile. Cannot delete the default profile. - operationId: deleteReadingProfile - responses: - '204': - description: Profile deleted - '401': - $ref: '#/components/responses/UnauthorizedError' - '403': - description: Cannot delete default profile - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - $ref: '#/components/responses/NotFoundError' - - /reading-profiles/{profile_id}/set-default: - parameters: - - name: profile_id - in: path - required: true - schema: - type: string - format: uuid - - post: - tags: [Users] - summary: Set default reading profile - description: Sets this profile as the default for new books. - operationId: setDefaultReadingProfile - responses: - '200': - description: Default profile set - content: - application/json: - schema: - $ref: '#/components/schemas/ReadingProfile' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - # ============================================================================ - # Saved Filters - # ============================================================================ - /saved-filters: - get: - tags: [Books] - summary: List saved filters - description: Returns all saved search/filter queries. - operationId: listSavedFilters - responses: - '200': - description: List of saved filters - content: - application/json: - schema: - $ref: '#/components/schemas/SavedFilterList' - '401': - $ref: '#/components/responses/UnauthorizedError' - - post: - tags: [Books] - summary: Create saved filter - description: Saves a search/filter query for reuse. - operationId: createSavedFilter - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateSavedFilterRequest' - responses: - '201': - description: Filter saved - content: - application/json: - schema: - $ref: '#/components/schemas/SavedFilter' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - - /saved-filters/{filter_id}: - parameters: - - name: filter_id - in: path - required: true - schema: - type: string - format: uuid - - get: - tags: [Books] - summary: Get saved filter - description: Returns a specific saved filter. - operationId: getSavedFilter - responses: - '200': - description: Saved filter - content: - application/json: - schema: - $ref: '#/components/schemas/SavedFilter' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - patch: - tags: [Books] - summary: Update saved filter - description: Updates a saved filter. - operationId: updateSavedFilter - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateSavedFilterRequest' - responses: - '200': - description: Filter updated - content: - application/json: - schema: - $ref: '#/components/schemas/SavedFilter' - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - delete: - tags: [Books] - summary: Delete saved filter - description: Deletes a saved filter. - operationId: deleteSavedFilter - responses: - '204': - description: Filter deleted - '401': - $ref: '#/components/responses/UnauthorizedError' - '404': - $ref: '#/components/responses/NotFoundError' - - # ============================================================================ - # Export - # ============================================================================ - /export/library: - post: - tags: [Books] - summary: Export library data - description: Exports library data in structured format. - operationId: exportLibrary - requestBody: - required: true - content: - application/json: - schema: - type: object - required: [format] - properties: - format: - type: string - enum: [json, csv, opml] - include_books: - type: boolean - default: true - include_annotations: - type: boolean - default: true - include_notes: - type: boolean - default: true - include_progress: - type: boolean - default: true - shelf_ids: - type: array - items: - type: string - format: uuid - description: Export only specific shelves - tag_ids: - type: array - items: - type: string - format: uuid - description: Export only books with these tags - responses: - '200': - description: Export file - content: - application/json: - schema: - type: string - format: binary - text/csv: - schema: - type: string - format: binary - application/xml: - schema: - type: string - format: binary - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - - /export/books: - post: - tags: [Files] - summary: Export book files - description: | - Exports book files as a ZIP archive. - Only includes files stored on the server. - operationId: exportBooks - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - book_ids: - type: array - items: - type: string - format: uuid - description: Specific books to export (all if empty) - include_metadata: - type: boolean - default: true - description: Include metadata JSON files - responses: - '200': - description: ZIP archive - content: - application/zip: - schema: - type: string - format: binary - '400': - $ref: '#/components/responses/ValidationError' - '401': - $ref: '#/components/responses/UnauthorizedError' - -# ============================================================================== -# Components -# ============================================================================== -components: - securitySchemes: - bearerAuth: - type: http - scheme: bearer - bearerFormat: JWT - description: JWT access token - - parameters: - PageParam: - name: page - in: query - schema: - type: integer - minimum: 1 - default: 1 - description: Page number - - LimitParam: - name: limit - in: query - schema: - type: integer - minimum: 1 - maximum: 100 - default: 20 - description: Items per page - - SortParam: - name: sort - in: query - schema: - type: string - default: '-added_at' - description: | - Sort field with optional direction prefix. - Prefix with `-` for descending order. - Examples: `title`, `-added_at`, `author` - - BookIdParam: - name: book_id - in: path - required: true - schema: - type: string - format: uuid - description: Book ID - - ShelfIdParam: - name: shelf_id - in: path - required: true - schema: - type: string - format: uuid - description: Shelf ID - - TagIdParam: - name: tag_id - in: path - required: true - schema: - type: string - format: uuid - description: Tag ID - - SeriesIdParam: - name: series_id - in: path - required: true - schema: - type: string - format: uuid - description: Series ID - - AnnotationIdParam: - name: annotation_id - in: path - required: true - schema: - type: string - format: uuid - description: Annotation ID - - NoteIdParam: - name: note_id - in: path - required: true - schema: - type: string - format: uuid - description: Note ID - - BookmarkIdParam: - name: bookmark_id - in: path - required: true - schema: - type: string - format: uuid - description: Bookmark ID - - GoalIdParam: - name: goal_id - in: path - required: true - schema: - type: string - format: uuid - description: Goal ID - - responses: - UnauthorizedError: - description: Authentication required - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - NotFoundError: - description: Resource not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - ValidationError: - description: Validation error - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - RateLimitError: - description: Too many requests - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - example: - error: - code: RATE_LIMIT_EXCEEDED - message: Too many requests. Please try again later. - details: - retry_after: 60 - - schemas: - # ========================================================================== - # Common - # ========================================================================== - Error: - type: object - required: [error] - properties: - error: - type: object - required: [code, message] - properties: - code: - type: string - description: Error code - example: VALIDATION_ERROR - message: - type: string - description: Human-readable error message - details: - type: object - additionalProperties: true - description: Additional error details - - Pagination: - type: object - properties: - page: - type: integer - example: 1 - limit: - type: integer - example: 20 - total: - type: integer - example: 150 - total_pages: - type: integer - example: 8 - has_next: - type: boolean - example: true - has_prev: - type: boolean - example: false - - # ========================================================================== - # Auth - # ========================================================================== - RegisterRequest: - type: object - required: [email, password, display_name] - properties: - email: - type: string - format: email - example: user@example.com - password: - type: string - format: password - minLength: 8 - description: Must contain uppercase, lowercase, and number - display_name: - type: string - minLength: 1 - maxLength: 100 - example: John Doe - - RegisterResponse: - type: object - properties: - user_id: - type: string - format: uuid - email: - type: string - format: email - message: - type: string - example: Account created. Please verify your email. - - LoginRequest: - type: object - required: [email, password] - properties: - email: - type: string - format: email - password: - type: string - format: password - - GoogleOAuthRequest: - type: object - required: [id_token] - properties: - id_token: - type: string - description: Google OAuth ID token - - RefreshTokenRequest: - type: object - required: [refresh_token] - properties: - refresh_token: - type: string - description: Refresh token from login - - AuthTokens: - type: object - properties: - access_token: - type: string - description: JWT access token - refresh_token: - type: string - description: Refresh token for obtaining new access tokens - token_type: - type: string - example: Bearer - expires_in: - type: integer - description: Access token expiry in seconds - example: 3600 - user: - $ref: '#/components/schemas/User' - - # ========================================================================== - # User - # ========================================================================== - User: - type: object - properties: - user_id: - type: string - format: uuid - email: - type: string - format: email - display_name: - type: string - avatar_url: - type: string - format: uri - is_anonymous: - type: boolean - email_verified: - type: boolean - created_at: - type: string - format: date-time - last_login_at: - type: string - format: date-time - - UpdateUserRequest: - type: object - properties: - display_name: - type: string - minLength: 1 - maxLength: 100 - avatar_url: - type: string - format: uri - - UserPreferences: - type: object - additionalProperties: true - description: User application preferences (flexible structure) - example: - theme: dark - notifications_enabled: true - default_shelf: "Currently Reading" - sync_wifi_only: false - - # ========================================================================== - # Book - # ========================================================================== - ReadingStatus: - type: string - enum: [not_started, in_progress, completed, paused, abandoned] - - Book: - type: object - properties: - book_id: - type: string - format: uuid - title: - type: string - subtitle: - type: string - author: - type: string - co_authors: - type: array - items: - type: string - isbn: - type: string - isbn13: - type: string - publication_date: - type: string - format: date - publisher: - type: string - language: - type: string - example: en - page_count: - type: integer - description: - type: string - cover_image_url: - type: string - format: uri - series_id: - type: string - format: uuid - series_name: - type: string - series_number: - type: number - file_path: - type: string - file_format: - type: string - enum: [epub, pdf, mobi, azw3, txt, cbr, cbz] - file_size: - type: integer - format: int64 - file_hash: - type: string - storage_backend_id: - type: string - format: uuid - is_physical: - type: boolean - physical_location: - type: string - lent_to: - type: string - lent_at: - type: string - format: date-time - is_favorite: - type: boolean - rating: - type: integer - minimum: 1 - maximum: 5 - reading_status: - $ref: '#/components/schemas/ReadingStatus' - current_page: - type: integer - current_position: - type: number - minimum: 0 - maximum: 1 - current_cfi: - type: string - started_at: - type: string - format: date-time - completed_at: - type: string - format: date-time - added_at: - type: string - format: date-time - last_read_at: - type: string - format: date-time - custom_metadata: - type: object - additionalProperties: true - is_ocr_processed: - type: boolean - ocr_confidence: - type: number - updated_at: - type: string - format: date-time - shelves: - type: array - items: - $ref: '#/components/schemas/ShelfSummary' - tags: - type: array - items: - $ref: '#/components/schemas/Tag' - - BookSummary: - type: object - properties: - book_id: - type: string - format: uuid - title: - type: string - author: - type: string - cover_image_url: - type: string - format: uri - reading_status: - $ref: '#/components/schemas/ReadingStatus' - current_position: - type: number - is_favorite: - type: boolean - rating: - type: integer - - BookList: - type: object - properties: - books: - type: array - items: - $ref: '#/components/schemas/Book' - pagination: - $ref: '#/components/schemas/Pagination' - - CreateBookRequest: - type: object - required: [title, author] - properties: - title: - type: string - maxLength: 500 - subtitle: - type: string - maxLength: 500 - author: - type: string - maxLength: 255 - co_authors: - type: array - items: - type: string - isbn: - type: string - isbn13: - type: string - publication_date: - type: string - format: date - publisher: - type: string - language: - type: string - default: en - page_count: - type: integer - description: - type: string - cover_image_url: - type: string - format: uri - series_id: - type: string - format: uuid - series_number: - type: number - file_path: - type: string - description: Path returned from file upload - file_format: - type: string - file_size: - type: integer - format: int64 - file_hash: - type: string - storage_backend_id: - type: string - format: uuid - is_physical: - type: boolean - default: false - physical_location: - type: string - custom_metadata: - type: object - additionalProperties: true - shelf_ids: - type: array - items: - type: string - format: uuid - tag_ids: - type: array - items: - type: string - format: uuid - maxItems: 10 - - UpdateBookRequest: - type: object - properties: - title: - type: string - subtitle: - type: string - author: - type: string - co_authors: - type: array - items: - type: string - isbn: - type: string - isbn13: - type: string - publication_date: - type: string - format: date - publisher: - type: string - language: - type: string - page_count: - type: integer - description: - type: string - cover_image_url: - type: string - format: uri - series_id: - type: string - format: uuid - series_number: - type: number - is_physical: - type: boolean - physical_location: - type: string - lent_to: - type: string - lent_at: - type: string - format: date-time - is_favorite: - type: boolean - rating: - type: integer - minimum: 1 - maximum: 5 - reading_status: - $ref: '#/components/schemas/ReadingStatus' - custom_metadata: - type: object - additionalProperties: true - - ReadingProgress: - type: object - properties: - book_id: - type: string - format: uuid - reading_status: - $ref: '#/components/schemas/ReadingStatus' - current_page: - type: integer - current_position: - type: number - minimum: 0 - maximum: 1 - current_cfi: - type: string - started_at: - type: string - format: date-time - completed_at: - type: string - format: date-time - last_read_at: - type: string - format: date-time - total_reading_time_minutes: - type: integer - sessions_count: - type: integer - - UpdateProgressRequest: - type: object - properties: - reading_status: - $ref: '#/components/schemas/ReadingStatus' - current_page: - type: integer - current_position: - type: number - minimum: 0 - maximum: 1 - current_cfi: - type: string - - MetadataSearchResult: - type: object - properties: - source: - type: string - enum: [open_library, google_books] - title: - type: string - author: - type: string - isbn: - type: string - isbn13: - type: string - publication_date: - type: string - format: date - publisher: - type: string - description: - type: string - cover_image_url: - type: string - format: uri - page_count: - type: integer - language: - type: string - - # ========================================================================== - # Shelf - # ========================================================================== - Shelf: - type: object - properties: - shelf_id: - type: string - format: uuid - name: - type: string - description: - type: string - color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - icon: - type: string - is_default: - type: boolean - is_smart: - type: boolean - smart_query: - type: string - sort_order: - type: integer - parent_shelf_id: - type: string - format: uuid - book_count: - type: integer - children: - type: array - items: - $ref: '#/components/schemas/Shelf' - created_at: - type: string - format: date-time - updated_at: - type: string - format: date-time - - ShelfSummary: - type: object - properties: - shelf_id: - type: string - format: uuid - name: - type: string - color: - type: string - - ShelfList: - type: object - properties: - shelves: - type: array - items: - $ref: '#/components/schemas/Shelf' - - CreateShelfRequest: - type: object - required: [name] - properties: - name: - type: string - maxLength: 100 - description: - type: string - color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - icon: - type: string - parent_shelf_id: - type: string - format: uuid - is_smart: - type: boolean - default: false - smart_query: - type: string - sort_order: - type: integer - - UpdateShelfRequest: - type: object - properties: - name: - type: string - maxLength: 100 - description: - type: string - color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - icon: - type: string - parent_shelf_id: - type: string - format: uuid - is_smart: - type: boolean - smart_query: - type: string - sort_order: - type: integer - - # ========================================================================== - # Tag - # ========================================================================== - Tag: - type: object - properties: - tag_id: - type: string - format: uuid - name: - type: string - color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - description: - type: string - usage_count: - type: integer - created_at: - type: string - format: date-time - - TagList: - type: object - properties: - tags: - type: array - items: - $ref: '#/components/schemas/Tag' - - CreateTagRequest: - type: object - required: [name, color] - properties: - name: - type: string - maxLength: 50 - color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - description: - type: string - - UpdateTagRequest: - type: object - properties: - name: - type: string - maxLength: 50 - color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - description: - type: string - - # ========================================================================== - # Series - # ========================================================================== - Series: - type: object - properties: - series_id: - type: string - format: uuid - name: - type: string - description: - type: string - author: - type: string - total_books: - type: integer - is_complete: - type: boolean - book_count: - type: integer - created_at: - type: string - format: date-time - updated_at: - type: string - format: date-time - - SeriesWithBooks: - allOf: - - $ref: '#/components/schemas/Series' - - type: object - properties: - books: - type: array - items: - $ref: '#/components/schemas/BookSummary' - - SeriesList: - type: object - properties: - series: - type: array - items: - $ref: '#/components/schemas/Series' - - CreateSeriesRequest: - type: object - required: [name] - properties: - name: - type: string - maxLength: 255 - description: - type: string - author: - type: string - total_books: - type: integer - is_complete: - type: boolean - default: false - - UpdateSeriesRequest: - type: object - properties: - name: - type: string - maxLength: 255 - description: - type: string - author: - type: string - total_books: - type: integer - is_complete: - type: boolean - - # ========================================================================== - # Annotation - # ========================================================================== - Annotation: - type: object - properties: - annotation_id: - type: string - format: uuid - book_id: - type: string - format: uuid - book_title: - type: string - selected_text: - type: string - note: - type: string - highlight_color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - start_position: - type: string - end_position: - type: string - chapter_title: - type: string - chapter_index: - type: integer - page_number: - type: integer - created_at: - type: string - format: date-time - updated_at: - type: string - format: date-time - - AnnotationList: - type: object - properties: - annotations: - type: array - items: - $ref: '#/components/schemas/Annotation' - pagination: - $ref: '#/components/schemas/Pagination' - - CreateAnnotationRequest: - type: object - required: [selected_text, highlight_color, start_position, end_position] - properties: - selected_text: - type: string - note: - type: string - highlight_color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - default: '#FFEB3B' - start_position: - type: string - description: CFI or offset - end_position: - type: string - chapter_title: - type: string - chapter_index: - type: integer - page_number: - type: integer - - UpdateAnnotationRequest: - type: object - properties: - note: - type: string - highlight_color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - - # ========================================================================== - # Note - # ========================================================================== - Note: - type: object - properties: - note_id: - type: string - format: uuid - book_id: - type: string - format: uuid - book_title: - type: string - title: - type: string - content: - type: string - is_pinned: - type: boolean - created_at: - type: string - format: date-time - updated_at: - type: string - format: date-time - - NoteList: - type: object - properties: - notes: - type: array - items: - $ref: '#/components/schemas/Note' - pagination: - $ref: '#/components/schemas/Pagination' - - CreateNoteRequest: - type: object - required: [title, content] - properties: - title: - type: string - maxLength: 255 - content: - type: string - is_pinned: - type: boolean - default: false - - UpdateNoteRequest: - type: object - properties: - title: - type: string - maxLength: 255 - content: - type: string - is_pinned: - type: boolean - - # ========================================================================== - # Bookmark - # ========================================================================== - Bookmark: - type: object - properties: - bookmark_id: - type: string - format: uuid - book_id: - type: string - format: uuid - position: - type: string - page_number: - type: integer - chapter_title: - type: string - note: - type: string - color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - created_at: - type: string - format: date-time - - BookmarkList: - type: object - properties: - bookmarks: - type: array - items: - $ref: '#/components/schemas/Bookmark' - - CreateBookmarkRequest: - type: object - required: [position] - properties: - position: - type: string - description: CFI, page number, or offset - page_number: - type: integer - chapter_title: - type: string - note: - type: string - maxLength: 500 - color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - default: '#FF5722' - - UpdateBookmarkRequest: - type: object - properties: - note: - type: string - maxLength: 500 - color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - - # ========================================================================== - # Reading Session - # ========================================================================== - ReadingSession: - type: object - properties: - session_id: - type: string - format: uuid - book_id: - type: string - format: uuid - book_title: - type: string - start_time: - type: string - format: date-time - end_time: - type: string - format: date-time - start_position: - type: number - end_position: - type: number - pages_read: - type: integer - duration_minutes: - type: integer - readOnly: true - description: Calculated from start_time and end_time - device_type: - type: string - device_name: - type: string - created_at: - type: string - format: date-time - - ReadingSessionList: - type: object - properties: - sessions: - type: array - items: - $ref: '#/components/schemas/ReadingSession' - pagination: - $ref: '#/components/schemas/Pagination' - - CreateReadingSessionRequest: - type: object - required: [book_id, start_time] - properties: - book_id: - type: string - format: uuid - start_time: - type: string - format: date-time - end_time: - type: string - format: date-time - start_position: - type: number - minimum: 0 - maximum: 1 - end_position: - type: number - minimum: 0 - maximum: 1 - pages_read: - type: integer - device_type: - type: string - device_name: - type: string - - # ========================================================================== - # Statistics - # ========================================================================== - ReadingStatistics: - type: object - properties: - period: - type: object - properties: - start_date: - type: string - format: date - end_date: - type: string - format: date - totals: - type: object - properties: - reading_time_minutes: - type: integer - pages_read: - type: integer - books_completed: - type: integer - sessions_count: - type: integer - average_session_minutes: - type: number - reading_days: - type: integer - current_streak: - type: integer - longest_streak: - type: integer - daily_breakdown: - type: array - items: - type: object - properties: - date: - type: string - format: date - reading_time_minutes: - type: integer - pages_read: - type: integer - sessions_count: - type: integer - books_breakdown: - type: array - items: - type: object - properties: - book_id: - type: string - format: uuid - title: - type: string - reading_time_minutes: - type: integer - pages_read: - type: integer - sessions_count: - type: integer - - # ========================================================================== - # Goals - # ========================================================================== - GoalType: - type: string - enum: [books_count, pages_count, reading_time] - - TimePeriod: - type: string - enum: [daily, weekly, monthly, yearly, custom] - - Goal: - type: object - properties: - goal_id: - type: string - format: uuid - title: - type: string - description: - type: string - goal_type: - $ref: '#/components/schemas/GoalType' - target_value: - type: integer - current_value: - type: integer - progress_percentage: - type: number - time_period: - $ref: '#/components/schemas/TimePeriod' - start_date: - type: string - format: date - end_date: - type: string - format: date - is_active: - type: boolean - is_completed: - type: boolean - completed_at: - type: string - format: date-time - created_at: - type: string - format: date-time - updated_at: - type: string - format: date-time - - GoalList: - type: object - properties: - goals: - type: array - items: - $ref: '#/components/schemas/Goal' - - CreateGoalRequest: - type: object - required: [title, goal_type, target_value, time_period, start_date, end_date] - properties: - title: - type: string - maxLength: 255 - description: - type: string - goal_type: - $ref: '#/components/schemas/GoalType' - target_value: - type: integer - minimum: 1 - time_period: - $ref: '#/components/schemas/TimePeriod' - start_date: - type: string - format: date - end_date: - type: string - format: date - - UpdateGoalRequest: - type: object - properties: - title: - type: string - maxLength: 255 - description: - type: string - target_value: - type: integer - minimum: 1 - end_date: - type: string - format: date - is_active: - type: boolean - - # ========================================================================== - # Metadata Server Config - # ========================================================================== - ServerType: - type: string - enum: [official, self_hosted] - - MetadataServerConfig: - type: object - properties: - config_id: - type: string - format: uuid - server_url: - type: string - format: uri - server_type: - $ref: '#/components/schemas/ServerType' - is_connected: - type: boolean - sync_enabled: - type: boolean - sync_interval_seconds: - type: integer - last_sync_at: - type: string - format: date-time - sync_status: - type: string - enum: [idle, syncing, error] - sync_error_message: - type: string - created_at: - type: string - format: date-time - updated_at: - type: string - format: date-time - - CreateMetadataServerConfigRequest: - type: object - required: [server_url] - properties: - server_url: - type: string - format: uri - description: URL of the metadata server - server_type: - $ref: '#/components/schemas/ServerType' - sync_enabled: - type: boolean - default: true - sync_interval_seconds: - type: integer - default: 30 - minimum: 10 - maximum: 3600 - auth_token: - type: string - description: JWT or API token for authentication - - # ========================================================================== - # Sync - # ========================================================================== - SyncChanges: - type: object - properties: - changes: - type: array - items: - type: object - properties: - entity_type: - type: string - entity_id: - type: string - format: uuid - operation: - type: string - enum: [create, update, delete] - data: - type: object - version: - type: integer - updated_at: - type: string - format: date-time - device_id: - type: string - server_timestamp: - type: string - format: date-time - - SyncPushRequest: - type: object - required: [changes, device_id] - properties: - changes: - type: array - items: - type: object - required: [entity_type, entity_id, operation, data, timestamp] - properties: - entity_type: - type: string - entity_id: - type: string - format: uuid - operation: - type: string - enum: [create, update, delete] - data: - type: object - timestamp: - type: string - format: date-time - version: - type: integer - device_id: - type: string - - SyncPushResponse: - type: object - properties: - accepted: - type: array - items: - type: object - properties: - entity_type: - type: string - entity_id: - type: string - format: uuid - new_version: - type: integer - rejected: - type: array - items: - type: object - properties: - entity_type: - type: string - entity_id: - type: string - format: uuid - reason: - type: string - server_timestamp: - type: string - format: date-time - - SyncConflictResponse: - type: object - properties: - conflicts: - type: array - items: - type: object - properties: - entity_type: - type: string - entity_id: - type: string - format: uuid - local_version: - type: integer - server_version: - type: integer - server_data: - type: object - resolved_data: - type: object - resolution_strategy: - type: string - enum: [latest_wins, merge, manual] - - SyncStatus: - type: object - properties: - status: - type: string - enum: [idle, syncing, error] - last_sync_at: - type: string - format: date-time - pending_changes: - type: integer - error_message: - type: string - - # ========================================================================== - # Storage - # ========================================================================== - StorageBackendType: - type: string - enum: [local, google_drive, onedrive, dropbox, webdav, minio, s3, papyrus_server] - - ConnectionStatus: - type: string - enum: [connected, disconnected, error] - - StorageBackend: - type: object - properties: - backend_id: - type: string - format: uuid - backend_type: - $ref: '#/components/schemas/StorageBackendType' - name: - type: string - is_primary: - type: boolean - is_active: - type: boolean - base_path: - type: string - storage_used_bytes: - type: integer - format: int64 - storage_quota_bytes: - type: integer - format: int64 - last_accessed_at: - type: string - format: date-time - connection_status: - $ref: '#/components/schemas/ConnectionStatus' - error_message: - type: string - created_at: - type: string - format: date-time - updated_at: - type: string - format: date-time - - StorageBackendList: - type: object - properties: - backends: - type: array - items: - $ref: '#/components/schemas/StorageBackend' - - CreateStorageBackendRequest: - type: object - required: [backend_type, name] - properties: - backend_type: - $ref: '#/components/schemas/StorageBackendType' - name: - type: string - maxLength: 100 - is_primary: - type: boolean - default: false - connection_config: - type: object - description: Type-specific connection settings - additionalProperties: true - credentials: - type: object - description: OAuth tokens or API keys - additionalProperties: true - base_path: - type: string - - UpdateStorageBackendRequest: - type: object - properties: - name: - type: string - maxLength: 100 - is_active: - type: boolean - connection_config: - type: object - additionalProperties: true - credentials: - type: object - additionalProperties: true - base_path: - type: string - - # ========================================================================== - # Files - # ========================================================================== - FileInfo: - type: object - properties: - file_path: - type: string - description: Relative path in storage - file_format: - type: string - file_size: - type: integer - format: int64 - file_hash: - type: string - description: SHA-256 checksum - storage_backend_id: - type: string - format: uuid - uploaded_at: - type: string - format: date-time - - # ========================================================================== - # Reading Profile - # ========================================================================== - TextAlign: - type: string - enum: [left, right, center, justify] - - ThemeMode: - type: string - enum: [light, dark, sepia, custom] - - ReadingMode: - type: string - enum: [paginated, continuous] - - ReadingProfile: - type: object - properties: - profile_id: - type: string - format: uuid - name: - type: string - is_default: - type: boolean - font_family: - type: string - font_size: - type: integer - minimum: 8 - maximum: 72 - font_weight: - type: integer - line_height: - type: number - letter_spacing: - type: number - paragraph_spacing: - type: number - text_align: - $ref: '#/components/schemas/TextAlign' - margin_horizontal: - type: integer - margin_vertical: - type: integer - background_color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - text_color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - link_color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - selection_color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - theme_mode: - $ref: '#/components/schemas/ThemeMode' - reading_mode: - $ref: '#/components/schemas/ReadingMode' - page_turn_animation: - type: boolean - column_count: - type: integer - minimum: 1 - maximum: 3 - hyphenation: - type: boolean - created_at: - type: string - format: date-time - updated_at: - type: string - format: date-time - - ReadingProfileList: - type: object - properties: - profiles: - type: array - items: - $ref: '#/components/schemas/ReadingProfile' - - CreateReadingProfileRequest: - type: object - required: [name] - properties: - name: - type: string - maxLength: 100 - is_default: - type: boolean - default: false - font_family: - type: string - default: Georgia - font_size: - type: integer - default: 16 - font_weight: - type: integer - default: 400 - line_height: - type: number - default: 1.5 - letter_spacing: - type: number - default: 0 - paragraph_spacing: - type: number - default: 1.0 - text_align: - $ref: '#/components/schemas/TextAlign' - margin_horizontal: - type: integer - default: 20 - margin_vertical: - type: integer - default: 20 - background_color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - default: '#FFFFFF' - text_color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - default: '#000000' - link_color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - default: '#0066CC' - selection_color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - default: '#B3D4FC' - theme_mode: - $ref: '#/components/schemas/ThemeMode' - reading_mode: - $ref: '#/components/schemas/ReadingMode' - page_turn_animation: - type: boolean - default: true - column_count: - type: integer - default: 1 - hyphenation: - type: boolean - default: true - - UpdateReadingProfileRequest: - type: object - properties: - name: - type: string - maxLength: 100 - font_family: - type: string - font_size: - type: integer - font_weight: - type: integer - line_height: - type: number - letter_spacing: - type: number - paragraph_spacing: - type: number - text_align: - $ref: '#/components/schemas/TextAlign' - margin_horizontal: - type: integer - margin_vertical: - type: integer - background_color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - text_color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - link_color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - selection_color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - theme_mode: - $ref: '#/components/schemas/ThemeMode' - reading_mode: - $ref: '#/components/schemas/ReadingMode' - page_turn_animation: - type: boolean - column_count: - type: integer - hyphenation: - type: boolean - - # ========================================================================== - # Saved Filter - # ========================================================================== - FilterType: - type: string - enum: [search, shelf, custom] - - SavedFilter: - type: object - properties: - filter_id: - type: string - format: uuid - name: - type: string - description: - type: string - query: - type: string - filter_type: - $ref: '#/components/schemas/FilterType' - icon: - type: string - color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - is_pinned: - type: boolean - usage_count: - type: integer - last_used_at: - type: string - format: date-time - created_at: - type: string - format: date-time - updated_at: - type: string - format: date-time - - SavedFilterList: - type: object - properties: - filters: - type: array - items: - $ref: '#/components/schemas/SavedFilter' - - CreateSavedFilterRequest: - type: object - required: [name, query] - properties: - name: - type: string - maxLength: 100 - description: - type: string - query: - type: string - maxLength: 1000 - filter_type: - $ref: '#/components/schemas/FilterType' - icon: - type: string - color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - is_pinned: - type: boolean - default: false - - UpdateSavedFilterRequest: - type: object - properties: - name: - type: string - maxLength: 100 - description: - type: string - query: - type: string - maxLength: 1000 - filter_type: - $ref: '#/components/schemas/FilterType' - icon: - type: string - color: - type: string - pattern: '^#[0-9A-Fa-f]{6}$' - is_pinned: - type: boolean diff --git a/api/index.rst b/api/index.rst index 103c511..d4b9a65 100644 --- a/api/index.rst +++ b/api/index.rst @@ -1,9 +1,17 @@ REST API ======== -.. openapi:: /_static/openapi.yaml - :examples: - :group: +This snapshot is generated from the server at the revision pinned in the docs CI +workflow, using ``/v1`` and deterministic documentation settings. Deployments can +configure ``API_PREFIX``; their runtime ``/openapi.json`` is authoritative. + +:download:`Download the OpenAPI JSON <../_static/openapi.json>` or +`open the API reference in a separate tab <../_static/api.html>`_. + +.. raw:: html + + Related documentation --------------------- diff --git a/conf.py b/conf.py index 2a7c9bd..b4a2008 100644 --- a/conf.py +++ b/conf.py @@ -2,7 +2,7 @@ copyright = "2026, Papyrus" author = "Karolis Strazdas" -extensions = ["sphinx_needs", "sphinxcontrib.mermaid", "sphinx.ext.graphviz", "sphinxcontrib.openapi"] +extensions = ["sphinx_needs", "sphinxcontrib.mermaid", "sphinx.ext.graphviz"] html_theme = "furo" html_static_path = ["_static"] @@ -97,7 +97,7 @@ needs_id_required = True needs_id_regex = r"^(FR|NFR|UC)-[0-9]+_[0-9]+(_[0-9]+)?$" needs_default_style = "" -needs_role_need_template = "{title} ({id})" +needs_role_need_template = "{{ title }} ({{ id }})" graphviz_output_format = "svg" mermaid_output_format = "raw" @@ -105,6 +105,7 @@ "_build", "src", ".venv", + ".server", "venv", "site", "Thumbs.db", @@ -113,4 +114,4 @@ "README.md", ] -templates_path = ["_templates"] +templates_path = [] diff --git a/design/server-architecture.rst b/design/server-architecture.rst index ecd2558..781ab8d 100644 --- a/design/server-architecture.rst +++ b/design/server-architecture.rst @@ -1,108 +1,32 @@ Server architecture =================== -This document describes the back-end architecture, -including the self-hostable server, file storage backends, and -synchronization mechanisms that enable cross-device functionality. - -Architecture overview ---------------------- +The current implementation uses FastAPI, PostgreSQL and self-hosted PowerSync. +The Flutter client keeps a local SQLite library and profile-scoped media cache; +the reader package owns transient EPUB/PDF sessions and the host persists positions. .. mermaid:: - flowchart TB - subgraph Clients["Clients"] - Android["Android"] - iOS["iOS"] - Web["Web"] - Desktop["Desktop"] - end - - subgraph Server["Server"] - subgraph Metadata["Metadata storage"] - M1["User accounts"] - M2["Book metadata"] - M3["Reading progress"] - M4["Annotations & bookmarks"] - M5["Shelves, tags, series"] - M6["Reading goals"] - M7["Sync coordination"] - end - - subgraph FileStorage["File storage (optional)"] - F1["Book files"] - F2["Cover images"] - end - end - - subgraph AltStorage["Alternative file storage"] - direction LR - G["Google Drive"] - O["OneDrive"] - D["Dropbox"] - W["WebDAV"] - S3["S3"] - L["Local device only"] - G --- O - O --- D - D --- W - W --- S3 - S3 --- L - end - - Android --> Server - iOS --> Server - Web --> Server - Desktop --> Server - Server -.->|"OR (user's choice)"| AltStorage - linkStyle 0,1,2,3,4 stroke:transparent,stroke-width:0px; - -API endpoints -~~~~~~~~~~~~~ - -The Papyrus Server exposes a RESTful API: - -.. list-table:: - :header-rows: 1 - - * - Category - - Endpoints - - Description - * - **Auth** - - ``/api/v1/auth/*`` - - Register, login, OAuth, refresh tokens - * - **Users** - - ``/api/v1/users/*`` - - Profile, preferences, account deletion - * - **Books** - - ``/api/v1/books/*`` - - CRUD operations, metadata, cover images - * - **Shelves** - - ``/api/v1/shelves/*`` - - Create, update, organize books - * - **Tags** - - ``/api/v1/tags/*`` - - Tag management - * - **Series** - - ``/api/v1/series/*`` - - Series management and ordering - * - **Annotations** - - ``/api/v1/annotations/*`` - - Highlights, notes, bookmarks - * - **Progress** - - ``/api/v1/progress/*`` - - Reading position, sessions, statistics - * - **Goals** - - ``/api/v1/goals/*`` - - Goal creation and tracking - * - **Sync** - - ``/api/v1/sync/*`` - - Change synchronization - * - **Storage** - - ``/api/v1/storage/*`` - - Backend configuration - * - **Files** - - ``/api/v1/files/*`` - - File upload/download (when server is file backend) - -Full server's API specification in described in the :doc:`API ` section. \ No newline at end of file + flowchart LR + Client["Flutter client / SQLite"] -->|"Auth, uploads, media, OPDS"| API["FastAPI"] + API --> DB["PostgreSQL"] + DB --> Sync["PowerSync service"] + Sync -->|"Library replication"| Client + API --> Media["Server media storage"] + API --> Catalogs["OPDS catalogs / acquisition integrations"] + +The API prefix is configurable. The server's example configuration uses ``/v1``, +not ``/api/v1``. Authentication, library entities, reading profiles, saved filters, +media and acquisition routes are documented in the generated :doc:`/api/index`. +Development sandbox routes are available only in debug configurations. + +Account ownership is validated by services. Offline uploads are serialized per +owner and committed atomically; tombstones prevent delayed writes from restoring +deleted data. Physical media cleanup runs after commit. These contracts belong to +the server services and their regression tests, not a copied endpoint table. + +Local media and Papyrus-managed server storage are implemented. Other cloud +provider adapters are product goals and should not be inferred from stored +storage-profile configuration. The requirement and entity diagrams elsewhere in +this documentation describe target behavior; consult the server models and Alembic +revisions for the deployed schema. diff --git a/implementation/technologies.rst b/implementation/technologies.rst index 142e521..56099ca 100644 --- a/implementation/technologies.rst +++ b/implementation/technologies.rst @@ -26,10 +26,12 @@ Back-end - Used for * - FastAPI (Python) - Backend API for authentication, library management, sync, and configuration endpoints. - * - Supabase - - Managed backend capabilities, especially authentication and hosted Postgres integrations. - * - Redis - - Caching, transient state, and coordination workloads (for example sessions and rate limiting). + * - SQLAlchemy / asyncpg + - Asynchronous PostgreSQL persistence. + * - Alembic + - Versioned database migrations. + * - PowerSync + - Self-hosted replication from PostgreSQL to client SQLite storage. * - Docker - Containerized local development and deployment packaging. @@ -58,17 +60,3 @@ Metadata - Optional external metadata lookup for books. * - Open Library API - Optional external metadata lookup for books. - -Analytics ---------- - -.. list-table:: - :header-rows: 1 - :widths: 30 70 - - * - Technology - - Used for - * - Sentry - - Optional error monitoring and diagnostics. - * - Plausible - - Optional privacy-focused analytics. diff --git a/index.rst b/index.rst index 332b158..ace739b 100644 --- a/index.rst +++ b/index.rst @@ -1,6 +1,13 @@ Papyrus ======= +This site contains both current implementation guidance and product requirements. +Requirements and design diagrams describe intended behavior; they are not a list +of released capabilities. See :doc:`implementation/technologies`, +:doc:`design/server-architecture` and :doc:`api/index` for the implemented stack +and generated HTTP contract. Current reading supports EPUB and PDF. The client +also supports metadata import for several additional formats and OPDS catalogs. + Overview -------- @@ -25,8 +32,8 @@ Target audience - Habit builders who want to track reading statistics and build reading habits through goals and gamification. - Multi-device users who want to read and access the same data on phones, tablets, e-readers, and PCs interchangeably. -Supported platforms -------------------- +Target platforms +---------------- - Android (8.0+). - iOS (12.0+). @@ -35,8 +42,8 @@ Supported platforms - macOS (10.15+). - Linux. -Supported file formats ------------------------- +Target file formats +------------------- 1. EPUB. 2. PDF. @@ -49,8 +56,8 @@ Supported file formats 9. ODT 10. DJVU. -Features overview ------------------ +Product feature requirements +---------------------------- Core features ~~~~~~~~~~~~~ @@ -144,7 +151,6 @@ Advanced features These features are planned for future releases, and may not be seriously considered for implementation: - Format conversion between formats (create a book copy or replace existing) -- OPDS catalog browsing to download from online catalogs - OCR processing to extract text from scanned document or book files - Audiobook support to manage and play audiobooks with synchronized progress - Text-to-speech to read books aloud diff --git a/pyproject.toml b/pyproject.toml index 0805c1b..bfeb40f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,6 @@ dependencies = [ "furo>=2024.0", "sphinx-needs>=4.0", "sphinxcontrib-mermaid>=1.0", - "sphinxcontrib-openapi>=0.9," ] [project.optional-dependencies] diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..f7401f1 --- /dev/null +++ b/uv.lock @@ -0,0 +1,1425 @@ +version = 1 +revision = 3 +requires-python = ">=3.10" +resolution-markers = [ + "python_full_version >= '3.12'", + "python_full_version == '3.11.*'", + "python_full_version < '3.11'", +] + +[[package]] +name = "accessible-pygments" +version = "0.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c1/bbac6a50d02774f91572938964c582fff4270eee73ab822a4aeea4d8b11b/accessible_pygments-0.0.5.tar.gz", hash = "sha256:40918d3e6a2b619ad424cb91e556bd3bd8865443d9f22f1dcdf79e33c8046872", size = 1377899, upload-time = "2024-05-10T11:23:10.216Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/3f/95338030883d8c8b91223b4e21744b04d11b161a3ef117295d8241f50ab4/accessible_pygments-0.0.5-py3-none-any.whl", hash = "sha256:88ae3211e68a1d0b011504b2ffc1691feafce124b845bd072ab6f9f66f34d4b7", size = 1395903, upload-time = "2024-05-10T11:23:08.421Z" }, +] + +[[package]] +name = "alabaster" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210, upload-time = "2024-07-26T18:15:03.762Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" }, +] + +[[package]] +name = "anyio" +version = "4.15.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "idna" }, + { name = "typing-extensions", marker = "python_full_version < '3.15'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a9/d2/f4d173e22df740bc37b1db102b386ba719b66e95b0f0d751f556b387e6d2/anyio-4.15.1.tar.gz", hash = "sha256:9f28306018cbd6d329e64a36d58256edff76dd996fe423bc957326e578b82a94", size = 276966, upload-time = "2026-09-05T10:42:39.44Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl", hash = "sha256:6152fdbbf9a77fdec97731721bebf7c4c44f7c29b424b0065826173efc7ed101", size = 132079, upload-time = "2026-09-05T10:42:37.923Z" }, +] + +[[package]] +name = "babel" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554, upload-time = "2026-02-01T12:30:56.078Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/43/65/318323f98dbee45d42dff61d8f047181bc6f2268a9068cfad035a46be5af/beautifulsoup4-4.15.0.tar.gz", hash = "sha256:288e3ca7d54b06f2ac191970bc275c1939cb46d450b255bf6718b04aa37ab4f7", size = 632571, upload-time = "2026-06-07T16:44:20.453Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/c6/92fcd42f1ba33e1184263f25bfabf3d27c383410470f169e4b8163bf9c17/beautifulsoup4-4.15.0-py3-none-any.whl", hash = "sha256:d6f88de62e1d4e38ecb1077eb9724cd0eff29d2a08ca16a401e9b9e93f117cf9", size = 109924, upload-time = "2026-06-07T16:44:21.566Z" }, +] + +[[package]] +name = "certifi" +version = "2026.7.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", size = 138112, upload-time = "2026-07-22T03:35:12.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", size = 136983, upload-time = "2026-07-22T03:35:11.276Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/33/1c/f41d4e74c28ab327ff3acd36053f7ea506c55872d7a90b0fa71aa3ab0c89/charset_normalizer-3.5.2.tar.gz", hash = "sha256:39de2a259fc954455c57274dc94c79d5842774e1247a016aff30bc0efed0f4ef", size = 172659, upload-time = "2026-09-30T04:39:23.398Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/77/46e87bcfc45d25ab4db7cfc9bb544bfa3ffd302289ed31ae93f5433eb899/charset_normalizer-3.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:195c26fb65950f8fce54e26349852b7bdd7c5f120aeefbcc440b8a20faaed4a3", size = 373348, upload-time = "2026-09-30T04:34:42.843Z" }, + { url = "https://files.pythonhosted.org/packages/52/fc/e518013affcc43c9f919c3ba41bffe9b4ee4aceb0a6462a6243efcca5f2d/charset_normalizer-3.5.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9373ad13ef0d2c0fb761e04e55bfdee5a08b52cef2c882c8fbe9935b1517152e", size = 260860, upload-time = "2026-09-30T04:34:44.817Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ad/2a895c945ee61988dfd9ccee64f0b78dc09f29c9b34d1dd545246d78e0ad/charset_normalizer-3.5.2-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ddf19c062bea7a0cc80f519243d2c01dd091be0cf952a0750d4ad576709559f5", size = 246491, upload-time = "2026-09-30T04:34:46.227Z" }, + { url = "https://files.pythonhosted.org/packages/c9/05/5d958bc8ea503e26be25ada5430fd409cfb45dc22ff33f9f96e649613c99/charset_normalizer-3.5.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3d14b50de6bf4d0edf857a9386836846f982b8f524e188e2e68b96d702bcf4aa", size = 290875, upload-time = "2026-09-30T04:34:47.691Z" }, + { url = "https://files.pythonhosted.org/packages/55/e2/06bad57dfdb49cad92c0ba85b6b4fa5827a67df37897287cfef0553843c2/charset_normalizer-3.5.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:28a15fdad492a99b6eccfaaed66ef3f74050680545ea61ec8b2f4c538f1f1320", size = 286987, upload-time = "2026-09-30T04:34:49.356Z" }, + { url = "https://files.pythonhosted.org/packages/c4/9f/9f52d2886d52645987d603425482c63c5045a3005db1354a7097e5ed1ae9/charset_normalizer-3.5.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a893cc101149f80a653f82062ebc95b34525a2614382e1da5458fe7c6997249", size = 271105, upload-time = "2026-09-30T04:34:50.957Z" }, + { url = "https://files.pythonhosted.org/packages/4a/41/e05e19578b7b87e7db2c3ecb884bd09d065274ab41e1f535542e8bae9b06/charset_normalizer-3.5.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:619799369eeef6366ed3e8755a5670f4f2f0fb6b30a0fd7264dc0fdc2357058e", size = 269833, upload-time = "2026-09-30T04:34:52.623Z" }, + { url = "https://files.pythonhosted.org/packages/c2/cd/fc7152414561ff78f9c61a4a627025f65fd244abaefc99ac4e75c6169b33/charset_normalizer-3.5.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:447441e76ec720b15e64418d32e092297340387053047c7c694f579efb0ee1d9", size = 263048, upload-time = "2026-09-30T04:34:54.013Z" }, + { url = "https://files.pythonhosted.org/packages/71/71/fb379e399b1013962716a059d551e03bd80b3e02f05d81246886af6c0958/charset_normalizer-3.5.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:62588a277bfb59def052abd940703fa35107152bf479781a878617d60faf8fb5", size = 249237, upload-time = "2026-09-30T04:34:55.373Z" }, + { url = "https://files.pythonhosted.org/packages/33/4f/aeadccd6d20882909eb2597ec40eccc05d505e2262f14dc76d7620700657/charset_normalizer-3.5.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:44bd4fbb29dfbeba60e7d2bd000c59e4b21ddb3cc53912b14048d37092706d7c", size = 290756, upload-time = "2026-09-30T04:34:56.867Z" }, + { url = "https://files.pythonhosted.org/packages/b9/7b/e8a92613236b257d3b75d532496eb21f68ad8231d7d56df94497e460112e/charset_normalizer-3.5.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:30fcd120b732aa79317f08dee04d7de0847822e4cf7ee0e9f445bb958832252c", size = 269026, upload-time = "2026-09-30T04:34:58.278Z" }, + { url = "https://files.pythonhosted.org/packages/ff/ac/21d5c6b972285c5f095ff78afdc99f3539e3985dfcf7ff1cfbe9e772f529/charset_normalizer-3.5.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:50e3adfb96fc189eb27b1cf62d3b598b89b4bb0420d93a3d3e42e137409011be", size = 287601, upload-time = "2026-09-30T04:34:59.703Z" }, + { url = "https://files.pythonhosted.org/packages/59/72/263491ec1494a194b16fcbff88a0220f2af633738c79e92b4d7189226322/charset_normalizer-3.5.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b736353c0a625bbd5fcec108576e2385db3496f4f771f785ff32e108d3c3bc45", size = 272660, upload-time = "2026-09-30T04:35:01.26Z" }, + { url = "https://files.pythonhosted.org/packages/38/7a/81f1186c57e406233969ae96b5fd0c907254ab8b6e47da8ae24cd20fb9d7/charset_normalizer-3.5.2-cp310-cp310-win32.whl", hash = "sha256:f5833ad231be5eb6553de524a70f48d71b2c8563101750531e0b80184e175cd4", size = 187301, upload-time = "2026-09-30T04:35:02.659Z" }, + { url = "https://files.pythonhosted.org/packages/ae/ab/fb8b5178fdf7bf68efa61cbe892286bc9f73846f26147d4725fb89388475/charset_normalizer-3.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:1461ac396c4fdb983a675f20aa555624f0ee18ac83d832b9244ffff3d8055275", size = 215446, upload-time = "2026-09-30T04:35:04.011Z" }, + { url = "https://files.pythonhosted.org/packages/36/40/e270b74e0d3f583d78d902960845a149e80eb7c737ee5613ccc6efc7264b/charset_normalizer-3.5.2-cp310-cp310-win_arm64.whl", hash = "sha256:c6708715abcf3c73b99508253e961a9967f02fe536532834149574eda6de0d1c", size = 203389, upload-time = "2026-09-30T04:35:05.577Z" }, + { url = "https://files.pythonhosted.org/packages/22/67/6a0b94a7960d5e1b5eacd2fb529f3fccc47db4644f7f0a7cfdcfc3be578a/charset_normalizer-3.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d21b8b13c7592db2ac5e544a6d83187b995257472b0c9e8351b6d507ae37ed6", size = 370642, upload-time = "2026-09-30T04:35:06.91Z" }, + { url = "https://files.pythonhosted.org/packages/fb/94/01009e13b94041599004edf32e56e382c24e570f60f79bab8efe45cfe1eb/charset_normalizer-3.5.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d760fe2a4d7c3b226cb9026d6a842868d52a7901bd98420e1baf14e80da85cf5", size = 259280, upload-time = "2026-09-30T04:35:08.448Z" }, + { url = "https://files.pythonhosted.org/packages/66/85/3b5358f60a13210f0b67d3755c168ef758701b021e655d88d4da28554467/charset_normalizer-3.5.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c9790464842f85f437dbbb54417eda1e0e6bfc52dd8d22d6fd1c994b73b2dc74", size = 245335, upload-time = "2026-09-30T04:35:10.104Z" }, + { url = "https://files.pythonhosted.org/packages/74/75/77c1c479b09ecd751d1e767b251ea5c14d4d50ff757bf404afab2692f600/charset_normalizer-3.5.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4685902cf26edf013ed7a3da0f426ebba7a00ebb9541386d835afbf002c11cab", size = 291707, upload-time = "2026-09-30T04:35:11.575Z" }, + { url = "https://files.pythonhosted.org/packages/0b/0d/363f78cacb70f58f15f4b083961bbd9d292f335d3f5c66fc4f1cfe69cb90/charset_normalizer-3.5.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4495c5002a7b28557e7e222e77e0b661183e432b7d6d2e788101e3f240e05b8c", size = 286747, upload-time = "2026-09-30T04:35:13.022Z" }, + { url = "https://files.pythonhosted.org/packages/e4/ed/cf505d3011ffceb12c2067a7a5d3cfe92b875d4d44bb0ff0d69375e2c184/charset_normalizer-3.5.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:211d5a3eb6af8f513b8d4ca19a8c1b7accab1b5f0d3175f9826b03c1a920dc1f", size = 269972, upload-time = "2026-09-30T04:35:14.606Z" }, + { url = "https://files.pythonhosted.org/packages/15/d8/f0a93a431d170e7ca681d4f6650fee3de934d18560e474e7267eb4b0f987/charset_normalizer-3.5.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ef4fcbf3327382cd4c9f540babd61248208af7b93eec4de397b4d5f58a09e288", size = 269339, upload-time = "2026-09-30T04:35:16.087Z" }, + { url = "https://files.pythonhosted.org/packages/86/bd/9b2bd1c5b7af02462c9752d33994834ff972a96b4c483eefde9e594488e2/charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd16aabe4a02a297c23417aa17ac6299dbd8c49f673bcd645b4929b11f5a4400", size = 261683, upload-time = "2026-09-30T04:35:17.488Z" }, + { url = "https://files.pythonhosted.org/packages/76/a5/cac540ab0fd61f3fec88ad3dbb64509e71424593d73cfdfff5ab3e4db279/charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:fb9e68df06293761f9fe66ade60a9bc6d0f5e42b8acf2939a9158af86ab0e5bd", size = 248143, upload-time = "2026-09-30T04:35:18.849Z" }, + { url = "https://files.pythonhosted.org/packages/71/7a/ff467301deef2089fad87f72df9e000a26a78fec7acbb18e1999371b8369/charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:59f63901b0031c3136cf64704dcb21de0bbae62ce2c9529bc39d27665463de37", size = 292358, upload-time = "2026-09-30T04:35:20.326Z" }, + { url = "https://files.pythonhosted.org/packages/ad/77/22d7e785d1e210afc2e2f58600dd1799d17a35665faf84383f002826c5f8/charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:304d5463e65a35d7bb0850550e0780395395f6fcf452f04db7d5ca7cecc425ac", size = 268766, upload-time = "2026-09-30T04:35:21.72Z" }, + { url = "https://files.pythonhosted.org/packages/ae/91/e8e946267f1c2d9e2bd651726e2fbd2addf02c4d36cea5069e32ca9d7bb5/charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9cf9b1a857e25c4baceeb3624e92a56df3668f398c4acba74e174d81fb4d1d3a", size = 287432, upload-time = "2026-09-30T04:35:23.273Z" }, + { url = "https://files.pythonhosted.org/packages/4e/88/7561d8a88d555e7df6623abe7c0070b4baf47549b9408783a2ae0a1a6cf7/charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:114e4d0c92d618409ed82a99e22b5c5e768fe995f2973f78265f4524f49d4640", size = 272470, upload-time = "2026-09-30T04:35:24.655Z" }, + { url = "https://files.pythonhosted.org/packages/35/7e/578c702301ec036f01455f30744a08d2b42f6ab35b9b2d4bf8cae0ef2a80/charset_normalizer-3.5.2-cp311-cp311-win32.whl", hash = "sha256:2625388c6c754520c37abaf3b41eb34d1cc4a373f457898f08606c8e362b891d", size = 186688, upload-time = "2026-09-30T04:35:26.225Z" }, + { url = "https://files.pythonhosted.org/packages/e8/fc/fdf8cf52ff21cd5bf158f20978991cf985325842f74283eb6df26c8a39d8/charset_normalizer-3.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:87e50a3e7cb90af586b6c5faf23e302a970415ac73bd7bd90a515a04b427ef96", size = 214932, upload-time = "2026-09-30T04:35:27.796Z" }, + { url = "https://files.pythonhosted.org/packages/97/66/3e45a506d8110b632541faf9a9470185aa9878f1ed44020f31346c1c5e5b/charset_normalizer-3.5.2-cp311-cp311-win_arm64.whl", hash = "sha256:254eb48b9fa5ee9898a3c445825a1f340fe53712a098904b39b0bddba8ea3cb1", size = 202828, upload-time = "2026-09-30T04:35:29.259Z" }, + { url = "https://files.pythonhosted.org/packages/e7/c8/693809898870237d82785a03f3b2b58fe4c9f14669f84a7d4e623c92a59e/charset_normalizer-3.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed2a239c0ea213acc1908150a3037257083c7c083128f1a4cec2ec4b97dca491", size = 367780, upload-time = "2026-09-30T04:35:30.888Z" }, + { url = "https://files.pythonhosted.org/packages/c9/87/2fea8c13dc24b3ca9c6f803a5b2dfdeae73eb4f9e12c7885ed908ff0433c/charset_normalizer-3.5.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b91363207bd9dc966a691e959bb47f64b30f7ac4b072be9968b366982f7db77c", size = 246730, upload-time = "2026-09-30T04:35:32.286Z" }, + { url = "https://files.pythonhosted.org/packages/a8/9e/09efac30b937722f46d3110ba30b875b24b2e3a266ed746cc4e376a94d80/charset_normalizer-3.5.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:38a873987f3be698494da8b2e3085e29da02da7b633dce73e79c699a113d7bf0", size = 237707, upload-time = "2026-09-30T04:35:33.709Z" }, + { url = "https://files.pythonhosted.org/packages/9e/18/70d76670b13686237863a379928d60bd10e021f17d243ab3d7014c4a5f4e/charset_normalizer-3.5.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:355ad8011081dec5412240c087a9a0c9d4d5039f3ed11a3f13e18c2b29b56c51", size = 273050, upload-time = "2026-09-30T04:35:35.138Z" }, + { url = "https://files.pythonhosted.org/packages/54/e2/77a8b09d5adc013ed07b95b01b8b8fa5441c4e810e83ee7e4aae2fa4d91a/charset_normalizer-3.5.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ee21e28f0430bd6dc9086c6e525d5e818a44a5ad19720c8a0ef766792f3eb5e5", size = 270345, upload-time = "2026-09-30T04:35:36.502Z" }, + { url = "https://files.pythonhosted.org/packages/7f/c5/38806a25ab5e65fc178f39affeda20858efafede2fce1ffc2556cfc9fe73/charset_normalizer-3.5.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3d31298449090ab8d47b7b1b2a555ff73cac7ed438a08b7ac160980c7ebed649", size = 257601, upload-time = "2026-09-30T04:35:37.919Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8d/213565184708fdb263ae55e2c04ee1ff748129dd65d48ed0e3502da9c85a/charset_normalizer-3.5.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5cde776b7cc66e4f6c99612cea4aa7269aa65863f7a15841b2c264f103822f4e", size = 252222, upload-time = "2026-09-30T04:35:39.544Z" }, + { url = "https://files.pythonhosted.org/packages/7e/24/76d2cefc25472531e4c5c7dfff68865eb1c39b78482f0fdc15b46f047830/charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ae4f5fea5b8b8ccff88238cc8569303e5ee95efae67fa62922a311397a71f346", size = 248482, upload-time = "2026-09-30T04:35:41.088Z" }, + { url = "https://files.pythonhosted.org/packages/7d/dc/65a801b66ab4c197e22c433ab25e7ac24324ac6f45a2269aca42cce309bf/charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:f7d486c83842422badd511868fd8a9a20e9407ace71564b6af47ce7e60a336c1", size = 241206, upload-time = "2026-09-30T04:35:42.59Z" }, + { url = "https://files.pythonhosted.org/packages/a7/95/ca9b5eabde673002c6f1e7ada1b223916fe18f6d661da7aabd4d643718f1/charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:11a4d68a6ecda3292cb1e50239e111543ba5d709bb62a6b4ea1afcfa729d8875", size = 273190, upload-time = "2026-09-30T04:35:44.347Z" }, + { url = "https://files.pythonhosted.org/packages/2d/8b/803b4d2a3f6e1740f63f1e87b04d14b42f3d4fdfe6ed7d4db2d34102b14f/charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d6734d2ef8a50fbf8445c139477da401f50d62a0606bf00e20ec6d87773fefb1", size = 253527, upload-time = "2026-09-30T04:35:45.915Z" }, + { url = "https://files.pythonhosted.org/packages/a9/55/93c0e5dbd085ae0471346026abbe7e0db9ea2d6fea74e51f0b5a46f233a7/charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a815775b6c38d4e0ff7bcffbeba67feded90202bb6a226b8dd35f1c855217413", size = 271285, upload-time = "2026-09-30T04:35:47.49Z" }, + { url = "https://files.pythonhosted.org/packages/95/69/0dbd0e0b9b16cfa816cdfcb3e2e3854a1f680dc07fb1245ea125e7448060/charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:23851fb4e1b85ed3f6c2a27b777cdfe2e19fb5b38429a8faf38c7542b7665869", size = 260010, upload-time = "2026-09-30T04:35:48.996Z" }, + { url = "https://files.pythonhosted.org/packages/58/9d/e7b88e7b1bf403590c3b573277b5e1e488c68c7a6fbacca310a2c324e90c/charset_normalizer-3.5.2-cp312-cp312-win32.whl", hash = "sha256:db19d07e2e0129e974a0e65d0064fc222a446cd5122c2fd4184d2af9fc734a9e", size = 184125, upload-time = "2026-09-30T04:35:50.777Z" }, + { url = "https://files.pythonhosted.org/packages/eb/e6/e6e083884cbcfd49c64865af05027fe7011be7b2d9179524f099a1b611f3/charset_normalizer-3.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:780fbe7cab297b81dad9fb8dc5eb003c0468ffb0d9e5f65068c53a34661a96bc", size = 207486, upload-time = "2026-09-30T04:35:52.194Z" }, + { url = "https://files.pythonhosted.org/packages/c4/e3/017aea0911ada7405a825c7d937eb3a13009664e2f5b38e8c4bbf2abf894/charset_normalizer-3.5.2-cp312-cp312-win_arm64.whl", hash = "sha256:e2af3aad578aa6bd1384bcf4750fc285e5a9de53f40b7d41e5a0bf748edeb2b3", size = 196734, upload-time = "2026-09-30T04:35:53.636Z" }, + { url = "https://files.pythonhosted.org/packages/c5/34/68292d68512768591aaff07c59bb53ee31341c87759433a859c4641a50c2/charset_normalizer-3.5.2-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:ed905975ab14056a2e5eb1c376cb2e1ebc5396baf84163939c518556fccde9f5", size = 225946, upload-time = "2026-09-30T04:35:55.313Z" }, + { url = "https://files.pythonhosted.org/packages/e3/80/bee0b01b90ccd5322ae1d0abb33fab1bd95b7c2eadaf02aeccf22e04ee83/charset_normalizer-3.5.2-cp313-cp313-android_24_x86_64.whl", hash = "sha256:a66c3bc5ab1f0ff2164fc9965ddd611ff0802173f4b9d24554c563f6ab7e1d6e", size = 238619, upload-time = "2026-09-30T04:35:56.863Z" }, + { url = "https://files.pythonhosted.org/packages/78/6e/60ce52a85a7fd631ae8482ae6d74521014ca2f255892679484dc04d7ef56/charset_normalizer-3.5.2-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d2374b62878abb00cd8309b32af6c0b715cd02dec0ca74ef12e5069bdc64144a", size = 206701, upload-time = "2026-09-30T04:35:58.639Z" }, + { url = "https://files.pythonhosted.org/packages/36/8c/71aafad23f971afc84c2b295bc0c560739ce1dac558aad9fec22e39f3639/charset_normalizer-3.5.2-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:d376bbd28b3a8999db1a103b3b388aee6f1ddeb3e51bc2172993efdcd86e064d", size = 210506, upload-time = "2026-09-30T04:36:00.147Z" }, + { url = "https://files.pythonhosted.org/packages/91/da/3c5a7798c046df7d2d68ad653cf5b6c5a8bfee225055a843c6f2f42aac1a/charset_normalizer-3.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6045373d5a89a5ec71afde535db987ca28e76dfa276c2d4c818265b375d4b055", size = 366626, upload-time = "2026-09-30T04:36:01.77Z" }, + { url = "https://files.pythonhosted.org/packages/e1/16/710ac3de2ee354e2bd1a9c94efe45a2d27b5c6ad39b2d6a905be2c094b6c/charset_normalizer-3.5.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:849df64e889b2e17230d58410a03dba311a65b163508fd33679b2b737d4b7858", size = 244624, upload-time = "2026-09-30T04:36:03.389Z" }, + { url = "https://files.pythonhosted.org/packages/d6/39/45c7439f5b63d24f7d5b2a1d760f34af7628782d7144b4cc8ded45c2d4bc/charset_normalizer-3.5.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:15c44f7edfd477b06f517a5cc317fc1707edb9de2c865f43d4b6513907473234", size = 235731, upload-time = "2026-09-30T04:36:04.987Z" }, + { url = "https://files.pythonhosted.org/packages/4d/34/38f3154785ce92e9f56eb226f4d35bdfae6b008480dd055f58837a89c810/charset_normalizer-3.5.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a89012d6d5476ee112d20d998570ed58df2260a852afb1758809cd6900411d21", size = 270352, upload-time = "2026-09-30T04:36:06.412Z" }, + { url = "https://files.pythonhosted.org/packages/04/f3/859f74e7babc977705026b30593b3be04049632a522fb7000f83c033d747/charset_normalizer-3.5.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0c951d5e6dd9c2ff60609476752bee49da4206adde960ebc247766937f72e718", size = 267393, upload-time = "2026-09-30T04:36:07.865Z" }, + { url = "https://files.pythonhosted.org/packages/4b/85/41d27f234b82e47c167a5f6c0f62501dc0c640585ff4aba79e08a390336a/charset_normalizer-3.5.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7218e8f32b0956cfcd048fd42d9d5779809745ca1d86113ca56f66e7ae1549c4", size = 254660, upload-time = "2026-09-30T04:36:09.248Z" }, + { url = "https://files.pythonhosted.org/packages/58/ca/5d1a997587febe5b26d8daffe363b5c1a091cece19828eec6502fd09c5ef/charset_normalizer-3.5.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19a731138fc27d5682277d3b9df22855cea1239bce7fcec5f78f42ef2d1f3c3", size = 249996, upload-time = "2026-09-30T04:36:10.73Z" }, + { url = "https://files.pythonhosted.org/packages/b3/1f/d1e78246f7ed60c8c8d606b4ac27f66ce49cc3e95f24893ccbeba9f77302/charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:62603db9a7caa0802eaa28c1c46fecd7b3a263a774069c24c3c28c302448721c", size = 247028, upload-time = "2026-09-30T04:36:12.294Z" }, + { url = "https://files.pythonhosted.org/packages/8e/37/eba316edd4f0c4d3a5d945924c4eeeae59abac4056aa815d8a4268f863a2/charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b6856554c4f44d79fc2307d5768854310a8f0096e501c75637542c82292b0429", size = 240562, upload-time = "2026-09-30T04:36:13.887Z" }, + { url = "https://files.pythonhosted.org/packages/c8/8e/aaa037d40ca9ef045977f1a661048b1aa33f223adfce3452fe9be9f79d14/charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1bc0baf5ef96b6ede57d47f4b8fe4d9d84019c3bfcbeb20a41edc6a6ee341f1f", size = 271699, upload-time = "2026-09-30T04:36:15.41Z" }, + { url = "https://files.pythonhosted.org/packages/26/19/1c1c9f75974adf523b87f34b8a2adc5a435cd65916812bcbd0dfa45f9a29/charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:56bc200a365efb37383b7852e4cc5898d3b2da5987289b543956cf8cad71018a", size = 252030, upload-time = "2026-09-30T04:36:16.839Z" }, + { url = "https://files.pythonhosted.org/packages/bc/90/0660ef18e18df0a4d2a1a0edff7dfbba42d4e50ef2425557a5bb7051f77b/charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2c9ad19a6cfcd5ea5c0d41161d22f9df1dcc277e9bef2751391334546a314c00", size = 268565, upload-time = "2026-09-30T04:36:18.468Z" }, + { url = "https://files.pythonhosted.org/packages/79/ba/57adc269824e8658f1a0f97a9e514c247445a9632b3419b97e0ba37f16dc/charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e243bd13217235fc7290c621941c3f5cc8b66e4872495be821d7436ba2fb838d", size = 257627, upload-time = "2026-09-30T04:36:19.938Z" }, + { url = "https://files.pythonhosted.org/packages/9a/85/33abd4315c052d3d4f54c92b1ee49bfbc0dc7115a981e462a793b6d2ab87/charset_normalizer-3.5.2-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:a090bb2c68df85450502e3e20d665e3a5af9c65a84d6508ed477badd49166fd3", size = 143407, upload-time = "2026-09-30T04:36:21.376Z" }, + { url = "https://files.pythonhosted.org/packages/4f/de/6435e18d1aaa5d910b896d551411c96af1f42a0c56c29afc2016c61ccc2e/charset_normalizer-3.5.2-cp313-cp313-win32.whl", hash = "sha256:2b7b3bbfb4fe8ef40600792d762fbaa9057559f9d3fad209525b7a22b99e91fd", size = 183207, upload-time = "2026-09-30T04:36:22.776Z" }, + { url = "https://files.pythonhosted.org/packages/9c/76/b8ec57f4e9ee3253541abf95e4a462c0175fe8032dcd070f1f2421240942/charset_normalizer-3.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:78456a747de8dc58360ffa581f30a002baf5aa28cb262536545e91f113ed7639", size = 206489, upload-time = "2026-09-30T04:36:24.306Z" }, + { url = "https://files.pythonhosted.org/packages/3e/60/c647c6ae47480221e875ea5d743ff94946f7416e3c69415ab772928e8d32/charset_normalizer-3.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:11912e4bb14baae7c5d8791aa55ba0a3a03ec6729073307b0f57270abaa713d3", size = 195501, upload-time = "2026-09-30T04:36:25.846Z" }, + { url = "https://files.pythonhosted.org/packages/58/ca/7aa91362a2f77ac8e9e28a9b902a74f7d0e11a851ef0d27a74308da8cd90/charset_normalizer-3.5.2-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:1afb975bd5d68d5ce9f6b6d44fdf2f7e34b895a35e95708a7a91b20a3b51d187", size = 226010, upload-time = "2026-09-30T04:36:27.669Z" }, + { url = "https://files.pythonhosted.org/packages/a8/cf/ac8878d0322cf88a1aad4c7b147db32ca0bd806eb0060957b2e31486dbe6/charset_normalizer-3.5.2-cp314-cp314-android_24_x86_64.whl", hash = "sha256:bbbfc8e28816f19d7c0f1816664980c0a9875d01b27cdf8eedddb639d9e108ad", size = 239266, upload-time = "2026-09-30T04:36:29.434Z" }, + { url = "https://files.pythonhosted.org/packages/c9/6d/9a08d7e0b29b7208e2c6c01dc56c8e0520e7c7beadbbfb024b58fd69c8a5/charset_normalizer-3.5.2-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:7967d08cf06dee78443b874f98c98036f624f3a4e73e11f9f64f5be4d25393cf", size = 206783, upload-time = "2026-09-30T04:36:30.872Z" }, + { url = "https://files.pythonhosted.org/packages/82/44/b0aa350280e6ff5a5492d17cf10460dd39d5ee848f872f7ba2df10607f60/charset_normalizer-3.5.2-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:4c2b5031f63e331e3839b40aed2dd6f191e9c07edbde303e7876846ea1946995", size = 210449, upload-time = "2026-09-30T04:36:32.625Z" }, + { url = "https://files.pythonhosted.org/packages/7c/8a/40db9aa9f5907bb0e6f8b6d64064bf8852fb33d4b813ff9414911df7647c/charset_normalizer-3.5.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fcff63213e8e6e47770541a4607175404f47cbb3ebea7b6058cc82d524a0e424", size = 367815, upload-time = "2026-09-30T04:36:34.197Z" }, + { url = "https://files.pythonhosted.org/packages/7f/72/9c5e7707b57c8ddfa9ddf7b0b1d009d7fbab9e9e887d5b721060f37e307d/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8d86d6fc60743dc916eb79e2eb1ec4818e21e427731543af40a3021851174a13", size = 247095, upload-time = "2026-09-30T04:36:35.803Z" }, + { url = "https://files.pythonhosted.org/packages/83/09/71e453691e927de4ddf792770cfaab3f49d494e222f66ea5e404bbd5e39c/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a881931aa470808df94a8c380eed2bbbc76cd9dc622310f99665658c821eb6d", size = 233942, upload-time = "2026-09-30T04:36:37.407Z" }, + { url = "https://files.pythonhosted.org/packages/9f/86/85c84e4da8b27dd409577d9437926ff581c5f9d3c66038dc68c1a526de51/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8024d00c3faf3fc0c16e07a69f4405e8eac7cc0ab15f65fe6cf43827c4cf72b4", size = 273762, upload-time = "2026-09-30T04:36:38.904Z" }, + { url = "https://files.pythonhosted.org/packages/92/08/564955a4b5f2ccb410ab480bbe8c6a18063ff27f2d35458731c4a5335df9/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4d48f2d08b9de5864e2c8744d4461b862fb149a18274abc8b698c45975573438", size = 269514, upload-time = "2026-09-30T04:36:40.469Z" }, + { url = "https://files.pythonhosted.org/packages/18/24/bad3ac4271589df29cf5ce2f5ae490518a5739358052bd0d61209e6fea54/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34276fd796040bf0993ab33a369aa572e6979c7aab225a88893667ad8eac8f7a", size = 255056, upload-time = "2026-09-30T04:36:42.02Z" }, + { url = "https://files.pythonhosted.org/packages/d6/3e/350d89ad49916b86554d6f5f2d03ec1152148f87e5ff735106c6a03b1a36/charset_normalizer-3.5.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0521c5665880b33d603717defa76c094048900010897909952397feb3039da56", size = 251311, upload-time = "2026-09-30T04:36:43.577Z" }, + { url = "https://files.pythonhosted.org/packages/56/5b/4970a2d154df502e133402906dd04e3ae7cada7b3011283c88d0479a2585/charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:eff0ac9dbe711a4aee69bf04a83896aa9b85f19641264053a9f6d48573abb7dd", size = 250190, upload-time = "2026-09-30T04:36:45.185Z" }, + { url = "https://files.pythonhosted.org/packages/88/8c/f1a91bddc8fb47c2889e29ea7ea49a194eb0d9868675d786806519c00d76/charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:1503bccbeb36d5527790c3930327704c39af22de3112f1b1666a9f3ce15ee204", size = 237098, upload-time = "2026-09-30T04:36:46.689Z" }, + { url = "https://files.pythonhosted.org/packages/24/0e/bb5dace3cc7e79068425386a6589c19b5a2ab5fefc2a46abea6919683332/charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:52aa6992700996af31f375de0c6bacd402b0097fe40b53c426b9f51a90ebabc7", size = 274228, upload-time = "2026-09-30T04:36:48.31Z" }, + { url = "https://files.pythonhosted.org/packages/9d/79/b849ad523017ea9f5a45581bbebed91439e0cf42fd2860a6f64e358eb5a6/charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e09a3942ecbdee5cce73ea9d42da82b81b72ac1bf031ce069b93b5adf4eac8cd", size = 252401, upload-time = "2026-09-30T04:36:50.091Z" }, + { url = "https://files.pythonhosted.org/packages/89/8c/75469d690cf47200bce8f6cad7655724fc23148e147abfc5ce78b5f65863/charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:c7c9ab723cde841fefb34efbad91e87f00a674b1fe1cd0784fde742bf2c154dc", size = 271846, upload-time = "2026-09-30T04:36:51.719Z" }, + { url = "https://files.pythonhosted.org/packages/26/cd/6d52d3c7437cdcf2e310ce9f28f282e733d4ef60ed19105d1819c356255f/charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ddc7dacc8ece3a182e7f15cb862d1fd616b46d076cb1ae9dd232b2c38b655874", size = 258151, upload-time = "2026-09-30T04:36:53.234Z" }, + { url = "https://files.pythonhosted.org/packages/f7/4c/070b38bdb5f49a70199fce923ec0726a49536a63ab262abbfcaaf351110b/charset_normalizer-3.5.2-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:ee43c17b173d46a3212baa6ead3ae258eeabdae48c263a01ccf0218c366dd655", size = 143570, upload-time = "2026-09-30T04:36:54.816Z" }, + { url = "https://files.pythonhosted.org/packages/81/84/9ebfc8ed6c8c4fcd8e726ff6bf220cc8deb3966e31dce9be8dd8aa017e64/charset_normalizer-3.5.2-cp314-cp314-win32.whl", hash = "sha256:4f87960d57feabfb618e4e0af6e7371645fa26a277860739d6e5d6e0012c92f0", size = 186412, upload-time = "2026-09-30T04:36:56.643Z" }, + { url = "https://files.pythonhosted.org/packages/d1/78/5ed86f743d4bc350db307e7636419a0a5ee1d91806d30c7f667bd5c80dae/charset_normalizer-3.5.2-cp314-cp314-win_amd64.whl", hash = "sha256:e4e81e09c1578b8df602e3db08b0b3ea0a6947ad612f52bf8dc5ea8d47691f0c", size = 210965, upload-time = "2026-09-30T04:36:58.205Z" }, + { url = "https://files.pythonhosted.org/packages/53/94/a3a7698e9b1a395e1eb99ccd9a324be9347973bff4e72db2a06496d7cd27/charset_normalizer-3.5.2-cp314-cp314-win_arm64.whl", hash = "sha256:80d02b6f04e92601a081dd97b23d3128033098bff5d35d392ddcc0476ea11253", size = 200406, upload-time = "2026-09-30T04:36:59.764Z" }, + { url = "https://files.pythonhosted.org/packages/c1/48/c5dd00d5ef7791f02666de250a5bb6071e29b7e133cf4b835800b6d3bc27/charset_normalizer-3.5.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:dca9ab98072a5a54ebacebdc45f53e645336b320c667410b061be1ca588ae709", size = 396871, upload-time = "2026-09-30T04:37:01.543Z" }, + { url = "https://files.pythonhosted.org/packages/12/c8/8379554b42e8368161d898476686947a0fdbd3e8865170d7909dcabfdee8/charset_normalizer-3.5.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f0aa869112ef88429ae17820d99c3dd9504c9e9c671d3c246f3d7442cb051084", size = 249711, upload-time = "2026-09-30T04:37:03.111Z" }, + { url = "https://files.pythonhosted.org/packages/4a/eb/2ddb1035d17320caa9f41682935123a9a250277b261c3efc86b2d2a21343/charset_normalizer-3.5.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c0afc6800ba57ccc350374c5bd6150419915d95ce93cdbab2d783d75eaf30ecb", size = 231146, upload-time = "2026-09-30T04:37:04.721Z" }, + { url = "https://files.pythonhosted.org/packages/4a/24/2ecb4bde104322cd7859d6594fcfa74649f8d90b3221c9feecbef149875b/charset_normalizer-3.5.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7dcd882da75ef9adf94903b1e3b9419e8aa8fb4c7396822b834b9ef7fb96954f", size = 271552, upload-time = "2026-09-30T04:37:06.295Z" }, + { url = "https://files.pythonhosted.org/packages/3f/98/9d5f6ebc3aee9fef5d30b4aff11fb2ab7a1222b4064f8ef2c7c87cde217a/charset_normalizer-3.5.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2e06a3a98f916dd41d27f3105e02e7a40181c98c94b9158733d03a6f80506c09", size = 269810, upload-time = "2026-09-30T04:37:07.905Z" }, + { url = "https://files.pythonhosted.org/packages/09/e1/a3b06a10461b1b7628853c934c644e03bc28e42767116afb52f19a56519b/charset_normalizer-3.5.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6bd128f206a7752ae1f2ab6c61bf8a24ba28913a10df8b14c2637b973ff97a80", size = 259845, upload-time = "2026-09-30T04:37:09.554Z" }, + { url = "https://files.pythonhosted.org/packages/fd/d3/6f561f74a296cf27d61775a1dc665ad13f3bff6a798810ca05907f37a7c4/charset_normalizer-3.5.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c8f3d67aeaf55f017982b73683f0e7342ba2f6635a78f69ce89ebb26aa411e5c", size = 252825, upload-time = "2026-09-30T04:37:11.274Z" }, + { url = "https://files.pythonhosted.org/packages/26/9f/69e13ca3b18f43e0eafcd34c04a45b732ae22a43b54a5fc9e119103356eb/charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fe9753dfee015c570d73df76f899f18444d41388bffcde097deba51c4fadbb9f", size = 252659, upload-time = "2026-09-30T04:37:12.941Z" }, + { url = "https://files.pythonhosted.org/packages/73/a9/ace29806a0dae18939919c76ba526472d83214afa101105fabff2cf30625/charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:92888bb3187c5ba50500b00b3b310c9f2c651709d28036077680cb5255450a03", size = 238819, upload-time = "2026-09-30T04:37:14.659Z" }, + { url = "https://files.pythonhosted.org/packages/f8/c1/6116d52a2e3311ec80f21f5fb5e17b27405f10b9608af8f6e69516841a1b/charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:d008d90a7f2471519aef0c90dfbe73b3e6e4d5e66ac48e19154c17e89e98b604", size = 272973, upload-time = "2026-09-30T04:37:16.346Z" }, + { url = "https://files.pythonhosted.org/packages/19/aa/9955c7e93bba10a9c7e8f7a5031b7ced66f3a1883a55c00712b8d5850ff3/charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:31f3930700408d211f13378ccbe1c40845d8da54bd0681fac3a9b5aae81c7aa8", size = 253692, upload-time = "2026-09-30T04:37:18.212Z" }, + { url = "https://files.pythonhosted.org/packages/bb/33/2a6ae7fdc1b10cb581cef91addd8cdfc5f40d50abb5702309369d5834579/charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:2a925889534b3748302dae5dead07cc13480de1dac3aea80a941b729b471ef93", size = 268757, upload-time = "2026-09-30T04:37:19.877Z" }, + { url = "https://files.pythonhosted.org/packages/a2/22/80992720a0282cd39bba1db35868e6b9c22f41281160143a836544bc1d8a/charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f5ec61164adcec446f8969a3358ec3f9b26bbda3b9213e5586d219afa8df2915", size = 262220, upload-time = "2026-09-30T04:37:21.583Z" }, + { url = "https://files.pythonhosted.org/packages/92/9f/181fd07e1bffea1d95cd80c84ac537354f50699c22cfc4d3c02b6fc16208/charset_normalizer-3.5.2-cp314-cp314t-win32.whl", hash = "sha256:598a11a2c7ebaa5334bf698bf29568c9c390abac6a154d8170fedecd1cea38c5", size = 197797, upload-time = "2026-09-30T04:37:23.235Z" }, + { url = "https://files.pythonhosted.org/packages/49/1c/25d8415ec1c4f2f41f1680435e4c87cfb378ff2f677d950946f2a45d0632/charset_normalizer-3.5.2-cp314-cp314t-win_amd64.whl", hash = "sha256:7fdde2c9fd9e3eca40631e024664cf2584272cc8f96308cbe5fdfc930f51d8bc", size = 222765, upload-time = "2026-09-30T04:37:24.891Z" }, + { url = "https://files.pythonhosted.org/packages/3e/b4/46b48f013dadfc0d0d33b375438e31bdf5a989dc68389c6bf627054d4df9/charset_normalizer-3.5.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d1befeed746d247c81127bb14de9dc3d30edb6e5976d34f83f86ed262b1d9105", size = 210985, upload-time = "2026-09-30T04:37:26.634Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e9/34e597dee616d0b8ee4b34d29399e85c2204ade174157a48505d42baa4ff/charset_normalizer-3.5.2-cp315-cp315-macosx_10_15_universal2.whl", hash = "sha256:87475fabc8d9996fd9c27debb395e642e8c838d78a00b6e932227a0e06b81e26", size = 367676, upload-time = "2026-09-30T04:37:28.329Z" }, + { url = "https://files.pythonhosted.org/packages/60/9f/a5d1c91c0263745e2cd344c5a4415d787c575501ab1d449f1148ac6b495d/charset_normalizer-3.5.2-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9409a8bf35cf78353942504b24a57de3d75b708997a1e4bd8db71ac8633ce364", size = 248414, upload-time = "2026-09-30T04:37:30.167Z" }, + { url = "https://files.pythonhosted.org/packages/26/79/e697f77464748a3ee3cf490c83d592459400d4898380d66c38366b03080c/charset_normalizer-3.5.2-cp315-cp315-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:498dc3188ca05a68231ac3fdbfc7f57eb67e1343c30e0fea17f8218c1599b253", size = 244775, upload-time = "2026-09-30T04:37:31.964Z" }, + { url = "https://files.pythonhosted.org/packages/ca/87/3d42a42e18ea066e2513936fd678a00696e77878b5ae04528976abdbcb83/charset_normalizer-3.5.2-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e242bb1c5e76e97dfa9e7f209a71e93a01d7f19ffdd5cfbb2e2d55b4f08f8ab0", size = 273877, upload-time = "2026-09-30T04:37:33.661Z" }, + { url = "https://files.pythonhosted.org/packages/c3/76/8a28136f3938ba9836f84280ce0c4d61ed1cf15a036b2034900c62634162/charset_normalizer-3.5.2-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:def79fa35ef0cef8d2accec024f4fdc7ead3012ff02f5215c783f39f03ef8cfc", size = 269455, upload-time = "2026-09-30T04:37:35.573Z" }, + { url = "https://files.pythonhosted.org/packages/a0/a1/4fbf5d0f0f1b2a080474c1cf9a2f12c4c6531bb0e8ba591055e846d2b4e9/charset_normalizer-3.5.2-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3df041de8887954562c9b261cba85ca0e9ded74048daf125f45edcfaa4832229", size = 257336, upload-time = "2026-09-30T04:37:37.397Z" }, + { url = "https://files.pythonhosted.org/packages/ba/a2/8b50aa320adb880ad579518e6f718f24944804b42a88b83d267d5d444125/charset_normalizer-3.5.2-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:04851f73ae72b8413dddadb16a49dfee95263553741fd42d546f7d66907e6be5", size = 257584, upload-time = "2026-09-30T04:37:39.522Z" }, + { url = "https://files.pythonhosted.org/packages/a5/57/50e3fed84e175f40349bd0da7a4fce94c87f0378f52d74f511d89e0bdc20/charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:183b88127acdb4fabe59d951ab424faf1af7b63cdbb5f776186c1ea2ffcaed98", size = 251854, upload-time = "2026-09-30T04:37:41.23Z" }, + { url = "https://files.pythonhosted.org/packages/d6/54/f7fbb3493c9f49091213b9c2d6dd65800696f1ce1a3f196a4205f50417b1/charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:16fa0eccf81304b79c5cd87f9271c3b85dd9dd99245e4422ae9c0dd45e0f99d3", size = 248767, upload-time = "2026-09-30T04:37:42.883Z" }, + { url = "https://files.pythonhosted.org/packages/d9/37/b3a6385acc5a1e45b39ae9c90bfb9cf838a09b9dd37ef2740ab4c6b4a2eb/charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:7441d755b7ab94f8d4eb3e43ec05482d760842fd263d003a99102d742cd835e2", size = 274479, upload-time = "2026-09-30T04:37:44.658Z" }, + { url = "https://files.pythonhosted.org/packages/89/44/809913e2cfd279e635a9294fdbbfb1b1dc62a8189d473d561f649fce98d8/charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:ca403d7e4798f525fdfc78e258820419cbbd0f0ecbab9de7840e3c017cf6b8cf", size = 258310, upload-time = "2026-09-30T04:37:46.529Z" }, + { url = "https://files.pythonhosted.org/packages/af/a2/f28400ab13359d91bd39179df8e149376b9bf36588e739a3a4f9de2b84b2/charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_s390x.whl", hash = "sha256:df29a0a7107f7011e77f4eebdddec4c7331e24d787a0b21a46d63bdf7445da95", size = 271100, upload-time = "2026-09-30T04:37:48.399Z" }, + { url = "https://files.pythonhosted.org/packages/e9/89/9bab37955edf0adb3b66f8a3a6617d9f2f487e0d56f295a6a286cb640aa6/charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:f3c96f633825733f735c5a9cf21d21a257d8e1edf0b1cee0a064b9c424ca0f7d", size = 259936, upload-time = "2026-09-30T04:37:50.023Z" }, + { url = "https://files.pythonhosted.org/packages/23/b5/4459e08d45a679f903d50fea08bc52cfa728cca4d7bd02c757b5e5abda2e/charset_normalizer-3.5.2-cp315-cp315-win32.whl", hash = "sha256:281cb91036248400f4cc957495cccd44c275c2e0c5854f7e45ac5cf7dc193847", size = 186301, upload-time = "2026-09-30T04:37:51.722Z" }, + { url = "https://files.pythonhosted.org/packages/98/e8/55d5fd3935b4bce6da4fe0df61898e8c82653e317e677bd58aceb9c60f13/charset_normalizer-3.5.2-cp315-cp315-win_amd64.whl", hash = "sha256:89b53f3cda69831909888e0494f4fa0bcd3537e3e138dabeb620bd6ad946bae8", size = 210858, upload-time = "2026-09-30T04:37:53.427Z" }, + { url = "https://files.pythonhosted.org/packages/a9/5b/974423c2fd8e524c7a7f64318c1e02240ef954912fa2b4d70344107b9c68/charset_normalizer-3.5.2-cp315-cp315-win_arm64.whl", hash = "sha256:6be488a102b8cf28d0391d8c4ba7748938ae28b78ad901f8585520fca33ead1a", size = 200309, upload-time = "2026-09-30T04:37:55.015Z" }, + { url = "https://files.pythonhosted.org/packages/ee/f9/00ee0195db1013d8f7c416fd770fbeb560bb46eb2e36b054d05cb56f6cfa/charset_normalizer-3.5.2-cp315-cp315t-macosx_10_15_universal2.whl", hash = "sha256:915563965d418f986e7e145accc592eae9e1a1be3566ff98a05d7a9ec42a76e1", size = 395343, upload-time = "2026-09-30T04:37:56.743Z" }, + { url = "https://files.pythonhosted.org/packages/04/3a/c00b50e94c964cf934c7899cd47c97952fc11dad71cc5884b3c61795b09b/charset_normalizer-3.5.2-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:65cd72beeeca9d3aaea1201e5923859f308f952f9c71de93f06063c79f0f7a3b", size = 250114, upload-time = "2026-09-30T04:37:58.607Z" }, + { url = "https://files.pythonhosted.org/packages/50/27/d102dc880bbcffd0479ab64dfc1fb96777a854355a55e2bda72a71efadcb/charset_normalizer-3.5.2-cp315-cp315t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b7fd005a73d9e657273b7a10dc71a9e03c8fb9ee6999798d6918ce095b81ac7f", size = 239997, upload-time = "2026-09-30T04:38:00.511Z" }, + { url = "https://files.pythonhosted.org/packages/a5/4a/bf7ef45794dd293fab5f98a9309817977fbb845b9998f171b8cc5d8437a3/charset_normalizer-3.5.2-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e54da4baf05720032d527874d40b65fa4d7e5c6c6a43d0c3adbeffcaf275a2b3", size = 272313, upload-time = "2026-09-30T04:38:02.509Z" }, + { url = "https://files.pythonhosted.org/packages/e8/ee/008a2837737991474c5754bb3191010007663860979701990982a502cbaf/charset_normalizer-3.5.2-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:124fbf1a8ff966d87ae05bb8bd45a71f966055ed8bba320d0c7cf450bc5f4d0e", size = 269986, upload-time = "2026-09-30T04:38:04.435Z" }, + { url = "https://files.pythonhosted.org/packages/93/ad/bd74a283940dc910c5b14f8e4f80a248082bc9c0fcbe1f54530cb6d9cc5e/charset_normalizer-3.5.2-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28b4f0d66fb834ff90f28209ac7bce77868c45d8c93e26f906709d9b7c2e1af9", size = 260202, upload-time = "2026-09-30T04:38:06.549Z" }, + { url = "https://files.pythonhosted.org/packages/8a/7b/ed341c66f69f688723501fac752be3d63c7159ca0d0d4174fc611e5710bb/charset_normalizer-3.5.2-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:58ca3755ee7ff7f59b57789ec9833c9de9ea275405cdd240eda1f193112e398a", size = 259083, upload-time = "2026-09-30T04:38:08.311Z" }, + { url = "https://files.pythonhosted.org/packages/cc/9d/e41588b777965e5031a43128a1e96173ebb35ac75fc53ec3b517e7c21cd4/charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:443eae2bf318abeaf6f15d785138f71fd6de770e99a92158b8b814265e079115", size = 253081, upload-time = "2026-09-30T04:38:10.402Z" }, + { url = "https://files.pythonhosted.org/packages/81/35/b761eb6d8c1eb218b9b42b9b4d5ac902afdc399fb6dac6f9a9aac7bda589/charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:58f361dcbab699cf8f42db3f47c8e7fd1036f138c23a5d08de9fde5f425a730c", size = 248712, upload-time = "2026-09-30T04:38:12.317Z" }, + { url = "https://files.pythonhosted.org/packages/4d/2c/147169a041b747759f37405c0a97157e8e92de967968373101ff14915cba/charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:1b4cbc7c3491ccb4aa17fcd8165649d01cf39f76de1696da8631b5f71b85401d", size = 274176, upload-time = "2026-09-30T04:38:14.138Z" }, + { url = "https://files.pythonhosted.org/packages/f0/2d/0ff8db0d373ba8538db686db11cd7e8912031490b9e4f383b41912e8d594/charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:ba0b1d2620edf869789c3879223f52bf2afc5d31b3cb47cc57b3a12c05e2aa9d", size = 259413, upload-time = "2026-09-30T04:38:15.841Z" }, + { url = "https://files.pythonhosted.org/packages/8a/8e/b4a085fb47c9d3a7e43576a4784fdd8fe23f907514a972de8086edaf7a48/charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_s390x.whl", hash = "sha256:5e2b6b57e9733d39f0c9fd3185efa6b8e29652c4cd8fe94180272cf6ed9a78c4", size = 269434, upload-time = "2026-09-30T04:38:17.626Z" }, + { url = "https://files.pythonhosted.org/packages/83/1c/d8d8d7322a7c3eecdf3237a4a419cf41d2eaad8e006ce7dfdd9d4c8fa2eb/charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:51cf45226a9b588d0d2b4880c62d686934b63ab0bd79ca23ab0e9762eb27441b", size = 262716, upload-time = "2026-09-30T04:38:19.214Z" }, + { url = "https://files.pythonhosted.org/packages/a0/16/0e4c6ba9b44e97a2da150e52d331e8f9c968b21b358fbffa6c856cebcd89/charset_normalizer-3.5.2-cp315-cp315t-win32.whl", hash = "sha256:5fb29fb8cd1a46c27a1bf9613ad5ec2599310d46b4025d9556404a6b6a292800", size = 197159, upload-time = "2026-09-30T04:38:21.037Z" }, + { url = "https://files.pythonhosted.org/packages/be/33/e90bc2b1374f7f36ef106f56620de5a783907e19ca857efe2277e31cac3e/charset_normalizer-3.5.2-cp315-cp315t-win_amd64.whl", hash = "sha256:a192e2c40070d92c3ccf777e3a5c4ff515573cd2bb7ed0c537fdadbbec5bbf21", size = 221322, upload-time = "2026-09-30T04:38:22.886Z" }, + { url = "https://files.pythonhosted.org/packages/66/89/dfa6dcb08c200b7830ab56439e8c1890f2971d51aafbb3937894a2e7fcfc/charset_normalizer-3.5.2-cp315-cp315t-win_arm64.whl", hash = "sha256:749e97e1b32313717a565abbe321bc2190bc8b35f1a67e4cdbc7c56c8d8ffe58", size = 209192, upload-time = "2026-09-30T04:38:24.648Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ab/176fbfd5b64939c55d652366aa5b9ef1d767af207a3aa6ebeb0d226c484d/charset_normalizer-3.5.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:4275811936e2f06feff5e598fb42a1b7ae852da8e39605211892b56b81a34efd", size = 331815, upload-time = "2026-09-30T04:38:26.216Z" }, + { url = "https://files.pythonhosted.org/packages/7e/84/371eac6b30bdbcbf2d632a1a01809103459216fcaae61b8b8d922c1bfb8a/charset_normalizer-3.5.2-cp37-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1c50fe28bbc2ced33386f298650d91218076c05420e6cbd790b913adc41659e7", size = 253276, upload-time = "2026-09-30T04:38:28.032Z" }, + { url = "https://files.pythonhosted.org/packages/43/6f/c4fbae58febff71709c51bc7e18fdfa55341dc382704740f9f0cbf03817b/charset_normalizer-3.5.2-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d19fbd981a488e22cd04883659ca6b08f50b5974f9fd7c95655ef6a043e5893f", size = 241239, upload-time = "2026-09-30T04:38:29.732Z" }, + { url = "https://files.pythonhosted.org/packages/61/71/458c3f42164a07d0c5210798e9e704b39e540a6793b05aba67f3a35243a9/charset_normalizer-3.5.2-cp37-abi3-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0fed1d06615f022ee3b13caf5e8b180cfea32bb2c5aded8a9d44277afc040f93", size = 231121, upload-time = "2026-09-30T04:38:31.462Z" }, + { url = "https://files.pythonhosted.org/packages/09/54/ab9e89367076f6331bb6c65c4bf14a5361fa5191cb6561bf534f18504e1b/charset_normalizer-3.5.2-cp37-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:838dcc90063569a0448120554591a1d6c4a4ffe11babf048908793154ab86ade", size = 260350, upload-time = "2026-09-30T04:38:33.239Z" }, + { url = "https://files.pythonhosted.org/packages/7c/c1/061431ecc688d9d76602502cb57cc01e691e682c18f1beb45f9673b5bbd2/charset_normalizer-3.5.2-cp37-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2ce45c6627b22c47e390bc91a41c3d13032192e699fa0bea96e9671b373d69b0", size = 255430, upload-time = "2026-09-30T04:38:34.865Z" }, + { url = "https://files.pythonhosted.org/packages/8d/1f/20c8949f0676f7ab811abdeb7f4d7f1cbc6e61ff20bef08b44edeb092bc8/charset_normalizer-3.5.2-cp37-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0774bf9bf620249fee3e0b8b9fd3065de213be30f3aa94ce2494b3b638949e26", size = 250612, upload-time = "2026-09-30T04:38:36.649Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9e/46f2fa4c431fc98c4ae76a8cb5bdca54e0341e3cfc3fcfd8e82740250818/charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1db38f4c5496827c1a501846d64d14c3b80c7e6714e406cd7dc36a9899fa1011", size = 242083, upload-time = "2026-09-30T04:38:38.26Z" }, + { url = "https://files.pythonhosted.org/packages/bd/39/559be29a0c0f086e0bba6922babd38916cc5e0b58ced4de13ee01ea05508/charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:304d8e4d493af723536393eee0c689eb7813f4a474c8b479dee63f1fdd98f621", size = 232738, upload-time = "2026-09-30T04:38:39.81Z" }, + { url = "https://files.pythonhosted.org/packages/ff/6c/387b0e4f756a282831c1d9fc6aeb6c51ca4507ca202767c8de15ce9b12e2/charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:9b7f416ff0978e2f2249330527f0ad6fa02f4932e6199692d3b52da2048c19e4", size = 260703, upload-time = "2026-09-30T04:38:41.346Z" }, + { url = "https://files.pythonhosted.org/packages/96/92/1fdf015f09ef449f50d3ac4b67c90887c9c318b727daa95cc4f866e6521d/charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:01077390b03f7988f11d700a2194e69b119741a86b1a638b1db88891e3eced8e", size = 247622, upload-time = "2026-09-30T04:38:42.937Z" }, + { url = "https://files.pythonhosted.org/packages/dc/3c/8e7b8a5671ad5d433669fb2a76f1a0164df2d9b1718b0206bc2a16d840cc/charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_s390x.whl", hash = "sha256:7e841fb9010836c992c9f12fcbd43a831de93a5f726fc1ccd8ca1d0268c5014c", size = 257500, upload-time = "2026-09-30T04:38:44.604Z" }, + { url = "https://files.pythonhosted.org/packages/b4/f0/45b579df5cabc1d5d53ea1cc35e8437d3ca768c0acccc7041517cb6fbb32/charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9cae88599c7219005d879f98e5ed53341e9a122af585e1091200358a3003d2a0", size = 255100, upload-time = "2026-09-30T04:38:46.289Z" }, + { url = "https://files.pythonhosted.org/packages/31/68/fdec18a343f5fb3f310588dd478b09ac4799e0b187dbade3a8cd776f03ef/charset_normalizer-3.5.2-cp37-abi3-win32.whl", hash = "sha256:01b0c0d2262a9e28e8484a278c7e1b5d650e3ac8cf2683d2967e25899f208bdf", size = 174499, upload-time = "2026-09-30T04:38:47.999Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8a/b618149cc5207943a0242068d7a27897f56a62947b5a039085f2a22029f8/charset_normalizer-3.5.2-cp37-abi3-win_amd64.whl", hash = "sha256:9f56f72050826f63dcee7a7f55b0a77168cb3bfc553fd405e7f8f9ece75a4036", size = 200092, upload-time = "2026-09-30T04:38:49.707Z" }, + { url = "https://files.pythonhosted.org/packages/03/cf/4c66866fa9e2b1c78e3c911516d1de497a677b7ac60f1eceda74ce777ca3/charset_normalizer-3.5.2-cp37-abi3-win_arm64.whl", hash = "sha256:40ab6bffa02ae10a0581e6c198be7d2d8ca5c2a0c64e4ed3465d766df457573e", size = 294363, upload-time = "2026-09-30T04:38:51.312Z" }, + { url = "https://files.pythonhosted.org/packages/fc/ad/d07d7862a62ffa6d79d68074d14823243dd235a77c45262acbf6adeb28bf/charset_normalizer-3.5.2-py3-none-any.whl", hash = "sha256:b6b751274acb69d77b3323d6b7dbaa3c7fdfc1eb829b7eb61d262f32e1af9685", size = 68872, upload-time = "2026-09-30T04:39:21.828Z" }, +] + +[[package]] +name = "click" +version = "8.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/0e/7fa0ef50764b67090eca4114772a2abf8b6148198475e54c660b97caeee6/click-8.5.0.tar.gz", hash = "sha256:ba0d2089de75ea0310e2dde03160e6ca10009947fb95a182f9b54021bb272e34", size = 382235, upload-time = "2026-08-26T13:33:14.56Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl", hash = "sha256:255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360", size = 125251, upload-time = "2026-08-26T13:33:12.928Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "dnspython" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, +] + +[[package]] +name = "docutils" +version = "0.21.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444, upload-time = "2024-04-23T18:57:18.24Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" }, +] + +[[package]] +name = "docutils" +version = "0.22.4" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.12'", + "python_full_version == '3.11.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/b6/03bb70946330e88ffec97aefd3ea75ba575cb2e762061e0e62a213befee8/docutils-0.22.4.tar.gz", hash = "sha256:4db53b1fde9abecbb74d91230d32ab626d94f6badfc575d6db9194a49df29968", size = 2291750, upload-time = "2025-12-18T19:00:26.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl", hash = "sha256:d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de", size = 633196, upload-time = "2025-12-18T19:00:18.077Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, +] + +[[package]] +name = "furo" +version = "2025.12.19" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "accessible-pygments" }, + { name = "beautifulsoup4" }, + { name = "pygments" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "sphinx-basic-ng" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ec/20/5f5ad4da6a5a27c80f2ed2ee9aee3f9e36c66e56e21c00fde467b2f8f88f/furo-2025.12.19.tar.gz", hash = "sha256:188d1f942037d8b37cd3985b955839fea62baa1730087dc29d157677c857e2a7", size = 1661473, upload-time = "2025-12-19T17:34:40.889Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/b2/50e9b292b5cac13e9e81272c7171301abc753a60460d21505b606e15cf21/furo-2025.12.19-py3-none-any.whl", hash = "sha256:bb0ead5309f9500130665a26bee87693c41ce4dbdff864dbfb6b0dae4673d24f", size = 339262, upload-time = "2025-12-19T17:34:38.905Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "idna" +version = "3.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/08/8eea9d4b8302028f3abb2c0813953f7aec26d33b7a8960ed760e65ff29fa/idna-3.20.tar.gz", hash = "sha256:a7db850025b95ded1eae8a46181a1a6c56c92c96f0e2b005d9ff8dc0210cab44", size = 216463, upload-time = "2026-09-17T14:11:04.752Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl", hash = "sha256:ab7ae7122974553370f0bdb919e1a960b2cd1bc1ef0276416d896db81c14582c", size = 69583, upload-time = "2026-09-17T14:11:03.168Z" }, +] + +[[package]] +name = "imagesize" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fb/5e/513ff06670c84e7b9887c1fdf61b2d42b4f574a831f2f1d2222023049d8a/imagesize-2.0.1.tar.gz", hash = "sha256:b2ba6a4dea487a7ebcd53248d3476aca449d30db12a2dde5e0c5ca9624fd77e5", size = 1883774, upload-time = "2026-08-24T12:35:19.13Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/f9/575c8d760eae1fc99651b7cc5efd96ad5379ca4d6b53750b0fb4fe983f34/imagesize-2.0.1-py3-none-any.whl", hash = "sha256:ea0c9a0384df69ed86a943a15cde37d0360b82491b3910dc2215e202e62b5b02", size = 14794, upload-time = "2026-08-24T12:35:12.548Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "jsonschema-rs" +version = "0.52.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e6/48/771a96c524eafadcd2366271c13bd6e5b79af9032821f11e22846d36da3f/jsonschema_rs-0.52.1.tar.gz", hash = "sha256:25ec1da52bc1c11c012e17a01b97e24d33a15d1d76c705fd5a7c276d1bbe7677", size = 2631333, upload-time = "2026-08-30T09:52:05.865Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/37/92f23a0e53b6448faaae98ea4896f549c104cea8c07b8d213a22b2fb84dd/jsonschema_rs-0.52.1-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:cf728999f2cf4fb4fba8abf8d5a110565f716f4a460f13157de59e836c03706d", size = 10119218, upload-time = "2026-08-30T09:51:25.959Z" }, + { url = "https://files.pythonhosted.org/packages/71/3e/52261a693a148d8746db1ff67591e9e9f4b56b155be3d48840f7e5cbab58/jsonschema_rs-0.52.1-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:d32934b6a3032e968e59bb172addb8e752d7fdbff742834390f87549889c86db", size = 5277560, upload-time = "2026-08-30T09:51:28.055Z" }, + { url = "https://files.pythonhosted.org/packages/82/07/94db20d60141955d1987b73bcae8fdd3db6cfdf7ef4ad68fb9b399cd436d/jsonschema_rs-0.52.1-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5eb2562cca5effc43134c4f8d2ba0c2b04b97c7cfcb6ac27997f0a5b2aab662f", size = 5179470, upload-time = "2026-08-30T09:51:29.328Z" }, + { url = "https://files.pythonhosted.org/packages/5f/5d/cd7ab77544d6a8fad152c0ec1c332de1506da1c753475357fbfbf5ed91a2/jsonschema_rs-0.52.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:150845b65c701d5db2a397c97beb98356123548b29c70095ec9a851a611cc736", size = 5418427, upload-time = "2026-08-30T09:51:30.682Z" }, + { url = "https://files.pythonhosted.org/packages/ac/30/8b3d95e7be67daa93996a1444ca2238bdfcb58debf8bccf6469b5f183dc8/jsonschema_rs-0.52.1-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:895e7ec4c6e7ff564786f86e197c95d15017a42177523319bd45ede20e4c4417", size = 4999697, upload-time = "2026-08-30T09:51:31.998Z" }, + { url = "https://files.pythonhosted.org/packages/c7/24/001bb2ee8ca4ba19a7e31daad391de8e10f554a4f8c8396f83775eb585fa/jsonschema_rs-0.52.1-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4b05b745f05859ca8b2d056e22a3fae036e922a61805680cbe77cac31141be2e", size = 5185040, upload-time = "2026-08-30T09:51:33.943Z" }, + { url = "https://files.pythonhosted.org/packages/f8/84/50cd77eb2d1763625e8b394d5da6ffebcb148f71f4350b7bf3872ba25996/jsonschema_rs-0.52.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f709d4666f7fc728829503ff653c8a578634ab1ed54e9f11097da89dd18baf75", size = 5658962, upload-time = "2026-08-30T09:51:35.305Z" }, + { url = "https://files.pythonhosted.org/packages/02/5d/a588c8fc4d3f9fc06e222d35003c9c60a28bbcc492c49f273e19fa205ef8/jsonschema_rs-0.52.1-cp310-abi3-win32.whl", hash = "sha256:9131e083499ea49157e559dff813215f3ed116ed3a2996b108fed2faf1b80c0a", size = 4613745, upload-time = "2026-08-30T09:51:36.776Z" }, + { url = "https://files.pythonhosted.org/packages/1d/64/6b08a726984c8a3eb648cc516efa5bf20d218f6c26b912ffc126746c8147/jsonschema_rs-0.52.1-cp310-abi3-win_amd64.whl", hash = "sha256:3c9152a9aaec6a656b89fa203ccc26de54065e26cf6785378d54b6390ad403f2", size = 5340066, upload-time = "2026-08-30T09:51:38.183Z" }, + { url = "https://files.pythonhosted.org/packages/2d/b8/7873aad3d4eaa3f82ef32222760c5ed36fc379537045e5c413e026dbccdf/jsonschema_rs-0.52.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:ef551bc76041b967df43897d4397ba69dd7fb934a7579b86c3d071d6aa9cdaad", size = 5290294, upload-time = "2026-08-30T09:51:39.49Z" }, + { url = "https://files.pythonhosted.org/packages/fc/cb/389eebcabec9aae49047c0804c006980ece69d0ca8fe0bf8627bd577ee89/jsonschema_rs-0.52.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2bb49b9c0bf481d61d26f75f9b8504c916402ad0ebd4e4c80bb7b27321192dd7", size = 4880026, upload-time = "2026-08-30T09:51:41.55Z" }, + { url = "https://files.pythonhosted.org/packages/1d/17/f4052898e6ec5abb4c51ad00807fb2664ecb627fe92caacd7bd178d0aff2/jsonschema_rs-0.52.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1e027ee48f79b508c34c91a0b2f0072736f0a5994ff8ba8b36c6ed17f461713", size = 5414218, upload-time = "2026-08-30T09:51:43.456Z" }, + { url = "https://files.pythonhosted.org/packages/be/ee/c0af76c0e96262dd04b332a3c47c1df22fa0efe59d61d6faef6fa3702d02/jsonschema_rs-0.52.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:df29b238aa0a99c9cd2c7d4e7e1db39317661806fa9253c22dbc82f6cf5905d6", size = 4994321, upload-time = "2026-08-30T09:51:44.966Z" }, + { url = "https://files.pythonhosted.org/packages/86/d5/94cc7a8c9617345ca1a251173423bbcf713632817821f202a01e439428f6/jsonschema_rs-0.52.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ef3fd0424418f33adc1dfbb8edd76b64d46d45711c64135b07f871ec995ba4ff", size = 5180550, upload-time = "2026-08-30T09:51:46.404Z" }, + { url = "https://files.pythonhosted.org/packages/c1/72/4cce201f45fc18db2bccf373d6a3b194d9b9c8d47829812a25acc7563eb2/jsonschema_rs-0.52.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3bc356e00da14e4c02d273c72c228e863daba83340d11af99f78ec906f8b5480", size = 5654620, upload-time = "2026-08-30T09:51:48.046Z" }, + { url = "https://files.pythonhosted.org/packages/1f/66/42d21d3c5f6cc79d11602abf68f348d982fce4ac16aa0c05fd1bee1a07af/jsonschema_rs-0.52.1-cp314-cp314t-win_amd64.whl", hash = "sha256:eed1ab32e1398d9a30311abf7d00c45f8ff29b7998bcfca9dfabb82f27ba8f9e", size = 5332161, upload-time = "2026-08-30T09:51:49.392Z" }, + { url = "https://files.pythonhosted.org/packages/c9/00/dee569ee080dbee68b3bc2abe2c894313feeb6da6b8221b5f3d82caea157/jsonschema_rs-0.52.1-cp315-cp315t-macosx_10_12_x86_64.whl", hash = "sha256:e105518e7109bbec7732bad34caa41dc9497f5060f0b77a5ab3d74b0c00ae32f", size = 5290342, upload-time = "2026-08-30T09:51:50.671Z" }, + { url = "https://files.pythonhosted.org/packages/97/57/ad36a8f91d14885f73212b0ec8146baff6aa82f9e5cfa0d36b3dfbb8023f/jsonschema_rs-0.52.1-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:4390738c2f21829ec4df80e3496017bd80ab2fff9e6cf8d44518cf8e5dbcbb9e", size = 4879978, upload-time = "2026-08-30T09:51:52.012Z" }, + { url = "https://files.pythonhosted.org/packages/ac/82/db133f9ab014be784f2c76afbee10369df2ecc800dbb99e19c64486339e2/jsonschema_rs-0.52.1-cp315-cp315t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca97d13103d4ea0f04c89bf7f002008398b62ca898cdaf0ed91159e8350b95d4", size = 5413831, upload-time = "2026-08-30T09:51:53.339Z" }, + { url = "https://files.pythonhosted.org/packages/56/47/f5bc417b69cd260e85772226f6e32fbd006fd7e25f43862571ca800d7f88/jsonschema_rs-0.52.1-cp315-cp315t-manylinux_2_28_aarch64.whl", hash = "sha256:4a6839c4f35038ac3aa8108265287080fd2a6d3afef3977b337d0f964e820b7b", size = 4996153, upload-time = "2026-08-30T09:51:54.568Z" }, + { url = "https://files.pythonhosted.org/packages/2e/2b/c21c2bb559174a2a9c057de5b58955d4a924a5932577e8538417dc0ad209/jsonschema_rs-0.52.1-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:6e14a84fca6a38c7a141843552c57854bb2b0e2b43bb35f7de0223f8f5061faf", size = 5180115, upload-time = "2026-08-30T09:51:55.864Z" }, + { url = "https://files.pythonhosted.org/packages/e5/00/8bd6e291d170ddbc12ff7537eafaca99607ebca651ebec9951c8be798962/jsonschema_rs-0.52.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:980031eedb20ec294f58f0983ee51af442e5a110860e428fbe1ef7c4fe4b1cc9", size = 5654796, upload-time = "2026-08-30T09:51:57.347Z" }, + { url = "https://files.pythonhosted.org/packages/a6/61/5ee246b16b35a122bc44b91a44aa7cdf1c2b5bb426fe3139433df1102d38/jsonschema_rs-0.52.1-cp315-cp315t-win_amd64.whl", hash = "sha256:c5b9cfca088a8fef45f49c02d08dff63154cc129ead1dd71297d17fccf4df777", size = 5332439, upload-time = "2026-08-30T09:51:58.706Z" }, + { url = "https://files.pythonhosted.org/packages/19/ec/84c414f43e0eba6f2ce3af54e48ba94f0502dc8c61229577d44aec85b17c/jsonschema_rs-0.52.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:697274ecdf0ba51b8efda17d0a53b7e7bead7e1eb3c3bc0a158bc3e5b02959c8", size = 5280272, upload-time = "2026-08-30T09:52:00.275Z" }, + { url = "https://files.pythonhosted.org/packages/24/19/a2a852f170063bb89cb9cf1b116b665d027998782193d0ae26eb669701e9/jsonschema_rs-0.52.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fdd5bb2f104366294dda7b7cecf3978c4bb163cb451d87fe8c0c9699ab605ba", size = 5420004, upload-time = "2026-08-30T09:52:01.593Z" }, + { url = "https://files.pythonhosted.org/packages/74/88/345e6e64f144c2e1602d0eb42c67a9fe5e3b1962f15cfe7b7970b78e3db2/jsonschema_rs-0.52.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:6670f476f98ab8a5949989d85b215ce0f8776c2bda9b0f7ff62c2d4781bc87c7", size = 5000920, upload-time = "2026-08-30T09:52:02.989Z" }, + { url = "https://files.pythonhosted.org/packages/72/0a/ddf9c416a4bfb2b6f20842e8e77b72d332b0ff70f58e5dd2698310f346f9/jsonschema_rs-0.52.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:89f603cb5db7c5d28fb3254f0649e7fcfd9e4ecce30b0cac78acf3d2efb1d9fc", size = 5342280, upload-time = "2026-08-30T09:52:04.58Z" }, +] + +[[package]] +name = "linkchecker" +version = "10.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "dnspython" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6e/60/1ad47dd9db638546c4e70b49b5adfddfaadb2c6669a1a9b06a4dcf140d7b/LinkChecker-10.6.0.tar.gz", hash = "sha256:fb7e8facda7749c2fa5fa5dc241c0adc302da3d31d588964a2570db501aa49e5", size = 547746, upload-time = "2025-07-28T18:43:50.884Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/07/ff8a29330fa35483a19221fd89e102e7ebf700acda8f0ba0b66ef14bcd48/LinkChecker-10.6.0-py3-none-any.whl", hash = "sha256:5268587ed0b0f7e7521b75905128c96856f30f67dad49f66e2c963bc174ca92d", size = 280937, upload-time = "2025-07-28T18:43:48.932Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/38/9b/e422a865e1d5d57d0e509b4e0bf1c1a70a7f6382c29a5aa428df994c8bc8/markupsafe-3.0.4.tar.gz", hash = "sha256:2e9ad7dd851bf45fab9f75cbff4cb493fee9979e8d8c7c9c3ee119022518edd6", size = 153777, upload-time = "2026-10-02T23:07:22.29Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/aa/9a65962e364bf19745f6bec7bde398fb1f5ca53ad2e734258e6198cc32ba/markupsafe-3.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd8ea6ebee7aedbf7c749fa80521d9ccf1ba473e0d1e14805caafbaad281c889", size = 11521, upload-time = "2026-10-02T23:04:20.141Z" }, + { url = "https://files.pythonhosted.org/packages/14/36/927999a34b7d1def6957de89153d327fedc4030061940b5a468584e6c5a8/markupsafe-3.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dff05cb7016dff1e9fd68f4122c127b65dfc59de5306cfb7ad92f956f230bee2", size = 12066, upload-time = "2026-10-02T23:04:21.275Z" }, + { url = "https://files.pythonhosted.org/packages/17/54/69e7b0db9bd687bfd83451eed5666384d67cfed3be062bfc59a06a15474e/markupsafe-3.0.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cf63c214fe879a65e69a386f915e36104fc84254ab141240f8854602d8e0be2a", size = 22081, upload-time = "2026-10-02T23:04:22.221Z" }, + { url = "https://files.pythonhosted.org/packages/bd/14/f6f5c97903f7d2db76bbfaced31509a47d360a103b3aaf4849f6536591ec/markupsafe-3.0.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2a6ef68ae94aed8721934072b27a3b654ea2100b97e4ab864cf1489c90926fbc", size = 26079, upload-time = "2026-10-02T23:04:23.346Z" }, + { url = "https://files.pythonhosted.org/packages/d0/04/c3cc9b75f94f8b54d7e503c44cebd4b4a115ec1d6f1b996b999807daba99/markupsafe-3.0.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd9f8797427910198f95bced71ddfed61130d7e349213bfb8466c9c99e2c46a8", size = 22611, upload-time = "2026-10-02T23:04:24.401Z" }, + { url = "https://files.pythonhosted.org/packages/00/26/c4708ed3b0f08e8e6d7cbce3314ac130cb5352d1f62951b6fef7878f2b1e/markupsafe-3.0.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1aca03ede943eb80ab3d63bb082c84b7aab85ea83bd0fd0c200260945fb49d9", size = 20712, upload-time = "2026-10-02T23:04:25.386Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b9/f3894d6aae3d7a52c9363317f4baf2fcadc052163d6dbc871266e32639ed/markupsafe-3.0.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0764a13d34cae40db7bbf3a09b7e9b491bf4603e20b263a7a9d6b8e324975d0a", size = 20742, upload-time = "2026-10-02T23:04:26.403Z" }, + { url = "https://files.pythonhosted.org/packages/59/7c/8e248ddbfe286ab6bddb462bdac0851cbb1510d2cbbb815a415fcb0511af/markupsafe-3.0.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9388003072b95f2f1e3fd908604194d653ba21330d811961a78b7da1a77e9e36", size = 21560, upload-time = "2026-10-02T23:04:27.522Z" }, + { url = "https://files.pythonhosted.org/packages/df/26/2353fef7d4bcf2b18e16bad81979fcecff2915156ca6882447917205b8e2/markupsafe-3.0.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:8698d70a8081ee8c090dbb394768b5789a1da8b131b5499f89d071dd3cfaf6be", size = 20973, upload-time = "2026-10-02T23:04:28.573Z" }, + { url = "https://files.pythonhosted.org/packages/67/6f/a9561d98d9a6ee3494b0b970a1c766e58bab128cc84841d56ec009456dbd/markupsafe-3.0.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf053da3c97a4bc5ecfbb218cdd2983febd91c617be8367d139882aa11e490aa", size = 22036, upload-time = "2026-10-02T23:04:29.568Z" }, + { url = "https://files.pythonhosted.org/packages/55/83/6217df9192eca95af3ff0cad955c9854a93fa43b288cf7411ae24713eb52/markupsafe-3.0.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:9438a2648b2195980cb2dd8e53ed7b8df91319e2d0b70ae61a9e1d1bc8d3bec9", size = 20314, upload-time = "2026-10-02T23:04:30.881Z" }, + { url = "https://files.pythonhosted.org/packages/35/7c/9cd8081dae70e17fdab3558121fa618d459c7950c8abd8fc10fc024486d7/markupsafe-3.0.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:88d59b473bfb03259722600839af9bbd7fa13a2eb514beefeedb95997882f69a", size = 20780, upload-time = "2026-10-02T23:04:31.975Z" }, + { url = "https://files.pythonhosted.org/packages/44/37/c5f2f45f4d8f0c24e4af7b9dc711640c888044cbf5f7e2ba2c0bb74cbb55/markupsafe-3.0.4-cp310-cp310-win32.whl", hash = "sha256:4a540e2d3192792fc84eced57bef37851ccb2b41f73291bb17408eea77bcd278", size = 14096, upload-time = "2026-10-02T23:04:33.129Z" }, + { url = "https://files.pythonhosted.org/packages/50/50/394a1c61c9b9972cb4f76875c332af7109bd39bdad09d3a0ec5327a339dc/markupsafe-3.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:5c22873ad1f0532ba40fa1727f3c0fc1bbbaab6d373d4cbe3f0dc74b2e2521c7", size = 14329, upload-time = "2026-10-02T23:04:34.168Z" }, + { url = "https://files.pythonhosted.org/packages/d1/9a/86d03d2f32ba41a57baa124a7bcb76d0a6d39b1622e9bd4d550074e8b61a/markupsafe-3.0.4-cp310-cp310-win_arm64.whl", hash = "sha256:3d23795802fc8bd72534836d64489bbf0f67c088959091bdb22e10735a5107bf", size = 14196, upload-time = "2026-10-02T23:04:35.201Z" }, + { url = "https://files.pythonhosted.org/packages/32/55/18dbb4778b30ada5ce071608503cc3edc9e14e13d868c17a6d178fc30f7a/markupsafe-3.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e25feb9e330b63edb0278a0acdf85e50d0cb0fbf49c3084abbe4e24ae195346", size = 11520, upload-time = "2026-10-02T23:04:36.299Z" }, + { url = "https://files.pythonhosted.org/packages/6c/14/0b05f79b4733e264a18d08fe08fa1df7347630ff32a6cb82180d9dccec55/markupsafe-3.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7d3391b2188d18737cb2fa147028b1096236eaa7e156446c650a489fa2cadc91", size = 12063, upload-time = "2026-10-02T23:04:37.291Z" }, + { url = "https://files.pythonhosted.org/packages/ca/3a/63ba10b6c1463216b3e4df669a9f0e5a3b0c3071557d2e8229e3968c79fb/markupsafe-3.0.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:849dd2bb0e5e4ab2b71c7191726a4a8d5aa8a610daa584728cbee0b710ddc4ef", size = 24321, upload-time = "2026-10-02T23:04:38.262Z" }, + { url = "https://files.pythonhosted.org/packages/1a/2e/5f015261b76ad633d187ef6f388b413aedd64a8773c4df59e530a0be5525/markupsafe-3.0.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:befb4158af32106b9a93db8d6d1d1cbbd418c0d5aca0cabb7b1780abf0c89169", size = 28845, upload-time = "2026-10-02T23:04:39.295Z" }, + { url = "https://files.pythonhosted.org/packages/33/cf/26e594b26be40c2f1fec63ccf8a8b99d0335a5b2cbe84835c7d82a994375/markupsafe-3.0.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:71f88e749ea29f67f21f3b36433c1dc54c7729ed2a6d9e2da2e0d9e0d7b224eb", size = 24701, upload-time = "2026-10-02T23:04:40.348Z" }, + { url = "https://files.pythonhosted.org/packages/81/a5/a513b76c139a3915b43404324e55c0b7979ae4f0d39eb6f075b0282e90a8/markupsafe-3.0.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6da83a088f8ef93b2d483a8232a4dbf4d69d3d8496b568a03c56becac43e1808", size = 22961, upload-time = "2026-10-02T23:04:41.372Z" }, + { url = "https://files.pythonhosted.org/packages/46/cf/4c66192c100b4542bcbe392ae06696b670f66927be3ac38a213234778ff9/markupsafe-3.0.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8f0fac8b13d14bb06c68195f849371924ae53dd7b1c00fed24650f704383b692", size = 21920, upload-time = "2026-10-02T23:04:42.429Z" }, + { url = "https://files.pythonhosted.org/packages/cb/17/ac3662678bfbad649893117ada2ba44dc30bf56884e84f13154a792b10f1/markupsafe-3.0.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4a7cdc2a420ca01058182da4253329764d4bfa055564d1eced90e6ba1e8b1d3d", size = 23726, upload-time = "2026-10-02T23:04:43.531Z" }, + { url = "https://files.pythonhosted.org/packages/f7/af/fe47cee339180a69ebca3c57fb3483d0f5cbd1e8337d1871fb1d9c1aebee/markupsafe-3.0.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:83b3944fea42a8400edf92fd1770fb8d0d4f7de651353bd2d8525a92dba69a21", size = 22539, upload-time = "2026-10-02T23:04:44.618Z" }, + { url = "https://files.pythonhosted.org/packages/12/32/d55440ba140442800e02d799c9cb5ab597bf6ebdb1177b5ea39a11f797bd/markupsafe-3.0.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8138eb83940ec7299024d92d4dee45f601b9e6c5ffde9d25f4e35e326203c707", size = 23963, upload-time = "2026-10-02T23:04:45.656Z" }, + { url = "https://files.pythonhosted.org/packages/50/9d/9c86042cb364c2ad4c971e6d1247929effd25f714cd7ee11b05e6316445b/markupsafe-3.0.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:811d02d5122171c1941357efd8f9bf4ffe907b7f0a1a4e729a880e4be3f46e3e", size = 21506, upload-time = "2026-10-02T23:04:46.671Z" }, + { url = "https://files.pythonhosted.org/packages/75/ef/5b824f03ba40c3b3652b6272d083d2fc4fcdd440de519a3a39ba2c3e7262/markupsafe-3.0.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:50b5bedc9ed8a94fc8857a42ef4f84a81ea88f8d4f05dc8705fb23ee6d8dcca7", size = 22955, upload-time = "2026-10-02T23:04:47.698Z" }, + { url = "https://files.pythonhosted.org/packages/1e/e8/44cfcb5ea40e5e43cec7793ef90704ed0c475280839076c4345757eb8e59/markupsafe-3.0.4-cp311-cp311-win32.whl", hash = "sha256:2e5a7cd7fdd14fcb1ae5d7d8bf23d24fbd1daefd1fbca2580132e1ea75f098b5", size = 14094, upload-time = "2026-10-02T23:04:48.788Z" }, + { url = "https://files.pythonhosted.org/packages/91/89/f2b509f7bf79352e40117824c1070dbeafd4df67031d3fa98165a3134228/markupsafe-3.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:fdb4ca07ab75ffadab4a8b135ad59cdbb3156b99310f3d565370da74a15d6bd3", size = 14328, upload-time = "2026-10-02T23:04:49.801Z" }, + { url = "https://files.pythonhosted.org/packages/2b/5a/ccf22672a0f64dc682306e288f0dabcb06c7a201f3bb6e6cbf86d9e8ad03/markupsafe-3.0.4-cp311-cp311-win_arm64.whl", hash = "sha256:569d65055d367e3dcdf30c3f41119467b73d9ee9faf332bdf40402644f5ac08e", size = 14188, upload-time = "2026-10-02T23:04:50.847Z" }, + { url = "https://files.pythonhosted.org/packages/81/09/4c59d56b8461ae8eb0d8ba34bb25b7e618547044679d58a82ef9b2479fc1/markupsafe-3.0.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:61631e08084be9e21a8967ec3139c7616ed7c5e9368e05c86d1b39562c8a57b6", size = 11658, upload-time = "2026-10-02T23:04:51.876Z" }, + { url = "https://files.pythonhosted.org/packages/a2/f0/d6613774d86fbf6d145751d43c59875e47a6f9f17daee0aef173bd36d90e/markupsafe-3.0.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0930db9bdc62d22944e10b066448bb65dc9abe9112880c7cab8da54db4284d5f", size = 12050, upload-time = "2026-10-02T23:04:52.931Z" }, + { url = "https://files.pythonhosted.org/packages/0d/f2/8f18e0b806eb13c1f8d07d917a720831ead54253a6dec011fbc78098a6f8/markupsafe-3.0.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6a45c3d514f2436064db00d7fc8778d888f0236ebfed649b53d13a59e69ad51b", size = 24363, upload-time = "2026-10-02T23:04:53.895Z" }, + { url = "https://files.pythonhosted.org/packages/60/ce/fa07dbe8a5675558fa36dea033e19995bc783de2dec5f540ccb9030b06aa/markupsafe-3.0.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1e1451fab512d1bcc3dc26988ec1edb0b82c2db909132872cd9356070a6b63df", size = 28525, upload-time = "2026-10-02T23:04:54.905Z" }, + { url = "https://files.pythonhosted.org/packages/85/40/be87c01f3868ec217f8a2015089d71c22c8c5a75324822e5ed1cdd87210d/markupsafe-3.0.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bd3ce56ae2cbae3ba82b683bc425cd7e48d2ed8b10f3e818186b6f5646d9271c", size = 24733, upload-time = "2026-10-02T23:04:56.229Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a7/aeedb5140afa41fc74c225e9184ab96723a6e873b6ee1c9fede7283456d8/markupsafe-3.0.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e124f974786f831d6043728e38296969d3579db8896fe004682f5758e613581", size = 22985, upload-time = "2026-10-02T23:04:57.521Z" }, + { url = "https://files.pythonhosted.org/packages/c3/fc/e91352bb08c6a59da3ef0909d457bf95a5f5908fbf151b30a06d9dbcfbb4/markupsafe-3.0.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c02e8f18bdedba082cef725942ac823b9b60656db07f7e265cb31618dfd00d77", size = 22001, upload-time = "2026-10-02T23:04:58.597Z" }, + { url = "https://files.pythonhosted.org/packages/5d/f8/bffee5e7d2a3deb59748a797650a48af7e672025cf641a79344a771ad106/markupsafe-3.0.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9f098115c247e11d138ab83a28fa0323c77015007ea2df73ba5fd714dfefd67c", size = 23793, upload-time = "2026-10-02T23:04:59.686Z" }, + { url = "https://files.pythonhosted.org/packages/ed/59/b853d6628ecb4d658e1d637224846d5e9bb4adf4f8df97f3be9f29dce2ec/markupsafe-3.0.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d5f93ebbeb8032d47e349328ec8662d973d9b05a70b3c35df1f91fe419b84749", size = 22640, upload-time = "2026-10-02T23:05:00.768Z" }, + { url = "https://files.pythonhosted.org/packages/09/b2/1506df394f0f075797c418d0301498f49e43be194e3ffcb49e6fe6ccf022/markupsafe-3.0.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:64511c54db4e4987aef4c41923235927428729e8174c5dba488429be70a998ed", size = 24074, upload-time = "2026-10-02T23:05:01.813Z" }, + { url = "https://files.pythonhosted.org/packages/c7/81/5ed69cda630ac69ef60d06c09ba5a7f84ff66a2e28cf986fd5614ab3c6e6/markupsafe-3.0.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e1a622f13970d81f95d0c72f9dc090dce9085fccfa4c9f2174377ee32bd15786", size = 21563, upload-time = "2026-10-02T23:05:03.239Z" }, + { url = "https://files.pythonhosted.org/packages/0c/fe/fb1e79be0fea60aa32602ebefc9c35a82bb42b4df157285ab7dfec12341a/markupsafe-3.0.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c9a7f43c0b202b334cc9184af09bb8f21d3a209e038efaf106936fb69e6b026e", size = 23048, upload-time = "2026-10-02T23:05:04.479Z" }, + { url = "https://files.pythonhosted.org/packages/c8/52/7632a53360671a9b750cdbabaf9cdd89f18b42248b8e4cb42c0b0296e459/markupsafe-3.0.4-cp312-cp312-win32.whl", hash = "sha256:f0ec3b750b59375eab5b0fb2b9254810c00a3375be6d789899f1055a1d556237", size = 14108, upload-time = "2026-10-02T23:05:05.513Z" }, + { url = "https://files.pythonhosted.org/packages/3f/bf/62495e180b7000aaf30000fff849e933f74264638057176cf46852500adc/markupsafe-3.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:11935df9bf455ed0c04eb87bcd720f02b1fe5e02128a9430f23aed6f93336fc7", size = 14303, upload-time = "2026-10-02T23:05:06.538Z" }, + { url = "https://files.pythonhosted.org/packages/c5/8e/4c24208776a65878d656996945aacfbfe010d3720d1a98fc0eb8491fc03b/markupsafe-3.0.4-cp312-cp312-win_arm64.whl", hash = "sha256:a4bbd2d87dd233b9fc5812160c3d0ffbe42edc22a26ce0469f58479ede633fe9", size = 14174, upload-time = "2026-10-02T23:05:07.617Z" }, + { url = "https://files.pythonhosted.org/packages/6d/18/4bc5ba32499e87bb2b0ef5b3a9bb9c00a131fa961ddf0be548cb550f548b/markupsafe-3.0.4-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:de8b364c423ef0a4bad9069657d617f9a5d2b2062457a89b1fa16ee199c399c1", size = 12786, upload-time = "2026-10-02T23:05:08.709Z" }, + { url = "https://files.pythonhosted.org/packages/4e/6f/17f0c099bf25f3e31e63cc19244d9f6af861a9a4ab778c203997903cfdd0/markupsafe-3.0.4-cp313-cp313-android_24_x86_64.whl", hash = "sha256:34bdde374c5932765d7dc685c4a1d191a3207852d67e8e0a9eb6ea85156181f1", size = 12510, upload-time = "2026-10-02T23:05:09.93Z" }, + { url = "https://files.pythonhosted.org/packages/11/af/1a141081b905036ee904ec4bd945e1f70b4e1b32d33c4e59e8cf1d58b247/markupsafe-3.0.4-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:6bd9e1788e15bfcf6a9082de42e30387e7b85d211ab21e57a939bb8cfaaf8d96", size = 11583, upload-time = "2026-10-02T23:05:10.884Z" }, + { url = "https://files.pythonhosted.org/packages/e7/0a/a89385ae590232622a03e091805cff12f24fabe6c11e0e8bae096cece81c/markupsafe-3.0.4-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:5066b244f576f91afc8ee3ba029a89f99d39c79b1853fe9d39bea9f0afbec148", size = 11801, upload-time = "2026-10-02T23:05:11.913Z" }, + { url = "https://files.pythonhosted.org/packages/ed/85/ea548dc013962eb73653124bc595635fbf9e0fa41d1f181a967ccb784dfb/markupsafe-3.0.4-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7a83aa6e4805df46fed18e989d3d16f86ef60cb50bbc8d9ce3a6be89165fbf6e", size = 11443, upload-time = "2026-10-02T23:05:12.887Z" }, + { url = "https://files.pythonhosted.org/packages/cc/72/15f2e5ec9cf2eb00d5cdfe968d94e4156a7bd7303832c3f3b2c403a36839/markupsafe-3.0.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2d1b7d9308288661f56672b1b157d75fc536714d3638487bbea17b6318a78248", size = 11665, upload-time = "2026-10-02T23:05:13.829Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e0/4030bea613677e333c8a2c901fd405055f657f9d06acba5b7357984b6ef7/markupsafe-3.0.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:73e77980c7207854f00fc4e71fb1626868d5740ab4012623d55c7a99ad122a72", size = 12061, upload-time = "2026-10-02T23:05:14.807Z" }, + { url = "https://files.pythonhosted.org/packages/f3/a5/28b76a7449eb702966b88bef599e2360b411fbb3afeee8fe560939be06ec/markupsafe-3.0.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7018d4af1cd272e847aa5917983ab5e83e4f6579f9dbfecd4a79c0ca80b144c2", size = 24395, upload-time = "2026-10-02T23:05:15.909Z" }, + { url = "https://files.pythonhosted.org/packages/07/6c/21232811afc3a063b5e934b1ae2efda52f46154ec382f585149c020e61fe/markupsafe-3.0.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c90d5b3d4e944e065a301d741b3c1d784f6bd1f503aa68b4967e32b2ba313d85", size = 27183, upload-time = "2026-10-02T23:05:16.976Z" }, + { url = "https://files.pythonhosted.org/packages/14/38/6ccdfa5b59049cb36fb80cbc80aee9cf1fc9bb77d1335ad435f2070b08cf/markupsafe-3.0.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:18a801868a884f216e784d7d14db2a4077143ce7610440aee2ce8f734e7cfcde", size = 24772, upload-time = "2026-10-02T23:05:18.209Z" }, + { url = "https://files.pythonhosted.org/packages/63/e0/cec6865dfe88cb48fedd4b20aed6af5158e41092adcbf3e028bcc6ec2108/markupsafe-3.0.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:434139499bb20b502ed3baa1f169e618f924a97e7a777fea1a49446d80106cf6", size = 23017, upload-time = "2026-10-02T23:05:19.286Z" }, + { url = "https://files.pythonhosted.org/packages/ee/76/6ed4940bb7648a9aac457c14f870cfdd5105f139a0fb1f29cd61fafa47d1/markupsafe-3.0.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9e227f3dbe6bde7491cf0a9965d00b88c6b1a4a95d11480ddf88bb96d397c19f", size = 22036, upload-time = "2026-10-02T23:05:20.352Z" }, + { url = "https://files.pythonhosted.org/packages/a1/4f/ed476226d4fe46a09090a36025bf319296810028df55eb12f1253b540f3a/markupsafe-3.0.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b8cd1f918b26fd7b1832ece557cc18f2d8747309ff8b3f0ef9d4250c5ad67a39", size = 23786, upload-time = "2026-10-02T23:05:21.576Z" }, + { url = "https://files.pythonhosted.org/packages/9a/35/66ff30450e35ef5fba9ebc930c9411747e537fd9447b65e44f5007e2b84d/markupsafe-3.0.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a5fcffb37e602b0b3c1638a97746b9b96125caa9bcf6fa41d337a9261de231ee", size = 22672, upload-time = "2026-10-02T23:05:22.922Z" }, + { url = "https://files.pythonhosted.org/packages/32/0b/72f45ce4b4efcbca4b80cf1b06703eff0be8d37e82abb78f66c85a7ead1e/markupsafe-3.0.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5989cb26b2e1efc6a42216a9f6b5ee495ce5ace2e5b352a9af489976b32d1ee2", size = 24107, upload-time = "2026-10-02T23:05:24.175Z" }, + { url = "https://files.pythonhosted.org/packages/d2/03/71776e5fdcba04614b384cc102e8a4198208579d896fd1394cb7cb9aa900/markupsafe-3.0.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:add96447a86d205ab616665d53b2950ee81083757f56e6ea833c8b2917646b46", size = 21615, upload-time = "2026-10-02T23:05:25.215Z" }, + { url = "https://files.pythonhosted.org/packages/ab/5f/801ce02a02e7aee0f784b1ec7843026178f6adeb9c93ac67eb1992a9a84d/markupsafe-3.0.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2628d3a8cb648ecebb3c5d6b0a1052d400e4d8b7ac0fb786be8d285b50040d17", size = 23076, upload-time = "2026-10-02T23:05:26.423Z" }, + { url = "https://files.pythonhosted.org/packages/4a/85/c43776625428f3bb4a61e8633940400e3efe6409e3c6f5bff26de5e45618/markupsafe-3.0.4-cp313-cp313-win32.whl", hash = "sha256:672d207103e6b16ca098611b0f9efad6bc00afd47c03d6ef62186495ca677dc0", size = 14118, upload-time = "2026-10-02T23:05:27.716Z" }, + { url = "https://files.pythonhosted.org/packages/6f/36/163da64de88a13db79214ef75fa041be7fa13bdb42261cf5b7484de14bfb/markupsafe-3.0.4-cp313-cp313-win_amd64.whl", hash = "sha256:1f1f9477e174582b0a1b583d60b66e1f2cf5d3fe12cee985e4aedf44766600e5", size = 14313, upload-time = "2026-10-02T23:05:28.749Z" }, + { url = "https://files.pythonhosted.org/packages/9f/a8/9b662783ffaa1149221432a923cee562f78b9cbbb8baa3df9b3753e63e1e/markupsafe-3.0.4-cp313-cp313-win_arm64.whl", hash = "sha256:06de8ef6331f6e822c28d577dc8bf43fe398800477c49498f38fc38b67ff33fc", size = 14189, upload-time = "2026-10-02T23:05:29.917Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c3/a944f3b0df22bd129e96915b9f4e98d2eeca6516687d7618304a966c3c74/markupsafe-3.0.4-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:4ed644d75aa94a2baf7ec3a96eaa160ea58c742eb9d27c6506053c5c40fc84ed", size = 12787, upload-time = "2026-10-02T23:05:30.971Z" }, + { url = "https://files.pythonhosted.org/packages/d4/d6/a44863f69d88b6c7e27889108f70d47aed259edf89d5df3c5fca1eac87d6/markupsafe-3.0.4-cp314-cp314-android_24_x86_64.whl", hash = "sha256:6d2a9efe686f9de00d0d1ea32a4a5a86d558a2277501bd78d964214eab625e59", size = 12525, upload-time = "2026-10-02T23:05:32.263Z" }, + { url = "https://files.pythonhosted.org/packages/17/8f/168ba80e532dd6a93f96f8f706f1ad41d7990b6e1aeedc1cc0d211a33497/markupsafe-3.0.4-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:8781a792a070cf2bd1b86d3aa943894115faaba6e88122a7bf32d62072742453", size = 11589, upload-time = "2026-10-02T23:05:33.251Z" }, + { url = "https://files.pythonhosted.org/packages/32/b3/aa2c95a574d3af39403a469b295886eb9b6d448da568cbebb5a2cbfdc2e5/markupsafe-3.0.4-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:971a3bbb75d97ae4e2e8f7d4834236f86f85f0c85e04ab2e191db1123b04f80b", size = 11801, upload-time = "2026-10-02T23:05:34.315Z" }, + { url = "https://files.pythonhosted.org/packages/60/d0/34b810107d83840e768bf485de795893ebbae35b26ab061b487adfa0a692/markupsafe-3.0.4-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:8909c2f1c6dd65e054ac4b573a91c8384d1492281e55d82d159d653f7a13adf6", size = 11447, upload-time = "2026-10-02T23:05:35.302Z" }, + { url = "https://files.pythonhosted.org/packages/6c/ab/2f8488f0f817a39fca068d2b17daf446bf5cdb3eae28c3720af534d873b4/markupsafe-3.0.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:4cf3468d5ec187ffffcaca8e61929a37448f215dafc1386a12c750a72fe53634", size = 11722, upload-time = "2026-10-02T23:05:36.363Z" }, + { url = "https://files.pythonhosted.org/packages/ad/40/e2d117b048d47282ade906fbfd92814cbee5647afc13fda88a3406039372/markupsafe-3.0.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:52704c5d36eb6dda8866493decd61111fff86244c9b1ad225ca01b9e91e5970f", size = 12061, upload-time = "2026-10-02T23:05:37.397Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a8/73a81135e85ba66217f5af7facb03bbb386807e1a729ab64532e4c802652/markupsafe-3.0.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1caa2fa5a6184fb233153b35f654e6687bd555476f6170f29d8ee9be1a8b0af9", size = 24434, upload-time = "2026-10-02T23:05:38.407Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ca/fa9216dd01efee2dfdacafe7df32b4d0170fbac694b0c258a193d6e53999/markupsafe-3.0.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:387d8cd30e69b3f0a72877b9ae717033396404e19095b17fe89753a981fda44f", size = 27183, upload-time = "2026-10-02T23:05:39.581Z" }, + { url = "https://files.pythonhosted.org/packages/fa/4e/a469509e538d37af51103b17b073126973f2b1cbf197ff32c7ddf025cfe5/markupsafe-3.0.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:051417f74bcaaefa316276e0ff723f541616ca51043d070da00249d9bddd3e3c", size = 24813, upload-time = "2026-10-02T23:05:40.671Z" }, + { url = "https://files.pythonhosted.org/packages/8f/db/d7282caf7ab03af44d5d6fdbaa019b35c7d7f1c90588b839c07cba640d6a/markupsafe-3.0.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8e9f292fcda89b324f2f5c91d13f1424a153e40fc2756f38ee23b15835ff300", size = 23049, upload-time = "2026-10-02T23:05:41.864Z" }, + { url = "https://files.pythonhosted.org/packages/30/f3/b6a425206e6964efda6acee544d0eb01d1501784d0b8e2dcc74986f33b17/markupsafe-3.0.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:df1ae86ff54725a01fa1a0510b914ca53a161b7050be74f6204e24aded5971d0", size = 22088, upload-time = "2026-10-02T23:05:43.014Z" }, + { url = "https://files.pythonhosted.org/packages/ea/8a/84d3582fc1f0d5bd466cdf2eebf175e172158a6e70701aacec1de1b35430/markupsafe-3.0.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8965520ac587c94a4ac48b729be3d8b8de00af39699b17585dfb599babe77977", size = 23846, upload-time = "2026-10-02T23:05:44.098Z" }, + { url = "https://files.pythonhosted.org/packages/1c/65/db101cce51b7ba4864ac491a9859d297dd1adf0e55b103fee9db9c47c527/markupsafe-3.0.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:340cbb1957ba99929cbf19a75626d36ba1ae21d1730b287d1cf7f824a20c4fc7", size = 22674, upload-time = "2026-10-02T23:05:45.23Z" }, + { url = "https://files.pythonhosted.org/packages/e0/49/ddee9813d71db0c7a5c9d97c832125e6758a0c844777f1cf076569bb0e22/markupsafe-3.0.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:3a93d9616ddecfb393727a0041a562cf0b15a244e20f2bd25efc7949be4c4f17", size = 24104, upload-time = "2026-10-02T23:05:46.398Z" }, + { url = "https://files.pythonhosted.org/packages/aa/0e/7d8518d726726870a2399d69fd30d0fa36c5e57a2132c336b58d7c491073/markupsafe-3.0.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d2e56fd3b00222722abfb3f5f0759ddbae4b90811b5ad4343c64030ad1bde70c", size = 21637, upload-time = "2026-10-02T23:05:47.48Z" }, + { url = "https://files.pythonhosted.org/packages/b4/b0/b505e8a361ba557dbf3b3aa7331ea39b00d2022a26e925ff8463b9714bb3/markupsafe-3.0.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:0d9c47709875fdb321452056622e930c52afbc07a7d780762fbb8b4d91ce6fa4", size = 23081, upload-time = "2026-10-02T23:05:48.611Z" }, + { url = "https://files.pythonhosted.org/packages/1c/ea/9cc3cea873f980c75cbdb6f4277ce30ee955de38be0b3d02f14c108e0698/markupsafe-3.0.4-cp314-cp314-win32.whl", hash = "sha256:38fc55594dab834470b6733dead2ee9e3f657fb0608c769dcafa0ba5ab52f45c", size = 14272, upload-time = "2026-10-02T23:05:49.707Z" }, + { url = "https://files.pythonhosted.org/packages/80/f0/5792ff768a410f93ee3f84fc19345295ffc352d2c936b424cb37e514714c/markupsafe-3.0.4-cp314-cp314-win_amd64.whl", hash = "sha256:c1bc67752d5f21013cfe430df4062441714eab79f65a6a05e01505957e9c35fe", size = 14501, upload-time = "2026-10-02T23:05:50.788Z" }, + { url = "https://files.pythonhosted.org/packages/5f/cf/3d074a8edffcc6899355232ff2543ae8d929733239596423b7db79698bc9/markupsafe-3.0.4-cp314-cp314-win_arm64.whl", hash = "sha256:7e1636da3d8dfc220b6dd10264db5f2b165e4888c4518594898fbe381049af8a", size = 14364, upload-time = "2026-10-02T23:05:51.857Z" }, + { url = "https://files.pythonhosted.org/packages/d9/31/87ce42159aae2163cf3bbbd0c44bc87780510eecab1ea3859099aed95dcb/markupsafe-3.0.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:805c8b84534fa10891890f0e4be39f3a99e94615d93e8836bf9fa1fdca2feeb2", size = 11759, upload-time = "2026-10-02T23:05:52.951Z" }, + { url = "https://files.pythonhosted.org/packages/5f/53/b047207eeb7752e960aca3eb1df5fb7eefa7dd4c62ac49bb156456c8a702/markupsafe-3.0.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fa95848c929b6a75f6848d3c9793e59db365ee436776e57db835cdbfa79ba977", size = 12096, upload-time = "2026-10-02T23:05:54.066Z" }, + { url = "https://files.pythonhosted.org/packages/ee/51/4326c88a13c7b755657d44b4bb986f8c3d9843ecba7e22d98661d87f9a57/markupsafe-3.0.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e916035e3e9930cbdfdd10abf48861340221857f45509565898e012263f7b289", size = 25699, upload-time = "2026-10-02T23:05:55.15Z" }, + { url = "https://files.pythonhosted.org/packages/f2/bb/990581b7474bfcf2cf34bed6ba5ea23bd87adb9d671213d68e88620e7a6b/markupsafe-3.0.4-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b4d12837e0203bbace818ff4a7461afdcd78bcd782351cea148139180d7bcffe", size = 27804, upload-time = "2026-10-02T23:05:56.29Z" }, + { url = "https://files.pythonhosted.org/packages/6b/89/89491878c28e8291f5aa2fffe2c2d57230d10ae366d55dd810b840513d78/markupsafe-3.0.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5086f9975abb1ab531ee6afca1761e4b59a19b446f3f6522ed776963228cfe5a", size = 25912, upload-time = "2026-10-02T23:05:57.416Z" }, + { url = "https://files.pythonhosted.org/packages/30/77/680998b54efdea06fc114565cd739b6d059f826a0279219b218dfa750d29/markupsafe-3.0.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b4a635a0487774f841cb1fb62e907e7195cc95bc761e053184b8acc3ceb20733", size = 23623, upload-time = "2026-10-02T23:05:58.557Z" }, + { url = "https://files.pythonhosted.org/packages/ae/75/2709f5ac5de9467b40b10e2bb8f89cc63dfb74582e09aa734b1124a217de/markupsafe-3.0.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb96e6e088d6cf71c1ea977510948320234824cf226e32f6f6e044f7a9c82b34", size = 23301, upload-time = "2026-10-02T23:05:59.94Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c8/39eadc6c5b14c9c7679bfb98f4d4c6a97863b5beb91839aca4d2d6e16e55/markupsafe-3.0.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8b5d563170ff8ba3181caa967c99a3c804d1dedb702c7cb93a6a7c32247da978", size = 24950, upload-time = "2026-10-02T23:06:01.289Z" }, + { url = "https://files.pythonhosted.org/packages/1a/5e/01037f8a43e8ccb0bffb4fbdc5212db05bf080fdd7286cd392332d58128a/markupsafe-3.0.4-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:396ec4e65cc889f69786b3b89478b471cee5a3bcf468b9d9bb03e1a30fb291fc", size = 23330, upload-time = "2026-10-02T23:06:02.441Z" }, + { url = "https://files.pythonhosted.org/packages/d4/f4/23e83ce0596bb0cbe670502d31df8f757bbd01a392aa486fa3b40d1ed399/markupsafe-3.0.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:15ba9e28640feef770374b116a6f019c21f52404aeabe516aa7f800587b98cfc", size = 25239, upload-time = "2026-10-02T23:06:03.579Z" }, + { url = "https://files.pythonhosted.org/packages/88/5b/3708897368073cc683d524750474f41a77d2986152c380dcc55b20fdf340/markupsafe-3.0.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d920abdfa61279ba1a2ef9484aab07bf03331f8c08a10120fa332353d06e6932", size = 22767, upload-time = "2026-10-02T23:06:04.699Z" }, + { url = "https://files.pythonhosted.org/packages/c6/61/ebda1307864b409e6b3115757a3d4a09cca46cfb6cc65191b5de226b424b/markupsafe-3.0.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a9f54054101545a9a9cccefddf54316aa6e4491611fcbef9e91b3b6bebec04f6", size = 23668, upload-time = "2026-10-02T23:06:05.9Z" }, + { url = "https://files.pythonhosted.org/packages/09/15/98075cceac3b5ba0dbb8e4762a847be967d2befc349a2cf2d0ac77f62c9d/markupsafe-3.0.4-cp314-cp314t-win32.whl", hash = "sha256:12a606a492de952afcb43b59a14aaaaad120e708d3663dd0fdf2d738d427a691", size = 14301, upload-time = "2026-10-02T23:06:07.109Z" }, + { url = "https://files.pythonhosted.org/packages/0b/a3/768b560fcc4156685cb563d922b217810cfa7bc135773367f62f1f9d2078/markupsafe-3.0.4-cp314-cp314t-win_amd64.whl", hash = "sha256:a18f38cafc329bac5e3c2b96c765b4c96d3d103421ed22ab7988c1e3fce27464", size = 14526, upload-time = "2026-10-02T23:06:08.276Z" }, + { url = "https://files.pythonhosted.org/packages/93/63/da554b4c97a6b0ea3229ca7fe8cbfb620be81613d517f482e85958550537/markupsafe-3.0.4-cp314-cp314t-win_arm64.whl", hash = "sha256:eba154571c16e032112afac0dc2dfe9e63c2ceb7aedd07bb7eecf2ce26d4dd4c", size = 14421, upload-time = "2026-10-02T23:06:09.402Z" }, + { url = "https://files.pythonhosted.org/packages/a9/30/54d11c8ca027114898cab97421fb39e4ffd9ddf47cdbc44df2ec76722da9/markupsafe-3.0.4-cp315-cp315-android_24_arm64_v8a.whl", hash = "sha256:737c9c3981998eba27f11786f84fddcbabc74068b72a4a1f454ea02094b57b65", size = 12791, upload-time = "2026-10-02T23:06:10.485Z" }, + { url = "https://files.pythonhosted.org/packages/10/6d/97c913e253a14bd3cd0e15a5c56d13203b823fa7ee32498342896a072dc4/markupsafe-3.0.4-cp315-cp315-android_24_x86_64.whl", hash = "sha256:489505b03f692c3f376394e49194fa7a7f9e8558d6e293a7056a0032b0c38163", size = 12527, upload-time = "2026-10-02T23:06:11.834Z" }, + { url = "https://files.pythonhosted.org/packages/26/f9/b86d032042a4d597d9e1997f0e5f63a3eedaf11258e0a05760b0a0a826ea/markupsafe-3.0.4-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:077293e425f28ec737dbcad442a71752e28f8ae27cde3d68acd1fb212091cd92", size = 11602, upload-time = "2026-10-02T23:06:13.122Z" }, + { url = "https://files.pythonhosted.org/packages/f2/dc/73c14c1eedf0ac5fa3292ba43435e6c49d2c2050f33cebde541f8f4807f1/markupsafe-3.0.4-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:9348cbb300d224fe3b89793262cb093504d4ae927004468463f745188a193e4a", size = 11817, upload-time = "2026-10-02T23:06:14.227Z" }, + { url = "https://files.pythonhosted.org/packages/8f/69/2c2fcaa5fcee22d72c7819c0d536fd181c74a688e6143845419579cd2863/markupsafe-3.0.4-cp315-cp315-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:b807e598953730f82e4eae3bd30f6a122cf6b31c398c6b504c0e04c13c170429", size = 11446, upload-time = "2026-10-02T23:06:15.574Z" }, + { url = "https://files.pythonhosted.org/packages/88/54/9e5ec76c62e6e2834d5a93623018c943e8b3bb41d663e3fd4c03303b9b85/markupsafe-3.0.4-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:799c39bdf5e2f1292fedd3009f7b3c9e760f10b2420cb9638d56920840ff6db8", size = 11719, upload-time = "2026-10-02T23:06:16.701Z" }, + { url = "https://files.pythonhosted.org/packages/96/24/3ec292b44064c16229e064d770b2625bd8ea941aa61f44905a9fa44942c0/markupsafe-3.0.4-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:ae9dcb8fbe244cb82f8a6458b455b927a03685e383d9bacf1ea5ce180b96dc97", size = 12075, upload-time = "2026-10-02T23:06:17.855Z" }, + { url = "https://files.pythonhosted.org/packages/aa/85/b64fdb1f304848518742136983c24e96d967bfb59a0ea160e92736901ab0/markupsafe-3.0.4-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bced6e2a6dba6a28f7dd3c6ce14df1b2dd495923f16ea484cad03decd463b2b", size = 24656, upload-time = "2026-10-02T23:06:18.963Z" }, + { url = "https://files.pythonhosted.org/packages/9c/18/23997d4c65b355da6390d61cd56e0ab3befd6ba8dda25cb40c602bd0fa6b/markupsafe-3.0.4-cp315-cp315-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3882fb412298575bae3b9c46868251f15cc69307359f87bb1b382e53d6e5a2c9", size = 27737, upload-time = "2026-10-02T23:06:20.117Z" }, + { url = "https://files.pythonhosted.org/packages/d4/36/35998dead3c6af88c38265a56e58100211f036234ab88eb2283fd4cbce44/markupsafe-3.0.4-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:04e7902ba80ee4bac1d50a549606527a1dcf0476cd81403db41099d3b60ec653", size = 25003, upload-time = "2026-10-02T23:06:21.284Z" }, + { url = "https://files.pythonhosted.org/packages/82/96/ef49135ce260db4ca4a12b119ed468449cd248db6b1468e2112b546d7a2e/markupsafe-3.0.4-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:925f929d6b59a8b3f8b8c6ac363cd0af7eecc81efb3071770b3c6717c450a369", size = 23111, upload-time = "2026-10-02T23:06:22.524Z" }, + { url = "https://files.pythonhosted.org/packages/50/7d/83126e338bd88c17a220668235368ad719fd4638e426739858cbb8508f77/markupsafe-3.0.4-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f68edfc67aabac33708941f26f22a7b8e9f81429bc0cf249fcf7d66b23af8d19", size = 22403, upload-time = "2026-10-02T23:06:23.785Z" }, + { url = "https://files.pythonhosted.org/packages/83/dd/daf7e420de23c8206c365204e7b85e1251d8e19d34196a56336f316e5ed2/markupsafe-3.0.4-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:e5c802729725bd07e2bc3ab7b76dc7e0bbfc53129d8f1eb1c002c24cf774717e", size = 24083, upload-time = "2026-10-02T23:06:25.037Z" }, + { url = "https://files.pythonhosted.org/packages/19/3c/11eecdc06bc44ad5570350085b572ebf049e8f9a38d1ece6d76640b739cd/markupsafe-3.0.4-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:55ffd6ce583d97dc71dc92e930324c8c0d25aea7e3ade6ae54ef77cedb096811", size = 22931, upload-time = "2026-10-02T23:06:26.328Z" }, + { url = "https://files.pythonhosted.org/packages/0d/9e/ac0fd77f2a726e56ecc3ca0235d095feace1358d1b822406c2a2ef26a4dc/markupsafe-3.0.4-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:2cb3dd71fc6be918ad4264346a8ed69485f9b7ed7bf35495d8e22807cd6b8bea", size = 24299, upload-time = "2026-10-02T23:06:27.742Z" }, + { url = "https://files.pythonhosted.org/packages/d7/09/c6bd842ad58ff5b3bc76eeed7e9a42a6f11adc5d090ec697b72c9672731e/markupsafe-3.0.4-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:94f5407f7bc64fa6463906b896f9904beeeb7dd8dc116ee8e9056c8714ff9916", size = 21948, upload-time = "2026-10-02T23:06:29.274Z" }, + { url = "https://files.pythonhosted.org/packages/a3/46/82f586711fed61e86faa1ee1bc317d68cd45a10c8bdbe3f7d1fdf9026ad8/markupsafe-3.0.4-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:2dad610540cb2e6272855c178f08ae9a1c7ac258a7fb71660553a5f104b42741", size = 23150, upload-time = "2026-10-02T23:06:30.583Z" }, + { url = "https://files.pythonhosted.org/packages/19/2d/2dfdce99318abbfa26925195fbc17db188c46a1ec6457be121b6f9cfeb42/markupsafe-3.0.4-cp315-cp315-win32.whl", hash = "sha256:03470d1a8268e692ecf79ecd565593e59d44219377a7ead61f1f1b94c1f7ff6b", size = 14269, upload-time = "2026-10-02T23:06:31.949Z" }, + { url = "https://files.pythonhosted.org/packages/5b/ec/6000fd82e8791e58fcd0456ec20f098957e2b03d5ed02eb73241a577c0ba/markupsafe-3.0.4-cp315-cp315-win_amd64.whl", hash = "sha256:d882a373d8093c2941e01291b7ced96e9cbe4781da9a7751ca7e6c70385e5214", size = 14496, upload-time = "2026-10-02T23:06:33.258Z" }, + { url = "https://files.pythonhosted.org/packages/bc/66/e73bd5016421d5d6e2fb6de7dd609f9de020942ac8c626526bd8c6eeaf82/markupsafe-3.0.4-cp315-cp315-win_arm64.whl", hash = "sha256:353bd63081912ab8cfa6a0c7d185934cdf8426f04c618bba6bc4b394f2069b67", size = 14361, upload-time = "2026-10-02T23:06:34.539Z" }, + { url = "https://files.pythonhosted.org/packages/90/df/cb8c3dc98d313a951df2f8968f44e4cb5643df6d3cab749a530ce2f7d972/markupsafe-3.0.4-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:c61750fadcd119d0825bcb7d7d675dd264dcc89cc05292aab5be68ebdbb374ad", size = 11760, upload-time = "2026-10-02T23:06:35.807Z" }, + { url = "https://files.pythonhosted.org/packages/d6/bb/4af9b3ca0753d654ac75f9531d5bd741bb77ca6e696f36807c475ffc099a/markupsafe-3.0.4-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:1c0df495a977d10460a94941799c72d5b5ab03d3858d949b55b5a66c8f371c99", size = 12108, upload-time = "2026-10-02T23:06:37.089Z" }, + { url = "https://files.pythonhosted.org/packages/3f/d4/b56429313aee5fd59b079c3df5615299959e25e7113eb6d8caadbdd7d38a/markupsafe-3.0.4-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02fa4acbc6a3fc5c693c34d4dd8c1130b7fe99cc915181b0ddd6f72aeb296002", size = 25762, upload-time = "2026-10-02T23:06:38.419Z" }, + { url = "https://files.pythonhosted.org/packages/65/f5/34c181e891aa4f7d59c918584672e0c5eb7fffe76c1387d1246008bf4081/markupsafe-3.0.4-cp315-cp315t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:05295589e619b9bed252a86b532b8e27350abc372d18ba89b59375325e91ec1e", size = 28400, upload-time = "2026-10-02T23:06:39.819Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b5/ad14694fd0ac9a5ce30bc6498f2999378f418583dd1679cca5a1b512957e/markupsafe-3.0.4-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:be6cb0c799abb0e2ba3e618e6d28ddddf7e485f6c2ce938dfa237daf3905072c", size = 25946, upload-time = "2026-10-02T23:06:41.381Z" }, + { url = "https://files.pythonhosted.org/packages/d6/a8/26b606445387d0ceb1eb1f21840094b84e4e3c3c3983d80d10b89823b490/markupsafe-3.0.4-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:26e9867520db70d37f7fb421a7f0d8adb40171011fb84ce869afa1a83370dfa8", size = 23634, upload-time = "2026-10-02T23:06:42.748Z" }, + { url = "https://files.pythonhosted.org/packages/39/a2/b8814de672f1f0094d498bf646f2fec9d6356b503d28ef500b71c5095377/markupsafe-3.0.4-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f03460ff076f70ab595bb45a0205ccea1971443575b6920c52e755dec2b3fbfe", size = 23488, upload-time = "2026-10-02T23:06:44.176Z" }, + { url = "https://files.pythonhosted.org/packages/db/c7/287223376fb73335a3cc5d6eb22c6ab01358cf33945a9c39c06b9dac3f4b/markupsafe-3.0.4-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:436e3ffc6310d3c41878c601db29098102fe5d8a467c49da4a4125254e0980f2", size = 25037, upload-time = "2026-10-02T23:06:45.646Z" }, + { url = "https://files.pythonhosted.org/packages/f9/29/4df8355e313426d19e62ba33e0253c009ca12a0894ee77d67fa67255361c/markupsafe-3.0.4-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:4e2c4809c14559aa7ef426f27fb35afbb38104c349a903bf8f3600456764bb38", size = 23543, upload-time = "2026-10-02T23:06:47.264Z" }, + { url = "https://files.pythonhosted.org/packages/71/e5/8377731e8495668dcc768f645e717df18318c841edaf023a99395f6da9b4/markupsafe-3.0.4-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:da2af0d7aebfc2074080d72efa6ab8317c62481ef1f896f65d9999c1c01f4494", size = 25282, upload-time = "2026-10-02T23:06:48.795Z" }, + { url = "https://files.pythonhosted.org/packages/ed/5f/373456e37ceb1478d657d6fe769cbe0a39f0a8dfc1548eeb19c471eefdd9/markupsafe-3.0.4-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:aa2c838cc024642cc04c6854232f32b43e5e22833dd11119c1766c7873b8370d", size = 22993, upload-time = "2026-10-02T23:06:50.31Z" }, + { url = "https://files.pythonhosted.org/packages/d7/93/2cbd5628435afb6f541bbaced4bce0c2edac4b09a142e6e928b8b0da9858/markupsafe-3.0.4-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:b91cc9d336957239ff200f30097e6fea2dc6d6fb3c81e853eaa09eac904fd894", size = 23712, upload-time = "2026-10-02T23:06:51.759Z" }, + { url = "https://files.pythonhosted.org/packages/81/99/157e10966b033b363aeda5263e82596ee232a0b1d082fdbf90aa417ff083/markupsafe-3.0.4-cp315-cp315t-win32.whl", hash = "sha256:e49fb0d1ce92cfa0cb198cc5b1b11cdf9d0638658e2a2db2687e39db7c87fc78", size = 14300, upload-time = "2026-10-02T23:06:53.241Z" }, + { url = "https://files.pythonhosted.org/packages/33/05/55884815414c9706a23deca150b72c25a62109e65b0b6ce232077802c719/markupsafe-3.0.4-cp315-cp315t-win_amd64.whl", hash = "sha256:4f6e0852a0283b1b1fd776eeb7b766a5f440b3e2bd31ab51af3b400585f3965c", size = 14522, upload-time = "2026-10-02T23:06:54.729Z" }, + { url = "https://files.pythonhosted.org/packages/92/f9/ecbde7149e95b8a0f18e16d5d747f7dc06049d5da2e4f77f6f5e4a1f46a8/markupsafe-3.0.4-cp315-cp315t-win_arm64.whl", hash = "sha256:39dbacefc411633db5b4378b066a9aca70a3d7e2922c9e578d825f844026eeba", size = 14417, upload-time = "2026-10-02T23:06:56.246Z" }, +] + +[[package]] +name = "minijinja" +version = "2.24.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/18/2dbb84297175b77b5eb497e07e66e71c71b8073bdbe3d3cb1d3309823d66/minijinja-2.24.0.tar.gz", hash = "sha256:8e9dc11bd5c7a20869c42d6c7c0caa5cd437c62a00a042f65df20036f0def93c", size = 299288, upload-time = "2026-08-31T19:28:46.351Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/16/9170db3a85bf7fed14c5281e13927d310385e5fd945518dda80e2ec0a631/minijinja-2.24.0-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:f286106f9d2ffd73702a470cc4d9262b1588eb48916fc84b98d19df4e3064bd4", size = 2174596, upload-time = "2026-08-31T19:28:25.642Z" }, + { url = "https://files.pythonhosted.org/packages/82/ec/9a1e7513d7e18ff11907eb6ae92f060f2abd85e0df029625816b8f469eb4/minijinja-2.24.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e252fa4c59cff1794dfffb5349da6a4885de97aaaf2fbc6983becc1eb973e9", size = 1140515, upload-time = "2026-08-31T19:28:27.648Z" }, + { url = "https://files.pythonhosted.org/packages/66/0c/835223a549b924b1bf9a7a2e6723783342a05896c90cf49a10bbef72a253/minijinja-2.24.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:94964dca64c80b2a85b598037ab07f01a794d238c66d5556d01c4f400b630fd0", size = 1115064, upload-time = "2026-08-31T19:28:29.634Z" }, + { url = "https://files.pythonhosted.org/packages/ad/ed/14056592c0008a0945e96966c5e2b215579d6f3487032d7ba2d8ad2e9c12/minijinja-2.24.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5a4dbd73f2c02ab6d0ab0b62b68a7d2557e5d45723d3b4e423b7c3877f31cad", size = 1178991, upload-time = "2026-08-31T19:28:31.538Z" }, + { url = "https://files.pythonhosted.org/packages/4b/6b/71ca5f679c03a67af5d551b32e306c6bb87aa7157767c3a7a678323d748f/minijinja-2.24.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43d633999cb06509ba3de9a0e5798f97d5ba5bc0d337f9d8f8ea02f349050cbd", size = 1312790, upload-time = "2026-08-31T19:28:33.473Z" }, + { url = "https://files.pythonhosted.org/packages/56/13/3c7c6f34c41eece458f4f416dbab229024502173de780ee978ef38a4c605/minijinja-2.24.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:90cc9e1196d98e56fdc87b69a5949bc76ecbbc512c7654081483c5acabf8ca8f", size = 1308284, upload-time = "2026-08-31T19:28:36.272Z" }, + { url = "https://files.pythonhosted.org/packages/2e/c9/bbcf76a1bd02a503c2d05f996d6271358c77bab68893689d3bd14514fdab/minijinja-2.24.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:194364c0a060606e96ae635cd997c7e014b4ef026d12c02fe9f8912749622481", size = 1381830, upload-time = "2026-08-31T19:28:37.994Z" }, + { url = "https://files.pythonhosted.org/packages/20/91/980d6b2572a0985ec033c1b93bb8eea6be87f920a7cab2097ef740894c61/minijinja-2.24.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:6c2106a399eaff009ebf308ccebed397787ff4442159de9598543298f3eee522", size = 1463332, upload-time = "2026-08-31T19:28:39.749Z" }, + { url = "https://files.pythonhosted.org/packages/92/98/75d6a76499fd40f839a0a1a8fc46aa43cf6c47ea9680d4174289fd6fec3a/minijinja-2.24.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5e0cdc27520d2163ec8a2078e4ff20c3afff4fb89eb05d21679c3facd30369ab", size = 1388664, upload-time = "2026-08-31T19:28:41.421Z" }, + { url = "https://files.pythonhosted.org/packages/7d/f1/e8d82609d7aad5791d52fdec4c642fab46974094cef9102110efa6fc2713/minijinja-2.24.0-cp38-abi3-win32.whl", hash = "sha256:b68aa1bd72da3a6175afa721090592f19e637b7a02408f796298d342b709d06b", size = 1058094, upload-time = "2026-08-31T19:28:43.157Z" }, + { url = "https://files.pythonhosted.org/packages/5b/e5/d86c8c706b3820fc6f58baa0f7d322e78885843ddba7e9cba77985a3fbc7/minijinja-2.24.0-cp38-abi3-win_amd64.whl", hash = "sha256:541959f4529017e437b8822cdaabaaab9d4090c140138dec40dbd739b3b0f778", size = 1118117, upload-time = "2026-08-31T19:28:44.843Z" }, +] + +[[package]] +name = "packaging" +version = "26.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" }, +] + +[[package]] +name = "papyrus-docs" +version = "1.0.0" +source = { editable = "." } +dependencies = [ + { name = "furo" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "sphinx-needs" }, + { name = "sphinxcontrib-mermaid" }, +] + +[package.optional-dependencies] +dev = [ + { name = "linkchecker" }, + { name = "sphinx-autobuild", version = "2024.10.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx-autobuild", version = "2025.8.25", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, +] + +[package.metadata] +requires-dist = [ + { name = "furo", specifier = ">=2024.0" }, + { name = "linkchecker", marker = "extra == 'dev'", specifier = ">=10.0" }, + { name = "sphinx", specifier = ">=8.0" }, + { name = "sphinx-autobuild", marker = "extra == 'dev'", specifier = ">=2024.0" }, + { name = "sphinx-needs", specifier = ">=4.0" }, + { name = "sphinxcontrib-mermaid", specifier = ">=1.0" }, +] +provides-extras = ["dev"] + +[[package]] +name = "pygments" +version = "2.21.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/49/2e/ced460408999b33da6b31b0021b0f37d329e202d4169aeb164493778f25b/pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c", size = 5005329, upload-time = "2026-08-17T08:02:48.824Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", size = 1250147, upload-time = "2026-08-17T08:02:44.912Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "requests" +version = "2.34.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, +] + +[[package]] +name = "requests-file" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3c/f8/5dc70102e4d337063452c82e1f0d95e39abfe67aa222ed8a5ddeb9df8de8/requests_file-3.0.1.tar.gz", hash = "sha256:f14243d7796c588f3521bd423c5dea2ee4cc730e54a3cac9574d78aca1272576", size = 6967, upload-time = "2025-10-20T18:56:42.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/d5/de8f089119205a09da657ed4784c584ede8381a0ce6821212a6d4ca47054/requests_file-3.0.1-py2.py3-none-any.whl", hash = "sha256:d0f5eb94353986d998f80ac63c7f146a307728be051d4d1cd390dbdb59c10fa2", size = 4514, upload-time = "2025-10-20T18:56:41.184Z" }, +] + +[[package]] +name = "roman-numerals" +version = "4.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/f9/41dc953bbeb056c17d5f7a519f50fdf010bd0553be2d630bc69d1e022703/roman_numerals-4.1.0.tar.gz", hash = "sha256:1af8b147eb1405d5839e78aeb93131690495fe9da5c91856cb33ad55a7f1e5b2", size = 9077, upload-time = "2025-12-17T18:25:34.381Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/54/6f679c435d28e0a568d8e8a7c0a93a09010818634c3c3907fc98d8983770/roman_numerals-4.1.0-py3-none-any.whl", hash = "sha256:647ba99caddc2cc1e55a51e4360689115551bf4476d90e8162cf8c345fe233c7", size = 7676, upload-time = "2025-12-17T18:25:33.098Z" }, +] + +[[package]] +name = "snowballstemmer" +version = "3.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/f8/0a71edf031f03c40db17503cb8ca78a69a171254e568e7db241b0ab57ea1/snowballstemmer-3.1.1.tar.gz", hash = "sha256:e07bbc54a0d798fe6010a12398422e62a8bfbba95c394fd0956ef58cb4d3e260", size = 123314, upload-time = "2026-06-03T00:56:40.194Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/07/2ebca9b11fb9be7340a818d8d6f63feaebb146be2c4afbd6061701d6df6e/snowballstemmer-3.1.1-py3-none-any.whl", hash = "sha256:7e207fa178741da09cdee59d3ecec3827ad5f92b1fc5c9ff3755b639f71f5752", size = 104164, upload-time = "2026-06-03T00:56:38.614Z" }, +] + +[[package]] +name = "soupsieve" +version = "2.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/71/c3/1b817965ac12dc002d7c9cd7dfffdd7d4fbf9b45763ef2ffe7b86ee94670/soupsieve-2.10.tar.gz", hash = "sha256:49e9380d7d2905463583bafe285e818c7366a9ed7b3aee221c1ac79c905d8bc0", size = 124337, upload-time = "2026-09-24T02:36:35.048Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/87/5ed59e1d0290564e2027ed066c52b059892c4637741337fc0967183c8d4d/soupsieve-2.10-py3-none-any.whl", hash = "sha256:8596eb8967d744174820280fa62b4542a2e955bfaccca73ed8a13c6eb8e9b502", size = 38019, upload-time = "2026-09-24T02:36:33.709Z" }, +] + +[[package]] +name = "sphinx" +version = "8.1.3" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "alabaster" }, + { name = "babel" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "docutils", version = "0.21.2", source = { registry = "https://pypi.org/simple" } }, + { name = "imagesize" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pygments" }, + { name = "requests" }, + { name = "snowballstemmer" }, + { name = "sphinxcontrib-applehelp" }, + { name = "sphinxcontrib-devhelp" }, + { name = "sphinxcontrib-htmlhelp" }, + { name = "sphinxcontrib-jsmath" }, + { name = "sphinxcontrib-qthelp" }, + { name = "sphinxcontrib-serializinghtml" }, + { name = "tomli" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/be0b61178fe2cdcb67e2a92fc9ebb488e3c51c4f74a36a7824c0adf23425/sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927", size = 8184611, upload-time = "2024-10-13T20:27:13.93Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/60/1ddff83a56d33aaf6f10ec8ce84b4c007d9368b21008876fceda7e7381ef/sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2", size = 3487125, upload-time = "2024-10-13T20:27:10.448Z" }, +] + +[[package]] +name = "sphinx" +version = "9.0.4" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version == '3.11.*'", +] +dependencies = [ + { name = "alabaster" }, + { name = "babel" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "docutils", version = "0.22.4", source = { registry = "https://pypi.org/simple" } }, + { name = "imagesize" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pygments" }, + { name = "requests" }, + { name = "roman-numerals" }, + { name = "snowballstemmer" }, + { name = "sphinxcontrib-applehelp" }, + { name = "sphinxcontrib-devhelp" }, + { name = "sphinxcontrib-htmlhelp" }, + { name = "sphinxcontrib-jsmath" }, + { name = "sphinxcontrib-qthelp" }, + { name = "sphinxcontrib-serializinghtml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/50/a8c6ccc36d5eacdfd7913ddccd15a9cee03ecafc5ee2bc40e1f168d85022/sphinx-9.0.4.tar.gz", hash = "sha256:594ef59d042972abbc581d8baa577404abe4e6c3b04ef61bd7fc2acbd51f3fa3", size = 8710502, upload-time = "2025-12-04T07:45:27.343Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/3f/4bbd76424c393caead2e1eb89777f575dee5c8653e2d4b6afd7a564f5974/sphinx-9.0.4-py3-none-any.whl", hash = "sha256:5bebc595a5e943ea248b99c13814c1c5e10b3ece718976824ffa7959ff95fffb", size = 3917713, upload-time = "2025-12-04T07:45:24.944Z" }, +] + +[[package]] +name = "sphinx" +version = "9.1.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.12'", +] +dependencies = [ + { name = "alabaster" }, + { name = "babel" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "docutils", version = "0.22.4", source = { registry = "https://pypi.org/simple" } }, + { name = "imagesize" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pygments" }, + { name = "requests" }, + { name = "roman-numerals" }, + { name = "snowballstemmer" }, + { name = "sphinxcontrib-applehelp" }, + { name = "sphinxcontrib-devhelp" }, + { name = "sphinxcontrib-htmlhelp" }, + { name = "sphinxcontrib-jsmath" }, + { name = "sphinxcontrib-qthelp" }, + { name = "sphinxcontrib-serializinghtml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/bd/f08eb0f4eed5c83f1ba2a3bd18f7745a2b1525fad70660a1c00224ec468a/sphinx-9.1.0.tar.gz", hash = "sha256:7741722357dd75f8190766926071fed3bdc211c74dd2d7d4df5404da95930ddb", size = 8718324, upload-time = "2025-12-31T15:09:27.646Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/f7/b1884cb3188ab181fc81fa00c266699dab600f927a964df02ec3d5d1916a/sphinx-9.1.0-py3-none-any.whl", hash = "sha256:c84fdd4e782504495fe4f2c0b3413d6c2bf388589bb352d439b2a3bb99991978", size = 3921742, upload-time = "2025-12-31T15:09:25.561Z" }, +] + +[[package]] +name = "sphinx-autobuild" +version = "2024.10.3" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "colorama" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" } }, + { name = "starlette" }, + { name = "uvicorn" }, + { name = "watchfiles" }, + { name = "websockets", version = "16.1.1", source = { registry = "https://pypi.org/simple" } }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a5/2c/155e1de2c1ba96a72e5dba152c509a8b41e047ee5c2def9e9f0d812f8be7/sphinx_autobuild-2024.10.3.tar.gz", hash = "sha256:248150f8f333e825107b6d4b86113ab28fa51750e5f9ae63b59dc339be951fb1", size = 14023, upload-time = "2024-10-02T23:15:30.172Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/c0/eba125db38c84d3c74717008fd3cb5000b68cd7e2cbafd1349c6a38c3d3b/sphinx_autobuild-2024.10.3-py3-none-any.whl", hash = "sha256:158e16c36f9d633e613c9aaf81c19b0fc458ca78b112533b20dafcda430d60fa", size = 11908, upload-time = "2024-10-02T23:15:28.739Z" }, +] + +[[package]] +name = "sphinx-autobuild" +version = "2025.8.25" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.12'", + "python_full_version == '3.11.*'", +] +dependencies = [ + { name = "colorama" }, + { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, + { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "starlette" }, + { name = "uvicorn" }, + { name = "watchfiles" }, + { name = "websockets", version = "17.2", source = { registry = "https://pypi.org/simple" } }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e0/3c/a59a3a453d4133777f7ed2e83c80b7dc817d43c74b74298ca0af869662ad/sphinx_autobuild-2025.8.25.tar.gz", hash = "sha256:9cf5aab32853c8c31af572e4fecdc09c997e2b8be5a07daf2a389e270e85b213", size = 15200, upload-time = "2025-08-25T18:44:55.436Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/20/56411b52f917696995f5ad27d2ea7e9492c84a043c5b49a3a3173573cd93/sphinx_autobuild-2025.8.25-py3-none-any.whl", hash = "sha256:b750ac7d5a18603e4665294323fd20f6dcc0a984117026d1986704fa68f0379a", size = 12535, upload-time = "2025-08-25T18:44:54.164Z" }, +] + +[[package]] +name = "sphinx-basic-ng" +version = "1.0.0b2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/0b/a866924ded68efec7a1759587a4e478aec7559d8165fac8b2ad1c0e774d6/sphinx_basic_ng-1.0.0b2.tar.gz", hash = "sha256:9ec55a47c90c8c002b5960c57492ec3021f5193cb26cebc2dc4ea226848651c9", size = 20736, upload-time = "2023-07-08T18:40:54.166Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/dd/018ce05c532a22007ac58d4f45232514cd9d6dd0ee1dc374e309db830983/sphinx_basic_ng-1.0.0b2-py3-none-any.whl", hash = "sha256:eb09aedbabfb650607e9b4b68c9d240b90b1e1be221d6ad71d61c52e29f7932b", size = 22496, upload-time = "2023-07-08T18:40:52.659Z" }, +] + +[[package]] +name = "sphinx-data-viewer" +version = "0.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/3a/7aeeb805327af5b0e6f072312f9bc660615045e791a5a8f7258276fdddd1/sphinx_data_viewer-0.1.5.tar.gz", hash = "sha256:a7d5e58613562bb745380bfe61ca8b69997998167fd6fa9aea55606c9a4b17e4", size = 103260, upload-time = "2024-08-28T10:34:21.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/60/5e902d53a5eb3ec7166a8eda602bd78d4b8671a73917567edc8f13a3b366/sphinx_data_viewer-0.1.5-py3-none-any.whl", hash = "sha256:b74b1d304c505c464d07c7b225ed0d84ea02dcc88bc1c49cdad7c2275fbbdad4", size = 8215, upload-time = "2024-08-28T10:34:20.136Z" }, +] + +[[package]] +name = "sphinx-needs" +version = "8.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonschema-rs" }, + { name = "minijinja" }, + { name = "requests" }, + { name = "requests-file" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "sphinx-data-viewer" }, + { name = "sphinxcontrib-jquery" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/c2/9db8259372467a85da7d07aa9f642d292f56feadebb37caab73683bbcfed/sphinx_needs-8.5.0.tar.gz", hash = "sha256:42d327baaf39f5041f692cb85609ef7023c0a73b688cde5803db444e577bb63d", size = 28245371, upload-time = "2026-09-03T11:42:25.929Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/96/e0a0b6fdf37460b7aaf8fb887922138aa23bbef7635ddaf09fb64823927a/sphinx_needs-8.5.0-py3-none-any.whl", hash = "sha256:aa7548d1ec33cd66cd0223cf8d5c0a934dc4c67d67ad471b5351b817d5f02750", size = 2767023, upload-time = "2026-09-03T11:42:23.717Z" }, +] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053, upload-time = "2024-07-29T01:09:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300, upload-time = "2024-07-29T01:08:58.99Z" }, +] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967, upload-time = "2024-07-29T01:09:23.417Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530, upload-time = "2024-07-29T01:09:21.945Z" }, +] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617, upload-time = "2024-07-29T01:09:37.889Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705, upload-time = "2024-07-29T01:09:36.407Z" }, +] + +[[package]] +name = "sphinxcontrib-jquery" +version = "4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331, upload-time = "2023-03-14T15:01:01.944Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae", size = 121104, upload-time = "2023-03-14T15:01:00.356Z" }, +] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787, upload-time = "2019-01-21T16:10:16.347Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" }, +] + +[[package]] +name = "sphinxcontrib-mermaid" +version = "2.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "pyyaml" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8c/87/06537dff20aa57df2d0f2afa87edff4afa85dec6f57f03f7acc24f83ff88/sphinxcontrib_mermaid-2.1.1.tar.gz", hash = "sha256:f8d7f1b2f0ad69b7ebdd5cbf532fb4ee107893b5373bc2d0e9634089c0b2cfee", size = 22353, upload-time = "2026-09-01T16:10:23.671Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/6a/5bf2222b8084c7a7bc3ec23d470c91e3e03e82e4ce0bbacaa61f456ce7c1/sphinxcontrib_mermaid-2.1.1-py3-none-any.whl", hash = "sha256:3b9ac1a8e0b5154dec3c0acf9b5c54dd9ba58540e416f20858c300814c25648f", size = 16368, upload-time = "2026-09-01T16:10:22.377Z" }, +] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165, upload-time = "2024-07-29T01:09:56.435Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743, upload-time = "2024-07-29T01:09:54.885Z" }, +] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080, upload-time = "2024-07-29T01:10:09.332Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, +] + +[[package]] +name = "starlette" +version = "1.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7b/2b/3850dc6bf7ef71b088962eba31dafc6cffd2f96e577ebb0bb316df96da3e/starlette-1.7.0.tar.gz", hash = "sha256:c79f74ea63cff761804fbbfb182f1e0b440c2d07b164d24700c5a1bab5d6ff5d", size = 2736246, upload-time = "2026-09-23T07:30:26.35Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/d6/1ec1b290f9e0fb067899b61e1d37a30c923068bad260b216dbe37a7d2967/starlette-1.7.0-py3-none-any.whl", hash = "sha256:67f8e99895493dd2911a03f11314af6ceebeae4e704bb9f43dfc6a9db151c93e", size = 78980, upload-time = "2026-09-23T07:30:24.567Z" }, +] + +[[package]] +name = "tomli" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload-time = "2026-03-25T20:21:10.473Z" }, + { url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload-time = "2026-03-25T20:21:12.036Z" }, + { url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload-time = "2026-03-25T20:21:13.098Z" }, + { url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload-time = "2026-03-25T20:21:14.569Z" }, + { url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload-time = "2026-03-25T20:21:15.712Z" }, + { url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload-time = "2026-03-25T20:21:17.001Z" }, + { url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload-time = "2026-03-25T20:21:18.079Z" }, + { url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload-time = "2026-03-25T20:21:18.978Z" }, + { url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload-time = "2026-03-25T20:21:20.309Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, + { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" }, + { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" }, + { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" }, + { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" }, + { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" }, + { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" }, + { url = "https://files.pythonhosted.org/packages/07/06/b823a7e818c756d9a7123ba2cda7d07bc2dd32835648d1a7b7b7a05d848d/tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54", size = 155866, upload-time = "2026-03-25T20:21:31.65Z" }, + { url = "https://files.pythonhosted.org/packages/14/6f/12645cf7f08e1a20c7eb8c297c6f11d31c1b50f316a7e7e1e1de6e2e7b7e/tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a", size = 149887, upload-time = "2026-03-25T20:21:33.028Z" }, + { url = "https://files.pythonhosted.org/packages/5c/e0/90637574e5e7212c09099c67ad349b04ec4d6020324539297b634a0192b0/tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897", size = 243704, upload-time = "2026-03-25T20:21:34.51Z" }, + { url = "https://files.pythonhosted.org/packages/10/8f/d3ddb16c5a4befdf31a23307f72828686ab2096f068eaf56631e136c1fdd/tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f", size = 251628, upload-time = "2026-03-25T20:21:36.012Z" }, + { url = "https://files.pythonhosted.org/packages/e3/f1/dbeeb9116715abee2485bf0a12d07a8f31af94d71608c171c45f64c0469d/tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d", size = 247180, upload-time = "2026-03-25T20:21:37.136Z" }, + { url = "https://files.pythonhosted.org/packages/d3/74/16336ffd19ed4da28a70959f92f506233bd7cfc2332b20bdb01591e8b1d1/tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5", size = 251674, upload-time = "2026-03-25T20:21:38.298Z" }, + { url = "https://files.pythonhosted.org/packages/16/f9/229fa3434c590ddf6c0aa9af64d3af4b752540686cace29e6281e3458469/tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd", size = 97976, upload-time = "2026-03-25T20:21:39.316Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1e/71dfd96bcc1c775420cb8befe7a9d35f2e5b1309798f009dca17b7708c1e/tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36", size = 108755, upload-time = "2026-03-25T20:21:40.248Z" }, + { url = "https://files.pythonhosted.org/packages/83/7a/d34f422a021d62420b78f5c538e5b102f62bea616d1d75a13f0a88acb04a/tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd", size = 95265, upload-time = "2026-03-25T20:21:41.219Z" }, + { url = "https://files.pythonhosted.org/packages/3c/fb/9a5c8d27dbab540869f7c1f8eb0abb3244189ce780ba9cd73f3770662072/tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf", size = 155726, upload-time = "2026-03-25T20:21:42.23Z" }, + { url = "https://files.pythonhosted.org/packages/62/05/d2f816630cc771ad836af54f5001f47a6f611d2d39535364f148b6a92d6b/tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac", size = 149859, upload-time = "2026-03-25T20:21:43.386Z" }, + { url = "https://files.pythonhosted.org/packages/ce/48/66341bdb858ad9bd0ceab5a86f90eddab127cf8b046418009f2125630ecb/tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662", size = 244713, upload-time = "2026-03-25T20:21:44.474Z" }, + { url = "https://files.pythonhosted.org/packages/df/6d/c5fad00d82b3c7a3ab6189bd4b10e60466f22cfe8a08a9394185c8a8111c/tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853", size = 252084, upload-time = "2026-03-25T20:21:45.62Z" }, + { url = "https://files.pythonhosted.org/packages/00/71/3a69e86f3eafe8c7a59d008d245888051005bd657760e96d5fbfb0b740c2/tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15", size = 247973, upload-time = "2026-03-25T20:21:46.937Z" }, + { url = "https://files.pythonhosted.org/packages/67/50/361e986652847fec4bd5e4a0208752fbe64689c603c7ae5ea7cb16b1c0ca/tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba", size = 256223, upload-time = "2026-03-25T20:21:48.467Z" }, + { url = "https://files.pythonhosted.org/packages/8c/9a/b4173689a9203472e5467217e0154b00e260621caa227b6fa01feab16998/tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6", size = 98973, upload-time = "2026-03-25T20:21:49.526Z" }, + { url = "https://files.pythonhosted.org/packages/14/58/640ac93bf230cd27d002462c9af0d837779f8773bc03dee06b5835208214/tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7", size = 109082, upload-time = "2026-03-25T20:21:50.506Z" }, + { url = "https://files.pythonhosted.org/packages/d5/2f/702d5e05b227401c1068f0d386d79a589bb12bf64c3d2c72ce0631e3bc49/tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232", size = 96490, upload-time = "2026-03-25T20:21:51.474Z" }, + { url = "https://files.pythonhosted.org/packages/45/4b/b877b05c8ba62927d9865dd980e34a755de541eb65fffba52b4cc495d4d2/tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4", size = 164263, upload-time = "2026-03-25T20:21:52.543Z" }, + { url = "https://files.pythonhosted.org/packages/24/79/6ab420d37a270b89f7195dec5448f79400d9e9c1826df982f3f8e97b24fd/tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c", size = 160736, upload-time = "2026-03-25T20:21:53.674Z" }, + { url = "https://files.pythonhosted.org/packages/02/e0/3630057d8eb170310785723ed5adcdfb7d50cb7e6455f85ba8a3deed642b/tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d", size = 270717, upload-time = "2026-03-25T20:21:55.129Z" }, + { url = "https://files.pythonhosted.org/packages/7a/b4/1613716072e544d1a7891f548d8f9ec6ce2faf42ca65acae01d76ea06bb0/tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41", size = 278461, upload-time = "2026-03-25T20:21:56.228Z" }, + { url = "https://files.pythonhosted.org/packages/05/38/30f541baf6a3f6df77b3df16b01ba319221389e2da59427e221ef417ac0c/tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c", size = 274855, upload-time = "2026-03-25T20:21:57.653Z" }, + { url = "https://files.pythonhosted.org/packages/77/a3/ec9dd4fd2c38e98de34223b995a3b34813e6bdadf86c75314c928350ed14/tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f", size = 283144, upload-time = "2026-03-25T20:21:59.089Z" }, + { url = "https://files.pythonhosted.org/packages/ef/be/605a6261cac79fba2ec0c9827e986e00323a1945700969b8ee0b30d85453/tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8", size = 108683, upload-time = "2026-03-25T20:22:00.214Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/da524626d3b9cc40c168a13da8335fe1c51be12c0a63685cc6db7308daae/tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26", size = 121196, upload-time = "2026-03-25T20:22:01.169Z" }, + { url = "https://files.pythonhosted.org/packages/5a/cd/e80b62269fc78fc36c9af5a6b89c835baa8af28ff5ad28c7028d60860320/tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396", size = 100393, upload-time = "2026-03-25T20:22:02.137Z" }, + { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, +] + +[[package]] +name = "urllib3" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/05/b17359e1cefb4f909b5e40b1b90a496d987258916dbbf88e842c729f510e/urllib3-2.8.0.tar.gz", hash = "sha256:63bf2ead4c879426ebf22ef2a781eeb4aa3b4ae798a0435506f8687fd5bb9b63", size = 458972, upload-time = "2026-09-15T19:29:36.253Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl", hash = "sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3", size = 135717, upload-time = "2026-09-15T19:29:34.577Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.54.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/34/30e9280707135d2cfc589dfff3cb796bd07a3aeb1a3e415ba09dd89d7bb4/uvicorn-0.54.0.tar.gz", hash = "sha256:a2e33cbfaa0306f8e6b0c13e0cb89d7d7a2da3e62b90c66e18c33d9807b28620", size = 112283, upload-time = "2026-09-25T06:52:37.601Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/0c/b54a4fdd7f90a3af8b02ebc9ce6712c2c208b7926a2f7bad95c33ebbe943/uvicorn-0.54.0-py3-none-any.whl", hash = "sha256:505bdb0f318731d45f1f712071fc781a8981f6847a31c902c9f5e652d4f67faf", size = 87427, upload-time = "2026-09-25T06:52:35.829Z" }, +] + +[[package]] +name = "watchfiles" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/68/e6aa0b77d217b31f8f486ec0cdfe5e00e6e38dc0be657e7d85819b9faf0a/watchfiles-1.3.0.tar.gz", hash = "sha256:99aee4a07847c06820765fd7b1b49ceac4f3f711ccb7d104655a33231de1c207", size = 108119, upload-time = "2026-09-21T09:08:55.664Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/fa/c0b840d5d8bafe640925408ce11095948c8945bb61be1e67d0ab629b872a/watchfiles-1.3.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:000b9688fc8133037a8b075c8ebf98f32844ff8964dda61e85c1db547dafc441", size = 399703, upload-time = "2026-09-21T09:08:13.518Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8a/894799b485fe9473ad10422a0d9668e53fb78e3a2b5cc6061159572844ad/watchfiles-1.3.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:bbc1198edfdc90fda0600f825aa94150f428dfcbf8138746f55998e0e660d64c", size = 397647, upload-time = "2026-09-21T09:08:15.16Z" }, + { url = "https://files.pythonhosted.org/packages/5a/61/f277cd5ead05f5d37b98b41fbdd0c943ee0c04d49738f62e902cb291cf43/watchfiles-1.3.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4af9c464d410e8c44b58ddf1cbec7c3a02c1cb2c6c80df9c74659ba2fbda0ab5", size = 454994, upload-time = "2026-09-21T09:08:16.587Z" }, + { url = "https://files.pythonhosted.org/packages/46/66/ea4c01382975e53b1ac1b0a0ea1b353416b8127fb6e04f5c1c313119aab6/watchfiles-1.3.0-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb94e40b9a0db19636b5e3fed0a9803452ecc7381df13b385272abb779ee83ca", size = 460105, upload-time = "2026-09-21T09:08:17.961Z" }, + { url = "https://files.pythonhosted.org/packages/31/c3/1a501b597817096c9831c255f6270c124ce0e2faeb74124be24dcc93b86d/watchfiles-1.3.0-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7398930a2b76b9dc67a4e6b8bfc7baf30946892a86f417a3920c07bdd6febc30", size = 493761, upload-time = "2026-09-21T09:08:19.327Z" }, + { url = "https://files.pythonhosted.org/packages/5a/16/77352d05e152c7786a016e9f1decdb4507e8aa5bcf3343c72142a0413d14/watchfiles-1.3.0-cp310-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:025b108f2d5cc2799cb941f79380df3e8b22bfb589c218e801767fe78d598c95", size = 577500, upload-time = "2026-09-21T09:08:20.723Z" }, + { url = "https://files.pythonhosted.org/packages/95/fe/81001c55b24466fe9911135e50269fd3a29f43e446627a92adfab54553b6/watchfiles-1.3.0-cp310-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:be9ef3cd403d756a304a0a08a112163c63da7ec72c8c9d083c98818291ff8f29", size = 469209, upload-time = "2026-09-21T09:08:22.346Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cf/e3ad894ed5909a7c44b0707e89bc25d19a3d78b3a7aec846119443b6ae56/watchfiles-1.3.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5768b49e426fd5b550b012c866db347cdf15c398ef98dc557b6e6b72fa74cd1", size = 458353, upload-time = "2026-09-21T09:08:23.7Z" }, + { url = "https://files.pythonhosted.org/packages/7f/f5/2f106829e6e2bc91ad74614730f6df484202b9a4d20d927dbf2f08d37d44/watchfiles-1.3.0-cp310-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:d36c72fcdc08f143d87316a4c4c3b064e340da2c7383d39803950740ed418935", size = 468707, upload-time = "2026-09-21T09:08:25.167Z" }, + { url = "https://files.pythonhosted.org/packages/15/37/2741ab776b978669c1f3bba1e573f1a184f727ab8b4d3a6d9c61090800ed/watchfiles-1.3.0-cp310-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:f0c9865240e065a2247f4b5248528ae3d01e0e8ae071462c250c884dc16e3ee3", size = 632510, upload-time = "2026-09-21T09:08:26.532Z" }, + { url = "https://files.pythonhosted.org/packages/48/64/db4a4684275fe9b696ee5118c194705c1423b3d42181c3f8ee70194d5c73/watchfiles-1.3.0-cp310-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:380f513d26cc2e598266b88d66456e07d67ef4be8f0f435a1154d9c44b43d509", size = 661723, upload-time = "2026-09-21T09:08:28.004Z" }, + { url = "https://files.pythonhosted.org/packages/52/80/95ddb24f6a2f595c031c24432ab7b8aa7d6d1ada0c6d63a552166e06e8d1/watchfiles-1.3.0-cp310-abi3-win32.whl", hash = "sha256:509d9f74d2bec5c1f4cd868ddcfe0c9601f7ea53066dfcb19d8ede742c4de661", size = 277761, upload-time = "2026-09-21T09:08:29.335Z" }, + { url = "https://files.pythonhosted.org/packages/48/a1/1c4a1b3c8030cd03206232612be8a6e8799093490c220b0fcb935d02b75a/watchfiles-1.3.0-cp310-abi3-win_amd64.whl", hash = "sha256:1acabde19b67e673274e89a04d613b7fb1f122e2c4b8ec9a581e59c149264b61", size = 290643, upload-time = "2026-09-21T09:08:30.45Z" }, + { url = "https://files.pythonhosted.org/packages/82/e0/d2db577c632d26d08078c4390dd870b8555c4e558df25d22270f0166c71f/watchfiles-1.3.0-cp310-abi3-win_arm64.whl", hash = "sha256:d978cc1dd7ba44f5590d7de74f7a9c8be7262d9e469c2c0efb8bbfc2574321dc", size = 285510, upload-time = "2026-09-21T09:08:31.561Z" }, + { url = "https://files.pythonhosted.org/packages/4f/55/a122743607939429ab6a7272672f49303aa02bbd34c3f06676765a3861de/watchfiles-1.3.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:e0204f90677b7fb8d3a824279a71a01166bea9f6e53923b8056592d87b33b0b6", size = 395978, upload-time = "2026-09-21T09:08:32.747Z" }, + { url = "https://files.pythonhosted.org/packages/3e/9d/0ee1b0ea42acfe72afa2484f0222e2386dd09992e9034a81e63cc3cdab0a/watchfiles-1.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7c1125e99f84934a92996ae343501285617373acd66f16b59fd5654b27ad8d80", size = 387997, upload-time = "2026-09-21T09:08:33.953Z" }, + { url = "https://files.pythonhosted.org/packages/b7/f2/4319c6b683e8bd28465dfc53c750617a2a07f072eb2e3ab0182ccf812229/watchfiles-1.3.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a85e243c87109d9f48a2e0d10d6abdee8768cc114848b32281ec83d7f81d86ef", size = 448067, upload-time = "2026-09-21T09:08:35.104Z" }, + { url = "https://files.pythonhosted.org/packages/b7/71/9f37ac192a51a24de3a2d7fe9aac1e99b2b2668300674ff7a9f85d95beb1/watchfiles-1.3.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd538c71766c59c732e2c5cedc39323c99c11897b99f93eac773438e54af206a", size = 452881, upload-time = "2026-09-21T09:08:36.238Z" }, + { url = "https://files.pythonhosted.org/packages/34/07/1224667c32a4a96876ddd642da69733cbfe6a15897db0865aec5a882cebc/watchfiles-1.3.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da213822ec9082b62cadf3008e07a8c690ec7a3c89f6dc5e55a8cf07b56a1b26", size = 484802, upload-time = "2026-09-21T09:08:37.717Z" }, + { url = "https://files.pythonhosted.org/packages/bd/4d/7f29cd87e1f826df86fc0418d0b8f370ca0311c29c618406dc492aad9951/watchfiles-1.3.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4593392e87669836670f87d62fc754059eaeb0e6157af44060a46558cebe5a3", size = 567522, upload-time = "2026-09-21T09:08:38.94Z" }, + { url = "https://files.pythonhosted.org/packages/e3/ac/3aa1f84abd4dbbfbae99a817dd931f77b439261c911189cad4c30fdfd470/watchfiles-1.3.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26b81bc515a0f03f66a69a6fea86eea54c8eca4173c46dd7222569f79dd2f977", size = 461997, upload-time = "2026-09-21T09:08:40.142Z" }, + { url = "https://files.pythonhosted.org/packages/82/1c/27c66764d5b0dbb70a36770a32eca217eba739c28b24e8583a035087a3d7/watchfiles-1.3.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca39661934749df580d89f3dde266f2af7c6968f4c21c72ce2dc387d299e6aa7", size = 451856, upload-time = "2026-09-21T09:08:41.305Z" }, + { url = "https://files.pythonhosted.org/packages/1e/b3/a45827084d953c1d0dd3d75abf85dcac26a0f5d115ad2fe0b7e9e931573b/watchfiles-1.3.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:04c5500faa725d69a99b0f63750e80795e455bb951849e9c98a811b4324997c4", size = 459889, upload-time = "2026-09-21T09:08:42.58Z" }, + { url = "https://files.pythonhosted.org/packages/7a/3d/07740d23ce2bb23419bb24055c435a9abe5fe03efdaea1ba0720b831aab6/watchfiles-1.3.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:ec3cd4bb181a7b6329134204c2277c7144ab5f62cce9c5335d6f901ee7ce8d6a", size = 624482, upload-time = "2026-09-21T09:08:44.064Z" }, + { url = "https://files.pythonhosted.org/packages/91/46/9540f8123eaec86df989f26d7704cad0448d9fb7271763a4f8f9fe23617d/watchfiles-1.3.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:e5871d4a7f788a9f64fb06f5793389d29d171e5c32d37c3ebfd520b017cc7694", size = 653724, upload-time = "2026-09-21T09:08:45.257Z" }, + { url = "https://files.pythonhosted.org/packages/25/9d/b9deb52f1e4528ffe44338c5ebab95c32ed79203082da661de50288e130a/watchfiles-1.3.0-cp314-cp314t-win32.whl", hash = "sha256:81c989d7267bfb7b676cd32c83bec97914e396870983cbf493e29415037bff5e", size = 270863, upload-time = "2026-09-21T09:08:46.518Z" }, + { url = "https://files.pythonhosted.org/packages/59/59/8b1881afccbafda06248be4185e28034dd73c80c85e4da24f2cb0c1321eb/watchfiles-1.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d754e049006e81a9be49dc78ba7802081cee426e968cbc63ee19e164fa2d0e39", size = 286879, upload-time = "2026-09-21T09:08:47.874Z" }, + { url = "https://files.pythonhosted.org/packages/46/dd/41c12ae9745d5d72f709333287679d71cbba68ad7678fed872207bba94f4/watchfiles-1.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:a5b631db08fd3032db57ec6a92d1777cd60f88803287e4e941a4858c53aab1e0", size = 276924, upload-time = "2026-09-21T09:08:48.976Z" }, + { url = "https://files.pythonhosted.org/packages/cd/eb/289fec71eba51d6c3ef3a28c81f7213f4e860084ffae5abc866933c564f0/watchfiles-1.3.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:45726c6b5a8d67c8087eb2933c4398948546d04206ef40f629dc4881d65d23d1", size = 396932, upload-time = "2026-09-21T09:08:50.217Z" }, + { url = "https://files.pythonhosted.org/packages/92/cc/a3c3f557992a20a5bb24607f0da44d39cf6d6ba3f8f6ed7cb31f6c73371a/watchfiles-1.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:6398d250994baff581147ccba846223076fe6492ca93c0d1b3588fcf5355eb5c", size = 394852, upload-time = "2026-09-21T09:08:51.412Z" }, + { url = "https://files.pythonhosted.org/packages/55/65/d45763a5e1108a65af85a217af2930ebf1081c73fd8169d3f75e586992bb/watchfiles-1.3.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:591de392458bca26f6130fea4e667c06b657e873ad334ea06fad5a79f5086cef", size = 451789, upload-time = "2026-09-21T09:08:53.144Z" }, + { url = "https://files.pythonhosted.org/packages/02/96/165c6e540bf765ca1115062017adf861d0816525f02464ba71313fe7cf92/watchfiles-1.3.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ec46a1ff4c1d81405a5fc645abdbff5e4e9388f7c9a6cdb392316a7c29b884f", size = 456919, upload-time = "2026-09-21T09:08:54.372Z" }, +] + +[[package]] +name = "websockets" +version = "16.1.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +sdist = { url = "https://files.pythonhosted.org/packages/21/f7/bc3a25c5ec26ce62ce487690becc2f3710bbc7b33338f005ad390db0b986/websockets-16.1.1.tar.gz", hash = "sha256:db234eda965dcce15df96bb9709f587cd87d4d52aaf0e80e2f34ec04c7670c57", size = 182204, upload-time = "2026-07-17T22:51:05.858Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/e7/d1671fb984f9dd844e1da5288070c7c23c9eaba3082d3871aae19c3ab8b9/websockets-16.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:49ae99bdfcae803a885c926bf14f886196e84925395bb3f568fef5c0f0979d7d", size = 179570, upload-time = "2026-07-17T22:48:24.032Z" }, + { url = "https://files.pythonhosted.org/packages/99/f5/70df723bf571f5e0b1b845e0a4ff1c966eeb84f667599fc251caa37d15a3/websockets-16.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5bfd1ac19b1b9986a9c95a82d5e23a391ebb09e12c34d7be6094b86efcc35731", size = 177252, upload-time = "2026-07-17T22:48:25.775Z" }, + { url = "https://files.pythonhosted.org/packages/90/72/2f14b2e167170b8bf1c8bb7f9b0d78000f470d41a2085a91f33e3917b6c9/websockets-16.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9246a0d063cfcbcc85f2359dd6876d681213f4790832272aa16641b4ed5d64d4", size = 177530, upload-time = "2026-07-17T22:48:27.337Z" }, + { url = "https://files.pythonhosted.org/packages/f3/18/a17e2f0cde02dc10154c808deed7e1d8528afff93612f70d3f0a5b19b011/websockets-16.1.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1214e673c404684b9bf7154f5cf43b45025b1a6160fac3a9e438e9c1a97e22cb", size = 186038, upload-time = "2026-07-17T22:48:28.756Z" }, + { url = "https://files.pythonhosted.org/packages/d5/b0/41de283899cf5929d637b72a508cdbc9aa40dc0f317c6b77613fd1000488/websockets-16.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90001d893bc368e302ef168d82130b4e4fdd27b85fa094682df9b667c2d48838", size = 187278, upload-time = "2026-07-17T22:48:30.328Z" }, + { url = "https://files.pythonhosted.org/packages/50/61/874aab5257e027f9f61b5004cec65e592babca7942b1bc09f38e72b7f1fd/websockets-16.1.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:130937b167a52af203c8d58e78d67705874e82759862e3b9671a452fec4abc87", size = 189936, upload-time = "2026-07-17T22:48:31.896Z" }, + { url = "https://files.pythonhosted.org/packages/a6/1a/42173913ac5519607220849ed417c864d77384e4119f06dbba964a50f096/websockets-16.1.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c9f23004a3d40e89c01a7955d186a6cc83418d93b749701944ce2de3e95a1f3", size = 187796, upload-time = "2026-07-17T22:48:33.344Z" }, + { url = "https://files.pythonhosted.org/packages/1b/f4/37c1840bd89b529479aec41470b97b7c683b107ca90b6399ac5afb99dedf/websockets-16.1.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f55f0b01956a094c8587146d9558c91937e78789c333860ffaf35931a6e5dbc4", size = 186481, upload-time = "2026-07-17T22:48:34.843Z" }, + { url = "https://files.pythonhosted.org/packages/9e/70/652d9b964adcfbeb056f42e0ca6bece34d108fe75534e74df20643cae199/websockets-16.1.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6aaface73b9c71974c6497366d8b9628357f6c9749e09c4ea3610176c63f2ae3", size = 184351, upload-time = "2026-07-17T22:48:36.307Z" }, + { url = "https://files.pythonhosted.org/packages/13/f1/af3850e5d48d482921985be72ebcb169c6180b3a77b57bd612deebcee23b/websockets-16.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dc0fad4933f427acd5b1cec210f3ea6dce7089e1724e4b9ec6ef47c6c04d1b3b", size = 186791, upload-time = "2026-07-17T22:48:37.762Z" }, + { url = "https://files.pythonhosted.org/packages/1d/40/1a4e3ed4969ec378dcad337e5f1472c5e292cb3e733bc392f0dc2e230abd/websockets-16.1.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f2769a0344a09e9ccf5b3cce538bc75a51b53eff3275d3896310c8552049195d", size = 185413, upload-time = "2026-07-17T22:48:39.127Z" }, + { url = "https://files.pythonhosted.org/packages/aa/3e/4e3fa1afe8f1a6a780434cd9ba8eb422632b044eff3dd73f6af67523c147/websockets-16.1.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f70541f3104339f59f830522d94ebadb1bf47426287381623443d8bb1cdbf33d", size = 187178, upload-time = "2026-07-17T22:48:40.676Z" }, + { url = "https://files.pythonhosted.org/packages/71/ab/dd742766aa5dda7f349be0de49e4d565b84cf6f7f7fa02e07692f0f2bdd9/websockets-16.1.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:dc385593a42e31cd6fb60c19f0ecb015b386603818fc2c6c274fb42bd2bb4165", size = 185051, upload-time = "2026-07-17T22:48:42.098Z" }, + { url = "https://files.pythonhosted.org/packages/ae/f5/76438c6560f416f1c0a7f587679fb97cc6e99ed336011d43ce2002dd27c1/websockets-16.1.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:387e8e4aa5df2f90b198fa3cad3478822a89cf905b6a6d6c97dc3664689640cc", size = 185846, upload-time = "2026-07-17T22:48:43.472Z" }, + { url = "https://files.pythonhosted.org/packages/62/12/5c0320f2127823d27b2d56d611d31b0b284ad4edcb41364d66bf4c92b537/websockets-16.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fd46fff7eb62c24804d234f0051c7a8ea81285ad63e0337d3dcf33ca82aee58a", size = 186066, upload-time = "2026-07-17T22:48:44.884Z" }, + { url = "https://files.pythonhosted.org/packages/a2/97/875986b857b955c3f9dd192cb8a1af81254dfb2ea22cc9590f0a1e020b8b/websockets-16.1.1-cp310-cp310-win32.whl", hash = "sha256:7883388947767080f094950b342b30d35a2a06b849cd967c422fa0db72b40ea9", size = 179940, upload-time = "2026-07-17T22:48:46.481Z" }, + { url = "https://files.pythonhosted.org/packages/54/82/1013a5fe7ddae8e102bc3b4b39db81d8d28fd02100a324ce6ede8cd832b1/websockets-16.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:d57685547e0060cc6fd90ee6a28405d6bd395e525545f13c8d7cd99c78afd79f", size = 180239, upload-time = "2026-07-17T22:48:48.043Z" }, + { url = "https://files.pythonhosted.org/packages/2b/03/47debfe28e9d6d354be5d777b67fd44c359b9eb299a5d103500bd7cc3e37/websockets-16.1.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d0fcf657e9f13ff4b177960ab2200237b12994232dfb6df16f1cfe1d4339f93c", size = 179566, upload-time = "2026-07-17T22:48:49.596Z" }, + { url = "https://files.pythonhosted.org/packages/72/93/31efa1ed78c17e5cfc229fd449e3966e1b9cc15753204cd585cc8dd01f4a/websockets-16.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b852788aa51764e2d8e4cf5493d559326bcae5e38d16ba25ffa322b034df272a", size = 177250, upload-time = "2026-07-17T22:48:50.942Z" }, + { url = "https://files.pythonhosted.org/packages/01/4a/542378ab3972b0c1cf1df3df3eff9591cea0d30c58c3aa3c4ddbc244e787/websockets-16.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1427fb4cf0d72f66333e2cacc3ff5f575bf2d7008166ce991a4a470b21d51a22", size = 177528, upload-time = "2026-07-17T22:48:52.59Z" }, + { url = "https://files.pythonhosted.org/packages/33/d9/162321f63c7eed558e9e1798ed7a1e34a4f6dab51f35419e4ed7a4907979/websockets-16.1.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:da4ca1a9d72f9030b3146b8d7022719a9f3d478f61efe6f7dd51d243f61c51b2", size = 186859, upload-time = "2026-07-17T22:48:53.915Z" }, + { url = "https://files.pythonhosted.org/packages/de/09/87df740f7430ce564bd52402e9c9458d4d0459cc7d2ee29e530c8204851b/websockets-16.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:86d7f0f8bdb25d2c632b72527325e4776430fd5bc61b9118de4e2b8ddb5f5b01", size = 188095, upload-time = "2026-07-17T22:48:55.384Z" }, + { url = "https://files.pythonhosted.org/packages/d2/12/3d2703af7cc095f3c81904c92208cc1ae79affbc67376944b50ee9301f73/websockets-16.1.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7dfcad78ea1492ee3a9ec765cb7f51bbc17d477107aaf6b22abf7b2558d1c5a0", size = 191385, upload-time = "2026-07-17T22:48:56.742Z" }, + { url = "https://files.pythonhosted.org/packages/1d/69/986aa0234a964a00f5149cfc46e136e96c8faad1c783474550f40d31aef4/websockets-16.1.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fb9a0a6dc3d1b3986cb88091b6899f0396651e0f74e2c9766ab8d6ffc3842e29", size = 188653, upload-time = "2026-07-17T22:48:58.134Z" }, + { url = "https://files.pythonhosted.org/packages/35/6b/10f9d03e3970a69ba67bd3b46b87a929b586d0300fadbfe14f57c1f85490/websockets-16.1.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29dfa8114c4a620c69591c5973860f768eac29d3fd6904f37f34266cb219c512", size = 187426, upload-time = "2026-07-17T22:48:59.515Z" }, + { url = "https://files.pythonhosted.org/packages/56/db/bb3aad62bf63d8bb3f0634b2eabffcfb3677a34bd19492110ff6869cf703/websockets-16.1.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6ff9417c0ada4d0f7d212f928303e5579bdf3ace4c802fa4afabb30995da58c3", size = 184882, upload-time = "2026-07-17T22:49:00.916Z" }, + { url = "https://files.pythonhosted.org/packages/6c/4c/c09a2ea9bfbeccce52fdc383e5f28af4bc8843338aabac28c81489af6120/websockets-16.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fe0b50da2d84535fb4f7b4bfa951280f97ce3d558a0443b541166d609e67b57", size = 187584, upload-time = "2026-07-17T22:49:02.283Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8b/31bb4eb4d9eaacf1fdd39d115772a8aeaedfc19b5dc262e57ffbc8a9d42c/websockets-16.1.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:34420aaa64440ebd51ac72ca8a45ef4626429438c9b02e633ae412ed43f925d3", size = 186174, upload-time = "2026-07-17T22:49:03.973Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e4/dc02d725610a1ad49e193ef91a548194d71bdc6cdf27da83067dd1f73995/websockets-16.1.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a6a61aff018180c9c50b7b0da33bfd29d378af3497429c95006c589a23a11648", size = 187986, upload-time = "2026-07-17T22:49:05.553Z" }, + { url = "https://files.pythonhosted.org/packages/e0/73/30ed84c8bfd14c73d4af29d5ed9323c3073b48e0b7b23b67070f4e7fd59b/websockets-16.1.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:04fd29a0e2fe9414a95b00e92c67ae51bf900c50c0f8a4b2dafdad621f49ea1d", size = 185565, upload-time = "2026-07-17T22:49:06.959Z" }, + { url = "https://files.pythonhosted.org/packages/7d/d3/4be8d4959f51e31b4f8fc0ece12b45bd3b6c0d15ea23b9990d9c11fc805f/websockets-16.1.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5c31aa7e39ee3e8a358573257f1c0bb5c52430d1b637030dd9c8cc2c282926be", size = 186598, upload-time = "2026-07-17T22:49:08.293Z" }, + { url = "https://files.pythonhosted.org/packages/26/fa/abb38597a52d84ed9cfacadc7a0c6f2db282c0ab23cdf72b58a666a21227/websockets-16.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d14bfb217eb4701e850f1525c9d29d79c44794cdf1c299ead25f39f8c78dea81", size = 186834, upload-time = "2026-07-17T22:49:09.766Z" }, + { url = "https://files.pythonhosted.org/packages/59/80/1119ad08a228b90c4eb77fbe48df7836731a605f5f881ba701ca826a4a65/websockets-16.1.1-cp311-cp311-win32.whl", hash = "sha256:2e28e602bb13da44fbe518c1781a88e3b9d4c3d48d02c9bad83e546164336f57", size = 179940, upload-time = "2026-07-17T22:49:11.196Z" }, + { url = "https://files.pythonhosted.org/packages/71/b2/e511c1c6f64a95c2f3fc54bffda0e14eaa7e9442be605c29270f7589b918/websockets-16.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:7421fad442de870a8cbf2287d1cad7e706ece0dbfeba5e911df132cbdc1cb56a", size = 180239, upload-time = "2026-07-17T22:49:12.519Z" }, + { url = "https://files.pythonhosted.org/packages/17/9d/681cda21c9eee743203a6cb79b9d3d05adad9aa60ec660c6c9bf4dd619ca/websockets-16.1.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:cc97814dfb786a83b6e2dc2e79351e1b83e6d715647d6887fcabd83026417a00", size = 179600, upload-time = "2026-07-17T22:49:13.92Z" }, + { url = "https://files.pythonhosted.org/packages/fb/8d/6195a88b45e8d2a8f745fc2046e36f885a3c9763e6767d2c46229bf9510c/websockets-16.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e047dc87ef7ca50f4d309bf775ad4a71711c58556d75d7bd0604b2317f43e94b", size = 177272, upload-time = "2026-07-17T22:49:15.453Z" }, + { url = "https://files.pythonhosted.org/packages/73/e3/fe2d498c64dea0095c9a9f9a351af4cd6eef31b618395582bc1f38ba45ff/websockets-16.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:01fbdcbac298efe19360b94bc0039c8f746f0220ba570f327577bfee81059175", size = 177542, upload-time = "2026-07-17T22:49:16.875Z" }, + { url = "https://files.pythonhosted.org/packages/fe/ed/f1831681fce0e3242346e5458486003c5f124ed69e5e0b847fd029db4973/websockets-16.1.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0f62863e8a00a6d33c3d6566ec0b89f23787b747ffe0c3bc71ec0e76b82c94b1", size = 187137, upload-time = "2026-07-17T22:49:18.323Z" }, + { url = "https://files.pythonhosted.org/packages/6f/79/4ff9dcc1bb46f6b4c536936dde1fd60f9b564f3304307274db97f4c9496d/websockets-16.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8087e82f842609734c9b5a1330464f8e94e346ba0e18c832c08bafa4b0d63c15", size = 188374, upload-time = "2026-07-17T22:49:19.65Z" }, + { url = "https://files.pythonhosted.org/packages/62/c3/5c49b6efb36cab733d23773f6de575e1dba65736ead17d5d2b2a1daef779/websockets-16.1.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2bb5d041a8307d2e18782e7ce777f6fdb1e8c2f5d09291484b18c294b789d9aa", size = 191155, upload-time = "2026-07-17T22:49:21.331Z" }, + { url = "https://files.pythonhosted.org/packages/6e/f6/56ccceda3a4838d18f1d40821480da4775397e8b1eecf4031e20c50e2e90/websockets-16.1.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1db4de4a0e95673f7545d393c49eeb0c2f18ac1ef93073218c79d5cdb2ee75ab", size = 189011, upload-time = "2026-07-17T22:49:22.889Z" }, + { url = "https://files.pythonhosted.org/packages/86/d6/ad5286241a2bce1107e2798d3bfbd62cf79aee167bdb654f8cb1e9dbf949/websockets-16.1.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f17dbe07eb3ea7f99e4df9b7e0efefe80fbf30d37a8cc4d561a0aed310bc8847", size = 187766, upload-time = "2026-07-17T22:49:24.339Z" }, + { url = "https://files.pythonhosted.org/packages/bc/67/d65c970b7e347fdca69479beb7811c2060529956730a7a4e3ae7c66b0e31/websockets-16.1.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4b57693728576d84ede0a77987ab16881b783d2cd9f1dc180a8fbbc3f79c4428", size = 185173, upload-time = "2026-07-17T22:49:25.743Z" }, + { url = "https://files.pythonhosted.org/packages/1d/5b/14af3cd4ee69d8ea9baca58f3dc3cfb1ba78332a347fd478cb096549d60e/websockets-16.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2a636ff1e7a5c4edf71ef0e79adae7f25dba93b4fcbe3dc958733477ffeb0eaf", size = 187809, upload-time = "2026-07-17T22:49:27.147Z" }, + { url = "https://files.pythonhosted.org/packages/7b/11/be301710d70de97e3e7b3586e6d492c9c06d6a61bf1c2202c36cf0c75607/websockets-16.1.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d6bec75c290fe484a8ba4cacdf838501e17c06ecfbbf31eede81a9e431bd7751", size = 186412, upload-time = "2026-07-17T22:49:28.611Z" }, + { url = "https://files.pythonhosted.org/packages/db/07/fe1435bf6fe738a3d3b54dbe0c18dabf12cba4d909ac8b58b539ce27c1f4/websockets-16.1.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:54509b8e92fee4453e152b7558ddef37ce9705a044922f2095a6105e3f80c96f", size = 188290, upload-time = "2026-07-17T22:49:29.965Z" }, + { url = "https://files.pythonhosted.org/packages/8a/0a/81f394aff8efcbb01208c1ced77df0a3c7fcce584a88c7273663697946c2/websockets-16.1.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:f0aa4aad3b1b69ad3fd85a0fd0952ec64331c762bd77ec51cc814170873890b2", size = 185844, upload-time = "2026-07-17T22:49:31.447Z" }, + { url = "https://files.pythonhosted.org/packages/39/5c/dd485b995473f415510251fe9bd708f2d24458f439fce958daf8d66dc7c6/websockets-16.1.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:42290eb6db4ccaca7012656738214f8514082fb6fa40cdeb61bb9a471b52e383", size = 186823, upload-time = "2026-07-17T22:49:33.104Z" }, + { url = "https://files.pythonhosted.org/packages/9d/0b/f78de76ff446f1e66af12b43c48a35f31744de93cfdec2f4ea67d5d7bbf1/websockets-16.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:53260c8930da5771cec89439bff99c20c8cb03ddb9588b980697355a83cd4bd3", size = 187102, upload-time = "2026-07-17T22:49:34.616Z" }, + { url = "https://files.pythonhosted.org/packages/37/a1/4cf892007778eaf84ad162bfc98046e0ed89b63ac55949e3236626b2a23f/websockets-16.1.1-cp312-cp312-win32.whl", hash = "sha256:1d27fa8462ad6a1cb36206a3d0640b2333340def181fae11ed7f9adeaa5c0747", size = 179943, upload-time = "2026-07-17T22:49:36.213Z" }, + { url = "https://files.pythonhosted.org/packages/d9/de/6abe251d28c3a3f217096575400b27750b18e0b1d2fff3a2a239960fea07/websockets-16.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:b436f6ec4fc3a6b4237c84d3f83170ed2b40bb584222f0ac47a0c8a5921980c7", size = 180243, upload-time = "2026-07-17T22:49:37.626Z" }, + { url = "https://files.pythonhosted.org/packages/ce/fd/6ec6c6d2850aea25b1b2aa9901a016980bb87d01e89b3eb00470b1b5d471/websockets-16.1.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ab59169ace05dcb49a1d4118f0bde139557adf45091bd85747e36bf5de984dd1", size = 179587, upload-time = "2026-07-17T22:49:38.959Z" }, + { url = "https://files.pythonhosted.org/packages/5f/d8/1d299d2dd34087db39831a34cc645ef8a6f89d78efada6983093513cd81c/websockets-16.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5e3b7d601f6f84156b08cc4a5e541c2b50ad7b36cfc302b657a12477c904a5df", size = 177272, upload-time = "2026-07-17T22:49:40.293Z" }, + { url = "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cd2ca96a082a36964aca83e992f72abeb61b7306c1a6cba4c7d06a7b93750cac", size = 177530, upload-time = "2026-07-17T22:49:41.786Z" }, + { url = "https://files.pythonhosted.org/packages/b5/c2/c676c69444d9db448b3f0a55a98dcc534affce0bce961d9d2f0b8499b10a/websockets-16.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f5d497865f05bb222cab7016c6034542e84e5f29f49c6fd3f4939cda7197b5b8", size = 187197, upload-time = "2026-07-17T22:49:43.658Z" }, + { url = "https://files.pythonhosted.org/packages/0b/13/88137fbaf726ebe29d62c1117fa11fa2bbb6209dc79d4ad738efbe36a2aa/websockets-16.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bae954c382e013d5ea5b190d2830526bfa45ad121c326da0049b8c769f185db6", size = 188433, upload-time = "2026-07-17T22:49:45.147Z" }, + { url = "https://files.pythonhosted.org/packages/01/6d/46c2f2ce6751cb26f39293e1ecbf8544cb01321397cd476c2756b98c216d/websockets-16.1.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e09f753a169951eb4f28c2c774f71069304f66e7277e0f5a2892423599cfa854", size = 189868, upload-time = "2026-07-17T22:49:46.581Z" }, + { url = "https://files.pythonhosted.org/packages/29/2b/170a9e8097636cfde4dc3c592b6e00b18a44a2f5407606d96ca542dd5838/websockets-16.1.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:024193f8551a2b0eafbdd160911012c4e6c228c28430c84433253299a9e42d6a", size = 189059, upload-time = "2026-07-17T22:49:47.972Z" }, + { url = "https://files.pythonhosted.org/packages/a7/48/f0d4ebc9ab4b473b8861b9e20fdb663d515d42f7befdf62cdb60fee7a1ec/websockets-16.1.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:aabe464bfd13bd25f4821faf111da6fefdc389f870265a53105580e45b0a2e49", size = 187814, upload-time = "2026-07-17T22:49:49.344Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ba/39a41d3ae8e72696a9492581900611c5a91e2b07563b0bcd2523adea9854/websockets-16.1.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a28fcbc9b6baf54a2e23f8655f308e4ccc6afdd7266f8fe7954f320dcda0f785", size = 185229, upload-time = "2026-07-17T22:49:50.787Z" }, + { url = "https://files.pythonhosted.org/packages/3c/36/ac15b604f850d1907f0a85ed721cefe47cd45034b3620069b829746cccbe/websockets-16.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79eace538c6a97e96d0d03d4f9d314f9677f5ed85a8a984992ffd90b13cb8a56", size = 187874, upload-time = "2026-07-17T22:49:52.228Z" }, + { url = "https://files.pythonhosted.org/packages/a8/f3/3fbd5d71d59299c3770faa5884d4f45070236ca5a35ab3a61830812c409a/websockets-16.1.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:496af849a472b531f758dbd4d61338f5000538cb1a7b3d20d9d32a264517f509", size = 186469, upload-time = "2026-07-17T22:49:53.776Z" }, + { url = "https://files.pythonhosted.org/packages/b4/fc/dd90349bba58af2a53ef2ddd9c32716c81eb6d59a0687939fff561860878/websockets-16.1.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5283810d2646741a0d8da2aa733d6aefa0545809afccb2a5d105a26bc45125f1", size = 188347, upload-time = "2026-07-17T22:49:55.202Z" }, + { url = "https://files.pythonhosted.org/packages/4c/f3/f73ba86427682da59b78c11d77ba56d5b801c32e84afe79b274bbd6a9bb2/websockets-16.1.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:4e3b680b1e0a27457e727a0d572fd81dffa87b6dbf8b228ab57da64f7d85aead", size = 185903, upload-time = "2026-07-17T22:49:56.75Z" }, + { url = "https://files.pythonhosted.org/packages/34/7c/f95eb20e80104173b3a0a092291f89ea4047ef6e608e0a57ca06eb14eecb/websockets-16.1.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:69159730a823dde3ea8d08783e8d47ef135a6d7e8d44eb127e32b321c9db8e3e", size = 186855, upload-time = "2026-07-17T22:49:58.467Z" }, + { url = "https://files.pythonhosted.org/packages/b0/35/dd875b3e050ff232d60fa377707f890e369f74d134f1be32e8f68879747c/websockets-16.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ed5bb271084b46530ee2ddc0410537a9961152c5ccba2fc98c5276d992ccba87", size = 187140, upload-time = "2026-07-17T22:50:00.016Z" }, + { url = "https://files.pythonhosted.org/packages/e8/dc/5cbfcb41824502f6af93b8f3943a4d06c67c23c7d2e31eb18748c4a5b2a7/websockets-16.1.1-cp313-cp313-win32.whl", hash = "sha256:cfb70b4eb56cac4da0a83588f3ad50d46beb0690391082f3d4e2d488c70b68ea", size = 179928, upload-time = "2026-07-17T22:50:01.685Z" }, + { url = "https://files.pythonhosted.org/packages/b0/c1/71e5deb5b7f8f226997ab64908c184ac3105c0155ce2d486f318e5dd08a8/websockets-16.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:d9531d9cbeac99af6f038fb1bc351403531f7d634a2c2e10e2f7c854c6ed5b68", size = 180242, upload-time = "2026-07-17T22:50:03.117Z" }, + { url = "https://files.pythonhosted.org/packages/73/a2/ba78a164eeea4620df4a4df4bd2ed6017438c4655cc0f36f2c0bc0432355/websockets-16.1.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:443aefe96b7fdb132e2a70806cca1f2af49bb3f28e47abcd7c2e9dcf4d8fa1b8", size = 179635, upload-time = "2026-07-17T22:50:05.001Z" }, + { url = "https://files.pythonhosted.org/packages/b9/08/d26d7a7628cd4ac34cbbdb63ac80914ca842ed8e42938c40a53567806df3/websockets-16.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6456ff333092d509127d75a638cb411afae8ff17f092635015d1902efec8a293", size = 177320, upload-time = "2026-07-17T22:50:06.427Z" }, + { url = "https://files.pythonhosted.org/packages/0f/45/ebec83e6269536aa5932533c67b0af5c781f3e73fdbcd68672dcf43f4f44/websockets-16.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fce6c48559c86d1ac3632ccb1bebc7d5442fbe79bd9bb0e40379ee54be2a4051", size = 177544, upload-time = "2026-07-17T22:50:07.834Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d5/abc614d2297f6c1c3e01e61260364457a47c25cc1cf6a879038902bc6aa8/websockets-16.1.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:92b820d345f7a3fc7b8163949ee92df910f290c3fc517b3d5301c78065adafe1", size = 187270, upload-time = "2026-07-17T22:50:09.275Z" }, + { url = "https://files.pythonhosted.org/packages/52/71/4c99af3b87dff1b2927981f6876607d4acb45338c665242168d3982f7758/websockets-16.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a606d9c24035242a3e256e9d5b77ed9cd6bccfcb7cf993e5ca3c0f6f68fb6a7", size = 188509, upload-time = "2026-07-17T22:50:10.722Z" }, + { url = "https://files.pythonhosted.org/packages/9b/b4/5c8ca14b0df7eb84ed0524165c5359150210140817a3312aee57bf62a1cf/websockets-16.1.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:414e596c75f74e0994084694189d7dc9229fb278e33064d6784b73ffbba3ca31", size = 189882, upload-time = "2026-07-17T22:50:12.293Z" }, + { url = "https://files.pythonhosted.org/packages/25/c1/bedfba9e70557129cb8083748d167bdcc01483dedf0f0df143676df05cbe/websockets-16.1.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:536676848fc5961aca9d20389951f59169508f765637a172403dc5434d722fa0", size = 189114, upload-time = "2026-07-17T22:50:13.789Z" }, + { url = "https://files.pythonhosted.org/packages/df/09/aa835b2787835aebd839114be5de51b797cb480b63ba42b26d34dfe147cb/websockets-16.1.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:97fd3a0e8b53efa41970ac1dff3d8cf0d2884cadeb4caaf95db7ad1526926ee3", size = 187861, upload-time = "2026-07-17T22:50:15.179Z" }, + { url = "https://files.pythonhosted.org/packages/20/26/f6408330694dbc9830857d9d23bc14ac4f6875127a480cfdda8d5ca21198/websockets-16.1.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7b1b19636af86a3c7995d4d028dbe376f39b4bf31541146f9c123582a6c94562", size = 185286, upload-time = "2026-07-17T22:50:16.741Z" }, + { url = "https://files.pythonhosted.org/packages/17/9a/e0675e70dd8a80762cf35bb18799d3f290a4890ffe6439bc51d222796083/websockets-16.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:41c8e77f17294c0ac18008a7309b99b34ee72247ef10b6dff4c3f8b5ac29896b", size = 187935, upload-time = "2026-07-17T22:50:18.213Z" }, + { url = "https://files.pythonhosted.org/packages/33/c1/3234cfb86afde01b81e9bddcc6e534c440975d60a13991259e833069ab3e/websockets-16.1.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:9f63bcef7f4b02b06b35fc01c93b96c43b5e88e1e8868676caacf493d5a31f3a", size = 186444, upload-time = "2026-07-17T22:50:19.67Z" }, + { url = "https://files.pythonhosted.org/packages/89/87/9c15206e1d778923d8daa9657de07aa62ea815e13448319c98458c37b281/websockets-16.1.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dab9eb87869da2d6ed3af3f3adf28414baae6ec9d4df355ffc18889132f3436c", size = 188409, upload-time = "2026-07-17T22:50:21.28Z" }, + { url = "https://files.pythonhosted.org/packages/f2/00/cf5de5c67676de2d3eef8b2a518f168f6796595447a5b7161ba0d012915c/websockets-16.1.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:43e3a9fdd7cbf7ba6040c31fae0faf84ca1474fef777c4e37912f1540f854499", size = 185958, upload-time = "2026-07-17T22:50:22.719Z" }, + { url = "https://files.pythonhosted.org/packages/62/c0/731b6ddede2e4136912ec4cff2cffbda35af73546be4762c3d7bd3bd79af/websockets-16.1.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:056ae37939ed7e9974f364f5864e76e49182622d8f9751ac1903c0d09b013985", size = 186911, upload-time = "2026-07-17T22:50:24.108Z" }, + { url = "https://files.pythonhosted.org/packages/8c/7f/39c634472c4469a24a7c09cecddffb08fac6d0e74f73881a94ee8a40a196/websockets-16.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a0eadbbf2c30f01efa58e1f110eb6fa293261f6b0b1aa38f7f48707107690af9", size = 187204, upload-time = "2026-07-17T22:50:25.548Z" }, + { url = "https://files.pythonhosted.org/packages/26/89/9667c256c256dafcc62d21328ce7a40067da857969b68ee9af375b0aaf72/websockets-16.1.1-cp314-cp314-win32.whl", hash = "sha256:195c978b065fa40910582464f99d6b15c8b314c68e0546549a55ed83f4735328", size = 179603, upload-time = "2026-07-17T22:50:27.086Z" }, + { url = "https://files.pythonhosted.org/packages/bd/dd/1c099d6c0fc5deb6b46ccdbb6981fdb4b12c917869cb3952408409dc18db/websockets-16.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:4e8d01cc3bcae7bbf8167f944aeafefed590fae5693552bba9794a9df68371cc", size = 179948, upload-time = "2026-07-17T22:50:28.521Z" }, + { url = "https://files.pythonhosted.org/packages/35/25/9956b2d5e0529d5d23924f21bba1440d4c5c88a562e4f08550871ffa97a7/websockets-16.1.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0ffd3031ea8bda8d61762e84220186105ba3b748b3c8da2ae4f7816fac03e573", size = 179963, upload-time = "2026-07-17T22:50:29.982Z" }, + { url = "https://files.pythonhosted.org/packages/17/06/55ffc976c488b6aee9ea05761ff7c4e88e7c1fd82818c8ca7b556ad2f90c/websockets-16.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:84a2cef8deffbd9ab8ee0ea546a2a6a7030c28f44e6cdd4547dbfeb489eb8999", size = 177497, upload-time = "2026-07-17T22:50:31.396Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3df13f73af9b3b38ab1195eb299ecb67a4330c911c97ae04043ff74085728abe", size = 177698, upload-time = "2026-07-17T22:50:32.829Z" }, + { url = "https://files.pythonhosted.org/packages/b2/39/26762f734113e22da2b942c3aca85798e0c0405d64c256549540ff31e5a1/websockets-16.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:23253dd5bcae3f9aaee0a1d30967a8dbd52e5d3cff93a2e5b84df57b77d4750d", size = 187561, upload-time = "2026-07-17T22:50:34.24Z" }, + { url = "https://files.pythonhosted.org/packages/11/94/c3f330851806b9b02138b774d593478323e73c99238681b4b93efe64e02d/websockets-16.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1c5705e314449e3308872fe084b8571ce078ee4fc55a98a769bdefe5917392", size = 188732, upload-time = "2026-07-17T22:50:36.088Z" }, + { url = "https://files.pythonhosted.org/packages/d1/f2/eb2c450f052de334ae33cf200ece6e87b0e14d186807074e4eb1cd2cdea2/websockets-16.1.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:69e52d175a0a7d1e13b4b67ad41c560b7d98e8c6f6126eb0bda496c784faf8c7", size = 190872, upload-time = "2026-07-17T22:50:38.008Z" }, + { url = "https://files.pythonhosted.org/packages/70/31/2ac8cecf3a74f7fed9132129fc3d90b3998a1554570c11a69b2a8c20332d/websockets-16.1.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1f79c89b5eb034d1722938a891916582f8f7f503f58ca22518a63c3f2cd18499", size = 189305, upload-time = "2026-07-17T22:50:39.53Z" }, + { url = "https://files.pythonhosted.org/packages/6a/cf/8ab19650d3c0d4562c92e70ab47c257c4aa5c6a713ed87fe63766b31fefc/websockets-16.1.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:39f2a024af5c345ffe8fcf1ee18c049c024c94df393bb09b044a6917c77bde43", size = 188033, upload-time = "2026-07-17T22:50:40.912Z" }, + { url = "https://files.pythonhosted.org/packages/66/d7/a49a38a6127a4acb134fb1912b215d900cc657605cff32445bf519f3acc4/websockets-16.1.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:952303a7318d4cbe1011400839bb2051c9f84fa0a35923267f5daba34b15d458", size = 185748, upload-time = "2026-07-17T22:50:42.559Z" }, + { url = "https://files.pythonhosted.org/packages/95/3e/ad1fa40388c7f2e0bb2c7930d0090b6c5498594bd1cdaec18864df3d9e97/websockets-16.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:249116b4a76063d930a46391ad56e135c286e4562a18309029fc2c73f4ed4c62", size = 188285, upload-time = "2026-07-17T22:50:43.974Z" }, + { url = "https://files.pythonhosted.org/packages/35/b8/d5db28ca264b9104f82196f92dc8843e35fd391f763d42e4ad358f5bc97e/websockets-16.1.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:61922544a0587a13fd3f53e4c0e5e606510c7b0d9d22c8444e5fae22a06b38cb", size = 186777, upload-time = "2026-07-17T22:50:45.474Z" }, + { url = "https://files.pythonhosted.org/packages/42/9c/726cb39d0cc43ae848dce4aa2acb04eecc6738b1264ec6d700bf6bcfb9f8/websockets-16.1.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:46dcaa042cd1de6c59e7d9269fa63ff7572b6df40510600b678f0826b3c7af51", size = 188682, upload-time = "2026-07-17T22:50:46.973Z" }, + { url = "https://files.pythonhosted.org/packages/be/c7/1168704de8c2dd483edabe4a22cbe4465dd8be8dd95561d214f9fe092871/websockets-16.1.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:38565aca3e01ea8734e578fb2118dade0ecb0250533f29e22b8d1a7a196cf4d0", size = 186377, upload-time = "2026-07-17T22:50:48.413Z" }, + { url = "https://files.pythonhosted.org/packages/ca/40/f9ff2d630ffce4e7dfea0b2288e1caf9ebbf9ff8a9ec9396136ce8b94935/websockets-16.1.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:42f599f4d48c7e1a3338fdaac3acd075be3b3cf02d4b274f3bf2767aedd3d217", size = 187148, upload-time = "2026-07-17T22:50:49.845Z" }, + { url = "https://files.pythonhosted.org/packages/b5/71/e177c8299f78d7cbe2d14df228643c10c70c0e86e108e092056bbcc16e46/websockets-16.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dcc04fedf83effaeb9cce98abc9469bb1b42ef85f03e01c8c1f4438ef7555737", size = 187578, upload-time = "2026-07-17T22:50:51.619Z" }, + { url = "https://files.pythonhosted.org/packages/49/b2/b6987faf330f5af5c787a2610124c2e8403d51724f9001ec4fff6311fe7a/websockets-16.1.1-cp314-cp314t-win32.whl", hash = "sha256:8483c2096363120eea8b07c06ae7304d520f686665fffd4811fad423930a65d7", size = 179729, upload-time = "2026-07-17T22:50:53.269Z" }, + { url = "https://files.pythonhosted.org/packages/a2/6e/fbac6ed878dd362fbad7d415fa4f84d38e3e33fed8cde45c64e783acf826/websockets-16.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:bcce07e23e5769375158f5efdcdafa8d5cd014b93c6683865b840ed65b96f231", size = 180072, upload-time = "2026-07-17T22:50:54.969Z" }, + { url = "https://files.pythonhosted.org/packages/e1/ed/71fea6e141590cafc40b14dc5943b0845606bee87bdb52a21b6a73eb4311/websockets-16.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:820fb8450edddae3812fd58cbc08e2bf22812cb248ecb5f06dbb82119a56e869", size = 177185, upload-time = "2026-07-17T22:50:56.665Z" }, + { url = "https://files.pythonhosted.org/packages/01/ec/00e7eeca200facf9266a83e4cbbf1bed0e67fba1d4d45031d3e5b3d81b5c/websockets-16.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:125f22dbefaf1554fea66fc83851490edb284ce4f501d37ffed2752f418332d9", size = 177459, upload-time = "2026-07-17T22:50:58.197Z" }, + { url = "https://files.pythonhosted.org/packages/75/fd/5774c4b33f7c0d8f0c51809c8b3a93456c48e3543579262cfa64eb5f522e/websockets-16.1.1-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:30bbe120437b5648a77d3519b7024ea09530e0b5b18d3698c5a0ae536fe0cc2e", size = 178294, upload-time = "2026-07-17T22:50:59.641Z" }, + { url = "https://files.pythonhosted.org/packages/37/c3/48e2c03d2bd79bb45948841c592d24156312dd5f58cdf8f549febe652fb6/websockets-16.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b6b9dadbef0cccd9f4c4ee96b08898afa73e26803bbe0f6aeb5bb12b0074206d", size = 179190, upload-time = "2026-07-17T22:51:01.129Z" }, + { url = "https://files.pythonhosted.org/packages/2d/3f/73e511ecf2496ceac57dd4ed8388efe2bcf0769338a2dbf242c8366ae87e/websockets-16.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56cd5fc4f10a9ea8aa0804bddb7b42506cf9e136046f3b4c27de8fec9e2ecba5", size = 180330, upload-time = "2026-07-17T22:51:02.603Z" }, + { url = "https://files.pythonhosted.org/packages/be/4d/2d0d67834092e354d2b0498f014a41249a89556bc406cf86f3e1557bb463/websockets-16.1.1-py3-none-any.whl", hash = "sha256:6abbd3e82c731c8e531714466acd5d87b5e88ac3243465337ba71d68e23ae7e3", size = 173814, upload-time = "2026-07-17T22:51:04.184Z" }, +] + +[[package]] +name = "websockets" +version = "17.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.12'", + "python_full_version == '3.11.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/01/89/3f825ab71c242fffb62ea8fe638741c290f62f8d7aadf8125ff897747af3/websockets-17.2.tar.gz", hash = "sha256:36c2fb94c990cc2545143b12690e2de6c16300f9dbe5b4f33fa300cf57dc8792", size = 188355, upload-time = "2026-10-03T14:56:53.5Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/f7/8a90cc2abbe4709dff4450824beb07cbf7256566ee043c2ba3faa1d5fb2a/websockets-17.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:569ed5db651e420b13279f9333443bb5b84a436cc66b599cbc535697ae4434a0", size = 217725, upload-time = "2026-10-03T14:52:50.797Z" }, + { url = "https://files.pythonhosted.org/packages/7f/85/e418ba2e7e412a5b35c42caf6d4fcc8ecee1a66edc4f2a5f780da775aa77/websockets-17.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3892d76754b5f36fb40619f3ef09c68e5c3091f1ab8840964518ae5a41f30952", size = 215415, upload-time = "2026-10-03T14:52:52.715Z" }, + { url = "https://files.pythonhosted.org/packages/b3/28/e4d7eb2e2e4ffed0b0dfbd2d1aa3c8101f42d34ac9f58b47b822c565d1d4/websockets-17.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5436ffea003adb50e283ca0684a3fcaa1396104f841736c3322ee6582bd09e98", size = 215690, upload-time = "2026-10-03T14:52:54.173Z" }, + { url = "https://files.pythonhosted.org/packages/4b/dd/e8718fa6114c4cd15b05133b548af985638e80774253c1faee8d49874c38/websockets-17.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9df9d048def11365d170b375b6ffc8b23a7f188c3560acd4418ba088ca2e2705", size = 224756, upload-time = "2026-10-03T14:52:56.132Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d5161c46f3eee2ae67cdec489532b51695a1c27ccfadd858dcd419ea26ac/websockets-17.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:376a693697ddb695ea282ead76060f4847f90e564b12b4389f2c7589e6fadb9e", size = 225026, upload-time = "2026-10-03T14:52:57.671Z" }, + { url = "https://files.pythonhosted.org/packages/d5/9a/3f83bace9636af07d7bb00cbae0bcb5bd1697892babac79664f3a2b3a011/websockets-17.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecd63d0c7ed0d3d719c91b5a3861f0f0b3cec9bf223033ddf69d17aaac74bb6d", size = 226260, upload-time = "2026-10-03T14:52:59.114Z" }, + { url = "https://files.pythonhosted.org/packages/03/50/5347cb13f97430526b9c31e9b30fa639bb1d0f9d53074da8622b327cfb6f/websockets-17.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:48997ed4431d8006988788ef4b62e1fd3f053c7463b4fa793aa6c4f9e96a3bb7", size = 229573, upload-time = "2026-10-03T14:53:00.601Z" }, + { url = "https://files.pythonhosted.org/packages/14/2b/7511082e3fe0cc3233ecb0c3b019ef12c1cd9df60ac1a7858f6093f490b5/websockets-17.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4e312e07557a5ad348f4e83d3419773527f6e790c7f97928b1911d767b6ea1c7", size = 226819, upload-time = "2026-10-03T14:53:02.235Z" }, + { url = "https://files.pythonhosted.org/packages/26/4f/86c1a9db323d4fdbf56cc089942f18328a48c3efbbad0d625a66a2195842/websockets-17.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:902ce8cafca2dc14cef9558a6fc3b45dbf7f121d1404bf2ad18a1c894555e48c", size = 225595, upload-time = "2026-10-03T14:53:03.768Z" }, + { url = "https://files.pythonhosted.org/packages/81/92/4f54f6031d97e284e01a0728cef38b095478dcaab81837aac8cb0e26ea6a/websockets-17.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e53d950e16d4bb672a5ff41fe3131e65a4e5d688d694e1c7074c8c9990bb3ceb", size = 222875, upload-time = "2026-10-03T14:53:05.7Z" }, + { url = "https://files.pythonhosted.org/packages/5c/32/c6d59b8b45c730a56ee5acf6c0ce9896356cba25ef3f9a4c9d1796f2e44f/websockets-17.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:946ac2164d646e733004946ae39536b5af473853183d81da5962e29d36e3ad35", size = 225745, upload-time = "2026-10-03T14:53:07.281Z" }, + { url = "https://files.pythonhosted.org/packages/d1/7c/5d9b91b43aa339b96551630940a847270c10a9d70243be4c81fe5dc6fb34/websockets-17.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:660aa158127035e741d4b1835dbe79ae18a1fbb21ecd236655f31d60110e68d5", size = 224342, upload-time = "2026-10-03T14:53:08.893Z" }, + { url = "https://files.pythonhosted.org/packages/d3/e1/c90c24b0dfb12b8b6f0d5e13fc7cf9f121a2e072f7f54bb888da826b2012/websockets-17.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4733fc2d99fe888261417b7e29995403a72d9ffa78629902882325ea141177f2", size = 225109, upload-time = "2026-10-03T14:53:10.495Z" }, + { url = "https://files.pythonhosted.org/packages/c1/5b/f38ca1299c10ea1cfc7f1d129c65a15e4f4b281d1f3dc25891d5fb9bf9db/websockets-17.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c2ec7e51157a3fa0e9cfdb1a8969bab38d1c22ad1ace7c6cea006383b43a1ad4", size = 226151, upload-time = "2026-10-03T14:53:11.976Z" }, + { url = "https://files.pythonhosted.org/packages/f9/21/ff6089c6921c7ae0e1801a4948aa1a3831deb1596e8f0d1cd3a0c0e44109/websockets-17.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:ada04d0262ab06527054a2a497f384d102698ff39b3865dc566a7d24b6f4058c", size = 223732, upload-time = "2026-10-03T14:53:13.864Z" }, + { url = "https://files.pythonhosted.org/packages/4a/c4/01ca4212f665e351123c84e7f7156badf5da958ef8aad8781b538682c699/websockets-17.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9c393a202df08e96ed619310f0cd78be700e532a57d9a6ceee5f80b4e35bef14", size = 224764, upload-time = "2026-10-03T14:53:15.411Z" }, + { url = "https://files.pythonhosted.org/packages/71/24/bc17b39d1e62b771d8a417b714439252d7abfca21185242cc293d75b20d5/websockets-17.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:af4c565b923bb5975401b8e4cedc2e17b2fdbf33b905737ee12384e6a6fd9507", size = 225002, upload-time = "2026-10-03T14:53:16.93Z" }, + { url = "https://files.pythonhosted.org/packages/0b/f6/ccab831ab6a841a35134937a1794c0f3f09ccc604625505be061dec5b3e4/websockets-17.2-cp311-cp311-win32.whl", hash = "sha256:c81d6cdbacccda7e0eef3b076a457fd14c3835cdbc5993d2881580c2fb1f5f26", size = 218226, upload-time = "2026-10-03T14:53:18.376Z" }, + { url = "https://files.pythonhosted.org/packages/0a/18/4fcc23f2159393ad7a668574ee97ee5a135003bfcbdd56b30581110c0fe8/websockets-17.2-cp311-cp311-win_amd64.whl", hash = "sha256:55c5b9eab079540bfb639b40b07b7b467e5c5a7ecf97a65cc8665781381c9856", size = 218523, upload-time = "2026-10-03T14:53:19.947Z" }, + { url = "https://files.pythonhosted.org/packages/86/41/5a3f4f75dadb7fbf980ea4b59d02528f87fb2d3c0ac120c2ff50d1dc1b34/websockets-17.2-cp311-cp311-win_arm64.whl", hash = "sha256:55f9a808a0e072473337c240c939849818276e288e2374b832255b5b791b0851", size = 218454, upload-time = "2026-10-03T14:53:21.417Z" }, + { url = "https://files.pythonhosted.org/packages/bc/de/87854af9b38fe4738fd85f7f21c5b49558ae20aec898880894e435f33375/websockets-17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:916ebdfd82e7fc68041d36b2b5f60361b9abce1e087454da15f8bd004839e090", size = 217757, upload-time = "2026-10-03T14:53:23.029Z" }, + { url = "https://files.pythonhosted.org/packages/3a/2e/1e80b5efa41544f626d56bd15ccb53dbfc56bf28bf80ab9cd6f82c4b1d20/websockets-17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3621f3686397708b8eeabfd0a9d75267c1f29a7537d2fe31e65d099e71587fa4", size = 215439, upload-time = "2026-10-03T14:53:24.531Z" }, + { url = "https://files.pythonhosted.org/packages/3b/6e/82c78b595aee05be76a7ee78539323da1593c1848e4fef51c704c696568f/websockets-17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a81e19710d48da88653473b6b9c366d47e99fe4f58e37ce415be47966748f31f", size = 215703, upload-time = "2026-10-03T14:53:26.226Z" }, + { url = "https://files.pythonhosted.org/packages/f8/c4/905ef6aa80423c03dba99e1e26fc0acf63a2a9a6a2d9e8c0e6a63caaf952/websockets-17.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f2731f9067976c8c4127212c0d2f2ada42d497d935e470419e029802365b12bb", size = 225023, upload-time = "2026-10-03T14:53:27.744Z" }, + { url = "https://files.pythonhosted.org/packages/03/c0/a6d8be9c43e4456fb9597fdf8b5e0ce1f0a5df41503acce6d869536e4e23/websockets-17.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6627b913b8586b1c06db9516b31dd0dfbc621de3bb9312616d92a7e44f268a5b", size = 225299, upload-time = "2026-10-03T14:53:29.171Z" }, + { url = "https://files.pythonhosted.org/packages/2f/d4/976d34b5491258b0a86c2ce9b9aabb9fdd68919ffd7fe65999c14a502a98/websockets-17.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0198c4ec6a3406a2f7557c032967de426474c2c995c81076585e09d29a9f407b", size = 226540, upload-time = "2026-10-03T14:53:31.635Z" }, + { url = "https://files.pythonhosted.org/packages/83/2f/c4cfd42f53c697a8ed123fd82b8f85fcd13b6360d47f9f1d1d45d6ec6627/websockets-17.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:88c6a42c2632ff469e84155e44f6ed92cb15ccb047bf5fcb59225ae5a12fd33d", size = 229371, upload-time = "2026-10-03T14:53:33.061Z" }, + { url = "https://files.pythonhosted.org/packages/e7/55/9a221b29c6232ff9282eecb2fc102402cb9e42a3479264db0e5fc4fe6835/websockets-17.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:eb0023e6cdb4b8ece0b33875188dd16104ad8c335361d396a98394f99e30ff7a", size = 227173, upload-time = "2026-10-03T14:53:34.502Z" }, + { url = "https://files.pythonhosted.org/packages/8f/07/125e6d010c56c253d3d2b93cabaea0f96d33898151a16b49066a594acecf/websockets-17.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c1c09d5d4646eb96bda2cfb97493bcea21a0956a981de116e6b1f4a9de07f3fd", size = 225929, upload-time = "2026-10-03T14:53:36.071Z" }, + { url = "https://files.pythonhosted.org/packages/23/a8/aad3bd902aee84e1b261ad6ab83b405e4a564af43101b8ad1dc0293ff4f4/websockets-17.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0360c4dc13ac569cc245e0efa2f4d4b1e4733d24c47b8ab3f3747227b1356348", size = 223167, upload-time = "2026-10-03T14:53:37.528Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f4/ec8ab9be1a5310b4fea829f088c7aa2b7a58b61d34bce1b2a9338635ff12/websockets-17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:76693a16dead737946b651375ee3109d7db7ad9569a1c55c60aaed3ef85cfcc6", size = 225974, upload-time = "2026-10-03T14:53:38.959Z" }, + { url = "https://files.pythonhosted.org/packages/65/45/ba6503f8257d3f98b0f07ebaad0fd099c9023eae744fd5b775416743597e/websockets-17.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:77a42cc507993ec5471b5283f7eef869239173b6000031543e3938a86d1af0fd", size = 224581, upload-time = "2026-10-03T14:53:40.496Z" }, + { url = "https://files.pythonhosted.org/packages/d0/45/05cca59a876c6776727d96fc7ba59e0b6f9aa496afbf13e7e04ad0b63678/websockets-17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3bbc5543e39ee025d524077c5c15c2d67bc11c9f6676afe5b531839e24d701f6", size = 225347, upload-time = "2026-10-03T14:53:42.061Z" }, + { url = "https://files.pythonhosted.org/packages/1c/00/cf0e43292ae949b13f67535be84317102891d69fd1986ec2bf2ead42747b/websockets-17.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8da58558bfb0ca6ccac2419773521f1111e40654038b1afabdfc69c02cb82614", size = 226457, upload-time = "2026-10-03T14:53:43.575Z" }, + { url = "https://files.pythonhosted.org/packages/79/0d/9a5c61a18f0cc9876d94c70ccb3daf7614a9fee56abbb37c0e64e757fb96/websockets-17.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:01420cb1cb47433e8e7075d32cb8017ad3ffed0654bd1e48c0251b865920dec3", size = 224011, upload-time = "2026-10-03T14:53:45.077Z" }, + { url = "https://files.pythonhosted.org/packages/34/ed/991c1ab80ab2ce40e1c939fef6fa8f971c3ef3b21caf988a7a107e0ad27d/websockets-17.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:c49c9edd47d0e44d360299e2d8865e2950d2fcf1b4098782c9d7dcd070919e5a", size = 224990, upload-time = "2026-10-03T14:53:46.8Z" }, + { url = "https://files.pythonhosted.org/packages/e7/7a/363c835d17923e967fb66376188e67b9a261c85d826a0cd5e4dd3471221d/websockets-17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:96f6c8d0fe21930d1f982bfce2382789d2e8d005d2ab63d21280660f95ef8fe1", size = 225265, upload-time = "2026-10-03T14:53:48.382Z" }, + { url = "https://files.pythonhosted.org/packages/c8/90/6c51f6d78636bd1cd6781fae8ea5ea7bf1d5b4059354f3c1f5f8de793338/websockets-17.2-cp312-cp312-win32.whl", hash = "sha256:b25659ab2d655d742701487d5591e3f98e8f8b329fc999e05e3d59691ab344a1", size = 218228, upload-time = "2026-10-03T14:53:49.867Z" }, + { url = "https://files.pythonhosted.org/packages/c6/2a/90008411c652dcfae34345a2169f4becd066a4ba71eebfa8dd801e0445e1/websockets-17.2-cp312-cp312-win_amd64.whl", hash = "sha256:faa763b677e96f1beccc6b4d7e8c079dfeed2f249f57a19debc321b519ee64ec", size = 218528, upload-time = "2026-10-03T14:53:51.486Z" }, + { url = "https://files.pythonhosted.org/packages/1f/a1/b8ad6c17f8e75ba2215422fffe0d7f0c4b690dcff1c47c0473db0d253d51/websockets-17.2-cp312-cp312-win_arm64.whl", hash = "sha256:63499fc49efe48bccc2fca40723bc7adb198866cbe159093dd979905316994b6", size = 218457, upload-time = "2026-10-03T14:53:52.938Z" }, + { url = "https://files.pythonhosted.org/packages/54/54/a935a32dbc2e7365b1b59eb74b5ab7515456f02370fdca4c4efc3574e96f/websockets-17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:b24b83fbb34b2d8de06cf0f0d4bd7737344ef854482a614826d4356c0c3f0c12", size = 217752, upload-time = "2026-10-03T14:53:54.59Z" }, + { url = "https://files.pythonhosted.org/packages/cd/95/cb8881851abe2662730e6c61cc521b4c96513fdf9103a44f169afce2eba8/websockets-17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8a829db795e3f87053904493d184b185c8eb1f497c852f434168ec856aa6f997", size = 215436, upload-time = "2026-10-03T14:53:56.034Z" }, + { url = "https://files.pythonhosted.org/packages/ca/1e/621bb93f35ab7d337be98f1958294437527e2a1797089b5e734ddc5eec5f/websockets-17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cf8811d285acc91216368df7fb55cc8c9bf6fcd90eea42429c7186c7385a12b9", size = 215690, upload-time = "2026-10-03T14:53:57.587Z" }, + { url = "https://files.pythonhosted.org/packages/62/4a/49d0c983c082676d5d413b28e6ba5ae1d174c00268467bf78d9fe986a2d2/websockets-17.2-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89c4898da776193577279173dcf9860487590611d7320d379435a145881b048d", size = 225080, upload-time = "2026-10-03T14:53:59.081Z" }, + { url = "https://files.pythonhosted.org/packages/04/13/95a45eb410019772002d8f53d81396dad4120f7df39ca9962f86f5d7cd01/websockets-17.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d87091c4347daadbcc0833b65812ff38d7350c67339625d4e4a512cf38e3e8ef", size = 225361, upload-time = "2026-10-03T14:54:00.61Z" }, + { url = "https://files.pythonhosted.org/packages/f8/fe/0f0eda80bb441f54becdaf793eb20ee080926f8d2356388377cf262187e5/websockets-17.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1110fbfd530c447380e6e6db88b7e43ffe33d54178f5b0ff0aaa5a280301e668", size = 226602, upload-time = "2026-10-03T14:54:02.098Z" }, + { url = "https://files.pythonhosted.org/packages/5c/36/067fc09d8e6f154abde7c2f747c52cc442a02c5eb14816f5c39cb9f8bcc6/websockets-17.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:83abd8beab056aa77a116364811f8fc262dffbcc7abea48de0c85ccbfc6f1428", size = 228035, upload-time = "2026-10-03T14:54:03.545Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a2/939bade7a396b4c381aebbf3941969f124d0f98d56753f81cd256f3fc4d6/websockets-17.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:876da8ca5520d65b5d0f2ca6b4e7a00d35bb90ccda35cb2ce3cda4b6c711e84a", size = 227227, upload-time = "2026-10-03T14:54:05.045Z" }, + { url = "https://files.pythonhosted.org/packages/e5/8a/37b1033e21709dd7fa39239ea4d9cd7f348ad5bcba94eb47253878576f8a/websockets-17.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8462395df8f224d2daa3d80db3ae4450d9d4b7243c8483ac79a82862f1599dd6", size = 225985, upload-time = "2026-10-03T14:54:06.81Z" }, + { url = "https://files.pythonhosted.org/packages/a0/3a/0d89539900b06d86366facb7558198046de125ab8c371d9248d6262da70d/websockets-17.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6e9a04e69456015e6ae5e0d486d995137fd435794442122b00ce5f9526ea3ba8", size = 223226, upload-time = "2026-10-03T14:54:08.583Z" }, + { url = "https://files.pythonhosted.org/packages/31/9a/bfc5633e3d538d0a71cfbe7a5fee56c712e16c2dbd0ce17c83196a2a96a9/websockets-17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8a2321bcb73758c44c8076509024d02c15ee484fe77ce04edea4bf4d257492cc", size = 226042, upload-time = "2026-10-03T14:54:10.254Z" }, + { url = "https://files.pythonhosted.org/packages/bb/1f/cbaf1786d8e3aeafe9d76951fc01139ec353b92555580336f23669382a55/websockets-17.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8be4a87b3baca380ec3c7b1643b2dd268ac9d42c5097c0e8dc9a49342faf4774", size = 224639, upload-time = "2026-10-03T14:54:11.911Z" }, + { url = "https://files.pythonhosted.org/packages/80/49/175faa5bd169486f835602ac0ae6303318aa65693b79cdc72c5ee53b148d/websockets-17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:eb7b737ce8d18c8a08beb68f751572b7bf6a18093ecd1406ca1256b50592552e", size = 225407, upload-time = "2026-10-03T14:54:13.489Z" }, + { url = "https://files.pythonhosted.org/packages/ac/d1/3662f612456cfb2dcc128c8e596f0a55fb7b695025e2ebe8ba2abb355c3b/websockets-17.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d6605630c2808b33f362d6d08582e79821f77ed2bd3f49f9d467ea70defea06d", size = 226513, upload-time = "2026-10-03T14:54:15.046Z" }, + { url = "https://files.pythonhosted.org/packages/73/6b/07af5177a49e30156b0922556fa93624a920a2b17d3e63bf4ad94668112c/websockets-17.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:dd9252828073fd0d69e7667af4275a1b17c18d0833b1ab7f59db272f194a6b9a", size = 224072, upload-time = "2026-10-03T14:54:16.574Z" }, + { url = "https://files.pythonhosted.org/packages/eb/34/d18054ff4d8314524164f8b8efec2cb17627287e099f122c28ed6fa598e0/websockets-17.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:06c7386128a9d85de4e1960114604f3031c084d2f4eee8db382637f1634cbab1", size = 225022, upload-time = "2026-10-03T14:54:18.143Z" }, + { url = "https://files.pythonhosted.org/packages/e9/12/75433caa3e9fa3e51d7751dc6bad24a86addf76cbfb51e52b11d037ba7fd/websockets-17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:98f2d03df74977fd252831c997c388cd6c3f691a8a9d022b266d3cbd9849838f", size = 225303, upload-time = "2026-10-03T14:54:19.679Z" }, + { url = "https://files.pythonhosted.org/packages/6f/de/23e21c002aa2786ac9807c0876faa3b2576493b29ca3386287b0db46f021/websockets-17.2-cp313-cp313-win32.whl", hash = "sha256:5b43a1f7e4853ce08c3f6d3bf69799ee5b46548bfb71792a8158f7e45d66b547", size = 218219, upload-time = "2026-10-03T14:54:21.232Z" }, + { url = "https://files.pythonhosted.org/packages/13/eb/960411c0c574535d629c16e96a2b4e5353dbe4109df8ecea859e1b5245ee/websockets-17.2-cp313-cp313-win_amd64.whl", hash = "sha256:27c7a59b5352a8f741b422820adfe89dfe47c8f2d84fb32111e76111edaa0e83", size = 218531, upload-time = "2026-10-03T14:54:23.025Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1a/3ac07bb52378952eff1d52d04a7ee6e82ce84e3da319a52a4739cd9c78f5/websockets-17.2-cp313-cp313-win_arm64.whl", hash = "sha256:533b7c82bb1eafbeb921dfe131c9f88e55451ddc328d84bde1c9340ba72d2808", size = 218466, upload-time = "2026-10-03T14:54:24.857Z" }, + { url = "https://files.pythonhosted.org/packages/8b/74/6bc991a28ac983600e65de408ebd1b1413d554ed0468ae5c831bc52dded6/websockets-17.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:ecb748910e9ba4624ebe2057791df51dcbffb48c37108ab94a3c593472023c9e", size = 217791, upload-time = "2026-10-03T14:54:26.381Z" }, + { url = "https://files.pythonhosted.org/packages/cb/2f/158e99426be6e71d09520bae53f29294fbb614b2fc5fbf8867b1d08395a7/websockets-17.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2ab9af5cb7265899e659f079eb71691375a1025b6d5fbd3caa495dd08f70833a", size = 215486, upload-time = "2026-10-03T14:54:27.962Z" }, + { url = "https://files.pythonhosted.org/packages/5c/09/1abf942723c0001d9c2fca1551907dade6304517b982b0bf10bba107fa81/websockets-17.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:06e46da092bca3a52e98f0458c66b247993ce501a07cd09c858be3296511ab7d", size = 215699, upload-time = "2026-10-03T14:54:29.523Z" }, + { url = "https://files.pythonhosted.org/packages/a7/1d/1ade03963ef497c47e6bad79e24370827b2fe6145fa8f58070ff2b7dcbac/websockets-17.2-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:fcce735ffd72ac4056db05325d9f0232382b74826f0196eb6a15ca903abdaa0f", size = 225081, upload-time = "2026-10-03T14:54:31.278Z" }, + { url = "https://files.pythonhosted.org/packages/9f/fd/47b8a0361c49da939b976a07b27a72a9f893d01dfcf4d2a28b53419ce1ef/websockets-17.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:42cbca10f82a8b2fb1536e8a0830ca6ceeb6bb3d8d64b766e0795369135654a8", size = 225430, upload-time = "2026-10-03T14:54:32.917Z" }, + { url = "https://files.pythonhosted.org/packages/f0/26/f4d4c76264ee037c5556ab5f50fcba302746dabf7528955534e4dda9965e/websockets-17.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c63ff5a21f26bd0e6a8464b53fadbe174825c8718ac14180df45665eaacdb6af", size = 226676, upload-time = "2026-10-03T14:54:34.833Z" }, + { url = "https://files.pythonhosted.org/packages/37/b3/c8b1c981322a050c4babfd327ffc9880f9c3834f5b15d2574e37eeb8768c/websockets-17.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:63f543463601c1558b755f8dd7618b6ec3dd0934dda051d3b7030d8c76e54de2", size = 228048, upload-time = "2026-10-03T14:54:36.424Z" }, + { url = "https://files.pythonhosted.org/packages/f0/5a/1cb29ddb23e6bc27ffd1c5316cd3616360d1ba0c3854eaa134ee3207bd28/websockets-17.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4c32eb565ad9ce8a6444248e5b7a19dbb86a81c811fe5fcc2fba7a735aed5163", size = 227281, upload-time = "2026-10-03T14:54:38.01Z" }, + { url = "https://files.pythonhosted.org/packages/ba/64/135274572dc0c845fc1111e2b932c807c395daac75d6eae6cfa148d8a208/websockets-17.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5d459bbb6c22f26dcebea56924a362aba50d453b9867912862c970434fcf0d94", size = 226025, upload-time = "2026-10-03T14:54:39.613Z" }, + { url = "https://files.pythonhosted.org/packages/58/75/f1e386aec3124489411caf5138cdd5a2bc43d3fd4a681c69adcf5f6272a5/websockets-17.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f19ca1a21871f024e38faf4107b433047df27558dff1b72a1dac31481e2c1fe5", size = 223277, upload-time = "2026-10-03T14:54:41.165Z" }, + { url = "https://files.pythonhosted.org/packages/60/eb/24733a0f568c2eb99e60f9faa620a98fb228c06a01e7e2f348b33290ed9c/websockets-17.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c76b4bcbf0f713194591673fc86a42820e14da6bbd1bb445d3d002cc4d1e4521", size = 226148, upload-time = "2026-10-03T14:54:42.779Z" }, + { url = "https://files.pythonhosted.org/packages/55/6d/ea66a30af74f5983cae31ebb9ef78b178b366a12856a414e1472225c4a34/websockets-17.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:30201a7f69833b015556c72feb69ea501b645986fd0b90dab13f589e995ff428", size = 224615, upload-time = "2026-10-03T14:54:44.41Z" }, + { url = "https://files.pythonhosted.org/packages/87/80/c6f2228ad89774429d270179375ebddb657119215f52d1df7c680d65cad7/websockets-17.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:0c8600aec354cc259f1691b0b42816f04a9886a953f82cb227246df76057f97a", size = 225398, upload-time = "2026-10-03T14:54:46.063Z" }, + { url = "https://files.pythonhosted.org/packages/f7/4a/3d8da19732ad468d4be7f1e3ac298078b60bdda55edde6589bef84a5eb7e/websockets-17.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:307fc22ea496be8542d67b82ae8c867a978dfd19ac35573d4f15943fd9277dfe", size = 226571, upload-time = "2026-10-03T14:54:47.672Z" }, + { url = "https://files.pythonhosted.org/packages/58/22/1231657122d9cc24791bb90af13cc2f4e84cf0d3a454cb37e3abfdcb2fd9/websockets-17.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:9c88697fa943bd4ef67cc919a17d81de6581846f52bfa8c6f64a916098986556", size = 224125, upload-time = "2026-10-03T14:54:49.537Z" }, + { url = "https://files.pythonhosted.org/packages/1a/04/350ca2445da758bc42cdb4218b44d4ce0d5a9c1d5e4cc4a58d64348ad9da/websockets-17.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f7eac84d4969da82166d5e90d9c38d2f416fe24f9708a7013569b193745b9a31", size = 225081, upload-time = "2026-10-03T14:54:51.075Z" }, + { url = "https://files.pythonhosted.org/packages/da/c4/dec952b0df3a5d918ed2a545abb0c25ae519c3bc2d9aba3b7c46abae8f05/websockets-17.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:313f6703023d53baabab6d6c5c37cf637b2c4fee255acf2ed5e92ad69e28f1b7", size = 225376, upload-time = "2026-10-03T14:54:52.675Z" }, + { url = "https://files.pythonhosted.org/packages/f2/b4/198a260afbcc086ff4979774e51834ed7fb5b95f9ef305e0c4924630b857/websockets-17.2-cp314-cp314-win32.whl", hash = "sha256:08d90cf344bdb971ba3a826b78d4da9bfd56cc6a97a604d9b88cbd40bfa6c735", size = 217760, upload-time = "2026-10-03T14:54:54.247Z" }, + { url = "https://files.pythonhosted.org/packages/e5/9e/0523f8bc2f7aaddf39562d4fa01b4d38fa61b23d980917a16d2dd19c8dac/websockets-17.2-cp314-cp314-win_amd64.whl", hash = "sha256:dac93bf7a9beb215be3282b8441173cd50806c41c007b8be9bb24e03c60ad563", size = 218104, upload-time = "2026-10-03T14:54:55.845Z" }, + { url = "https://files.pythonhosted.org/packages/55/17/7b8bb4cb64a199e7082f1f9be784d657842fefc327ac777d6c1493504804/websockets-17.2-cp314-cp314-win_arm64.whl", hash = "sha256:2ab742249f953d148a9ba696c8b9944361e8cb92e8bc61ba2dd53a178403afd3", size = 217989, upload-time = "2026-10-03T14:54:57.376Z" }, + { url = "https://files.pythonhosted.org/packages/ee/76/f54ed054b6e860f1e0bbc7019542a048352d41231fdff6d904b379f881c7/websockets-17.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:a69ce25be5f1330ee1c74eb6fabbbceaa96b384beedd2627cecded7546490c40", size = 218125, upload-time = "2026-10-03T14:54:58.943Z" }, + { url = "https://files.pythonhosted.org/packages/e6/4c/0f3375cea66a125ae01d21fb9c537aae955ef499bfe7e2b2376a34362f2a/websockets-17.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:8e24b878cf54843a63985d90480f163ca7f692689fbcbe9cdbd8165521083a8b", size = 215658, upload-time = "2026-10-03T14:55:00.674Z" }, + { url = "https://files.pythonhosted.org/packages/0c/05/7c871a67bfb4b61adc1fe13583db97803f87dfeca644fe6ef51df7bb276d/websockets-17.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f33c7908a6885dcae9f462a4a8347b637053b4ff2b96beb4c23fba1cf7818e5f", size = 215858, upload-time = "2026-10-03T14:55:02.379Z" }, + { url = "https://files.pythonhosted.org/packages/41/8e/59df4d9cd357e902d1c74b13c3c0c3841c8df6e4b1b3d131bf26a23fdcb1/websockets-17.2-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c796a1bb3e4015249639849f30e8e680df8a431b45d417ba8acf843d2451d95f", size = 225443, upload-time = "2026-10-03T14:55:03.966Z" }, + { url = "https://files.pythonhosted.org/packages/5c/64/5e486a3a44e041203c62eccf1fc89c7f8824e21104a7b82b182e5b21c228/websockets-17.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:983bcdc898662f6ba9d6a025c30d29946ff0986d9ad60d400af0da3671f7cbf3", size = 225726, upload-time = "2026-10-03T14:55:05.797Z" }, + { url = "https://files.pythonhosted.org/packages/f0/98/b6eb53121c91fbe8b6897aba06861ce60f9ab58faffc6bca5750cbc21681/websockets-17.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:35e0f088ddfd9d9bc5019e27ff3767411779e92b59db5bb1507f2731a5b61158", size = 226895, upload-time = "2026-10-03T14:55:07.626Z" }, + { url = "https://files.pythonhosted.org/packages/8a/18/8c091321b99c91eb3eaec9acbd940e69308b4e465b5605c430af0cf7d3a5/websockets-17.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:19e2511412ad3393191de652513bc7a0ca3c93af143b32d96d46e59fbbddf1d4", size = 229040, upload-time = "2026-10-03T14:55:09.321Z" }, + { url = "https://files.pythonhosted.org/packages/1a/96/3a92f944305b7de42fcb7530b9fa69607b4b4ce993c36a9f2330dbc318ba/websockets-17.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb5e2bf969ac99a6ae3c71208a5eb05cfde973192540ffa6e1068b57fb78c4f8", size = 227469, upload-time = "2026-10-03T14:55:10.935Z" }, + { url = "https://files.pythonhosted.org/packages/ea/a9/624f6d75ba326c22d03698b34c0ada984f1d76196322a62f6c22903b831d/websockets-17.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:691780fca2be3dec512cb603cb91060271968cb4af86b51d07c57445c5754a37", size = 226202, upload-time = "2026-10-03T14:55:12.536Z" }, + { url = "https://files.pythonhosted.org/packages/47/af/1e6e8c625aeb268830af2c4227fe05e8db59f4f4debe1dadfd0ada214895/websockets-17.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2d39c19b1ba6a6791050383fd69efdd3b63533e2254693d0263879cd5f5921ba", size = 223743, upload-time = "2026-10-03T14:55:14.164Z" }, + { url = "https://files.pythonhosted.org/packages/dd/81/33c5280f4f6f81637c93ae065c6a594dfe35935622af135a5f7c3768bf22/websockets-17.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e48ac2b302986c6f55cf61e8e36b4dd97d0132c5078a713a697a940934ba422e", size = 226492, upload-time = "2026-10-03T14:55:15.796Z" }, + { url = "https://files.pythonhosted.org/packages/1d/f3/7aa9fc36e67caccbcfee2c48f4ada41e9da512d41523c024d039f0f22ba3/websockets-17.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:e136197f1262620ef2e507afc3ea759c1ae7d221886da20eec5f4c9f2618c2aa", size = 224940, upload-time = "2026-10-03T14:55:17.661Z" }, + { url = "https://files.pythonhosted.org/packages/3f/8c/457aff7081a63d1261608bb4d7b0b0f9dfe780697a2a334671745742850b/websockets-17.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3eb44019a2b0b3b91bac95998f1e4e5589730421170e060fe654a2b7be727dc7", size = 225835, upload-time = "2026-10-03T14:55:19.607Z" }, + { url = "https://files.pythonhosted.org/packages/3e/c3/7a13a3b3050db2c36772ded49f8d48f99eb080948e9f6f762e7529925ab5/websockets-17.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e5855e574804398859c5fbaf4fc7882b96278b7f6572a3d889627e6eb6cfca59", size = 226848, upload-time = "2026-10-03T14:55:21.274Z" }, + { url = "https://files.pythonhosted.org/packages/c4/3e/d5b2c1e473b1031a4a0ec0e10de69df5b981ab4a10aa482bb45c18dd43f5/websockets-17.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5dc29815520c329f5662f6eb3ebadecf0d4f8c82dfa416d4d6efbf8f39245559", size = 224541, upload-time = "2026-10-03T14:55:22.874Z" }, + { url = "https://files.pythonhosted.org/packages/79/5d/bb81976cc1aa546afb51395ce42913521e9dea062bb34a61308cfff30726/websockets-17.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d1a4f9462da6496b6cb79bbb09c60d17f7e63e8a1df136797b3afabec9560e4d", size = 225315, upload-time = "2026-10-03T14:55:24.443Z" }, + { url = "https://files.pythonhosted.org/packages/f4/6b/314962d5440c61b4c107914599c13ceeecc6bdb6e2e73a5f7e566a7d1f26/websockets-17.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9496bff5541086478264678bac73c0a75b2fde94fdf6568893bca1f7c6d50d18", size = 225747, upload-time = "2026-10-03T14:55:26.033Z" }, + { url = "https://files.pythonhosted.org/packages/98/fc/9eb64b34a3a4458eb08f3f24bde01508f72a00790330723c158ebb965048/websockets-17.2-cp314-cp314t-win32.whl", hash = "sha256:e1e3bc8090a7eae79fdf634b63bdbfa3c93999991023c37c6fd3b469fc8ff5dc", size = 217891, upload-time = "2026-10-03T14:55:27.681Z" }, + { url = "https://files.pythonhosted.org/packages/ba/ed/3a4e2a09b0822d6e525cbc6e44a4885669bad5b22ab9c64fa2444bc15325/websockets-17.2-cp314-cp314t-win_amd64.whl", hash = "sha256:65a89a5bde227bfe908016f35b5bd347970cd1e5b0360f389502eba1c7fde6e0", size = 218229, upload-time = "2026-10-03T14:55:29.314Z" }, + { url = "https://files.pythonhosted.org/packages/b5/66/cffb75ee746dd060984c3c3e2eac7f875a866225a30dfa53e2cd18232565/websockets-17.2-cp314-cp314t-win_arm64.whl", hash = "sha256:1c27339934109dfaca83f18ab2c23db06714e9d5deca2c8e37e8f492ab90d20b", size = 218146, upload-time = "2026-10-03T14:55:31.001Z" }, + { url = "https://files.pythonhosted.org/packages/12/e9/10a9b1633b63594054c87b97af048628cea2b21b5089a52a9fc1e0af60a3/websockets-17.2-cp315-cp315-macosx_10_15_universal2.whl", hash = "sha256:a7c4bb26de6ef496d24822aee4f6a305d97cd33d21a2b85f290292d69ba1c25e", size = 217719, upload-time = "2026-10-03T14:55:32.674Z" }, + { url = "https://files.pythonhosted.org/packages/0c/00/ff4020fe0886dac7199a16ce2805c7afd7b981bd2e81d3fa18dff5d9863a/websockets-17.2-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:c08da1f15040bd1e1a6074bd4518a6ef20e67b1594ecfb0aa75e5b45f87e6d6d", size = 215448, upload-time = "2026-10-03T14:55:34.338Z" }, + { url = "https://files.pythonhosted.org/packages/66/06/bc7b944f81514378b2c2ab96c17df19e871cd33b9be0f1f6dfc975457e5e/websockets-17.2-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:3117abfd32b183bdb6194df9317766d32c6517f3d1c0aa8c62d5c6ccfda0b4a8", size = 215674, upload-time = "2026-10-03T14:55:35.918Z" }, + { url = "https://files.pythonhosted.org/packages/a8/da/2b2b76faa2f10c4813e3872c9577fd13a798f5918b1785b86ff7d635eb2a/websockets-17.2-cp315-cp315-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a046227daa7f191e843d26b911c1146233e9a33d249e0c954dcb3ac7c398710e", size = 225119, upload-time = "2026-10-03T14:55:37.777Z" }, + { url = "https://files.pythonhosted.org/packages/ae/d4/22cbe288c0d5cef7620503be92c0098d82220353fc7e188034a19c517240/websockets-17.2-cp315-cp315-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2901bdf24f20bc884124b3e88c61f7ece260c20c81e610f2196007395264a4aa", size = 225549, upload-time = "2026-10-03T14:55:39.364Z" }, + { url = "https://files.pythonhosted.org/packages/4c/0a/504b0d3063679f2c60430c3539482d42a4cb8bd1a76646baf742030a93cc/websockets-17.2-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f60e39adfecf998488166aca8ff24ab1ac406c9ecbecbcf9b3bcfc43cb1ec9a1", size = 226717, upload-time = "2026-10-03T14:55:40.942Z" }, + { url = "https://files.pythonhosted.org/packages/4e/ea/5da9309cc55c2665a6eebc22c369d9918c0d77258c61e92058e6b08d5ff1/websockets-17.2-cp315-cp315-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d4df62fd8448a85c752bbea1803cb3a2785e6fc8352009ab64ad7447af079b3c", size = 228413, upload-time = "2026-10-03T14:55:42.54Z" }, + { url = "https://files.pythonhosted.org/packages/a6/74/5a24df72aa5500f311105687af864c27f1f9da910e968e97818c6149e6b0/websockets-17.2-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c8eea55fdfa9ba65c6981eea38bd20c800bce2f092a2803d82de764ecf0f071a", size = 227196, upload-time = "2026-10-03T14:55:44.251Z" }, + { url = "https://files.pythonhosted.org/packages/5e/ee/ca32cc1ed892dc4ac30a922e8f648048233fbdb8b0bce7048860ec4c60ec/websockets-17.2-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3f0def1279644acaa9bc861d4234af3f82ea9cee7e460dffac5cb63e691501e9", size = 226092, upload-time = "2026-10-03T14:55:45.842Z" }, + { url = "https://files.pythonhosted.org/packages/7d/0c/12d4a73324aa9798d5165d20c088f9dba66c75c871960e5d921ec66694e4/websockets-17.2-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fb78fb4158c12f77a934a003006784108a27a6553cfc0c6f10483c9c02e94f48", size = 223486, upload-time = "2026-10-03T14:55:47.45Z" }, + { url = "https://files.pythonhosted.org/packages/bc/a4/7fe15da5abb8f0f61e6a357593f7f2ed55724825b7db0ffe72b5c5fad68d/websockets-17.2-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:f8969ad228115ad8869b5fed801f899e52ab8ad376fdb165ba4760a277c8258a", size = 226200, upload-time = "2026-10-03T14:55:49.126Z" }, + { url = "https://files.pythonhosted.org/packages/08/b9/4cd3a311f96a2eea0ed458bc01fe2cce42f9cd50aa9e64315dfc855d63a9/websockets-17.2-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:4a49ca342efc0800e6ae94ed5c9cbdcb319308f75e73c21181e4c24d6710e8dd", size = 224862, upload-time = "2026-10-03T14:55:50.674Z" }, + { url = "https://files.pythonhosted.org/packages/41/b5/22caa3460f75e42bfcc74028870b556d22847ea9a9034aa03986f07f16a9/websockets-17.2-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:06fa3ce9c3154826c33d4395b225b2994aa64f1f3bcd8be8ed932019175d9268", size = 225391, upload-time = "2026-10-03T14:55:52.393Z" }, + { url = "https://files.pythonhosted.org/packages/95/be/8d28f92092076abf1ddfb3206b0ce956120a22e7c3105f6a3029d727deae/websockets-17.2-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:50644d8715be7e0ec0682f9d7744b63008e199c5e1618a48fa153756a332235f", size = 226545, upload-time = "2026-10-03T14:55:54.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/7b/ff943fa383e540fe17f066cc10a3eeedef26e50fd45aae2bdc6746d6f95a/websockets-17.2-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:60deca33e584c09e91f70f8b55a0b1de7d671d6a63f051d154920f48bed717c7", size = 224352, upload-time = "2026-10-03T14:55:55.856Z" }, + { url = "https://files.pythonhosted.org/packages/e9/df/1e6c3e06c473c9fd833a5c1620b15e2c3b37647b91b7d41871d20bc098de/websockets-17.2-cp315-cp315-musllinux_1_2_s390x.whl", hash = "sha256:b5f79366a8d8dbb981d53ba800bb54a95454595ab8a4548c2b95501b32a08326", size = 225255, upload-time = "2026-10-03T14:55:57.497Z" }, + { url = "https://files.pythonhosted.org/packages/db/f8/d8a4f988f7cbb568d8bd69da4632c5b6010aa9cd9366f285e23b73b678d9/websockets-17.2-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:f2bbf3f28d0b63157577c8b774b9136f076afa6797e1a52a2ecd477f23cad3a8", size = 225513, upload-time = "2026-10-03T14:55:59.338Z" }, + { url = "https://files.pythonhosted.org/packages/75/e0/920357165b2797a2530fc9e271d79a9b5fee2b750b154c990c740f767af3/websockets-17.2-cp315-cp315-win32.whl", hash = "sha256:74836317b7010b579522bb52426f1e225608b042c9e78cbe2493522bebb8a318", size = 217722, upload-time = "2026-10-03T14:56:01.307Z" }, + { url = "https://files.pythonhosted.org/packages/5f/eb/25bdca25bbc329ffb330ef33993397d6556a871e40a0d196e757699ea3f7/websockets-17.2-cp315-cp315-win_amd64.whl", hash = "sha256:aaead3d926e9ab4124ada727d20cd62d396649917822df4f771d1f07f1079b40", size = 218017, upload-time = "2026-10-03T14:56:02.914Z" }, + { url = "https://files.pythonhosted.org/packages/fa/cb/ea30a552bbcd1c75f0d14bfce6c884ee36187030b85b74a242aacc02406e/websockets-17.2-cp315-cp315-win_arm64.whl", hash = "sha256:40960554e60eb60c3eec4ff9e42a80f84f8cd3ca9bc80a5481a61f1e64d807c9", size = 217929, upload-time = "2026-10-03T14:56:04.604Z" }, + { url = "https://files.pythonhosted.org/packages/4a/01/477664c619af8aa3c908d482e2a95e13ceed9d78f21d15902013c3bc6c28/websockets-17.2-cp315-cp315t-macosx_10_15_universal2.whl", hash = "sha256:9a2a60a7f0ea5f239efb6391d2b28630a640d82dad63e3bee47cf2c623c4495d", size = 218029, upload-time = "2026-10-03T14:56:06.336Z" }, + { url = "https://files.pythonhosted.org/packages/2a/a9/b0be62ff1c0e2bc966da56b36d3d820c7e2ad3c0c4a4ac414fc7335b214f/websockets-17.2-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:cca2fcb72c007103740fa4fc3df19fdb1a318c641c69f3b0cc47ed63a889336e", size = 215607, upload-time = "2026-10-03T14:56:08.035Z" }, + { url = "https://files.pythonhosted.org/packages/fc/2b/a6738530de0437a31c1b168e4096ecf790aafaf561f33a009886c7d8042e/websockets-17.2-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:b789356bc4e2e6c20ba52817f92c3fed74e24657654237ecd536c54843b80c6c", size = 215817, upload-time = "2026-10-03T14:56:09.852Z" }, + { url = "https://files.pythonhosted.org/packages/c3/c2/2fc44ddc419cbb09ee1708af3e78d8a4b018db01fc7e4f91bd730e2f8d9e/websockets-17.2-cp315-cp315t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:222fb626fa15701a850eccc778be17312142b2f6a0e16aea80770b7459adb784", size = 225979, upload-time = "2026-10-03T14:56:11.85Z" }, + { url = "https://files.pythonhosted.org/packages/2e/91/a215b14caa7ea65bc36db81609108899c259503300d1560dae9c70a135e7/websockets-17.2-cp315-cp315t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4497e87c34a2d21cbec1227858fec3af8e514dd70c47625557a122fcebc081dc", size = 226250, upload-time = "2026-10-03T14:56:13.548Z" }, + { url = "https://files.pythonhosted.org/packages/65/b9/9406a18e9edf558ed504d2a7679371d0f8107e4ef526c80b154ea4ec9752/websockets-17.2-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6281c171557ce0e408e19d9a223f22d915117ac38a5a7f32ed83809e7492316c", size = 227579, upload-time = "2026-10-03T14:56:15.143Z" }, + { url = "https://files.pythonhosted.org/packages/fe/45/a73af119244f46f5130005d7ab63f1c75890c890141a0ca2adc9d97d4671/websockets-17.2-cp315-cp315t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:08d97098644728bd1895caa7ecf3090b8e563d70809870d2adb33a107bd061d0", size = 229205, upload-time = "2026-10-03T14:56:17.086Z" }, + { url = "https://files.pythonhosted.org/packages/c1/92/ccd8e2e921d134a56f1ed4642d276500d9e33b3dc4d6deb63d614b3e53a6/websockets-17.2-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1fdb8d5a1660307dc6d36d0b7fc725213cbd7f80800904dc4896aa3208b89121", size = 228011, upload-time = "2026-10-03T14:56:18.716Z" }, + { url = "https://files.pythonhosted.org/packages/e0/ef/7d71105d19a7aaab5ff87b9c712f6c1dda44e72ea56aa0e7b777f2fc274b/websockets-17.2-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:18b0a46e5e9b315e2b54ce8c3bafdeef0e1388ca363114fa868e6aab2dc58512", size = 226892, upload-time = "2026-10-03T14:56:20.412Z" }, + { url = "https://files.pythonhosted.org/packages/56/f7/87012d628b21e66e699440f39bfa7cc55fae7f52b2c532ab62184a589624/websockets-17.2-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7f115d5d804a2163dd89245710049078b0e726a58c1f44a1f86c2c6e79055d76", size = 224241, upload-time = "2026-10-03T14:56:22.257Z" }, + { url = "https://files.pythonhosted.org/packages/55/f5/495371068b27ee5f7c435187f9dafd62402f195e2c76063bdd4653da1565/websockets-17.2-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:1d829946a2e7630f92f9d7b45b62f3abe9f393cc2dea6a35edb3988f865e75f2", size = 227076, upload-time = "2026-10-03T14:56:23.909Z" }, + { url = "https://files.pythonhosted.org/packages/18/18/3dce3cc6099be5e044e0fd5d0e0c9931c8e3387511cdec8014a345f619e5/websockets-17.2-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:6c274fc1572edf7c197094a0eb1887d45fdc95254bc80597dc7599550486c06a", size = 225727, upload-time = "2026-10-03T14:56:25.689Z" }, + { url = "https://files.pythonhosted.org/packages/47/30/57d0c7aaf8d4473926fa8829b8136483f561388d1e747ae71c9f2a83d5fd/websockets-17.2-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:4173a4b8a025ae44313d9d9b4ecf31e886c7b7faf45386d51a8ca4ff2dcf3f2a", size = 226225, upload-time = "2026-10-03T14:56:27.246Z" }, + { url = "https://files.pythonhosted.org/packages/0c/9f/9dce1203756756c00b407b9a6b13a7500fcd38f2634d4daa3f65575814ec/websockets-17.2-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:d8cfe9522ad69b6abb26b413ed1deca43cb915cefc588433d557cb3ae1c783e2", size = 227333, upload-time = "2026-10-03T14:56:28.811Z" }, + { url = "https://files.pythonhosted.org/packages/9a/2f/d3b6b876678ebb03017b7afd7111fe44d54b93f036a80ebb4b481dd1ab74/websockets-17.2-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:908d81d88bb16141613a6275059b5114656d5c2f0b5400b421d54fe6f1943507", size = 225082, upload-time = "2026-10-03T14:56:30.578Z" }, + { url = "https://files.pythonhosted.org/packages/32/b0/a69b573a5e56d2e7a5dcbb447466f442380cf81515e1cb1220cd626c8042/websockets-17.2-cp315-cp315t-musllinux_1_2_s390x.whl", hash = "sha256:c6590e1eb624ff6b15b872421bc9a10bc6d2057635d69c6cd244ac3f928f85c6", size = 225945, upload-time = "2026-10-03T14:56:32.32Z" }, + { url = "https://files.pythonhosted.org/packages/70/be/a72911dc8e33f74c196012366ce4d99b1a803894a377a1ed0c8e66df9caa/websockets-17.2-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:61040f6f7da5a279d2f77496c69d51132aba75f701c52bded400d4c639277b18", size = 226241, upload-time = "2026-10-03T14:56:34.142Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a9/02a68c1d8e5572918e0962d3aad881078f73ede43abd9b1336e4efaa8909/websockets-17.2-cp315-cp315t-win32.whl", hash = "sha256:f90bad2839c185a1edf8ee22a257cfc8a39e0e337a0490ab185dfa76ef04d1bd", size = 217847, upload-time = "2026-10-03T14:56:36.204Z" }, + { url = "https://files.pythonhosted.org/packages/2b/bf/3d7c33b8d5e7712a60e0149c017ed50394ec5e8cf72e5cb6a1ffaf11a42d/websockets-17.2-cp315-cp315t-win_amd64.whl", hash = "sha256:315551f4ccedbbf9fd4f7e8bf037a5948c976ade0e919ba5d8f581d465f6f725", size = 218169, upload-time = "2026-10-03T14:56:37.79Z" }, + { url = "https://files.pythonhosted.org/packages/27/57/ab34cc6460c5322e6932750fa5c6c64be89e6ee4e2707d13c4e9d3312b25/websockets-17.2-cp315-cp315t-win_arm64.whl", hash = "sha256:0a6220bdf8d5f11af71251a599092d89ac1d6bfac691c7f5951c5b07953947a0", size = 218089, upload-time = "2026-10-03T14:56:39.427Z" }, + { url = "https://files.pythonhosted.org/packages/7f/e2/09ad9cec0fc7e39f983b52f9e49c44f89b7cf7a61d4761fa7fc398f003f9/websockets-17.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:2de1ccf298f5c9e0f27113836d742edb95f015eee3148f004ac386f7ba9a05b1", size = 215348, upload-time = "2026-10-03T14:56:41.037Z" }, + { url = "https://files.pythonhosted.org/packages/80/fe/c307b5d8cdf1852d00606a0403502f0ca5cd8a4736550bab70abce09f7e9/websockets-17.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:761cde41439f0be761aa460e1451a31e2e14baf4a46db6fe4913e5a06a90df66", size = 215621, upload-time = "2026-10-03T14:56:43.097Z" }, + { url = "https://files.pythonhosted.org/packages/78/29/af8412f154cd0568afc043ab478cc8c1ebdf9337b25c85cb9a049d18cfcb/websockets-17.2-pp311-pypy311_pp73-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:15a7101b660a9f15fac34108c92cefc9848f6753a50acef8869e3cd94148fdb7", size = 216569, upload-time = "2026-10-03T14:56:44.979Z" }, + { url = "https://files.pythonhosted.org/packages/fc/76/92ae57b985378036bb8133ea39d1e5cc4d97accad9cae38169426bdcef75/websockets-17.2-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:214da56dba368f61b3d745c77630b2d03c61c02da7b42fe80ef6efba079d3077", size = 216462, upload-time = "2026-10-03T14:56:46.771Z" }, + { url = "https://files.pythonhosted.org/packages/e5/35/e3b276473f7f38984990eb29cf525ffaed131f6136bedb929b5c2ce7151e/websockets-17.2-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:80cbc645af23ac5c12096545c161626960114a1bc10f864760558d3b3e82ba18", size = 217355, upload-time = "2026-10-03T14:56:48.654Z" }, + { url = "https://files.pythonhosted.org/packages/aa/a1/459ab96c5cda8a2164f594be6dc9f868de7971e6abafa696ea07534139a6/websockets-17.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:063508ce9e0db745f30ab52fc652f4e59efc79c2b74934b3837d5cdb974da620", size = 218612, upload-time = "2026-10-03T14:56:50.287Z" }, + { url = "https://files.pythonhosted.org/packages/8a/58/835cd51934d6780fa586f275b5d9901eead6d81569b4343b3767cdbaae4c/websockets-17.2-py3-none-any.whl", hash = "sha256:6aa59f0ef92e796b2db6f5f26550c4713c0e4036899fadf02f55e2ed4db0b7ae", size = 211883, upload-time = "2026-10-03T14:56:51.898Z" }, +] From ca816d3bddadf6859047f8583877b8d3df9cf841 Mon Sep 17 00:00:00 2001 From: Karolis Strazdas Date: Sun, 4 Oct 2026 00:29:07 +0300 Subject: [PATCH 2/2] ci: install Graphviz before strict documentation deployment --- .github/workflows/deploy.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 8251a9b..1f25116 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -25,6 +25,9 @@ jobs: python-version: "3.12" enable-cache: true + - name: Install Graphviz + run: sudo apt-get update && sudo apt-get install -y graphviz + - name: Install dependencies run: uv sync --locked