Files
scoreodonto.com/backend/newwhats/proxy.js
T
VPS 4 Builder b21fb0f159 feat(newwhats): satélite WhatsApp/Secretária IA adaptado ao odonto
Clona o satélite do mercado adaptado ao scoreodonto (ESM, sem PluginManager):
- backend/newwhats/: config (ENV), auth (x-nw-key), routes /nw/* (clinica,
  especialidades, dentistas, procedimentos, planos — multi-tenant por clinica_id),
  sync-knowledge (base de conhecimento odonto → motor), webhook-receiver (HMAC,
  enxuto), proxy REST /api/nw/v1/* → motor /api/ext/v1/*, manifest, INTEGRACAO-MOTOR.md.
- server.js: registerNewwhats(app, pool) antes do listen.
- Removidos (não úteis): media-transcribe (motor já transcreve), smart-router,
  personas, follow-up-detector, context-builder.
- Config por ENV: NEWWHATS_URL/INTEGRATION_KEY/WEBHOOK_SECRET/CLINICA_ID.
- ativo::int=1 normaliza boolean vs smallint entre tabelas.
- Validado: buildKnowledgeText gera 1195 chars de dados reais; registro ok no express 5.2.1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 17:38:36 +02:00

31 lines
1.2 KiB
JavaScript

// Proxy REST: /api/nw/v1/* (frontend da clínica) → motor /api/ext/v1/*,
// injetando a integration_key como x-nw-key. Nunca expõe a chave ao browser.
import { getConfig } from './config.js'
export function createRestProxy() {
return async function restProxy(req, res) {
const cfg = getConfig()
if (!cfg.motorUrl || !cfg.integrationKey) {
return res.status(503).json({ error: 'Integração NewWhats não configurada (NEWWHATS_URL / NEWWHATS_INTEGRATION_KEY).' })
}
// /api/nw/v1/inbox?x=1 → /api/ext/v1/inbox?x=1
const tail = req.originalUrl.replace(/^\/api\/nw\/v1/, '')
const url = `${cfg.motorUrl}/api/ext/v1${tail}`
try {
const opts = {
method: req.method,
headers: { 'Content-Type': 'application/json', 'x-nw-key': cfg.integrationKey },
}
if (!['GET', 'HEAD'].includes(req.method) && req.body && Object.keys(req.body).length) {
opts.body = JSON.stringify(req.body)
}
const r = await fetch(url, opts)
const text = await r.text()
res.status(r.status)
try { res.json(JSON.parse(text)) } catch { res.send(text) }
} catch (e) {
res.status(502).json({ error: `Motor indisponível: ${e.message}` })
}
}
}