/** * Which slugs a category may take. Category slugs live at the URL root (e.g. * /music), so they must never collide with the frontend's own routes. * * @module */ /** * Top-level path segments that already have meaning in the SPA router (see * src/App.tsx), plus a few reserved for infrastructure. */ export const RESERVED_SLUGS: readonly string[] = [ "~", "dumps", "users", "playlists", "search", "login", "register", "notifications", "reset-password", "manage", "api", "assets", ]; /** * A well-formed category slug: lowercase alphanumerics, * hyphen-separated, no leading, trailing or double hyphen. */ export const CATEGORY_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/; /** Checks whether `slug` is well-formed (see {@link CATEGORY_SLUG_RE}). */ export function isValidSlugFormat(slug: string): boolean { return CATEGORY_SLUG_RE.test(slug); } /** Checks whether `slug` is one of the {@link RESERVED_SLUGS}. */ export function isReservedSlug(slug: string): boolean { return RESERVED_SLUGS.includes(slug); } /** Checks whether `slug` is well-formed and not reserved. */ export function isSlugAvailable(slug: string): boolean { return isValidSlugFormat(slug) && !isReservedSlug(slug); }