Saltar al contenido principal
Las automatizaciones son las partes de una app que se ejecutan por sí solas — en una programación, o cuando un servicio externo envía un evento. Las declaras en un componente process en kazzle.config.ts. Un componente puede llevar tantos triggers como necesites.

La estructura

{
  name: 'events',
  type: 'process',
  path: './components/events/index.ts',
  processMode: 'persistent', // o 'triggered'
  triggers: [
    { name: 'daily-digest', kind: 'schedule', schedule: '0 9 * * *', path: '/cron/daily-digest' },
    { name: 'stripe',       kind: 'webhook',                          path: '/webhook/stripe' },
  ],
}
Aquí suceden dos cosas:
  • processMode elige el ciclo de vida — servidor de larga duración, o una ejecución única por trigger.
  • triggers[] lista los eventos que deben activar este componente.
Las dos partes son independientes. Un servidor persistente puede tener un cron. Un proceso efímero puede tener un webhook. Elige el ciclo de vida que se ajuste a la carga de trabajo, luego adjunta tantos triggers como quieras.

processMode

ModoQué se ejecutaCuándo usar
persistent (predeterminado)Un servidor HTTP de larga duración. Los triggers se envían por POST.El componente ya sirve HTTP, o mantiene estado en memoria (colas, websockets, cachés).
triggeredEl script de entrada se genera por trigger y sale.Trabajos de fondo puros — limpieza nocturna, manejador único de webhook de Stripe, etc. Sin servidores inactivos.

Triggers

Cada trigger tiene un name (único dentro del componente), un kind, y — dependiendo del modo — un schedule y/o path.
CampoCuándo es requeridoNotas
namesiempreSe usa como segmento de URL de webhook y en logs. Kebab-case.
kindsiempre'schedule' o 'webhook'.
schedulecuando kind: 'schedule'Expresión cron de 5 campos. La resolución de minutos es el mínimo.
pathcuando processMode: 'persistent'Ruta HTTP en tu servidor donde llega el trigger.

Modo persistente — HTTP hacia el servidor

Cuando un trigger se activa para un componente persistente, Kazzle envía un POST a tu servidor en el path declarado. La solicitud lleva:
EncabezadoQué te dice
Authorization: Bearer ${KAZZLE_TRIGGER_SECRET}Valida esto. Rechaza llamadas que no coincidan.
x-kazzle-trigger-nameEl name del trigger del manifiesto.
x-kazzle-trigger-run-idID opaco para correlación de logs.
x-kazzle-triggered-bycron | webhook | manual.
Para triggers de webhook, el cuerpo de la solicitud original se reenvía como cuerpo POST. Para triggers de programación el cuerpo está vacío.
// components/events/index.ts (modo persistente)
const TRIGGER_SECRET = process.env.KAZZLE_TRIGGER_SECRET ?? '';

Bun.serve({
  port: Number(process.env.PORT),
  hostname: process.env.HOST,
  async fetch(req) {
    const url = new URL(req.url);

    if (req.method === 'POST' && url.pathname === '/cron/daily-digest') {
      if (req.headers.get('authorization') !== `Bearer ${TRIGGER_SECRET}`) {
        return new Response('Unauthorized', { status: 401 });
      }
      await sendDigest();
      return Response.json({ ok: true });
    }

    if (req.method === 'POST' && url.pathname === '/webhook/stripe') {
      if (req.headers.get('authorization') !== `Bearer ${TRIGGER_SECRET}`) {
        return new Response('Unauthorized', { status: 401 });
      }
      const event = await req.json();
      await handleStripe(event);
      return Response.json({ ok: true });
    }

    return new Response('not found', { status: 404 });
  },
});

Modo activado — una ejecución única por trigger

Cuando un trigger se activa para un componente triggered, Kazzle genera el script de entrada nuevo y espera a que salga. No hay path; el script aprende qué trigger se activó desde variables de entorno.
Variable de entornoValor
TRIGGER_NAMEEl name del trigger del manifiesto.
TRIGGERED_BYcron | webhook | manual.
RUN_IDID opaco para correlación de logs.
WEBHOOK_PAYLOADCuerpo JSON (solo triggers de webhook).
// components/events/index.ts (modo activado)
const trigger = process.env.TRIGGER_NAME;
const runId = process.env.RUN_ID;

if (trigger === 'daily-digest') {
  await sendDigest();
} else if (trigger === 'stripe') {
  const event = JSON.parse(process.env.WEBHOOK_PAYLOAD ?? '{}');
  await handleStripe(event);
}

console.log(`run ${runId} done`);
Los componentes activados no tienen máquinas inactivas en producción — se inician por llamada y se apagan al salir.

URLs de webhook

POST https://api.kazzle.app/webhooks/{spaceId}/{appId}/{componentName}/{triggerName}
El segmento triggerName debe coincidir con una entrada kind: 'webhook' en el triggers[] de ese componente. Los nombres de trigger desconocidos devuelven 404.

Resolución de programación

Las expresiones cron son de 5 campos (minuto, hora, día del mes, mes, día de la semana) y la resolución de minutos es el mínimo. Las programaciones sub-minuto se rechazan en el tiempo de validación del manifiesto.

Cómo se registran las ejecuciones

Cada activación de trigger escribe una fila process_runs con el trigger_name, triggered_by, run_id, y el estado de salida de la ejecución. Puedes consultar estos desde tu propio código o inspeccionarlos en la vista de ejecuciones de la app.

Agotamiento de créditos

Una ejecución fallida se registra y se registra, pero la programación sigue ejecutándose en su cadencia normal — una ejecución inestable nunca desactiva el trigger. Lo único que detiene una ejecución son los créditos: cada activación de trigger se verifica contra el saldo del espacio, y mientras el espacio no tenga créditos (o no tenga facturación configurada) las ejecuciones se omiten con un 402. Esto se recupera automáticamente — la programación permanece armada y la siguiente activación después de que recargues se ejecuta normalmente, sin reanudación manual.

Agregar automatizaciones después

Una app simple puede comenzar sin triggers y ganarlos después — agregar un resumen diario, conectar Stripe, ejecutar limpieza. El ciclo de vida del componente (processMode) y los triggers (triggers[]) son independientes, así que puedes cambiarlos sin reescribir el resto de la app.