import { Message, ConversationStatus, ChatCloseType } from '../types'; type UserCfg = { restBase?: string; wsUrl?: string; nonce?: string }; type AdminCfg = { restUrl?: string; nonce?: string; wsUrl?: string }; const win = window as any; const userCfg = win.ZozoChatConfig as UserCfg | undefined; const adminCfg = win.ZozoChatAdminConfig as AdminCfg | undefined; export const IS_ADMIN = !!adminCfg; function normalizeBase(url: string) { return url.replace(/\/+$/, ""); } // REST base export const API_BASE = IS_ADMIN ? `${normalizeBase(adminCfg!.restUrl ?? "/wp-json")}/zozo-chat/v1` : normalizeBase(userCfg?.restBase ?? "/wp-json/zozo-chat/v1"); // Default JSON headers (frontend + admin) export function headersJSON(): HeadersInit { const h: Record = { "Content-Type": "application/json" }; const nonce = IS_ADMIN ? adminCfg?.nonce : userCfg?.nonce; if (nonce) { h["X-WP-Nonce"] = nonce; } return h; /** It will generate * "Content-Type": "application/json", "X-WP-Nonce": (window as any).ZozoChatAdminConfig.nonce, */ } // ---- Auth / Code flow ---- export async function requestCode(email: string): Promise { const resp = await fetch(`${API_BASE}/request_code`, { method: 'POST', headers: headersJSON(), body: JSON.stringify({ email }), credentials: 'include', // keep the cookie jar consistent }); if (!resp.ok) throw new Error((await resp.json()).message || 'Failed to request code'); } interface ApiResponse { success: boolean; data: T; } export interface VerifyCodeResult { conversation_id: number; conversation_status: ConversationStatus; email: string; ttl_seconds: number; } export async function verifyCode(email: string, code: string): Promise> { const resp = await fetch(`${API_BASE}/verify_code`, { method: 'POST', headers: headersJSON(), body: JSON.stringify({ email, code }), credentials: 'include', }); if (!resp.ok) throw new Error((await resp.json()).message || 'Failed to verify code'); return resp.json(); } // ---- Chat sendMessage REST ---- export async function sendMessage( conversation_id: number, email: string, content: string ): Promise { const resp = await fetch(`${API_BASE}/send_message`, { method: 'POST', headers: headersJSON(), body: JSON.stringify({ conversation_id, email, content }), credentials: 'include', }); if (!resp.ok) throw new Error((await resp.json()).message || 'Failed to send message'); } export async function fetchMessages() { const res = await fetch(`${API_BASE}/fetch_messages`, { method: 'GET', credentials: 'include', // important so zozochat_sess cookie is sent headers: { 'Content-Type': 'application/json' } }); let json: any = null; try { json = await res.json(); } catch { // no/invalid JSON } console.log('fetch_messages response:', res.status, json); // Build a richer error so callers can decide what to do (stop polling, authExpired, etc.) if (!res.ok || !json?.success) { const message = json?.error?.message || json?.message || `Failed to fetch messages (HTTP ${res.status})`; const err: any = new Error(message); err.status = res.status; // WP style: { code: 'no_session', message: 'No session cookie', data: ... } err.code = json?.code || json?.error?.code; err.payload = json; throw err; } return json.data; } export async function endChatSession(params: { action?: ChatCloseType } = {}) { const { action } = params; const res = await fetch(`${API_BASE}/session/close`, { method: 'POST', headers: headersJSON(), credentials: 'include', body: JSON.stringify({ action }), }); const text = await res.text(); console.log(`[endChatSession:${action}] status`, res.status, 'body', text); if (!res.ok) { throw new Error('Failed to end chat session'); } return res.ok; }