E frontend reconciliation (2/2): align consumers to generated bindings; svelte-check clean
Traceability Validation / Check Requirement Traces (push) Failing after 21s
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 13m21s
🏗️ Build and Test JellyTau / Build Android APK (push) Failing after 2m14s

Reconcile the ~50 frontend files that consumed the old hand-written types against
the stricter generated bindings (141 -> 0 svelte-check errors):

- Nullable strictness: null-coalesce/guard at consumer sites; widen shared helpers
  (CachedImage.tag, ticksToSeconds, formatDuration, getSessionIcon, session store
  send*/transferToRemote) to accept null.
- Field-name fixes exposed by codegen: userData.played -> isPlayed; remote
  NowPlayingItem uses album (not albumName); ArtistItem id/name.
- player.ts: normalize remote NowPlayingItem -> MediaItem in mergedMedia.
- ArtistItem now serializes camelCase (PascalCase alias retained for Jellyfin
  deserialize); update its serialize test.
- Update downloads.test.ts to the bundled { request } shape; complete the
  sessions.test.ts NowPlayingItem mock.

Frontend: svelte-check 0 errors, vitest 448 passing. Backend: 387 passing.
This commit is contained in:
2026-06-20 20:49:20 +02:00
parent 76c78e2edc
commit 14e9d7e03a
21 changed files with 85 additions and 68 deletions
+11 -8
View File
@@ -80,14 +80,17 @@ describe("downloads store", () => {
);
expect(mockInvoke).toHaveBeenCalledWith("download_item", {
itemId: "item-1",
userId: "user-1",
filePath: "/path/to/file.mp3",
mimeType: "audio/mpeg",
priority: 10,
itemName: undefined,
artistName: undefined,
albumName: undefined,
request: {
itemId: "item-1",
userId: "user-1",
filePath: "/path/to/file.mp3",
mimeType: "audio/mpeg",
priority: 10,
itemName: null,
artistName: null,
albumName: null,
expectedSize: null,
},
});
expect(downloadId).toBe(123);
});
+3 -3
View File
@@ -73,7 +73,7 @@ function createPlaybackModeStore() {
* - Polls remote session until track loads
* - Stops local playback
*/
async function transferToRemote(sessionId: string): Promise<void> {
async function transferToRemote(sessionId: string | null | undefined): Promise<void> {
console.log("[PlaybackMode] Transferring to remote session:", sessionId);
update((s) => ({ ...s, isTransferring: true, transferError: null }));
@@ -100,11 +100,11 @@ function createPlaybackModeStore() {
}
// Update local state
sessions.selectSession(sessionId);
sessions.selectSession(sessionId ?? null);
update((s) => ({
...s,
mode: "remote",
remoteSessionId: sessionId,
remoteSessionId: sessionId ?? null,
isTransferring: false,
}));
+9 -2
View File
@@ -40,8 +40,15 @@ describe("sessions store", () => {
nowPlayingItem: {
id: "item-1",
name: "Test Song",
type: "Audio",
serverId: "server-1",
Type: "Audio",
runTimeTicks: null,
album: null,
albumId: null,
albumArtist: null,
artists: null,
imageTags: null,
primaryImageTag: null,
albumPrimaryImageTag: null,
},
playableMediaTypes: ["Audio", "Video"],
supportedCommands: ["PlayPause", "Stop", "Seek", "NextTrack", "PreviousTrack"],
+8 -8
View File
@@ -89,7 +89,7 @@ function createSessionsStore() {
/**
* Send play/pause toggle command
*/
async function sendPlayPause(sessionId: string): Promise<void> {
async function sendPlayPause(sessionId: string | null | undefined): Promise<void> {
try {
await invoke("remote_send_command", {
sessionId,
@@ -106,7 +106,7 @@ function createSessionsStore() {
/**
* Send stop command
*/
async function sendStop(sessionId: string): Promise<void> {
async function sendStop(sessionId: string | null | undefined): Promise<void> {
try {
await invoke("remote_send_command", {
sessionId,
@@ -122,7 +122,7 @@ function createSessionsStore() {
/**
* Send next track command
*/
async function sendNext(sessionId: string): Promise<void> {
async function sendNext(sessionId: string | null | undefined): Promise<void> {
try {
await invoke("remote_send_command", {
sessionId,
@@ -138,7 +138,7 @@ function createSessionsStore() {
/**
* Send previous track command
*/
async function sendPrevious(sessionId: string): Promise<void> {
async function sendPrevious(sessionId: string | null | undefined): Promise<void> {
try {
await invoke("remote_send_command", {
sessionId,
@@ -154,7 +154,7 @@ function createSessionsStore() {
/**
* Seek to position (in ticks)
*/
async function sendSeek(sessionId: string, positionTicks: number): Promise<void> {
async function sendSeek(sessionId: string | null | undefined, positionTicks: number): Promise<void> {
try {
await invoke("remote_session_seek", {
sessionId,
@@ -170,7 +170,7 @@ function createSessionsStore() {
/**
* Set volume (0-100)
*/
async function sendVolume(sessionId: string, volume: number): Promise<void> {
async function sendVolume(sessionId: string | null | undefined, volume: number): Promise<void> {
try {
await invoke("remote_session_set_volume", {
sessionId,
@@ -186,7 +186,7 @@ function createSessionsStore() {
/**
* Toggle mute
*/
async function sendToggleMute(sessionId: string): Promise<void> {
async function sendToggleMute(sessionId: string | null | undefined): Promise<void> {
try {
await invoke("remote_send_command", {
sessionId,
@@ -203,7 +203,7 @@ function createSessionsStore() {
* Play item(s) on remote session
*/
async function playOnSession(
sessionId: string,
sessionId: string | null | undefined,
itemIds: string[],
startIndex = 0
): Promise<void> {