// The scopes the admin judges its write affordances against. // // READ THIS BEFORE SWAPPING IT OUT — the shape changed, and the old shape had a // trap. The admin no longer invents a scope per entity (`:create` and // friends). It reads each procedure's OWN declared access off the capability // map (`spec.create.guards` — the descriptor's `guards:` / `openAccess:`) and // decides with `useAccessDecision`. So these scopes are matched against what // your api really declares; a name that appears in neither place gates nothing. // // That is the whole fix. A UI gating on an invented convention hides every write // from every caller of every app that named its scopes differently — a total // outage of the affordance that reads like a working permission check, and that // a demo seeding `admin:full` can never surface. // // DEMO: we feed `admin:full` (the blanket-bypass scope) so the scaffold shows // every action on first boot. In a real app, REPLACE this with the current // subject's scopes from your session — e.g. a reactive query: // // const { data } = useSubscription<{ scopes: string[] }>('app', 'auth.session') // // // useAccessDecision reads these reactively, so affordances update the instant // the subject's roles change. (This is UX gating, not enforcement — the api's // own guards remain the real authorization boundary. A control shown while the // decision is `unknown` is deliberate: a per-row guard is the server's to // answer, and it answers with a typed ScopeError.) export const DEMO_SCOPES: ReadonlyArray = ['admin:full']