Files
RedditBot/apps/dashboard/src/features/operations/operations-api.ts
T

68 lines
2.2 KiB
TypeScript

import { z } from 'zod';
import {
ActivityResponseSchema,
ChatSyncStatusSchema,
ChatSyncTriggerResponseSchema,
FetchAllChatsResponseSchema,
} from '../../../../../packages/api-contracts/src/index.js';
import { createDashboardRequest } from '../../api/request.js';
export const RawLogEntrySchema = z.strictObject({
timestamp: z.number(),
level: z.union([z.literal('debug'), z.literal('info'), z.literal('warn'), z.literal('error')]),
message: z.string(),
data: z.unknown().optional(),
});
export const RawLogsResponseSchema = z.array(RawLogEntrySchema);
export type RawLogEntry = z.infer<typeof RawLogEntrySchema>;
async function parseResponse<T>(
response: Response,
schema: { parse(value: unknown): T },
): Promise<T> {
const payload: unknown = await response.json();
if (!response.ok) {
const message =
typeof payload === 'object' &&
payload !== null &&
'error' in payload &&
typeof payload.error === 'string'
? payload.error
: `Request failed (${response.status})`;
throw new Error(message);
}
return schema.parse(payload);
}
export function createOperationsApi(fetchImplementation?: typeof fetch) {
const request = createDashboardRequest(fetchImplementation);
return {
async getActivity() {
return parseResponse(await request('/api/activity'), ActivityResponseSchema);
},
async getLogs(limit = 200) {
return parseResponse(
await request(`/api/logs?limit=${limit}`),
RawLogsResponseSchema,
);
},
async getSyncStatus() {
return parseResponse(await request('/api/chats/sync'), ChatSyncStatusSchema);
},
async triggerSync(kind: 'delta' | 'full') {
const result = await parseResponse(
await request(`/api/chats/sync/${kind}`, { method: 'POST' }),
ChatSyncTriggerResponseSchema,
);
if (!('success' in result)) throw new Error(result.error);
if (!result.success) throw new Error(result.reason);
return result;
},
async fetchAllChats() {
return parseResponse(await request('/api/chats/fetch-all', { method: 'POST' }), FetchAllChatsResponseSchema);
},
};
}
export const operationsApi = createOperationsApi();