getstream-ruby 6.1.1 → 7.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 +4 -4
- data/README.md +8 -6
- data/lib/getstream_ruby/client.rb +47 -0
- data/lib/getstream_ruby/generated/common_client.rb +26 -0
- data/lib/getstream_ruby/generated/feed.rb +3 -1
- data/lib/getstream_ruby/generated/feeds_client.rb +3 -1
- data/lib/getstream_ruby/generated/models/async_export_error_event.rb +1 -1
- data/lib/getstream_ruby/generated/models/delete_feeds_batch_request.rb +6 -1
- data/lib/getstream_ruby/generated/models/labels_request.rb +5 -0
- data/lib/getstream_ruby/generated/models/query_bookmarks_request.rb +11 -1
- data/lib/getstream_ruby/generated/models/search_roles_response.rb +36 -0
- data/lib/getstream_ruby/generated/webhook.rb +401 -170
- data/lib/getstream_ruby/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 725fbf9f73fef4a9c33f241c9911d226222041e245084e2dbca69cbc0418eaef
|
|
4
|
+
data.tar.gz: 637cc6dd6bc256959b15ae6a98e62f1131f3bfdf6183e8c3f64acd6e6cfc33d2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 21e076ab8023229dbdda7feff3405716929d315aa96c0d0478df09c3f7b27db8a6d24e9ea399782e16cc52f355807e33adcebe558e2c040acfcb66875b8d9ed8
|
|
7
|
+
data.tar.gz: 96f2ce649e6c7f40e1651696f39c7e3612ea822e93351c3a86f0ce352b854f7a4ac12e7216f95df9933754da6a107dcb2ac6aa85892c9bc453f437c5cbf252a3
|
data/README.md
CHANGED
|
@@ -350,18 +350,20 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/getstr
|
|
|
350
350
|
|
|
351
351
|
## Release Process
|
|
352
352
|
|
|
353
|
-
Releases use two paths
|
|
353
|
+
Releases use two paths, both handled by `.github/workflows/release.yml`:
|
|
354
354
|
|
|
355
|
-
- Default
|
|
356
|
-
- Fallback
|
|
355
|
+
- **Default**: automatic release when a PR is merged to `main`/`master`. The PR title (and body) drives the semver bump.
|
|
356
|
+
- **Fallback**: manual release via the `Release` workflow's `workflow_dispatch` (admin use). Select a `version_bump` (`patch`/`minor`/`major`). `use_current_version=true` skips the bump and publishes whatever is already in `lib/getstream_ruby/version.rb`.
|
|
357
357
|
|
|
358
|
-
Automatic semver bump rules
|
|
358
|
+
Automatic semver bump rules:
|
|
359
359
|
|
|
360
360
|
- `feat:` -> minor
|
|
361
361
|
- `fix:` (or `bug:`) -> patch
|
|
362
|
-
- `feat
|
|
362
|
+
- `feat!:`, `<type>(scope)!:`, or `BREAKING CHANGE` in the PR body/title -> major
|
|
363
363
|
|
|
364
|
-
PRs with other
|
|
364
|
+
PRs with any other prefix do not trigger a release.
|
|
365
|
+
|
|
366
|
+
The release pipeline runs lint (`make format-check && make lint && make security`), the unit suite (`make test`), and all three integration suites (chat, feed, video) on the merged commit before publishing to RubyGems. Each step is idempotent; a failed run can be re-dispatched from the Actions UI.
|
|
365
367
|
|
|
366
368
|
## License
|
|
367
369
|
|
|
@@ -13,6 +13,7 @@ require_relative 'generated/chat_client'
|
|
|
13
13
|
require_relative 'generated/video_client'
|
|
14
14
|
require_relative 'extensions/moderation_extensions'
|
|
15
15
|
require_relative 'generated/feed'
|
|
16
|
+
require_relative 'generated/webhook'
|
|
16
17
|
require_relative 'stream_response'
|
|
17
18
|
|
|
18
19
|
module GetStreamRuby
|
|
@@ -76,6 +77,52 @@ module GetStreamRuby
|
|
|
76
77
|
GetStream::Generated::Feed.new(self, feed_group_id, feed_id)
|
|
77
78
|
end
|
|
78
79
|
|
|
80
|
+
# Verify a webhook signature using this client's API secret (CHA-2961).
|
|
81
|
+
#
|
|
82
|
+
# Convenience wrapper around StreamChat::Webhook.verify_signature that
|
|
83
|
+
# supplies the secret automatically. The module-level method is still
|
|
84
|
+
# available for callers that need to verify with an arbitrary secret.
|
|
85
|
+
#
|
|
86
|
+
# @param body [String] The raw request body (already-decompressed)
|
|
87
|
+
# @param signature [String] The signature from the X-Signature header
|
|
88
|
+
# @return [Boolean] true if the signature is valid, false otherwise
|
|
89
|
+
def verify_signature(body, signature)
|
|
90
|
+
StreamChat::Webhook.verify_signature(body, signature, @configuration.api_secret)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Verify and parse a webhook payload in one call, using this client's API
|
|
94
|
+
# secret (CHA-2961).
|
|
95
|
+
#
|
|
96
|
+
# Handles gzip-compressed bodies transparently. Raises
|
|
97
|
+
# StreamChat::Webhook::InvalidWebhookError on signature mismatch or parse
|
|
98
|
+
# failures; distinguish failure modes via the message substring.
|
|
99
|
+
#
|
|
100
|
+
# @param body [String] raw request body (possibly gzip-compressed)
|
|
101
|
+
# @param signature [String] X-Signature header value
|
|
102
|
+
# @return [Object] the typed event class instance or
|
|
103
|
+
# StreamChat::Webhook::UnknownEvent
|
|
104
|
+
# @raise [StreamChat::Webhook::InvalidWebhookError]
|
|
105
|
+
def verify_and_parse_webhook(body, signature)
|
|
106
|
+
StreamChat::Webhook.verify_and_parse_webhook(body, signature, @configuration.api_secret)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Decode + parse a Stream-delivered SQS message body.
|
|
110
|
+
#
|
|
111
|
+
# Convenience wrapper around StreamChat::Webhook.parse_sqs. No signature is
|
|
112
|
+
# required; SQS deliveries are authenticated via AWS IAM.
|
|
113
|
+
def parse_sqs(message_body)
|
|
114
|
+
StreamChat::Webhook.parse_sqs(message_body)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Decode + parse a Stream-delivered SNS notification body.
|
|
118
|
+
#
|
|
119
|
+
# Accepts either the raw SNS HTTP envelope JSON or the pre-extracted Message
|
|
120
|
+
# string. Convenience wrapper around StreamChat::Webhook.parse_sns. No signature
|
|
121
|
+
# is required; SNS deliveries are authenticated via AWS IAM.
|
|
122
|
+
def parse_sns(notification_body)
|
|
123
|
+
StreamChat::Webhook.parse_sns(notification_body)
|
|
124
|
+
end
|
|
125
|
+
|
|
79
126
|
# @param path [String] The API path
|
|
80
127
|
# @param body [Hash] The request body
|
|
81
128
|
# @return [GetStreamRuby::StreamResponse] The API response
|
|
@@ -981,6 +981,32 @@ module GetStream
|
|
|
981
981
|
)
|
|
982
982
|
end
|
|
983
983
|
|
|
984
|
+
# Searches mentionable roles (user-assignable + channel-assignable, built-in and custom) by name prefix for autocomplete
|
|
985
|
+
#
|
|
986
|
+
# @param query [String]
|
|
987
|
+
# @param limit [Integer]
|
|
988
|
+
# @param name_gt [String]
|
|
989
|
+
# @param role_type [String]
|
|
990
|
+
# @param include_global_roles [Boolean]
|
|
991
|
+
# @return [Models::SearchRolesResponse]
|
|
992
|
+
def search_roles(query, limit = nil, name_gt = nil, role_type = nil, include_global_roles = nil)
|
|
993
|
+
path = '/api/v2/roles/search'
|
|
994
|
+
# Build query parameters
|
|
995
|
+
query_params = {}
|
|
996
|
+
query_params['query'] = query unless query.nil?
|
|
997
|
+
query_params['limit'] = limit unless limit.nil?
|
|
998
|
+
query_params['name_gt'] = name_gt unless name_gt.nil?
|
|
999
|
+
query_params['role_type'] = role_type unless role_type.nil?
|
|
1000
|
+
query_params['include_global_roles'] = include_global_roles unless include_global_roles.nil?
|
|
1001
|
+
|
|
1002
|
+
# Make the API request
|
|
1003
|
+
@client.make_request(
|
|
1004
|
+
:get,
|
|
1005
|
+
path,
|
|
1006
|
+
query_params: query_params
|
|
1007
|
+
)
|
|
1008
|
+
end
|
|
1009
|
+
|
|
984
1010
|
# Deletes custom role
|
|
985
1011
|
#
|
|
986
1012
|
# @param name [String]
|
|
@@ -17,11 +17,13 @@ module GetStream
|
|
|
17
17
|
# Delete a single feed by its ID
|
|
18
18
|
#
|
|
19
19
|
# @param hard_delete [Boolean]
|
|
20
|
+
# @param purge_user_activities [Boolean]
|
|
20
21
|
# @return [Models::DeleteFeedResponse]
|
|
21
|
-
def delete_feed(hard_delete = nil)
|
|
22
|
+
def delete_feed(hard_delete = nil, purge_user_activities = nil)
|
|
22
23
|
# Build query parameters
|
|
23
24
|
query_params = {}
|
|
24
25
|
query_params['hard_delete'] = hard_delete unless hard_delete.nil?
|
|
26
|
+
query_params['purge_user_activities'] = purge_user_activities unless purge_user_activities.nil?
|
|
25
27
|
|
|
26
28
|
# Delegate to the FeedsClient
|
|
27
29
|
@client.feeds.delete_feed(@feed_group_id, @feed_id, query_params)
|
|
@@ -992,8 +992,9 @@ module GetStream
|
|
|
992
992
|
# @param feed_group_id [String]
|
|
993
993
|
# @param feed_id [String]
|
|
994
994
|
# @param hard_delete [Boolean]
|
|
995
|
+
# @param purge_user_activities [Boolean]
|
|
995
996
|
# @return [Models::DeleteFeedResponse]
|
|
996
|
-
def delete_feed(feed_group_id, feed_id, hard_delete = nil)
|
|
997
|
+
def delete_feed(feed_group_id, feed_id, hard_delete = nil, purge_user_activities = nil)
|
|
997
998
|
path = '/api/v2/feeds/feed_groups/{feed_group_id}/feeds/{feed_id}'
|
|
998
999
|
# Replace path parameters
|
|
999
1000
|
path = path.gsub('{feed_group_id}', feed_group_id.to_s)
|
|
@@ -1001,6 +1002,7 @@ module GetStream
|
|
|
1001
1002
|
# Build query parameters
|
|
1002
1003
|
query_params = {}
|
|
1003
1004
|
query_params['hard_delete'] = hard_delete unless hard_delete.nil?
|
|
1005
|
+
query_params['purge_user_activities'] = purge_user_activities unless purge_user_activities.nil?
|
|
1004
1006
|
|
|
1005
1007
|
# Make the API request
|
|
1006
1008
|
@client.make_request(
|
|
@@ -43,7 +43,7 @@ module GetStream
|
|
|
43
43
|
@started_at = attributes[:started_at] || attributes['started_at']
|
|
44
44
|
@task_id = attributes[:task_id] || attributes['task_id']
|
|
45
45
|
@custom = attributes[:custom] || attributes['custom']
|
|
46
|
-
@type = attributes[:type] || attributes['type'] || "export.
|
|
46
|
+
@type = attributes[:type] || attributes['type'] || "export.bulk_image_moderation.error"
|
|
47
47
|
@received_at = attributes[:received_at] || attributes['received_at'] || nil
|
|
48
48
|
end
|
|
49
49
|
|
|
@@ -15,19 +15,24 @@ module GetStream
|
|
|
15
15
|
# @!attribute hard_delete
|
|
16
16
|
# @return [Boolean] Whether to permanently delete the feeds instead of soft delete
|
|
17
17
|
attr_accessor :hard_delete
|
|
18
|
+
# @!attribute purge_user_activities
|
|
19
|
+
# @return [Boolean] When hard-deleting, also fully delete activities authored by each feed's owner from every other feed those activities were fanned out to. Default false preserves existing fan-out. Requires 'hard_delete' to be true; the request is rejected otherwise. Feeds with no recorded owner (created_by_id is empty) are silently skipped for the purge step — owner-matching against an empty string is a safety guard, not a wildcard.
|
|
20
|
+
attr_accessor :purge_user_activities
|
|
18
21
|
|
|
19
22
|
# Initialize with attributes
|
|
20
23
|
def initialize(attributes = {})
|
|
21
24
|
super(attributes)
|
|
22
25
|
@feeds = attributes[:feeds] || attributes['feeds']
|
|
23
26
|
@hard_delete = attributes[:hard_delete] || attributes['hard_delete'] || nil
|
|
27
|
+
@purge_user_activities = attributes[:purge_user_activities] || attributes['purge_user_activities'] || nil
|
|
24
28
|
end
|
|
25
29
|
|
|
26
30
|
# Override field mappings for JSON serialization
|
|
27
31
|
def self.json_field_mappings
|
|
28
32
|
{
|
|
29
33
|
feeds: 'feeds',
|
|
30
|
-
hard_delete: 'hard_delete'
|
|
34
|
+
hard_delete: 'hard_delete',
|
|
35
|
+
purge_user_activities: 'purge_user_activities'
|
|
31
36
|
}
|
|
32
37
|
end
|
|
33
38
|
end
|
|
@@ -21,6 +21,9 @@ module GetStream
|
|
|
21
21
|
# @!attribute content_type
|
|
22
22
|
# @return [String] Type of content: 'text' (default), 'message', or 'username'. Stored as-sent; only 'username' routes to the username moderation API.
|
|
23
23
|
attr_accessor :content_type
|
|
24
|
+
# @!attribute dry_run
|
|
25
|
+
# @return [Boolean] When true, run moderation and return labels without persisting the result. Useful for one-off checks (e.g. UI testers) that should not be recorded in the stored history.
|
|
26
|
+
attr_accessor :dry_run
|
|
24
27
|
# @!attribute policy
|
|
25
28
|
# @return [String] Optional moderation policy key (max 128 chars)
|
|
26
29
|
attr_accessor :policy
|
|
@@ -35,6 +38,7 @@ module GetStream
|
|
|
35
38
|
@category = attributes[:category] || attributes['category'] || nil
|
|
36
39
|
@content_id = attributes[:content_id] || attributes['content_id'] || nil
|
|
37
40
|
@content_type = attributes[:content_type] || attributes['content_type'] || nil
|
|
41
|
+
@dry_run = attributes[:dry_run] || attributes['dry_run'] || nil
|
|
38
42
|
@policy = attributes[:policy] || attributes['policy'] || nil
|
|
39
43
|
@user_id = attributes[:user_id] || attributes['user_id'] || nil
|
|
40
44
|
end
|
|
@@ -46,6 +50,7 @@ module GetStream
|
|
|
46
50
|
category: 'category',
|
|
47
51
|
content_id: 'content_id',
|
|
48
52
|
content_type: 'content_type',
|
|
53
|
+
dry_run: 'dry_run',
|
|
49
54
|
policy: 'policy',
|
|
50
55
|
user_id: 'user_id'
|
|
51
56
|
}
|
|
@@ -21,12 +21,18 @@ module GetStream
|
|
|
21
21
|
# @!attribute prev
|
|
22
22
|
# @return [String]
|
|
23
23
|
attr_accessor :prev
|
|
24
|
+
# @!attribute user_id
|
|
25
|
+
# @return [String]
|
|
26
|
+
attr_accessor :user_id
|
|
24
27
|
# @!attribute sort
|
|
25
28
|
# @return [Array<SortParamRequest>] Sorting parameters for the query
|
|
26
29
|
attr_accessor :sort
|
|
27
30
|
# @!attribute filter
|
|
28
31
|
# @return [Object] Filters to apply to the query
|
|
29
32
|
attr_accessor :filter
|
|
33
|
+
# @!attribute user
|
|
34
|
+
# @return [UserRequest]
|
|
35
|
+
attr_accessor :user
|
|
30
36
|
|
|
31
37
|
# Initialize with attributes
|
|
32
38
|
def initialize(attributes = {})
|
|
@@ -35,8 +41,10 @@ module GetStream
|
|
|
35
41
|
@limit = attributes[:limit] || attributes['limit'] || nil
|
|
36
42
|
@next = attributes[:next] || attributes['next'] || nil
|
|
37
43
|
@prev = attributes[:prev] || attributes['prev'] || nil
|
|
44
|
+
@user_id = attributes[:user_id] || attributes['user_id'] || nil
|
|
38
45
|
@sort = attributes[:sort] || attributes['sort'] || nil
|
|
39
46
|
@filter = attributes[:filter] || attributes['filter'] || nil
|
|
47
|
+
@user = attributes[:user] || attributes['user'] || nil
|
|
40
48
|
end
|
|
41
49
|
|
|
42
50
|
# Override field mappings for JSON serialization
|
|
@@ -46,8 +54,10 @@ module GetStream
|
|
|
46
54
|
limit: 'limit',
|
|
47
55
|
next: 'next',
|
|
48
56
|
prev: 'prev',
|
|
57
|
+
user_id: 'user_id',
|
|
49
58
|
sort: 'sort',
|
|
50
|
-
filter: 'filter'
|
|
59
|
+
filter: 'filter',
|
|
60
|
+
user: 'user'
|
|
51
61
|
}
|
|
52
62
|
end
|
|
53
63
|
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
|
+
#
|
|
9
|
+
class SearchRolesResponse < GetStream::BaseModel
|
|
10
|
+
|
|
11
|
+
# Model attributes
|
|
12
|
+
# @!attribute duration
|
|
13
|
+
# @return [String]
|
|
14
|
+
attr_accessor :duration
|
|
15
|
+
# @!attribute roles
|
|
16
|
+
# @return [Array<Role>] Matching roles, sorted ascending by name
|
|
17
|
+
attr_accessor :roles
|
|
18
|
+
|
|
19
|
+
# Initialize with attributes
|
|
20
|
+
def initialize(attributes = {})
|
|
21
|
+
super(attributes)
|
|
22
|
+
@duration = attributes[:duration] || attributes['duration']
|
|
23
|
+
@roles = attributes[:roles] || attributes['roles']
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Override field mappings for JSON serialization
|
|
27
|
+
def self.json_field_mappings
|
|
28
|
+
{
|
|
29
|
+
duration: 'duration',
|
|
30
|
+
roles: 'roles'
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT.
|
|
2
2
|
|
|
3
|
-
require '
|
|
3
|
+
require 'base64'
|
|
4
4
|
require 'json'
|
|
5
|
+
require 'openssl'
|
|
6
|
+
require 'time'
|
|
7
|
+
require 'zlib'
|
|
5
8
|
require_relative 'models/activity_added_event'
|
|
6
9
|
require_relative 'models/activity_deleted_event'
|
|
7
10
|
require_relative 'models/activity_feedback_event'
|
|
@@ -169,6 +172,47 @@ require_relative 'models/user_updated_event'
|
|
|
169
172
|
|
|
170
173
|
module StreamChat
|
|
171
174
|
module Webhook
|
|
175
|
+
# Raised for every webhook handling failure: signature mismatch, invalid
|
|
176
|
+
# JSON, missing/non-string +type+ field, gzip-prefixed body that fails to
|
|
177
|
+
# decompress, invalid base64 in a queue body, or a malformed SNS envelope.
|
|
178
|
+
#
|
|
179
|
+
# Rescue this single class for any webhook problem; filter on the message
|
|
180
|
+
# text or against the failure-mode constants below to differentiate.
|
|
181
|
+
class InvalidWebhookError < StandardError
|
|
182
|
+
SIGNATURE_MISMATCH = 'signature mismatch'
|
|
183
|
+
INVALID_BASE64 = 'invalid base64 encoding'
|
|
184
|
+
GZIP_FAILED = 'gzip decompression failed'
|
|
185
|
+
INVALID_JSON = 'invalid JSON payload'
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Returned by parse_event when the type discriminator is well-formed but
|
|
189
|
+
# unknown to this SDK version.
|
|
190
|
+
#
|
|
191
|
+
# Stable forward-compat surface: backend may add new event types before this
|
|
192
|
+
# SDK is regenerated. Switch on the returned object's class and include
|
|
193
|
+
# UnknownEvent as a fallback case.
|
|
194
|
+
#
|
|
195
|
+
# @!attribute [r] type
|
|
196
|
+
# @return [String] the unrecognized discriminator value
|
|
197
|
+
# @!attribute [r] created_at
|
|
198
|
+
# @return [Time, nil] parsed timestamp from the envelope, or nil if missing/unparseable
|
|
199
|
+
# @!attribute [r] raw
|
|
200
|
+
# @return [Hash] the full parsed JSON hash for inspection
|
|
201
|
+
class UnknownEvent
|
|
202
|
+
attr_reader :type, :created_at, :raw
|
|
203
|
+
|
|
204
|
+
def initialize(type:, created_at: nil, raw: {})
|
|
205
|
+
@type = type
|
|
206
|
+
@created_at = created_at
|
|
207
|
+
@raw = raw
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# gzip magic prefix (RFC 1952 §2.3.1). JSON cannot start with these bytes,
|
|
212
|
+
# so this gives unambiguous detection for Stream's always-JSON payloads.
|
|
213
|
+
GZIP_MAGIC = "\x1F\x8B".b.freeze
|
|
214
|
+
private_constant :GZIP_MAGIC
|
|
215
|
+
|
|
172
216
|
# Webhook event type constants
|
|
173
217
|
EVENT_TYPE_WILDCARD = '*'
|
|
174
218
|
EVENT_TYPE_APPEAL_ACCEPTED = 'appeal.accepted'
|
|
@@ -349,6 +393,9 @@ module StreamChat
|
|
|
349
393
|
|
|
350
394
|
# Deserialize a raw webhook payload into a typed event object.
|
|
351
395
|
#
|
|
396
|
+
# Throws on unknown event types. For forward-compatible parsing that returns
|
|
397
|
+
# an {UnknownEvent} on unrecognized discriminators, use {parse_event}.
|
|
398
|
+
#
|
|
352
399
|
# @param raw_event [String, Hash] The raw webhook payload
|
|
353
400
|
# @return [Object] A typed event object corresponding to the event type
|
|
354
401
|
# @raise [ArgumentError] if the event type is unknown or deserialization fails
|
|
@@ -383,339 +430,339 @@ module StreamChat
|
|
|
383
430
|
private_class_method def self.event_class_for_type(event_type)
|
|
384
431
|
case event_type
|
|
385
432
|
when '*'
|
|
386
|
-
|
|
433
|
+
GetStream::Generated::Models::CustomEvent
|
|
387
434
|
when 'appeal.accepted'
|
|
388
|
-
|
|
435
|
+
GetStream::Generated::Models::AppealAcceptedEvent
|
|
389
436
|
when 'appeal.created'
|
|
390
|
-
|
|
437
|
+
GetStream::Generated::Models::AppealCreatedEvent
|
|
391
438
|
when 'appeal.rejected'
|
|
392
|
-
|
|
439
|
+
GetStream::Generated::Models::AppealRejectedEvent
|
|
393
440
|
when 'call.accepted'
|
|
394
|
-
|
|
441
|
+
GetStream::Generated::Models::CallAcceptedEvent
|
|
395
442
|
when 'call.blocked_user'
|
|
396
|
-
|
|
443
|
+
GetStream::Generated::Models::BlockedUserEvent
|
|
397
444
|
when 'call.closed_caption'
|
|
398
|
-
|
|
445
|
+
GetStream::Generated::Models::ClosedCaptionEvent
|
|
399
446
|
when 'call.closed_captions_failed'
|
|
400
|
-
|
|
447
|
+
GetStream::Generated::Models::CallClosedCaptionsFailedEvent
|
|
401
448
|
when 'call.closed_captions_started'
|
|
402
|
-
|
|
449
|
+
GetStream::Generated::Models::CallClosedCaptionsStartedEvent
|
|
403
450
|
when 'call.closed_captions_stopped'
|
|
404
|
-
|
|
451
|
+
GetStream::Generated::Models::CallClosedCaptionsStoppedEvent
|
|
405
452
|
when 'call.created'
|
|
406
|
-
|
|
453
|
+
GetStream::Generated::Models::CallCreatedEvent
|
|
407
454
|
when 'call.deleted'
|
|
408
|
-
|
|
455
|
+
GetStream::Generated::Models::CallDeletedEvent
|
|
409
456
|
when 'call.dtmf'
|
|
410
|
-
|
|
457
|
+
GetStream::Generated::Models::CallDTMFEvent
|
|
411
458
|
when 'call.ended'
|
|
412
|
-
|
|
459
|
+
GetStream::Generated::Models::CallEndedEvent
|
|
413
460
|
when 'call.frame_recording_failed'
|
|
414
|
-
|
|
461
|
+
GetStream::Generated::Models::CallFrameRecordingFailedEvent
|
|
415
462
|
when 'call.frame_recording_ready'
|
|
416
|
-
|
|
463
|
+
GetStream::Generated::Models::CallFrameRecordingFrameReadyEvent
|
|
417
464
|
when 'call.frame_recording_started'
|
|
418
|
-
|
|
465
|
+
GetStream::Generated::Models::CallFrameRecordingStartedEvent
|
|
419
466
|
when 'call.frame_recording_stopped'
|
|
420
|
-
|
|
467
|
+
GetStream::Generated::Models::CallFrameRecordingStoppedEvent
|
|
421
468
|
when 'call.hls_broadcasting_failed'
|
|
422
|
-
|
|
469
|
+
GetStream::Generated::Models::CallHLSBroadcastingFailedEvent
|
|
423
470
|
when 'call.hls_broadcasting_started'
|
|
424
|
-
|
|
471
|
+
GetStream::Generated::Models::CallHLSBroadcastingStartedEvent
|
|
425
472
|
when 'call.hls_broadcasting_stopped'
|
|
426
|
-
|
|
473
|
+
GetStream::Generated::Models::CallHLSBroadcastingStoppedEvent
|
|
427
474
|
when 'call.kicked_user'
|
|
428
|
-
|
|
475
|
+
GetStream::Generated::Models::KickedUserEvent
|
|
429
476
|
when 'call.live_started'
|
|
430
|
-
|
|
477
|
+
GetStream::Generated::Models::CallLiveStartedEvent
|
|
431
478
|
when 'call.member_added'
|
|
432
|
-
|
|
479
|
+
GetStream::Generated::Models::CallMemberAddedEvent
|
|
433
480
|
when 'call.member_removed'
|
|
434
|
-
|
|
481
|
+
GetStream::Generated::Models::CallMemberRemovedEvent
|
|
435
482
|
when 'call.member_updated'
|
|
436
|
-
|
|
483
|
+
GetStream::Generated::Models::CallMemberUpdatedEvent
|
|
437
484
|
when 'call.member_updated_permission'
|
|
438
|
-
|
|
485
|
+
GetStream::Generated::Models::CallMemberUpdatedPermissionEvent
|
|
439
486
|
when 'call.missed'
|
|
440
|
-
|
|
487
|
+
GetStream::Generated::Models::CallMissedEvent
|
|
441
488
|
when 'call.moderation_blur'
|
|
442
|
-
|
|
489
|
+
GetStream::Generated::Models::CallModerationBlurEvent
|
|
443
490
|
when 'call.moderation_warning'
|
|
444
|
-
|
|
491
|
+
GetStream::Generated::Models::CallModerationWarningEvent
|
|
445
492
|
when 'call.notification'
|
|
446
|
-
|
|
493
|
+
GetStream::Generated::Models::CallNotificationEvent
|
|
447
494
|
when 'call.permission_request'
|
|
448
|
-
|
|
495
|
+
GetStream::Generated::Models::PermissionRequestEvent
|
|
449
496
|
when 'call.permissions_updated'
|
|
450
|
-
|
|
497
|
+
GetStream::Generated::Models::UpdatedCallPermissionsEvent
|
|
451
498
|
when 'call.reaction_new'
|
|
452
|
-
|
|
499
|
+
GetStream::Generated::Models::CallReactionEvent
|
|
453
500
|
when 'call.recording_failed'
|
|
454
|
-
|
|
501
|
+
GetStream::Generated::Models::CallRecordingFailedEvent
|
|
455
502
|
when 'call.recording_ready'
|
|
456
|
-
|
|
503
|
+
GetStream::Generated::Models::CallRecordingReadyEvent
|
|
457
504
|
when 'call.recording_started'
|
|
458
|
-
|
|
505
|
+
GetStream::Generated::Models::CallRecordingStartedEvent
|
|
459
506
|
when 'call.recording_stopped'
|
|
460
|
-
|
|
507
|
+
GetStream::Generated::Models::CallRecordingStoppedEvent
|
|
461
508
|
when 'call.rejected'
|
|
462
|
-
|
|
509
|
+
GetStream::Generated::Models::CallRejectedEvent
|
|
463
510
|
when 'call.ring'
|
|
464
|
-
|
|
511
|
+
GetStream::Generated::Models::CallRingEvent
|
|
465
512
|
when 'call.rtmp_broadcast_failed'
|
|
466
|
-
|
|
513
|
+
GetStream::Generated::Models::CallRtmpBroadcastFailedEvent
|
|
467
514
|
when 'call.rtmp_broadcast_started'
|
|
468
|
-
|
|
515
|
+
GetStream::Generated::Models::CallRtmpBroadcastStartedEvent
|
|
469
516
|
when 'call.rtmp_broadcast_stopped'
|
|
470
|
-
|
|
517
|
+
GetStream::Generated::Models::CallRtmpBroadcastStoppedEvent
|
|
471
518
|
when 'call.session_ended'
|
|
472
|
-
|
|
519
|
+
GetStream::Generated::Models::CallSessionEndedEvent
|
|
473
520
|
when 'call.session_participant_count_updated'
|
|
474
|
-
|
|
521
|
+
GetStream::Generated::Models::CallSessionParticipantCountsUpdatedEvent
|
|
475
522
|
when 'call.session_participant_joined'
|
|
476
|
-
|
|
523
|
+
GetStream::Generated::Models::CallSessionParticipantJoinedEvent
|
|
477
524
|
when 'call.session_participant_left'
|
|
478
|
-
|
|
525
|
+
GetStream::Generated::Models::CallSessionParticipantLeftEvent
|
|
479
526
|
when 'call.session_started'
|
|
480
|
-
|
|
527
|
+
GetStream::Generated::Models::CallSessionStartedEvent
|
|
481
528
|
when 'call.stats_report_ready'
|
|
482
|
-
|
|
529
|
+
GetStream::Generated::Models::CallStatsReportReadyEvent
|
|
483
530
|
when 'call.transcription_failed'
|
|
484
|
-
|
|
531
|
+
GetStream::Generated::Models::CallTranscriptionFailedEvent
|
|
485
532
|
when 'call.transcription_ready'
|
|
486
|
-
|
|
533
|
+
GetStream::Generated::Models::CallTranscriptionReadyEvent
|
|
487
534
|
when 'call.transcription_started'
|
|
488
|
-
|
|
535
|
+
GetStream::Generated::Models::CallTranscriptionStartedEvent
|
|
489
536
|
when 'call.transcription_stopped'
|
|
490
|
-
|
|
537
|
+
GetStream::Generated::Models::CallTranscriptionStoppedEvent
|
|
491
538
|
when 'call.unblocked_user'
|
|
492
|
-
|
|
539
|
+
GetStream::Generated::Models::UnblockedUserEvent
|
|
493
540
|
when 'call.updated'
|
|
494
|
-
|
|
541
|
+
GetStream::Generated::Models::CallUpdatedEvent
|
|
495
542
|
when 'call.user_feedback_submitted'
|
|
496
|
-
|
|
543
|
+
GetStream::Generated::Models::CallUserFeedbackSubmittedEvent
|
|
497
544
|
when 'call.user_muted'
|
|
498
|
-
|
|
545
|
+
GetStream::Generated::Models::CallUserMutedEvent
|
|
499
546
|
when 'campaign.completed'
|
|
500
|
-
|
|
547
|
+
GetStream::Generated::Models::CampaignCompletedEvent
|
|
501
548
|
when 'campaign.started'
|
|
502
|
-
|
|
549
|
+
GetStream::Generated::Models::CampaignStartedEvent
|
|
503
550
|
when 'channel.created'
|
|
504
|
-
|
|
551
|
+
GetStream::Generated::Models::ChannelCreatedEvent
|
|
505
552
|
when 'channel.deleted'
|
|
506
|
-
|
|
553
|
+
GetStream::Generated::Models::ChannelDeletedEvent
|
|
507
554
|
when 'channel.frozen'
|
|
508
|
-
|
|
555
|
+
GetStream::Generated::Models::ChannelFrozenEvent
|
|
509
556
|
when 'channel.hidden'
|
|
510
|
-
|
|
557
|
+
GetStream::Generated::Models::ChannelHiddenEvent
|
|
511
558
|
when 'channel.max_streak_changed'
|
|
512
|
-
|
|
559
|
+
GetStream::Generated::Models::MaxStreakChangedEvent
|
|
513
560
|
when 'channel.muted'
|
|
514
|
-
|
|
561
|
+
GetStream::Generated::Models::ChannelMutedEvent
|
|
515
562
|
when 'channel.truncated'
|
|
516
|
-
|
|
563
|
+
GetStream::Generated::Models::ChannelTruncatedEvent
|
|
517
564
|
when 'channel.unfrozen'
|
|
518
|
-
|
|
565
|
+
GetStream::Generated::Models::ChannelUnFrozenEvent
|
|
519
566
|
when 'channel.unmuted'
|
|
520
|
-
|
|
567
|
+
GetStream::Generated::Models::ChannelUnmutedEvent
|
|
521
568
|
when 'channel.updated'
|
|
522
|
-
|
|
569
|
+
GetStream::Generated::Models::ChannelUpdatedEvent
|
|
523
570
|
when 'channel.visible'
|
|
524
|
-
|
|
571
|
+
GetStream::Generated::Models::ChannelVisibleEvent
|
|
525
572
|
when 'channel_batch_update.completed'
|
|
526
|
-
|
|
573
|
+
GetStream::Generated::Models::ChannelBatchCompletedEvent
|
|
527
574
|
when 'channel_batch_update.started'
|
|
528
|
-
|
|
575
|
+
GetStream::Generated::Models::ChannelBatchStartedEvent
|
|
529
576
|
when 'custom'
|
|
530
|
-
|
|
577
|
+
GetStream::Generated::Models::CustomVideoEvent
|
|
531
578
|
when 'export.bulk_image_moderation.error'
|
|
532
|
-
|
|
579
|
+
GetStream::Generated::Models::AsyncExportErrorEvent
|
|
533
580
|
when 'export.bulk_image_moderation.success'
|
|
534
|
-
|
|
581
|
+
GetStream::Generated::Models::AsyncBulkImageModerationEvent
|
|
535
582
|
when 'export.channels.error'
|
|
536
|
-
|
|
583
|
+
GetStream::Generated::Models::AsyncExportErrorEvent
|
|
537
584
|
when 'export.channels.success'
|
|
538
|
-
|
|
585
|
+
GetStream::Generated::Models::AsyncExportChannelsEvent
|
|
539
586
|
when 'export.moderation_logs.error'
|
|
540
|
-
|
|
587
|
+
GetStream::Generated::Models::AsyncExportErrorEvent
|
|
541
588
|
when 'export.moderation_logs.success'
|
|
542
|
-
|
|
589
|
+
GetStream::Generated::Models::AsyncExportModerationLogsEvent
|
|
543
590
|
when 'export.users.error'
|
|
544
|
-
|
|
591
|
+
GetStream::Generated::Models::AsyncExportErrorEvent
|
|
545
592
|
when 'export.users.success'
|
|
546
|
-
|
|
593
|
+
GetStream::Generated::Models::AsyncExportUsersEvent
|
|
547
594
|
when 'feeds.activity.added'
|
|
548
|
-
|
|
595
|
+
GetStream::Generated::Models::ActivityAddedEvent
|
|
549
596
|
when 'feeds.activity.deleted'
|
|
550
|
-
|
|
597
|
+
GetStream::Generated::Models::ActivityDeletedEvent
|
|
551
598
|
when 'feeds.activity.feedback'
|
|
552
|
-
|
|
599
|
+
GetStream::Generated::Models::ActivityFeedbackEvent
|
|
553
600
|
when 'feeds.activity.marked'
|
|
554
|
-
|
|
601
|
+
GetStream::Generated::Models::ActivityMarkEvent
|
|
555
602
|
when 'feeds.activity.pinned'
|
|
556
|
-
|
|
603
|
+
GetStream::Generated::Models::ActivityPinnedEvent
|
|
557
604
|
when 'feeds.activity.reaction.added'
|
|
558
|
-
|
|
605
|
+
GetStream::Generated::Models::ActivityReactionAddedEvent
|
|
559
606
|
when 'feeds.activity.reaction.deleted'
|
|
560
|
-
|
|
607
|
+
GetStream::Generated::Models::ActivityReactionDeletedEvent
|
|
561
608
|
when 'feeds.activity.reaction.updated'
|
|
562
|
-
|
|
609
|
+
GetStream::Generated::Models::ActivityReactionUpdatedEvent
|
|
563
610
|
when 'feeds.activity.removed_from_feed'
|
|
564
|
-
|
|
611
|
+
GetStream::Generated::Models::ActivityRemovedFromFeedEvent
|
|
565
612
|
when 'feeds.activity.restored'
|
|
566
|
-
|
|
613
|
+
GetStream::Generated::Models::ActivityRestoredEvent
|
|
567
614
|
when 'feeds.activity.unpinned'
|
|
568
|
-
|
|
615
|
+
GetStream::Generated::Models::ActivityUnpinnedEvent
|
|
569
616
|
when 'feeds.activity.updated'
|
|
570
|
-
|
|
617
|
+
GetStream::Generated::Models::ActivityUpdatedEvent
|
|
571
618
|
when 'feeds.bookmark.added'
|
|
572
|
-
|
|
619
|
+
GetStream::Generated::Models::BookmarkAddedEvent
|
|
573
620
|
when 'feeds.bookmark.deleted'
|
|
574
|
-
|
|
621
|
+
GetStream::Generated::Models::BookmarkDeletedEvent
|
|
575
622
|
when 'feeds.bookmark.updated'
|
|
576
|
-
|
|
623
|
+
GetStream::Generated::Models::BookmarkUpdatedEvent
|
|
577
624
|
when 'feeds.bookmark_folder.deleted'
|
|
578
|
-
|
|
625
|
+
GetStream::Generated::Models::BookmarkFolderDeletedEvent
|
|
579
626
|
when 'feeds.bookmark_folder.updated'
|
|
580
|
-
|
|
627
|
+
GetStream::Generated::Models::BookmarkFolderUpdatedEvent
|
|
581
628
|
when 'feeds.comment.added'
|
|
582
|
-
|
|
629
|
+
GetStream::Generated::Models::CommentAddedEvent
|
|
583
630
|
when 'feeds.comment.deleted'
|
|
584
|
-
|
|
631
|
+
GetStream::Generated::Models::CommentDeletedEvent
|
|
585
632
|
when 'feeds.comment.reaction.added'
|
|
586
|
-
|
|
633
|
+
GetStream::Generated::Models::CommentReactionAddedEvent
|
|
587
634
|
when 'feeds.comment.reaction.deleted'
|
|
588
|
-
|
|
635
|
+
GetStream::Generated::Models::CommentReactionDeletedEvent
|
|
589
636
|
when 'feeds.comment.reaction.updated'
|
|
590
|
-
|
|
637
|
+
GetStream::Generated::Models::CommentReactionUpdatedEvent
|
|
591
638
|
when 'feeds.comment.restored'
|
|
592
|
-
|
|
639
|
+
GetStream::Generated::Models::CommentRestoredEvent
|
|
593
640
|
when 'feeds.comment.updated'
|
|
594
|
-
|
|
641
|
+
GetStream::Generated::Models::CommentUpdatedEvent
|
|
595
642
|
when 'feeds.feed.created'
|
|
596
|
-
|
|
643
|
+
GetStream::Generated::Models::FeedCreatedEvent
|
|
597
644
|
when 'feeds.feed.deleted'
|
|
598
|
-
|
|
645
|
+
GetStream::Generated::Models::FeedDeletedEvent
|
|
599
646
|
when 'feeds.feed.updated'
|
|
600
|
-
|
|
647
|
+
GetStream::Generated::Models::FeedUpdatedEvent
|
|
601
648
|
when 'feeds.feed_group.changed'
|
|
602
|
-
|
|
649
|
+
GetStream::Generated::Models::FeedGroupChangedEvent
|
|
603
650
|
when 'feeds.feed_group.deleted'
|
|
604
|
-
|
|
651
|
+
GetStream::Generated::Models::FeedGroupDeletedEvent
|
|
605
652
|
when 'feeds.feed_group.restored'
|
|
606
|
-
|
|
653
|
+
GetStream::Generated::Models::FeedGroupRestoredEvent
|
|
607
654
|
when 'feeds.feed_member.added'
|
|
608
|
-
|
|
655
|
+
GetStream::Generated::Models::FeedMemberAddedEvent
|
|
609
656
|
when 'feeds.feed_member.removed'
|
|
610
|
-
|
|
657
|
+
GetStream::Generated::Models::FeedMemberRemovedEvent
|
|
611
658
|
when 'feeds.feed_member.updated'
|
|
612
|
-
|
|
659
|
+
GetStream::Generated::Models::FeedMemberUpdatedEvent
|
|
613
660
|
when 'feeds.follow.created'
|
|
614
|
-
|
|
661
|
+
GetStream::Generated::Models::FollowCreatedEvent
|
|
615
662
|
when 'feeds.follow.deleted'
|
|
616
|
-
|
|
663
|
+
GetStream::Generated::Models::FollowDeletedEvent
|
|
617
664
|
when 'feeds.follow.updated'
|
|
618
|
-
|
|
665
|
+
GetStream::Generated::Models::FollowUpdatedEvent
|
|
619
666
|
when 'feeds.notification_feed.updated'
|
|
620
|
-
|
|
667
|
+
GetStream::Generated::Models::NotificationFeedUpdatedEvent
|
|
621
668
|
when 'feeds.stories_feed.updated'
|
|
622
|
-
|
|
669
|
+
GetStream::Generated::Models::StoriesFeedUpdatedEvent
|
|
623
670
|
when 'flag.updated'
|
|
624
|
-
|
|
671
|
+
GetStream::Generated::Models::FlagUpdatedEvent
|
|
625
672
|
when 'ingress.error'
|
|
626
|
-
|
|
673
|
+
GetStream::Generated::Models::IngressErrorEvent
|
|
627
674
|
when 'ingress.started'
|
|
628
|
-
|
|
675
|
+
GetStream::Generated::Models::IngressStartedEvent
|
|
629
676
|
when 'ingress.stopped'
|
|
630
|
-
|
|
677
|
+
GetStream::Generated::Models::IngressStoppedEvent
|
|
631
678
|
when 'member.added'
|
|
632
|
-
|
|
679
|
+
GetStream::Generated::Models::MemberAddedEvent
|
|
633
680
|
when 'member.removed'
|
|
634
|
-
|
|
681
|
+
GetStream::Generated::Models::MemberRemovedEvent
|
|
635
682
|
when 'member.updated'
|
|
636
|
-
|
|
683
|
+
GetStream::Generated::Models::MemberUpdatedEvent
|
|
637
684
|
when 'message.deleted'
|
|
638
|
-
|
|
685
|
+
GetStream::Generated::Models::MessageDeletedEvent
|
|
639
686
|
when 'message.flagged'
|
|
640
|
-
|
|
687
|
+
GetStream::Generated::Models::MessageFlaggedEvent
|
|
641
688
|
when 'message.new'
|
|
642
|
-
|
|
689
|
+
GetStream::Generated::Models::MessageNewEvent
|
|
643
690
|
when 'message.pending'
|
|
644
|
-
|
|
691
|
+
GetStream::Generated::Models::PendingMessageEvent
|
|
645
692
|
when 'message.read'
|
|
646
|
-
|
|
693
|
+
GetStream::Generated::Models::MessageReadEvent
|
|
647
694
|
when 'message.unblocked'
|
|
648
|
-
|
|
695
|
+
GetStream::Generated::Models::MessageUnblockedEvent
|
|
649
696
|
when 'message.undeleted'
|
|
650
|
-
|
|
697
|
+
GetStream::Generated::Models::MessageUndeletedEvent
|
|
651
698
|
when 'message.updated'
|
|
652
|
-
|
|
699
|
+
GetStream::Generated::Models::MessageUpdatedEvent
|
|
653
700
|
when 'moderation.custom_action'
|
|
654
|
-
|
|
701
|
+
GetStream::Generated::Models::ModerationCustomActionEvent
|
|
655
702
|
when 'moderation.flagged'
|
|
656
|
-
|
|
703
|
+
GetStream::Generated::Models::ModerationFlaggedEvent
|
|
657
704
|
when 'moderation.mark_reviewed'
|
|
658
|
-
|
|
705
|
+
GetStream::Generated::Models::ModerationMarkReviewedEvent
|
|
659
706
|
when 'moderation_check.completed'
|
|
660
|
-
|
|
707
|
+
GetStream::Generated::Models::ModerationCheckCompletedEvent
|
|
661
708
|
when 'moderation_rule.triggered'
|
|
662
|
-
|
|
709
|
+
GetStream::Generated::Models::ModerationRulesTriggeredEvent
|
|
663
710
|
when 'notification.mark_unread'
|
|
664
|
-
|
|
711
|
+
GetStream::Generated::Models::NotificationMarkUnreadEvent
|
|
665
712
|
when 'notification.reminder_due'
|
|
666
|
-
|
|
713
|
+
GetStream::Generated::Models::ReminderNotificationEvent
|
|
667
714
|
when 'notification.thread_message_new'
|
|
668
|
-
|
|
715
|
+
GetStream::Generated::Models::NotificationThreadMessageNewEvent
|
|
669
716
|
when 'reaction.deleted'
|
|
670
|
-
|
|
717
|
+
GetStream::Generated::Models::ReactionDeletedEvent
|
|
671
718
|
when 'reaction.new'
|
|
672
|
-
|
|
719
|
+
GetStream::Generated::Models::ReactionNewEvent
|
|
673
720
|
when 'reaction.updated'
|
|
674
|
-
|
|
721
|
+
GetStream::Generated::Models::ReactionUpdatedEvent
|
|
675
722
|
when 'reminder.created'
|
|
676
|
-
|
|
723
|
+
GetStream::Generated::Models::ReminderCreatedEvent
|
|
677
724
|
when 'reminder.deleted'
|
|
678
|
-
|
|
725
|
+
GetStream::Generated::Models::ReminderDeletedEvent
|
|
679
726
|
when 'reminder.updated'
|
|
680
|
-
|
|
727
|
+
GetStream::Generated::Models::ReminderUpdatedEvent
|
|
681
728
|
when 'review_queue_item.new'
|
|
682
|
-
|
|
729
|
+
GetStream::Generated::Models::ReviewQueueItemNewEvent
|
|
683
730
|
when 'review_queue_item.updated'
|
|
684
|
-
|
|
731
|
+
GetStream::Generated::Models::ReviewQueueItemUpdatedEvent
|
|
685
732
|
when 'thread.updated'
|
|
686
|
-
|
|
733
|
+
GetStream::Generated::Models::ThreadUpdatedEvent
|
|
687
734
|
when 'user.banned'
|
|
688
|
-
|
|
735
|
+
GetStream::Generated::Models::UserBannedEvent
|
|
689
736
|
when 'user.deactivated'
|
|
690
|
-
|
|
737
|
+
GetStream::Generated::Models::UserDeactivatedEvent
|
|
691
738
|
when 'user.deleted'
|
|
692
|
-
|
|
739
|
+
GetStream::Generated::Models::UserDeletedEvent
|
|
693
740
|
when 'user.flagged'
|
|
694
|
-
|
|
741
|
+
GetStream::Generated::Models::UserFlaggedEvent
|
|
695
742
|
when 'user.messages.deleted'
|
|
696
|
-
|
|
743
|
+
GetStream::Generated::Models::UserMessagesDeletedEvent
|
|
697
744
|
when 'user.muted'
|
|
698
|
-
|
|
745
|
+
GetStream::Generated::Models::UserMutedEvent
|
|
699
746
|
when 'user.reactivated'
|
|
700
|
-
|
|
747
|
+
GetStream::Generated::Models::UserReactivatedEvent
|
|
701
748
|
when 'user.unbanned'
|
|
702
|
-
|
|
749
|
+
GetStream::Generated::Models::UserUnbannedEvent
|
|
703
750
|
when 'user.unmuted'
|
|
704
|
-
|
|
751
|
+
GetStream::Generated::Models::UserUnmutedEvent
|
|
705
752
|
when 'user.unread_message_reminder'
|
|
706
|
-
|
|
753
|
+
GetStream::Generated::Models::UserUnreadReminderEvent
|
|
707
754
|
when 'user.updated'
|
|
708
|
-
|
|
755
|
+
GetStream::Generated::Models::UserUpdatedEvent
|
|
709
756
|
when 'user_group.created'
|
|
710
|
-
|
|
757
|
+
GetStream::Generated::Models::UserGroupCreatedEvent
|
|
711
758
|
when 'user_group.deleted'
|
|
712
|
-
|
|
759
|
+
GetStream::Generated::Models::UserGroupDeletedEvent
|
|
713
760
|
when 'user_group.member_added'
|
|
714
|
-
|
|
761
|
+
GetStream::Generated::Models::UserGroupMemberAddedEvent
|
|
715
762
|
when 'user_group.member_removed'
|
|
716
|
-
|
|
763
|
+
GetStream::Generated::Models::UserGroupMemberRemovedEvent
|
|
717
764
|
when 'user_group.updated'
|
|
718
|
-
|
|
765
|
+
GetStream::Generated::Models::UserGroupUpdatedEvent
|
|
719
766
|
else
|
|
720
767
|
nil
|
|
721
768
|
end
|
|
@@ -725,17 +772,201 @@ module StreamChat
|
|
|
725
772
|
|
|
726
773
|
# Verify the HMAC-SHA256 signature of a webhook payload.
|
|
727
774
|
#
|
|
728
|
-
# @param body [String] The raw request body
|
|
775
|
+
# @param body [String] The raw request body (already-decompressed)
|
|
729
776
|
# @param signature [String] The signature from the X-Signature header
|
|
730
777
|
# @param secret [String] Your webhook secret (found in the Stream Dashboard)
|
|
731
778
|
# @return [Boolean] true if the signature is valid, false otherwise
|
|
732
779
|
def self.verify_signature(body, signature, secret)
|
|
733
780
|
return false if signature.nil? || signature.bytesize != 64
|
|
734
|
-
|
|
781
|
+
|
|
735
782
|
expected = OpenSSL::HMAC.hexdigest('SHA256', secret, body)
|
|
736
783
|
OpenSSL.fixed_length_secure_compare(signature, expected)
|
|
737
784
|
rescue ArgumentError
|
|
738
785
|
false
|
|
739
786
|
end
|
|
787
|
+
|
|
788
|
+
# Decompress the body if it is gzip-prefixed (first two bytes 0x1F 0x8B),
|
|
789
|
+
# else return the body bytes unchanged.
|
|
790
|
+
#
|
|
791
|
+
# Magic-byte detection is reliable for Stream payloads because Stream webhook
|
|
792
|
+
# bodies are always JSON, and JSON cannot start with 0x1F.
|
|
793
|
+
#
|
|
794
|
+
# @param body [String] raw body (binary-safe)
|
|
795
|
+
# @return [String] decompressed body, or the original body if not gzip-prefixed
|
|
796
|
+
# @raise [InvalidWebhookError] if body has the gzip magic prefix but
|
|
797
|
+
# isn't a valid gzip stream
|
|
798
|
+
def self.gunzip_payload(body)
|
|
799
|
+
raise InvalidWebhookError, "#{InvalidWebhookError::INVALID_JSON}: body must be a String" unless body.is_a?(String)
|
|
800
|
+
|
|
801
|
+
bytes = body.b
|
|
802
|
+
return bytes if bytes.bytesize < 2 || bytes.byteslice(0, 2) != GZIP_MAGIC
|
|
803
|
+
|
|
804
|
+
Zlib.gunzip(bytes)
|
|
805
|
+
rescue Zlib::Error => e
|
|
806
|
+
raise InvalidWebhookError, "#{InvalidWebhookError::GZIP_FAILED}: #{e.message}"
|
|
807
|
+
end
|
|
808
|
+
|
|
809
|
+
# Decode an SQS Message Body: try base64 first, fall back to raw bytes if
|
|
810
|
+
# base64 fails, then gunzip if gzip-prefixed.
|
|
811
|
+
#
|
|
812
|
+
# Wire format (per CHA-3071): SQS bodies are raw JSON when
|
|
813
|
+
# enable_hook_payload_compression is off (today's default for all existing
|
|
814
|
+
# apps), and base64(gzip(json)) when it's on. This helper handles both:
|
|
815
|
+
# raw JSON starts with '{' which is not valid base64, so the base64 decode
|
|
816
|
+
# fails and we fall through to raw bytes, then {gunzip_payload}'s magic-byte
|
|
817
|
+
# detection decides whether to decompress.
|
|
818
|
+
#
|
|
819
|
+
# {parse_sqs} sits on top of this and works transparently for both wire
|
|
820
|
+
# formats — no caller code change, no flag, no header.
|
|
821
|
+
#
|
|
822
|
+
# @param message_body [String]
|
|
823
|
+
# @return [String]
|
|
824
|
+
# @raise [InvalidWebhookError] only if gzip decompression fails (input had gzip magic prefix)
|
|
825
|
+
def self.decode_sqs_payload(message_body)
|
|
826
|
+
raise InvalidWebhookError, "#{InvalidWebhookError::INVALID_JSON}: message_body must be a String" unless message_body.is_a?(String)
|
|
827
|
+
|
|
828
|
+
decoded =
|
|
829
|
+
begin
|
|
830
|
+
Base64.strict_decode64(message_body)
|
|
831
|
+
rescue ArgumentError
|
|
832
|
+
# Not base64 — treat input as raw bytes (uncompressed wire format).
|
|
833
|
+
message_body.dup.force_encoding(Encoding::ASCII_8BIT)
|
|
834
|
+
end
|
|
835
|
+
gunzip_payload(decoded)
|
|
836
|
+
end
|
|
837
|
+
|
|
838
|
+
# Return the inner +Message+ field when +body+ is a standard SNS
|
|
839
|
+
# notification envelope JSON; otherwise return +body+ unchanged so a
|
|
840
|
+
# pre-extracted Message string flows through.
|
|
841
|
+
#
|
|
842
|
+
# Heuristic: try to JSON-parse the input. If it yields a Hash with a
|
|
843
|
+
# String +Message+ field, that's the envelope shape — return the Message.
|
|
844
|
+
# Otherwise the input is presumed to BE the pre-extracted Message
|
|
845
|
+
# (base64-encoded bytes are not valid JSON, so this falls through cleanly).
|
|
846
|
+
def self.unwrap_sns_notification_body(body)
|
|
847
|
+
env = JSON.parse(body)
|
|
848
|
+
return env['Message'] if env.is_a?(Hash) && env['Message'].is_a?(String)
|
|
849
|
+
|
|
850
|
+
body
|
|
851
|
+
rescue JSON::ParserError
|
|
852
|
+
body
|
|
853
|
+
end
|
|
854
|
+
private_class_method :unwrap_sns_notification_body
|
|
855
|
+
|
|
856
|
+
# Decode an SNS notification body. Accepts either:
|
|
857
|
+
# * a full SNS HTTP notification envelope JSON
|
|
858
|
+
# ({"Type":"Notification","Message":"<base64>",...}), or
|
|
859
|
+
# * a pre-extracted Message string (forwarded-through-SQS path).
|
|
860
|
+
# The inner payload is then base64-decoded and gunzipped via
|
|
861
|
+
# {decode_sqs_payload}.
|
|
862
|
+
#
|
|
863
|
+
# @param notification_body [String]
|
|
864
|
+
# @return [String]
|
|
865
|
+
# @raise [InvalidWebhookError]
|
|
866
|
+
def self.decode_sns_payload(notification_body)
|
|
867
|
+
raise InvalidWebhookError, "#{InvalidWebhookError::INVALID_JSON}: notification_body must be a String" unless notification_body.is_a?(String)
|
|
868
|
+
|
|
869
|
+
decode_sqs_payload(unwrap_sns_notification_body(notification_body))
|
|
870
|
+
end
|
|
871
|
+
|
|
872
|
+
# Parse a webhook payload and return the typed event for known discriminators
|
|
873
|
+
# or {UnknownEvent} for well-formed-but-unknown ones.
|
|
874
|
+
#
|
|
875
|
+
# Distinct from {parse_webhook_event}: parse_event returns an UnknownEvent on
|
|
876
|
+
# unrecognized discriminators (forward-compat); parse_webhook_event throws.
|
|
877
|
+
#
|
|
878
|
+
# @param payload [String]
|
|
879
|
+
# @return [Object] the typed event class instance or {UnknownEvent}
|
|
880
|
+
# @raise [InvalidWebhookError] for invalid JSON, missing/non-string type field,
|
|
881
|
+
# or known-type deserialization failure
|
|
882
|
+
def self.parse_event(payload)
|
|
883
|
+
raise InvalidWebhookError, "#{InvalidWebhookError::INVALID_JSON}: payload must be a String" unless payload.is_a?(String)
|
|
884
|
+
raise InvalidWebhookError, "#{InvalidWebhookError::INVALID_JSON}: payload must not be empty" if payload.empty?
|
|
885
|
+
|
|
886
|
+
data = JSON.parse(payload)
|
|
887
|
+
raise InvalidWebhookError, "#{InvalidWebhookError::INVALID_JSON}: webhook payload must be a JSON object" unless data.is_a?(Hash)
|
|
888
|
+
|
|
889
|
+
event_type = data['type']
|
|
890
|
+
unless event_type.is_a?(String) && !event_type.empty?
|
|
891
|
+
raise InvalidWebhookError, "#{InvalidWebhookError::INVALID_JSON}: webhook payload missing 'type' string field"
|
|
892
|
+
end
|
|
893
|
+
|
|
894
|
+
event_class = event_class_for_type(event_type)
|
|
895
|
+
return build_unknown_event(event_type, data) if event_class.nil?
|
|
896
|
+
|
|
897
|
+
begin
|
|
898
|
+
event_class.new(data)
|
|
899
|
+
rescue StandardError => e
|
|
900
|
+
raise InvalidWebhookError, "#{InvalidWebhookError::INVALID_JSON}: failed to deserialize event: #{e.message}"
|
|
901
|
+
end
|
|
902
|
+
rescue JSON::ParserError => e
|
|
903
|
+
raise InvalidWebhookError, "#{InvalidWebhookError::INVALID_JSON}: failed to parse webhook payload: #{e.message}"
|
|
904
|
+
end
|
|
905
|
+
|
|
906
|
+
private_class_method def self.build_unknown_event(event_type, data)
|
|
907
|
+
created_raw = data['created_at']
|
|
908
|
+
created_at = nil
|
|
909
|
+
if created_raw.is_a?(String)
|
|
910
|
+
begin
|
|
911
|
+
created_at = Time.iso8601(created_raw)
|
|
912
|
+
rescue ArgumentError
|
|
913
|
+
created_at = nil
|
|
914
|
+
end
|
|
915
|
+
end
|
|
916
|
+
UnknownEvent.new(type: event_type, created_at: created_at, raw: data)
|
|
917
|
+
end
|
|
918
|
+
|
|
919
|
+
public
|
|
920
|
+
|
|
921
|
+
# HTTP composite: gunzip (if gzip-prefixed) -> verify HMAC-SHA256 -> parse.
|
|
922
|
+
#
|
|
923
|
+
# The signature header is X-Signature. The signature is HMAC-SHA256 of the
|
|
924
|
+
# *uncompressed* JSON body, hex-encoded. Magic-byte detection means callers
|
|
925
|
+
# can pass either the raw HTTP body or already-decompressed bytes; both work.
|
|
926
|
+
#
|
|
927
|
+
# @param body [String] raw request body (possibly gzip-compressed)
|
|
928
|
+
# @param signature [String] X-Signature header value
|
|
929
|
+
# @param secret [String] webhook secret
|
|
930
|
+
# @return [Object] the typed event class instance or {UnknownEvent}
|
|
931
|
+
# @raise [InvalidWebhookError] for every failure mode: signature mismatch,
|
|
932
|
+
# gunzip failure, JSON parse, type dispatch, or event deserialization
|
|
933
|
+
# failure. Filter on the message text (or the failure-mode constants
|
|
934
|
+
# on InvalidWebhookError) to differentiate.
|
|
935
|
+
def self.verify_and_parse_webhook(body, signature, secret)
|
|
936
|
+
payload = gunzip_payload(body)
|
|
937
|
+
raise InvalidWebhookError, InvalidWebhookError::SIGNATURE_MISMATCH unless verify_signature(payload, signature, secret)
|
|
938
|
+
|
|
939
|
+
parse_event(payload)
|
|
940
|
+
end
|
|
941
|
+
|
|
942
|
+
# SQS composite: base64-decode -> gunzip (if gzip-prefixed) -> parse.
|
|
943
|
+
#
|
|
944
|
+
# The backend emits no signature attribute on SQS messages today; this helper
|
|
945
|
+
# therefore performs no signature verification. If a signed variant is added
|
|
946
|
+
# later, it will be a separate function rather than retrofitting this signature.
|
|
947
|
+
#
|
|
948
|
+
# @param message_body [String]
|
|
949
|
+
# @return [Object] the typed event class instance or {UnknownEvent}
|
|
950
|
+
# @raise [InvalidWebhookError]
|
|
951
|
+
def self.parse_sqs(message_body)
|
|
952
|
+
parse_event(decode_sqs_payload(message_body))
|
|
953
|
+
end
|
|
954
|
+
|
|
955
|
+
# SNS composite: parse SNS envelope -> base64-decode -> gunzip -> parse.
|
|
956
|
+
# Same no-signature posture as {parse_sqs}.
|
|
957
|
+
#
|
|
958
|
+
# @param notification_body [String]
|
|
959
|
+
# @return [Object] the typed event class instance or {UnknownEvent}
|
|
960
|
+
# @raise [InvalidWebhookError]
|
|
961
|
+
def self.parse_sns(notification_body)
|
|
962
|
+
parse_event(decode_sns_payload(notification_body))
|
|
963
|
+
end
|
|
740
964
|
end
|
|
741
965
|
end
|
|
966
|
+
|
|
967
|
+
# Spec §7 alias: canonical name +Stream::Webhook+ aliases the existing
|
|
968
|
+
# +StreamChat::Webhook+ for one minor-version cycle. New callers should use
|
|
969
|
+
# the canonical name; existing callers continue to work unchanged.
|
|
970
|
+
module Stream
|
|
971
|
+
Webhook = StreamChat::Webhook
|
|
972
|
+
end
|
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:
|
|
4
|
+
version: 7.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-05-
|
|
11
|
+
date: 2026-05-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: dotenv
|
|
@@ -1112,6 +1112,7 @@ files:
|
|
|
1112
1112
|
- lib/getstream_ruby/generated/models/search_response.rb
|
|
1113
1113
|
- lib/getstream_ruby/generated/models/search_result.rb
|
|
1114
1114
|
- lib/getstream_ruby/generated/models/search_result_message.rb
|
|
1115
|
+
- lib/getstream_ruby/generated/models/search_roles_response.rb
|
|
1115
1116
|
- lib/getstream_ruby/generated/models/search_user_groups_response.rb
|
|
1116
1117
|
- lib/getstream_ruby/generated/models/search_warning.rb
|
|
1117
1118
|
- lib/getstream_ruby/generated/models/segment.rb
|