3adbc0b59d
continuous-integration/webhook Deploy concluido com sucesso (VPS 4)
SEC-01+SEC-11: /secretaria/ask agora envia reply via WhatsApp (sock.sendMessage) e persiste a mensagem no banco Prisma após brain.chat(), com notify Socket.IO. SEC-02+SEC-03: MessageHandler emite hookBus 'ext:message.new' para todo msg recebido. Listener no ext-api auto-dispara a Secretária apenas se NÃO houver AIBot ativo na instância (exclusão mútua — chatbot tem prioridade). SEC-04: ChatListItem exibe ícone BotOff (âmbar) quando chat.bot_paused = true, com tooltip "Bot pausado — aguardando atendente". SEC-05: chatToLegacy() mapeia c.botPaused → bot_paused na bridge legada. NewWhatsChat recebe campo bot_paused opcional. SEC-08: POST /secretaria/ask valida que existe instância CONNECTED antes de criar conversa. Retorna 503 se nenhuma instância disponível. SEC-10: POST /api/chatbot/bots/:instanceId valida que credentialId pertence ao mesmo tenantId antes de criar o bot. Retorna 403 se não pertencer. SEC-12: chatBotState.resumeBot() limpa botSummary (= null) ao retomar, evitando contexto defasado após escalação humana. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
55 lines
2.6 KiB
TypeScript
55 lines
2.6 KiB
TypeScript
/**
|
|
* Plugin: ext-api
|
|
* Entry point — registra rotas REST e WS bridge ao activar.
|
|
*/
|
|
import type { PluginInstance, PluginContext } from '../../backend/src/core/types'
|
|
import { buildApiKeyAuth } from './backend/apikey-auth'
|
|
import { buildExtRoutes } from './backend/routes'
|
|
import { buildWsBridge } from './backend/ws-bridge'
|
|
import { buildWebhookDispatcher } from './backend/webhook-dispatcher'
|
|
import { WhatsAppConnectionManager } from '../../backend/src/modules/whatsapp/connection/WhatsAppConnectionManager'
|
|
import manifest from './manifest.json'
|
|
|
|
// O WhatsAppConnectionManager é um singleton instanciado no server.ts.
|
|
// O plugin precisa de uma referência a ele para enviar mensagens.
|
|
// Injectamos via globalThis como bridge temporária (sem modificar o server.ts).
|
|
// Em revisão futura pode ser passado no PluginContext.
|
|
declare global {
|
|
// eslint-disable-next-line no-var
|
|
var __whatsAppManager: WhatsAppConnectionManager | undefined
|
|
}
|
|
|
|
const plugin: PluginInstance = {
|
|
manifest: manifest as any,
|
|
|
|
async activate(ctx: PluginContext): Promise<void> {
|
|
const { app, prisma, db, config, hooks, logger, httpServer, io } = ctx
|
|
|
|
// ── REST ────────────────────────────────────────────────────────────────
|
|
const manager = globalThis.__whatsAppManager
|
|
if (!manager) {
|
|
logger.warn('[ext-api] WhatsAppConnectionManager não disponível via globalThis.__whatsAppManager — endpoints de send desativados')
|
|
}
|
|
|
|
const authMiddleware = buildApiKeyAuth(prisma)
|
|
const extRouter = buildExtRoutes(prisma, manager as WhatsAppConnectionManager, db, config, hooks, io)
|
|
|
|
app.use('/api/ext/v1', authMiddleware, extRouter)
|
|
logger.info('[ext-api] Rotas REST registradas em /api/ext/v1')
|
|
|
|
// ── WS Bridge ───────────────────────────────────────────────────────────
|
|
buildWsBridge(httpServer, prisma, hooks)
|
|
logger.info('[ext-api] WS bridge ativo em /api/ext/v1/stream (x-nw-key auth)')
|
|
|
|
// ── Webhook Dispatcher ──────────────────────────────────────────────────
|
|
buildWebhookDispatcher(prisma, hooks)
|
|
logger.info('[ext-api] Webhook dispatcher ativo')
|
|
},
|
|
|
|
async deactivate(ctx: PluginContext): Promise<void> {
|
|
ctx.logger.warn('[ext-api] Desativado. Reinicie o servidor para remover as rotas.')
|
|
},
|
|
}
|
|
|
|
export default plugin
|