import { H as HttpClientOptions } from '../index.d-CS4ceNwT.cjs'; import { NextResponse, NextRequest } from 'next/server'; /** * '@palbase/web/next/proxy' — proactive cookie-session refresh in the Next.js * proxy (the file convention that replaced `middleware` in Next 16; this * package's peer range is `next >= 16`). * * REQUIRED — not optional — for session-bearing RSC apps. Server Components * cannot write cookies, so pbServer's reactive refresh cannot PERSIST a * rotated session there: every RSC render would re-refresh from the SAME * cookie refresh token, and once two of those land more than 30s apart * (outside palauth's rotation grace) the reuse detector REVOKES THE WHOLE * TOKEN FAMILY — the user is force-logged-out everywhere. The proxy refreshes * the cookie BEFORE the RSC tree renders, so pbServer hydrates a still-valid * session and never burns the token itself. * * BUNDLE RULE — why this is a SEPARATE entry taking an EXPLICIT config * instead of reading the process-global one like pbServer does: * * Next compiles the proxy into its OWN bundle, so the generated palbe.gen.ts * imported by app/layout.tsx does not reach it. Importing palbe.gen.ts from * proxy.ts to fix that would drag `__configure` → buildRuntime → * messaging/wasm/loader.ts into that graph: measured on a real app, 2.4 MB * where this entry ships 168 KB. (Under the pre-16 `middleware` convention it * was worse than size — that bundle was Edge, and webpack failed the build * outright with "Dynamic Code Evaluation ... not allowed in Edge Runtime". * `proxy` runs on nodejs, which is not configurable, so the hard error is * gone and the weight is not.) * * So the proxy never touches the runtime: it takes the two published identity * values it actually needs and speaks the one auth wire directly. Nothing on * this module's import graph may reach ../runtime.js — * __tests__/next-proxy-bundle.test.ts locks that against the real build * output. * * WHERE THE CONFIG COMES FROM — and why an explicit argument is not a chore the * application has to do. `palbe-gen` writes `palbase/config.ts`, a one-line * barrel over an IMPORT-FREE leaf beside the generated client, and rewrites * both on every run from PALBASE_ENV. So the proxy follows the same switch the * data client follows, while importing a module that has no graph to drag. That * is what keeps the rule above intact WITHOUT relying on tree-shaking: the leaf * reaches nothing, so there is nothing to shake. * * Import `palbase/config`, never `palbase/client`. The client barrel re-exports * palbe.gen.ts, which calls __configure at import time — that is the 2.4 MB * path. The bundle lock measures this chain (app proxy -> generated leaf -> this * entry), so pointing the import at the client barrel turns it red. * * 'next/server' is imported only lazily (the type-only NextRequest/ * NextResponse imports erase at build time). * * ```ts * // proxy.ts — written by `palbase link`, carries no address and no key * import { palbeProxy } from '@palbase/web/next/proxy'; * import { environmentConfig } from './palbase/config'; * import type { NextRequest } from 'next/server'; * * export function proxy(request: NextRequest) { * return palbeProxy(request, environmentConfig); * } * * // `config` MUST be declared here, in this file: Next reads it off THIS * // file's AST (export const + literal initializer). A re-exported or * // imported config is invisible and silently degrades to a catch-all. * export const config = { matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'] }; * ``` */ /** * The published identity palbeProxy needs — the same two values * `palbase web link` bakes into palbe.gen.ts. Both are publishable (the * anon key already ships in every browser bundle); a service_role key is * REJECTED, it has no business in a request-path bundle. * * A `PalbeConfig` is structurally assignable, so apps that already hold one * can pass it straight through. */ interface PalbeProxyConfig { /** Environment URL, e.g. `https://abc12345m.palbase.studio`. */ url: string; /** Publishable (anon) API key: `pb__c`. */ apiKey: string; /** Same auth encryption settings as the generated web configuration. */ sealed?: HttpClientOptions['sealed']; } interface PalbeProxyOptions { /** Refresh when the access token expires within this window. Default 60s. */ refreshMarginMs?: number; /** * Pre-built response to decorate (e.g. from your own chained proxy logic) instead of * building `NextResponse.next({ request })`. Pass-through cases return it * UNMODIFIED. Caveat: a pre-built response snapshotted the request headers * at ITS creation, so a rotated cookie reaches the browser (Set-Cookie) * but not the downstream RSC render of THIS request — prefer omitting this * and building your response after palbeProxy when possible. */ response?: NextResponse; } /** * Keep the session cookie fresh for the request. No session / still-fresh * session → untouched pass-through (no cache-control changes). Stale or * expired → single-flight refresh, then the rotated (or cleared, on a dead * token) cookies are written onto BOTH the request (for the downstream RSC * render via `NextResponse.next({ request })`) and the response (for the * browser), with `Cache-Control: private, no-store` on touched responses. * * Cookie writes go through Next's cookie APIs with the DECODED codec values: * Next percent-encodes on serialization, so the wire bytes come out exactly * as the shared codec's (see encodeSessionCookiesDecoded). NextRequest's * cookie store is NOT a CookieStoreLike (its set is the 2-arg/RequestCookie * form), hence the direct codec calls here instead of the pbServer adapter. */ declare function palbeProxy(request: NextRequest, config: PalbeProxyConfig, opts?: PalbeProxyOptions): Promise; export { type PalbeProxyConfig, type PalbeProxyOptions, palbeProxy };