feat(login): show the backend's server-version verdict, and drop a dead route builder
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 29m23s
🏗️ Build and Test JellyTau / Supply Chain (push) Successful in 44s
📱 Test APK / Build test APK (push) Successful in 43m47s
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 6m33s
Traceability Validation / Check Requirement Traces (push) Successful in 14s
🏗️ Build and Test JellyTau / Android Compile Check (push) Successful in 5m21s
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 29m23s
🏗️ Build and Test JellyTau / Supply Chain (push) Successful in 44s
📱 Test APK / Build test APK (push) Successful in 43m47s
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 6m33s
Traceability Validation / Check Requirement Traces (push) Successful in 14s
🏗️ Build and Test JellyTau / Android Compile Check (push) Successful in 5m21s
Two frontend halves of the version-compatibility work.
The login flow now renders ServerCompatibility. A server below the floor blocks
with a message naming the minimum; a server newer than this build gets a
non-blocking note and proceeds; an unreadable version says nothing at all,
because refusing — or even warning — on a version string we could not parse would
punish the user for a limitation of ours.
The frontend never receives a version number to reason about, only the opaque
verdict, for the same reason it never receives an item-type list. Rust decides
whether the server is usable; the frontend decides only how that reads.
Separately, imageCache.getCachedImageUrl is deleted. It built
${serverUrl}/Items/${itemId}/Images/${imageType} in Svelte — a Jellyfin route in
the presentation layer, which is domain logic by this project's own litmus test
(would it change if Jellyfin changed its API?). check:boundary does not catch it:
the tripwire flags item-type array literals, not route strings.
It was also entirely unused. Nothing outside its own file and test ever called
it; the live path is CachedImage.svelte -> commands.imageGetUrl -> Rust, which
was already correct. So the leak was in dead code and the fix is a deletion
rather than a migration.
One consequence left deliberately unacted: that function was the last
convertFileSrc caller, so the asset-protocol grant narrowed to
$APPDATA/thumbnails/** under DR-198 now has no caller at all. Dropping a
capability grant is a security change that deserves its own commit and its own
testing on Android, not a side effect of deleting dead code. Noted in the file.
TRACES: UR-012, UR-085 | DR-285, DR-286
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+43
-1
@@ -2135,7 +2135,18 @@ export type AuthServerInfo = { name: string; version: string; id: string;
|
||||
/**
|
||||
* Normalized server URL with protocol and no trailing slash
|
||||
*/
|
||||
normalizedUrl: string }
|
||||
normalizedUrl: string;
|
||||
/**
|
||||
* Whether this build can talk to this server, as an **opaque state**.
|
||||
*
|
||||
* The version string above is informational — for display and for the log.
|
||||
* This is the judgement, made in Rust, because deciding whether an API
|
||||
* version is usable is domain reasoning: the frontend must never compare a
|
||||
* version number, for the same reason it never receives an item-type list.
|
||||
*
|
||||
* TRACES: UR-085 | DR-286
|
||||
*/
|
||||
compatibility: ServerCompatibility }
|
||||
/**
|
||||
* Autoplay settings (controls next episode behavior)
|
||||
*/
|
||||
@@ -3428,6 +3439,37 @@ export type SecurityStatus = { usingKeyring: boolean; storageType: string }
|
||||
* Audio track preference for a series
|
||||
*/
|
||||
export type SeriesAudioPreference = { seriesId: string; audioTrackDisplayTitle: string | null; audioTrackLanguage: string | null; audioTrackIndex: number | null }
|
||||
/**
|
||||
* The verdict on a server's version.
|
||||
*
|
||||
* Deliberately three states rather than a boolean. "Unrecognised" is not a
|
||||
* failure: a server newer than this build resolves forward and works, and
|
||||
* refusing it would make every JellyTau release expire the moment the server
|
||||
* upgrades. Only a server below the supported floor is refused, where failure
|
||||
* is certain rather than merely likely.
|
||||
*
|
||||
* TRACES: UR-085 | DR-286
|
||||
*/
|
||||
export type ServerCompatibility =
|
||||
/**
|
||||
* A generation this build knows and was tested against.
|
||||
*/
|
||||
{ type: "supported" } |
|
||||
/**
|
||||
* Parsed, but newer than anything this build knows. Treated as the newest
|
||||
* known generation; everything works, and this exists so the UI *may*
|
||||
* mention it rather than so it must.
|
||||
*/
|
||||
{ type: "newerThanKnown" } |
|
||||
/**
|
||||
* The version string could not be parsed. Treated as supported — we do not
|
||||
* refuse a server on the strength of not understanding its version string.
|
||||
*/
|
||||
{ type: "unknownVersion" } |
|
||||
/**
|
||||
* Below the supported floor. This one is a refusal.
|
||||
*/
|
||||
{ type: "tooOld"; minimum: string }
|
||||
/**
|
||||
* Server info returned to frontend
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user