volcano-sdk 0.31.0 → 0.32.1

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -7
  3. data/lib/volcano/database.rb +28 -37
  4. data/lib/volcano/durable.rb +6 -6
  5. data/lib/volcano/durable_models.rb +65 -22
  6. data/lib/volcano/function_auth.rb +9 -2
  7. data/lib/volcano/functions.rb +18 -15
  8. data/lib/volcano/immutable_request_value.rb +21 -0
  9. data/lib/volcano/logs.rb +14 -9
  10. data/lib/volcano/models.rb +55 -22
  11. data/lib/volcano/realtime/broadcast_delivery.rb +26 -2
  12. data/lib/volcano/realtime/channel_callbacks.rb +23 -15
  13. data/lib/volcano/realtime/channel_lifecycle.rb +9 -9
  14. data/lib/volcano/realtime/connection.rb +9 -5
  15. data/lib/volcano/realtime/connection_callbacks.rb +5 -1
  16. data/lib/volcano/realtime/lifecycle.rb +2 -1
  17. data/lib/volcano/realtime/postgres_batch.rb +11 -3
  18. data/lib/volcano/realtime/postgres_changes.rb +33 -16
  19. data/lib/volcano/realtime/postgres_database.rb +14 -1
  20. data/lib/volcano/realtime/postgres_delivery.rb +6 -1
  21. data/lib/volcano/realtime/postgres_expansion.rb +10 -4
  22. data/lib/volcano/realtime/presence.rb +18 -4
  23. data/lib/volcano/realtime/presence_state.rb +23 -6
  24. data/lib/volcano/realtime/protocol.rb +14 -9
  25. data/lib/volcano/realtime/protocol_dispatch.rb +25 -7
  26. data/lib/volcano/realtime/protocol_io.rb +8 -4
  27. data/lib/volcano/realtime/protocol_lifecycle.rb +2 -0
  28. data/lib/volcano/realtime/protocol_publication_dispatch.rb +12 -10
  29. data/lib/volcano/realtime/protocol_recovery.rb +7 -3
  30. data/lib/volcano/realtime/protocol_recovery_dispatch.rb +2 -0
  31. data/lib/volcano/realtime/reconnect.rb +4 -1
  32. data/lib/volcano/realtime.rb +122 -99
  33. data/lib/volcano/session.rb +14 -3
  34. data/lib/volcano/transport.rb +53 -11
  35. data/lib/volcano/user.rb +12 -7
  36. data/lib/volcano/version.rb +1 -1
  37. data/lib/volcano.rb +1 -0
  38. data/sig/auth_session_records.rbs +1 -1
  39. data/sig/client.rbs +15 -0
  40. data/sig/core_facades.rbs +81 -0
  41. data/sig/durable_records.rbs +1 -1
  42. data/sig/locks.rbs +10 -0
  43. data/sig/realtime.rbs +45 -0
  44. data/sig/realtime_postgres_change.rbs +1 -2
  45. data/sig/user.rbs +1 -1
  46. metadata +6 -1
@@ -32,134 +32,148 @@ module Volcano
32
32
 
33
33
  # Recursively snapshots JSON-compatible values for callback and state safety.
34
34
  module Immutable
35
- module_function
36
-
37
- def optional(value)
38
- value && call(value)
35
+ def self.optional(value)
36
+ value && snapshot(value)
39
37
  end
40
38
 
41
- def call(value)
39
+ def self.call(value) = snapshot(value)
40
+
41
+ def self.snapshot(value)
42
42
  case value
43
43
  when Hash then call_hash(value)
44
- when Array then value.map { |child| call(child) }.freeze
44
+ when Array then value.map { |child| snapshot(child) }.freeze
45
45
  when String then value.dup.freeze
46
46
  else value.freeze
47
47
  end
48
48
  end
49
49
 
50
- def call_hash(value)
51
- value.to_h { |key, item| [call(key), call(item)] }.freeze
50
+ def self.call_hash(value)
51
+ value.to_h { |key, item| [snapshot(key), snapshot(item)] }.freeze
52
52
  end
53
53
  end
54
54
  private_constant :Immutable
55
55
 
56
- PresenceInfo = Data.define(:client, :user, :data) do
56
+ PresenceInfo = Data.define(:client, :user, :data)
57
+
58
+ # An immutable snapshot of one presence client.
59
+ class PresenceInfo
60
+ # @dynamic client, user, data, members, with, to_h, deconstruct, deconstruct_keys
61
+ # @dynamic self.[], self.members
57
62
  def initialize(client:, user: nil, data: {})
58
- super(
59
- client: Immutable.call(client.to_s),
60
- user: user.nil? ? nil : Immutable.call(user.to_s),
61
- data: Immutable.call(data)
62
- )
63
+ client = Immutable.call(client.to_s)
64
+ user = user.nil? ? nil : Immutable.call(user.to_s)
65
+ data = Immutable.call(data)
66
+ super
63
67
  end
64
68
  end
65
69
 
66
70
  CHANNEL_TYPES = %i[broadcast presence postgres].freeze
67
71
 
68
- def initialize(client, api_url:, socket_factory: nil, reconnect_delay: nil)
69
- @client = client
70
- @api_url = api_url
71
- @socket_factory = socket_factory || method(:open_socket)
72
- @reconnect_delay = reconnect_delay || method(:default_reconnect_delay)
73
- initialize_realtime_state
74
- initialize_postgres_database
75
- end
72
+ # Owns the public realtime facade and its channel collection.
73
+ module Core
74
+ # @dynamic initialize_postgres_database, connect_protocol, close_protocol, public_error
75
+ # @dynamic protocol_error, open_socket, default_reconnect_delay, __send__
76
+ def initialize(client, api_url:, socket_factory: nil, reconnect_delay: nil)
77
+ @client = client
78
+ @api_url = api_url
79
+ @socket_factory = socket_factory || ->(address) { open_socket(address) }
80
+ @reconnect_delay = reconnect_delay || ->(attempt) { default_reconnect_delay(attempt) }
81
+ initialize_realtime_state
82
+ initialize_postgres_database
83
+ end
76
84
 
77
- def initialize_realtime_state
78
- @protocol = nil
79
- @protocol_lock = nil
80
- @channel_lock = nil
81
- @channels = {}
82
- @connection_callbacks = { connect: {}, disconnect: {}, error: {} }
83
- @next_connection_callback_id = 0
84
- @protocol_session_lineage = nil
85
- @reconnect_task = nil
86
- @closed = false
87
- end
88
- private :initialize_realtime_state
89
-
90
- def channel(
91
- name, type: :broadcast, auto_fetch: true,
92
- fetch_batch_window_ms: 20, fetch_max_batch_size: 50
93
- )
94
- type = normalize_channel_type(type)
95
- batch_config = PostgresBatchConfig.new(
96
- auto_fetch:, batch_window_ms: fetch_batch_window_ms,
97
- max_batch_size: fetch_max_batch_size
85
+ def initialize_realtime_state
86
+ @protocol = nil
87
+ @protocol_lock = nil
88
+ @channel_lock = nil
89
+ @channels = {}
90
+ @connection_callbacks = { connect: {}, disconnect: {}, error: {} }
91
+ @next_connection_callback_id = 0
92
+ @protocol_session_lineage = nil
93
+ @reconnect_task = nil
94
+ @closed = false
95
+ end
96
+ private :initialize_realtime_state
97
+
98
+ def channel(
99
+ name, type: :broadcast, auto_fetch: true,
100
+ fetch_batch_window_ms: 20, fetch_max_batch_size: 50
98
101
  )
99
- channel_lock.acquire do
100
- ensure_open!
101
- channel_name = "#{type}:#{name}"
102
- channel = @channels[channel_name]
103
- next cached_channel(channel, batch_config) if channel
102
+ type = normalize_channel_type(type)
103
+ batch_config = PostgresBatchConfig.new(
104
+ auto_fetch:, batch_window_ms: fetch_batch_window_ms,
105
+ max_batch_size: fetch_max_batch_size
106
+ )
107
+ channel_lock.acquire do
108
+ ensure_open!
109
+ channel_name = "#{type}:#{name}"
110
+ channel = @channels[channel_name]
111
+ next cached_channel(channel, batch_config) if channel
104
112
 
105
- @channels[channel_name] = build_channel(channel_name, type, batch_config)
113
+ @channels[channel_name] = build_channel(channel_name, type, batch_config)
114
+ end
106
115
  end
107
- end
108
-
109
- def protocol
110
- ensure_open!
111
- return @protocol if @protocol
112
116
 
113
- protocol_lock.acquire do
117
+ def protocol
114
118
  ensure_open!
115
- @protocol ||= connect_protocol
119
+ current_protocol = @protocol
120
+ return current_protocol if current_protocol
121
+
122
+ protocol_lock.acquire do
123
+ ensure_open!
124
+ @protocol ||= connect_protocol
125
+ end
126
+ rescue StandardError => e
127
+ raise public_error(e), cause: nil
116
128
  end
117
- rescue StandardError => e
118
- raise public_error(e), cause: nil
119
- end
120
- private :protocol
129
+ private :protocol
121
130
 
122
- def disconnect
123
- @protocol_lock ? @protocol_lock.acquire { close_protocol } : close_protocol
124
- rescue StandardError => e
125
- raise public_error(e), cause: nil
126
- end
131
+ def disconnect
132
+ lock = @protocol_lock
133
+ lock ? lock.acquire { close_protocol } : close_protocol
134
+ rescue StandardError => e
135
+ raise public_error(e), cause: nil
136
+ end
127
137
 
128
- def ensure_open!
129
- raise ClosedError, 'realtime connection closed' if @closed
138
+ def ensure_open!
139
+ raise ClosedError, 'realtime connection closed' if @closed
130
140
 
131
- self
132
- end
141
+ self
142
+ end
133
143
 
134
- private
144
+ private
135
145
 
136
- def normalize_channel_type(type)
137
- normalized = type.to_s.to_sym
138
- return normalized if CHANNEL_TYPES.include?(normalized)
146
+ def normalize_channel_type(type)
147
+ normalized = type.to_s.to_sym
148
+ return normalized if CHANNEL_TYPES.include?(normalized)
139
149
 
140
- raise ArgumentError, "unsupported realtime channel type: #{type}"
141
- end
150
+ raise ArgumentError, "unsupported realtime channel type: #{type}"
151
+ end
142
152
 
143
- def report_channel_error(error) = protocol_error(public_error(error))
153
+ def report_channel_error(error) = protocol_error(public_error(error))
144
154
 
145
- def cached_channel(channel, batch_config)
146
- channel.__send__(:ensure_fetch_config!, batch_config)
147
- channel
148
- end
155
+ def cached_channel(channel, batch_config)
156
+ channel.__send__(:ensure_fetch_config!, batch_config)
157
+ channel
158
+ end
149
159
 
150
- def build_channel(name, type, batch_config)
151
- Channel.new(self, method(:protocol), name, type, batch_config:)
152
- end
160
+ def build_channel(name, type, batch_config)
161
+ Channel.new(self, -> { protocol }, name, type, batch_config:)
162
+ end
153
163
 
154
- def protocol_lock
155
- require 'async/semaphore'
156
- @protocol_lock ||= Async::Semaphore.new(1)
157
- end
164
+ def protocol_lock
165
+ require 'async/semaphore'
166
+ @protocol_lock ||= Async::Semaphore.new(1)
167
+ end
158
168
 
159
- def channel_lock
160
- require 'async/semaphore'
161
- @channel_lock ||= Async::Semaphore.new(1)
169
+ def channel_lock
170
+ require 'async/semaphore'
171
+ @channel_lock ||= Async::Semaphore.new(1)
172
+ end
162
173
  end
174
+ include Core
175
+
176
+ private_constant :Core
163
177
 
164
178
  # Represents one realtime broadcast channel.
165
179
  class Channel
@@ -175,14 +189,15 @@ module Volcano
175
189
 
176
190
  attr_reader :name
177
191
 
192
+ # @dynamic name
193
+
178
194
  def initialize(realtime, protocol_provider, name, type, batch_config:)
179
195
  @realtime = realtime
180
196
  @protocol_provider = protocol_provider
181
197
  @name = name.freeze
182
198
  @handler_registered = @subscribed = @subscription_desired = @closed = false
183
199
  @lifecycle_lock = nil
184
- @recovery_position = {}.freeze
185
- @recovery_lineage = nil
200
+ initialize_recovery_state
186
201
  initialize_callback_dispatch
187
202
  initialize_presence(type)
188
203
  initialize_postgres_delivery(batch_config)
@@ -208,7 +223,7 @@ module Volcano
208
223
 
209
224
  def unsubscribe
210
225
  state = with_lifecycle_lock { unsubscribe_protocol }
211
- emit_presence_sync(state)
226
+ emit_presence_sync(state) if state.is_a?(Hash)
212
227
  nil
213
228
  end
214
229
 
@@ -218,11 +233,12 @@ module Volcano
218
233
 
219
234
  def restore_subscription(protocol)
220
235
  state = with_lifecycle_lock do
221
- next unless restoration_needed?
222
-
223
- subscribe_protocol(protocol)
236
+ restoration_needed? ? subscribe_protocol(protocol) : nil
237
+ end
238
+ if state
239
+ subscribed_protocol, epoch = state
240
+ sync_presence(subscribed_protocol, epoch)
224
241
  end
225
- sync_presence(*state) if state
226
242
  nil
227
243
  end
228
244
 
@@ -240,6 +256,13 @@ module Volcano
240
256
 
241
257
  private
242
258
 
259
+ def initialize_recovery_state
260
+ # @type var recovery_position: Hash[Symbol, String | Integer]
261
+ recovery_position = {}
262
+ @recovery_position = recovery_position.freeze
263
+ @recovery_lineage = nil
264
+ end
265
+
243
266
  def subscribe_with_intent
244
267
  ensure_open!
245
268
  raise DuplicateSubscriptionError, "already subscribed to #{@name}" if @subscription_desired
@@ -254,8 +277,8 @@ module Volcano
254
277
 
255
278
  def with_lifecycle_lock(&)
256
279
  require 'async/semaphore'
257
- @lifecycle_lock ||= Async::Semaphore.new(1)
258
- @lifecycle_lock.acquire(&)
280
+ lock = @lifecycle_lock ||= Async::Semaphore.new(1)
281
+ lock.acquire(&)
259
282
  end
260
283
 
261
284
  def ensure_open!
@@ -10,15 +10,26 @@ module Volcano
10
10
  private_constant :SESSION_USER_CODER
11
11
 
12
12
  # Local credentials; refresh credentials and user identity may be unknown.
13
- Session = Data.define(:access_token, :refresh_token, :user_id, :user) do
13
+ Session = Data.define(:access_token, :refresh_token, :user_id, :user)
14
+
15
+ # Reopens the generated record for checked initialization.
16
+ class Session
17
+ # @dynamic access_token, refresh_token, user_id, user, members, with, to_h
18
+ # @dynamic deconstruct, deconstruct_keys, self.[], self.members
14
19
  def initialize(access_token:, refresh_token: nil, user_id: nil, user: nil)
15
- super(access_token:, refresh_token:, user_id:, user: immutable_user(user))
20
+ user = immutable_user(user)
21
+ super
16
22
  end
17
23
 
18
24
  private
19
25
 
20
26
  def immutable_user(value)
21
- SESSION_USER_CODER.load(SESSION_USER_CODER.dump(value))
27
+ return if value.nil?
28
+
29
+ snapshot = SESSION_USER_CODER.load(SESSION_USER_CODER.dump(value))
30
+ raise TypeError, 'Session user snapshot must be a Hash' unless snapshot.is_a?(Hash)
31
+
32
+ snapshot
22
33
  rescue JSON::GeneratorError, JSON::NestingError
23
34
  raise TypeError, 'Session user snapshot must contain JSON values or timestamps', cause: nil
24
35
  end
@@ -20,21 +20,20 @@ module Volcano
20
20
 
21
21
  NETWORK_ERRORS = [IOError, SystemCallError, SocketError, Timeout::Error].freeze
22
22
 
23
- module_function
24
-
25
- def invoke
23
+ def self.invoke
26
24
  yield
27
- rescue *NETWORK_ERRORS => e
25
+ rescue IOError, SystemCallError, SocketError, Timeout::Error => e
28
26
  raise Error::TransportError, e.message, cause: e
29
27
  end
30
28
 
31
- def body(response, expected_status)
29
+ def self.body(response, expected_status)
32
30
  return response.body if response.status == expected_status
33
31
 
34
32
  raise response_error(response)
35
33
  end
36
34
 
37
- def response_error(response)
35
+ def self.response_error(response)
36
+ # @type var payload: Hash[String, Object?]
38
37
  payload = response.body.is_a?(Hash) ? response.body : {}
39
38
  retry_after = integer_header(response.headers, 'Retry-After') if response.status == 429
40
39
  error_type(response.status).new(
@@ -45,20 +44,63 @@ module Volcano
45
44
  )
46
45
  end
47
46
 
48
- def error_message(payload)
49
- payload['error'] || payload['message'] || 'Volcano request failed'
47
+ def self.error_message(payload)
48
+ error = payload['error']
49
+ return error if error.is_a?(String)
50
+
51
+ message = payload['message']
52
+ message.is_a?(String) ? message : 'Volcano request failed'
53
+ end
54
+
55
+ def self.json_value(value)
56
+ case value
57
+ when Array then value.map { |entry| json_value(entry) }
58
+ when Hash then json_object(value)
59
+ else json_scalar(value)
60
+ end
61
+ end
62
+
63
+ def self.json_object(value, message: 'Expected a JSON object')
64
+ raise TypeError, message unless value.is_a?(Hash)
65
+
66
+ value.to_h do |key, item|
67
+ raise TypeError, message unless key.is_a?(String)
68
+
69
+ [key, json_value(item)]
70
+ end
71
+ end
72
+
73
+ def self.json_rows(value)
74
+ rows = json_object(value)['data']
75
+ raise TypeError, 'Expected database rows' unless rows.is_a?(Array)
76
+
77
+ rows.map { |row| json_object(row) }
78
+ end
79
+
80
+ def self.finite_float(value)
81
+ raise TypeError, 'Expected a finite JSON number' unless value.finite?
82
+
83
+ value
84
+ end
85
+
86
+ def self.json_scalar(value)
87
+ case value
88
+ when NilClass, TrueClass, FalseClass, Integer, String then value
89
+ when Float then finite_float(value)
90
+ else raise TypeError, 'Expected a JSON response'
91
+ end
50
92
  end
51
93
 
52
- def error_type(status)
94
+ def self.error_type(status)
53
95
  ERROR_TYPES.fetch(status) do
54
96
  status.between?(500, 599) ? Error::ServerError : Error::VolcanoError
55
97
  end
56
98
  end
57
99
 
58
- def integer_header(headers, name)
100
+ def self.integer_header(headers, name)
59
101
  value = headers&.find { |key, _| key.casecmp?(name) }&.last
60
102
  Integer(value, exception: false)
61
103
  end
62
- private_class_method :error_type, :integer_header, :response_error
104
+ private_class_method :error_type, :integer_header, :response_error, :finite_float, :json_scalar
63
105
  end
64
106
  end
data/lib/volcano/user.rb CHANGED
@@ -10,15 +10,20 @@ module Volcano
10
10
  User = Data.define(
11
11
  :id, :project_id, :email, :email_confirmed, :user_metadata, :app_metadata,
12
12
  :avatar_url, :status, :banned_until, :last_sign_in_at, :created_at, :updated_at
13
- ) do
13
+ )
14
+
15
+ # Reopens the generated record for checked initialization.
16
+ class User
17
+ # @dynamic id, project_id, email, email_confirmed, user_metadata, app_metadata
18
+ # @dynamic avatar_url, status, banned_until, last_sign_in_at, created_at, updated_at
19
+ # @dynamic members, with, to_h, deconstruct, deconstruct_keys, self.[], self.members
14
20
  def initialize(id:, email:, status:, **attributes)
15
21
  validate_optional_attributes(attributes)
16
- super(
17
- id: freeze_value(id),
18
- email: freeze_value(email),
19
- status: freeze_value(status),
20
- **USER_OPTIONAL_ATTRIBUTES.to_h { |name| [name, freeze_value(attributes[name])] }
21
- )
22
+ id = freeze_value(id)
23
+ email = freeze_value(email)
24
+ status = freeze_value(status)
25
+ attributes = USER_OPTIONAL_ATTRIBUTES.to_h { |name| [name, freeze_value(attributes[name])] }
26
+ super
22
27
  end
23
28
 
24
29
  private
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Volcano
4
- VERSION = '0.31.0'
4
+ VERSION = '0.32.1'
5
5
  end
data/lib/volcano.rb CHANGED
@@ -16,6 +16,7 @@ require_relative 'volcano/auth_state'
16
16
  require_relative 'volcano/errors'
17
17
  require_relative 'volcano/redaction'
18
18
  require_relative 'volcano/transport'
19
+ require_relative 'volcano/immutable_request_value'
19
20
  require_relative 'volcano/generated_transport'
20
21
  require_relative 'volcano/auth_notification_dispatch'
21
22
  require_relative 'volcano/auth_session_binding'
@@ -20,7 +20,7 @@ module Volcano
20
20
  | (id: String, user_id: String, provider: String, expires_at: Time, is_active: bool, is_current: bool, ?user_agent: String?, ?ip_address: String?, ?last_ip_address: String?, ?last_activity_at: Time?, ?session_started_at: Time?, ?created_at: Time?, ?updated_at: Time?) -> AuthSession
21
21
  def self.members: () -> [:id, :user_id, :provider, :expires_at, :is_active, :is_current, :user_agent, :ip_address, :last_ip_address, :last_activity_at, :session_started_at, :created_at, :updated_at]
22
22
 
23
- def initialize: (id: String, user_id: String, provider: String, expires_at: Time, is_active: bool, is_current: bool, ?user_agent: String?, ?ip_address: String?, ?last_ip_address: String?, ?last_activity_at: Time?, ?session_started_at: Time?, ?created_at: Time?, ?updated_at: Time?) -> void
23
+ private def initialize: (**Object? attributes) -> void
24
24
  def members: () -> [:id, :user_id, :provider, :expires_at, :is_active, :is_current, :user_agent, :ip_address, :last_ip_address, :last_activity_at, :session_started_at, :created_at, :updated_at]
25
25
  def with: (?id: String, ?user_id: String, ?provider: String, ?expires_at: Time, ?is_active: bool, ?is_current: bool, ?user_agent: String?, ?ip_address: String?, ?last_ip_address: String?, ?last_activity_at: Time?, ?session_started_at: Time?, ?created_at: Time?, ?updated_at: Time?) -> AuthSession
26
26
  def to_h: () -> { id: String, user_id: String, provider: String, expires_at: Time, is_active: bool, is_current: bool, user_agent: String?, ip_address: String?, last_ip_address: String?, last_activity_at: Time?, session_started_at: Time?, created_at: Time?, updated_at: Time? }
data/sig/client.rbs ADDED
@@ -0,0 +1,15 @@
1
+ module Volcano
2
+ class Client
3
+ attr_reader auth: Auth
4
+ attr_reader functions: Functions
5
+ attr_reader durable: Durable
6
+ attr_reader logs: Logs
7
+ attr_reader storage: Storage
8
+ attr_reader locks: Locks
9
+ attr_reader realtime: Realtime
10
+
11
+ def initialize: (anon_key: String, ?api_url: String, ?service_key: String?, ?timeout: (Integer | Float), ?access_token: String?, ?refresh_token: String?) -> void
12
+ def current_session: () -> Session?
13
+ def database: (String name) -> Database
14
+ end
15
+ end
@@ -0,0 +1,81 @@
1
+ module Volcano
2
+ type sdk_json = nil | bool | Integer | Float | String | Time | Array[sdk_json] | Hash[String | Symbol, sdk_json]
3
+ type sdk_payload = Hash[String | Symbol, sdk_json]
4
+ type database_rows = Array[Hash[String, json_value]]
5
+
6
+ class Database
7
+ def from: (String table) -> QueryBuilder
8
+ end
9
+
10
+ class QueryBuilder
11
+ def select: (*String columns) -> QueryBuilder
12
+ def insert: (sdk_payload values) -> InsertBuilder
13
+ def update: (sdk_payload values) -> UpdateBuilder
14
+ def delete: () -> DeleteBuilder
15
+ def order: (String column, ?ascending: bool) -> QueryBuilder
16
+ def limit: (Integer count) -> QueryBuilder
17
+ def offset: (Integer count) -> QueryBuilder
18
+ def execute: () -> database_rows
19
+
20
+ def eq: (String column, sdk_json value) -> QueryBuilder
21
+ def neq: (String column, sdk_json value) -> QueryBuilder
22
+ def gt: (String column, sdk_json value) -> QueryBuilder
23
+ def gte: (String column, sdk_json value) -> QueryBuilder
24
+ def lt: (String column, sdk_json value) -> QueryBuilder
25
+ def lte: (String column, sdk_json value) -> QueryBuilder
26
+ def like: (String column, String pattern) -> QueryBuilder
27
+ def ilike: (String column, String pattern) -> QueryBuilder
28
+ def is: (String column, sdk_json value) -> QueryBuilder
29
+ def in: (String column, Array[sdk_json] values) -> QueryBuilder
30
+ end
31
+
32
+ class InsertBuilder
33
+ def execute: () -> database_rows
34
+ end
35
+
36
+ class UpdateBuilder
37
+ def execute: () -> database_rows
38
+
39
+ def eq: (String column, sdk_json value) -> UpdateBuilder
40
+ def neq: (String column, sdk_json value) -> UpdateBuilder
41
+ def gt: (String column, sdk_json value) -> UpdateBuilder
42
+ def gte: (String column, sdk_json value) -> UpdateBuilder
43
+ def lt: (String column, sdk_json value) -> UpdateBuilder
44
+ def lte: (String column, sdk_json value) -> UpdateBuilder
45
+ def like: (String column, String pattern) -> UpdateBuilder
46
+ def ilike: (String column, String pattern) -> UpdateBuilder
47
+ def is: (String column, sdk_json value) -> UpdateBuilder
48
+ def in: (String column, Array[sdk_json] values) -> UpdateBuilder
49
+ end
50
+
51
+ class DeleteBuilder
52
+ def execute: () -> database_rows
53
+
54
+ def eq: (String column, sdk_json value) -> DeleteBuilder
55
+ def neq: (String column, sdk_json value) -> DeleteBuilder
56
+ def gt: (String column, sdk_json value) -> DeleteBuilder
57
+ def gte: (String column, sdk_json value) -> DeleteBuilder
58
+ def lt: (String column, sdk_json value) -> DeleteBuilder
59
+ def lte: (String column, sdk_json value) -> DeleteBuilder
60
+ def like: (String column, String pattern) -> DeleteBuilder
61
+ def ilike: (String column, String pattern) -> DeleteBuilder
62
+ def is: (String column, sdk_json value) -> DeleteBuilder
63
+ def in: (String column, Array[sdk_json] values) -> DeleteBuilder
64
+ end
65
+
66
+ class Functions
67
+ def invoke: (String name, ?sdk_payload payload) -> FunctionResponse
68
+ end
69
+
70
+ class Durable
71
+ def start: (String function_name, ?sdk_payload payload, ?execution_name: String?) -> DurableExecution
72
+ def get: (String project_id, String function_name, String execution_id) -> DurableExecution
73
+ def list: (String project_id, String function_name, ?status: String?, ?page: Integer?, ?limit: Integer?) -> DurableExecutionPage
74
+ def stop: (String project_id, String function_name, String execution_id) -> DurableExecution
75
+ end
76
+
77
+ class Logs
78
+ def search: (String project_id, sdk_payload request) -> LogSearchResponse
79
+ def activity: (String project_id, sdk_payload request) -> LogActivityResponse
80
+ end
81
+ end
@@ -36,7 +36,7 @@ module Volcano
36
36
  | (id: String, function_id: String, name: String, status: String, region: String, created_at: Time, ?result: json_value, ?result_expired: bool?, ?error: DurableExecutionError?, ?completed_at: Time?) -> DurableExecution
37
37
  def self.members: () -> [:id, :function_id, :name, :status, :region, :created_at, :result, :result_expired, :error, :completed_at]
38
38
 
39
- def initialize: (id: String, function_id: String, name: String, status: String, region: String, created_at: Time, ?result: json_value, ?result_expired: bool?, ?error: DurableExecutionError?, ?completed_at: Time?) -> void
39
+ private def initialize: (**(json_value | Time | DurableExecutionError) attributes) -> void
40
40
  def members: () -> [:id, :function_id, :name, :status, :region, :created_at, :result, :result_expired, :error, :completed_at]
41
41
  def with: (?id: String, ?function_id: String, ?name: String, ?status: String, ?region: String, ?created_at: Time, ?result: json_value, ?result_expired: bool?, ?error: DurableExecutionError?, ?completed_at: Time?) -> DurableExecution
42
42
  def to_h: () -> { id: String, function_id: String, name: String, status: String, region: String, created_at: Time, result: json_value, result_expired: bool?, error: DurableExecutionError?, completed_at: Time? }
data/sig/locks.rbs ADDED
@@ -0,0 +1,10 @@
1
+ module Volcano
2
+ class Locks
3
+ def get: (String key, ?request_id: String?) -> LockState
4
+ def acquire: (String key, ttl: Integer, ?token: String?, ?request_id: String?) -> LockLease
5
+ def renew: (String key, LockLease lease, ttl: Integer, ?request_id: String?) -> LockLease
6
+ def release: (String key, LockLease lease, ?request_id: String?) -> nil
7
+ def force_release: (String key, ?request_id: String?) -> nil
8
+ def with_lock: [T] (String key, ttl: Integer, ?token: String?, ?request_id: String?) { (LockGuard) -> T } -> T
9
+ end
10
+ end
data/sig/realtime.rbs ADDED
@@ -0,0 +1,45 @@
1
+ module Volcano
2
+ class Realtime
3
+ def channel: (String name, ?type: String | Symbol, ?auto_fetch: bool, ?fetch_batch_window_ms: Integer, ?fetch_max_batch_size: Integer) -> Channel
4
+ def connected?: () -> bool
5
+ def disconnect: () -> void
6
+ def remove_channel: (String name, ?type: String | Symbol) -> nil
7
+ def remove_all_channels: () -> nil
8
+
9
+ def on_connect: (^(ConnectContext) -> void callback) -> ^() -> Proc?
10
+ | () { (ConnectContext) -> void } -> ^() -> Proc?
11
+ def on_disconnect: (^(DisconnectContext) -> void callback) -> ^() -> Proc?
12
+ | () { (DisconnectContext) -> void } -> ^() -> Proc?
13
+ def on_error: (^(ErrorContext) -> void callback) -> ^() -> Proc?
14
+ | () { (ErrorContext) -> void } -> ^() -> Proc?
15
+
16
+ def database_name: () -> String?
17
+ def database_name=: (String? name) -> String?
18
+
19
+ class Channel
20
+ attr_reader name: String
21
+
22
+ def subscribe: () -> nil
23
+ def unsubscribe: () -> nil
24
+ def send: (event: String | Symbol, **json_value payload) -> nil
25
+
26
+ def on: ("message" event, ^(Hash[String, json_value]) -> void callback) -> self
27
+ | ("message" event) { (Hash[String, json_value]) -> void } -> self
28
+ | ("join" | "leave" event, ^(PresenceInfo) -> void callback) -> self
29
+ | ("join" | "leave" event) { (PresenceInfo) -> void } -> self
30
+ | ("presence_sync" event, ^(Hash[String, PresenceInfo]) -> void callback) -> self
31
+ | ("presence_sync" event) { (Hash[String, PresenceInfo]) -> void } -> self
32
+ | ("INSERT" | "UPDATE" | "DELETE" | "*" event, ^(PostgresChange) -> void callback) -> self
33
+ | ("INSERT" | "UPDATE" | "DELETE" | "*" event) { (PostgresChange) -> void } -> self
34
+ def on_presence_sync: (^(Hash[String, PresenceInfo]) -> void callback) -> self
35
+ | () { (Hash[String, PresenceInfo]) -> void } -> self
36
+ def on_postgres_changes: (String | Symbol event, schema: String, table: String, callback: ^(PostgresChange) -> void) -> self
37
+ | (String | Symbol event, schema: String, table: String) { (PostgresChange) -> void } -> self
38
+
39
+ def track: (?Hash[String, json_value] state) -> nil
40
+ def presence_state: () -> Hash[String, PresenceInfo]
41
+ def get_presence_state: () -> Hash[String, PresenceInfo]
42
+ def tracked_state: () -> Hash[String, json_value]
43
+ end
44
+ end
45
+ end