feat(web): add API client modules for Lidarr, requests, admin
T13 of the M5a Lidarr plan. Three new client modules wrap api.get/post/put/del
helpers and the existing TanStack Query qk namespace:
lidarr.ts - searchLidarr() + createLidarrSearchQuery()
requests.ts - createRequest, listMyRequests, getRequest, cancelRequest;
createMyRequestsQuery(); cancel goes through apiFetch
directly because the backend returns the cancelled row body
(api.del's return type is fixed to null).
admin.ts - getLidarrConfig, putLidarrConfig, testLidarrConnection,
listQualityProfiles, listRootFolders, listAdminRequests,
approveRequest, rejectRequest; query factories for each
read; quality profiles + root folders take an enabled prop
so the call site decides when Lidarr is configured.
Shared LidarrRequestStatus / LidarrRequestKind enums and request/config/
search-result shapes added to types.ts. Per-module helpers (CreateRequestParams)
stay in their module files. testLidarrConnection returns a discriminated union
({ok:true,version} | {ok:false,error}) and never throws on ok:false so the
SPA can render either branch.
qk extended with lidarrSearch, myRequests, lidarrConfig,
lidarrQualityProfiles, lidarrRootFolders, adminRequests.
Tests mirror likes.test.ts (vi.mock('./client')) and cover URL construction,
query-param encoding, body shapes, the not-ok testLidarrConnection branch,
and qk additions. 32 new tests, 217 total passing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import { createQuery } from '@tanstack/svelte-query';
|
||||
import { api, apiFetch } from './client';
|
||||
import { qk } from './queries';
|
||||
import type { LidarrRequest, LidarrRequestKind } from './types';
|
||||
|
||||
// CreateRequestParams is the shape callers pass; unused MBID fields are
|
||||
// optional, and we omit them from the wire body rather than sending empty
|
||||
// strings (the backend tolerates either, but this keeps test expectations
|
||||
// crisp and matches the spec §5 wire shape).
|
||||
export type CreateRequestParams = {
|
||||
kind: LidarrRequestKind;
|
||||
lidarr_artist_mbid: string;
|
||||
lidarr_album_mbid?: string;
|
||||
lidarr_track_mbid?: string;
|
||||
artist_name: string;
|
||||
album_title?: string;
|
||||
track_title?: string;
|
||||
};
|
||||
|
||||
type CreateRequestBody = {
|
||||
kind: LidarrRequestKind;
|
||||
lidarr_artist_mbid: string;
|
||||
artist_name: string;
|
||||
lidarr_album_mbid?: string;
|
||||
lidarr_track_mbid?: string;
|
||||
album_title?: string;
|
||||
track_title?: string;
|
||||
};
|
||||
|
||||
function buildCreateBody(params: CreateRequestParams): CreateRequestBody {
|
||||
const body: CreateRequestBody = {
|
||||
kind: params.kind,
|
||||
lidarr_artist_mbid: params.lidarr_artist_mbid,
|
||||
artist_name: params.artist_name
|
||||
};
|
||||
if (params.lidarr_album_mbid) body.lidarr_album_mbid = params.lidarr_album_mbid;
|
||||
if (params.lidarr_track_mbid) body.lidarr_track_mbid = params.lidarr_track_mbid;
|
||||
if (params.album_title) body.album_title = params.album_title;
|
||||
if (params.track_title) body.track_title = params.track_title;
|
||||
return body;
|
||||
}
|
||||
|
||||
export async function createRequest(params: CreateRequestParams): Promise<LidarrRequest> {
|
||||
return api.post<LidarrRequest>('/api/requests', buildCreateBody(params));
|
||||
}
|
||||
|
||||
export async function listMyRequests(): Promise<LidarrRequest[]> {
|
||||
return api.get<LidarrRequest[]>('/api/requests');
|
||||
}
|
||||
|
||||
export async function getRequest(id: string): Promise<LidarrRequest> {
|
||||
return api.get<LidarrRequest>(`/api/requests/${id}`);
|
||||
}
|
||||
|
||||
// Server returns the cancelled row body (not 204) so callers can patch the
|
||||
// cache without a refetch. api.del's return type is fixed to null, so we
|
||||
// drop down to apiFetch here to keep typing honest.
|
||||
export async function cancelRequest(id: string): Promise<LidarrRequest> {
|
||||
return apiFetch(`/api/requests/${id}`, { method: 'DELETE' }) as Promise<LidarrRequest>;
|
||||
}
|
||||
|
||||
export function createMyRequestsQuery() {
|
||||
return createQuery({
|
||||
queryKey: qk.myRequests(),
|
||||
queryFn: listMyRequests
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user