feat(supabase): add plugins option to createClient#2485
Open
mandarini wants to merge 1 commit into
Open
Conversation
Adds a plugins option to createClient plus a co-located defineSupabasePlugin helper. Each plugin contributes one typed namespace at supabase.<name>, inferred from the plugins array via a recursive PluginNamespaces type — mirroring the PluginsCtx pattern from supabase/server#88 and the Entry pattern from supabase/web-middleware#9. - overload 1 keeps today's exact createClient signature (plugins?: never forces correct overload resolution); overload 2 infers the plugins tuple and returns SupabaseClient & PluginNamespaces<Plugins> - namespaces attach at the end of the SupabaseClient constructor so plugin factories receive a fully initialized client; collisions with existing client members or duplicate plugin names throw - scope: name + client namespace only; the events bus from the RFC is a follow-up (SDK-1163) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@supabase/auth-js
@supabase/functions-js
@supabase/postgrest-js
@supabase/realtime-js
@supabase/storage-js
@supabase/supabase-js
commit: |
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.
🔍 Description
Adds a
pluginsoption tocreateClientplus a co-locateddefineSupabasePluginhelper — the SDK leg of the Supabase Plugins initiative. Each plugin contributes one typed namespace on the client, inferred from thepluginsarray with no manual annotations:Pattern siblings (same overload + type-accumulation approach, so the whole family reads the same):
pipeline()+Entry(server middleware composition)middlewareoption onwithSupabase(MiddlewareCtxaccumulation; the server-side array holds a plugin's middleware, this PR's array holds its client namespaces)What changed?
src/lib/plugins.ts(new) —SupabasePlugin<Name, Namespace>, recursivePluginNamespaces<Plugins>,defineSupabasePlugin()(identity fn that captures the literal name + namespace type), andattachPlugins()src/index.ts—createClientbecomes an overloaded function: overload 1 is byte-for-byte today's signature plusplugins?: never(forces correct overload resolution — TS skips excess-property checks during overload resolution); overload 2 infersconst Pluginsfromoptions.pluginsand returnsSupabaseClient<...> & PluginNamespaces<Plugins>. The class's five generics are untouchedsrc/SupabaseClient.ts— plugins attach as the last constructor statement, so factories receive a fully initialized client (client.functions,client.from, earlier plugins' namespaces all usable). Read fromoptions, notsettings(same asoptions?.storage)src/lib/types.ts—plugins?: readonly AnySupabasePlugin[]onSupabaseClientOptions, sonew SupabaseClient()users and@supabase/ssrwrappers get runtime behavior for freefrom,auth,functions,storage, ...) or a duplicate plugin name throws at constructiontest/unit/plugins.test.ts(9 tests) + tsd cases intest/types/index.test-d.tsWhy was this change needed?
SDK leg of the Supabase Plugins RFC (Linear: SDK, project Supabase Plugins – Better Auth paradigm). The RFC decided
defineSupabasePluginis co-located in supabase-js — thepluginsruntime hook has to live here anyway, since only the client can mount the namespace.🔄 Breaking changes
Additive only (
feat→ minor). Overload 1 preserves the existingcreateClientsignature exactly; all existing tsd assertions pass unchanged.📝 Additional notes
Deliberate scope cuts (tracked in Linear SDK-1163):
eventsbus (auth.userCreated, …) — follow-up per the RFC phasingType caveats, stated honestly:
createClient<Database>(url, key, { plugins })compiles and works at runtime, but plugin namespaces fall back to untyped (TS has no partial inference — Proposal: Partial Type Argument Inference microsoft/TypeScript#26242; server#88 has the identical latent behavior). Escape hatch documented in JSDoc:const plugins = [...] as const+ passtypeof pluginsas the 4th type arg. AwithPlugins(client, plugins)compositional helper is a possible clean follow-upconsttype-parameter modifier in the emitted d.ts raises minimum consumer TypeScript to 5.0. If that's a concern, a union-based mapped type can replace the recursive tuple — happy to switchsupabase_js_v2.yml) is a separate-repo follow-upVerification:
build,test:unit(123 passed),test:types(tsd + jsr dry-run),test:exports(attw) all green. The pkg.pr.new preview from this PR will be consumed by plugin-examples to replace its hand-rolledwithGuestbookPluginclient wiring — that's the end-to-end validation on a real local stack.🤖 Generated with Claude Code
Merge order
middlewareon the server,pluginshere), not dependencies; the three are exercised together in plugin-examples.