getstream-ruby 6.1.0 → 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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +22 -6
  3. data/lib/getstream_ruby/client.rb +63 -5
  4. data/lib/getstream_ruby/configuration.rb +32 -5
  5. data/lib/getstream_ruby/generated/common_client.rb +26 -0
  6. data/lib/getstream_ruby/generated/feed.rb +3 -1
  7. data/lib/getstream_ruby/generated/feeds_client.rb +3 -1
  8. data/lib/getstream_ruby/generated/models/add_activity_request.rb +5 -0
  9. data/lib/getstream_ruby/generated/models/add_reaction_request.rb +5 -0
  10. data/lib/getstream_ruby/generated/models/bodyguard_profile_summary.rb +6 -1
  11. data/lib/getstream_ruby/generated/models/chat_draft_payload_response.rb +91 -0
  12. data/lib/getstream_ruby/generated/models/chat_draft_response.rb +56 -0
  13. data/lib/getstream_ruby/generated/models/chat_message_response.rb +59 -4
  14. data/lib/getstream_ruby/generated/models/chat_moderation_v2_response.rb +66 -0
  15. data/lib/getstream_ruby/generated/models/chat_reaction_group_response.rb +51 -0
  16. data/lib/getstream_ruby/generated/models/chat_reaction_group_user_response.rb +41 -0
  17. data/lib/getstream_ruby/generated/models/chat_reaction_response.rb +66 -0
  18. data/lib/getstream_ruby/generated/models/chat_reminder_response_data.rb +66 -0
  19. data/lib/getstream_ruby/generated/models/chat_shared_location_response_data.rb +76 -0
  20. data/lib/getstream_ruby/generated/models/delete_feeds_batch_request.rb +6 -1
  21. data/lib/getstream_ruby/generated/models/feeds_activity_location.rb +36 -0
  22. data/lib/getstream_ruby/generated/models/feeds_bookmark_response.rb +61 -0
  23. data/lib/getstream_ruby/generated/models/feeds_enriched_collection_response.rb +61 -0
  24. data/lib/getstream_ruby/generated/models/feeds_feed_response.rb +116 -0
  25. data/lib/getstream_ruby/generated/models/feeds_notification_comment.rb +46 -0
  26. data/lib/getstream_ruby/generated/models/feeds_notification_context.rb +36 -0
  27. data/lib/getstream_ruby/generated/models/feeds_notification_parent_activity.rb +51 -0
  28. data/lib/getstream_ruby/generated/models/feeds_notification_target.rb +71 -0
  29. data/lib/getstream_ruby/generated/models/feeds_notification_trigger.rb +46 -0
  30. data/lib/getstream_ruby/generated/models/feeds_reaction_group_response.rb +3 -3
  31. data/lib/getstream_ruby/generated/models/feeds_reaction_response.rb +6 -6
  32. data/lib/getstream_ruby/generated/models/feeds_v3_activity_response.rb +66 -6
  33. data/lib/getstream_ruby/generated/models/feeds_v3_comment_response.rb +17 -2
  34. data/lib/getstream_ruby/generated/models/labels_request.rb +5 -0
  35. data/lib/getstream_ruby/generated/models/query_bookmarks_request.rb +11 -1
  36. data/lib/getstream_ruby/generated/models/search_roles_response.rb +36 -0
  37. data/lib/getstream_ruby/generated/models/submit_moderation_feedback_request.rb +71 -0
  38. data/lib/getstream_ruby/generated/models/submit_moderation_feedback_response.rb +31 -0
  39. data/lib/getstream_ruby/generated/models/update_app_request.rb +5 -0
  40. data/lib/getstream_ruby/generated/models/upsert_activities_request.rb +5 -0
  41. data/lib/getstream_ruby/generated/moderation_client.rb +17 -0
  42. data/lib/getstream_ruby/generated/webhook.rb +401 -170
  43. data/lib/getstream_ruby/version.rb +1 -1
  44. data/lib/getstream_ruby.rb +2 -3
  45. metadata +22 -2
@@ -1,7 +1,10 @@
1
1
  # Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT.
2
2
 
3
- require 'openssl'
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
- StreamChat::CustomEvent
433
+ GetStream::Generated::Models::CustomEvent
387
434
  when 'appeal.accepted'
388
- StreamChat::AppealAcceptedEvent
435
+ GetStream::Generated::Models::AppealAcceptedEvent
389
436
  when 'appeal.created'
390
- StreamChat::AppealCreatedEvent
437
+ GetStream::Generated::Models::AppealCreatedEvent
391
438
  when 'appeal.rejected'
392
- StreamChat::AppealRejectedEvent
439
+ GetStream::Generated::Models::AppealRejectedEvent
393
440
  when 'call.accepted'
394
- StreamChat::CallAcceptedEvent
441
+ GetStream::Generated::Models::CallAcceptedEvent
395
442
  when 'call.blocked_user'
396
- StreamChat::BlockedUserEvent
443
+ GetStream::Generated::Models::BlockedUserEvent
397
444
  when 'call.closed_caption'
398
- StreamChat::ClosedCaptionEvent
445
+ GetStream::Generated::Models::ClosedCaptionEvent
399
446
  when 'call.closed_captions_failed'
400
- StreamChat::CallClosedCaptionsFailedEvent
447
+ GetStream::Generated::Models::CallClosedCaptionsFailedEvent
401
448
  when 'call.closed_captions_started'
402
- StreamChat::CallClosedCaptionsStartedEvent
449
+ GetStream::Generated::Models::CallClosedCaptionsStartedEvent
403
450
  when 'call.closed_captions_stopped'
404
- StreamChat::CallClosedCaptionsStoppedEvent
451
+ GetStream::Generated::Models::CallClosedCaptionsStoppedEvent
405
452
  when 'call.created'
406
- StreamChat::CallCreatedEvent
453
+ GetStream::Generated::Models::CallCreatedEvent
407
454
  when 'call.deleted'
408
- StreamChat::CallDeletedEvent
455
+ GetStream::Generated::Models::CallDeletedEvent
409
456
  when 'call.dtmf'
410
- StreamChat::CallDTMFEvent
457
+ GetStream::Generated::Models::CallDTMFEvent
411
458
  when 'call.ended'
412
- StreamChat::CallEndedEvent
459
+ GetStream::Generated::Models::CallEndedEvent
413
460
  when 'call.frame_recording_failed'
414
- StreamChat::CallFrameRecordingFailedEvent
461
+ GetStream::Generated::Models::CallFrameRecordingFailedEvent
415
462
  when 'call.frame_recording_ready'
416
- StreamChat::CallFrameRecordingFrameReadyEvent
463
+ GetStream::Generated::Models::CallFrameRecordingFrameReadyEvent
417
464
  when 'call.frame_recording_started'
418
- StreamChat::CallFrameRecordingStartedEvent
465
+ GetStream::Generated::Models::CallFrameRecordingStartedEvent
419
466
  when 'call.frame_recording_stopped'
420
- StreamChat::CallFrameRecordingStoppedEvent
467
+ GetStream::Generated::Models::CallFrameRecordingStoppedEvent
421
468
  when 'call.hls_broadcasting_failed'
422
- StreamChat::CallHLSBroadcastingFailedEvent
469
+ GetStream::Generated::Models::CallHLSBroadcastingFailedEvent
423
470
  when 'call.hls_broadcasting_started'
424
- StreamChat::CallHLSBroadcastingStartedEvent
471
+ GetStream::Generated::Models::CallHLSBroadcastingStartedEvent
425
472
  when 'call.hls_broadcasting_stopped'
426
- StreamChat::CallHLSBroadcastingStoppedEvent
473
+ GetStream::Generated::Models::CallHLSBroadcastingStoppedEvent
427
474
  when 'call.kicked_user'
428
- StreamChat::KickedUserEvent
475
+ GetStream::Generated::Models::KickedUserEvent
429
476
  when 'call.live_started'
430
- StreamChat::CallLiveStartedEvent
477
+ GetStream::Generated::Models::CallLiveStartedEvent
431
478
  when 'call.member_added'
432
- StreamChat::CallMemberAddedEvent
479
+ GetStream::Generated::Models::CallMemberAddedEvent
433
480
  when 'call.member_removed'
434
- StreamChat::CallMemberRemovedEvent
481
+ GetStream::Generated::Models::CallMemberRemovedEvent
435
482
  when 'call.member_updated'
436
- StreamChat::CallMemberUpdatedEvent
483
+ GetStream::Generated::Models::CallMemberUpdatedEvent
437
484
  when 'call.member_updated_permission'
438
- StreamChat::CallMemberUpdatedPermissionEvent
485
+ GetStream::Generated::Models::CallMemberUpdatedPermissionEvent
439
486
  when 'call.missed'
440
- StreamChat::CallMissedEvent
487
+ GetStream::Generated::Models::CallMissedEvent
441
488
  when 'call.moderation_blur'
442
- StreamChat::CallModerationBlurEvent
489
+ GetStream::Generated::Models::CallModerationBlurEvent
443
490
  when 'call.moderation_warning'
444
- StreamChat::CallModerationWarningEvent
491
+ GetStream::Generated::Models::CallModerationWarningEvent
445
492
  when 'call.notification'
446
- StreamChat::CallNotificationEvent
493
+ GetStream::Generated::Models::CallNotificationEvent
447
494
  when 'call.permission_request'
448
- StreamChat::PermissionRequestEvent
495
+ GetStream::Generated::Models::PermissionRequestEvent
449
496
  when 'call.permissions_updated'
450
- StreamChat::UpdatedCallPermissionsEvent
497
+ GetStream::Generated::Models::UpdatedCallPermissionsEvent
451
498
  when 'call.reaction_new'
452
- StreamChat::CallReactionEvent
499
+ GetStream::Generated::Models::CallReactionEvent
453
500
  when 'call.recording_failed'
454
- StreamChat::CallRecordingFailedEvent
501
+ GetStream::Generated::Models::CallRecordingFailedEvent
455
502
  when 'call.recording_ready'
456
- StreamChat::CallRecordingReadyEvent
503
+ GetStream::Generated::Models::CallRecordingReadyEvent
457
504
  when 'call.recording_started'
458
- StreamChat::CallRecordingStartedEvent
505
+ GetStream::Generated::Models::CallRecordingStartedEvent
459
506
  when 'call.recording_stopped'
460
- StreamChat::CallRecordingStoppedEvent
507
+ GetStream::Generated::Models::CallRecordingStoppedEvent
461
508
  when 'call.rejected'
462
- StreamChat::CallRejectedEvent
509
+ GetStream::Generated::Models::CallRejectedEvent
463
510
  when 'call.ring'
464
- StreamChat::CallRingEvent
511
+ GetStream::Generated::Models::CallRingEvent
465
512
  when 'call.rtmp_broadcast_failed'
466
- StreamChat::CallRtmpBroadcastFailedEvent
513
+ GetStream::Generated::Models::CallRtmpBroadcastFailedEvent
467
514
  when 'call.rtmp_broadcast_started'
468
- StreamChat::CallRtmpBroadcastStartedEvent
515
+ GetStream::Generated::Models::CallRtmpBroadcastStartedEvent
469
516
  when 'call.rtmp_broadcast_stopped'
470
- StreamChat::CallRtmpBroadcastStoppedEvent
517
+ GetStream::Generated::Models::CallRtmpBroadcastStoppedEvent
471
518
  when 'call.session_ended'
472
- StreamChat::CallSessionEndedEvent
519
+ GetStream::Generated::Models::CallSessionEndedEvent
473
520
  when 'call.session_participant_count_updated'
474
- StreamChat::CallSessionParticipantCountsUpdatedEvent
521
+ GetStream::Generated::Models::CallSessionParticipantCountsUpdatedEvent
475
522
  when 'call.session_participant_joined'
476
- StreamChat::CallSessionParticipantJoinedEvent
523
+ GetStream::Generated::Models::CallSessionParticipantJoinedEvent
477
524
  when 'call.session_participant_left'
478
- StreamChat::CallSessionParticipantLeftEvent
525
+ GetStream::Generated::Models::CallSessionParticipantLeftEvent
479
526
  when 'call.session_started'
480
- StreamChat::CallSessionStartedEvent
527
+ GetStream::Generated::Models::CallSessionStartedEvent
481
528
  when 'call.stats_report_ready'
482
- StreamChat::CallStatsReportReadyEvent
529
+ GetStream::Generated::Models::CallStatsReportReadyEvent
483
530
  when 'call.transcription_failed'
484
- StreamChat::CallTranscriptionFailedEvent
531
+ GetStream::Generated::Models::CallTranscriptionFailedEvent
485
532
  when 'call.transcription_ready'
486
- StreamChat::CallTranscriptionReadyEvent
533
+ GetStream::Generated::Models::CallTranscriptionReadyEvent
487
534
  when 'call.transcription_started'
488
- StreamChat::CallTranscriptionStartedEvent
535
+ GetStream::Generated::Models::CallTranscriptionStartedEvent
489
536
  when 'call.transcription_stopped'
490
- StreamChat::CallTranscriptionStoppedEvent
537
+ GetStream::Generated::Models::CallTranscriptionStoppedEvent
491
538
  when 'call.unblocked_user'
492
- StreamChat::UnblockedUserEvent
539
+ GetStream::Generated::Models::UnblockedUserEvent
493
540
  when 'call.updated'
494
- StreamChat::CallUpdatedEvent
541
+ GetStream::Generated::Models::CallUpdatedEvent
495
542
  when 'call.user_feedback_submitted'
496
- StreamChat::CallUserFeedbackSubmittedEvent
543
+ GetStream::Generated::Models::CallUserFeedbackSubmittedEvent
497
544
  when 'call.user_muted'
498
- StreamChat::CallUserMutedEvent
545
+ GetStream::Generated::Models::CallUserMutedEvent
499
546
  when 'campaign.completed'
500
- StreamChat::CampaignCompletedEvent
547
+ GetStream::Generated::Models::CampaignCompletedEvent
501
548
  when 'campaign.started'
502
- StreamChat::CampaignStartedEvent
549
+ GetStream::Generated::Models::CampaignStartedEvent
503
550
  when 'channel.created'
504
- StreamChat::ChannelCreatedEvent
551
+ GetStream::Generated::Models::ChannelCreatedEvent
505
552
  when 'channel.deleted'
506
- StreamChat::ChannelDeletedEvent
553
+ GetStream::Generated::Models::ChannelDeletedEvent
507
554
  when 'channel.frozen'
508
- StreamChat::ChannelFrozenEvent
555
+ GetStream::Generated::Models::ChannelFrozenEvent
509
556
  when 'channel.hidden'
510
- StreamChat::ChannelHiddenEvent
557
+ GetStream::Generated::Models::ChannelHiddenEvent
511
558
  when 'channel.max_streak_changed'
512
- StreamChat::MaxStreakChangedEvent
559
+ GetStream::Generated::Models::MaxStreakChangedEvent
513
560
  when 'channel.muted'
514
- StreamChat::ChannelMutedEvent
561
+ GetStream::Generated::Models::ChannelMutedEvent
515
562
  when 'channel.truncated'
516
- StreamChat::ChannelTruncatedEvent
563
+ GetStream::Generated::Models::ChannelTruncatedEvent
517
564
  when 'channel.unfrozen'
518
- StreamChat::ChannelUnFrozenEvent
565
+ GetStream::Generated::Models::ChannelUnFrozenEvent
519
566
  when 'channel.unmuted'
520
- StreamChat::ChannelUnmutedEvent
567
+ GetStream::Generated::Models::ChannelUnmutedEvent
521
568
  when 'channel.updated'
522
- StreamChat::ChannelUpdatedEvent
569
+ GetStream::Generated::Models::ChannelUpdatedEvent
523
570
  when 'channel.visible'
524
- StreamChat::ChannelVisibleEvent
571
+ GetStream::Generated::Models::ChannelVisibleEvent
525
572
  when 'channel_batch_update.completed'
526
- StreamChat::ChannelBatchCompletedEvent
573
+ GetStream::Generated::Models::ChannelBatchCompletedEvent
527
574
  when 'channel_batch_update.started'
528
- StreamChat::ChannelBatchStartedEvent
575
+ GetStream::Generated::Models::ChannelBatchStartedEvent
529
576
  when 'custom'
530
- StreamChat::CustomVideoEvent
577
+ GetStream::Generated::Models::CustomVideoEvent
531
578
  when 'export.bulk_image_moderation.error'
532
- StreamChat::AsyncExportErrorEvent
579
+ GetStream::Generated::Models::AsyncExportErrorEvent
533
580
  when 'export.bulk_image_moderation.success'
534
- StreamChat::AsyncBulkImageModerationEvent
581
+ GetStream::Generated::Models::AsyncBulkImageModerationEvent
535
582
  when 'export.channels.error'
536
- StreamChat::AsyncExportErrorEvent
583
+ GetStream::Generated::Models::AsyncExportErrorEvent
537
584
  when 'export.channels.success'
538
- StreamChat::AsyncExportChannelsEvent
585
+ GetStream::Generated::Models::AsyncExportChannelsEvent
539
586
  when 'export.moderation_logs.error'
540
- StreamChat::AsyncExportErrorEvent
587
+ GetStream::Generated::Models::AsyncExportErrorEvent
541
588
  when 'export.moderation_logs.success'
542
- StreamChat::AsyncExportModerationLogsEvent
589
+ GetStream::Generated::Models::AsyncExportModerationLogsEvent
543
590
  when 'export.users.error'
544
- StreamChat::AsyncExportErrorEvent
591
+ GetStream::Generated::Models::AsyncExportErrorEvent
545
592
  when 'export.users.success'
546
- StreamChat::AsyncExportUsersEvent
593
+ GetStream::Generated::Models::AsyncExportUsersEvent
547
594
  when 'feeds.activity.added'
548
- StreamChat::ActivityAddedEvent
595
+ GetStream::Generated::Models::ActivityAddedEvent
549
596
  when 'feeds.activity.deleted'
550
- StreamChat::ActivityDeletedEvent
597
+ GetStream::Generated::Models::ActivityDeletedEvent
551
598
  when 'feeds.activity.feedback'
552
- StreamChat::ActivityFeedbackEvent
599
+ GetStream::Generated::Models::ActivityFeedbackEvent
553
600
  when 'feeds.activity.marked'
554
- StreamChat::ActivityMarkEvent
601
+ GetStream::Generated::Models::ActivityMarkEvent
555
602
  when 'feeds.activity.pinned'
556
- StreamChat::ActivityPinnedEvent
603
+ GetStream::Generated::Models::ActivityPinnedEvent
557
604
  when 'feeds.activity.reaction.added'
558
- StreamChat::ActivityReactionAddedEvent
605
+ GetStream::Generated::Models::ActivityReactionAddedEvent
559
606
  when 'feeds.activity.reaction.deleted'
560
- StreamChat::ActivityReactionDeletedEvent
607
+ GetStream::Generated::Models::ActivityReactionDeletedEvent
561
608
  when 'feeds.activity.reaction.updated'
562
- StreamChat::ActivityReactionUpdatedEvent
609
+ GetStream::Generated::Models::ActivityReactionUpdatedEvent
563
610
  when 'feeds.activity.removed_from_feed'
564
- StreamChat::ActivityRemovedFromFeedEvent
611
+ GetStream::Generated::Models::ActivityRemovedFromFeedEvent
565
612
  when 'feeds.activity.restored'
566
- StreamChat::ActivityRestoredEvent
613
+ GetStream::Generated::Models::ActivityRestoredEvent
567
614
  when 'feeds.activity.unpinned'
568
- StreamChat::ActivityUnpinnedEvent
615
+ GetStream::Generated::Models::ActivityUnpinnedEvent
569
616
  when 'feeds.activity.updated'
570
- StreamChat::ActivityUpdatedEvent
617
+ GetStream::Generated::Models::ActivityUpdatedEvent
571
618
  when 'feeds.bookmark.added'
572
- StreamChat::BookmarkAddedEvent
619
+ GetStream::Generated::Models::BookmarkAddedEvent
573
620
  when 'feeds.bookmark.deleted'
574
- StreamChat::BookmarkDeletedEvent
621
+ GetStream::Generated::Models::BookmarkDeletedEvent
575
622
  when 'feeds.bookmark.updated'
576
- StreamChat::BookmarkUpdatedEvent
623
+ GetStream::Generated::Models::BookmarkUpdatedEvent
577
624
  when 'feeds.bookmark_folder.deleted'
578
- StreamChat::BookmarkFolderDeletedEvent
625
+ GetStream::Generated::Models::BookmarkFolderDeletedEvent
579
626
  when 'feeds.bookmark_folder.updated'
580
- StreamChat::BookmarkFolderUpdatedEvent
627
+ GetStream::Generated::Models::BookmarkFolderUpdatedEvent
581
628
  when 'feeds.comment.added'
582
- StreamChat::CommentAddedEvent
629
+ GetStream::Generated::Models::CommentAddedEvent
583
630
  when 'feeds.comment.deleted'
584
- StreamChat::CommentDeletedEvent
631
+ GetStream::Generated::Models::CommentDeletedEvent
585
632
  when 'feeds.comment.reaction.added'
586
- StreamChat::CommentReactionAddedEvent
633
+ GetStream::Generated::Models::CommentReactionAddedEvent
587
634
  when 'feeds.comment.reaction.deleted'
588
- StreamChat::CommentReactionDeletedEvent
635
+ GetStream::Generated::Models::CommentReactionDeletedEvent
589
636
  when 'feeds.comment.reaction.updated'
590
- StreamChat::CommentReactionUpdatedEvent
637
+ GetStream::Generated::Models::CommentReactionUpdatedEvent
591
638
  when 'feeds.comment.restored'
592
- StreamChat::CommentRestoredEvent
639
+ GetStream::Generated::Models::CommentRestoredEvent
593
640
  when 'feeds.comment.updated'
594
- StreamChat::CommentUpdatedEvent
641
+ GetStream::Generated::Models::CommentUpdatedEvent
595
642
  when 'feeds.feed.created'
596
- StreamChat::FeedCreatedEvent
643
+ GetStream::Generated::Models::FeedCreatedEvent
597
644
  when 'feeds.feed.deleted'
598
- StreamChat::FeedDeletedEvent
645
+ GetStream::Generated::Models::FeedDeletedEvent
599
646
  when 'feeds.feed.updated'
600
- StreamChat::FeedUpdatedEvent
647
+ GetStream::Generated::Models::FeedUpdatedEvent
601
648
  when 'feeds.feed_group.changed'
602
- StreamChat::FeedGroupChangedEvent
649
+ GetStream::Generated::Models::FeedGroupChangedEvent
603
650
  when 'feeds.feed_group.deleted'
604
- StreamChat::FeedGroupDeletedEvent
651
+ GetStream::Generated::Models::FeedGroupDeletedEvent
605
652
  when 'feeds.feed_group.restored'
606
- StreamChat::FeedGroupRestoredEvent
653
+ GetStream::Generated::Models::FeedGroupRestoredEvent
607
654
  when 'feeds.feed_member.added'
608
- StreamChat::FeedMemberAddedEvent
655
+ GetStream::Generated::Models::FeedMemberAddedEvent
609
656
  when 'feeds.feed_member.removed'
610
- StreamChat::FeedMemberRemovedEvent
657
+ GetStream::Generated::Models::FeedMemberRemovedEvent
611
658
  when 'feeds.feed_member.updated'
612
- StreamChat::FeedMemberUpdatedEvent
659
+ GetStream::Generated::Models::FeedMemberUpdatedEvent
613
660
  when 'feeds.follow.created'
614
- StreamChat::FollowCreatedEvent
661
+ GetStream::Generated::Models::FollowCreatedEvent
615
662
  when 'feeds.follow.deleted'
616
- StreamChat::FollowDeletedEvent
663
+ GetStream::Generated::Models::FollowDeletedEvent
617
664
  when 'feeds.follow.updated'
618
- StreamChat::FollowUpdatedEvent
665
+ GetStream::Generated::Models::FollowUpdatedEvent
619
666
  when 'feeds.notification_feed.updated'
620
- StreamChat::NotificationFeedUpdatedEvent
667
+ GetStream::Generated::Models::NotificationFeedUpdatedEvent
621
668
  when 'feeds.stories_feed.updated'
622
- StreamChat::StoriesFeedUpdatedEvent
669
+ GetStream::Generated::Models::StoriesFeedUpdatedEvent
623
670
  when 'flag.updated'
624
- StreamChat::FlagUpdatedEvent
671
+ GetStream::Generated::Models::FlagUpdatedEvent
625
672
  when 'ingress.error'
626
- StreamChat::IngressErrorEvent
673
+ GetStream::Generated::Models::IngressErrorEvent
627
674
  when 'ingress.started'
628
- StreamChat::IngressStartedEvent
675
+ GetStream::Generated::Models::IngressStartedEvent
629
676
  when 'ingress.stopped'
630
- StreamChat::IngressStoppedEvent
677
+ GetStream::Generated::Models::IngressStoppedEvent
631
678
  when 'member.added'
632
- StreamChat::MemberAddedEvent
679
+ GetStream::Generated::Models::MemberAddedEvent
633
680
  when 'member.removed'
634
- StreamChat::MemberRemovedEvent
681
+ GetStream::Generated::Models::MemberRemovedEvent
635
682
  when 'member.updated'
636
- StreamChat::MemberUpdatedEvent
683
+ GetStream::Generated::Models::MemberUpdatedEvent
637
684
  when 'message.deleted'
638
- StreamChat::MessageDeletedEvent
685
+ GetStream::Generated::Models::MessageDeletedEvent
639
686
  when 'message.flagged'
640
- StreamChat::MessageFlaggedEvent
687
+ GetStream::Generated::Models::MessageFlaggedEvent
641
688
  when 'message.new'
642
- StreamChat::MessageNewEvent
689
+ GetStream::Generated::Models::MessageNewEvent
643
690
  when 'message.pending'
644
- StreamChat::PendingMessageEvent
691
+ GetStream::Generated::Models::PendingMessageEvent
645
692
  when 'message.read'
646
- StreamChat::MessageReadEvent
693
+ GetStream::Generated::Models::MessageReadEvent
647
694
  when 'message.unblocked'
648
- StreamChat::MessageUnblockedEvent
695
+ GetStream::Generated::Models::MessageUnblockedEvent
649
696
  when 'message.undeleted'
650
- StreamChat::MessageUndeletedEvent
697
+ GetStream::Generated::Models::MessageUndeletedEvent
651
698
  when 'message.updated'
652
- StreamChat::MessageUpdatedEvent
699
+ GetStream::Generated::Models::MessageUpdatedEvent
653
700
  when 'moderation.custom_action'
654
- StreamChat::ModerationCustomActionEvent
701
+ GetStream::Generated::Models::ModerationCustomActionEvent
655
702
  when 'moderation.flagged'
656
- StreamChat::ModerationFlaggedEvent
703
+ GetStream::Generated::Models::ModerationFlaggedEvent
657
704
  when 'moderation.mark_reviewed'
658
- StreamChat::ModerationMarkReviewedEvent
705
+ GetStream::Generated::Models::ModerationMarkReviewedEvent
659
706
  when 'moderation_check.completed'
660
- StreamChat::ModerationCheckCompletedEvent
707
+ GetStream::Generated::Models::ModerationCheckCompletedEvent
661
708
  when 'moderation_rule.triggered'
662
- StreamChat::ModerationRulesTriggeredEvent
709
+ GetStream::Generated::Models::ModerationRulesTriggeredEvent
663
710
  when 'notification.mark_unread'
664
- StreamChat::NotificationMarkUnreadEvent
711
+ GetStream::Generated::Models::NotificationMarkUnreadEvent
665
712
  when 'notification.reminder_due'
666
- StreamChat::ReminderNotificationEvent
713
+ GetStream::Generated::Models::ReminderNotificationEvent
667
714
  when 'notification.thread_message_new'
668
- StreamChat::NotificationThreadMessageNewEvent
715
+ GetStream::Generated::Models::NotificationThreadMessageNewEvent
669
716
  when 'reaction.deleted'
670
- StreamChat::ReactionDeletedEvent
717
+ GetStream::Generated::Models::ReactionDeletedEvent
671
718
  when 'reaction.new'
672
- StreamChat::ReactionNewEvent
719
+ GetStream::Generated::Models::ReactionNewEvent
673
720
  when 'reaction.updated'
674
- StreamChat::ReactionUpdatedEvent
721
+ GetStream::Generated::Models::ReactionUpdatedEvent
675
722
  when 'reminder.created'
676
- StreamChat::ReminderCreatedEvent
723
+ GetStream::Generated::Models::ReminderCreatedEvent
677
724
  when 'reminder.deleted'
678
- StreamChat::ReminderDeletedEvent
725
+ GetStream::Generated::Models::ReminderDeletedEvent
679
726
  when 'reminder.updated'
680
- StreamChat::ReminderUpdatedEvent
727
+ GetStream::Generated::Models::ReminderUpdatedEvent
681
728
  when 'review_queue_item.new'
682
- StreamChat::ReviewQueueItemNewEvent
729
+ GetStream::Generated::Models::ReviewQueueItemNewEvent
683
730
  when 'review_queue_item.updated'
684
- StreamChat::ReviewQueueItemUpdatedEvent
731
+ GetStream::Generated::Models::ReviewQueueItemUpdatedEvent
685
732
  when 'thread.updated'
686
- StreamChat::ThreadUpdatedEvent
733
+ GetStream::Generated::Models::ThreadUpdatedEvent
687
734
  when 'user.banned'
688
- StreamChat::UserBannedEvent
735
+ GetStream::Generated::Models::UserBannedEvent
689
736
  when 'user.deactivated'
690
- StreamChat::UserDeactivatedEvent
737
+ GetStream::Generated::Models::UserDeactivatedEvent
691
738
  when 'user.deleted'
692
- StreamChat::UserDeletedEvent
739
+ GetStream::Generated::Models::UserDeletedEvent
693
740
  when 'user.flagged'
694
- StreamChat::UserFlaggedEvent
741
+ GetStream::Generated::Models::UserFlaggedEvent
695
742
  when 'user.messages.deleted'
696
- StreamChat::UserMessagesDeletedEvent
743
+ GetStream::Generated::Models::UserMessagesDeletedEvent
697
744
  when 'user.muted'
698
- StreamChat::UserMutedEvent
745
+ GetStream::Generated::Models::UserMutedEvent
699
746
  when 'user.reactivated'
700
- StreamChat::UserReactivatedEvent
747
+ GetStream::Generated::Models::UserReactivatedEvent
701
748
  when 'user.unbanned'
702
- StreamChat::UserUnbannedEvent
749
+ GetStream::Generated::Models::UserUnbannedEvent
703
750
  when 'user.unmuted'
704
- StreamChat::UserUnmutedEvent
751
+ GetStream::Generated::Models::UserUnmutedEvent
705
752
  when 'user.unread_message_reminder'
706
- StreamChat::UserUnreadReminderEvent
753
+ GetStream::Generated::Models::UserUnreadReminderEvent
707
754
  when 'user.updated'
708
- StreamChat::UserUpdatedEvent
755
+ GetStream::Generated::Models::UserUpdatedEvent
709
756
  when 'user_group.created'
710
- StreamChat::UserGroupCreatedEvent
757
+ GetStream::Generated::Models::UserGroupCreatedEvent
711
758
  when 'user_group.deleted'
712
- StreamChat::UserGroupDeletedEvent
759
+ GetStream::Generated::Models::UserGroupDeletedEvent
713
760
  when 'user_group.member_added'
714
- StreamChat::UserGroupMemberAddedEvent
761
+ GetStream::Generated::Models::UserGroupMemberAddedEvent
715
762
  when 'user_group.member_removed'
716
- StreamChat::UserGroupMemberRemovedEvent
763
+ GetStream::Generated::Models::UserGroupMemberRemovedEvent
717
764
  when 'user_group.updated'
718
- StreamChat::UserGroupUpdatedEvent
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