feat(web): add home/albums/artists API clients for M6a
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,33 @@
|
|||||||
|
import { afterEach, describe, expect, test, vi } from 'vitest';
|
||||||
|
|
||||||
|
vi.mock('./client', () => ({
|
||||||
|
api: { get: vi.fn() }
|
||||||
|
}));
|
||||||
|
|
||||||
|
import { listAlbumsAlpha } from './albums';
|
||||||
|
import { qk } from './queries';
|
||||||
|
import { api } from './client';
|
||||||
|
|
||||||
|
afterEach(() => vi.clearAllMocks());
|
||||||
|
|
||||||
|
describe('albums client', () => {
|
||||||
|
test('listAlbumsAlpha hits /api/library/albums with paging', async () => {
|
||||||
|
(api.get as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||||
|
items: [], total: 0, limit: 50, offset: 0
|
||||||
|
});
|
||||||
|
await listAlbumsAlpha(50, 0);
|
||||||
|
expect(api.get).toHaveBeenCalledWith('/api/library/albums?limit=50&offset=0');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('listAlbumsAlpha honors custom limit and offset', async () => {
|
||||||
|
(api.get as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||||
|
items: [], total: 0, limit: 25, offset: 100
|
||||||
|
});
|
||||||
|
await listAlbumsAlpha(25, 100);
|
||||||
|
expect(api.get).toHaveBeenCalledWith('/api/library/albums?limit=25&offset=100');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('qk.albumsAlpha key is stable', () => {
|
||||||
|
expect(qk.albumsAlpha()).toEqual(['albumsAlpha']);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { createInfiniteQuery } from '@tanstack/svelte-query';
|
||||||
|
import { api } from './client';
|
||||||
|
import { qk } from './queries';
|
||||||
|
import type { AlbumRef, Page } from './types';
|
||||||
|
|
||||||
|
export const ALBUM_PAGE_SIZE = 50;
|
||||||
|
|
||||||
|
export async function listAlbumsAlpha(limit: number, offset: number): Promise<Page<AlbumRef>> {
|
||||||
|
return api.get<Page<AlbumRef>>(`/api/library/albums?limit=${limit}&offset=${offset}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createAlbumsAlphaInfiniteQuery() {
|
||||||
|
return createInfiniteQuery({
|
||||||
|
queryKey: qk.albumsAlpha(),
|
||||||
|
queryFn: ({ pageParam = 0 }) => listAlbumsAlpha(ALBUM_PAGE_SIZE, pageParam),
|
||||||
|
initialPageParam: 0,
|
||||||
|
getNextPageParam: (last) => {
|
||||||
|
const loaded = last.offset + last.items.length;
|
||||||
|
return loaded >= last.total ? undefined : loaded;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { afterEach, describe, expect, test, vi } from 'vitest';
|
||||||
|
|
||||||
|
vi.mock('./client', () => ({
|
||||||
|
api: { get: vi.fn() }
|
||||||
|
}));
|
||||||
|
|
||||||
|
import { listArtistTracks } from './artists';
|
||||||
|
import { qk } from './queries';
|
||||||
|
import { api } from './client';
|
||||||
|
|
||||||
|
afterEach(() => vi.clearAllMocks());
|
||||||
|
|
||||||
|
describe('artists client', () => {
|
||||||
|
test('listArtistTracks hits /api/artists/:id/tracks', async () => {
|
||||||
|
(api.get as ReturnType<typeof vi.fn>).mockResolvedValueOnce([]);
|
||||||
|
await listArtistTracks('art-1');
|
||||||
|
expect(api.get).toHaveBeenCalledWith('/api/artists/art-1/tracks');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('qk.artistTracks key includes the artist id', () => {
|
||||||
|
expect(qk.artistTracks('art-1')).toEqual(['artistTracks', 'art-1']);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { createQuery } from '@tanstack/svelte-query';
|
||||||
|
import { api } from './client';
|
||||||
|
import { qk } from './queries';
|
||||||
|
import type { TrackRef } from './types';
|
||||||
|
|
||||||
|
export async function listArtistTracks(artistId: string): Promise<TrackRef[]> {
|
||||||
|
return api.get<TrackRef[]>(`/api/artists/${artistId}/tracks`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createArtistTracksQuery(artistId: string) {
|
||||||
|
return createQuery({
|
||||||
|
queryKey: qk.artistTracks(artistId),
|
||||||
|
queryFn: () => listArtistTracks(artistId),
|
||||||
|
enabled: artistId.length > 0
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { afterEach, describe, expect, test, vi } from 'vitest';
|
||||||
|
|
||||||
|
vi.mock('./client', () => ({
|
||||||
|
api: { get: vi.fn() }
|
||||||
|
}));
|
||||||
|
|
||||||
|
import { listHome } from './home';
|
||||||
|
import { qk } from './queries';
|
||||||
|
import { api } from './client';
|
||||||
|
import type { HomePayload } from './types';
|
||||||
|
|
||||||
|
afterEach(() => vi.clearAllMocks());
|
||||||
|
|
||||||
|
describe('home client', () => {
|
||||||
|
test('listHome hits /api/home', async () => {
|
||||||
|
const fixture: HomePayload = {
|
||||||
|
recently_added_albums: [],
|
||||||
|
rediscover_albums: [],
|
||||||
|
rediscover_artists: [],
|
||||||
|
most_played_tracks: [],
|
||||||
|
last_played_artists: []
|
||||||
|
};
|
||||||
|
(api.get as ReturnType<typeof vi.fn>).mockResolvedValueOnce(fixture);
|
||||||
|
const got = await listHome();
|
||||||
|
expect(api.get).toHaveBeenCalledWith('/api/home');
|
||||||
|
expect(got).toEqual(fixture);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('qk.home key is stable', () => {
|
||||||
|
expect(qk.home()).toEqual(['home']);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { createQuery } from '@tanstack/svelte-query';
|
||||||
|
import { api } from './client';
|
||||||
|
import { qk } from './queries';
|
||||||
|
import type { HomePayload } from './types';
|
||||||
|
|
||||||
|
export async function listHome(): Promise<HomePayload> {
|
||||||
|
return api.get<HomePayload>('/api/home');
|
||||||
|
}
|
||||||
|
|
||||||
|
// staleTime = 60s — repeat home-page mounts within a minute reuse cached
|
||||||
|
// data. Like-state changes, new plays, freshly-added albums surface on
|
||||||
|
// the next refetch.
|
||||||
|
export function createHomeQuery() {
|
||||||
|
return createQuery({
|
||||||
|
queryKey: qk.home(),
|
||||||
|
queryFn: listHome,
|
||||||
|
staleTime: 60_000
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user