// BFF → external backend wiring. Two surfaces, one upstream: // // • `backend` — typed JSON client (`backend.get("/widgets")`). Use // this from server components, route handlers, and any code that // calls the backend with a typed response. // // • `proxyToBackend` — raw `Response` passthrough used by the // `app/api/backend/[...path]/route.ts` proxy. Necessary because the // proxy streams the body untouched; the typed client buffers it. // // Configure `BACKEND_URL` in your env. Tokens, retry/timeout, and auth // header injection live in this file — that's the one place that talks // to the upstream service. import { createFetchHttpClient, type HttpClient } from "@raredays/core"; const BACKEND_URL = process.env.BACKEND_URL ?? ""; // Lazy-initialized: warn once, on first actual use of the backend client, // rather than at module-import time. This keeps `next build` quiet for // apps that don't (yet) use backend calls, while still surfacing a clear // signal the first time a missing config bites. let warnedMissingBackendUrl = false; function warnIfMissingBackendUrl(): void { if (warnedMissingBackendUrl) return; if (BACKEND_URL) return; if (process.env.NODE_ENV !== "production") return; warnedMissingBackendUrl = true; // eslint-disable-next-line no-console console.warn("[backend-client] BACKEND_URL is not set — backend calls will fail."); } export const backend: HttpClient = createFetchHttpClient({ // `baseUrl` is read at call time by the underlying client, so the lazy // warning above is sufficient — no module-load side effect needed. baseUrl: BACKEND_URL, // Default retry: 2 attempts on 5xx/network errors with 100ms backoff. // Tune per-call via `backend.get(path, { retry: { ... } })` when you need // different semantics (e.g. webhooks shouldn't retry, batch jobs should). retry: { maxAttempts: 2 }, }); /** * Raw passthrough for the `[...path]` proxy route. Keeps the streaming * semantics that `fetch` provides — the typed `backend` client buffers * the body and isn't appropriate for proxying. */ export async function proxyToBackend(path: string, init: RequestInit): Promise { warnIfMissingBackendUrl(); if (!BACKEND_URL) { return new Response("BACKEND_URL not configured", { status: 502 }); } const url = `${BACKEND_URL.replace(/\/$/, "")}/${path.replace(/^\//, "")}`; return fetch(url, init); }