NODEDC_LAUNCHER/src/shared/api/adminApi.ts

228 lines
8.0 KiB
TypeScript

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<ServiceAppRole, "owner"> | "deny" | "unset";
export interface ControlPlaneSnapshot {
actor: {
id: string;
name: string;
email: string | null;
source: string;
};
counts: Record<string, number>;
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<ControlPlaneSnapshot> {
return requestJson<ControlPlaneSnapshot>("/api/admin/control-plane");
}
export async function createAdminClient(payload: Partial<Client>): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>("/api/admin/clients", {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function updateAdminClient(clientId: string, patch: Partial<Client>): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>(`/api/admin/clients/${encodeURIComponent(clientId)}`, {
method: "PATCH",
body: JSON.stringify(patch),
});
}
export async function deleteAdminClient(clientId: string): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>(`/api/admin/clients/${encodeURIComponent(clientId)}`, { method: "DELETE" });
}
export async function updateAdminUserProfile(userId: string, patch: Partial<LauncherUser>): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>(`/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<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>("/api/admin/users", {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function provisionAdminUserAuthentik(
userId: string,
payload: { generatePassword?: boolean; password?: string } = {}
): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>(`/api/admin/users/${encodeURIComponent(userId)}/provision-authentik`, {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function updateAdminMembership(
membershipId: string,
patch: Partial<ClientMembership>
): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>(`/api/admin/memberships/${encodeURIComponent(membershipId)}`, {
method: "PATCH",
body: JSON.stringify(patch),
});
}
export async function deleteAdminMembership(membershipId: string): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>(`/api/admin/memberships/${encodeURIComponent(membershipId)}`, { method: "DELETE" });
}
export async function createAdminGroup(payload: Pick<ClientGroup, "clientId"> & Partial<ClientGroup>): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>("/api/admin/groups", {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function updateAdminGroup(groupId: string, patch: Partial<ClientGroup>): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>(`/api/admin/groups/${encodeURIComponent(groupId)}`, {
method: "PATCH",
body: JSON.stringify(patch),
});
}
export async function deleteAdminGroup(groupId: string): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>(`/api/admin/groups/${encodeURIComponent(groupId)}`, { method: "DELETE" });
}
export async function createAdminService(payload: Partial<Service> = {}): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>("/api/admin/services", {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function updateAdminService(serviceId: string, patch: Partial<Service>): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>(`/api/admin/services/${encodeURIComponent(serviceId)}`, {
method: "PATCH",
body: JSON.stringify(patch),
});
}
export async function reorderAdminServices(orderedServiceIds: string[]): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>("/api/admin/services/reorder", {
method: "PATCH",
body: JSON.stringify({ orderedServiceIds }),
});
}
export async function deleteAdminService(serviceId: string): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>(`/api/admin/services/${encodeURIComponent(serviceId)}`, { method: "DELETE" });
}
export async function createAdminInvite(
payload: Pick<Invite, "clientId" | "email" | "role">
): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>("/api/admin/invites", {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function updateAdminInvite(inviteId: string, patch: Partial<Invite>): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>(`/api/admin/invites/${encodeURIComponent(inviteId)}`, {
method: "PATCH",
body: JSON.stringify(patch),
});
}
export async function deleteAdminInvite(inviteId: string): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>(`/api/admin/invites/${encodeURIComponent(inviteId)}`, { method: "DELETE" });
}
export async function setAdminUserServiceAccess(payload: {
userId: string;
serviceId: string;
value: AdminAccessAssignmentValue;
}): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>("/api/admin/access/user-service", {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function upsertAdminGrant(payload: Partial<ServiceGrant>): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>("/api/admin/access/grants", {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function upsertAdminException(payload: Partial<ServiceAccessException>): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>("/api/admin/access/exceptions", {
method: "POST",
body: JSON.stringify(payload),
});
}
export async function retryAdminSync(syncId: string): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>(`/api/admin/sync/${encodeURIComponent(syncId)}/retry`, { method: "POST" });
}
export async function updateAdminSettings(patch: Partial<LauncherSettings>): Promise<ControlPlaneMutationResult> {
return requestJson<ControlPlaneMutationResult>("/api/admin/settings", {
method: "PATCH",
body: JSON.stringify(patch),
});
}
async function requestJson<T>(url: string, init: RequestInit = {}): Promise<T> {
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;
}
}