supabase-rb 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/supabase/auth/client.rb +2 -2
- data/lib/supabase/client.rb +4 -2
- data/lib/supabase/functions/types.rb +18 -0
- data/lib/supabase/postgrest/client.rb +3 -0
- data/lib/supabase/realtime/channel.rb +46 -1
- data/lib/supabase/realtime/client.rb +17 -2
- data/lib/supabase/storage/client.rb +2 -0
- data/lib/supabase/storage/file_api.rb +23 -6
- data/lib/supabase/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4c6d9216ec9407182b784f962757533f0dcb4bff3be7c7b04a4b2e3ff708878f
|
|
4
|
+
data.tar.gz: cd2aa70a2e15fdb624d0891d23ea5fdcd018eb258f3585a22e70b5736b6e03d1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 595191ce59fb0c18028b0dc32d4b87fcc3c8a83ba4039cd3bd104c78653935c00ec234c6da85dcda2d173856465270262e2ddce8dc1b3cb8af105259b3727a15
|
|
7
|
+
data.tar.gz: b494cdfd89a8ac25eddc59434545bc705116ff01ea97d06e279c5c88555e35ecea638ab88ac6f3c3381b1ed9f7a3d6276af85e87b4f67f8fe02ce0c20ee89c1d
|
data/lib/supabase/auth/client.rb
CHANGED
|
@@ -1205,7 +1205,7 @@ module Supabase
|
|
|
1205
1205
|
payload = decoded[:payload]
|
|
1206
1206
|
|
|
1207
1207
|
aal = payload["aal"]
|
|
1208
|
-
|
|
1208
|
+
amr_entries = (payload["amr"] || []).map { |entry| Types::AMREntry.from_hash(entry) }.compact
|
|
1209
1209
|
|
|
1210
1210
|
verified_factors = (session.user&.factors || []).select { |f| f.status == "verified" }
|
|
1211
1211
|
next_level = verified_factors.any? ? "aal2" : aal
|
|
@@ -1213,7 +1213,7 @@ module Supabase
|
|
|
1213
1213
|
Types::AuthMFAGetAuthenticatorAssuranceLevelResponse.new(
|
|
1214
1214
|
current_level: aal,
|
|
1215
1215
|
next_level: next_level,
|
|
1216
|
-
current_authentication_methods:
|
|
1216
|
+
current_authentication_methods: amr_entries
|
|
1217
1217
|
)
|
|
1218
1218
|
end
|
|
1219
1219
|
end
|
data/lib/supabase/client.rb
CHANGED
|
@@ -100,9 +100,11 @@ module Supabase
|
|
|
100
100
|
postgrest.rpc(func, params, **opts)
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
+
# Return a Postgrest client scoped to `name` without mutating self. Matches
|
|
104
|
+
# supabase-py: `client.schema("foo").from_("x")` queries the foo schema but
|
|
105
|
+
# leaves `client.from(...)` (and other call sites) on the default schema.
|
|
103
106
|
def schema(name)
|
|
104
|
-
|
|
105
|
-
self
|
|
107
|
+
postgrest.schema(name)
|
|
106
108
|
end
|
|
107
109
|
|
|
108
110
|
# --- Shared auth context -------------------------------------------------
|
|
@@ -31,6 +31,24 @@ module Supabase
|
|
|
31
31
|
CA_CENTRAL_1, EU_CENTRAL_1, EU_WEST_1, EU_WEST_2, EU_WEST_3,
|
|
32
32
|
SA_EAST_1, US_EAST_1, US_WEST_1, US_WEST_2
|
|
33
33
|
].freeze
|
|
34
|
+
|
|
35
|
+
# PascalCase aliases mirroring supabase-py's FunctionRegion StrEnum, so
|
|
36
|
+
# snippets ported from py (`FunctionRegion.UsEast1`) work without edits.
|
|
37
|
+
Any = ANY
|
|
38
|
+
ApNortheast1 = AP_NORTHEAST_1
|
|
39
|
+
ApNortheast2 = AP_NORTHEAST_2
|
|
40
|
+
ApSouth1 = AP_SOUTH_1
|
|
41
|
+
ApSoutheast1 = AP_SOUTHEAST_1
|
|
42
|
+
ApSoutheast2 = AP_SOUTHEAST_2
|
|
43
|
+
CaCentral1 = CA_CENTRAL_1
|
|
44
|
+
EuCentral1 = EU_CENTRAL_1
|
|
45
|
+
EuWest1 = EU_WEST_1
|
|
46
|
+
EuWest2 = EU_WEST_2
|
|
47
|
+
EuWest3 = EU_WEST_3
|
|
48
|
+
SaEast1 = SA_EAST_1
|
|
49
|
+
UsEast1 = US_EAST_1
|
|
50
|
+
UsWest1 = US_WEST_1
|
|
51
|
+
UsWest2 = US_WEST_2
|
|
34
52
|
end
|
|
35
53
|
end
|
|
36
54
|
end
|
|
@@ -64,6 +64,9 @@ module Supabase
|
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
alias table from
|
|
67
|
+
# Compat alias for snippets ported from supabase-py where `from` is a
|
|
68
|
+
# reserved keyword and the method is named `from_`.
|
|
69
|
+
alias from_ from
|
|
67
70
|
|
|
68
71
|
# Stored procedure call.
|
|
69
72
|
# @param func [String] function name
|
|
@@ -138,6 +138,34 @@ module Supabase
|
|
|
138
138
|
self
|
|
139
139
|
end
|
|
140
140
|
|
|
141
|
+
# Convenience wrappers around the underlying `channel.presence` object,
|
|
142
|
+
# matching supabase-py's `channel.on_presence_sync/join/leave` API. If
|
|
143
|
+
# called after the channel is already joined, the channel resubscribes so
|
|
144
|
+
# the server starts forwarding presence events (presence has to be enabled
|
|
145
|
+
# in the join config — see #default_params).
|
|
146
|
+
def on_presence_sync(&block)
|
|
147
|
+
@presence.on_sync(&block)
|
|
148
|
+
resubscribe_for_presence!
|
|
149
|
+
self
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def on_presence_join(&block)
|
|
153
|
+
@presence.on_join(&block)
|
|
154
|
+
resubscribe_for_presence!
|
|
155
|
+
self
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def on_presence_leave(&block)
|
|
159
|
+
@presence.on_leave(&block)
|
|
160
|
+
resubscribe_for_presence!
|
|
161
|
+
self
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Shortcut for `channel.presence.state` so callers don't have to drill in.
|
|
165
|
+
def presence_state
|
|
166
|
+
@presence.state
|
|
167
|
+
end
|
|
168
|
+
|
|
141
169
|
# ----- Outbound -----
|
|
142
170
|
|
|
143
171
|
# Send a custom broadcast message. The server will forward it to other
|
|
@@ -214,7 +242,9 @@ module Supabase
|
|
|
214
242
|
# Mirrors phoenix.js / supabase-py: every registered on_postgres_changes
|
|
215
243
|
# listener is serialized into config.postgres_changes on the join payload
|
|
216
244
|
# so the server filters before sending, instead of shipping every change
|
|
217
|
-
# for the topic and forcing the client to drop most of them.
|
|
245
|
+
# for the topic and forcing the client to drop most of them. Also flips
|
|
246
|
+
# config.presence.enabled when any presence callback is attached, so the
|
|
247
|
+
# server starts emitting presence_state/diff frames.
|
|
218
248
|
def inject_postgres_changes_bindings
|
|
219
249
|
config = (@join_push.payload["config"] ||= {})
|
|
220
250
|
config["postgres_changes"] = @postgres_changes_callbacks.map do |binding|
|
|
@@ -224,6 +254,21 @@ module Supabase
|
|
|
224
254
|
entry["filter"] = binding[:filter] if binding[:filter]
|
|
225
255
|
entry
|
|
226
256
|
end
|
|
257
|
+
|
|
258
|
+
presence_cfg = (config["presence"] ||= {})
|
|
259
|
+
presence_cfg["enabled"] = true if @presence.any_callbacks?
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# If a presence callback is added after the channel is already joined,
|
|
263
|
+
# the server's join config is stale (presence.enabled is still false), so
|
|
264
|
+
# we resubscribe to send a fresh join payload. Matches py's _resubscribe.
|
|
265
|
+
def resubscribe_for_presence!
|
|
266
|
+
return unless joined?
|
|
267
|
+
|
|
268
|
+
unsubscribe
|
|
269
|
+
@joined_once = false
|
|
270
|
+
@join_push.instance_variable_set(:@received_status, nil)
|
|
271
|
+
subscribe(&@subscribe_callback)
|
|
227
272
|
end
|
|
228
273
|
|
|
229
274
|
def send_push(push, register_pending:)
|
|
@@ -88,14 +88,23 @@ module Supabase
|
|
|
88
88
|
self
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
+
# Compat alias mirroring supabase-py's `client.close()`.
|
|
92
|
+
alias close disconnect
|
|
93
|
+
|
|
91
94
|
def connected?
|
|
92
95
|
@socket && @socket.connected?
|
|
93
96
|
end
|
|
94
97
|
|
|
95
98
|
# Get or create a Channel for the given topic. Subsequent calls with the
|
|
96
99
|
# same topic return the same Channel instance, matching phoenix.js semantics.
|
|
100
|
+
#
|
|
101
|
+
# Topic names are auto-prefixed with `"realtime:"` to match supabase-py:
|
|
102
|
+
# `client.channel("public:users")` reaches the same channel as
|
|
103
|
+
# `client.channel("realtime:public:users")`. Pre-prefixed topics are left
|
|
104
|
+
# alone so existing code keeps working.
|
|
97
105
|
def channel(topic, params: nil)
|
|
98
|
-
|
|
106
|
+
full_topic = topic.start_with?("realtime:") ? topic : "realtime:#{topic}"
|
|
107
|
+
@channels[full_topic] ||= Channel.new(full_topic, params: params, socket: self)
|
|
99
108
|
end
|
|
100
109
|
|
|
101
110
|
def get_channels
|
|
@@ -176,6 +185,10 @@ module Supabase
|
|
|
176
185
|
end
|
|
177
186
|
end
|
|
178
187
|
|
|
188
|
+
# NOTE: supabase-py exposes this as `client.send(message)`. In Ruby that
|
|
189
|
+
# name would shadow Object#send and break reflective `obj.send(:method)`
|
|
190
|
+
# calls, so the rb port uses `push` instead.
|
|
191
|
+
|
|
179
192
|
private
|
|
180
193
|
|
|
181
194
|
def attach_socket
|
|
@@ -218,7 +231,9 @@ module Supabase
|
|
|
218
231
|
return if @heartbeat_interval.nil? || @heartbeat_interval <= 0
|
|
219
232
|
return if @heartbeat_thread&.alive?
|
|
220
233
|
|
|
221
|
-
|
|
234
|
+
# Mirror supabase-py: clamp to a 15s floor so an overeager caller can't
|
|
235
|
+
# hammer the server with sub-15s heartbeats.
|
|
236
|
+
interval = [@heartbeat_interval, 15].max
|
|
222
237
|
@heartbeat_thread = Thread.new do
|
|
223
238
|
Thread.current.report_on_exception = false
|
|
224
239
|
loop do
|
|
@@ -53,9 +53,20 @@ module Supabase
|
|
|
53
53
|
|
|
54
54
|
# ----- Download -----
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
# When `transform:` is provided, the request is routed through the image
|
|
57
|
+
# rendering endpoint (`render/image/authenticated`) and the transform opts
|
|
58
|
+
# are passed as query params. Mirrors supabase-py's DownloadOptions /
|
|
59
|
+
# TransformOptions split.
|
|
60
|
+
def download(path, transform: nil)
|
|
61
|
+
render_path = transform ? %w[render image authenticated] : %w[object]
|
|
62
|
+
query = if transform
|
|
63
|
+
transform.transform_keys(&:to_s).transform_values(&:to_s)
|
|
64
|
+
else
|
|
65
|
+
{}
|
|
66
|
+
end
|
|
67
|
+
|
|
57
68
|
parts = Utils.relative_path_to_parts(path)
|
|
58
|
-
response = _request(:get, [
|
|
69
|
+
response = _request(:get, [*render_path, @id, *parts], raw_response: true, query: query)
|
|
59
70
|
response.body
|
|
60
71
|
end
|
|
61
72
|
|
|
@@ -196,7 +207,8 @@ module Supabase
|
|
|
196
207
|
send_multipart(:put, ["object", "upload", "sign", @id, *parts],
|
|
197
208
|
file: file, filename: parts.last, content_type: content_type,
|
|
198
209
|
cache_control: cache_control, upsert: nil, metadata: metadata,
|
|
199
|
-
extra_headers: headers, query: { "token" => token }
|
|
210
|
+
extra_headers: headers, query: { "token" => token },
|
|
211
|
+
relative_path: parts.join("/"))
|
|
200
212
|
end
|
|
201
213
|
|
|
202
214
|
private
|
|
@@ -207,10 +219,11 @@ module Supabase
|
|
|
207
219
|
file: file, filename: parts.last,
|
|
208
220
|
content_type: content_type, cache_control: cache_control,
|
|
209
221
|
upsert: omit_upsert ? nil : upsert,
|
|
210
|
-
metadata: metadata, extra_headers: headers
|
|
222
|
+
metadata: metadata, extra_headers: headers,
|
|
223
|
+
relative_path: parts.join("/"))
|
|
211
224
|
end
|
|
212
225
|
|
|
213
|
-
def send_multipart(method, segments, file:, filename:, content_type:, cache_control:, upsert:, metadata:, extra_headers:, query: nil)
|
|
226
|
+
def send_multipart(method, segments, file:, filename:, content_type:, cache_control:, upsert:, metadata:, extra_headers:, query: nil, relative_path: nil)
|
|
214
227
|
request_headers = {}
|
|
215
228
|
request_headers["cache-control"] = "max-age=#{cache_control}" if cache_control
|
|
216
229
|
request_headers["x-upsert"] = upsert.to_s unless upsert.nil?
|
|
@@ -240,7 +253,11 @@ module Supabase
|
|
|
240
253
|
response = @session.run_request(method, url, form, merged_headers)
|
|
241
254
|
raise_for_status(response)
|
|
242
255
|
parsed = parse_json(response.body) || {}
|
|
243
|
-
|
|
256
|
+
# Caller passes the user-facing relative path explicitly: index slicing
|
|
257
|
+
# off `segments` would yield "sign/<bucket>/<path>" for upload_to_signed_url
|
|
258
|
+
# (segments: ["object","upload","sign",@id,*parts]) instead of just <path>.
|
|
259
|
+
upload_path = relative_path || segments[2..].join("/")
|
|
260
|
+
Types::UploadResponse.from_hash(path: upload_path, key: parsed["Key"])
|
|
244
261
|
end
|
|
245
262
|
|
|
246
263
|
def build_upload_io(file, filename, content_type)
|
data/lib/supabase/version.rb
CHANGED