Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@
* `TaskError < StreamError`. Raised by `wait_for_task` when an async task finishes with `status="failed"`. Exposes `task_id`, `error_type`, `description`, `stack_trace`, `version`.
- New `Client#wait_for_task(task_id, poll_interval: 1, timeout: 60)` helper. Polls `/api/v2/tasks/:id` and: returns the task `result` payload when status reaches `completed`; raises `TaskError` when status reaches `failed`; raises `TransportError` with `error_type: "timeout"` when the deadline elapses.
- `Client#post` (and the multipart upload path) now deserialize the full canonical `APIError` envelope (`code`, `message`, `exception_fields`, `more_info`, `StatusCode`, `details`, `unrecoverable`, `duration`) and populate the new `ApiError` attributes.
- Regenerated from the latest chat OpenAPI spec. New endpoints: `Moderation#analyze`, `Moderation#bulk_action_appeals`, `Moderation#get_setup_session`, `Moderation#upsert_setup_session`; `Feeds#get_or_create_follow`, `Feeds#get_or_create_unfollow`, `Feeds#get_user_interests`; `Chat#create_segment`, `Chat#update_segment`, `Chat#add_segment_targets`; `Common#cancel_import_v2_task`; `Video#report_client_call_event`, together with the request and response models backing them.
- New webhook event types `moderation.image_analysis.complete` and `moderation.text_analysis.complete`, parsed into `ModerationImageAnalysisCompleteEvent` and `ModerationTextAnalysisCompleteEvent`.

### Changed

- The old `GetStreamRuby::APIError` constant remains as a deprecated alias for `GetStreamRuby::ApiError` for one minor cycle, slated for removal in v9.0. First access emits a one-time `Kernel.warn` deprecation notice.
- The old `GetStreamRuby::Error` constant is preserved as an alias for `StreamError`. Existing `rescue GetStreamRuby::Error` clauses continue to match.
- Pre-flight multipart validation (`file name must be provided`, `file not found`) now raises `ArgumentError` instead of the old `APIError`. These are caller-side programming errors and don't belong on the API-error surface.
- `Models::FlagResponse` now represents the full flag record (`created_at`, `updated_at`, `target_message`, `target_user`, `user`, `reason`, `details`, `custom`, and related fields). The moderation flag-action acknowledgement, which carries `item_id` and `duration`, moved to the new `Models::FlagItemResponse`; `Moderation#flag` now returns `FlagItemResponse`. The wire response of `/api/v2/moderation/flag` is unchanged, only the model name changed, so code reading `item_id`/`duration` off the parsed response is unaffected. Code referencing the `FlagResponse` model class for those two fields should switch to `FlagItemResponse`.
- `ChannelInput#config_overrides` and `ChannelDataUpdate#config_overrides` are now typed as `ChannelConfigOverrides` (the override-specific field set) instead of the full `ChannelConfig`.
- `LLMRule#description` and `TargetResolution#bitrate` are now optional.

### Webhook helpers

Expand Down
57 changes: 57 additions & 0 deletions lib/getstream_ruby/generated/chat_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1540,6 +1540,23 @@ def search(payload = nil)
)
end

# Create a segment
#
# @param create_segment_request [CreateSegmentRequest]
# @return [Models::CreateSegmentResponse]
def create_segment(create_segment_request)
path = '/api/v2/chat/segments'
# Build request body
body = create_segment_request

# Make the API request
@client.make_request(
:post,
path,
body: body
)
end

# Query segments
#
# @param query_segments_request [QuerySegmentsRequest]
Expand Down Expand Up @@ -1589,6 +1606,46 @@ def get_segment(_id)
)
end

# Update an existing segment
#
# @param _id [String]
# @param update_segment_request [UpdateSegmentRequest]
# @return [Models::UpdateSegmentResponse]
def update_segment(_id, update_segment_request)
path = '/api/v2/chat/segments/{id}'
# Replace path parameters
path = path.gsub('{id}', _id.to_s)
# Build request body
body = update_segment_request

# Make the API request
@client.make_request(
:put,
path,
body: body
)
end

# Add targets to a segment
#
# @param _id [String]
# @param add_segment_targets_request [AddSegmentTargetsRequest]
# @return [Models::Response]
def add_segment_targets(_id, add_segment_targets_request)
path = '/api/v2/chat/segments/{id}/addtargets'
# Replace path parameters
path = path.gsub('{id}', _id.to_s)
# Build request body
body = add_segment_targets_request

# Make the API request
@client.make_request(
:post,
path,
body: body
)
end

# Delete targets from a segment
#
# @param _id [String]
Expand Down
16 changes: 16 additions & 0 deletions lib/getstream_ruby/generated/common_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,22 @@ def get_import_v2_task(_id)
)
end

# Requests a controlled stop of an import v2 task. Allowed only for tasks in queued or processing state; a processing import stops cleanly on its next progress tick.
#
# @param _id [String]
# @return [Models::CancelImportV2TaskResponse]
def cancel_import_v2_task(_id)
path = '/api/v2/imports/v2/{id}/cancel'
# Replace path parameters
path = path.gsub('{id}', _id.to_s)

# Make the API request
@client.make_request(
:post,
path
)
end

# Gets an import
#
# @param _id [String]
Expand Down
55 changes: 55 additions & 0 deletions lib/getstream_ruby/generated/feeds_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1746,6 +1746,23 @@ def reject_follow(reject_follow_request)
)
end

# Creates a follow if it does not exist, or returns the existing one. Broadcasts feeds.follow.created (FollowCreatedEvent) only when the follow is newly created.
#
# @param follow_request [FollowRequest]
# @return [Models::GetOrCreateFollowResponse]
def get_or_create_follow(follow_request)
path = '/api/v2/feeds/follows/upsert'
# Build request body
body = follow_request

# Make the API request
@client.make_request(
:post,
path,
body: body
)
end

# Removes a follow and broadcasts FollowRemovedEvent
#
# @param source [String]
Expand Down Expand Up @@ -1911,6 +1928,23 @@ def get_or_create_unfollows(unfollow_batch_request)
)
end

# Removes a follow and broadcasts feeds.follow.deleted (FollowDeletedEvent). Does not return an error if the follow does not exist.
#
# @param get_or_create_unfollow_request [GetOrCreateUnfollowRequest]
# @return [Models::GetOrCreateUnfollowResponse]
def get_or_create_unfollow(get_or_create_unfollow_request)
path = '/api/v2/feeds/unfollow/upsert'
# Build request body
body = get_or_create_unfollow_request

# Make the API request
@client.make_request(
:post,
path,
body: body
)
end

# Delete all feed data for a user including: feeds, activities, follows, comments, feed reactions, bookmark folders, bookmarks, and collections owned by the user
#
# @param user_id [String]
Expand Down Expand Up @@ -1947,6 +1981,27 @@ def export_feed_user_data(user_id)
)
end

# Returns the user's most common interest tags ranked by the number of distinct activities they reacted to that carried each tag. Client-side callers may only read their own interests; server-side callers may fetch any user. Results are sorted by descending count, then alphabetically by tag.
#
# @param user_id [String]
# @param limit [Integer]
# @return [Models::GetUserInterestsResponse]
def get_user_interests(user_id, limit = nil)
path = '/api/v2/feeds/users/{user_id}/interests'
# Replace path parameters
path = path.gsub('{user_id}', user_id.to_s)
# Build query parameters
query_params = {}
query_params['limit'] = limit unless limit.nil?

# Make the API request
@client.make_request(
:get,
path,
query_params: query_params
)
end

end
end
end
31 changes: 31 additions & 0 deletions lib/getstream_ruby/generated/models/add_segment_targets_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT.

module GetStream
module Generated
module Models
#
class AddSegmentTargetsRequest < GetStream::BaseModel

# Model attributes
# @!attribute target_ids
# @return [Array<String>] Target IDs
attr_accessor :target_ids

# Initialize with attributes
def initialize(attributes = {})
super(attributes)
@target_ids = attributes[:target_ids] || attributes['target_ids']
end

# Override field mappings for JSON serialization
def self.json_field_mappings
{
target_ids: 'target_ids'
}
end
end
end
end
end
56 changes: 56 additions & 0 deletions lib/getstream_ruby/generated/models/analyze_image_field.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# frozen_string_literal: true

# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT.

module GetStream
module Generated
module Models
#
class AnalyzeImageField < GetStream::BaseModel

# Model attributes
# @!attribute action
# @return [String] Per-image action: keep | flag | remove.
attr_accessor :action
# @!attribute confidence
# @return [Float] Highest confidence (0–1) across detected classifications + sub-classifications. Convenience aggregate over the nested values in `classifications`.
attr_accessor :confidence
# @!attribute error
# @return [String] Set when moderation couldn't be determined for this image — action is absent.
attr_accessor :error
# @!attribute id
# @return [String] Echo of `content_ids[label]` when supplied on the request; omitted otherwise.
attr_accessor :id
# @!attribute classifications
# @return [Array<Classification>] Hierarchical list of L1 (parent) classifications. Each entry: `name`, `confidence` (0–1), and nested `subclassifications` (L2 leaves with their own confidence). Resolved against the app's effective taxonomy (custom taxonomy when configured, otherwise the standard Bodyguard catalogue).
attr_accessor :classifications
# @!attribute ocr_classifications
# @return [Array<Classification>] Flat list of Bodyguard OCR text-moderation labels on the image's extracted text (e.g. VULGARITY, PII). Each entry: `name` + `severity`. Populated when BG's OCR pipeline returned non-empty results for this image.
attr_accessor :ocr_classifications

# Initialize with attributes
def initialize(attributes = {})
super(attributes)
@action = attributes[:action] || attributes['action'] || nil
@confidence = attributes[:confidence] || attributes['confidence'] || nil
@error = attributes[:error] || attributes['error'] || nil
@id = attributes[:id] || attributes['id'] || nil
@classifications = attributes[:classifications] || attributes['classifications'] || nil
@ocr_classifications = attributes[:ocr_classifications] || attributes['ocr_classifications'] || nil
end

# Override field mappings for JSON serialization
def self.json_field_mappings
{
action: 'action',
confidence: 'confidence',
error: 'error',
id: 'id',
classifications: 'classifications',
ocr_classifications: 'ocr_classifications'
}
end
end
end
end
end
81 changes: 81 additions & 0 deletions lib/getstream_ruby/generated/models/analyze_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# frozen_string_literal: true

# Code generated by GetStream internal OpenAPI code generator. DO NOT EDIT.

module GetStream
module Generated
module Models
#
class AnalyzeRequest < GetStream::BaseModel

# Model attributes
# @!attribute async_response
# @return [Boolean] When true, the response carries no verdicts (status `pending`) and per-modality results arrive via `moderation.text_analysis.complete` and `moderation.image_analysis.complete` webhooks. Image moderation runs on a background worker; text moderation runs synchronously and is then delivered via webhook.
attr_accessor :async_response
# @!attribute config_key
# @return [String] Moderation policy key. Optional in stateful mode, required in stateless mode.
attr_accessor :config_key
# @!attribute content_published_at
# @return [DateTime] Original timestamp when the content was produced. Used as the `published_at` timestamp on per-content log entries that surface in `matched_contents` on aggregation-rule webhooks.
attr_accessor :content_published_at
# @!attribute entity_creator_id
# @return [String] ID of the user who created the content. Required with entity_type + entity_id; omit all three for stateless mode.
attr_accessor :entity_creator_id
# @!attribute entity_id
# @return [String] Caller-supplied content identifier. Required with entity_type + entity_creator_id; omit all three for stateless mode.
attr_accessor :entity_id
# @!attribute entity_type
# @return [String] Caller-defined entity type. Required with entity_id + entity_creator_id; omit all three for stateless mode.
attr_accessor :entity_type
# @!attribute user_id
# @return [String]
attr_accessor :user_id
# @!attribute content_ids
# @return [Hash<String, String>] Optional map from a content label (either a `texts` key or an `image:<key>` multipart label) to a caller-supplied per-instance identifier. Echoed on per-field verdicts and surfaced in `matched_contents` when an aggregation rule fires.
attr_accessor :content_ids
# @!attribute custom
# @return [Object] Arbitrary metadata surfaced in the dashboard.
attr_accessor :custom
# @!attribute texts
# @return [Hash<String, String>] Named text fields to moderate, keyed by caller label (e.g. title, description).
attr_accessor :texts
# @!attribute user
# @return [UserRequest]
attr_accessor :user

# Initialize with attributes
def initialize(attributes = {})
super(attributes)
@async_response = attributes[:async_response] || attributes['async_response'] || nil
@config_key = attributes[:config_key] || attributes['config_key'] || nil
@content_published_at = attributes[:content_published_at] || attributes['content_published_at'] || nil
@entity_creator_id = attributes[:entity_creator_id] || attributes['entity_creator_id'] || nil
@entity_id = attributes[:entity_id] || attributes['entity_id'] || nil
@entity_type = attributes[:entity_type] || attributes['entity_type'] || nil
@user_id = attributes[:user_id] || attributes['user_id'] || nil
@content_ids = attributes[:content_ids] || attributes['content_ids'] || nil
@custom = attributes[:custom] || attributes['custom'] || nil
@texts = attributes[:texts] || attributes['texts'] || nil
@user = attributes[:user] || attributes['user'] || nil
end

# Override field mappings for JSON serialization
def self.json_field_mappings
{
async_response: 'async_response',
config_key: 'config_key',
content_published_at: 'content_published_at',
entity_creator_id: 'entity_creator_id',
entity_id: 'entity_id',
entity_type: 'entity_type',
user_id: 'user_id',
content_ids: 'content_ids',
custom: 'custom',
texts: 'texts',
user: 'user'
}
end
end
end
end
end
Loading
Loading