78 lines
2.4 KiB
TypeScript
78 lines
2.4 KiB
TypeScript
|
|
import type { Post, Settings, InteractionConfig, Asset, APIKey, AnalyticsSummary } from './types'
|
||
|
|
|
||
|
|
const BASE = '/api/studio'
|
||
|
|
|
||
|
|
async function request<T>(path: string, options?: RequestInit): Promise<T> {
|
||
|
|
const res = await fetch(`${BASE}${path}`, {
|
||
|
|
...options,
|
||
|
|
headers: {
|
||
|
|
'Content-Type': 'application/json',
|
||
|
|
...options?.headers,
|
||
|
|
},
|
||
|
|
})
|
||
|
|
if (!res.ok) {
|
||
|
|
const error = await res.json().catch(() => ({ error: res.statusText }))
|
||
|
|
throw new Error(error.error || 'Request failed')
|
||
|
|
}
|
||
|
|
if (res.status === 204) return undefined as T
|
||
|
|
return res.json()
|
||
|
|
}
|
||
|
|
|
||
|
|
export const api = {
|
||
|
|
posts: {
|
||
|
|
list: () => request<Post[]>('/posts'),
|
||
|
|
get: (slug: string) => request<Post>(`/posts/${slug}`),
|
||
|
|
create: (data: Partial<Post>) => request<Post>('/posts', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify(data),
|
||
|
|
}),
|
||
|
|
update: (slug: string, data: Partial<Post>) => request<Post>(`/posts/${slug}`, {
|
||
|
|
method: 'PUT',
|
||
|
|
body: JSON.stringify(data),
|
||
|
|
}),
|
||
|
|
delete: (slug: string) => request<void>(`/posts/${slug}`, { method: 'DELETE' }),
|
||
|
|
},
|
||
|
|
|
||
|
|
settings: {
|
||
|
|
get: () => request<Settings>('/settings'),
|
||
|
|
update: (data: Settings) => request<{ success: boolean }>('/settings', {
|
||
|
|
method: 'PUT',
|
||
|
|
body: JSON.stringify(data),
|
||
|
|
}),
|
||
|
|
},
|
||
|
|
|
||
|
|
interactions: {
|
||
|
|
get: () => request<InteractionConfig>('/interaction-config'),
|
||
|
|
update: (data: Partial<InteractionConfig>) => request<InteractionConfig>('/interaction-config', {
|
||
|
|
method: 'PUT',
|
||
|
|
body: JSON.stringify(data),
|
||
|
|
}),
|
||
|
|
},
|
||
|
|
|
||
|
|
assets: {
|
||
|
|
list: () => request<Asset[]>('/assets'),
|
||
|
|
upload: async (file: File): Promise<Asset> => {
|
||
|
|
const form = new FormData()
|
||
|
|
form.append('file', file)
|
||
|
|
const res = await fetch(`${BASE}/assets`, { method: 'POST', body: form })
|
||
|
|
if (!res.ok) throw new Error('Upload failed')
|
||
|
|
return res.json()
|
||
|
|
},
|
||
|
|
delete: (id: string) => request<void>(`/assets/${id}`, { method: 'DELETE' }),
|
||
|
|
},
|
||
|
|
|
||
|
|
apiKeys: {
|
||
|
|
list: () => request<APIKey[]>('/api-keys'),
|
||
|
|
create: (name: string) => request<APIKey>('/api-keys', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ name }),
|
||
|
|
}),
|
||
|
|
delete: (key: string) => request<void>(`/api-keys/${key}`, { method: 'DELETE' }),
|
||
|
|
},
|
||
|
|
|
||
|
|
analytics: {
|
||
|
|
get: (days = 30) => request<AnalyticsSummary>(`/analytics?days=${days}`),
|
||
|
|
getPost: (slug: string, days = 30) => request<AnalyticsSummary>(`/analytics/posts/${slug}?days=${days}`),
|
||
|
|
},
|
||
|
|
}
|