Skip to content
← Public packages

@kentcdodds/audible

Personal Audible library app — browser re-auth, library, wishlist, NAS archive stub.

src/wishlist.ts

96 lines · 2.4 KB · TypeScript
import { createClient } from './client.ts'

const DEFAULT_RESPONSE_GROUPS = [
	'product_desc',
	'product_attrs',
	'contributors',
	'media',
	'price',
	'rating',
].join(',')

/**
 * List, add, or remove Audible wishlist titles for the signed-in account.
 * Use `action: "list"` (default) to inventory; pass `asin` with add/remove to mutate.
 *
 * @param input - action plus optional asin / pagination
 * @returns Wishlist page, or confirmation for add/remove
 *
 * @example
 * import wishlist from 'kody:@kentcdodds/audible/wishlist'
 *
 * const page = await wishlist({ action: 'list', numResults: 20 })
 * await wishlist({ action: 'add', asin: 'B08G9PRS1K' })
 * await wishlist({ action: 'remove', asin: 'B08G9PRS1K' })
 */
export default async function wishlist(input: {
	action?: 'list' | 'add' | 'remove'
	asin?: string
	numResults?: number
	page?: number
	sortBy?: string
	responseGroups?: string
	locale?: string
} = {}) {
	const action = input.action ?? 'list'
	const client = await createClient({ locale: input.locale })

	if (action === 'list') {
		const payload = await client.request<{
			products?: Array<Record<string, unknown>>
			total_results?: number
		}>({
			path: '/1.0/wishlist',
			query: {
				num_results: Math.min(Math.max(input.numResults ?? 20, 1), 50),
				page: input.page ?? 0,
				sort_by: input.sortBy ?? '-DateAdded',
				response_groups: input.responseGroups ?? DEFAULT_RESPONSE_GROUPS,
			},
		})
		const products = payload.products ?? []
		return {
			action: 'list' as const,
			locale: client.locale.countryCode,
			totalResults: payload.total_results ?? products.length,
			count: products.length,
			products: products.map((p) => ({
				asin: String(p.asin ?? ''),
				title: typeof p.title === 'string' ? p.title : undefined,
				authors: Array.isArray(p.authors)
					? (p.authors as Array<{ name?: string }>)
							.map((a) => a.name)
							.filter(Boolean)
					: undefined,
			})),
		}
	}

	const asin = input.asin?.trim()
	if (!asin) throw new Error(`asin is required for wishlist ${action}.`)

	if (action === 'add') {
		await client.request({
			method: 'POST',
			path: '/1.0/wishlist',
			body: { asin },
		})
		return {
			action: 'add' as const,
			asin,
			ok: true,
			locale: client.locale.countryCode,
		}
	}

	await client.request({
		method: 'DELETE',
		path: `/1.0/wishlist/${encodeURIComponent(asin)}`,
	})
	return {
		action: 'remove' as const,
		asin,
		ok: true,
		locale: client.locale.countryCode,
	}
}