import type { ZodType } from 'zod'; import { ConversationsResponseSchema, ConversationDetailResponseSchema, ConversationMediaShareOptionsResponseSchema, ErrorResponseSchema, ProcessedPostsResponseSchema, SendReplyRequestSchema, ShareConversationMediaRequestSchema, StartConversationRequestSchema, StartConversationResponseSchema, SuccessResponseSchema, SuggestedReplyResponseSchema, BulkMarkConversationsReadRequestSchema, BulkMarkConversationsReadResponseSchema, SellerScanResponseSchema, MarkConversationReadRequestSchema, MarkConversationUnreadRequestSchema, SetConversationStatusRequestSchema, type ActiveChat, type BulkMarkConversationsReadResponse, type ConversationDetailResponse, type ConversationMediaShareOptions, type ConversationTriageStatus, type ProcessedPost, type SellerScanResponse, type SuccessResponse, } from '../../../../../packages/api-contracts/src/index.js'; import { createDashboardRequest } from '../../api/request.js'; async function parseResponse(response: Response, schema: ZodType): Promise { const payload: unknown = await response.json(); if (!response.ok) { const parsedError = ErrorResponseSchema.safeParse(payload); throw new Error(parsedError.success ? parsedError.data.error : `Request failed (${response.status})`); } return schema.parse(payload); } function conversationPath(id: string): string { return `/api/conversations/${encodeURIComponent(id)}`; } export interface ConversationApi { list(): Promise; detail(id: string): Promise; suggestReply(id: string): Promise; suggestMediaAsk(id: string): Promise; mediaShareOptions(id: string): Promise; processedPosts(username: string): Promise; sendReply(id: string, message: string): Promise; shareMedia(id: string, assetId: string): Promise; startConversation(accountId: string, username: string, message: string): Promise; markRead(id: string, throughTimestamp?: number): Promise; markUnread(id: string, beforeTimestamp?: number): Promise; setStatus(id: string, status: ConversationTriageStatus, snoozeUntil?: number | null): Promise; bulkMarkRead(ids: string[]): Promise; sellerScan(): Promise; } function jsonPost(body: unknown): RequestInit { return { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }; } export function createConversationApi(fetchImplementation?: typeof fetch): ConversationApi { const request = createDashboardRequest(fetchImplementation); return { async list() { return parseResponse( await request('/api/conversations?includeImageMetadata=true'), ConversationsResponseSchema, ); }, async detail(id) { return parseResponse(await request(conversationPath(id)), ConversationDetailResponseSchema); }, async suggestReply(id) { const response = await parseResponse( await request(`${conversationPath(id)}/suggest-reply`, { method: 'POST' }), SuggestedReplyResponseSchema, ); return response.suggestedReply; }, async suggestMediaAsk(id) { const response = await parseResponse( await request(`${conversationPath(id)}/suggest-media-ask`, { method: 'POST' }), SuggestedReplyResponseSchema, ); return response.suggestedReply; }, async mediaShareOptions(id) { return parseResponse( await request(`${conversationPath(id)}/shareable-media`), ConversationMediaShareOptionsResponseSchema, ); }, async processedPosts(username) { return parseResponse( await request(`/api/posts/by-author/${encodeURIComponent(username.trim().replace(/^u\//i, ''))}`), ProcessedPostsResponseSchema, ); }, async sendReply(id, message) { const body = SendReplyRequestSchema.parse({ message: message.trim() }); return parseResponse( await request(`${conversationPath(id)}/send-reply`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }), SuccessResponseSchema, ); }, async shareMedia(id, assetId) { const body = ShareConversationMediaRequestSchema.parse({ assetId }); return parseResponse( await request(`${conversationPath(id)}/share-media`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }), SuccessResponseSchema, ); }, async startConversation(accountId, username, message) { const body = StartConversationRequestSchema.parse({ accountId, username: username.trim().replace(/^u\//i, ''), message: message.trim(), }); const response = await parseResponse( await request('/api/conversations/start', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }), StartConversationResponseSchema, ); return response.chat; }, async markRead(id, throughTimestamp) { const body = MarkConversationReadRequestSchema.parse( throughTimestamp === undefined ? {} : { throughTimestamp }, ); return parseResponse( await request(`${conversationPath(id)}/read`, jsonPost(body)), SuccessResponseSchema, ); }, async markUnread(id, beforeTimestamp) { const body = MarkConversationUnreadRequestSchema.parse( beforeTimestamp === undefined ? {} : { beforeTimestamp }, ); return parseResponse( await request(`${conversationPath(id)}/unread`, jsonPost(body)), SuccessResponseSchema, ); }, async setStatus(id, status, snoozeUntil) { const body = SetConversationStatusRequestSchema.parse( snoozeUntil === undefined ? { status } : { status, snoozeUntil }, ); return parseResponse( await request(`${conversationPath(id)}/status`, jsonPost(body)), SuccessResponseSchema, ); }, async bulkMarkRead(ids) { const body = BulkMarkConversationsReadRequestSchema.parse({ conversationIds: ids }); return parseResponse( await request('/api/conversations/bulk-read', jsonPost(body)), BulkMarkConversationsReadResponseSchema, ); }, async sellerScan() { return parseResponse( await request('/api/conversations/seller-scan', { method: 'POST' }), SellerScanResponseSchema, ); }, }; } export const conversationApi = createConversationApi();