fix(sync): don't treat a stale-server 404 as 'book not in library'

The resolve-endpoint 404 handler conflated two very different failures
because they share a status code. The server's resolve handler answers a
book miss with JSON {"error": "book not found"}, but a 404 produced by
anything else — a server image predating the resolve endpoint, a reverse
proxy, or a mistyped server URL — returns an HTML error page the API
layer surfaces as error="HTTP 404". Both landed in the 'book not in
your library, push progress to link it' branch.

Following that advice against a stale server resurrects the original
first-pull bug through a different door: the push fuzzy-matches the book
by title and overwrites the server's mid-read progress with the device's
first-page position. Plugin and server deploy independently, so version
skew will happen again; this makes it harmless.

Now only the JSON book-not-found body advises pushing (and only
background flows attempt the legacy push-bootstrap). Any other 404 is
reported as an outdated/unreachable server and, critically, pushes
nothing.

Verified against a live server: bogus hash -> 404 {"error":"book not
found"}; route missing (pre-endpoint image) -> HTML 404.
This commit is contained in:
2026-08-22 11:06:58 -04:00
parent 656505eda7
commit 957ae80836
+22 -3
View File
@@ -1186,10 +1186,20 @@ function Bookhoard:_linkBookThenPull(interactive)
end
if result and result.status == 404 then
-- Two very different failures share this status. The server's
-- resolve handler answers a book miss with JSON
-- {"error": "book not found"}; anything else behind a 404
-- (an HTML error page) means the route itself is missing —
-- a server image predating the resolve endpoint, a reverse
-- proxy, or a wrong server URL. Only the former may advise
-- pushing to link: acting on a stale-server 404 would push
-- this device's first-page position over the server's real
-- progress — the very conflict this flow exists to prevent.
if result.error == "book not found" then
-- Genuinely unknown to the server (sideloaded book). The
-- legacy push-bootstrap only ever linked such books via fuzzy
-- title/author matching; keep that as a background attempt,
-- but tell interactive users to push explicitly.
-- legacy push-bootstrap only ever linked such books via
-- fuzzy title/author matching; keep that as a background
-- attempt, but tell interactive users to push explicitly.
if interactive then
UIManager:show(InfoMessage:new{
text = _("This book is not in your Bookhoard library yet. Push progress to link it."),
@@ -1198,6 +1208,15 @@ function Bookhoard:_linkBookThenPull(interactive)
else
self:_bootstrapUUIDThenPull(interactive)
end
else
logger.warn("Bookhoard: resolve endpoint returned 404 without a book-not-found body (stale server?)")
if interactive then
UIManager:show(InfoMessage:new{
text = _("Your Bookhoard server does not support this request and may be outdated. Update the server and try again."),
timeout = 5,
})
end
end
return
end