getstream-ruby 9.0.0 → 10.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 95df1de0290331e3d4c2040f9afbadb7f0ee6fa5cc931cbef126c2f244672632
4
- data.tar.gz: 484cd5ddc8b072644bbc8f0808c87f4f3e933b936fb114fb49b23c3e32327329
3
+ metadata.gz: f7c2582f037fa1be220f8b72647c0a87254d0eeb42af2b5046cdb410852f25d7
4
+ data.tar.gz: a880f9c77e414fe74ee4dd7d82631c927b5af8b4c8b0dca6fca5d00386ff08cf
5
5
  SHA512:
6
- metadata.gz: c577cceb9a470b2835b48eb1bb5554e3f955227d63b595786c1516f7e6ea0f56e1bc5d452486e3ff4e0b1b7bda34d49b6d5e7c5f14e746b8d972f899034a55c3
7
- data.tar.gz: 0c616c6ad3ac9ebd6701f049e2d0432b0cb3309363fbd2dd5da8bfc75e787f0f0e44628363f1f9a40a97a97b07861af4e05c366d50f09f6783d06397d8695c54
6
+ metadata.gz: 10ad2c2ba0fb122b5a0048136d605eba7de662c86c7cd62123b8e84ad17f96a88750e0dc416764208e42106dab904d5127f711b36aab9083d637e8684582dd26
7
+ data.tar.gz: b1bffe4b14da26fb2761eb596c78b3337f8bd7f4600869e1be0792b4c581bea79108990bd7ab5898c083826b66a8b68a054eda8c2e4d93c94d75a9007735af67
data/README.md CHANGED
@@ -163,6 +163,42 @@ rescue GetStreamRuby::APIError => e
163
163
  end
164
164
  ```
165
165
 
166
+ ## Retries
167
+
168
+ Retries are opt-in via `retry_config:` and disabled by default (the client makes exactly one attempt; errors surface unchanged). When enabled, only `GET`/`HEAD` requests are retried, and only when they fail with HTTP 429 (unless the error is marked `unrecoverable`) or a transport-level error (connection reset, timeout, DNS failure, TLS handshake failure). Writes, 5xx responses, and other 4xx responses are never retried.
169
+
170
+ ```ruby
171
+ client = GetStreamRuby::Client.new(
172
+ api_key: '...', api_secret: '...',
173
+ retry_config: GetStreamRuby::RetryConfig.new(enabled: true, max_attempts: 3, max_backoff: 30.0)
174
+ )
175
+ ```
176
+
177
+ `max_attempts` caps the total number of attempts (default 3). `max_backoff` caps the wait between attempts (default 30.0 seconds). A 429 with a `Retry-After` header waits exactly that long, clamped to `max_backoff`, with no jitter. Otherwise the wait is full jitter: a random delay between 0 and `min(max_backoff, 2**attempt)` seconds.
178
+
179
+ ## Logging
180
+
181
+ Pass a stdlib `Logger` via `logger:` to get structured, single-line log events. With no `logger:`, the SDK produces zero output; the SDK never sets the logger's level either, that's the caller's call.
182
+
183
+ ```ruby
184
+ require 'logger'
185
+
186
+ client = GetStreamRuby.manual(
187
+ api_key: "your_api_key",
188
+ api_secret: "your_api_secret",
189
+ logger: Logger.new($stdout)
190
+ )
191
+ ```
192
+
193
+ Four events are emitted:
194
+
195
+ - `client.initialized` (INFO, once at construction): SDK version and the effective client config (pool size, timeouts, gzip, whether a custom `http_client`/`log_bodies` is set).
196
+ - `http.request.sent` (DEBUG, before each request).
197
+ - `http.response.received` (DEBUG, after any response including 4xx/5xx — those are just data, not a failure).
198
+ - `http.request.failed` (ERROR, transport failure only: no HTTP response was received at all, e.g. connection reset, timeout, DNS failure, TLS handshake failure). When [retries](#retries) are enabled, each retried attempt also emits `http.request.failed` at DEBUG with a `retry.attempt` field (1-indexed) before its backoff sleep; a 429 retry omits `error.type` (the paired `http.response.received` already recorded the status), a transport-error retry includes it.
199
+
200
+ Query values for `api_key`/`api_secret`/`token` are always redacted to `<redacted>`, and the same keys are redacted (shallowly, top-level only) in JSON body logging. No headers are ever logged. Request/response bodies are not logged by default; pass `log_bodies: true` to opt in (values for the keys above are still redacted). Enabling it emits one WARN at construction as a reminder that your logs will now contain body content.
201
+
166
202
  ## Development
167
203
 
168
204
  ### Quick Start
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'faraday'
4
4
  require 'faraday/gzip'
5
- require 'faraday/retry'
6
5
  require 'faraday/multipart'
7
6
  require 'faraday/net_http_persistent'
8
7
  require 'logger'
@@ -20,11 +19,15 @@ require_relative 'generated/webhook'
20
19
  require_relative 'generated/models/api_error'
21
20
  require_relative 'stream_response'
22
21
  require_relative 'error_mapping'
22
+ require_relative 'log_redaction'
23
+ require_relative 'request_logging'
23
24
 
24
25
  module GetStreamRuby
25
26
 
26
27
  class Client
27
28
 
29
+ include RequestLogging
30
+
28
31
  # Backdate the JWT `iat` claim by this many seconds.
29
32
  #
30
33
  # JWT timestamps are whole-second (RFC 7519 NumericDate), so `Time.now.to_i`
@@ -38,20 +41,23 @@ module GetStreamRuby
38
41
  attr_reader :configuration
39
42
 
40
43
  def initialize(config = nil, api_key: nil, api_secret: nil, **options)
41
- @configuration = config || GetStreamRuby.configuration
42
-
43
- # Create new configuration with overrides if any parameters provided
44
- if api_key || api_secret || !options.empty?
45
- @configuration = Configuration.with_overrides(
46
- api_key: api_key,
47
- api_secret: api_secret,
48
- **options,
49
- )
50
- end
44
+ # Overrides win over an explicit config, matching prior behavior. Only
45
+ # fall back to GetStreamRuby.configuration when neither is given, so
46
+ # that path (currently unimplemented) isn't evaluated needlessly.
47
+ @configuration = if api_key || api_secret || !options.empty?
48
+ Configuration.with_overrides(
49
+ api_key: api_key,
50
+ api_secret: api_secret,
51
+ **options,
52
+ )
53
+ else
54
+ config || GetStreamRuby.configuration
55
+ end
51
56
 
52
57
  @configuration.validate!
53
58
  @connection = build_connection
54
59
  @configuration.log_pool_config_to(@configuration.logger)
60
+ warn_log_bodies_enabled
55
61
  end
56
62
 
57
63
  def feed_resource
@@ -209,21 +215,76 @@ module GetStreamRuby
209
215
  # Check if this is a file upload request that needs multipart
210
216
  return make_multipart_request(method, path, query_params, data) if multipart_request?(data)
211
217
 
212
- response = @connection.send(method) do |req|
218
+ body_json = data.to_json
219
+ attempt = 0
213
220
 
214
- req.url path, query_params
215
- req.headers['Authorization'] = generate_auth_header
216
- req.headers['Content-Type'] = 'application/json'
217
- req.headers['stream-auth-type'] = 'jwt'
218
- req.headers['X-Stream-Client'] = user_agent
219
- req.body = data.to_json
220
- req.options.timeout = request_timeout if request_timeout
221
+ begin
222
+ started = monotonic_now
223
+ log_request_sent(method, path, query_params, body_json)
224
+
225
+ response = @connection.send(method) do |req|
226
+
227
+ req.url path, query_params
228
+ req.headers['Authorization'] = generate_auth_header
229
+ req.headers['Content-Type'] = 'application/json'
230
+ req.headers['stream-auth-type'] = 'jwt'
231
+ req.headers['X-Stream-Client'] = user_agent
232
+ req.body = body_json
233
+ req.options.timeout = request_timeout if request_timeout
234
+
235
+ end
221
236
 
237
+ log_response_received(response, started)
238
+ handle_response(response)
239
+ rescue Faraday::Error => e
240
+ error = TransportError.new("Request failed: #{e.message}", error_type: ErrorMapping.classify_faraday_error(e))
241
+ if retry_eligible?(method, error, attempt)
242
+ wait_before_retry(method, path, error, attempt, started)
243
+ attempt += 1
244
+ retry
245
+ end
246
+ log_request_failed(method, path, e, started)
247
+ raise error
248
+ rescue RateLimitError => e
249
+ if retry_eligible?(method, e, attempt)
250
+ wait_before_retry(method, path, e, attempt, started)
251
+ attempt += 1
252
+ retry
253
+ end
254
+ raise
222
255
  end
256
+ end
223
257
 
224
- handle_response(response)
225
- rescue Faraday::Error => e
226
- raise TransportError.new("Request failed: #{e.message}", error_type: ErrorMapping.classify_faraday_error(e))
258
+ # True when the opt-in retry policy (GetStreamRuby::RetryConfig) allows
259
+ # another attempt for this failure: disabled by default (single attempt,
260
+ # errors surface unchanged); enabled only retries idempotent GET/HEAD
261
+ # requests that failed with a recoverable RateLimitError or a
262
+ # TransportError, and only while attempts remain.
263
+ def retry_eligible?(method, error, attempt)
264
+ config = @configuration.retry_config
265
+ return false unless config&.enabled?
266
+ return false unless %i[get head].include?(method)
267
+ return false if error.is_a?(RateLimitError) && error.unrecoverable
268
+ return false unless attempt + 1 < config.max_attempts
269
+
270
+ true
271
+ end
272
+
273
+ # Emits the retry-attempt log, then blocks for the backoff delay:
274
+ # RateLimitError#retry_after (if positive) capped at max_backoff, no
275
+ # jitter; otherwise full jitter over 2**attempt capped at max_backoff.
276
+ # `sleep` is called on self so specs can stub it.
277
+ def wait_before_retry(method, path, error, attempt, started)
278
+ log_retry_attempt(method, path, error, attempt, started)
279
+ config = @configuration.retry_config
280
+ delay =
281
+ if error.is_a?(RateLimitError) && error.retry_after&.positive?
282
+ [error.retry_after, config.max_backoff].min
283
+ else
284
+ ceiling = [config.max_backoff, 2.0**attempt].min
285
+ ceiling <= 0 ? 0.0 : rand * ceiling
286
+ end
287
+ sleep(delay)
227
288
  end
228
289
 
229
290
  def build_connection
@@ -234,13 +295,10 @@ module GetStreamRuby
234
295
  Faraday.new(url: @configuration.base_url) do |conn|
235
296
 
236
297
  conn.request :multipart
237
- conn.request :retry, {
238
- max: 3,
239
- interval: 0.05,
240
- interval_randomness: 0.5,
241
- backoff_factor: 2,
242
- }
243
- conn.response :json, content_type: /\bjson$/
298
+ # preserve_raw: true keeps the wire string in env[:raw_body] alongside
299
+ # the parsed body, so response logging can report size/content
300
+ # without re-serializing an already-parsed Hash.
301
+ conn.response :json, content_type: /\bjson$/, preserve_raw: true
244
302
  # :gzip must come after :json (Faraday runs response middleware in reverse).
245
303
  conn.request :gzip
246
304
  configure_adapter(conn)
@@ -277,8 +335,6 @@ module GetStreamRuby
277
335
  # A fallback silently disables pooling, so always WARN (never swallow).
278
336
  @configuration.warn_pool_fallback(Faraday.default_adapter, e)
279
337
  connection.adapter Faraday.default_adapter
280
- # Record the adapter actually built so the INFO log reports it accurately.
281
- @configuration.effective_adapter = Faraday.default_adapter.to_s
282
338
  end
283
339
 
284
340
  def generate_auth_header
@@ -346,6 +402,9 @@ module GetStreamRuby
346
402
  payload[:upload_sizes] = upload_sizes_json
347
403
  end
348
404
 
405
+ started = monotonic_now
406
+ log_request_sent(method, path, query_params)
407
+
349
408
  response = @connection.send(method) do |req|
350
409
 
351
410
  req.url path, query_params
@@ -356,8 +415,10 @@ module GetStreamRuby
356
415
 
357
416
  end
358
417
 
418
+ log_response_received(response, started)
359
419
  handle_response(response)
360
420
  rescue Faraday::Error => e
421
+ log_request_failed(method, path, e, started)
361
422
  raise TransportError.new("Request failed: #{e.message}", error_type: ErrorMapping.classify_faraday_error(e))
362
423
  end
363
424
 
@@ -8,7 +8,7 @@ module GetStreamRuby
8
8
 
9
9
  attr_accessor :api_key, :api_secret, :base_url, :timeout, :logger, :faraday_adapter, :faraday_adapter_options,
10
10
  :connection_keep_alive, :max_conns_per_host, :idle_timeout, :connect_timeout,
11
- :request_timeout, :http_client, :effective_adapter
11
+ :request_timeout, :http_client, :log_bodies, :retry_config
12
12
 
13
13
  def initialize(api_key: nil, api_secret: nil, use_env: true, **options)
14
14
  http_options = options[:http_options] || {}
@@ -22,6 +22,8 @@ module GetStreamRuby
22
22
  @timeout = @request_timeout
23
23
  @http_client = options[:http_client]
24
24
  @logger = options[:logger]
25
+ @log_bodies = options[:log_bodies] || false
26
+ @retry_config = options[:retry_config] || RetryConfig.new
25
27
  end
26
28
 
27
29
  def valid?
@@ -48,41 +50,36 @@ module GetStreamRuby
48
50
  faraday_adapter_options: @faraday_adapter_options.dup,
49
51
  connection_keep_alive: @connection_keep_alive,
50
52
  logger: @logger,
53
+ log_bodies: @log_bodies,
54
+ retry_config: @retry_config,
51
55
  )
52
56
  end
53
57
 
54
- # Emit a single INFO line listing the 5 effective pool knobs plus the active escape hatch (CHA-2956).
55
- # If no logger is supplied, a default $stdout INFO logger is used.
56
- # The faraday_adapter label reflects the adapter actually built
57
- # (effective_adapter, set by Client#configure_adapter) so a silent fallback
58
- # to the default adapter is never misreported as the requested adapter.
58
+ # Emit the `client.initialized` INFO event once at construction (structured
59
+ # logging spec §6.1). A no-op when no logger is configured: unlike
60
+ # `warn_pool_fallback` below, a quiet start-up here is expected, not a
61
+ # silently-swallowed problem, so there is no $stdout fallback.
59
62
  def log_pool_config_to(logger)
60
- logger ||= Logger.new($stdout).tap { |l| l.level = Logger::INFO }
61
- flag = @http_client ? 'user_http_client=true' : 'user_http_client=false'
62
- adapter_label = if @http_client
63
- 'user-supplied'
64
- elsif @effective_adapter
65
- @effective_adapter
66
- elsif @faraday_adapter
67
- @faraday_adapter.to_s
68
- else
69
- 'default'
70
- end
71
- fmt = 'connection pool: max_conns_per_host=%<m>d idle_timeout=%<i>d ' \
72
- 'connect_timeout=%<c>d request_timeout=%<r>d %<flag>s faraday_adapter=%<a>s'
73
- logger.info(
74
- format(
75
- fmt,
76
- m: @max_conns_per_host, i: @idle_timeout, c: @connect_timeout,
77
- r: @request_timeout, flag: flag, a: adapter_label
78
- ),
79
- )
63
+ return if logger.nil?
64
+
65
+ fields = {
66
+ 'stream.sdk.name' => 'getstream-ruby',
67
+ 'stream.sdk.version' => VERSION,
68
+ 'stream.client.max_conns_per_host' => @max_conns_per_host,
69
+ 'stream.client.idle_timeout_seconds' => @idle_timeout,
70
+ 'stream.client.connect_timeout_seconds' => @connect_timeout,
71
+ 'stream.client.request_timeout_seconds' => @request_timeout,
72
+ 'stream.client.gzip_enabled' => true,
73
+ 'stream.client.user_http_client' => !@http_client.nil?,
74
+ 'stream.client.log_bodies' => @log_bodies,
75
+ }
76
+ logger.info { "client.initialized #{fields.map { |k, v| "#{k}=#{v}" }.join(' ')}" }
80
77
  end
81
78
 
82
79
  # Emit a WARNING that the requested adapter could not be built and pooling
83
- # is disabled (CHA-2956). A fallback must never be silent, so when no logger
84
- # is configured this uses a default $stdout logger, exactly like
85
- # log_pool_config_to.
80
+ # is disabled (CHA-2956). A fallback must never be silent, so unlike the
81
+ # structured-logging events below, this uses a default $stdout logger when
82
+ # none is configured.
86
83
  def warn_pool_fallback(fallback_adapter, error)
87
84
  warn_logger = @logger || Logger.new($stdout).tap { |l| l.level = Logger::WARN }
88
85
  warn_logger.warn(
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module GetStreamRuby
6
+
7
+ # Redaction helpers for the SDK's structured log events. Shallow by design.
8
+ module LogRedaction
9
+
10
+ REDACTED = '<redacted>'
11
+ QUERY_PARAMS = %w[api_key api_secret token].freeze
12
+ BODY_KEYS = %w[api_secret token password].freeze
13
+ # Matches `key=value` for the secret query params wherever they appear in a
14
+ # free-form string (e.g. a transport error message that embeds the request
15
+ # URL), value runs up to the next `&`, whitespace, or end of string.
16
+ MESSAGE_SECRET_PATTERN = /\b(#{QUERY_PARAMS.join('|')})=[^&\s]*/i.freeze
17
+
18
+ module_function
19
+
20
+ def redact_query(params)
21
+ return params if params.nil? || params.empty?
22
+
23
+ params.to_h { |k, v| [k, QUERY_PARAMS.include?(k.to_s.downcase) ? REDACTED : v] }
24
+ end
25
+
26
+ def redact_json_body(body)
27
+ return body if body.nil? || body.empty?
28
+
29
+ data = JSON.parse(body)
30
+ return body unless data.is_a?(Hash)
31
+
32
+ changed = false
33
+ BODY_KEYS.each do |key|
34
+
35
+ if data.key?(key)
36
+ data[key] = REDACTED
37
+ changed = true
38
+ end
39
+
40
+ end
41
+ changed ? JSON.generate(data) : body
42
+ rescue JSON::ParserError
43
+ body
44
+ end
45
+
46
+ # Redacts secret query-parameter values wherever they appear in a free
47
+ # string (e.g. `error.message` from a transport exception, which may embed
48
+ # the full request URL). Case-insensitive on the key; the value is
49
+ # replaced regardless of its own case.
50
+ def redact_message(string)
51
+ return string if string.nil? || string.empty?
52
+
53
+ string.gsub(MESSAGE_SECRET_PATTERN) { "#{Regexp.last_match(1)}=#{REDACTED}" }
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GetStreamRuby
4
+
5
+ # Structured-logging event emission mixed into Client (kept in its own file
6
+ # to stay under Metrics/ClassLength; these methods rely on Client's
7
+ # @configuration/monotonic_now same as if they lived on the class directly).
8
+ module RequestLogging
9
+
10
+ private
11
+
12
+ # One-shot WARN at construction so a log_bodies: true deployment can't miss
13
+ # that bodies (secrets key-redacted, but otherwise verbatim) are now being
14
+ # written to its logs.
15
+ def warn_log_bodies_enabled
16
+ return unless @configuration.log_bodies && @configuration.logger
17
+
18
+ @configuration.logger.warn do
19
+
20
+ 'HTTP request/response bodies will be logged. Auth headers and ' \
21
+ 'known-secret fields are still redacted, but other sensitive ' \
22
+ 'data (messages, PII) may appear in logs. Disable for production.'
23
+
24
+ end
25
+ end
26
+
27
+ def log_request_sent(method, path, query_params, body_json = nil)
28
+ logger = @configuration.logger
29
+ return unless logger
30
+
31
+ query = LogRedaction.redact_query(query_params).map { |k, v| "#{k}=#{v}" }.join('&')
32
+ line = +"http.request.sent http.request.method=#{method} url.path=#{path} url.query=#{query}"
33
+ line << " http.request.body=#{LogRedaction.redact_json_body(body_json)}" if @configuration.log_bodies && body_json
34
+ logger.debug { line }
35
+ end
36
+
37
+ def log_response_received(response, started)
38
+ logger = @configuration.logger
39
+ return unless logger
40
+
41
+ raw_body = raw_response_body(response)
42
+ line = +"http.response.received http.response.status_code=#{response.status} " \
43
+ "http.response.body.size=#{raw_body.bytesize} duration_ms=#{elapsed_ms(started)}"
44
+ line << " http.response.body=#{LogRedaction.redact_json_body(raw_body)}" if @configuration.log_bodies
45
+ logger.debug { line }
46
+ end
47
+
48
+ def log_request_failed(method, path, error, started)
49
+ logger = @configuration.logger
50
+ return unless logger
51
+
52
+ error_type = ErrorMapping.classify_faraday_error(error)
53
+ message = LogRedaction.redact_message(error.message)
54
+ logger.error do
55
+
56
+ "http.request.failed http.request.method=#{method} url.path=#{path} " \
57
+ "error.type=#{error_type} error.message=#{message} duration_ms=#{elapsed_ms(started)}"
58
+
59
+ end
60
+ end
61
+
62
+ # DEBUG-level counterpart to `log_request_failed`, emitted before each
63
+ # retry backoff sleep (opt-in RetryConfig). `error.type` is the closed
64
+ # transport-classifier enum (see ErrorMapping.classify_faraday_error /
65
+ # TRANSPORT_ERROR_TYPES) and is only meaningful for TransportError; a 429
66
+ # retry omits it rather than invent a value; the paired
67
+ # http.response.received log already recorded the 429 status.
68
+ def log_retry_attempt(method, path, error, attempt, started)
69
+ logger = @configuration.logger
70
+ return unless logger
71
+
72
+ message = LogRedaction.redact_message(error.message)
73
+ line = +"http.request.failed http.request.method=#{method} url.path=#{path} retry.attempt=#{attempt + 1}"
74
+ line << " error.type=#{error.error_type}" if error.is_a?(TransportError)
75
+ line << " error.message=#{message} duration_ms=#{elapsed_ms(started)}"
76
+ logger.debug { line }
77
+ end
78
+
79
+ def elapsed_ms(started)
80
+ ((monotonic_now - started) * 1000).round
81
+ end
82
+
83
+ # The `:json` response middleware parses env[:body] in place once its
84
+ # content type matches, so the raw wire string only survives via
85
+ # `preserve_raw:` (see Client#build_connection). Falls back to
86
+ # `response.body` itself when it was never parsed (non-JSON content type,
87
+ # or no body).
88
+ def raw_response_body(response)
89
+ raw = response.env[:raw_body]
90
+ return raw unless raw.nil?
91
+
92
+ response.body.to_s
93
+ end
94
+
95
+ end
96
+
97
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GetStreamRuby
4
+
5
+ # Opt-in auto-retry policy. Disabled by default: the client performs exactly
6
+ # one attempt and surfaces errors unchanged. When enabled, only GET/HEAD
7
+ # requests failing with HTTP 429 or a transport error are retried.
8
+ class RetryConfig
9
+
10
+ attr_reader :max_attempts, :max_backoff
11
+
12
+ def initialize(enabled: false, max_attempts: 3, max_backoff: 30.0)
13
+ raise ArgumentError, 'max_attempts must be >= 1' if max_attempts < 1
14
+ raise ArgumentError, 'max_backoff must be >= 0' if max_backoff.negative?
15
+
16
+ @enabled = enabled
17
+ @max_attempts = max_attempts
18
+ @max_backoff = max_backoff.to_f
19
+ end
20
+
21
+ def enabled?
22
+ @enabled
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GetStreamRuby
4
4
 
5
- VERSION = '9.0.0'
5
+ VERSION = '10.0.0'
6
6
 
7
7
  end
@@ -2,6 +2,8 @@
2
2
 
3
3
  # Only load dotenv for .env method, not for system env method
4
4
  require 'getstream_ruby/version'
5
+ require 'getstream_ruby/log_redaction'
6
+ require 'getstream_ruby/retry_config'
5
7
  require 'getstream_ruby/client'
6
8
  require 'getstream_ruby/configuration'
7
9
  require 'getstream_ruby/errors'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: getstream-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.0.0
4
+ version: 10.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GetStream
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-07-15 00:00:00.000000000 Z
11
+ date: 2026-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dotenv
@@ -80,20 +80,6 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '2.3'
83
- - !ruby/object:Gem::Dependency
84
- name: faraday-retry
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '2.0'
90
- type: :runtime
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '2.0'
97
83
  - !ruby/object:Gem::Dependency
98
84
  name: json
99
85
  requirement: !ruby/object:Gem::Requirement
@@ -1534,7 +1520,10 @@ files:
1534
1520
  - lib/getstream_ruby/generated/moderation_client.rb
1535
1521
  - lib/getstream_ruby/generated/video_client.rb
1536
1522
  - lib/getstream_ruby/generated/webhook.rb
1523
+ - lib/getstream_ruby/log_redaction.rb
1524
+ - lib/getstream_ruby/request_logging.rb
1537
1525
  - lib/getstream_ruby/resources/feed.rb
1526
+ - lib/getstream_ruby/retry_config.rb
1538
1527
  - lib/getstream_ruby/stream_response.rb
1539
1528
  - lib/getstream_ruby/version.rb
1540
1529
  homepage: https://getstream.io
@@ -1556,7 +1545,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1556
1545
  - !ruby/object:Gem::Version
1557
1546
  version: '0'
1558
1547
  requirements: []
1559
- rubygems_version: 3.5.3
1548
+ rubygems_version: 3.3.3
1560
1549
  signing_key:
1561
1550
  specification_version: 4
1562
1551
  summary: Ruby SDK for GetStream