Files
luna-recipes/frontend/src/api/client.ts
clawd 301e42b1dc v2.1.2026 — PostgreSQL, Auth, Household, Shopping Smart-Add, Docker
Backend:
- SQLite → PostgreSQL (pg_trgm search, async services)
- All services rewritten to async with pg Pool
- Data imported (50 recipes, 8 categories)
- better-sqlite3 removed

Frontend:
- ProfilePage complete (edit profile, change password, no more stubs)
- HouseholdCard (create, join via code, manage members, leave)
- Shopping scope toggle (personal/household)
- IngredientPickerModal (smart add with basics filter)
- Auth token auto-attached to all API calls (token.ts)
- Removed PlaceholderPage

Infrastructure:
- Docker Compose (backend + frontend + postgres)
- Dockerfile for backend (node:22-alpine + tsx)
- Dockerfile for frontend (vite build + nginx)
- nginx.conf with API proxy + SPA fallback
- .env.example for production secrets

Spec:
- AUTH-V2-SPEC updated: household join flow, manual shopping items
2026-02-18 17:26:24 +00:00

30 lines
855 B
TypeScript

import { getAuthToken } from './token'
const BASE_URL = '/api'
export async function apiFetch<T>(path: string, options?: RequestInit): Promise<T> {
const method = options?.method?.toUpperCase() || 'GET'
const headers: Record<string, string> = { ...options?.headers as Record<string, string> }
// Auto-attach auth token
const token = getAuthToken()
if (token) {
headers.Authorization = `Bearer ${token}`
}
if (['POST', 'PUT', 'PATCH'].includes(method) && options?.body) {
headers['Content-Type'] = headers['Content-Type'] || 'application/json'
}
const res = await fetch(`${BASE_URL}${path}`, {
...options,
headers,
credentials: 'include',
})
if (!res.ok) {
const errorData = await res.json().catch(() => ({}))
throw new Error(errorData.message || `API Error: ${res.status}`)
}
return res.json()
}