hermes-kanban-miniapp/frontend/src/api/client.ts

98 lines
2.5 KiB
TypeScript
Raw Normal View History

import type {
Board,
BoardListData,
TaskSummary,
TaskDetail,
TaskListData,
CreateTaskPayload,
CommentPayload,
ApiResponse,
HealthData,
} from '@kanban/contracts'
import { getInitData } from '../telegram'
const BRIDGE_URL = import.meta.env.VITE_BRIDGE_URL || '/bridge'
const AUTH_TOKEN: string = import.meta.env.VITE_AUTH_TOKEN || ''
async function request<T>(path: string, init: RequestInit = {}): Promise<T> {
const headers = new Headers(init.headers)
headers.set('Content-Type', 'application/json')
// Auth: prefer X-Bridge-Token, fall back to Telegram initData
if (AUTH_TOKEN) {
headers.set('X-Bridge-Token', AUTH_TOKEN)
} else {
const initData = getInitData()
if (initData) {
headers.set('X-Bridge-Token', initData)
}
}
const url = `${BRIDGE_URL}${path}`
const response = await fetch(url, { ...init, headers })
const data = await response.json().catch(() => null)
if (!response.ok || !data) {
const message =
(data as { error?: { message?: string } })?.error?.message ||
response.statusText ||
`HTTP ${response.status}`
throw new Error(message)
}
const envelope = data as ApiResponse<T>
if (!envelope.ok) {
throw new Error(envelope.error?.message || 'API error')
}
return envelope.data
}
// ─── API methods ────────────────────────────────────────────
export async function fetchHealth(): Promise<HealthData> {
return request<HealthData>('/v1/health')
}
export async function fetchBoards(): Promise<Board[]> {
return request<BoardListData>('/v1/boards')
}
export async function fetchTasks(board: string): Promise<TaskListData> {
return request<TaskListData>(`/v1/boards/${encodeURIComponent(board)}/tasks`)
}
export async function fetchTask(board: string, taskId: string): Promise<TaskDetail> {
return request<TaskDetail>(
`/v1/boards/${encodeURIComponent(board)}/tasks/${encodeURIComponent(taskId)}`
)
}
export async function createTask(
board: string,
payload: CreateTaskPayload
): Promise<TaskDetail> {
return request<TaskDetail>(
`/v1/boards/${encodeURIComponent(board)}/tasks`,
{
method: 'POST',
body: JSON.stringify(payload),
}
)
}
export async function addComment(
board: string,
taskId: string,
payload: CommentPayload
): Promise<void> {
await request<void>(
`/v1/boards/${encodeURIComponent(board)}/tasks/${encodeURIComponent(taskId)}/comments`,
{
method: 'POST',
body: JSON.stringify(payload),
}
)
}