Spaces:
Running
Running
Download console/src/lib/api.ts from Leon4gr45/brain: direct link, hf CLI and curl.
- Browser
- Download file 6.1 kB
-
https://huggingface.co/spaces/Leon4gr45/brain/resolve/main/console/src/lib/api.ts
- Command line
-
hf download hf://spaces/Leon4gr45/brain/console/src/lib/api.ts
-
curl -L -o api.ts https://huggingface.co/spaces/Leon4gr45/brain/resolve/main/console/src/lib/api.ts
6.1 kB
| import { requireAcceptedTask } from "./ingestContract.mjs"; | |
| import { clearSession, loadSession, saveSession, normalizeBaseUrl, type AuthSession } from "./auth"; | |
| export class ApiError extends Error { | |
| status: number; | |
| constructor(status: number, message: string) { | |
| super(message); | |
| this.status = status; | |
| } | |
| } | |
| export interface BrainRecord { | |
| id?: string; | |
| name_key: string; | |
| } | |
| export interface ApiFetchOptions { | |
| logoutOn401?: boolean; | |
| } | |
| export interface Workspace { | |
| id?: string; | |
| brain_id: string; | |
| slug: string; | |
| display_name: string; | |
| description?: string | null; | |
| archived: boolean; | |
| api_base_url: string; | |
| console_url: string; | |
| } | |
| export interface CreateWorkspaceInput { | |
| slug: string; | |
| display_name: string; | |
| description?: string | null; | |
| } | |
| export interface UpdateWorkspaceInput { | |
| display_name?: string; | |
| description?: string | null; | |
| archived?: boolean; | |
| } | |
| let session: AuthSession | null = null; | |
| export function getSession(): AuthSession | null { | |
| return session; | |
| } | |
| export function setSession(next: AuthSession | null): void { | |
| session = next; | |
| } | |
| function authHeaders(brainId?: string | null, path?: string): Headers { | |
| const headers = new Headers(); | |
| if (session?.csrfToken) headers.set("X-CSRF-Token", session.csrfToken); | |
| if (brainId && path && !path.startsWith("/system")) headers.set("X-Brain-ID", brainId); | |
| return headers; | |
| } | |
| export async function apiFetch<T>( | |
| path: string, | |
| options: RequestInit = {}, | |
| overrideBrainId?: string, | |
| fetchOptions: ApiFetchOptions = {}, | |
| ): Promise<T> { | |
| if (!session) { | |
| throw new ApiError(401, "Not authenticated"); | |
| } | |
| const headers = authHeaders(overrideBrainId ?? session.brainId, path); | |
| for (const [key, value] of new Headers(options.headers).entries()) { | |
| headers.set(key, value); | |
| } | |
| if (options.body && !headers.has("Content-Type")) { | |
| headers.set("Content-Type", "application/json"); | |
| } | |
| const url = `${normalizeBaseUrl(session.apiBaseUrl)}${path}`; | |
| const response = await fetch(url, { ...options, headers, credentials: "include" }); | |
| if (response.status === 401 && fetchOptions.logoutOn401 !== false) { | |
| clearSession(); | |
| setSession(null); | |
| if (!window.location.pathname.endsWith("/login")) { | |
| window.location.href = "/console/login"; | |
| } | |
| throw new ApiError(401, "Unauthorized"); | |
| } | |
| const text = await response.text(); | |
| let data: unknown = null; | |
| if (text) { | |
| try { | |
| data = JSON.parse(text); | |
| } catch { | |
| data = text; | |
| } | |
| } | |
| if (!response.ok) { | |
| const envelope = typeof data === "object" && data !== null ? data as {detail?: unknown; error?: {message?: string}} : null; | |
| const reason = envelope?.detail; | |
| const detail = typeof reason === "string" ? reason | |
| : reason ? `${envelope?.error?.message ?? "Request failed"}: ${JSON.stringify(reason)}` | |
| : envelope?.error?.message ?? `Request failed (${response.status})`; | |
| throw new ApiError(response.status, detail); | |
| } | |
| if ((path.startsWith("/ingest/") || path.includes("/agent/memory")) && options.method === "POST") { | |
| requireAcceptedTask(response.status, data); | |
| } | |
| return data as T; | |
| } | |
| export function workspaceApiFetch<T>( | |
| workspace: Pick<Workspace, "brain_id">, | |
| path: string, | |
| options: RequestInit = {}, | |
| fetchOptions: ApiFetchOptions = {}, | |
| ): Promise<T> { | |
| return apiFetch<T>(path, options, workspace.brain_id, fetchOptions); | |
| } | |
| export async function fetchWorkspaces(): Promise<Workspace[]> { | |
| const result = await apiFetch<{ workspaces: Workspace[] }>( | |
| "/system/workspaces", | |
| ); | |
| return result.workspaces; | |
| } | |
| export function fetchWorkspace(slug: string): Promise<Workspace> { | |
| return apiFetch<Workspace>(`/system/workspaces/${encodeURIComponent(slug)}`); | |
| } | |
| export function createWorkspace( | |
| input: CreateWorkspaceInput, | |
| ): Promise<Workspace> { | |
| return apiFetch<Workspace>("/system/workspaces", { | |
| method: "POST", | |
| body: JSON.stringify(input), | |
| }); | |
| } | |
| export function updateWorkspace( | |
| slug: string, | |
| input: UpdateWorkspaceInput, | |
| ): Promise<Workspace> { | |
| return apiFetch<Workspace>( | |
| `/system/workspaces/${encodeURIComponent(slug)}`, | |
| { method: "PATCH", body: JSON.stringify(input) }, | |
| ); | |
| } | |
| interface SessionIdentity { | |
| is_system: boolean; | |
| brain_id: string | null; | |
| csrf_token?: string; | |
| } | |
| export async function connectSession(apiBaseUrl: string, token: string): Promise<AuthSession> { | |
| const base = normalizeBaseUrl(apiBaseUrl); | |
| const response = await fetch(`${base}/auth/session`, { | |
| method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, | |
| body: JSON.stringify({ token }), | |
| }); | |
| if (!response.ok) throw new ApiError(response.status, "Access token rejected"); | |
| const identity: SessionIdentity = await response.json(); | |
| session = { apiBaseUrl: base, brainId: identity.brain_id, isSystemPat: identity.is_system, csrfToken: identity.csrf_token }; | |
| // The credential has served its purpose; all subsequent calls use the cookie. | |
| return session; | |
| } | |
| export async function restoreSession(): Promise<AuthSession | null> { | |
| const base = loadSession()?.apiBaseUrl ?? window.location.origin; | |
| const response = await fetch(`${normalizeBaseUrl(base)}/auth/me`, { credentials: "include" }); | |
| if (!response.ok) { session = null; return null; } | |
| const identity: SessionIdentity = await response.json(); | |
| session = { apiBaseUrl: base, brainId: identity.brain_id, isSystemPat: identity.is_system, csrfToken: identity.csrf_token }; | |
| saveSession(session); | |
| return session; | |
| } | |
| export async function logoutSession(): Promise<void> { | |
| try { await apiFetch("/auth/logout", { method: "POST" }); } | |
| finally { clearSession(); session = null; } | |
| } | |
| export function mergeBrainOptions( | |
| brains: BrainRecord[], | |
| activeBrainId: string, | |
| ): BrainRecord[] { | |
| const byKey = new Map<string, BrainRecord>(); | |
| for (const brain of brains) { | |
| byKey.set(brain.name_key, brain); | |
| } | |
| if (activeBrainId && !byKey.has(activeBrainId)) { | |
| byKey.set(activeBrainId, { name_key: activeBrainId }); | |
| } | |
| return [...byKey.values()].sort((a, b) => | |
| a.name_key.localeCompare(b.name_key), | |
| ); | |
| } | |