// O contrato comum aos dois clientes configurados (cliente-axios.ts e // cliente-fetch.ts). Quem usa o cliente não sabe qual biblioteca está por // baixo: recebe o corpo já interpretado ou um ErroDaApi. import type { CorpoDeErro } from './api.js'; export class ErroDaApi extends Error { override name = 'ErroDaApi'; constructor( // null quando não houve resposta: API fora do ar, tempo esgotado. readonly status: number | null, // As mensagens do envelope de erro da API (aula 6), ou uma só, local. readonly detalhes: string[], opcoes?: ErrorOptions, ) { super(status === null ? `sem resposta: ${detalhes[0]}` : `${status}: ${detalhes.join('; ')}`, opcoes); } } export interface ClienteDaApi { get(caminho: string): Promise; post(caminho: string, corpo: unknown): Promise; patch(caminho: string, corpo: unknown): Promise; delete(caminho: string): Promise; } // Guarda de tipo do envelope de erro: o corpo veio de fora e pode não ser // o que o contrato promete (um proxy no caminho responde HTML, por exemplo). export function ehCorpoDeErro(valor: unknown): valor is CorpoDeErro { if (typeof valor !== 'object' || valor === null) return false; const candidato = valor as Record; return ( typeof candidato.status === 'number' && Array.isArray(candidato.detalhes) && candidato.detalhes.every((d) => typeof d === 'string') ); } // Um lugar só para guardar o token. Os dois clientes leem daqui a cada // requisição, em vez de receber o token como parâmetro em cada chamada. export const sessao: { token?: string } = {};