chore: auto-commit (57 archivos)

- frontend/functions/core/format_datetime_short.md
- frontend/functions/core/format_datetime_short.test.ts
- frontend/functions/core/format_datetime_short.ts
- frontend/functions/core/format_duration.md
- frontend/functions/core/format_duration.test.ts
- frontend/functions/core/format_duration.ts
- frontend/functions/core/month_grid.md
- frontend/functions/core/month_grid.test.ts
- frontend/functions/core/month_grid.ts
- frontend/functions/core/string_hash_palette.md
- ...

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-09 03:41:58 +02:00
parent 4d5a5bd3ea
commit 8618aa1be3
58 changed files with 2923 additions and 0 deletions
+69
View File
@@ -0,0 +1,69 @@
---
name: fetch_json
kind: function
lang: ts
domain: infra
version: "1.0.0"
purity: impure
signature: "async function fetchJSON<T>(path: string, init?: RequestInit, baseUrl?: string): Promise<T>"
description: "Wrapper de fetch que parsea JSON, lanza HTTPError en errores HTTP y retorna undefined en 204. Exporta la clase HTTPError con el status code de la respuesta fallida."
tags: [http, fetch, json, rest, api, error, httperror, infra]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
params:
- name: path
desc: "Path relativo a baseUrl (ej: /api/users). Se concatena directamente: ${baseUrl ?? ''}${path}"
- name: init
desc: "RequestInit de fetch (method, body, headers, etc.). headers se mergea con el default Content-Type: application/json. credentials se puede sobreescribir (default: include)"
- name: baseUrl
desc: "URL base sin slash final (ej: https://api.example.com). Opcional, default string vacio"
output: "Promise<T> con el JSON parseado. Lanza HTTPError si !res.ok. Retorna undefined as T si status 204."
tested: false
tests: []
test_file_path: ""
file_path: "frontend/functions/infra/fetch_json.ts"
---
## Ejemplo
```typescript
import { fetchJSON, HTTPError } from "@fn_library/../infra/fetch_json";
// GET con base URL
const users = await fetchJSON<User[]>("/users", undefined, "https://api.example.com");
// POST con body
const card = await fetchJSON<Card>(
"/cards",
{ method: "POST", body: JSON.stringify({ title: "Nueva tarea" }) },
"/api",
);
// Capturar HTTPError
try {
await fetchJSON("/protected");
} catch (err) {
if (err instanceof HTTPError) {
console.error(`HTTP ${err.status}: ${err.message}`);
}
}
```
## Comportamiento detallado
- **URL**: `${baseUrl ?? ""}${path}` — si baseUrl es undefined o vacío, path se usa tal cual.
- **Headers**: `{ "Content-Type": "application/json" }` como base, mergeados con `init?.headers`. Los headers de init tienen precedencia.
- **credentials**: `"include"` por defecto (envía cookies). Se puede sobreescribir pasando `credentials: "omit"` en init.
- **Error HTTP** (`!res.ok`): intenta `res.json()` para leer el cuerpo del error. Si el parse falla (body vacío, no-JSON), usa `{ Message: res.statusText }`. Construye `HTTPError(status, err.Message ?? err.message ?? res.statusText)`.
- **204 No Content**: retorna `undefined as T` sin intentar parsear el body (que está vacío).
- **Errores de red**: no se capturan — el rechazo de la Promise nativa de `fetch` se propaga tal cual.
## Notas
Extraído de `apps/kanban/frontend/src/api.ts` (líneas 1432) y generalizado añadiendo el parámetro `baseUrl` opcional para reutilización fuera del contexto kanban.
`HTTPError` se exporta para que el consumidor pueda hacer `instanceof HTTPError` en sus catch.