import { hostApiFetch } from '@/lib/host-api'; export type WorksImageAspectRatio = '1:1' | '4:3' | '16:9' | '9:16'; export type WorksImageQuality = 'standard' | 'high'; export type WorksImageJobStatus = | 'queued' | 'running' | 'succeeded' | 'failed' | 'expired' | 'cancelled' | string; export type WorksImageJob = { id: string; status: WorksImageJobStatus; prompt?: string; outputUrls?: string[]; error?: string | { message?: string } | null; createdAt?: string; updatedAt?: string; }; export type WorksImageGenerationInput = { accessToken: string; prompt: string; aspectRatio: WorksImageAspectRatio; quality: WorksImageQuality; }; type WorksImageResponse = { success: boolean; status?: number; error?: string; } & { [key in TField]?: TValue; }; export class WorksImageApiError extends Error { readonly statusCode?: number; constructor(message: string, statusCode?: number) { super(message); this.name = 'WorksImageApiError'; this.statusCode = statusCode; } } function assertSuccess( response: WorksImageResponse, field: TField, fallback: string, ): TValue { if (!response.success || response[field] === undefined) { throw new WorksImageApiError(response.error || fallback, response.status); } return response[field] as TValue; } function authHeaders(accessToken: string): Record { return { 'X-NianCode-Access-Token': accessToken, }; } function mapQuality(quality: WorksImageQuality): string { return quality === 'high' ? 'high' : 'medium'; } function normalizeJob(payload: unknown, fallbackPrompt?: string): WorksImageJob { const record = payload && typeof payload === 'object' ? payload as Record : {}; const taskId = record.task_id ?? record.taskId ?? record.id; const resultUrls = record.result_urls ?? record.resultUrls ?? record.outputUrls; return { id: typeof taskId === 'string' && taskId ? taskId : 'image-task', status: typeof record.status === 'string' ? record.status : 'queued', prompt: typeof record.prompt === 'string' ? record.prompt : fallbackPrompt, outputUrls: Array.isArray(resultUrls) ? resultUrls.filter((url): url is string => typeof url === 'string' && Boolean(url.trim())) : [], error: typeof record.error === 'string' || (record.error && typeof record.error === 'object') ? record.error as WorksImageJob['error'] : null, createdAt: typeof record.created_at === 'string' ? record.created_at : undefined, updatedAt: typeof record.updated_at === 'string' ? record.updated_at : undefined, }; } export async function fetchWorksImageTask(accessToken: string, taskId: string): Promise { const response = await hostApiFetch>( `/api/works/ai-gateway/images/tasks/${encodeURIComponent(taskId)}`, { headers: authHeaders(accessToken), }, ); return normalizeJob(assertSuccess(response, 'job', 'Failed to load image generation task')); } export async function submitWorksImageGeneration(input: WorksImageGenerationInput): Promise { const response = await hostApiFetch>( '/api/works/ai-gateway/images/generations', { method: 'POST', headers: authHeaders(input.accessToken), body: JSON.stringify({ prompt: input.prompt, image_urls: [], size: input.aspectRatio, quality: mapQuality(input.quality), resolution: '2K', }), }, ); return normalizeJob(assertSuccess(response, 'job', 'Failed to submit image generation'), input.prompt); }