Newer
Older
navi-1 / webclient / src / api / index.js
const BASE = import.meta.env.DEV ? '/api' : ''

// Global safety net: log unhandled rejections so the UI doesn't silently break.
window.addEventListener('unhandledrejection', (ev) => {
  console.error('[API] Unhandled rejection:', ev.reason)
})

async function request(method, path, body) {
  const opts = {
    method,
    headers: {},
    credentials: 'include',
  }
  if (body !== undefined) {
    opts.headers['Content-Type'] = 'application/json'
    opts.body = JSON.stringify(body)
  }
  const res = await fetch(`${BASE}${path}`, opts)
  if (!res.ok) {
    const text = await res.text().catch(() => '')
    throw new Error(`${method} ${path} → ${res.status}: ${text}`)
  }
  if (res.status === 204) return null
  return res.json()
}

// ─── Auth ─────────────────────────────────────────────────────────────────
export function getMe() {
  return request('GET', '/auth/me')
}

export function logout() {
  return request('POST', '/auth/logout')
}

// ─── Profiles ──────────────────────────────────────────────────────────────
export function getProfiles() {
  return request('GET', '/agents/profiles')
}

// ─── Sessions ──────────────────────────────────────────────────────────────
export function getSessions({ limit = 30, offset = 0, profileId = null } = {}) {
  const params = new URLSearchParams({
    limit: String(limit),
    offset: String(offset),
  })
  if (profileId) params.set('profile_id', profileId)
  return request('GET', `/sessions?${params.toString()}`)
}

export function getSession(id) {
  return request('GET', `/sessions/${id}`)
}

export function createSession(profileId) {
  return request('POST', '/sessions', { profile_id: profileId })
}

export function deleteSession(id) {
  return request('DELETE', `/sessions/${id}`)
}

export function pinSession(id, pinned) {
  return request('PATCH', `/sessions/${id}/pin`, { pinned })
}

export function stopSession(id) {
  return request('POST', `/sessions/${id}/stop`)
}

export function generateSessionName(id) {
  return request('POST', `/sessions/${id}/generate-name`)
}

export function getSessionContent(id) {
  return request('GET', `/sessions/${id}/content`)
}

// ─── Eval feedback ─────────────────────────────────────────────────────────
export function getFeedback(sessionId) {
  return request('GET', `/eval/feedback/${sessionId}`)
}

export function setFeedback(sessionId, messageIndex, rating) {
  return request('POST', '/eval/feedback', {
    session_id: sessionId,
    message_index: messageIndex,
    rating
  })
}

// ─── Files ─────────────────────────────────────────────────────────────────
export async function uploadFile(sessionId, file) {
  const form = new FormData()
  form.append('file', file)
  const res = await fetch(`${BASE}/sessions/${sessionId}/files`, {
    method: 'POST',
    credentials: 'include',
    body: form
  })
  if (!res.ok) {
    const text = await res.text().catch(() => '')
    throw new Error(`Upload failed: ${res.status}: ${text}`)
  }
  return res.json()
}

// ─── Admin ─────────────────────────────────────────────────────────────────
export function getAdminUsers() { return request('GET', '/admin/users') }
export function getAdminSessions() { return request('GET', '/admin/sessions') }
export function getAdminMemory() { return request('GET', '/admin/memory') }
export function getAdminProfiles() { return request('GET', '/admin/profiles') }
export function getAdminSession(id) { return request('GET', `/admin/sessions/${id}`) }
export function deleteAdminSession(id) { return request('DELETE', `/admin/sessions/${id}`) }
export function getAdminUser(id) { return request('GET', `/admin/users/${id}`) }
export function getAdminUserSessions(id) { return request('GET', `/admin/users/${id}/sessions`) }
export function updateUserRole(id, role) { return request('PATCH', `/admin/users/${id}/role`, { role }) }
export function updateProfileAvailability(id, isAdminOnly) { return request('PATCH', `/admin/profiles/${id}/availability`, { is_admin_only: isAdminOnly }) }