diff --git a/frontend/CLAUDE.md b/frontend/CLAUDE.md index 6094c34..9ed7f16 100644 --- a/frontend/CLAUDE.md +++ b/frontend/CLAUDE.md @@ -30,3 +30,15 @@ npm run check # svelte-check — debe salir 0 errores antes de cerrar un camb `hooks.server.ts` valida la cookie de sesión cifrada (`mf_session`), refresca el `access_token` y puebla `locals.user` / `locals.accessToken`. Para proteger una ruta, comprueba `locals.user` en su `load` y redirige a `/login?returnTo=…`. Para el backend, envía `locals.accessToken` como Bearer hacia `API_BASE_URL`. Variables de entorno en `.env` (ver `.env.example`): `ZITADEL_*`, `AUTH_REDIRECT_URI`, `AUTH_POST_LOGOUT_URI`, `SESSION_SECRET`, `API_BASE_URL`. + +## Backend API + +Cliente tipado con `openapi-fetch` sobre el OpenAPI de `Musify.Api`. En un `load`/action server: + +```ts +import { createApiClient } from '$lib/server/api'; +const api = createApiClient({ fetch, accessToken: locals.accessToken ?? undefined }); +const { data, error: err } = await api.GET('/tracks'); +``` + +Devuelve `{ data, error }` (estilo ErrorOr), no lanza. Los tipos viven en `src/lib/api/schema.d.ts` y se regeneran con `npm run gen:api` (requiere la API dev levantada en `API_BASE_URL`, que expone `/openapi/v1.json` solo en Development). diff --git a/frontend/package-lock.json b/frontend/package-lock.json index e022877..dc407b6 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@sveltejs/adapter-node": "^5.5.7", "jose": "^6.2.3", + "openapi-fetch": "^0.17.0", "openid-client": "^6.8.4" }, "devDependencies": { @@ -1834,6 +1835,21 @@ "node": ">=12.20.0" } }, + "node_modules/openapi-fetch": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/openapi-fetch/-/openapi-fetch-0.17.0.tgz", + "integrity": "sha512-PsbZR1wAPcG91eEthKhN+Zn92FMHxv+/faECIwjXdxfTODGSGegYv0sc1Olz+HYPvKOuoXfp+0pA2XVt2cI0Ig==", + "license": "MIT", + "dependencies": { + "openapi-typescript-helpers": "^0.1.0" + } + }, + "node_modules/openapi-typescript-helpers": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/openapi-typescript-helpers/-/openapi-typescript-helpers-0.1.0.tgz", + "integrity": "sha512-OKTGPthhivLw/fHz6c3OPtg72vi86qaMlqbJuVJ23qOvQ+53uw1n7HdmkJFibloF7QEjDrDkzJiOJuockM/ljw==", + "license": "MIT" + }, "node_modules/openid-client": { "version": "6.8.4", "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-6.8.4.tgz", diff --git a/frontend/package.json b/frontend/package.json index 84f2b4f..2857179 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,7 +9,8 @@ "preview": "vite preview", "prepare": "svelte-kit sync || echo ''", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "gen:api": "npx -y openapi-typescript@7 http://localhost:5111/openapi/v1.json -o src/lib/api/schema.d.ts" }, "devDependencies": { "@sveltejs/adapter-auto": "^7.0.1", @@ -25,6 +26,7 @@ "dependencies": { "@sveltejs/adapter-node": "^5.5.7", "jose": "^6.2.3", + "openapi-fetch": "^0.17.0", "openid-client": "^6.8.4" } } diff --git a/frontend/src/lib/api/schema.d.ts b/frontend/src/lib/api/schema.d.ts new file mode 100644 index 0000000..0830276 --- /dev/null +++ b/frontend/src/lib/api/schema.d.ts @@ -0,0 +1,4 @@ +export type paths = Record; +export type webhooks = Record; +export type components = Record; +export type operations = Record; diff --git a/frontend/src/lib/server/api.ts b/frontend/src/lib/server/api.ts new file mode 100644 index 0000000..e321e93 --- /dev/null +++ b/frontend/src/lib/server/api.ts @@ -0,0 +1,16 @@ +import createClient from 'openapi-fetch'; +import type { paths } from '$lib/api/schema'; +import { apiConfig } from '$lib/server/config'; + +interface ApiClientOptions { + fetch: typeof fetch; + accessToken?: string; +} + +export function createApiClient({ fetch, accessToken }: ApiClientOptions) { + return createClient({ + baseUrl: apiConfig.baseUrl, + fetch, + headers: accessToken ? { Authorization: `Bearer ${accessToken}` } : undefined + }); +} diff --git a/frontend/src/lib/server/config.ts b/frontend/src/lib/server/config.ts index 76515cb..75863b2 100644 --- a/frontend/src/lib/server/config.ts +++ b/frontend/src/lib/server/config.ts @@ -45,3 +45,9 @@ export const authConfig = { return env.AUTH_ALLOW_INSECURE_HTTP === 'true'; } }; + +export const apiConfig = { + get baseUrl() { + return (env.API_BASE_URL ?? '').replace(/\/+$/, ''); + } +};