Repository navigation
Releases: felixapel/book-translator-hub
Release list
v2.5.2 — localized settings-menu position controls and publication docs
Container image: ghcr.io/felixapel/cwa-ebook-translate-plugin:2.5.2@sha256:50abc0560627757d06871be3665fb1660e08497a4d91e57928dd161bc8c45c02 (amd64, SBOM and provenance attached).
Changed
- Documentation: Kavita
0.9.1.4with stock OIDC login and the managed hub on Unraid 7.3.4 are recorded as browser-accepted. The README no longer claims a multi-architecture image (it islinux/amd64only) or a bug-bounty programme. Malformed configuration-table rows were fixed and their examples use a generic LAN address. The pull request template moved to.github/pull_request_template.md, so GitHub and Gitea apply it by default. The unuseddocs/assets/demo.giffrom the project's former name was removed. - The README leads with a real screenshot of the stock CWA reader in bilingual mode (a public-domain book translated by a local model) instead of a concept illustration, and adds a features list, an at-a-glance table and install prerequisites.
Fixed
- The settings menu's position controls showed hard-coded Spanish whatever the interface language ("↕ Mover a Top", "Libre (arrastrada)"). They are now translated in all five interface languages.
v2.5.1 — exact edge trust, Unraid exclusive shares and cache/stream fixes
Container image: ghcr.io/felixapel/cwa-ebook-translate-plugin:2.5.1@sha256:9bca080f605a72b1f840375a0708bc3dd7ccfc7c75cfbdb23427a8a4c1ac756e (amd64, SBOM and provenance attached).
Fixed
- Bumped the Alpine packages that Alpine withdrew after the 2.5.0 candidate, so the images build again from a clean cache:
nginx1.30.6-r0in the runtime image, andbrotli-libs1.2.1-r0,c-ares1.34.9-r0,libcurl8.23.0-r0(also in the embeddedbtctlbootstrap Dockerfile),docker-cli29.9.2-r0anddocker-cli-buildx0.38.1-r0inDockerfile.btctl. Thev2.5.0tag exists, but its runtime image could not be built, so no 2.5.0 image was published; 2.5.1 ships the 2.5.0 changes below.
Included from 2.5.0 (tagged, no image published)
Added
- Optional
BT_EDGE_TRUSTED_PROXIEStrusts at most 32 exact operator-controlled immediate edge IPs at nginx, so browsers behind that edge have separate pre-auth admission keys. Empty configuration keeps socket-peer forwarding and existing managed fingerprints. Reader/API/session routes share one address and exact User-Agent; identity assertions are consistently stripped. Enabling, changing or clearing trust requires a new reader login and translator session. Split, hub and standalone Compose inputs are supported, with actual-nginx and native Chromium contract tests; external proxy and physical stock-reader acceptance remain release gates.
Changed
- Removed the overlay's unused streaming client code. The bundled overlay translates through
/translate/batch;/translate/streamremains an API endpoint. The README, architecture and Community Applications guides now describe that behavior, and the Community Applications guide no longer contradicts its own boundary: the profile proxies CWA only and does not publish API port8390. - Documented that behind an operator reverse proxy with empty edge trust all readers share one pre-auth admission budget (
BT_AUTH_RATE_LIMIT_PER_MINUTE,BT_AUTH_MAX_INFLIGHT_PER_CLIENT), in ADR-006, troubleshooting and the configuration reference. The configuration reference now also listsBT_SESSION_COOKIE_NAME,BT_API_PORTand the glossary/feedback limits, and states that HTTP translation requests do not use singleflight coalescing. The README and architecture guide no longer claim that the server can enable browser persistence of translated text. /statsno longer prunes. It ran cache expiry and the full cap scan as a write transaction on every uncached call, which any authenticated reader could repeat through a rate-limit-exempt route. Retention still runs on the write watermark, and/statscounts only unexpired rows, matching cache reads./translateand/translate/streamload the book glossary once per request instead of twice, and a cache lookup probes the single-text contract once when it equals the one-paragraph batch contract.- Startup logs a warning when
BT_LOCAL_URLresolves only to public addresses, because the reader labels that provider local and uses it as a fallback without remote-fallback consent.
Security
- Updated
certifito 2026.10.23 (PYSEC-2026-4320) and the development-onlyundicito 8.12.3 (GHSA-4qv8-2p9j-2685, GHSA-f72v-6w45-q472, GHSA-xjj6-f33q-929c). Both advisories appeared after the 2.5.0 candidate and failed the dependency audits.
Fixed
- Unraid exclusive shares no longer break
btctl. With Permit exclusive shares enabled, Unraid turns/mnt/user/<share>into the link../<pool>/<share>, and every lifecycle command rejected paths below it: the dispatcher refused the environment file ("must use one canonical path without symbolic components") and the mount planner refusedBT_STATE_DIR("Unraid share must be one real directory").btctlnow follows only that exact link. It validates the pool directory, compares overlaps on pool paths and binds the pool path to the configured/mnt/userpath, so the operator, state and Docker binds keep the configured paths. Every other symbolic link is still refused. The stock-Unraid mount plan protocol is now version 3. BT_EDGE_TRUSTED_PROXIESaccepts IPv4 peers only and rejects unspecified and multicast addresses. The reader listener is IPv4-only, so IPv6 peers and these addresses matched no immediate peer and left trust silently off. A retained managed configuration or environment that contains one of them now stopsbtctland the hub with a configuration error; remove the entry. The proxy now warns at startup when a trusted peer is the container's own default gateway: Docker relays host and other-network connections to a published port from that address, so trusting it let them choose their client address. The configuration reference and ADR-021 describe how to trust only the edge.- Bumped the pinned Alpine packages in
Dockerfile.btctlafter Alpine withdrew the old builds:libexpat2.9.0-r0(also in the embeddedbtctlbootstrap Dockerfile),docker-cli29.8.2-r1anddocker-cli-buildx0.34.1-r2.libexpat2.8.5-r0was no longer served, which broke thedocker-smokebootstrap step on every branch. - Managed hub configuration retains a custom CWA login header across restarts and includes it in the deployment fingerprint. All proxy routes strip that assertion; shared validation rejects names that collide with managed context or credentials, including
User-Agent. - A one-paragraph translation group is cached under a contract that includes the book glossary. The first visible paragraph is such a group, so adding or changing a glossary term previously kept serving its cached pre-glossary translation, and translations made with a glossary were stored under the no-glossary key. Entries already stored that way remain reachable only if the book's glossary is emptied again.
/translate/streamwith an Anthropic-protocol provider (Anthropic, MiniMax) no longer waits for a second upstream slot while holding the first. WithBT_MAX_UPSTREAM_INFLIGHT=1every such request failed withwork_budget_exhausted, and two concurrent requests blocked each other until the queue timeout.- A provider stream that fails after sending part of a translation now ends with
provider_stream_interruptedinstead of appending a complete fallback translation to the partial text and caching the result. Failures before the first delta still use an eligible fallback, and HTTP failures follow the same retry, fallback andprovider_rate_limitedpolicy as non-streamed calls. - Glossary terms and paragraph ratings are capped per reader across all books (
BT_GLOSSARY_MAX_TENANT_ENTRIES, default5000;BT_FEEDBACK_MAX_TENANT_ENTRIES, default50000). The existing caps were per book, and book ids are client metadata, so one reader could grow both tables without bound. Each cap check and write now runs in one transaction. - CI, the release gate and the maintainer guides discover the Python suite as the
tests.pythonpackage (-s tests/python -t .). Top-level discovery skipped the package'sDB_PATHredirect, so the 2.4.2 fix did not apply to the main suite run: it still wrotetranslations.dbinto the checkout, and a reused file made database-backed tests depend on earlier runs. - The combined
BT_ROLE=allcontainer (Community Applications profile) serves the API on127.0.0.1only. It listened on all interfaces, so another container on the same Docker network could call the API directly instead of through the proxy. - Removed the overlay's IndexedDB copy of opt-in persisted translations (
BookTranslatorDB). It grew without eviction, was loaded whole on every page, and "Clear all cache" did not reach it. The overlay now deletes that database on load; opt-in persistence keeps the bounded per-languagelocalStoragecache, and the server cache is unchanged. - A leading
<think>…</think>block from a reasoning model served without a reasoning parser is no longer cached or shown as the translation, in single, batch and streamed responses. Streams hold that block back, within the response byte cap, instead of emitting it, and a block that never closes is rejected as an invalid provider response. Cached translations that start with such a block read as misses and are replaced by the next translation. Output is left unchanged when the source paragraph itself contains<think>. - Opt-in browser persistence starts a fresh cache generation and removes the prior generation, so reasoning saved before the provider fix cannot bypass sanitized backend results by being displayed or exported from browser storage. Fresh translations preserve literal
<think>source text. - EPUB export drops characters that XML 1.0 cannot represent (for example a form feed carried over from the source book), which previously produced a chapter readers could not open. Every selectable target language now has its own
dc:languagetag instead of 82 of them falling back toen, and the chapter declares the same language inlang/xml:lang. - Streamed translations are stripped and must be non-empty before they are cached, so they match non-streamed provider output. Streamed responses are closed when the stream ends, a single SSE line is bounded by
BT_MAX_UPSTREAM_RESPONSE_BYTES, andopenai-compatiblestreams connect only to the per-attempt vetted public addresses.
v2.4.2 — Werkzeug security update and startup config validation
Changed
- The Community Applications profile and the managed hub are browser-accepted with CWA 4.0.8.
Security
- Updated Werkzeug to 3.1.9 (CVE-2026-102598) and the development-only
source-map-jsto 1.2.2 (GHSA-68fv-2mgg-jv7q, event-loop denial of service). The v2.4.1 runtime image ships Werkzeug 3.1.8.
Fixed
- Numeric
BT_*settings now fail startup with the variable's name when they are malformed, and the previously unchecked limits (BT_TIMEOUT,BT_MAX_CONCURRENT, token ceilings, paragraph, scope, content-length, glossary and feedback caps) reject zero or negative values instead of failing later at request time. - The Python test suite no longer writes
translations.dbinto the checkout.
v2.4.1 — Stable reader tenants, auth and supply-chain fixes
Changed
- Corrected the public installation, provider-default, compatibility and
performance documentation to match the managed local-provider template and
bounded runtime contracts. - Moved external reverse-proxy guidance to a superseding decision record; it
is not a managed or certified deployment topology. - Historical performance and offline-cache statements describe the work at the
time of those releases; they are not latency, availability or browser-storage
guarantees for a new deployment. - Every CWA and Kavita reader entry and page reload starts with translation
OFF, even when an older mode is stored; book text is sent only after manual
activation. OFF skips paragraph scans and content observation. - Reader asset URLs are versioned from
VERSIONplus the packaged overlay
files, so the one-year immutable cache cannot keep stale JavaScript or CSS
between builds that share a version. Missing packaged assets fail startup.
Fixed
- The reader proxy now re-resolves a named reader upstream through the container's DNS servers from
/etc/resolv.conf(Docker's127.0.0.11on user-defined networks) instead of once at nginx startup, so recreating CWA or Kavita (new container IP) no longer leaves the hub returning 502 until it is restarted. IP literals and names that exist only in/etc/hosts(such ashost.docker.internalfromextra_hosts) keep a staticproxy_pass, because nginx's runtime resolver cannot see them. - Bumped the pinned Alpine
libexpatinDockerfile.btctland the embeddedbtctlbootstrap Dockerfile to2.8.5-r0; Alpine no longer serves2.8.4-r0, which broke thedocker-smokebootstrap step. - Restored image builds after Alpine 3.24 withdrew more pinned packages: the runtime image now pins
libcrypto3/libssl33.5.9-r0andpcre210.49-r0; the operator image and embedded bootstrap pinpcre210.49-r0,nghttp2-libs1.70.0-r0anddocker-cli29.8.2-r0. - Managed CWA readers keep one cache and glossary tenant per CWA user. CWA re-signs its session cookie on every response, so the previous cookie-hash tenant changed on every session exchange: server cache hits lasted at most five minutes and per-book glossaries disappeared. Cookies that name a user are now probed one at a time and the tenant follows the proven user id (ADR-020).
- The
cwa_sessionauthentication mode (Community Applications profile and reference Compose) keeps one cache and glossary tenant per CWA user. Its tenant was a hash of the CWA cookies, which CWA re-signs on every response, so it changed on almost every request. It now uses the same single-cookie user identity as managed readers, keyed by a privatecwa_tenant_keybesideDB_PATHand scoped toBT_CWA_AUTH_URL. - Cache and glossary tenants of managed installs now survive
btctlreinstall and upgrade. Subjects were keyed byreader_session_key, which uninstall deletes to revoke browser sessions, so every hub upgrade orphaned all existing tenants. They now use a privatetenant_keykept with the translation data; an install restarted in place seeds it from its current session key. Upgrading from a 2.4.0 runtime via uninstall/install still starts new tenants once. Split and Unraid installs keep their tenants too: the subject is scoped to the reader's authority URL instead of the connector id, which they regenerate per install. - Enforced exact Origin, CSRF and CORS boundaries for managed reader-session
exchange, and covered the exact Origin path in the Community Applications
smoke gate. - Prevented stale translation state across reader navigation, iframe
replacement and saved-preference changes. - Fixed
setTargetLanguagescope in frontend script (static/translator.js)
preventing runtime ReferenceError on dynamic target language switching. - Completed IndexedDB cache write path (
persistToIndexedDB) to persist cached
book chapters asynchronously across reader sessions. - Propagated HTTP stream errors immediately via
raise_for_status()on
/translate/streamto prevent stalled SSE requests. - Hardened RFC 6265 cookie header tokenization in
reader_session.pyagainst
malformed, quoted, or trailing semicolons in upstream authentication headers. - Hardened cross-platform filesystem locking, permissions, and directory flushing
inbtctl_core.pyand test contracts for Windows environments. - Kept the exact Kavita
0.9.1.4native-account fixture contract explicit;
it does not establish public-browser or OIDC acceptance. - Kept hub smoke response headers in a runner-owned temporary file and accepted
equivalent Docker tmpfs-size representations during managed hub validation. - Pinned patched OpenSSL and libuuid runtime packages.
- CWA no longer translates earlier clipped columns, waits for a page turn
after delayed content, or jumps backward when translation reflows the
chapter; admission and rendering are limited to visible source nodes. - Calibre tables of contents (
div.calibre1 > ul > li > a) are translated
link by link while keeping their destinations.
Security
- Upgraded
urllib3to2.8.0(PYSEC-2026-4175, PYSEC-2026-4176, PYSEC-2026-4177) and the jsdom test dependencyundicito8.11.2, so thepip-auditandnpm auditgates pass again. - Removed the unreferenced legacy
deploy/unraid/my-book-translator-hub.xmlexample. It published API port8390withBT_AUTH_MODE=disabledandBT_ALLOW_INSECURE_AUTH=trueby default, the exact topology the runtime boundary forbids. Managed installs usebtctl; Community Applications uses the separate digest-pinned listing. - CWA reader-session exchange now ignores ambient browser cookies and forwards
only selected CWA authentication cookies to its validation probe.
v2.4.0 — Streaming translation and reader controls
Book Translator Hub v2.4.0
This historical release introduced streamed translation, surrounding-paragraph context, EPUB language detection, and target-language controls for the reader overlay.
/translate/streamrenders model output progressively, with buffered or cached fallback paths.BT_CONTEXT_WINDOWcontrols how surrounding text is supplied as translation context.- Source-language detection uses available book metadata and text hints; readers can choose their target language.
- The session broker exchanges supported reader credentials for short-lived hub sessions. Exact reader versions and authentication modes require their own acceptance checks.
- Translation caching includes a server-side SQLite cache. Browser persistence is optional and subject to browser storage limits and configuration.
Corrections to the original announcement
These notes replace earlier unqualified claims about 160 ms latency, zero-wait page turns, universal Kavita compatibility, complete offline books, guaranteed isolation, and fully backward-compatible upgrades. They were not established release guarantees. Latency and translation quality depend on the model, hardware, workload, network, and cache state. Consult the documentation at the selected release tag and validate the complete reader flow before upgrading.
The immutable v2.4.0 tag and its source remain unchanged. Subsequent authentication, reader-navigation, and runtime hardening on the main branch are not part of this historical tag. Follow the repository pull requests and changelog for the next patch release and its acceptance status.
v2.3.2 — Instant Viewport Rush & Top-3 Paragraph Low-Latency Pipeline
[2.3.2] - 2026-09-04
Added
- Instant Viewport Rush: First 1, 2, and 3 uncached visible paragraphs on every page are dispatched concurrently in parallel micro-requests directly to
/translate. - Progressive Per-Paragraph Rendering: Each of the top 3 paragraphs appears in the reader DOM the instant its individual inference completes (~1.9s - 2.2s total for all 3 paragraphs).
- Reader Navigation Keyboard Shortcuts:
ArrowRight,ArrowLeft,PageDown,PageUp,Spacewith fast 80ms settle detection. - Cross-Endpoint Bidirectional Cache Interoperability: Single-paragraph translations saved by
/translateare immediately recognized as cache hits by/translate/batch, and vice versa.
Fixed
- Unblocked Page-Turn Detector: Background prefetching no longer freezes page turn recognition, allowing instant cancellation of background work to prioritize the reader's new visible page immediately.
v2.3.1 — Zero-Wait Directional Lookahead & SQLite MMAP Cache
[2.3.1] - 2026-09-04
Added
- Zero-Wait Directional Lookahead Prefetch: Translates upcoming pages ahead of the reader for an instantaneous 0ms page-turn experience.
- Directional Paragraph Queue Sorting: Visible viewport first, forward paragraphs next, backward paragraphs last.
- Instant TTFT Initial Micro-Chunking: Micro-chunking for low-latency initial paragraph response.
Performance
- High-Throughput SQLite WAL PRAGMAs: 256MB mmap, 64MB RAM page cache, and in-memory temp tables for sub-millisecond cache lookups.
v2.3.0 — Universal reader hub, adaptive batching & decoupled proxy
[2.3.0] - 2026-09-03
Added
- Added draggable floating translator interface with pointer and touch events,
viewport boundary clamping, quick-position controls, and persistent geometry
stored inlocalStorageunderbt_pos(ADR-018). - Added architectural support and guidance for master reverse proxy (SWAG)
decoupling using HTTPsub_filterinjection, allowing stock readers (CWA, Kavita)
to stay online independently while the hub runs in pure API mode (BT_ROLE=api). - Configured Gunicorn worker heartbeat tmpdir to
/dev/shmacross standalone API
and supervised hub runtimes to eliminate spurious heartbeat timeouts during heavy inference. - Pinned updated Alpine 3.24 dependencies in base container images and exporter
bootstrap:pcre2=10.48-r0,libcurl=8.22.0-r0, andlibexpat=2.8.4-r0.
Changed
- Added managed cloud-oriented batching: a configurable browser/group maximum,
an optional CJK-aware source-token budget, and background-only prefetch
pacing reduce provider request pressure without delaying the first visible
paragraph. Compatibility defaults retain count-only grouping. - Added sanitized provider rate-limit metadata, explicit pre-provider replay
safety for HTTP429, and fixed-cardinality provider/batch metrics. Ambiguous
or provider-originated failures remain terminal until an explicit retry. - Documented the universal one-container hub as the default CWA/Kavita install,
with explicit reader switches, topology-specific provider cutover and rollback,
and split deployment retained as an advanced isolation option. - Made Gemini a complete server-side backend in quick-start examples using the
stablegemini-3.5-flash-litemodel; local vLLM and fallback providers are now
described as optional instead of implied deployment requirements. - Expanded lifecycle, troubleshooting, compatibility and security guidance for
hub operation, Gemini API errors, private key handling, regenerated browser
sessions and per-reader isolation. - Moved generated Compose credentials into mode-
0600raw environment files,
introduced split state schema 3, retained read-only doctor/uninstall support
for former inline-environment schema 2, and required Docker Compose 2.30 or
newer for new Compose installations. - Reduced reader latency with a one-paragraph first visible request followed by
bounded five-paragraph batches, removed the unconditional client delay,
reused fixed-provider HTTP connections per worker, and committed each cache
batch in one SQLite transaction. - Added keyboard retry and settings-dialog focus management, bounded custom DNS
resolver capacity, full discovered backend coverage, universal hub smoke and
opt-in deep provider diagnosis.
Fixed
- Normalized fresh universal-hub data directories before inspecting private
reader credentials, so caller-owned mode-0700paths work for non-root
Compose and root Unraid while retained UID-101 keys remain distinguishable
from credentials created by a failed install attempt. - Ran read-only hub credential and data verification as the owning runtime UID,
allowing reinstall and non-root Compose operation to traverse retained
mode-0700reader directories without adding Docker capabilities. - Journaled universal-hub installs before persistent mutation, preserved exact
cleaned retry evidence, removed only session keys created by a failed attempt,
and surfaced cleanup failures instead of leaving an ambiguous partial runtime. - Corrected the immutable release sequence so the identical annotated tag is
verified on the GitHub mirror before authoritative Gitea publication begins. - Added fixed-cardinality translation latency buckets so cloud batch tuning can
observe tail movement without book, reader or request labels. - Propagated adaptive batching through both hub and split managed installs,
rejected browser/API batch-limit mismatches before startup, made provider
429terminal before retry/fallback, and kept safe browser retry bounds and
visible-work priority stable across reader DOM rediscovery. - Updated Gemini/OpenAI-compatible request contracts for current Gemini models,
including omission of deprecated sampling fields and invalid prefilled model
turns.
[2.3.0-rc.1] - Unreleased candidate
Security
- Added a reader-neutral, five-minute maximum session broker. Raw CWA cookies,
Kavita access tokens and exact Kavita OIDC cookie chunks are accepted only by
the same-origin exchange route, validated against the pinned reader account
endpoint, never persisted, and replaced with an opaque HttpOnly cookie bound
to the connector, public origin, observed address and User-Agent. - Ordinary translation routes now strip bearer credentials and, in managed
reader-session mode, every reader cookie. Provider HTTP clients ignore
inherited proxy variables, expired cache rows are deleted on lookup, DOM
restoration uses pristine clones, and uninstall removes the connector secret
without removing translations. - Lifecycle mutation now binds execution to immutable plan inputs and journals
recoverable install attempts before the first owned runtime mutation. - The managed v2.1.4 migration path now recognizes the exact historical
Community Applicationsghcr.io/felixapel/cwa-ebook-translate-plugin:latest
reference only after the container's immutable image ID is probed in a
network-disabled sandbox and reports version 2.1.4. Other mutablelatest
references remain rejected.
Changed
- Managed reader preflight can now bind a mutable container tag to an explicit
immutable Docker image ID; the install and doctor fail closed if that exact
runtime image changes. - Generalized schema-2 lifecycle state, generated resources and browser
contracts from CWA-specific fields to explicit stock-reader connectors while
retaining schema-1 CWA compatibility. - Updated the pinned Alpine runtime closure to the exact packages still
available for the immutable base image, including nginx1.30.4-r1. - Replaced the accumulated, overlapping documentation set with one indexed
guide hierarchy for installation, operations, reference material,
maintainers, and durable architecture decisions. - Moved automated tests under
tests/, live probes and benchmarks under
tools/, and Python dependency inputs and hash locks underrequirements/. - Narrowed the Docker build context to runtime inputs and removed obsolete
systemd and legacy Unraid template artifacts from the supported tree. - Added repository guidance and documentation contracts so CI, contributor
commands, release checks, and public docs stay aligned with the canonical
layout. - Pinned the lock compiler's build frontend to a reviewed non-yanked release
instead of retaining a withdrawn transitive candidate.
Added
- Added a stock Kavita v0.9.0.2 EPUB connector for the exact
/library/:libraryId/series/:seriesId/book/:chapterIdroute and
.book-contentDOM, including SPA teardown, route-derived cache scopes and
one bounded session refresh/replay after401. - Added unit, real-Chromium and real-container coverage for separate CWA/Kavita
connectors, Kavita native authentication, unsupported manga/PDF isolation,
credential stripping and reader-neutral lifecycle artifacts.
v2.3.0-rc.1 — Universal reader hub, adaptive batching & decoupled proxy
[2.3.0-rc.1] - 2026-09-03
Added
- Added draggable floating translator interface with pointer and touch events,
viewport boundary clamping, quick-position controls, and persistent geometry
stored inlocalStorageunderbt_pos(ADR-018). - Added architectural support and guidance for master reverse proxy (SWAG)
decoupling using HTTPsub_filterinjection, allowing stock readers (CWA, Kavita)
to stay online independently while the hub runs in pure API mode (BT_ROLE=api). - Configured Gunicorn worker heartbeat tmpdir to
/dev/shmacross standalone API
and supervised hub runtimes to eliminate spurious heartbeat timeouts during heavy inference. - Pinned updated Alpine 3.24 dependencies in base container images and exporter
bootstrap:pcre2=10.48-r0,libcurl=8.22.0-r0, andlibexpat=2.8.4-r0.
Changed
- Added managed cloud-oriented batching: a configurable browser/group maximum,
an optional CJK-aware source-token budget, and background-only prefetch
pacing reduce provider request pressure without delaying the first visible
paragraph. Compatibility defaults retain count-only grouping. - Added sanitized provider rate-limit metadata, explicit pre-provider replay
safety for HTTP429, and fixed-cardinality provider/batch metrics. Ambiguous
or provider-originated failures remain terminal until an explicit retry. - Documented the universal one-container hub as the default CWA/Kavita install,
with explicit reader switches, topology-specific provider cutover and rollback,
and split deployment retained as an advanced isolation option. - Made Gemini a complete server-side backend in quick-start examples using the
stablegemini-3.5-flash-litemodel; local vLLM and fallback providers are now
described as optional instead of implied deployment requirements. - Expanded lifecycle, troubleshooting, compatibility and security guidance for
hub operation, Gemini API errors, private key handling, regenerated browser
sessions and per-reader isolation. - Moved generated Compose credentials into mode-
0600raw environment files,
introduced split state schema 3, retained read-only doctor/uninstall support
for former inline-environment schema 2, and required Docker Compose 2.30 or
newer for new Compose installations. - Reduced reader latency with a one-paragraph first visible request followed by
bounded five-paragraph batches, removed the unconditional client delay,
reused fixed-provider HTTP connections per worker, and committed each cache
batch in one SQLite transaction. - Added keyboard retry and settings-dialog focus management, bounded custom DNS
resolver capacity, full discovered backend coverage, universal hub smoke and
opt-in deep provider diagnosis.
Fixed
- Normalized fresh universal-hub data directories before inspecting private
reader credentials, so caller-owned mode-0700paths work for non-root
Compose and root Unraid while retained UID-101 keys remain distinguishable
from credentials created by a failed install attempt. - Ran read-only hub credential and data verification as the owning runtime UID,
allowing reinstall and non-root Compose operation to traverse retained
mode-0700reader directories without adding Docker capabilities. - Journaled universal-hub installs before persistent mutation, preserved exact
cleaned retry evidence, removed only session keys created by a failed attempt,
and surfaced cleanup failures instead of leaving an ambiguous partial runtime. - Corrected the immutable release sequence so the identical annotated tag is
verified on the GitHub mirror before authoritative Gitea publication begins. - Added fixed-cardinality translation latency buckets so cloud batch tuning can
observe tail movement without book, reader or request labels. - Propagated adaptive batching through both hub and split managed installs,
rejected browser/API batch-limit mismatches before startup, made provider
429terminal before retry/fallback, and kept safe browser retry bounds and
visible-work priority stable across reader DOM rediscovery. - Updated Gemini/OpenAI-compatible request contracts for current Gemini models,
including omission of deprecated sampling fields and invalid prefilled model
turns.
[2.3.0-rc.1] - Unreleased candidate
Security
- Added a reader-neutral, five-minute maximum session broker. Raw CWA cookies,
Kavita access tokens and exact Kavita OIDC cookie chunks are accepted only by
the same-origin exchange route, validated against the pinned reader account
endpoint, never persisted, and replaced with an opaque HttpOnly cookie bound
to the connector, public origin, observed address and User-Agent. - Ordinary translation routes now strip bearer credentials and, in managed
reader-session mode, every reader cookie. Provider HTTP clients ignore
inherited proxy variables, expired cache rows are deleted on lookup, DOM
restoration uses pristine clones, and uninstall removes the connector secret
without removing translations. - Lifecycle mutation now binds execution to immutable plan inputs and journals
recoverable install attempts before the first owned runtime mutation. - The managed v2.1.4 migration path now recognizes the exact historical
Community Applicationsghcr.io/felixapel/cwa-ebook-translate-plugin:latest
reference only after the container's immutable image ID is probed in a
network-disabled sandbox and reports version 2.1.4. Other mutablelatest
references remain rejected.
Changed
- Managed reader preflight can now bind a mutable container tag to an explicit
immutable Docker image ID; the install and doctor fail closed if that exact
runtime image changes. - Generalized schema-2 lifecycle state, generated resources and browser
contracts from CWA-specific fields to explicit stock-reader connectors while
retaining schema-1 CWA compatibility. - Updated the pinned Alpine runtime closure to the exact packages still
available for the immutable base image, including nginx1.30.4-r1. - Replaced the accumulated, overlapping documentation set with one indexed
guide hierarchy for installation, operations, reference material,
maintainers, and durable architecture decisions. - Moved automated tests under
tests/, live probes and benchmarks under
tools/, and Python dependency inputs and hash locks underrequirements/. - Narrowed the Docker build context to runtime inputs and removed obsolete
systemd and legacy Unraid template artifacts from the supported tree. - Added repository guidance and documentation contracts so CI, contributor
commands, release checks, and public docs stay aligned with the canonical
layout. - Pinned the lock compiler's build frontend to a reviewed non-yanked release
instead of retaining a withdrawn transitive candidate.
Added
- Added a stock Kavita v0.9.0.2 EPUB connector for the exact
/library/:libraryId/series/:seriesId/book/:chapterIdroute and
.book-contentDOM, including SPA teardown, route-derived cache scopes and
one bounded session refresh/replay after401. - Added unit, real-Chromium and real-container coverage for separate CWA/Kavita
connectors, Kavita native authentication, unsupported manga/PDF isolation,
credential stripping and reader-neutral lifecycle artifacts.