Skip to content

Commit f3dfdc2

Browse files
robbeverhelstclaude
andcommitted
fix(lidarr): unwrap paged blocklist and wanted results
GET /api/v1/blocklist, /api/v1/wanted/missing, and /api/v1/wanted/cutoff return paging resources, not bare arrays. The CLI passed those responses straight to unwrapData<any[]>() and then called .map(), so all three commands crashed with "…map is not a function". Add a getRecords() helper that accepts either shape and use it at the three call sites. Covered by regression tests that exercise both the array and { records: [...] } response forms. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent d87b949 commit f3dfdc2

2 files changed

Lines changed: 96 additions & 3 deletions

File tree

src/cli/commands/lidarr.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ export const resources: ResourceDef[] = [
455455
description: 'List blocked releases',
456456
columns: ['id', 'artistName', 'sourceTitle', 'date'],
457457
run: async (c: LidarrClient) => {
458-
const items = unwrapData<any[]>(await c.getBlocklist());
458+
const items = getRecords<any>(await c.getBlocklist());
459459
return items.map(withArtistName);
460460
},
461461
},
@@ -477,7 +477,7 @@ export const resources: ResourceDef[] = [
477477
description: 'List albums with missing tracks',
478478
columns: ['id', 'artistName', 'title', 'releaseDate'],
479479
run: async (c: LidarrClient) => {
480-
const albums = unwrapData<any[]>(await c.getWantedMissing());
480+
const albums = getRecords<any>(await c.getWantedMissing());
481481
return albums.map(withArtistName);
482482
},
483483
},
@@ -486,7 +486,7 @@ export const resources: ResourceDef[] = [
486486
description: 'List albums below quality cutoff',
487487
columns: ['id', 'artistName', 'title', 'releaseDate'],
488488
run: async (c: LidarrClient) => {
489-
const albums = unwrapData<any[]>(await c.getWantedCutoff());
489+
const albums = getRecords<any>(await c.getWantedCutoff());
490490
return albums.map(withArtistName);
491491
},
492492
},
@@ -592,3 +592,12 @@ function withArtistName(item: any) {
592592
artistName: item?.artistName ?? item?.artist?.artistName ?? '—',
593593
};
594594
}
595+
596+
function getRecords<T>(result: unknown): T[] {
597+
const data = unwrapData<any>(result);
598+
599+
if (Array.isArray(data)) return data;
600+
if (Array.isArray(data?.records)) return data.records;
601+
602+
return [];
603+
}

tests/cli-lidarr-defs.test.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,4 +231,88 @@ describe('Lidarr command definitions', () => {
231231
expect(system!.actions.map(a => a.name)).toEqual(['status', 'health']);
232232
});
233233
});
234+
235+
it('normalizes array and paged blocklist responses', async () => {
236+
const action = getAction('blocklist', 'list');
237+
const blocklistItems = [
238+
{
239+
id: 3,
240+
sourceTitle: 'Artist - Album',
241+
date: '2026-07-23T12:00:00Z',
242+
artist: { artistName: 'Test Artist' },
243+
},
244+
];
245+
246+
for (const data of [blocklistItems, { records: blocklistItems }]) {
247+
const result = await action.run(
248+
{
249+
getBlocklist: () => Promise.resolve({ data }),
250+
},
251+
{}
252+
);
253+
254+
expect(result).toEqual([
255+
{
256+
...blocklistItems[0],
257+
artistName: 'Test Artist',
258+
},
259+
]);
260+
}
261+
});
262+
263+
it('normalizes array and paged wanted missing responses', async () => {
264+
const action = getAction('wanted', 'missing');
265+
const albums = [
266+
{
267+
id: 4,
268+
title: 'Album',
269+
releaseDate: '2026-07-23',
270+
artist: { artistName: 'Test Artist' },
271+
},
272+
];
273+
274+
for (const data of [albums, { records: albums }]) {
275+
const result = await action.run(
276+
{
277+
getWantedMissing: () => Promise.resolve({ data }),
278+
},
279+
{}
280+
);
281+
282+
expect(result).toEqual([
283+
{
284+
...albums[0],
285+
artistName: 'Test Artist',
286+
},
287+
]);
288+
}
289+
});
290+
291+
it('normalizes array and paged wanted cutoff responses', async () => {
292+
const action = getAction('wanted', 'cutoff');
293+
const albums = [
294+
{
295+
id: 5,
296+
title: 'Album',
297+
releaseDate: '2026-07-23',
298+
artist: { artistName: 'Test Artist' },
299+
},
300+
];
301+
302+
for (const data of [albums, { records: albums }]) {
303+
const result = await action.run(
304+
{
305+
getWantedCutoff: () => Promise.resolve({ data }),
306+
},
307+
{}
308+
);
309+
310+
expect(result).toEqual([
311+
{
312+
...albums[0],
313+
artistName: 'Test Artist',
314+
},
315+
]);
316+
}
317+
});
234318
});

0 commit comments

Comments
 (0)