/** * Platforms — what a project is built on or ships as (milestone 463). * * The catalog is GLOBAL, like the canonical areas, and admin-written. A * project's answer per platform is `declared` (a person said so), `detected` * (a marker file in a bound repo said so) or `rejected` (a person said no — * kept, so the next refresh cannot detect it back). Only declared and * detected make a project a member, and membership is what decides which * family ideas reach it. */ import { apiGet, apiPatch, apiPost, apiPut } from "@/api/client"; export interface Platform { id: number; name: string; /** The match key, and the name every door takes (stable across restores). */ slug: string; description: string | null; /** Repo-relative globs. A bare name matches a basename anywhere; one with * a slash matches the whole path. Empty = declare-only. */ markers: string[]; order_index: number; created_at: string | null; updated_at: string | null; } export type PlatformState = "declared" | "detected" | "rejected"; /** What a person may set. `null` withdraws the answer. */ export type SettablePlatformState = "declared" | "rejected" | null; export interface ProjectPlatform { id: number; slug: string; name: string; state: PlatformState; } export const MEMBER_STATES: PlatformState[] = ["declared", "detected"]; export async function listPlatforms(): Promise { const data = await apiGet<{ platforms: Platform[] }>("/api/platforms"); return data.platforms; } /** Admin only. A name that reduces to an existing slug answers 409. */ export async function createPlatform(data: { name: string; description?: string; markers?: string[]; }): Promise { return apiPost("/api/platforms", data); } export async function updatePlatform( id: number, data: Partial<{ name: string; description: string; order_index: number; markers: string[] }>, ): Promise { return apiPatch(`/api/platforms/${id}`, data); } export async function fetchProjectPlatforms(projectId: number): Promise { const data = await apiGet<{ project_platforms: ProjectPlatform[] }>( `/api/projects/${projectId}/platforms`, ); return data.project_platforms; } /** Only the slugs named change; the update applies whole or not at all. */ export async function setProjectPlatforms( projectId: number, platforms: Record, ): Promise { const data = await apiPut<{ project_platforms: ProjectPlatform[] }>( `/api/projects/${projectId}/platforms`, { platforms }, ); return data.project_platforms; }