Skip to main content

Firma

import { define, z } from "@jelou/functions";

export default define({
  name: "mi-funcion",
  description: "Qué hace esta función",
  input: z.object({ /* ... */ }),
  output: z.object({ /* ... */ }),
  tags: ["categoria"],
  auth: true,
  config: { /* ... */ },
  handler: async (input, ctx, request) => {
    return { /* ... */ };
  },
});

Opciones

OpciónTipoRequeridoPredeterminadoDescripción
namestringNoNombre visible y nombre de la herramienta MCP
descriptionstringNoDescripción legible, mostrada en el listado MCP
inputz.ZodObjectNoEsquema Zod para validar la entrada. Rechaza con 400 si falla.
outputz.ZodObjectNoEsquema Zod para validar la salida. Solo advierte, nunca bloquea.
tagsstring[]NoTags de categorización
authAuthOptionNofalseAutenticación Bearer token (ver Autenticación)
configConfigNo{}Configuración de runtime (ver Configuración)
handler(input, ctx, request) => PromiseFunción que procesa la petición

Handler

type Handler<TInput, TOutput> = (
  input: z.infer<TInput>,
  ctx: Context,
  request: Request
) => Promise<z.infer<TOutput>> | z.infer<TOutput>;
ParámetroTipoDescripción
inputz.infer<TInput>Entrada parseada y validada (con tipos inferidos del esquema Zod)
ctxContextObjeto context con metadata de la petición y acceso a la plataforma (ver Context)
requestRequestObjeto Web estándar Request
Puedes retornar un valor directamente o una Promise.

Del handler a la respuesta HTTP

Lo que retornas en el handler determina la respuesta HTTP que recibe el cliente:
Retornas en el handlerStatusContent-TypeBody
{ ok: true }200application/json{"ok":true}
"texto plano"200text/plaintexto plano
undefined / sin return204vacío
throw new Error(...)500application/json{"error":"Internal server error"}
Timeout excedido504application/json{"error":"Function timed out"}
Input inválido (schema)400application/json{"error":"Validation failed","details":[...]}
handler: async (input, ctx) => {
  const result = await procesarPedido(input.pedidoId);
  return { procesado: true, id: result.id };
}
// → 200 {"procesado":true,"id":"abc-123"}
Los errores de negocio (cliente no encontrado, saldo insuficiente) son tu responsabilidad — retornas un JSON con tu propia estructura y el status siempre es 200. Los errores de plataforma (validación del schema, timeout, crash) generan automáticamente 400, 500 o 504.

Validación de entrada

Cuando defines un esquema input, cada petición se valida antes de ejecutar el handler. Si falla, el handler no se ejecuta y se retorna un 400:
{
  "error": "Validation failed",
  "details": [
    {
      "path": ["email"],
      "message": "Invalid email",
      "code": "invalid_string"
    }
  ]
}
Para peticiones GET, los query parameters son strings. Usa z.coerce para convertir tipos:
input: z.object({
  q: z.string(),
  limit: z.coerce.number().default(10),
})
// GET /search?q=hello&limit=5

Validación de salida

Cuando defines un esquema output, el valor retornado se valida después de la ejecución. Si no coincide, se registra una advertencia en los logs pero la respuesta se envía normalmente con status 200.
La validación de output nunca bloquea la respuesta. Es una herramienta de desarrollo para detectar inconsistencias.

Anotaciones .describe()

Usa .describe() en los campos del esquema para documentar parámetros. Estas descripciones aparecen automáticamente en el esquema MCP:
input: z.object({
  telefono: z.string().min(10).describe("Número con código de país, ej: 593987654321"),
  tipo: z.enum(["prepago", "pospago"]).describe("Tipo de plan del cliente"),
})

app() — funciones multi-tool

Usa app() para agrupar múltiples define() en un solo despliegue. Cada tool obtiene su propia ruta HTTP, registro MCP y schedules cron.
import { app, define, z } from "@jelou/functions";

export default app({
  config: { cors: { origin: "*" }, timeout: 30_000 },
  tools: {
    enviarEmail: define({
      description: "Envía un correo electrónico",
      input: z.object({ to: z.string(), subject: z.string() }),
      handler: async (input) => ({ sent: true }),
    }),
    leerBandeja: define({
      description: "Lee los mensajes de la bandeja de entrada",
      input: z.object({ limit: z.coerce.number().default(10) }),
      handler: async (input) => ({ messages: [] }),
    }),
  },
});
Firma de tipo:
function app(options: {
  config?: AppConfig;
  tools: Record<string, AnyEdgeFunction>;
}): EdgeApp;

AppConfig

interface AppConfig {
  cors?: {
    origin?: string | string[];
    methods?: string[];
    headers?: string[];
    credentials?: boolean;
    maxAge?: number;
  };
  timeout?: number;
  methods?: string[];
  mcp?: boolean;
}

Guardas de tipo

import { isEdgeApp, isEdgeFunction } from "@jelou/functions";

isEdgeApp(module);      // true si fue creado con app()
isEdgeFunction(module);  // true si fue creado con define()

Guía completa de multi-tool

Rutas auto-generadas, combinación de config, MCP unificado y cron por tool.