bffStream

A Next.js route handler that relays the API's event stream with the session's bearer, so the token never reaches the browser.

app/api/conversations/[id]/events/route.ts
import { bffStream } from "@/lib/bff-stream";export const dynamic = "force-dynamic";export const GET = bffStream({  upstream: (req) => `${process.env.API_URL}/conversations/${conversationId(req)}/events`,  getAccessToken: async () => (await auth())?.accessToken ?? null,});

Installation

Once per app, set up Aedis UI. The CLI verifies the signed release before writing anything and pins every dependency:

npx @aedis/cli@0.1.0 init

Import the theme once in your global CSS, after Tailwind:

app/globals.css
@import "tailwindcss";@import "./styles/aedis-theme.css";

Then add the component:

npx @aedis/cli@0.1.0 add bff-stream# pnpm dlx @aedis/cli@0.1.0 add bff-stream · yarn dlx @aedis/cli@0.1.0 add bff-stream · bunx @aedis/cli@0.1.0 add bff-stream

Props

PropTypeDefaultDescription
upstreamstring | URL | (request) => string | URL—The API stream, from configuration; http(s) only. Never read a URL from the request.
getAccessToken(request) => string | null—The bearer of the server-side session; null answers 401 without calling the API.
headersRecord<string, string>—Extra headers for the API; credentials, cookies and hop-by-hop headers throw.
log(message, details) => voidconsole.errorWhere failure details go.
connectTimeoutMsnumber15000Wait for the API to start the stream.

Security

  • The bearer comes from the server session only; the browser never sees it.
  • Nothing from the browser goes upstream except a Last-Event-ID of at most 256 printable characters: no cookies, no Authorization, no query.
  • No-store, no-transform and X-Accel-Buffering: no; upstream headers (Set-Cookie, internal ones) are not copied.
  • The API request is aborted when the browser disconnects, and after connectTimeoutMs without a response.
  • The browser gets a bare status (401, 403, 204 or 502); details go to the server log. server-only keeps it out of client bundles.