> ## Documentation Index
> Fetch the complete documentation index at: https://docs.jelou.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Context

> Referencia completa del objeto ctx disponible en cada handler: empresa, bot, usuario, trigger, environment, mensajería, memoria y más.

El objeto `ctx` es el segundo parámetro de todo handler. Contiene información de la empresa, bot, usuario, tipo de trigger, y da acceso a secrets, mensajería, memoria y logging.

```typescript theme={null}
handler: async (input, ctx, request) => {
  ctx.log("Petición recibida", {
    company: ctx.company.name,
    bot: ctx.bot.channel,
    user: ctx.user.id,
    trigger: ctx.trigger.type,
  });
}
```

## Referencia

| Propiedad          | Tipo                      | Descripción                         |
| ------------------ | ------------------------- | ----------------------------------- |
| `ctx.functionSlug` | `string`                  | Slug de la función                  |
| `ctx.company`      | `{ id, name }`            | Empresa del request                 |
| `ctx.bot`          | `{ id, name, channel }`   | Bot que originó el request          |
| `ctx.user`         | `{ id, names?, roomId? }` | Usuario de la conversación          |
| `ctx.conversation` | `{ id?, ... }`            | Datos de la conversación            |
| `ctx.operator`     | `{ id?, ... }`            | Operador asignado                   |
| `ctx.trigger`      | `TriggerInfo`             | Tipo de trigger (http, cron, event) |
| `ctx.env`          | `EnvAccessor`             | Acceso a secrets                    |
| `ctx.params`       | `Record<string, string>`  | Parámetros de ruta                  |
| `ctx.query`        | `Record<string, string>`  | Query string params                 |
| `ctx.jelou`        | `JelouSDK`                | Cliente de mensajería WhatsApp      |
| `ctx.memory`       | `MemorySDK`               | Memoria de sesión key-value         |
| `ctx.method`       | `string`                  | Método HTTP (GET, POST, etc.)       |
| `ctx.path`         | `string`                  | Path del request                    |
| `ctx.requestId`    | `string`                  | UUID único del request              |
| `ctx.isCron`       | `boolean`                 | `true` si es trigger cron           |
| `ctx.isEvent`      | `boolean`                 | `true` si es trigger event          |
| `ctx.isHttp`       | `boolean`                 | `true` si es request HTTP           |
| `ctx.skillId`      | `string \| null`          | ID del flujo de Brain Studio        |
| `ctx.executionId`  | `string \| null`          | ID de ejecución de Brain Studio     |
| `ctx.log()`        | `(...args) => void`       | Logger estructurado                 |

## Identidad

```typescript theme={null}
handler: async (input, ctx) => {
  // Empresa
  ctx.company.id;    // 42
  ctx.company.name;  // "Tienda ABC"

  // Bot
  ctx.bot.id;        // "bot-123"
  ctx.bot.name;      // "Bot de Soporte"
  ctx.bot.channel;   // "whatsapp"

  // Usuario
  ctx.user.id;       // 99
  ctx.user.names;    // "María García" (opcional)
  ctx.user.roomId;   // "room-456" (opcional)

  // Conversación y operador
  ctx.conversation.id;  // "conv-789" (opcional)
  ctx.operator.id;      // "op-012" (opcional)
}
```

Los datos se hidratan automáticamente desde la plataforma según los headers del request (`x-bot-id`, `x-user-id`).

## Trigger

Tres tipos de trigger determinan cómo se invocó tu función:

<Tabs>
  <Tab title="HTTP">
    ```typescript theme={null}
    handler: async (input, ctx) => {
      if (ctx.isHttp) {
        // Petición HTTP normal
        ctx.trigger; // { type: "http" }
      }
    }
    ```
  </Tab>

  <Tab title="Cron">
    ```typescript theme={null}
    handler: async (input, ctx) => {
      if (ctx.isCron) {
        ctx.trigger.type; // "cron"
        ctx.trigger.cron; // "0 9 * * *"
        ctx.trigger.cronName; // "recordatorio-mañana" (opcional)
      }
    }
    ```
  </Tab>

  <Tab title="Event">
    ```typescript theme={null}
    handler: async (input, ctx) => {
      if (ctx.isEvent) {
        ctx.trigger.type;  // "event"
        ctx.trigger.event; // "pago.completado"
      }
    }
    ```
  </Tab>
</Tabs>

<Tip>
  Usa los guards `ctx.isCron`, `ctx.isEvent` y `ctx.isHttp` en lugar de comparar `ctx.trigger.type` manualmente.
</Tip>

## Request

```typescript theme={null}
export default define({
  description: "API con ruta parametrizada",
  input: z.object({}),
  config: { path: "/users/:id" },
  handler: async (input, ctx) => {
    ctx.method;      // "GET"
    ctx.path;        // "/users/42"
    ctx.params.id;   // "42"
    ctx.query.format // "json" (de ?format=json)
    ctx.requestId;   // "a1b2c3d4-..."

    return { userId: ctx.params.id };
  },
});
```

## Environment (secrets)

```typescript theme={null}
handler: async (input, ctx) => {
  // Obtener un secret
  const apiKey = ctx.env.get("CRM_API_KEY"); // string | undefined

  // Verificar si existe
  if (ctx.env.has("WEBHOOK_SECRET")) {
    // ...
  }

  // Obtener todos (excepto internos __FN_*)
  const all = ctx.env.toObject(); // Record<string, string>
}
```

<Note>
  Las variables internas con prefijo `__FN_` están bloqueadas — `ctx.env.get("__FN_COMPANY_ID")` retorna `undefined`.
</Note>

## Mensajería (`ctx.jelou`)

Envía mensajes de WhatsApp directamente desde tu función:

```typescript theme={null}
handler: async (input, ctx) => {
  if (ctx.jelou.available) {
    await ctx.jelou.send({
      type: "text",
      to: "+593987654321",
      text: "Tu pedido está listo",
    });
  }
}
```

<Card title="Guía de mensajería" icon="message" href="/guides/functions/mensajeria">
  14 tipos de mensaje, templates HSM y manejo de errores.
</Card>

## Memoria (`ctx.memory`)

Persiste datos por sesión (key-value con TTL):

```typescript theme={null}
handler: async (input, ctx) => {
  if (ctx.memory.available) {
    const paso = await ctx.memory.get("paso", "inicio");
    await ctx.memory.set("paso", "confirmacion", 3600);
  }
}
```

<Card title="Guía de memoria" icon="database" href="/guides/functions/memoria">
  Primitivos, JSON, TTL, límites y patrones comunes.
</Card>

## Brain Studio (`skillId`, `executionId`)

Cuando tu función es invocada desde Brain Studio como herramienta MCP:

```typescript theme={null}
handler: async (input, ctx) => {
  if (ctx.skillId) {
    ctx.log("Invocado desde Brain Studio", {
      skillId: ctx.skillId,         // "skill-abc-123"
      executionId: ctx.executionId, // "exec-def-456"
    });
  }
}
```

Estos campos son `null` para peticiones HTTP directas y triggers cron.

## Logging

`ctx.log()` escribe JSON estructurado con metadatos automáticos:

```typescript theme={null}
handler: async (input, ctx) => {
  ctx.log("Procesando pedido", { telefono: input.telefono });
  // Escribe a stdout:
  // {
  //   "requestId": "a1b2c3d4-...",
  //   "function": "mi-funcion",
  //   "company": 42,
  //   "timestamp": "2026-04-07T15:30:01.234Z",
  //   "args": ["Procesando pedido", { "telefono": "593987654321" }]
  // }
}
```

Visualiza los logs con `jelou functions logs mi-funcion`.

## Ejemplo completo

```typescript index.ts theme={null}
import { define, z } from "@jelou/functions";

export default define({
  name: "procesar-pedido",
  description: "Procesa un pedido y notifica al cliente por WhatsApp",
  input: z.object({
    pedidoId: z.string(),
    telefono: z.string().min(10),
  }),
  handler: async (input, ctx) => {
    ctx.log("Procesando pedido", {
      pedidoId: input.pedidoId,
      company: ctx.company.id,
      bot: ctx.bot.name,
    });

    // Consultar API externa con secret
    const apiKey = ctx.env.get("ORDERS_API_KEY");
    const res = await fetch(`https://api.example.com/orders/${input.pedidoId}`, {
      headers: { Authorization: `Bearer ${apiKey}` },
    });
    const pedido = await res.json();

    // Notificar al cliente por WhatsApp
    if (ctx.jelou.available) {
      await ctx.jelou.send({
        type: "text",
        to: input.telefono,
        text: `Tu pedido ${pedido.id} está ${pedido.status}.`,
      });
    }

    // Guardar estado en memoria
    if (ctx.memory.available) {
      await ctx.memory.set("ultimo_pedido", input.pedidoId, 86400);
    }

    return {
      pedidoId: pedido.id,
      status: pedido.status,
      notificado: ctx.jelou.available,
    };
  },
});
```

<CardGroup cols={2}>
  <Card title="Mensajería" icon="message" href="/guides/functions/mensajeria">
    Enviar WhatsApp con ctx.jelou.
  </Card>

  <Card title="Memoria" icon="database" href="/guides/functions/memoria">
    Persistir datos con ctx.memory.
  </Card>

  <Card title="Secrets" icon="key" href="/guides/functions/secrets">
    Variables de entorno cifradas.
  </Card>

  <Card title="Autenticación" icon="lock" href="/guides/functions/autenticacion">
    Runtime tokens y funciones públicas.
  </Card>
</CardGroup>
