// Cliente base do satélite NewWhats → /api/nw/v1/* (proxy do backend → motor // /api/ext/v1/*). Auth: Bearer do scoreodonto (localStorage SCOREODONTO_AUTH_TOKEN). // Retorna JSON já parseado; em erro, lança Error com `.response = { status, data }` // (mesmo shape do axios, que o código portado do motor espera). const API: string = (import.meta as any).env?.VITE_API_URL || '/api'; const TOKEN_KEY = 'SCOREODONTO_AUTH_TOKEN'; export function nwToken(): string | null { try { return localStorage.getItem(TOKEN_KEY); } catch { return null; } } // Clínica do workspace ativo — escopo por-requisição (modelo de canal). function activeClinicaId(): string | null { try { return JSON.parse(localStorage.getItem('SCOREODONTO_ACTIVE_WORKSPACE') || '{}')?.id || null; } catch { return null; } } function authHeaders(extra?: Record): Record { const t = nwToken(); const c = activeClinicaId(); return { ...(t ? { Authorization: `Bearer ${t}` } : {}), ...(c ? { 'x-nw-clinica': c } : {}), ...(extra || {}), }; } async function req(method: string, path: string, body?: any): Promise { const isForm = typeof FormData !== 'undefined' && body instanceof FormData; const res = await fetch(`${API}/nw/v1${path}`, { method, headers: authHeaders(isForm ? undefined : (body != null ? { 'Content-Type': 'application/json' } : undefined)), body: body == null ? undefined : (isForm ? body : JSON.stringify(body)), }); const text = await res.text(); let data: any = null; try { data = text ? JSON.parse(text) : null; } catch { data = text; } if (!res.ok) { const err: any = new Error((data && data.error) || `${res.status}`); err.response = { status: res.status, data }; throw err; } return data; } export const nw = { get: (p: string) => req('GET', p), post: (p: string, body?: any) => req('POST', p, body), put: (p: string, body?: any) => req('PUT', p, body), patch: (p: string, body?: any) => req('PATCH', p, body), delete: (p: string) => req('DELETE', p), // URL base ('/api' relativo ou absoluta) — usada pelo socketService p/ o WS. base: () => API, };