SPB Git

spb/akos

Public
12.6 KB · 97 lines typescript
1export class ApiError extends Error {2  status: number;3  code: string;4  correlationId?: string;5  payload: unknown;6  constructor(status: number, code: string, message: string, correlationId?: string, payload?: unknown) {7    super(message);8    this.status = status;9    this.code = code;10    this.correlationId = correlationId;11    this.payload = payload;12  }13}1415export const UNAUTH_EVENT = "akos:unauthenticated";1617type Opts = { method?: string; body?: unknown; raw?: boolean; signal?: AbortSignal; noRedirect?: boolean };1819export async function api<T = unknown>(path: string, opts: Opts = {}): Promise<T> {20  const url = path.startsWith("/") ? path : `/api/v1/${path}`;21  const init: RequestInit = { method: opts.method ?? (opts.body !== undefined ? "POST" : "GET"), credentials: "include", headers: {}, signal: opts.signal };22  if (opts.body !== undefined) {23    (init.headers as Record<string, string>)["Content-Type"] = "application/json";24    init.body = JSON.stringify(opts.body);25  }26  const r = await fetch(url, init);27  if (r.status === 401 && !opts.noRedirect) {28    window.dispatchEvent(new CustomEvent(UNAUTH_EVENT));29  }30  if (opts.raw) {31    if (!r.ok) {32      let msg = r.statusText;33      try { const j = await r.json(); msg = j?.error?.message ?? msg; } catch { /* ignore */ }34      throw new ApiError(r.status, "http_error", msg);35    }36    return (await r.text()) as unknown as T;37  }38  const ct = r.headers.get("content-type") ?? "";39  const data = ct.includes("application/json") ? await r.json() : await r.text();40  if (!r.ok) {41    const e = (data && typeof data === "object" && "error" in data ? (data as { error: { code?: string; message?: string; correlation_id?: string } }).error : undefined) ?? {};42    throw new ApiError(r.status, e.code ?? "http_error", e.message ?? (typeof data === "string" ? data.slice(0, 200) : r.statusText), e.correlation_id, e);43  }44  return data as T;45}4647export const v1 = (p: string) => `/api/v1/${p.replace(/^\//, "")}`;4849export function qs(params: Record<string, string | number | undefined | null>): string {50  const u = new URLSearchParams();51  for (const [k, v] of Object.entries(params)) if (v !== undefined && v !== null && v !== "") u.set(k, String(v));52  const s = u.toString();53  return s ? `?${s}` : "";54}5556// ---------- shared types (shape mirrors akos/api/*.py) ----------57export type Me = { id: string; email: string; role: "admin" | "operator" | "viewer"; kind: string; scopes: string[]; project_id: string | null };58export type Job = { id: string; kind: string; state: string; attempts: number; max_attempts?: number; error: string | null; result: Record<string, unknown> | null; created_at: string; finished_at: string | null; started_at?: string | null; locked_by?: string | null; created_by?: string | null };59export type Overview = {60  counts: Record<string, number>;61  lifecycle: { lifecycle: string; n: number }[];62  knowledge_states: { knowledge_state: string; n: number }[];63  execution_states_7d: { state: string; n: number }[];64  daily: { day: string; n: number; ok: number; bad: number }[];65  recent_executions: ExecutionRow[];66  debt: { severity: string; n: number }[];67  jobs: { by_state: Record<string, number>; queued: number; running: number; dead: number; oldest_queued: string | null };68  workers: Worker[];69  version: string;70};71export type Worker = { name: string; pid: number | null; host: string | null; version: string | null; started_at: string; last_seen: string; current_job: string | null };72export type ApiRow = { id: string; slug: string; name: string; kind: string; base_url: string | null; lifecycle: string; knowledge_state: string; opaque_internal_implementation: boolean; tags: string[]; updated_at: string; created_at: string; provider_slug: string; provider_name: string; versions: number; endpoints: number; packages: number; open_debt: number; executions: number };73export type Endpoint = { id: string; operation_id: string; method: string; path: string; summary: string | null; description?: string | null; inferred: boolean; pagination: Record<string, unknown>; parameters: Param[]; request_schema?: unknown; response_schema?: unknown; rate_limit?: Record<string, unknown> };74export type Param = { name: string; in: string; required: boolean; description?: string; schema?: Record<string, unknown>; example?: unknown };75export type Variable = { id: string; name: string; json_path: string | null; data_type: string | null; unit: string | null; description: string | null; semantic_concept: string | null; endpoint_id: string | null };76export type Evidence = { id: string; subject_type: string; subject_id: string; kind: string; result: "pass" | "fail" | "blocked" | "info"; command: string | null; output_excerpt: string | null; output_hash: string | null; artifact_id: string | null; details: Record<string, unknown>; created_by: string | null; created_at: string };77export type Debt = { id: string; kind: string; severity: "low" | "medium" | "high" | "critical"; subject_type: string; subject_id: string; project_ids: string[]; description: string; remediation: string | null; owner_id: string | null; status: string; evidence_id: string | null; created_at: string; resolved_at: string | null; owner?: string | null; subject_label?: string | null };78export type DriftAlert = { id: string; api_version_id: string; endpoint_id: string | null; kind: string; details: Record<string, unknown>; affected_projects: string[]; status: string; debt_id: string | null; detected_at: string; resolved_at: string | null; version?: string; api_name?: string; api_id?: string };79export type VersionRow = { id: string; version: string; lifecycle: string; contract_hash: string; source_kind: string; source_url: string | null; created_at: string; created_by: string | null; endpoints: number };80export type PackageRow = { id: string; akp_id: string; version: number; lifecycle: string; knowledge_state: string; hash: string; created_at: string; superseded_by: string | null; credential_ref_id?: string | null; api_name?: string; api_id?: string; opaque?: boolean; provider_slug?: string; open_debt?: number; evidence_pass?: number; evidence_fail?: number; license?: Record<string, unknown> };81export type ApiDetail = ApiRow & { description: string | null; docs_url: string | null; auth_scheme: Record<string, unknown>; current_version_id: string | null; provider_id: string; provider_license: Record<string, unknown>; provider_docs: string | null; versions: VersionRow[]; endpoints?: Endpoint[]; variables?: Variable[]; packages: PackageRow[]; evidence: Evidence[]; debt: Debt[]; executions: ExecutionRow[]; drift: DriftAlert[]; allowed_transitions: string[] };82export type PackageDetail = PackageRow & { api_version_id: string; created_by: string | null; manifest: Record<string, unknown>; contract_yaml: string; recipe: Record<string, unknown>; readme: string; license: Record<string, unknown>; api_slug: string; api_kind: string; base_url: string | null; provider_name: string; api_version_label: string; contract_hash: string; files: { filename: string; language: string; static_scan: Record<string, unknown>; sha256: string; size_bytes: number }[]; evidence: Evidence[]; debt: Debt[]; endpoints: Endpoint[]; allowed_transitions: string[] };83export type ExecutionRow = { id: string; state: string; akp_lifecycle?: string | null; method: string | null; url: string | null; status_code: number | null; duration_ms: number | null; created_at: string; finished_at?: string | null; policy_mode?: string; purpose?: string | null; caller?: string | null; observed?: boolean; provisional?: boolean; response_hash?: string | null; response_bytes?: number | null; error?: string | null; correlation_id?: string | null; project_slug?: string; api_name?: string | null; api_id?: string | null; akp_id?: string | null; akp_version?: number | null; agent_name?: string | null; decision?: string | null };84export type ExecutionDetail = ExecutionRow & { project_id: string; params: Record<string, unknown>; request_fingerprint: string | null; credential_name: string | null; credential_ref: string | null; credential_version: number | null; operation_id: string | null; endpoint_path: string | null; endpoint_id: string | null; package_id: string | null; api_version_id: string | null; response_media_type: string | null; response_artifact_id: string | null; retries: number; started_at: string | null; api_opaque: boolean | null; policy_decision: { decision: string; reasons: string[]; checks: Record<string, unknown>; mode: string; created_at: string } | null; artifact?: { id: string; sha256: string; size_bytes: number; media_type: string; retention: string } | null; lineage: { from_type: string; from_id: string; to_type: string; to_id: string; relation: string }[]; audit: { seq: number; ts: string; actor_type: string; actor_id: string | null; action: string; details: Record<string, unknown>; hash: string }[]; egress: { ts: string; host: string; port: number; decision: string; reason: string | null }[] };85export type Credential = { id: string; name: string; ref: string; scheme: string; placement: string | null; scopes: string[]; allowed_projects: string[]; environment: string; version: number; fingerprint: string | null; expires_at: string | null; rotated_at: string | null; revoked_at: string | null; created_at: string; provider_name?: string | null; provider_slug?: string | null; owner?: string | null; uses?: number; last_used?: string | null; vault_present?: boolean; packages?: PackageRow[] };86export type Project = { id: string; slug: string; name: string; policy_mode: string; owner_id: string | null; approved_akps: string[]; budget: Record<string, number>; settings: Record<string, unknown>; created_at: string; executions?: number; datasets?: number; agents?: number; executions_24h?: number };87export type Agent = { id: string; name: string; kind: string; project_id: string | null; budget: Record<string, number>; permissions: Record<string, boolean>; created_at: string; last_seen_at: string | null; project_slug?: string; executions?: number; executions_24h?: number };88export type Dataset = { id: string; name: string; row_count: number | null; verification: string; granularity: string | null; units: Record<string, string>; identifiers: { keys?: string[] }; hash: string | null; created_at: string; created_by: string | null; license: Record<string, unknown>; project_slug: string; project_id?: string; executions?: number; transformations?: number };89export type DatasetDetail = Dataset & { project_id: string; execution_ids: string[]; artifact_id: string | null; schema_json: { columns?: Record<string, string>; records_path?: string | null }; coverage: Record<string, unknown>; assessment: { verified: boolean; checks: { check: string; ok: boolean; detail: string }[] }; executions: ExecutionRow[]; transformations: { id: string; name: string; kind: string; code_hash: string; input_dataset_ids: string[]; params: Record<string, unknown>; validation: Record<string, unknown>; created_at: string }[]; exports: { artifact_id: string; details: Record<string, unknown>; created_at: string; sha256: string; size_bytes: number }[]; preview: Record<string, unknown>[] };90export type Graph = { nodes: GraphNode[]; edges: { from: string; to: string; relation: string }[] };91export type GraphNode = { id: string; type: string; label: string; [k: string]: unknown };92export type Recipe = { id: string; name: string; version: number; status: string; validation: Record<string, unknown>; output_dataset_id: string | null; created_at: string; spec: Record<string, unknown>; project_slug?: string; project_id: string };93export type AuditEvent = { seq: number; id: string; ts: string; actor_type: string; actor_id: string | null; action: string; target_type: string | null; target_id: string | null; project_id: string | null; correlation_id: string | null; details: Record<string, unknown>; prev_hash: string | null; hash: string };94export type SearchResult = { type: string; id: string; title: string; snippet: string; lifecycle: string; knowledge_state: string; provider: string; api_id: string; rank: number };95export type Health = { status: string; version: string; uptime_s: number; db: { ok: boolean; latency_ms: number; size_bytes: number; migrations: { name: string; applied_at: string }[] }; workers: Worker[]; live_workers: number; proxy: { port: number; listening: boolean }; jobs: Overview["jobs"]; sandbox: boolean; disk: { free_bytes: number; total_bytes: number } | null; data_dir: string; public_url: string; host: string };96export type Metrics = { executions_24h: { p50: number | null; p95: number | null; max: number | null; n: number }; jobs_24h: { done: number; dead: number; avg_s: number | null }; egress_24h: { decision: string; n: number }[]; by_api_7d: { name: string; n: number; avg_ms: number | null; ok: number }[]; hourly: { hour: string; n: number }[] };97
Files · da58f809c01c422e65c786b05d6ffa3079c9feba
Menu

Theme