Skip to main content
ctx.memory provee almacenamiento key-value por sesión respaldado por Redis.

Disponibilidad

if (!ctx.memory.available) {
  ctx.log("Memory API no disponible — faltan socketId o API key del workflow");
  return { error: "memory_unavailable" };
}
ctx.memory.available requiere socketId y una API key del workflow configurada. Llamar a métodos en un cliente no disponible lanza un Error.

¿String o JSON?

¿Tu valor es un string, número o boolean?
  → Sí: usa set() / get()
  → No (objeto, array): usa setJson() / getJson()

Métodos

MétodoFirmaRetornaDescripción
getget(key, defaultValue)Promise<string | number | boolean>Lee un valor primitivo
getJsongetJson<T>(key, defaultValue)Promise<T>Lee un valor JSON tipado
setset(key, value, ttl?)Promise<void>Guarda un valor primitivo
setJsonsetJson(key, value, ttl)Promise<void>Guarda un objeto JSON (TTL requerido)
deletedelete(key)Promise<void>Elimina una clave

get(key, defaultValue)

Lee un valor primitivo. El tipo del retorno coincide con el tipo del defaultValue:
const nombre = await ctx.memory.get("nombre", "anónimo");      // string
const intentos = await ctx.memory.get("intentos", 0);            // number
const verificado = await ctx.memory.get("verificado", false);    // boolean
Si la clave no existe, retorna el defaultValue.

getJson<T>(key, defaultValue)

Lee un valor JSON con tipado genérico:
interface Carrito {
  items: Array<{ id: string; cantidad: number }>;
  total: number;
}

const carritoVacio: Carrito = { items: [], total: 0 };
const carrito = await ctx.memory.getJson<Carrito>("carrito", carritoVacio);

set(key, value, ttl?)

Guarda un valor primitivo. El TTL es opcional (en segundos).
await ctx.memory.set("paso", "confirmacion");
await ctx.memory.set("paso", "confirmacion", 3600);
await ctx.memory.set("intentos", 3, 1800);
await ctx.memory.set("verificado", true);

setJson(key, value, ttl)

Guarda un objeto JSON. El TTL es requerido (en segundos).
await ctx.memory.setJson("carrito", {
  items: [{ id: "SKU-001", cantidad: 2 }],
  total: 49.98,
}, 86400);

delete(key)

Elimina una clave de la memoria.
await ctx.memory.delete("carrito");

Límites

ConstanteValorDescripción
MAX_PRIMITIVE_LENGTH255Máximo de caracteres para valores con set()
MAX_TTL_SECONDS86,400TTL máximo (24 horas)
setJson() requiere TTL porque almacena datos potencialmente grandes. Para valores primitivos con set(), el TTL es opcional.

Ejemplos prácticos

interface Carrito {
  items: Array<{ id: string; nombre: string; cantidad: number; precio: number }>;
  total: number;
}

const carritoVacio: Carrito = { items: [], total: 0 };

handler: async (input, ctx) => {
  const carrito = await ctx.memory.getJson<Carrito>("carrito", carritoVacio);

  carrito.items.push({
    id: input.productoId,
    nombre: input.nombre,
    cantidad: input.cantidad,
    precio: input.precio,
  });
  carrito.total = carrito.items.reduce((sum, i) => sum + i.precio * i.cantidad, 0);

  await ctx.memory.setJson("carrito", carrito, 86400);

  return { carrito };
}

MemoryApiError

Se lanza cuando la API de memoria retorna una respuesta no-2xx.
import { MemoryApiError } from "@jelou/functions";

try {
  await ctx.memory.set("clave", "valor", 3600);
} catch (err) {
  if (err instanceof MemoryApiError) {
    ctx.log("Memory API falló", { status: err.status, code: err.code });

    if (err.isRateLimit()) {
      ctx.log("Rate limit alcanzado, reintentando...");
    }
    if (err.isAuth()) {
      ctx.log("Problema de autenticación con la API de workflow");
    }
  }
}
Propiedad / MétodoTipoDescripción
statusnumberCódigo HTTP
codestringCódigo de error
messagestringMensaje descriptivo
isRateLimit()booleantrue cuando status === 429
isAuth()booleantrue cuando status === 401 o 403

ctx.memory vs base de datos externa

Criterioctx.memoryBase de datos externa
AlcancePor sesión (socketId)Global
PersistenciaTemporal (máx 24h TTL)Permanente
ConfiguraciónCero — viene incluidoRequiere connection string
Ideal paraEstado de conversación, cache de sesiónDatos de usuario, historial, configuración
  • Session-scoped: los datos están ligados al socketId de la conversación actual. No se comparten entre sesiones.
  • TTL requerido en setJson: olvidar el TTL causa un error de compilación TypeScript.
  • Límite de 255 caracteres en set(): valores más largos son truncados. Para datos extensos usa setJson().

Testing

import { assertEquals } from "jsr:@std/assert";
import { createMockContext, createMockMemoryClient } from "@jelou/functions/testing";

const mockMemory = createMockMemoryClient({
  store: { paso: "inicio", intentos: 0 },
});
const ctx = createMockContext({ memory: mockMemory });

Deno.test("lee valor existente", async () => {
  const paso = await ctx.memory.get("paso", "desconocido");
  assertEquals(paso, "inicio");
});

Deno.test("escribe y lee nuevo valor", async () => {
  await ctx.memory.set("paso", "confirmacion", 3600);
  const paso = await ctx.memory.get("paso", "desconocido");
  assertEquals(paso, "confirmacion");
});

Deno.test("inspecciona llamadas", async () => {
  mockMemory.reset();
  await ctx.memory.set("clave", "valor");
  assertEquals(mockMemory.calls.length, 1);
  assertEquals(mockMemory.calls[0].method, "set");
});

Deno.test("JSON tipado", async () => {
  await ctx.memory.setJson("carrito", { items: [], total: 0 }, 3600);
  const carrito = await ctx.memory.getJson("carrito", { items: [], total: 0 });
  assertEquals(carrito.total, 0);
});

createMockMemoryClient()

Referencia completa del mock de memoria.