feat: compose withSupabase as a pipeline entry - #145
Open
mandarini wants to merge 3 commits into
Open
Conversation
commit: |
mandarini
force-pushed
the
feat/withsupabase-composite
branch
from
September 8, 2026 10:05
f9db35f to
cce6deb
Compare
johnstonmatt
approved these changes
Sep 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Test it out on the
@betaIf you want to test:
withSupabaseis now one entry in apipeline. Placement in the array decides what runs before the auth gate and what runs after it; thewithSupabase(config, handler)form is unchanged.What changed
withSupabaseis adefineComposite(@supabase/middleware0.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 exactlySupabaseContext.withSupabase(config)returnsEntry<SupabaseContext<Database>>.withSupabaseClient, so a missing URL or key still renders as the 500 JSON error while errors thrown by the handler or by lazyctx.supabaseAdminaccess still propagate.withSupabaseClient/withSupabaseAdminClientdeclare their entry type in the record form,Entry<{ supabase: SupabaseClient<Database> }>.pipeline; the OAuth reference shows the wrap and pipeline forms. The e2e Postgres routes run through the pipeline form on Node and Deno.@supabase/middlewaredependency is^0.5.0. Thejsr.jsonchange is formatting only.Removed
The alpha-labeled
middleware: [...]option onwithSupabase. 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), becomespipeline([withSupabase({ auth: 'user' }), withPostgresClient()], handler), or nesting:withSupabase({ auth: 'user' }, withPostgresClient(handler)).SDK-1713 acceptance
withSupabasein a pipelineGET, no credentials401200+ metadata document401, header absent401+WWW-Authenticate: Bearer resource_metadata="…"OPTIONS204204+mcp-protocol-versionTests:
serves OAuth discovery ahead of the auth gate,enriches the gate 401 with WWW-Authenticate,lets the OAuth middleware answer the metadata preflightinsrc/with-supabase.test.ts.Parity
Every pre-existing
withSupabasetest 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 andtypecheck:e2eclean.Behavior deltas, none pinned by prior tests: a Workers third
fetchargument triggers the engine's one-time "not honored" warning;x-supabase-server-erroris exposed cross-origin on any response carrying it; part construction runs once perwithSupabase(config, …)call; the handler'sRequestis a buffering proxy when a body is present (rawreq.bodystreaming bypasses the cache).Not affected
BYO-MCP surfaces use the wrap form with exact version pins: the ui-library
mcp-serverblock (1.5.1) andedge-function-mcp-sandbox(1.5.0-rc.117).Links
SDK-1729 · SDK-1713 · supabase/middleware#36