Current path: {$location.path}
``` --- ## API layer ### Core function: `api()` Located in `frontend/src/lib/api.ts`. Features: - **Request deduplication** — identical concurrent GETs share one promise - **Loading indicator** — drives `activeRequests` store → `LoadingBar` - **Build-version check** — auto-reloads page when server build is newer - **Mock interceptor** — when `__MOCK__` is `true`, routes requests to `frontend/mocking/*.json` - **Sentry integration** — span instrumentation (when enabled) ### Shared browser/SSR transport The project intentionally shares the low-level API transport between browser and SSR via `api/hooks/lib/ssr`. - In the browser, it eventually becomes `fetch(...)`. - In SSR, `apiRequest(...)` delegates to `context.ssrRequest(...)`. - GET responses reached during SSR are written into `window.__SSR_CACHE__` for hydration. This is why SSR can preload both content and navigation without building a separate frontend-only data layer. ### Usage patterns ```typescript import { api, getCachedEntries, getCachedEntry, getDBEntries, postDBEntry } from "./lib/api" // Cached (1h TTL, for read-heavy data) const pages = await getCachedEntries<"content">("content", { lang: "de", active: true }) const page = await getCachedEntry<"content">("content", { path: "/about" }) // Uncached const items = await getDBEntries<"content">("content", { type: "blog" }, "sort", 10) // Write const result = await postDBEntry("content", { name: "New Page", active: true }) // Raw API call const { data, count } = await api{$_("hero.subtitle", { values: { name: "World" } })}
``` --- ## Common pitfalls - **Never `spaNavigate()` in SSR** — always guard with `typeof window !== "undefined"`. - **Store subscriptions in modules** — if subscribing to stores outside components, remember to unsubscribe to prevent memory leaks. - **API PUT returns only changed fields** — don't expect a full object back from PUT requests. - **`_id` not `id` for filters** — API filters use MongoDB's `_id`, but response objects may have both `id` and `_id`. - **`$location` strips trailing slashes** — `/about/` becomes `/about` (except root `/`). - **Content cache is 1 hour** — `getCachedEntries` caches in memory for 1h. For admin previews, use `getDBEntries` (uncached). - **`$effect` alone is not SSR** — server-side rendering must trigger the same data path explicitly outside browser-only reactive effects. - **A rendered shell is not enough** — always verify that SSR HTML actually contains page-critical content and navigation.