// Cached fetch of the signed-in operator's profile from platform-api. // Mirrors the portal's useMe — kept here so any future middleware / // layout in operator can read identity data SSR-safely without flashing // the wrong layout to the browser. // // No current consumer; the portal version is what motivated this pattern // (route middleware fetching /api/me with bare $fetch missed the session // cookie on SSR, causing a flash of the end-user dashboard before the // client-side redirect kicked in). Adding the same shape here means the // trap is pre-disarmed if operator ever grows comparable middleware. interface MeProfile { _id: string authentikSubjectId: string email: string name: string role: string active: boolean platformAdmin: boolean tenantIds: string[] partnerId?: string partner?: { _id: string; slug: string; name: string; status: string } lastLoginAt?: string } interface MeResponse { profile: MeProfile tenants: unknown[] subscriptions: unknown[] } export function useMe() { const state = useState('operator-me', () => null) async function fetchMe(force = false): Promise { if (state.value && !force) return state.value try { // useRequestFetch on SSR forwards the incoming request's headers // (including the nuxt-oidc-auth session cookie) when calling the // Nitro route. Bare $fetch on SSR has no cookie context and would // 401, producing a stale-state / wrong-layout flash on full reload. const fetcher = useRequestFetch() state.value = await fetcher('/api/me') } catch { state.value = null } return state.value } const profile = computed(() => state.value?.profile ?? null) const isPlatformAdmin = computed(() => !!profile.value?.platformAdmin) return { state, profile, isPlatformAdmin, fetchMe } }