Skip to content

feat: add Express 5 adapter#66

Open
bogdantarasenko wants to merge 1 commit into
supabase:mainfrom
bogdantarasenko:feat/express-adapter
Open

feat: add Express 5 adapter#66
bogdantarasenko wants to merge 1 commit into
supabase:mainfrom
bogdantarasenko:feat/express-adapter

Conversation

@bogdantarasenko
Copy link
Copy Markdown

@bogdantarasenko bogdantarasenko commented May 15, 2026

Summary

Adds a community Express 5 adapter under @supabase/server/adapters/express, alongside the existing Hono, H3, and Elysia adapters.

  • withSupabase(config) returns a standard Express middleware. Resolved context lives on res.locals.supabaseContext via Express.Locals declaration merging, so downstream handlers and middleware get full type inference.
  • requireAuth(...modes) is a per-route guard that asserts the context is set and (optionally) that authMode matches one of the listed modes. Useful when one app mixes routes with different auth requirements.
  • withSupabaseRoute(config, handler) is a per-route wrapper for cases where global middleware doesn't fit — same context shape, async errors are forwarded to next().
  • Auth errors flow through a configurable onError option. Default is next(error) (Express-idiomatic); pass a function to send a custom response instead.
  • The Express req → Fetch Request bridge preserves headers (incl. multi-value Set-Cookie / Cookie), composes absolute URLs under app.set('trust proxy', true), and forwards bodies for non-GET/HEAD methods.

express is added as an optional peer dep (^5.0.0), so users who don't import the adapter aren't forced to install Express. No new runtime dependencies.

What's in the diff

  • src/adapters/express/{middleware,require-auth,with-supabase-route,to-fetch-request,index}.ts — adapter source
  • src/adapters/express/*.test.ts — unit tests covering every AuthMode (user / publishable / secret / none), the array form, invalid-JWT / missing-credential failures, the res.locals.supabaseContext short-circuit path, default and custom onError, the requireAuth() guard (present / missing context / mode mismatch), the withSupabaseRoute() wrapper (success, auth failure, async-thrown errors), and the reqRequest bridge (headers, body, trust-proxy URL composition)
  • tsdown.config.ts, package.json exports + peerDependencies + peerDependenciesMeta + devDependencies, jsr.json — wire the new entry point
  • README.md, src/adapters/README.md, new docs/adapters/express.md — documentation

Test plan

  • pnpm install resolves the new peer/dev dependencies
  • pnpm typecheck
  • pnpm lint
  • pnpm test — 190/190 pass, including all Express adapter test files
  • pnpm build produces dist/adapters/express/index.{mjs,cjs,d.mts,d.cts}
  • Reviewer: confirm the optional-peer-dep approach (peerDependenciesMeta) is consistent with the other adapters
  • Reviewer: smoke-test on an Express 5 app with app.set('trust proxy', true) behind a reverse proxy to confirm the bridged URL uses X-Forwarded-*

@bogdantarasenko bogdantarasenko requested review from a team as code owners May 15, 2026 15:25
@kallebysantos
Copy link
Copy Markdown
Member

Please remove this .chief/ folder, I believe it was accidentally added

@bogdantarasenko bogdantarasenko requested a review from a team as a code owner May 20, 2026 11:26
Adds @supabase/server/adapters/express targeting Express 5, mirroring the
Hono/H3 adapter contract. Public surface: withSupabase() middleware,
requireAuth() guard, withSupabaseRoute() per-route wrapper, and the
WithSupabaseExpressConfig type. Resolved context lives on
res.locals.supabaseContext via Express.Locals declaration merging.

Auth errors flow through a configurable onError option (default:
next(error), Express-idiomatic). The Express req to Fetch Request bridge
preserves headers including multi-value Set-Cookie and Cookie, composes
absolute URLs under trust proxy, and forwards bodies for non-GET/HEAD
methods. No new runtime deps; express ^5.0.0 is an optional peer.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants