Loto / src /utils /CaixaAPIOfficial.ts
Raí Santos
oi
4c1e4ec
/**
* CONEXÃO EXCLUSIVA COM A API OFICIAL DA CAIXA ECONÔMICA FEDERAL
* Sistema especializado para garantir conexão REAL com a Caixa
*/
import { LotomaniaResult } from '../types';
export class CaixaAPIOfficial {
private static instance: CaixaAPIOfficial;
private readonly BASE_URL = 'https://servicebus2.caixa.gov.br/portaldeloterias/api/lotomania/';
private lastSuccessfulMethod: string = '';
static getInstance(): CaixaAPIOfficial {
if (!CaixaAPIOfficial.instance) {
CaixaAPIOfficial.instance = new CaixaAPIOfficial();
}
return CaixaAPIOfficial.instance;
}
/**
* MÉTODO PRINCIPAL: Buscar dados OFICIAIS da Caixa
*/
async fetchOfficialData(): Promise<any> {
console.log('🏦 CONECTANDO À API OFICIAL DA CAIXA ECONÔMICA FEDERAL');
console.log('📍 URL:', this.BASE_URL);
// ESTRATÉGIA 1: Conexão DIRETA (funciona em muitos casos)
try {
const directData = await this.fetchDirect();
if (directData) {
console.log('✅ SUCESSO: Conexão DIRETA com API oficial da Caixa!');
this.lastSuccessfulMethod = 'direct';
this.logOfficialData(directData);
return directData;
}
} catch (error) {
console.log('⚠️ Conexão direta não disponível, tentando métodos alternativos...');
}
// ESTRATÉGIA 2: Proxies CORS públicos
const corsProxies = [
'https://api.allorigins.win/get?url=',
'https://corsproxy.io/?',
'https://cors-anywhere.herokuapp.com/',
'https://api.codetabs.com/v1/proxy?quest='
];
for (const proxy of corsProxies) {
try {
console.log(`🔄 Tentando proxy: ${proxy}`);
const proxyData = await this.fetchWithProxy(proxy);
if (proxyData) {
console.log(`✅ SUCESSO: Dados oficiais obtidos via proxy ${proxy}`);
this.lastSuccessfulMethod = `proxy:${proxy}`;
this.logOfficialData(proxyData);
return proxyData;
}
} catch (error) {
console.log(`❌ Proxy ${proxy} falhou:`, (error as Error).message);
continue;
}
}
// ESTRATÉGIA 3: Fetch com diferentes configurações
const fetchConfigurations = [
{ mode: 'no-cors' as RequestMode, cache: 'no-cache' as RequestCache },
{ mode: 'cors' as RequestMode, credentials: 'omit' as RequestCredentials },
{ mode: 'same-origin' as RequestMode }
];
for (const config of fetchConfigurations) {
try {
console.log(`🔄 Tentando configuração:`, config);
const configData = await this.fetchWithConfig(config);
if (configData) {
console.log('✅ SUCESSO: Configuração alternativa funcionou!');
this.lastSuccessfulMethod = `config:${JSON.stringify(config)}`;
this.logOfficialData(configData);
return configData;
}
} catch (error) {
continue;
}
}
// ESTRATÉGIA 4: Usando XMLHttpRequest (mais compatível com CORS)
try {
console.log('🔄 Tentando XMLHttpRequest...');
const xhrData = await this.fetchWithXHR();
if (xhrData) {
console.log('✅ SUCESSO: XMLHttpRequest funcionou!');
this.lastSuccessfulMethod = 'xhr';
this.logOfficialData(xhrData);
return xhrData;
}
} catch (error) {
console.log('❌ XMLHttpRequest falhou:', (error as Error).message);
}
throw new Error('🚨 IMPOSSÍVEL CONECTAR À API OFICIAL DA CAIXA - Todas as estratégias falharam');
}
private async fetchDirect(): Promise<any> {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 15000);
try {
const response = await fetch(this.BASE_URL, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Referer': 'https://loterias.caixa.gov.br/',
'Origin': 'https://loterias.caixa.gov.br',
'X-Requested-With': 'XMLHttpRequest',
'Cache-Control': 'no-cache',
'Pragma': 'no-cache'
},
mode: 'cors',
cache: 'no-cache',
credentials: 'omit',
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
return data;
} catch (error) {
clearTimeout(timeoutId);
throw error;
}
}
private async fetchWithProxy(proxyURL: string): Promise<any> {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 12000);
try {
let finalURL: string;
if (proxyURL.includes('allorigins')) {
finalURL = `${proxyURL}${encodeURIComponent(this.BASE_URL)}`;
} else if (proxyURL.includes('corsproxy')) {
finalURL = `${proxyURL}${encodeURIComponent(this.BASE_URL)}`;
} else if (proxyURL.includes('codetabs')) {
finalURL = `${proxyURL}${encodeURIComponent(this.BASE_URL)}`;
} else {
finalURL = `${proxyURL}${this.BASE_URL}`;
}
const response = await fetch(finalURL, {
method: 'GET',
headers: {
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
},
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`Proxy HTTP ${response.status}`);
}
const responseData = await response.json();
// Handle different proxy response formats
if (proxyURL.includes('allorigins') && responseData.contents) {
return JSON.parse(responseData.contents);
} else if (responseData.data) {
return responseData.data;
} else {
return responseData;
}
} catch (error) {
clearTimeout(timeoutId);
throw error;
}
}
private async fetchWithConfig(config: RequestInit): Promise<any> {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000);
try {
const response = await fetch(this.BASE_URL, {
method: 'GET',
headers: {
'Accept': 'application/json',
'User-Agent': 'Mozilla/5.0 LotomaniaApp/1.0'
},
signal: controller.signal,
...config
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`Config HTTP ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
clearTimeout(timeoutId);
throw error;
}
}
private async fetchWithXHR(): Promise<any> {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
const timeout = setTimeout(() => {
xhr.abort();
reject(new Error('XHR Timeout'));
}, 15000);
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
clearTimeout(timeout);
if (xhr.status === 200) {
try {
const data = JSON.parse(xhr.responseText);
resolve(data);
} catch (error) {
reject(new Error('XHR Parse Error'));
}
} else {
reject(new Error(`XHR HTTP ${xhr.status}`));
}
}
};
xhr.onerror = () => {
clearTimeout(timeout);
reject(new Error('XHR Network Error'));
};
xhr.open('GET', this.BASE_URL, true);
xhr.setRequestHeader('Accept', 'application/json');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.send();
});
}
private logOfficialData(data: any): void {
console.log('📊 ===== DADOS OFICIAIS DA CAIXA ===== 📊');
console.log('🎯 Concurso:', data.numero);
console.log('📅 Data do Sorteio:', data.dataApuracao);
console.log('🔢 Números Sorteados:', data.listaDezenas || data.dezenas || []);
console.log('💰 Valor Arrecadado: R$', (data.valorArrecadado || 0).toLocaleString('pt-BR'));
console.log('🎰 Acumulado:', data.acumulado ? 'SIM' : 'NÃO');
console.log('🏢 Local do Sorteio:', data.localSorteio || 'ESPAÇO DA SORTE');
console.log('🔄 Próximo Concurso:', data.numeroConcursoProximo || 'N/A');
console.log('💵 Estimativa Próximo: R$', (data.valorEstimadoProximoConcurso || 0).toLocaleString('pt-BR'));
const premiacoes = data.listaRateioPremio || data.premiacoes || [];
if (premiacoes.length > 0) {
console.log('🏆 Premiação:');
premiacoes.forEach((premio: any) => {
const descricao = premio.descricaoFaixa || premio.descricao || 'N/A';
const ganhadores = premio.numeroDeGanhadores || premio.ganhadores || 0;
const valor = premio.valorPremio || premio.valor || 0;
console.log(` ${descricao}: ${ganhadores} ganhador(es) - R$ ${valor.toLocaleString('pt-BR')}`);
});
}
console.log('✅ DADOS 100% OFICIAIS E VERIFICADOS DA CAIXA');
console.log('====================================== ✅');
}
/**
* Buscar concurso específico
*/
async fetchConcursoEspecifico(numero: number): Promise<any> {
const concursoURL = `${this.BASE_URL}${numero}`;
console.log(`🎯 Buscando concurso específico ${numero} na Caixa...`);
// Aplicar as mesmas estratégias para concurso específico
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 15000);
const response = await fetch(concursoURL, {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
},
mode: 'cors',
cache: 'no-cache',
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
console.log(`✅ Concurso ${numero} obtido da API oficial da Caixa`);
this.logOfficialData(data);
return data;
} catch (error) {
console.error(`❌ Erro ao buscar concurso ${numero}:`, error);
throw error;
}
}
/**
* Verificar status da API oficial
*/
async verificarStatusAPI(): Promise<{
online: boolean;
metodo: string;
tempoResposta: number;
ultimaVerificacao: string;
}> {
const inicio = performance.now();
try {
await this.fetchOfficialData();
const tempoResposta = Math.round(performance.now() - inicio);
return {
online: true,
metodo: this.lastSuccessfulMethod,
tempoResposta,
ultimaVerificacao: new Date().toLocaleString('pt-BR')
};
} catch (error) {
const tempoResposta = Math.round(performance.now() - inicio);
return {
online: false,
metodo: 'nenhum',
tempoResposta,
ultimaVerificacao: new Date().toLocaleString('pt-BR')
};
}
}
/**
* Converter dados da API oficial para formato interno
*/
formatarDadosOficiais(dadosAPI: any): LotomaniaResult {
// Garantir que sempre temos dados válidos, mesmo com API inconsistente
const numerosConcurso = dadosAPI.listaDezenas || dadosAPI.dezenas || [];
const premiacoes = dadosAPI.listaRateioPremio || dadosAPI.premiacoes || [];
const ganhadores = dadosAPI.listaMunicipioUFGanhadores || dadosAPI.ganhadores || [];
return {
concurso: dadosAPI.numero || dadosAPI.concurso || 0,
data: dadosAPI.dataApuracao || dadosAPI.data || new Date().toLocaleDateString('pt-BR'),
numeros: numerosConcurso.map((n: string | number) =>
typeof n === 'string' ? parseInt(n, 10) : n
).filter((n: number) => !isNaN(n)) || [],
acumulado: Boolean(dadosAPI.acumulado),
valorArrecadado: Number(dadosAPI.valorArrecadado) || 0,
valorAcumuladoProximoConcurso: Number(dadosAPI.valorAcumuladoProximoConcurso) || 0,
valorEstimadoProximoConcurso: Number(dadosAPI.valorEstimadoProximoConcurso) || 0,
numeroProximoConcurso: dadosAPI.numeroConcursoProximo || dadosAPI.numeroProximoConcurso || (dadosAPI.numero + 1),
dataProximoConcurso: dadosAPI.dataProximoConcurso || dadosAPI.dataProximo || '',
localSorteio: dadosAPI.localSorteio || dadosAPI.local || 'ESPAÇO DA SORTE',
premiacoes: premiacoes.map((premio: any) => ({
faixa: Number(premio.faixa) || 0,
descricao: String(premio.descricaoFaixa || premio.descricao || ''),
acertos: this.extrairAcertos(String(premio.descricaoFaixa || premio.descricao || '')),
ganhadores: Number(premio.numeroDeGanhadores || premio.ganhadores) || 0,
valorPremio: Number(premio.valorPremio || premio.valor) || 0
})),
ganhadores: ganhadores.map((ganhador: any) => ({
municipio: String(ganhador.municipio || ''),
uf: String(ganhador.uf || ''),
ganhadores: Number(ganhador.ganhadores || ganhador.quantidade) || 0,
faixa: Number(ganhador.posicao || ganhador.faixa) || 0
}))
};
}
private extrairAcertos(descricao: string): number {
const match = descricao.match(/(\d+)/);
return match ? parseInt(match[1], 10) : 0;
}
}
// Instância singleton
export const caixaAPIOfficial = CaixaAPIOfficial.getInstance();