b21fb0f159
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>
31 lines
1.2 KiB
JavaScript
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}` })
|
|
}
|
|
}
|
|
}
|