/** * Categories file dumps and playlists by topic, in two sets apart, one of each * {@link CategoryKind}, and give each topic its own page. This module types * them for the server and the client, with the bodies that create and change * them. Those who hold `category:manage` manage both sets on `/manage`. The * client lists them in its `CategoriesProvider`. * * @module */ /** * Lists what a category files: a dump category files dumps, a playlist * category playlists. Each kind is a set of its own, whose slugs and names are * unique within it. */ export const CATEGORY_KINDS = ["dump", "playlist"] as const; /** One of the {@link CATEGORY_KINDS}. */ export type CategoryKind = typeof CATEGORY_KINDS[number]; /** * Checks whether `value` is one of the {@link CATEGORY_KINDS}, for the * category validator and the rows the category service reads. */ export function isCategoryKind(value: unknown): value is CategoryKind { return (CATEGORY_KINDS as readonly unknown[]).includes(value); } /** * Returned by the category routes. A dump category's feed lives at `/` * on the client, a playlist category's at `/playlists/`, and a dump or * playlist names its categories by `id` in `categoryIds`. */ export interface Category { id: string; /** What it files. It never changes. */ kind: CategoryKind; slug: string; name: string; /** Sorts the categories, lowest first. */ position: number; createdAt: Date; updatedAt?: Date; } /** * Passed to `POST /api/categories`. The slug must be free within its kind, and * a dump category's not reserved by a route. */ export interface CreateCategoryRequest { kind: CategoryKind; slug: string; name: string; /** 0 when left out. */ position?: number; } /** * Passed to `PUT /api/categories/:id`. A field left out keeps its value, and * the kind is kept. */ export interface UpdateCategoryRequest { slug?: string; name?: string; position?: number; }