← DocumentaciónReferencia

Plugin SDK

Extendé Replai con rutas + handlers de mensajes — paquetes npm.

El Plugin SDK te permite extender Replai con paquetes npm que agregan rutas HTTP, reaccionan a mensajes entrantes, y envían respuestas — todo dentro del scope autenticado y multi-tenant del API.

Anatomía de un plugin

Un plugin es un módulo Node que exporta por defecto un objeto ReplaiPlugin:

import type { ReplaiPlugin } from '@replai/plugin-host';

const plugin: ReplaiPlugin = {
  name: 'echo',
  version: '0.1.0',
  description: 'Echoes WhatsApp messages prefixed with !echo back to the sender.',
  permissions: ['inbound:read', 'outbound:send'],

  setup(ctx, scope) {
    // HTTP route — mounted at /v1/plugins/echo/ping
    scope.get('/ping', () => ({ ok: true }));

    // Reacciona a mensajes entrantes
    ctx.onInbound(async (event) => {
      if (event.type !== 'message.received') return;
      if (!event.bodyPreview.startsWith('!echo ')) return;
      await ctx.sendText({
        sessionId: event.sessionId,
        to: event.remoteJid,
        text: event.bodyPreview.slice(6),
        clientMessageId: `echo:${event.messageId}`,
      });
    });
  },
};

export default plugin;

Cómo se cargan

Los plugins se listan por nombre en la variable de entorno REPLAI_PLUGINS (separados por coma):

REPLAI_PLUGINS=@replai/plugin-echo,@replai/plugin-stats

Cada uno se resuelve vía import estándar de Node — funcionan paquetes de npm, workspace packages, o paths absolutos (file://). El loader corre una sola vez al boot del API; cambios requieren restart.

Config por plugin

Si tu plugin tiene config, pasala como JSON en una variable de entorno con la forma REPLAI_PLUGIN_<NAME>_CONFIG:

REPLAI_PLUGIN_ECHO_CONFIG={"emoji":"🦜"}

Eso aparece en ctx.config dentro del setup. JSON inválido → fallback a {}.

Lo que tu plugin recibe

El argumento ctx (ReplaiPluginContext) expone una superficie chica y estable:

CampoPara qué
pluginNameNombre estable del plugin (matchea el prefix de ruta).
loggerPino-shaped logger child. Tag automático plugin: <name>.
configTu config parseada del env.
onInbound(handler)Subscribe a eventos message.received, message.sent, message.delivered, message.read. Filtrar por tenant en tu handler si hace falta.
sendText(args)Envía un mensaje saliente. Internamente encola en el outbound queue — mismo path que POST /v1/messages.

El scope que recibís es una FastifyInstance ya montada en /v1/plugins/<name>, detrás de la auth con API key. En cada handler tenés disponibles request.tenantId, request.apiKey, y request.db (Prisma scoped al tenant).

Inspeccionar plugins cargados

GET /v1/plugins/manifest

{
  "count": 1,
  "plugins": [
    {
      "name": "echo",
      "version": "0.1.0",
      "description": "Echoes WhatsApp messages...",
      "permissions": ["inbound:read", "outbound:send"],
      "spec": "@replai/plugin-echo",
      "mountPath": "/v1/plugins/echo"
    }
  ]
}

Trust model

  • Los plugins corren in-process con el API — tienen acceso completo a la base de datos y al sistema operativo del host. Cargá solo plugins que desarrollaste vos o partners verificados.
  • El campo permissions es documental hoy — declarás qué necesitás, pero no hay enforcement en runtime. Próxima iteración (Sprint 25) va a agregar gating por capability.
  • Errores en setup() o en route handlers se capturan + loggean como warning. Un plugin que crashea no derriba al resto.

Próximos pasos

  • Cloná @replai/plugin-echo como template.
  • Publicalo en npm como private package (o usalo desde un workspace en el mismo monorepo).
  • Agregalo a REPLAI_PLUGINS en tu deployment y restartea el API.
  • Verificá con GET /v1/plugins/manifest que cargó correctamente.
Plugin SDK · Replai · WhatsApp con IA en Venezuela