35 lines
1.1 KiB
TypeScript
35 lines
1.1 KiB
TypeScript
import type { BaseOption, VariantOption } from "@ben-to/builder/domain";
|
|
|
|
export type RecipesIndex = Readonly<{
|
|
bases: ReadonlyArray<BaseOption>;
|
|
variants: ReadonlyArray<VariantOption>;
|
|
}>;
|
|
|
|
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
typeof value === "object" && value !== null;
|
|
|
|
export const fetchRecipesIndex = async (
|
|
catalogUrl = "/recipes/catalog.json"
|
|
): Promise<RecipesIndex> => {
|
|
const response = await fetch(catalogUrl, { headers: { Accept: "application/json" } });
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to load recipe catalog (${response.status})`);
|
|
}
|
|
|
|
const payload: unknown = await response.json();
|
|
if (!isRecord(payload)) {
|
|
throw new Error("Invalid recipe catalog payload");
|
|
}
|
|
|
|
const bases = payload.bases;
|
|
const variants = payload.variants;
|
|
if (!Array.isArray(bases) || !Array.isArray(variants)) {
|
|
throw new Error("Invalid recipe catalog shape");
|
|
}
|
|
|
|
return Object.freeze({
|
|
bases: Object.freeze(bases as BaseOption[]),
|
|
variants: Object.freeze(variants as VariantOption[])
|
|
});
|
|
};
|