getstream-ruby 8.0.2 → 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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +36 -0
  3. data/lib/getstream_ruby/client.rb +92 -31
  4. data/lib/getstream_ruby/configuration.rb +26 -29
  5. data/lib/getstream_ruby/generated/chat_client.rb +29 -0
  6. data/lib/getstream_ruby/generated/feed.rb +16 -4
  7. data/lib/getstream_ruby/generated/feeds_client.rb +160 -10
  8. data/lib/getstream_ruby/generated/models/activity_response.rb +10 -0
  9. data/lib/getstream_ruby/generated/models/add_comment_reaction_request.rb +5 -0
  10. data/lib/getstream_ruby/generated/models/add_comment_reaction_response.rb +18 -2
  11. data/lib/getstream_ruby/generated/models/add_reaction_request.rb +5 -0
  12. data/lib/getstream_ruby/generated/models/add_reaction_response.rb +18 -2
  13. data/lib/getstream_ruby/generated/models/ai_audio_config_request.rb +36 -0
  14. data/lib/getstream_ruby/generated/models/ai_audio_config_response.rb +41 -0
  15. data/lib/getstream_ruby/generated/models/async_export_error_event.rb +1 -1
  16. data/lib/getstream_ruby/generated/models/async_export_review_queue_event.rb +66 -0
  17. data/lib/getstream_ruby/generated/models/batch_query_activity_reactions_request.rb +66 -0
  18. data/lib/getstream_ruby/generated/models/batch_query_activity_reactions_response.rb +46 -0
  19. data/lib/getstream_ruby/generated/models/batch_query_comment_reactions_request.rb +66 -0
  20. data/lib/getstream_ruby/generated/models/batch_query_comment_reactions_response.rb +46 -0
  21. data/lib/getstream_ruby/generated/models/check_response.rb +5 -0
  22. data/lib/getstream_ruby/generated/models/closed_caption_rule_parameters.rb +5 -0
  23. data/lib/getstream_ruby/generated/models/comment_response.rb +5 -0
  24. data/lib/getstream_ruby/generated/models/config_response.rb +5 -0
  25. data/lib/getstream_ruby/generated/models/create_queue_request.rb +61 -0
  26. data/lib/getstream_ruby/generated/models/delete_queue_request.rb +36 -0
  27. data/lib/getstream_ruby/generated/models/feeds_share_response.rb +41 -0
  28. data/lib/getstream_ruby/generated/models/feeds_v3_activity_response.rb +10 -0
  29. data/lib/getstream_ruby/generated/models/feeds_v3_comment_response.rb +5 -0
  30. data/lib/getstream_ruby/generated/models/filter_config_response.rb +5 -0
  31. data/lib/getstream_ruby/generated/models/list_queues_response.rb +36 -0
  32. data/lib/getstream_ruby/generated/models/moderation_call_response.rb +126 -0
  33. data/lib/getstream_ruby/generated/models/moderation_dashboard_preferences.rb +10 -10
  34. data/lib/getstream_ruby/generated/models/moderation_payload.rb +26 -1
  35. data/lib/getstream_ruby/generated/models/moderation_payload_request.rb +5 -0
  36. data/lib/getstream_ruby/generated/models/moderation_payload_response.rb +26 -1
  37. data/lib/getstream_ruby/generated/models/moderation_queue_response.rb +76 -0
  38. data/lib/getstream_ruby/generated/models/ocr_content_parameters.rb +41 -0
  39. data/lib/getstream_ruby/generated/models/permission.rb +5 -0
  40. data/lib/getstream_ruby/generated/models/query_activity_shares_response.rb +46 -0
  41. data/lib/getstream_ruby/generated/models/query_moderation_rules_response.rb +1 -1
  42. data/lib/getstream_ruby/generated/models/queue_response.rb +36 -0
  43. data/lib/getstream_ruby/generated/models/review_queue_item_response.rb +1 -1
  44. data/lib/getstream_ruby/generated/models/rule_builder_condition.rb +5 -0
  45. data/lib/getstream_ruby/generated/models/share_response.rb +41 -0
  46. data/lib/getstream_ruby/generated/models/threaded_comment_response.rb +5 -0
  47. data/lib/getstream_ruby/generated/models/translate_activity_request.rb +31 -0
  48. data/lib/getstream_ruby/generated/models/translate_activity_response.rb +36 -0
  49. data/lib/getstream_ruby/generated/models/translate_comment_request.rb +31 -0
  50. data/lib/getstream_ruby/generated/models/translate_comment_response.rb +36 -0
  51. data/lib/getstream_ruby/generated/models/triggered_rule_response.rb +5 -0
  52. data/lib/getstream_ruby/generated/models/update_app_request.rb +10 -0
  53. data/lib/getstream_ruby/generated/models/update_queue_request.rb +56 -0
  54. data/lib/getstream_ruby/generated/models/upsert_config_request.rb +5 -0
  55. data/lib/getstream_ruby/generated/moderation_client.rb +91 -0
  56. data/lib/getstream_ruby/generated/webhook.rb +7 -0
  57. data/lib/getstream_ruby/log_redaction.rb +58 -0
  58. data/lib/getstream_ruby/request_logging.rb +97 -0
  59. data/lib/getstream_ruby/retry_config.rb +27 -0
  60. data/lib/getstream_ruby/version.rb +1 -1
  61. data/lib/getstream_ruby.rb +2 -0
  62. metadata +27 -16
@@ -84,6 +84,9 @@ module GetStream
84
84
  # @!attribute custom
85
85
  # @return [Object]
86
86
  attr_accessor :custom
87
+ # @!attribute i18n
88
+ # @return [Hash<String, String>]
89
+ attr_accessor :i18n
87
90
  # @!attribute meta
88
91
  # @return [RepliesMeta]
89
92
  attr_accessor :meta
@@ -122,6 +125,7 @@ module GetStream
122
125
  @latest_reactions = attributes[:latest_reactions] || attributes['latest_reactions'] || nil
123
126
  @replies = attributes[:replies] || attributes['replies'] || nil
124
127
  @custom = attributes[:custom] || attributes['custom'] || nil
128
+ @i18n = attributes[:i18n] || attributes['i18n'] || nil
125
129
  @meta = attributes[:meta] || attributes['meta'] || nil
126
130
  @moderation = attributes[:moderation] || attributes['moderation'] || nil
127
131
  @reaction_groups = attributes[:reaction_groups] || attributes['reaction_groups'] || nil
@@ -155,6 +159,7 @@ module GetStream
155
159
  latest_reactions: 'latest_reactions',
156
160
  replies: 'replies',
157
161
  custom: 'custom',
162
+ i18n: 'i18n',
158
163
  meta: 'meta',
159
164
  moderation: 'moderation',
160
165
  reaction_groups: 'reaction_groups'
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT.
4
+
5
+ module GetStream
6
+ module Generated
7
+ module Models
8
+ #
9
+ class TranslateActivityRequest < GetStream::BaseModel
10
+
11
+ # Model attributes
12
+ # @!attribute language
13
+ # @return [String] ISO 639-1 language code to translate to
14
+ attr_accessor :language
15
+
16
+ # Initialize with attributes
17
+ def initialize(attributes = {})
18
+ super(attributes)
19
+ @language = attributes[:language] || attributes['language']
20
+ end
21
+
22
+ # Override field mappings for JSON serialization
23
+ def self.json_field_mappings
24
+ {
25
+ language: 'language'
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT.
4
+
5
+ module GetStream
6
+ module Generated
7
+ module Models
8
+ # Basic response information
9
+ class TranslateActivityResponse < GetStream::BaseModel
10
+
11
+ # Model attributes
12
+ # @!attribute duration
13
+ # @return [String] Duration of the request in milliseconds
14
+ attr_accessor :duration
15
+ # @!attribute activity
16
+ # @return [ActivityResponse]
17
+ attr_accessor :activity
18
+
19
+ # Initialize with attributes
20
+ def initialize(attributes = {})
21
+ super(attributes)
22
+ @duration = attributes[:duration] || attributes['duration']
23
+ @activity = attributes[:activity] || attributes['activity']
24
+ end
25
+
26
+ # Override field mappings for JSON serialization
27
+ def self.json_field_mappings
28
+ {
29
+ duration: 'duration',
30
+ activity: 'activity'
31
+ }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT.
4
+
5
+ module GetStream
6
+ module Generated
7
+ module Models
8
+ #
9
+ class TranslateCommentRequest < GetStream::BaseModel
10
+
11
+ # Model attributes
12
+ # @!attribute language
13
+ # @return [String] ISO 639-1 language code to translate to
14
+ attr_accessor :language
15
+
16
+ # Initialize with attributes
17
+ def initialize(attributes = {})
18
+ super(attributes)
19
+ @language = attributes[:language] || attributes['language']
20
+ end
21
+
22
+ # Override field mappings for JSON serialization
23
+ def self.json_field_mappings
24
+ {
25
+ language: 'language'
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT.
4
+
5
+ module GetStream
6
+ module Generated
7
+ module Models
8
+ # Basic response information
9
+ class TranslateCommentResponse < GetStream::BaseModel
10
+
11
+ # Model attributes
12
+ # @!attribute duration
13
+ # @return [String] Duration of the request in milliseconds
14
+ attr_accessor :duration
15
+ # @!attribute comment
16
+ # @return [CommentResponse]
17
+ attr_accessor :comment
18
+
19
+ # Initialize with attributes
20
+ def initialize(attributes = {})
21
+ super(attributes)
22
+ @duration = attributes[:duration] || attributes['duration']
23
+ @comment = attributes[:comment] || attributes['comment']
24
+ end
25
+
26
+ # Override field mappings for JSON serialization
27
+ def self.json_field_mappings
28
+ {
29
+ duration: 'duration',
30
+ comment: 'comment'
31
+ }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -18,6 +18,9 @@ module GetStream
18
18
  # @!attribute rule_name
19
19
  # @return [String] Name of the moderation rule that triggered
20
20
  attr_accessor :rule_name
21
+ # @!attribute type
22
+ # @return [String] Type of the moderation rule that triggered (content, user, or call)
23
+ attr_accessor :type
21
24
  # @!attribute violation_number
22
25
  # @return [Integer] Violation count for action sequence rules (1-based)
23
26
  attr_accessor :violation_number
@@ -31,6 +34,7 @@ module GetStream
31
34
  @rule_id = attributes[:rule_id] || attributes['rule_id']
32
35
  @actions = attributes[:actions] || attributes['actions']
33
36
  @rule_name = attributes[:rule_name] || attributes['rule_name'] || nil
37
+ @type = attributes[:type] || attributes['type'] || nil
34
38
  @violation_number = attributes[:violation_number] || attributes['violation_number'] || nil
35
39
  @call_options = attributes[:call_options] || attributes['call_options'] || nil
36
40
  end
@@ -41,6 +45,7 @@ module GetStream
41
45
  rule_id: 'rule_id',
42
46
  actions: 'actions',
43
47
  rule_name: 'rule_name',
48
+ type: 'type',
44
49
  violation_number: 'violation_number',
45
50
  call_options: 'call_options'
46
51
  }
@@ -42,6 +42,9 @@ module GetStream
42
42
  # @!attribute enforce_unique_usernames
43
43
  # @return [String]
44
44
  attr_accessor :enforce_unique_usernames
45
+ # @!attribute feed_audit_logs_enabled
46
+ # @return [Boolean]
47
+ attr_accessor :feed_audit_logs_enabled
45
48
  # @!attribute feeds_moderation_enabled
46
49
  # @return [Boolean]
47
50
  attr_accessor :feeds_moderation_enabled
@@ -87,6 +90,9 @@ module GetStream
87
90
  # @!attribute reminders_max_members
88
91
  # @return [Integer]
89
92
  attr_accessor :reminders_max_members
93
+ # @!attribute reminders_max_per_user
94
+ # @return [Integer]
95
+ attr_accessor :reminders_max_per_user
90
96
  # @!attribute revoke_tokens_issued_before
91
97
  # @return [DateTime]
92
98
  attr_accessor :revoke_tokens_issued_before
@@ -186,6 +192,7 @@ module GetStream
186
192
  @disable_permissions_checks = attributes[:disable_permissions_checks] || attributes['disable_permissions_checks'] || nil
187
193
  @enable_hook_payload_compression = attributes[:enable_hook_payload_compression] || attributes['enable_hook_payload_compression'] || nil
188
194
  @enforce_unique_usernames = attributes[:enforce_unique_usernames] || attributes['enforce_unique_usernames'] || nil
195
+ @feed_audit_logs_enabled = attributes[:feed_audit_logs_enabled] || attributes['feed_audit_logs_enabled'] || nil
189
196
  @feeds_moderation_enabled = attributes[:feeds_moderation_enabled] || attributes['feeds_moderation_enabled'] || nil
190
197
  @feeds_v2_region = attributes[:feeds_v2_region] || attributes['feeds_v2_region'] || nil
191
198
  @guest_user_creation_disabled = attributes[:guest_user_creation_disabled] || attributes['guest_user_creation_disabled'] || nil
@@ -201,6 +208,7 @@ module GetStream
201
208
  @permission_version = attributes[:permission_version] || attributes['permission_version'] || nil
202
209
  @reminders_interval = attributes[:reminders_interval] || attributes['reminders_interval'] || nil
203
210
  @reminders_max_members = attributes[:reminders_max_members] || attributes['reminders_max_members'] || nil
211
+ @reminders_max_per_user = attributes[:reminders_max_per_user] || attributes['reminders_max_per_user'] || nil
204
212
  @revoke_tokens_issued_before = attributes[:revoke_tokens_issued_before] || attributes['revoke_tokens_issued_before'] || nil
205
213
  @sns_key = attributes[:sns_key] || attributes['sns_key'] || nil
206
214
  @sns_secret = attributes[:sns_secret] || attributes['sns_secret'] || nil
@@ -245,6 +253,7 @@ module GetStream
245
253
  disable_permissions_checks: 'disable_permissions_checks',
246
254
  enable_hook_payload_compression: 'enable_hook_payload_compression',
247
255
  enforce_unique_usernames: 'enforce_unique_usernames',
256
+ feed_audit_logs_enabled: 'feed_audit_logs_enabled',
248
257
  feeds_moderation_enabled: 'feeds_moderation_enabled',
249
258
  feeds_v2_region: 'feeds_v2_region',
250
259
  guest_user_creation_disabled: 'guest_user_creation_disabled',
@@ -260,6 +269,7 @@ module GetStream
260
269
  permission_version: 'permission_version',
261
270
  reminders_interval: 'reminders_interval',
262
271
  reminders_max_members: 'reminders_max_members',
272
+ reminders_max_per_user: 'reminders_max_per_user',
263
273
  revoke_tokens_issued_before: 'revoke_tokens_issued_before',
264
274
  sns_key: 'sns_key',
265
275
  sns_secret: 'sns_secret',
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT.
4
+
5
+ module GetStream
6
+ module Generated
7
+ module Models
8
+ #
9
+ class UpdateQueueRequest < GetStream::BaseModel
10
+
11
+ # Model attributes
12
+ # @!attribute description
13
+ # @return [String]
14
+ attr_accessor :description
15
+ # @!attribute name
16
+ # @return [String]
17
+ attr_accessor :name
18
+ # @!attribute user_id
19
+ # @return [String]
20
+ attr_accessor :user_id
21
+ # @!attribute sort
22
+ # @return [Array<Object>]
23
+ attr_accessor :sort
24
+ # @!attribute filters
25
+ # @return [Object]
26
+ attr_accessor :filters
27
+ # @!attribute user
28
+ # @return [UserRequest]
29
+ attr_accessor :user
30
+
31
+ # Initialize with attributes
32
+ def initialize(attributes = {})
33
+ super(attributes)
34
+ @description = attributes[:description] || attributes['description'] || nil
35
+ @name = attributes[:name] || attributes['name'] || nil
36
+ @user_id = attributes[:user_id] || attributes['user_id'] || nil
37
+ @sort = attributes[:sort] || attributes['sort'] || nil
38
+ @filters = attributes[:filters] || attributes['filters'] || nil
39
+ @user = attributes[:user] || attributes['user'] || nil
40
+ end
41
+
42
+ # Override field mappings for JSON serialization
43
+ def self.json_field_mappings
44
+ {
45
+ description: 'description',
46
+ name: 'name',
47
+ user_id: 'user_id',
48
+ sort: 'sort',
49
+ filters: 'filters',
50
+ user: 'user'
51
+ }
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -21,6 +21,9 @@ module GetStream
21
21
  # @!attribute user_id
22
22
  # @return [String] Optional user ID to associate with the audit log entry
23
23
  attr_accessor :user_id
24
+ # @!attribute ai_audio_config
25
+ # @return [AIAudioConfigRequest]
26
+ attr_accessor :ai_audio_config
24
27
  # @!attribute ai_image_config
25
28
  # @return [AIImageConfig]
26
29
  attr_accessor :ai_image_config
@@ -77,6 +80,7 @@ module GetStream
77
80
  @async = attributes[:async] || attributes['async'] || nil
78
81
  @team = attributes[:team] || attributes['team'] || nil
79
82
  @user_id = attributes[:user_id] || attributes['user_id'] || nil
83
+ @ai_audio_config = attributes[:ai_audio_config] || attributes['ai_audio_config'] || nil
80
84
  @ai_image_config = attributes[:ai_image_config] || attributes['ai_image_config'] || nil
81
85
  @ai_text_config = attributes[:ai_text_config] || attributes['ai_text_config'] || nil
82
86
  @ai_video_config = attributes[:ai_video_config] || attributes['ai_video_config'] || nil
@@ -102,6 +106,7 @@ module GetStream
102
106
  async: 'async',
103
107
  team: 'team',
104
108
  user_id: 'user_id',
109
+ ai_audio_config: 'ai_audio_config',
105
110
  ai_image_config: 'ai_image_config',
106
111
  ai_text_config: 'ai_text_config',
107
112
  ai_video_config: 'ai_video_config',
@@ -618,6 +618,97 @@ module GetStream
618
618
  )
619
619
  end
620
620
 
621
+ #
622
+ #
623
+ # @return [Models::ListQueuesResponse]
624
+ def list_queues()
625
+ path = '/api/v2/moderation/queues'
626
+
627
+ # Make the API request
628
+ @client.make_request(
629
+ :get,
630
+ path
631
+ )
632
+ end
633
+
634
+ #
635
+ #
636
+ # @param create_queue_request [CreateQueueRequest]
637
+ # @return [Models::QueueResponse]
638
+ def create_queue(create_queue_request)
639
+ path = '/api/v2/moderation/queues'
640
+ # Build request body
641
+ body = create_queue_request
642
+
643
+ # Make the API request
644
+ @client.make_request(
645
+ :post,
646
+ path,
647
+ body: body
648
+ )
649
+ end
650
+
651
+ #
652
+ #
653
+ # @param _id [String]
654
+ # @param user_id [String]
655
+ # @return [Models::QueueResponse]
656
+ def get_queue(_id, user_id = nil)
657
+ path = '/api/v2/moderation/queues/{id}'
658
+ # Replace path parameters
659
+ path = path.gsub('{id}', _id.to_s)
660
+ # Build query parameters
661
+ query_params = {}
662
+ query_params['user_id'] = user_id unless user_id.nil?
663
+
664
+ # Make the API request
665
+ @client.make_request(
666
+ :get,
667
+ path,
668
+ query_params: query_params
669
+ )
670
+ end
671
+
672
+ #
673
+ #
674
+ # @param _id [String]
675
+ # @param update_queue_request [UpdateQueueRequest]
676
+ # @return [Models::QueueResponse]
677
+ def update_queue(_id, update_queue_request)
678
+ path = '/api/v2/moderation/queues/{id}'
679
+ # Replace path parameters
680
+ path = path.gsub('{id}', _id.to_s)
681
+ # Build request body
682
+ body = update_queue_request
683
+
684
+ # Make the API request
685
+ @client.make_request(
686
+ :patch,
687
+ path,
688
+ body: body
689
+ )
690
+ end
691
+
692
+ #
693
+ #
694
+ # @param _id [String]
695
+ # @param delete_queue_request [DeleteQueueRequest]
696
+ # @return [Models::QueueResponse]
697
+ def delete_queue(_id, delete_queue_request)
698
+ path = '/api/v2/moderation/queues/{id}/delete'
699
+ # Replace path parameters
700
+ path = path.gsub('{id}', _id.to_s)
701
+ # Build request body
702
+ body = delete_queue_request
703
+
704
+ # Make the API request
705
+ @client.make_request(
706
+ :post,
707
+ path,
708
+ body: body
709
+ )
710
+ end
711
+
621
712
  # Query review queue items allows you to filter the review queue items. This is used for building a moderation dashboard.
622
713
  #
623
714
  # @param query_review_queue_request [QueryReviewQueueRequest]
@@ -24,6 +24,7 @@ require_relative 'models/async_bulk_image_moderation_event'
24
24
  require_relative 'models/async_export_channels_event'
25
25
  require_relative 'models/async_export_error_event'
26
26
  require_relative 'models/async_export_moderation_logs_event'
27
+ require_relative 'models/async_export_review_queue_event'
27
28
  require_relative 'models/async_export_users_event'
28
29
  require_relative 'models/blocked_user_event'
29
30
  require_relative 'models/bookmark_added_event'
@@ -295,6 +296,8 @@ module StreamChat
295
296
  EVENT_TYPE_EXPORT_CHANNELS_SUCCESS = 'export.channels.success'
296
297
  EVENT_TYPE_EXPORT_MODERATION_LOGS_ERROR = 'export.moderation_logs.error'
297
298
  EVENT_TYPE_EXPORT_MODERATION_LOGS_SUCCESS = 'export.moderation_logs.success'
299
+ EVENT_TYPE_EXPORT_REVIEW_QUEUE_ERROR = 'export.review_queue.error'
300
+ EVENT_TYPE_EXPORT_REVIEW_QUEUE_SUCCESS = 'export.review_queue.success'
298
301
  EVENT_TYPE_EXPORT_USERS_ERROR = 'export.users.error'
299
302
  EVENT_TYPE_EXPORT_USERS_SUCCESS = 'export.users.success'
300
303
  EVENT_TYPE_FEEDS_ACTIVITY_ADDED = 'feeds.activity.added'
@@ -591,6 +594,10 @@ module StreamChat
591
594
  GetStream::Generated::Models::AsyncExportErrorEvent
592
595
  when 'export.moderation_logs.success'
593
596
  GetStream::Generated::Models::AsyncExportModerationLogsEvent
597
+ when 'export.review_queue.error'
598
+ GetStream::Generated::Models::AsyncExportErrorEvent
599
+ when 'export.review_queue.success'
600
+ GetStream::Generated::Models::AsyncExportReviewQueueEvent
594
601
  when 'export.users.error'
595
602
  GetStream::Generated::Models::AsyncExportErrorEvent
596
603
  when 'export.users.success'
@@ -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 = '8.0.2'
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'