// §22.9 (M3) — runtime deployment config, replacing the build-time // VITE_APP_NAME. Fetches GET /api/deployment once on boot and provides it to // the whole tree: // // { name, tagline, defaultProjectId, projects[], loading } // // `projects` is the per-caller-visible set (§22.5: public + member-gated; // unlisted omitted). `defaultProjectId` is the corpus-served project the // M3-frontend guard keys on. During the pre-fetch paint, consumers fall back // to the neutral brandTitle() default ('RFC') — never a hardcoded deployment // name. import { createContext, useContext, useEffect, useState } from 'react' import { getDeployment } from '../api' const DeploymentContext = createContext({ name: '', tagline: '', defaultProjectId: null, projects: [], loading: true, }) export function useDeployment() { return useContext(DeploymentContext) } export function DeploymentProvider({ children }) { const [state, setState] = useState({ name: '', tagline: '', defaultProjectId: null, projects: [], loading: true, }) useEffect(() => { let cancelled = false getDeployment() .then(d => { if (cancelled) return setState({ name: d.name || '', tagline: d.tagline || '', defaultProjectId: d.default_project_id || null, projects: Array.isArray(d.projects) ? d.projects : [], loading: false, }) }) .catch(() => { // A failed deployment fetch must not wedge the app: fall back to the // neutral brand and an empty directory so the shell still paints. if (!cancelled) setState(s => ({ ...s, loading: false })) }) return () => { cancelled = true } }, []) return ( {children} ) }