feat(phase-1): auth session wiring (proxy + layout + helpers)

- proxy.ts: composes Supabase session refresh + next-intl middleware
  into a single NextResponse via copyCookies helper. Coarse auth gate
  on /dashboard + /admin prefixes redirects unauth users to
  /[locale]/sign-in (no ?next= per trimmed plan).
- lib/supabase/session.ts: implements updateSupabaseSession() returning
  { response, user }. Cookies written onto both request.cookies (for
  downstream reads) and response.cookies (for browser). PROTECTED_PATH_PREFIXES
  exported as the gate list.
- lib/proxy/copy-cookies.ts: small helper that ports Set-Cookie entries
  between two NextResponses.
- lib/auth/get-server-session.ts: getServerSession() returning
  { user, role } | null. Derives User type from the factory's return
  type so @supabase/supabase-js stays out of allow-listed lib/auth/*
  per ESLint no-restricted-imports.
- lib/auth/session-provider.tsx: client-side context exposing user to
  client components via useSession() — populated once per request in
  the locale layout.
- app/[locale]/layout.tsx: reads user via getUser() outside any
  'use cache' scope; wraps children in SessionProvider; explicit
  'use cache' warning comment.
This commit is contained in:
2026-05-25 17:30:41 +07:00
parent 0a08f80450
commit 129cbb7bf0
6 changed files with 269 additions and 11 deletions
+16
View File
@@ -0,0 +1,16 @@
import type { NextResponse } from "next/server";
/**
* Copies all Set-Cookie entries from `from` onto `to`.
*
* Used when two middleware layers each produce a NextResponse — we must funnel
* both sets of cookies onto the single response that is ultimately returned.
* Specifically: Supabase session-refresh writes sb-* cookies onto a response;
* if next-intl then produces its own redirect/rewrite response, we must port
* the Supabase cookies onto it before returning or the auth token is lost.
*/
export function copyCookies(from: NextResponse, to: NextResponse): void {
for (const cookie of from.cookies.getAll()) {
to.cookies.set(cookie.name, cookie.value, cookie);
}
}