erpc-sdk 0.7.0 → 0.8.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.
@@ -18,9 +18,9 @@ module ERPC
18
18
  response = start(uri, timeout) { |http| http.request(request) }
19
19
  HttpResponse.new(status: response.code.to_i, body: response.body.to_s)
20
20
  rescue Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout
21
- raise TimeoutError, timeout
21
+ raise TimeoutError, timeout, cause: nil
22
22
  rescue IOError, EOFError, SocketError, SystemCallError, OpenSSL::SSL::SSLError
23
- raise TransportError, "Unable to reach ERPC"
23
+ raise TransportError, "Unable to reach ERPC", cause: nil
24
24
  end
25
25
 
26
26
  def stream(url:, headers:, timeout: DEFAULT_TIMEOUT)
@@ -36,11 +36,11 @@ module ERPC
36
36
  end
37
37
  end
38
38
  rescue Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout
39
- raise TimeoutError, timeout
39
+ raise TimeoutError, timeout, cause: nil
40
40
  rescue HttpError
41
41
  raise
42
42
  rescue IOError, EOFError, SocketError, SystemCallError, OpenSSL::SSL::SSLError
43
- raise TransportError, "Unable to reach ERPC"
43
+ raise TransportError, "Unable to reach ERPC", cause: nil
44
44
  end
45
45
  end
46
46
 
@@ -57,20 +57,34 @@ module ERPC
57
57
  end
58
58
 
59
59
  class HttpJsonRpcTransport
60
- attr_reader :endpoint, :max_batch_size
60
+ attr_reader :max_batch_size
61
61
 
62
- def initialize(api_key:, endpoint:, headers:, timeout:, adapter:, max_batch_size: 256)
62
+ def initialize(api_key: nil, endpoint:, headers: {}, timeout:, adapter:, max_batch_size: 256,
63
+ direct: false, redactions: [], unavailable_namespace: nil)
63
64
  @api_key = api_key
64
65
  @endpoint = endpoint
65
- @headers = headers
66
+ @public_endpoint = URLs.public_endpoint(endpoint)
67
+ @headers = headers.to_h.dup.freeze
66
68
  @timeout = timeout
67
69
  @adapter = adapter
68
70
  @max_batch_size = max_batch_size
71
+ @direct = direct
72
+ @redactions = redactions
73
+ @unavailable_namespace = unavailable_namespace
69
74
  @next_id = 0
70
75
  @id_mutex = Mutex.new
71
76
  end
72
77
 
78
+ def endpoint
79
+ @public_endpoint
80
+ end
81
+
82
+ def inspect
83
+ "#<#{self.class} endpoint=#{endpoint.inspect} max_batch_size=#{max_batch_size.inspect}>"
84
+ end
85
+
73
86
  def request(method, params = nil)
87
+ ensure_configured
74
88
  request_id = next_id
75
89
  body = { "jsonrpc" => "2.0", "id" => request_id, "method" => method }
76
90
  body["params"] = params unless params.nil?
@@ -82,6 +96,7 @@ module ERPC
82
96
  if calls.length > max_batch_size
83
97
  raise InvalidResponseError, "A batch may contain at most #{max_batch_size} calls"
84
98
  end
99
+ ensure_configured
85
100
 
86
101
  requests = calls.map do |call|
87
102
  method = call.fetch(:method) { call.fetch("method") }
@@ -123,19 +138,28 @@ module ERPC
123
138
 
124
139
  private
125
140
 
141
+ def ensure_configured
142
+ return if @unavailable_namespace.nil?
143
+
144
+ raise NotConfiguredError, @unavailable_namespace
145
+ end
146
+
126
147
  def next_id
127
148
  @id_mutex.synchronize { @next_id += 1 }
128
149
  end
129
150
 
130
151
  def post(body)
131
- uri = URI.parse(endpoint)
132
- query = URI.decode_www_form(uri.query.to_s)
133
- query << ["api-key", @api_key]
134
- uri.query = URI.encode_www_form(query)
152
+ ensure_configured
153
+ uri = URI.parse(@endpoint)
154
+ unless @direct
155
+ query = URI.decode_www_form(uri.query.to_s)
156
+ query << ["api-key", @api_key]
157
+ uri.query = URI.encode_www_form(query)
158
+ end
135
159
  response = @adapter.request(
136
160
  method: :post,
137
161
  url: uri.to_s,
138
- headers: @headers.merge("accept" => "application/json", "content-type" => "application/json"),
162
+ headers: protocol_headers,
139
163
  body: JSON.generate(body),
140
164
  timeout: @timeout
141
165
  )
@@ -143,7 +167,7 @@ module ERPC
143
167
 
144
168
  JSON.parse(response.body)
145
169
  rescue JSON::ParserError
146
- raise InvalidResponseError, "ERPC returned malformed JSON"
170
+ raise InvalidResponseError, "ERPC returned malformed JSON", cause: nil
147
171
  end
148
172
 
149
173
  def unwrap(response, expected_id)
@@ -161,8 +185,17 @@ module ERPC
161
185
  raise InvalidResponseError, "ERPC returned an invalid RPC error"
162
186
  end
163
187
 
164
- data = error.key?("data") ? Redaction.value(error["data"], @api_key) : nil
165
- raise JsonRpcError.new(error["code"], Redaction.text(error["message"], @api_key), data)
188
+ credentials = @direct ? @redactions : @api_key
189
+ data = error.key?("data") ? Redaction.value(error["data"], credentials) : nil
190
+ raise JsonRpcError.new(error["code"], Redaction.text(error["message"], credentials), data)
191
+ end
192
+
193
+ def protocol_headers
194
+ headers = @headers.dup
195
+ if @direct
196
+ headers.delete_if { |name, _| %w[accept content-type].include?(name.to_s.downcase) }
197
+ end
198
+ headers.merge("accept" => "application/json", "content-type" => "application/json")
166
199
  end
167
200
 
168
201
  def valid_id?(value)
@@ -171,17 +204,26 @@ module ERPC
171
204
  end
172
205
 
173
206
  class RestTransport
174
- attr_reader :endpoint
175
-
176
- def initialize(credential:, endpoint:, headers:, timeout:, adapter:)
207
+ def initialize(credential: nil, endpoint:, headers: {}, timeout:, adapter:, unavailable_namespace: nil)
177
208
  @credential = credential
178
209
  @endpoint = endpoint
179
- @headers = headers
210
+ @public_endpoint = URLs.public_endpoint(endpoint)
211
+ @headers = headers.to_h.dup.freeze
180
212
  @timeout = timeout
181
213
  @adapter = adapter
214
+ @unavailable_namespace = unavailable_namespace
215
+ end
216
+
217
+ def endpoint
218
+ @public_endpoint
219
+ end
220
+
221
+ def inspect
222
+ "#<#{self.class} endpoint=#{endpoint.inspect}>"
182
223
  end
183
224
 
184
225
  def get(path, query = nil)
226
+ ensure_configured
185
227
  response = @adapter.request(
186
228
  method: :get,
187
229
  url: url(path, query),
@@ -192,10 +234,11 @@ module ERPC
192
234
 
193
235
  JSON.parse(response.body)
194
236
  rescue JSON::ParserError
195
- raise InvalidResponseError, "ERPC returned malformed JSON"
237
+ raise InvalidResponseError, "ERPC returned malformed JSON", cause: nil
196
238
  end
197
239
 
198
240
  def stream(path, query = nil)
241
+ ensure_configured
199
242
  @adapter.stream(
200
243
  url: url(path, query),
201
244
  headers: @headers.merge("authorization" => "Bearer #{@credential}", "accept" => "text/event-stream"),
@@ -205,6 +248,12 @@ module ERPC
205
248
 
206
249
  private
207
250
 
251
+ def ensure_configured
252
+ return if @unavailable_namespace.nil?
253
+
254
+ raise NotConfiguredError, @unavailable_namespace
255
+ end
256
+
208
257
  def url(path, query)
209
258
  uri = URI.parse(URLs.with_path(endpoint, path))
210
259
  pairs = []
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ERPC
4
- VERSION = "0.7.0"
4
+ VERSION = "0.8.0"
5
5
  end
@@ -22,6 +22,10 @@ module ERPC
22
22
  connect
23
23
  end
24
24
 
25
+ def inspect
26
+ "#<#{self.class} endpoint=#{URLs.public_endpoint(@uri).inspect}>"
27
+ end
28
+
25
29
  def write_text(text)
26
30
  write_frame(0x1, text.b)
27
31
  end
@@ -84,13 +88,13 @@ module ERPC
84
88
  handshake
85
89
  rescue ::Timeout::Error
86
90
  tcp&.close
87
- raise TimeoutError, @timeout
91
+ raise TimeoutError, @timeout, cause: nil
88
92
  rescue ConfigError, TimeoutError
89
93
  tcp&.close
90
94
  raise
91
95
  rescue IOError, EOFError, SocketError, SystemCallError, OpenSSL::SSL::SSLError
92
96
  tcp&.close
93
- raise TransportError, "Unable to reach ERPC WebSocket"
97
+ raise TransportError, "Unable to reach ERPC WebSocket", cause: nil
94
98
  end
95
99
 
96
100
  def handshake
@@ -123,7 +127,7 @@ module ERPC
123
127
  raise TransportError, "ERPC returned an invalid WebSocket upgrade"
124
128
  end
125
129
  rescue ::Timeout::Error
126
- raise TimeoutError, @timeout
130
+ raise TimeoutError, @timeout, cause: nil
127
131
  end
128
132
 
129
133
  def read_until(delimiter, limit)
@@ -176,16 +180,16 @@ module ERPC
176
180
  Timeout.timeout(@timeout) { @socket.write(prefix + mask + masked) }
177
181
  end
178
182
  rescue ::Timeout::Error
179
- raise TimeoutError, @timeout
183
+ raise TimeoutError, @timeout, cause: nil
180
184
  rescue IOError, EOFError, SocketError, SystemCallError, OpenSSL::SSL::SSLError
181
- raise TransportError, "Unable to reach ERPC WebSocket"
185
+ raise TransportError, "Unable to reach ERPC WebSocket", cause: nil
182
186
  end
183
187
 
184
188
  def read_exact(length)
185
189
  value = +"".b
186
190
  while value.bytesize < length
187
191
  ready = IO.select([@socket], nil, nil, @timeout)
188
- raise TimeoutError, @timeout unless ready
192
+ raise TimeoutError, @timeout, cause: nil unless ready
189
193
 
190
194
  chunk = @socket.readpartial(length - value.bytesize)
191
195
  raise EOFError if chunk.empty?
@@ -194,7 +198,7 @@ module ERPC
194
198
  end
195
199
  value
196
200
  rescue EOFError, IOError, SocketError, SystemCallError, OpenSSL::SSL::SSLError
197
- raise TransportError, "ERPC WebSocket connection closed"
201
+ raise TransportError, "ERPC WebSocket connection closed", cause: nil
198
202
  end
199
203
 
200
204
  def secure_compare(left, right)
@@ -205,10 +209,17 @@ module ERPC
205
209
  end
206
210
 
207
211
  class WebSocketJsonRpcTransport
208
- def initialize(connection_url, credential, timeout, connection_factory: nil)
212
+ attr_reader :endpoint
213
+
214
+ def initialize(connection_url, credential, timeout, connection_factory: nil, direct: false,
215
+ redactions: [], unavailable_namespace: nil)
209
216
  @connection_url = connection_url
210
217
  @credential = credential
211
218
  @timeout = timeout
219
+ @direct = direct
220
+ @redactions = redactions
221
+ @unavailable_namespace = unavailable_namespace
222
+ @endpoint = URLs.public_endpoint(connection_url)
212
223
  @connection_factory = connection_factory || ->(url, seconds) { WebSocketConnection.new(url, seconds) }
213
224
  @mutex = Mutex.new
214
225
  @connection = nil
@@ -220,6 +231,10 @@ module ERPC
220
231
  @closed = false
221
232
  end
222
233
 
234
+ def inspect
235
+ "#<#{self.class} endpoint=#{endpoint.inspect}>"
236
+ end
237
+
223
238
  def request(method, params = nil)
224
239
  connection = ensure_connection
225
240
  request_id = @mutex.synchronize { @next_id += 1 }
@@ -233,7 +248,7 @@ module ERPC
233
248
 
234
249
  unwrap(response, request_id)
235
250
  rescue ::Timeout::Error
236
- raise TimeoutError, @timeout
251
+ raise TimeoutError, @timeout, cause: nil
237
252
  ensure
238
253
  @mutex.synchronize { @pending.delete(request_id) } if request_id
239
254
  end
@@ -268,6 +283,7 @@ module ERPC
268
283
  private
269
284
 
270
285
  def ensure_connection
286
+ ensure_configured
271
287
  @mutex.synchronize do
272
288
  raise TransportError, "WebSocket transport is closed" if @closed
273
289
  return @connection if @connection
@@ -302,7 +318,7 @@ module ERPC
302
318
  end
303
319
  rescue StandardError => error
304
320
  @mutex.synchronize { @connection = nil if @connection.equal?(connection) }
305
- fail_pending(TransportError.new(Redaction.text(error.message, @credential)))
321
+ fail_pending(TransportError.new(Redaction.text(error.message, redaction_credentials)))
306
322
  end
307
323
 
308
324
  def fail_pending(error)
@@ -319,13 +335,25 @@ module ERPC
319
335
  unless error.is_a?(Hash) && error["code"].is_a?(Integer) && error["message"].is_a?(String)
320
336
  raise InvalidResponseError, "ERPC returned an invalid RPC error"
321
337
  end
322
- data = error.key?("data") ? Redaction.value(error["data"], @credential) : nil
323
- raise JsonRpcError.new(error["code"], Redaction.text(error["message"], @credential), data)
338
+ credentials = redaction_credentials
339
+ data = error.key?("data") ? Redaction.value(error["data"], credentials) : nil
340
+ raise JsonRpcError.new(error["code"], Redaction.text(error["message"], credentials), data)
324
341
  end
325
342
  raise InvalidResponseError, "ERPC returned an invalid WebSocket response" unless response.key?("result")
326
343
 
327
344
  response["result"]
328
345
  end
346
+
347
+ def ensure_configured
348
+ return if @unavailable_namespace.nil?
349
+
350
+ raise NotConfiguredError, @unavailable_namespace
351
+ end
352
+
353
+ def redaction_credentials
354
+ @direct ? @redactions : @credential
355
+ end
356
+
329
357
  end
330
358
 
331
359
  class RpcSubscription
@@ -355,7 +383,7 @@ module ERPC
355
383
 
356
384
  Timeout.timeout(timeout) { @queue.pop }
357
385
  rescue ::Timeout::Error
358
- raise TimeoutError, timeout
386
+ raise TimeoutError, timeout, cause: nil
359
387
  end
360
388
 
361
389
  def unsubscribe
@@ -372,6 +400,10 @@ module ERPC
372
400
  @transport = transport
373
401
  end
374
402
 
403
+ def endpoint
404
+ @transport.endpoint
405
+ end
406
+
375
407
  def on_notification(listener = nil, &block)
376
408
  @transport.on_notification(listener, &block)
377
409
  end
data/lib/erpc_sdk.rb CHANGED
@@ -12,3 +12,4 @@ require_relative "erpc_sdk/swap"
12
12
  require_relative "erpc_sdk/client"
13
13
  require_relative "erpc_sdk/token_catalog"
14
14
  require_relative "erpc_sdk/token_rankings"
15
+ require_relative "erpc_sdk/bridge"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erpc-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ELSOUL LABO B.V.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-16 00:00:00.000000000 Z
11
+ date: 2026-09-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -60,11 +60,14 @@ files:
60
60
  - LICENSE
61
61
  - README.md
62
62
  - lib/erpc_sdk.rb
63
+ - lib/erpc_sdk/bridge.rb
63
64
  - lib/erpc_sdk/client.rb
64
65
  - lib/erpc_sdk/config.rb
65
66
  - lib/erpc_sdk/dex_catalog.rb
66
67
  - lib/erpc_sdk/errors.rb
68
+ - lib/erpc_sdk/generated/bridge_capabilities.rb
67
69
  - lib/erpc_sdk/generated/dex_catalog.rb
70
+ - lib/erpc_sdk/generated/swap_execution_capabilities.rb
68
71
  - lib/erpc_sdk/generated/token_catalog.rb
69
72
  - lib/erpc_sdk/generated/token_rankings.rb
70
73
  - lib/erpc_sdk/rest.rb