Class: Supabase::Client
- Inherits:
-
Object
- Object
- Supabase::Client
- Defined in:
- lib/supabase/client.rb
Overview
Top-level client that combines every sub-library behind one object, mirroring supabase-py’s ‘supabase.create_client()`.
client = Supabase.create_client(
supabase_url: "https://project.supabase.co",
supabase_key: ENV["SUPABASE_ANON_KEY"]
)
client.auth.sign_in_with_password(email:, password:)
users = client.from("users").select("*").execute
client.storage.from("avatars").upload("a.png", bytes)
client.functions.invoke("hello-world", body: { name: "Ada" })
ch = client.realtime.channel("realtime:public:users")
Sub-clients are built lazily and memoized. Pass ‘async: true` to swap in the async-http-faraday variants for Auth / Postgrest / Storage / Functions; the Realtime client is transport-agnostic and ships sync regardless (a real WS transport is wired in by the caller — see lib/supabase/realtime/socket.rb).
Instance Attribute Summary collapse
-
#headers ⇒ Object
readonly
Returns the value of attribute headers.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#supabase_key ⇒ Object
readonly
Returns the value of attribute supabase_key.
-
#supabase_url ⇒ Object
readonly
Returns the value of attribute supabase_url.
Class Method Summary collapse
-
.create(supabase_url:, supabase_key:, options: nil, async: false) ⇒ Object
Mirrors supabase-py’s ‘Client.create(…)`: builds a client, then — if no explicit Authorization was supplied via options — tries to pull a persisted session via the auth client and applies its access_token as the bearer token.
Instance Method Summary collapse
- #async? ⇒ Boolean
-
#auth ⇒ Object
— Sub-clients ———————————————————.
-
#channel(topic, params: nil) ⇒ Object
Realtime shortcuts on the umbrella — mirror supabase-py so callers can do ‘client.channel(“public:users”)` instead of `client.realtime.channel(…)`.
- #from(table) ⇒ Object (also: #table)
- #functions ⇒ Object
- #get_channels ⇒ Object
-
#initialize(supabase_url:, supabase_key:, options: {}, async: false) ⇒ Client
constructor
A new instance of Client.
-
#postgrest ⇒ Object
PostgREST is the only sub-library where the public API is reached via a bare method on the umbrella (‘client.from(’users’)‘) rather than a named accessor.
- #realtime ⇒ Object
-
#remove_all_channels ⇒ Object
Unsubscribe every realtime channel registered on this client.
-
#remove_channel(channel) ⇒ Object
Unsubscribe a channel and drop it from the realtime registry.
- #rpc(func, params = {}, **opts) ⇒ Object
-
#schema(name) ⇒ Object
Return a Postgrest client scoped to ‘name` without mutating self.
-
#set_auth(token) ⇒ Object
Update the Authorization header used by every sub-client.
- #storage ⇒ Object
Constructor Details
#initialize(supabase_url:, supabase_key:, options: {}, async: false) ⇒ Client
Returns a new instance of Client.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/supabase/client.rb', line 64 def initialize(supabase_url:, supabase_key:, options: {}, async: false) # Use Supabase::SupabaseException once defined; fall back to ArgumentError # during early require cycles. Matches supabase-py's contract. err = defined?(Supabase::SupabaseException) ? Supabase::SupabaseException : ArgumentError raise err, "supabase_url is required" if supabase_url.to_s.empty? raise err, "supabase_key is required" if supabase_key.to_s.empty? raise err, "Invalid URL" unless supabase_url.to_s.match?(%r{^https?://.+}) @supabase_url = supabase_url.to_s.chomp("/") @supabase_key = supabase_key # Plain Hash → ClientOptions: paritet with supabase-py, where every # option flows through a typed dataclass. The legacy nested # `{ auth: {...}, postgrest: {...}, global: { headers: {...} } }` shape # is kept as a raw Hash so existing callers don't break — anything # else is canonicalized into a ClientOptions struct so the per-sub- # client kwargs derivation has one code path. legacy_hash_shape = .is_a?(Hash) && .keys.any? { |k| %i[auth postgrest storage functions realtime global].include?(k.to_sym) } @options = if .is_a?(Hash) && !legacy_hash_shape ClientOptions.new(**.transform_keys(&:to_sym)) elsif .is_a?(Supabase::ClientOptions) # Mirror supabase-py's `self.options = copy.copy(options)` followed by # `self.options.headers = {**options.headers, ...}` — both the struct # and its headers hash become unique to this client, so a downstream # `client.options.headers["X"] = ...` mutation can't leak across # clients constructed from the same `ClientOptions` instance (F-C?). isolated = .dup isolated.headers = isolated.headers.dup isolated else end @async = async configured_headers = if @options.is_a?(Supabase::ClientOptions) @options.headers else @options[:global]&.dig(:headers) || @options.dig("global", "headers") || {} end @headers = { "apikey" => @supabase_key, "Authorization" => "Bearer #{@supabase_key}" }.merge(configured_headers || {}) end |
Instance Attribute Details
#headers ⇒ Object (readonly)
Returns the value of attribute headers.
31 32 33 |
# File 'lib/supabase/client.rb', line 31 def headers @headers end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
31 32 33 |
# File 'lib/supabase/client.rb', line 31 def @options end |
#supabase_key ⇒ Object (readonly)
Returns the value of attribute supabase_key.
31 32 33 |
# File 'lib/supabase/client.rb', line 31 def supabase_key @supabase_key end |
#supabase_url ⇒ Object (readonly)
Returns the value of attribute supabase_url.
31 32 33 |
# File 'lib/supabase/client.rb', line 31 def supabase_url @supabase_url end |
Class Method Details
.create(supabase_url:, supabase_key:, options: nil, async: false) ⇒ Object
Mirrors supabase-py’s ‘Client.create(…)`: builds a client, then — if no explicit Authorization was supplied via options — tries to pull a persisted session via the auth client and applies its access_token as the bearer token. Useful when bootstrapping from a session file the user previously signed into. Any error from get_session is swallowed so the client always returns successfully.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/supabase/client.rb', line 39 def self.create(supabase_url:, supabase_key:, options: nil, async: false) configured_auth = nil if .is_a?(Supabase::ClientOptions) configured_auth = .headers["Authorization"] || .headers[:Authorization] elsif .is_a?(Hash) global_headers = [:global]&.dig(:headers) || .dig("global", "headers") || {} configured_auth = global_headers["Authorization"] || global_headers[:Authorization] end client = new(supabase_url: supabase_url, supabase_key: supabase_key, options: || {}, async: async) if configured_auth.nil? begin session = client.auth.get_session client.set_auth(session.access_token) if session&.access_token rescue StandardError # No persisted session, or auth storage unavailable — fall back to # the apikey-only bearer that initialize set up. end end client end |
Instance Method Details
#async? ⇒ Boolean
114 115 116 |
# File 'lib/supabase/client.rb', line 114 def async? @async end |
#auth ⇒ Object
— Sub-clients ———————————————————
120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/supabase/client.rb', line 120 def auth return @auth if @auth @auth = auth_class.new(url: rest_url_for("auth/v1"), headers: @headers, **(:auth)) # Mirror supabase-py's `self.auth.on_auth_state_change(self._listen_to_auth_events)`: # when the auth client emits SIGNED_IN / TOKEN_REFRESHED / SIGNED_OUT, # propagate the new token to every other sub-client. @auth.on_auth_state_change do |event, session| next unless %w[SIGNED_IN TOKEN_REFRESHED SIGNED_OUT].include?(event) apply_auth(session&.access_token) end @auth end |
#channel(topic, params: nil) ⇒ Object
Realtime shortcuts on the umbrella — mirror supabase-py so callers can do ‘client.channel(“public:users”)` instead of `client.realtime.channel(…)`. The `realtime:` topic prefix is still optional (handled inside the Realtime client).
179 180 181 |
# File 'lib/supabase/client.rb', line 179 def channel(topic, params: nil) realtime.channel(topic, params: params) end |
#from(table) ⇒ Object Also known as: table
161 162 163 |
# File 'lib/supabase/client.rb', line 161 def from(table) postgrest.from(table) end |
#functions ⇒ Object
140 141 142 143 |
# File 'lib/supabase/client.rb', line 140 def functions @functions ||= functions_class.new(base_url: rest_url_for("functions/v1"), headers: @headers, **(:functions)) end |
#get_channels ⇒ Object
183 184 185 |
# File 'lib/supabase/client.rb', line 183 def get_channels realtime.get_channels end |
#postgrest ⇒ Object
PostgREST is the only sub-library where the public API is reached via a bare method on the umbrella (‘client.from(’users’)‘) rather than a named accessor. We expose both for explicitness.
156 157 158 159 |
# File 'lib/supabase/client.rb', line 156 def postgrest @postgrest ||= postgrest_class.new(base_url: rest_url_for("rest/v1"), headers: @headers, **(:postgrest)) end |
#realtime ⇒ Object
145 146 147 148 149 150 151 |
# File 'lib/supabase/client.rb', line 145 def realtime @realtime ||= Realtime::Client.new( url: realtime_url, params: { "apikey" => @supabase_key, "access_token" => @supabase_key }, **(:realtime) ) end |
#remove_all_channels ⇒ Object
Unsubscribe every realtime channel registered on this client. Mirrors supabase-py’s ‘Client.remove_all_channels`; same sync/async contract as #remove_channel.
202 203 204 |
# File 'lib/supabase/client.rb', line 202 def remove_all_channels dispatch_realtime { realtime.remove_all_channels } end |
#remove_channel(channel) ⇒ Object
Unsubscribe a channel and drop it from the realtime registry. Mirrors supabase-py: the sync client blocks until the phx_leave frame is written; the async client (‘async def remove_channel`) lets callers await it. Under `async: true` we get the same shape via #dispatch_realtime — the call returns an `Async::Task` the caller may `.wait` on (US-050), so a slow `Socket#send` never stalls the calling fiber.
194 195 196 |
# File 'lib/supabase/client.rb', line 194 def remove_channel(channel) dispatch_realtime { realtime.remove_channel(channel) } end |
#rpc(func, params = {}, **opts) ⇒ Object
171 172 173 |
# File 'lib/supabase/client.rb', line 171 def rpc(func, params = {}, **opts) postgrest.rpc(func, params, **opts) end |
#schema(name) ⇒ Object
Return a Postgrest client scoped to ‘name` without mutating self. Matches supabase-py: `client.schema(“foo”).from_(“x”)` queries the foo schema but leaves `client.from(…)` (and other call sites) on the default schema.
209 210 211 |
# File 'lib/supabase/client.rb', line 209 def schema(name) postgrest.schema(name) end |
#set_auth(token) ⇒ Object
Update the Authorization header used by every sub-client. Useful after auth.sign_in returns a fresh JWT — the apikey stays the same but the bearer token becomes the user’s access token.
Breaking change vs <=3.1.1: ‘set_auth(nil)` no longer drops the memoized auth sub-client (and with it any persisted session). Call `auth.sign_out` to clear session state.
222 223 224 225 |
# File 'lib/supabase/client.rb', line 222 def set_auth(token) apply_auth(token) self end |
#storage ⇒ Object
135 136 137 138 |
# File 'lib/supabase/client.rb', line 135 def storage @storage ||= storage_class.new(base_url: rest_url_for("storage/v1"), headers: @headers, **(:storage)) end |