Files
melgarafaelandClaude Opus 5.5 55def8727c Merge da main no PR 1: a 0501 passa a carregar os avisos do Jev (0500)
A main recebeu a 0500 (avisos do Jev na Central), que acrescenta
jev_pedido_de_humano e jev_parar_de_receber ao CHECK de agent_inbox_items.kind.
A 0501 reconstrói esse CHECK com a lista inteira e roda DEPOIS da 0500 na
cadeia do CLI: sem os dois tipos, ela apagaria o vocabulário da 0500 (ou
falharia com avisos do Jev já gravados). A lista da 0501 e o bloco único do
baseline levam os três tipos. Nos testes, os dois lados ficam.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 16:32:29 -03:00
..
…
…

lib/api/

Helpers e convenções compartilhadas por toda rota /api/v1/*.

  • wrappers.ts — ok(data, opts) / fail(code, message, status, opts) / noContent() + tipos ApiSuccess<T> / ApiError
  • errors.ts — ApiErrorCodes (constante canônica de códigos)
  • idempotency.ts — comIdempotencia: reserva antes do efeito, replay (mesma chave e corpo devolvem a resposta gravada) e conflito (mesma chave com corpo diferente, para o chamador responder 409). Persiste em idempotency_keys, com recibo de 24h e reserva de 60s.

Exemplo

import { ok, fail } from "@/lib/api/wrappers";
import { ApiErrorCodes } from "@/lib/api/errors";

export async function GET(req: Request) {
  const data = await fetchSomething();
  if (!data) return fail(ApiErrorCodes.not_found, "Lead não encontrado", 404);
  return ok(data, { meta: { cursor: nextCursor, has_more: true } });
}

A adicionar (próximas specs)

  • auth.ts — extrai user / tenant da request (cookie OU bearer); valida MFA; retorna AuthContext
  • rate-limit.ts — sliding window via Upstash; injeta headers X-RateLimit-*
  • pagination.ts — encode/decode de cursor opaco base64 + HMAC
  • audit.ts — fire-and-forget write em api_audit_log
  • cors.ts — allowlist por tenant