import type { ServiceAccessException, ServiceAppRole, ServiceGrant } from "../../entities/access/types"; import type { Client } from "../../entities/client/types"; import type { Invite } from "../../entities/invite/types"; import type { Service } from "../../entities/service/types"; import type { SyncStatus } from "../../entities/sync/types"; import type { ClientGroup, ClientMembership, LauncherUser } from "../../entities/user/types"; import type { LauncherData, LauncherSettings } from "./mockApi"; export type AdminAccessAssignmentValue = Exclude | "deny" | "unset"; export interface ControlPlaneSnapshot { actor: { id: string; name: string; email: string | null; source: string; }; counts: Record; data: LauncherData; } export interface ControlPlaneMutationResult { data: LauncherData; provisioning?: { authentikUserId: string; email: string; name: string; groups: string[]; created: boolean; temporaryPassword: string | null; } | null; } export async function fetchControlPlaneSnapshot(): Promise { return requestJson("/api/admin/control-plane"); } export async function createAdminClient(payload: Partial): Promise { return requestJson("/api/admin/clients", { method: "POST", body: JSON.stringify(payload), }); } export async function updateAdminClient(clientId: string, patch: Partial): Promise { return requestJson(`/api/admin/clients/${encodeURIComponent(clientId)}`, { method: "PATCH", body: JSON.stringify(patch), }); } export async function deleteAdminClient(clientId: string): Promise { return requestJson(`/api/admin/clients/${encodeURIComponent(clientId)}`, { method: "DELETE" }); } export async function updateAdminUserProfile(userId: string, patch: Partial): Promise { return requestJson(`/api/admin/users/${encodeURIComponent(userId)}/profile`, { method: "PATCH", body: JSON.stringify(patch), }); } export async function createAdminUser(payload: { clientId: string; email: string; name?: string; role?: ClientMembership["role"]; groupIds?: string[]; provisionAuth?: boolean; generatePassword?: boolean; password?: string; }): Promise { return requestJson("/api/admin/users", { method: "POST", body: JSON.stringify(payload), }); } export async function provisionAdminUserAuthentik( userId: string, payload: { generatePassword?: boolean; password?: string } = {} ): Promise { return requestJson(`/api/admin/users/${encodeURIComponent(userId)}/provision-authentik`, { method: "POST", body: JSON.stringify(payload), }); } export async function updateAdminMembership( membershipId: string, patch: Partial ): Promise { return requestJson(`/api/admin/memberships/${encodeURIComponent(membershipId)}`, { method: "PATCH", body: JSON.stringify(patch), }); } export async function deleteAdminMembership(membershipId: string): Promise { return requestJson(`/api/admin/memberships/${encodeURIComponent(membershipId)}`, { method: "DELETE" }); } export async function createAdminGroup(payload: Pick & Partial): Promise { return requestJson("/api/admin/groups", { method: "POST", body: JSON.stringify(payload), }); } export async function updateAdminGroup(groupId: string, patch: Partial): Promise { return requestJson(`/api/admin/groups/${encodeURIComponent(groupId)}`, { method: "PATCH", body: JSON.stringify(patch), }); } export async function deleteAdminGroup(groupId: string): Promise { return requestJson(`/api/admin/groups/${encodeURIComponent(groupId)}`, { method: "DELETE" }); } export async function createAdminService(payload: Partial = {}): Promise { return requestJson("/api/admin/services", { method: "POST", body: JSON.stringify(payload), }); } export async function updateAdminService(serviceId: string, patch: Partial): Promise { return requestJson(`/api/admin/services/${encodeURIComponent(serviceId)}`, { method: "PATCH", body: JSON.stringify(patch), }); } export async function reorderAdminServices(orderedServiceIds: string[]): Promise { return requestJson("/api/admin/services/reorder", { method: "PATCH", body: JSON.stringify({ orderedServiceIds }), }); } export async function deleteAdminService(serviceId: string): Promise { return requestJson(`/api/admin/services/${encodeURIComponent(serviceId)}`, { method: "DELETE" }); } export async function createAdminInvite( payload: Pick ): Promise { return requestJson("/api/admin/invites", { method: "POST", body: JSON.stringify(payload), }); } export async function updateAdminInvite(inviteId: string, patch: Partial): Promise { return requestJson(`/api/admin/invites/${encodeURIComponent(inviteId)}`, { method: "PATCH", body: JSON.stringify(patch), }); } export async function deleteAdminInvite(inviteId: string): Promise { return requestJson(`/api/admin/invites/${encodeURIComponent(inviteId)}`, { method: "DELETE" }); } export async function setAdminUserServiceAccess(payload: { userId: string; serviceId: string; value: AdminAccessAssignmentValue; }): Promise { return requestJson("/api/admin/access/user-service", { method: "POST", body: JSON.stringify(payload), }); } export async function upsertAdminGrant(payload: Partial): Promise { return requestJson("/api/admin/access/grants", { method: "POST", body: JSON.stringify(payload), }); } export async function upsertAdminException(payload: Partial): Promise { return requestJson("/api/admin/access/exceptions", { method: "POST", body: JSON.stringify(payload), }); } export async function retryAdminSync(syncId: string): Promise { return requestJson(`/api/admin/sync/${encodeURIComponent(syncId)}/retry`, { method: "POST" }); } export async function updateAdminSettings(patch: Partial): Promise { return requestJson("/api/admin/settings", { method: "PATCH", body: JSON.stringify(patch), }); } async function requestJson(url: string, init: RequestInit = {}): Promise { const headers = new Headers(init.headers); if (!headers.has("Content-Type")) { headers.set("Content-Type", "application/json"); } const response = await fetch(url, { ...init, headers, }); if (!response.ok) { throw new Error(await readErrorMessage(response)); } return (await response.json()) as T; } async function readErrorMessage(response: Response) { try { const payload = (await response.json()) as { error?: string }; return payload.error ?? response.statusText; } catch { return response.statusText; } }