Skip to content

feat: compose withSupabase as a pipeline entry - #145

Open
mandarini wants to merge 3 commits into
mainfrom
feat/withsupabase-composite
Open

feat: compose withSupabase as a pipeline entry#145
mandarini wants to merge 3 commits into
mainfrom
feat/withsupabase-composite

Conversation

@mandarini

@mandarini mandarini commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Test it out on the @beta

If you want to test:

npm i @supabase/server@1.6.0-beta.0

withSupabase is now one entry in a pipeline. Placement in the array decides what runs before the auth gate and what runs after it; the withSupabase(config, handler) form is unchanged.

import { pipeline } from '@supabase/middleware'
import { withOAuthProtectedResource, withSupabase } from '@supabase/server'
import { withPostgresClient } from '@supabase/server/middleware/postgres'

export default {
  fetch: pipeline(
    [withOAuthProtectedResource(), withSupabase({ auth: 'user' }), withPostgresClient()],
    async (_req, ctx) => Response.json(await ctx.postgres.query`select id from notes`),
  ),
}

What changed

  • withSupabase is a defineComposite (@supabase/middleware 0.5.0) of single-key parts, outermost first: CORS, construction boundary, auth gate, four projections (userClaims, jwtClaims, authMode, authKeyName), withSupabaseClient, withSupabaseAdminClient. The gate, CORS and boundary keys are internal to the composite; the handler sees exactly SupabaseContext.
  • New overload: withSupabase(config) returns Entry<SupabaseContext<Database>>.
  • Client-construction failures are recognized by a brand set in withSupabaseClient, so a missing URL or key still renders as the 500 JSON error while errors thrown by the handler or by lazy ctx.supabaseAdmin access still propagate.
  • withSupabaseClient / withSupabaseAdminClient declare their entry type in the record form, Entry<{ supabase: SupabaseClient<Database> }>.
  • The request body is buffered at the entry point, so a nested middleware and the handler can each read it.
  • Docs lead with pipeline; the OAuth reference shows the wrap and pipeline forms. The e2e Postgres routes run through the pipeline form on Node and Deno.
  • @supabase/middleware dependency is ^0.5.0. The jsr.json change is formatting only.

Removed

The alpha-labeled middleware: [...] option on withSupabase. It was a post-auth-only slot: middleware that must answer unauthenticated requests could not run there, and the placement compiled silently. Its one documented use, withSupabase({ auth: 'user', middleware: [withPostgresClient()] }, handler), becomes pipeline([withSupabase({ auth: 'user' }), withPostgresClient()], handler), or nesting: withSupabase({ auth: 'user' }, withPostgresClient(handler)).

SDK-1713 acceptance

Request Array form before withSupabase in a pipeline
discovery GET, no credentials 401 200 + metadata document
tool call, no credentials 401, header absent 401 + WWW-Authenticate: Bearer resource_metadata="…"
metadata OPTIONS generic 204 204 + mcp-protocol-version

Tests: serves OAuth discovery ahead of the auth gate, enriches the gate 401 with WWW-Authenticate, lets the OAuth middleware answer the metadata preflight in src/with-supabase.test.ts.

Parity

Every pre-existing withSupabase test that did not spell the removed option is unchanged and passes. New tests pin the exact six context keys, body buffering, the entry form, publishable:<name> key mirroring through the composite, and the type-level soundness of the entry overload. Suite: 446 tests, 32 files; typecheck, lint, build, attw, JSR dry-run and typecheck:e2e clean.

Behavior deltas, none pinned by prior tests: a Workers third fetch argument triggers the engine's one-time "not honored" warning; x-supabase-server-error is exposed cross-origin on any response carrying it; part construction runs once per withSupabase(config, …) call; the handler's Request is a buffering proxy when a body is present (raw req.body streaming bypasses the cache).

Not affected

BYO-MCP surfaces use the wrap form with exact version pins: the ui-library mcp-server block (1.5.1) and edge-function-mcp-sandbox (1.5.0-rc.117).

Links

SDK-1729 · SDK-1713 · supabase/middleware#36

@pkg-pr-new

pkg-pr-new Bot commented Sep 4, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@supabase/server@145

commit: cce6deb

@mandarini mandarini self-assigned this Sep 4, 2026
@mandarini
mandarini marked this pull request as ready for review September 4, 2026 14:57
@mandarini
mandarini requested review from a team as code owners September 4, 2026 14:57
@mandarini
mandarini force-pushed the feat/withsupabase-composite branch from f9db35f to cce6deb Compare September 8, 2026 10:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants