Agently / web /src /api /client.js
CI Deploy
Deploy 2026-05-24 20:27 UTC
fa3f9d1
Raw
History Blame Contribute Delete
3.13 kB
import { API_BASE } from '../utils/constants.js'
let _authToken = null
let _refreshToken = null
/**
* Set the current auth token to include in all API requests.
*/
export function setAuthToken(token) {
_authToken = token
}
/**
* Set a callback to refresh the token when a 401 is received.
* The callback should return the new token (or null if refresh fails).
*/
export function setTokenRefresh(fn) {
_refreshToken = fn
}
/**
* Get the auth headers object for direct fetch calls (e.g. chat SSE).
*/
export function getAuthHeaders() {
return _authToken ? { Authorization: `Bearer ${_authToken}` } : {}
}
/**
* Try to refresh the auth token via the registered callback.
* Returns true if the token was refreshed, false otherwise.
*/
export async function refreshAuthToken() {
if (!_refreshToken) return false
try {
const newToken = await _refreshToken()
if (newToken) {
_authToken = newToken
return true
}
} catch {
// Refresh failed
}
return false
}
function authHeaders() {
return getAuthHeaders()
}
async function request(url, options = {}) {
let retries = 0
const doFetch = async () => {
const res = await fetch(`${API_BASE}${url}`, {
headers: { 'Content-Type': 'application/json', ...authHeaders(), ...options.headers },
...options,
})
// On 401, try refreshing the token once and retry
if (res.status === 401 && retries < 1) {
retries++
const refreshed = await refreshAuthToken()
if (refreshed) {
return doFetch()
}
}
if (!res.ok) {
throw new Error(`API error: ${res.status} ${res.statusText}`)
}
return res.json()
}
return doFetch()
}
export async function get(url) {
return request(url, { method: 'GET' })
}
export async function post(url, body) {
return request(url, { method: 'POST', body: JSON.stringify(body) })
}
export async function patch(url, body) {
return request(url, { method: 'PATCH', body: JSON.stringify(body) })
}
export async function del(url) {
return request(url, { method: 'DELETE' })
}
/**
* Upload a file (multipart/form-data) to the API with auth.
*/
export async function uploadFile(url, file, params = {}) {
const formData = new FormData()
formData.append('file', file)
const query = new URLSearchParams(params).toString()
const fullUrl = query ? `${url}?${query}` : url
let retries = 0
const doFetch = async () => {
const res = await fetch(`${API_BASE}${fullUrl}`, {
method: 'POST',
headers: authHeaders(),
body: formData,
})
// On 401, try refreshing the token once and retry
if (res.status === 401 && retries < 1) {
retries++
// FormData can only be sent once, need to recreate
const retryFormData = new FormData()
retryFormData.append('file', file)
const refreshed = await refreshAuthToken()
if (refreshed) {
return doFetch()
}
}
if (!res.ok) {
const body = await res.text().catch(() => '')
throw new Error(`Upload failed (${res.status}): ${body}`)
}
return res.json()
}
return doFetch()
}