feat: add middleware option to withSupabase#88
Draft
mandarini wants to merge 8 commits into
Draft
Conversation
commit: |
mandarini
force-pushed
the
feat/plugins-option
branch
from
July 1, 2026 16:55
0e747ac to
ad449a9
Compare
1 task
mandarini
force-pushed
the
feat/plugins-option
branch
2 times, most recently
from
July 9, 2026 08:14
9e402e1 to
44b05da
Compare
…lution TypeScript doesn't apply excess property checking during overload resolution, so calls with plugins: [...] were silently matching overload 1 and typing ctx as SupabaseContext<unknown>. Adding plugins?: never to overload 1's config makes it definitively fail when plugins is present, falling through to the correct overload. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The array holds middleware entries (per-request behavior from
defineMiddleware) — the word 'plugins' is reserved for the package-level
concept whose client namespace goes in createClient({ plugins }). One
word per concept: server-side composition is 'middleware', client-side
namespaces are 'plugins', a Plugin is the package that ships both.
PluginsCtx -> MiddlewareCtx; overload trick unchanged
(middleware?: never on overload 1).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Graduate withPostgres and withClaims out of plugin-examples into @supabase/server/middleware/*, so the PRFAQ's built-in middleware ship from the package instead of example-local code (SDK-1163 item 5). - withPostgres reads claims from ctx.jwtClaims (already populated by withSupabase), so `middleware: [withPostgres()]` works with no separate withClaims. Keeps the RLS role-clamp and tx-local request.jwt.claims injection. pg is an optional peer dep (Node/Deno only, not Workers). - withClaims ships for the standalone agnostic pipeline() case (demo-only: no signature verification). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Append the caller-role grants hint to permission-denied errors and document the grants requirement in the withPostgres JSDoc. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Port from the @supabase/web-middleware PR-9 preview to
@supabase/middleware at main (0641674), which dropped ctx._runtime:
- withSupabase seeds the middleware chain via seedContext() instead of
faking a { _runtime } facet (the engine now marks contexts with a
symbol, so the structural fake no longer works)
- withPostgres defaults its connection string from the importable
getEnv('SUPABASE_DB_URL') instead of ctx._runtime.getEnv
- tests use vi.stubEnv for the env fallback; withClaims tests call the
handler as a bare fetch entry
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mandarini
force-pushed
the
feat/plugins-option
branch
from
July 21, 2026 11:34
fa1d063 to
ac091c2
Compare
JSR's slow-types check requires explicit types on public API symbols; the inferred defineMiddleware return type failed 'Verify JSR packaging'. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Summary
Adds a
middlewareoption towithSupabaseso that@supabase/middlewareentries can compose around the handler after the Supabase context is established — plus the first two first-party middleware,withPostgresandwithClaims.The middleware receive
ctx.supabase,ctx.jwtClaims, etc. already populated — they run after the Supabase context is created, not before. This is the key difference from wrappingwithSupabaseitself.Architecture
What changed
src/with-supabase.ts— two named overloads (no-middleware / with-middleware) so TypeScript can infer the handler'sctxtype concretely.MiddlewareCtx<Entries>accumulates the entries' key contributions via a recursive conditional type. At runtime, entries are folded right-to-left withreduceRight; the merged context is marked viaseedContext()so engine entries recognise it as upstream (the engine no longer has actx._runtimefacet — env access is the importablegetEnv)src/middleware/postgres(@supabase/server/middleware/postgres) —withPostgres: contributesctx.postgres, an RLS-scopedpgclient. Every query runs in its own transaction that injects the caller's claims (request.jwt.claims) and drops to their role, PostgREST-style — transaction-local, so nothing leaks onto the pooled connection; the role is clamped toauthenticated/anon. Connection string defaults togetEnv('SUPABASE_DB_URL'). Includes a table-grants hint on 42501 errorssrc/middleware/claims(@supabase/server/middleware/claims) —withClaims: contributesctx.jwtClaimsfor standalone pipelines outsidewithSupabase(demo-grade: decodes without signature verification, documented as such)src/with-supabase.test.ts+ middleware tests — composition after Supabase context, short-circuit before handler, array order, CORS with middleware present, claim injection/role clamp/rollback/42501 hint forwithPostgrespackage.json— adds@supabase/middlewareas a dependency (preview build of main:pkg.pr.new/supabase/middleware/@supabase/middleware@0641674) + the two new subpath exportsMiddleware<...>type annotations (JSR slow-types requires explicit public API types)Try it
Notes
withSupabase(config, handler)API is unchanged — overload 1 is identical to the current signatureMiddlewareCtx<Entries>mirrorspipeline's internalAccumulatetype without depending on the internal exportMiddlewareCtxto includeSupabaseContext, so middleware that declareInprerequisites onsupabaseorjwtClaimsget compile-time checking. Left as a follow-upwithSupabaseas composed middleware (withSupabaseClient/withSupabaseAdminClient) lands in this PR before merge — public API unchangedMerge order
Blocked by supabase/web-middleware#9— merged (and the engine repo/package renamed to@supabase/middleware, now including the importable-getEnvruntime API from middleware#12). Remaining before merge: land thewithSupabase-as-middleware internal rewrite (see Notes)pluginsarray oncreateClient— the package-level namespaces; this PR's array is the package's middleware); no code dependency in either direction