From f34b102d656e390aad16f77e185eb4c44c78753d Mon Sep 17 00:00:00 2001 From: nijeeshjoshy Date: Thu, 15 Oct 2026 01:11:42 +0200 Subject: [PATCH 1/2] feat: [CHA-5933] add scheduled messages Regenerate from chat master 39c07c8b1ce1a145a754e883721796c66467f313 and cover the scheduled message endpoints with an integration test. Co-Authored-By: Claude Opus 5.5 --- __tests__/scheduled-messages.test.ts | 125 ++++ src/gen/chat/ChannelApi.ts | 18 + src/gen/chat/ChatApi.ts | 137 ++++ src/gen/common/CommonApi.ts | 10 + src/gen/feeds/FeedsApi.ts | 11 + src/gen/model-decoders/decoders.ts | 213 +++++- src/gen/models/index.ts | 1024 +++++++++++++++++++++++--- src/gen/moderation/ModerationApi.ts | 3 + 8 files changed, 1421 insertions(+), 120 deletions(-) create mode 100644 __tests__/scheduled-messages.test.ts diff --git a/__tests__/scheduled-messages.test.ts b/__tests__/scheduled-messages.test.ts new file mode 100644 index 0000000..82f908d --- /dev/null +++ b/__tests__/scheduled-messages.test.ts @@ -0,0 +1,125 @@ +import 'dotenv/config'; +import { afterAll, beforeAll, describe, expect, it } from 'vitest'; +import { createTestClient } from './create-test-client'; +import { StreamChannel } from '../src/StreamChannel'; +import { StreamClient } from '../src/StreamClient'; +import { StreamError } from '../src/types'; +import { randomUUID } from 'crypto'; + +// Error code the API returns when scheduled messages are off for the app. +const SCHEDULED_MESSAGES_DISABLED = 114; + +const inOneHour = () => new Date(Date.now() + 60 * 60 * 1000); + +describe('scheduled messages API', () => { + let client: StreamClient; + const channelId = 'streamnodetest' + randomUUID(); + let channel: StreamChannel; + const user = { + id: 'stream-node-test-user', + name: 'Stream Node Test User', + role: 'admin', + }; + // Set when the app supports scheduled messages: the feature is opt-in per + // app, and backends without it ignore scheduled_at and send right away. + let scheduledMessageId: string | undefined; + + beforeAll(async () => { + client = createTestClient(); + + await client.upsertUsers([user]); + + channel = client.chat.channel('messaging', channelId); + await channel.getOrCreate({ + data: { + created_by_id: user.id, + members: [{ user_id: user.id }], + }, + }); + + try { + const response = await channel.sendMessage({ + message: { text: 'Scheduled from Stream Node SDK', user_id: user.id }, + scheduled_at: inOneHour(), + }); + scheduledMessageId = response.scheduled_message?.id; + } catch (error) { + if ( + !(error instanceof StreamError) || + error.code !== SCHEDULED_MESSAGES_DISABLED + ) { + throw error; + } + } + }); + + it('schedule a message', async (ctx) => { + if (!scheduledMessageId) ctx.skip(); + + const response = await client.chat.queryScheduledMessages({ + user_id: user.id, + filter: { cid: channel.cid }, + }); + + expect(response.scheduled_messages.length).toBe(1); + const scheduled = response.scheduled_messages[0]; + expect(scheduled.id).toBe(scheduledMessageId); + expect(scheduled.status).toBe('scheduled'); + expect(scheduled.cid).toBe(channel.cid); + expect(scheduled.message.text).toBe('Scheduled from Stream Node SDK'); + expect(scheduled.scheduled_at).toBeInstanceOf(Date); + }); + + it('update a scheduled message', async (ctx) => { + if (!scheduledMessageId) ctx.skip(); + + const scheduledAt = inOneHour(); + const response = await client.chat.updateScheduledMessage({ + id: scheduledMessageId!, + scheduled_at: scheduledAt, + message: { text: 'Rescheduled from Stream Node SDK' }, + }); + + expect(response.scheduled_message.message.text).toBe( + 'Rescheduled from Stream Node SDK', + ); + expect(response.scheduled_message.scheduled_at.getTime()).toBe( + scheduledAt.getTime(), + ); + }); + + it('send a scheduled message now', async (ctx) => { + if (!scheduledMessageId) ctx.skip(); + + const response = await client.chat.sendScheduledMessageNow({ + id: scheduledMessageId!, + }); + + expect(response.scheduled_message.id).toBe(scheduledMessageId); + }); + + it('delete a scheduled message', async (ctx) => { + if (!scheduledMessageId) ctx.skip(); + + const sendResponse = await channel.sendMessage({ + message: { text: 'Deleted before sending', user_id: user.id }, + scheduled_at: inOneHour(), + }); + const id = sendResponse.scheduled_message!.id; + + const response = await client.chat.deleteScheduledMessage({ id }); + + expect(response.scheduled_message.id).toBe(id); + expect(response.scheduled_message.status).toBe('canceled'); + + const queryResponse = await client.chat.queryScheduledMessages({ + user_id: user.id, + filter: { cid: channel.cid }, + }); + expect(queryResponse.scheduled_messages.map((m) => m.id)).not.toContain(id); + }); + + afterAll(async () => { + await channel.delete({ hard_delete: true }); + }); +}); diff --git a/src/gen/chat/ChannelApi.ts b/src/gen/chat/ChannelApi.ts index 8d793e3..1c4f16c 100644 --- a/src/gen/chat/ChannelApi.ts +++ b/src/gen/chat/ChannelApi.ts @@ -12,6 +12,8 @@ import { MarkReadRequest, MarkReadResponse, MarkUnreadRequest, + QueryChannelBansRequest, + QueryChannelBansResponse, Response, SendEventRequest, SendMessageRequest, @@ -114,6 +116,22 @@ export class ChannelApi { }); } + queryChannelBans( + request?: QueryChannelBansRequest, + ): Promise> { + if (!this.id) { + throw new Error( + `Channel isn't yet created, call getOrCreateDistinctChannel() before this operation`, + ); + } + + return this.chatApi.queryChannelBans({ + id: this.id, + type: this.type, + ...request, + }); + } + deleteDraft(request?: { parent_id?: string; user_id?: string; diff --git a/src/gen/chat/ChatApi.ts b/src/gen/chat/ChatApi.ts index 0e4388d..44e7f65 100644 --- a/src/gen/chat/ChatApi.ts +++ b/src/gen/chat/ChatApi.ts @@ -30,6 +30,7 @@ import { DeleteReminderResponse, DeleteRetentionPolicyRequest, DeleteRetentionPolicyResponse, + DeleteScheduledMessageResponse, DeleteSegmentTargetsRequest, EventResponse, ExportChannelsRequest, @@ -71,6 +72,8 @@ import { QueryBannedUsersResponse, QueryCampaignsRequest, QueryCampaignsResponse, + QueryChannelBansRequest, + QueryChannelBansResponse, QueryChannelsRequest, QueryChannelsResponse, QueryDraftsRequest, @@ -87,6 +90,8 @@ import { QueryReactionsResponse, QueryRemindersRequest, QueryRemindersResponse, + QueryScheduledMessagesRequest, + QueryScheduledMessagesResponse, QuerySegmentTargetsRequest, QuerySegmentTargetsResponse, QuerySegmentsRequest, @@ -103,6 +108,8 @@ import { SendMessageResponse, SendReactionRequest, SendReactionResponse, + SendScheduledMessageNowRequest, + SendScheduledMessageNowResponse, SendUserCustomEventRequest, SetRetentionPolicyRequest, SetRetentionPolicyResponse, @@ -141,6 +148,8 @@ import { UpdatePredefinedFilterResponse, UpdateReminderRequest, UpdateReminderResponse, + UpdateScheduledMessageRequest, + UpdateScheduledMessageResponse, UpdateSegmentRequest, UpdateSegmentResponse, UpdateThreadPartialRequest, @@ -452,6 +461,7 @@ export class ChatApi { const body = { limit: request?.limit, user_id: request?.user_id, + sort: request?.sort, groups: request?.groups, user: request?.user, }; @@ -661,6 +671,37 @@ export class ChatApi { return response; } + async queryChannelBans( + request: QueryChannelBansRequest & { type: string; id: string }, + ): Promise> { + const pathParams = { + type: request?.type, + id: request?.id, + }; + const body = { + exclude_expired_bans: request?.exclude_expired_bans, + include_total: request?.include_total, + limit: request?.limit, + next: request?.next, + prev: request?.prev, + user_id: request?.user_id, + filter_conditions: request?.filter_conditions, + user: request?.user, + }; + + const response = await this.apiClient.sendRequest( + 'POST', + '/api/v2/chat/channels/{type}/{id}/bans/query', + pathParams, + undefined, + body, + ); + + decoders['QueryChannelBansResponse']?.(response); + + return response; + } + async deleteDraft(request: { type: string; id: string; @@ -916,6 +957,7 @@ export class ChatApi { include_mentioned_members: request?.include_mentioned_members, keep_channel_hidden: request?.keep_channel_hidden, pending: request?.pending, + scheduled_at: request?.scheduled_at, skip_enrich_url: request?.skip_enrich_url, skip_push: request?.skip_push, pending_message_metadata: request?.pending_message_metadata, @@ -1854,6 +1896,8 @@ export class ChatApi { poll_id: request?.poll_id, }; const body = { + config_key: request?.config_key, + config_team: request?.config_team, user_id: request?.user_id, user: request?.user, vote: request?.vote, @@ -2339,6 +2383,99 @@ export class ChatApi { return response; } + async queryScheduledMessages( + request?: QueryScheduledMessagesRequest, + ): Promise> { + const body = { + limit: request?.limit, + next: request?.next, + user_id: request?.user_id, + sort: request?.sort, + filter: request?.filter, + user: request?.user, + }; + + const response = + await this.apiClient.sendRequest( + 'POST', + '/api/v2/chat/scheduled_messages/query', + undefined, + undefined, + body, + ); + + decoders['QueryScheduledMessagesResponse']?.(response); + + return response; + } + + async deleteScheduledMessage(request: { + id: string; + }): Promise> { + const pathParams = { + id: request?.id, + }; + + const response = + await this.apiClient.sendRequest( + 'DELETE', + '/api/v2/chat/scheduled_messages/{id}', + pathParams, + undefined, + ); + + decoders['DeleteScheduledMessageResponse']?.(response); + + return response; + } + + async updateScheduledMessage( + request: UpdateScheduledMessageRequest & { id: string }, + ): Promise> { + const pathParams = { + id: request?.id, + }; + const body = { + scheduled_at: request?.scheduled_at, + message: request?.message, + }; + + const response = + await this.apiClient.sendRequest( + 'PATCH', + '/api/v2/chat/scheduled_messages/{id}', + pathParams, + undefined, + body, + ); + + decoders['UpdateScheduledMessageResponse']?.(response); + + return response; + } + + async sendScheduledMessageNow( + request: SendScheduledMessageNowRequest & { id: string }, + ): Promise> { + const pathParams = { + id: request?.id, + }; + const body = {}; + + const response = + await this.apiClient.sendRequest( + 'POST', + '/api/v2/chat/scheduled_messages/{id}/send_now', + pathParams, + undefined, + body, + ); + + decoders['SendScheduledMessageNowResponse']?.(response); + + return response; + } + async search(request?: { payload?: SearchPayload; }): Promise> { diff --git a/src/gen/common/CommonApi.ts b/src/gen/common/CommonApi.ts index 0c9b712..557da90 100644 --- a/src/gen/common/CommonApi.ts +++ b/src/gen/common/CommonApi.ts @@ -1071,6 +1071,8 @@ export class CommonApi { name: request?.name, allow_answers: request?.allow_answers, allow_user_suggested_options: request?.allow_user_suggested_options, + config_key: request?.config_key, + config_team: request?.config_team, description: request?.description, enforce_unique_vote: request?.enforce_unique_vote, id: request?.id, @@ -1105,6 +1107,8 @@ export class CommonApi { name: request?.name, allow_answers: request?.allow_answers, allow_user_suggested_options: request?.allow_user_suggested_options, + config_key: request?.config_key, + config_team: request?.config_team, description: request?.description, enforce_unique_vote: request?.enforce_unique_vote, is_closed: request?.is_closed, @@ -1209,6 +1213,8 @@ export class CommonApi { poll_id: request?.poll_id, }; const body = { + config_key: request?.config_key, + config_team: request?.config_team, user_id: request?.user_id, unset: request?.unset, set: request?.set, @@ -1236,6 +1242,8 @@ export class CommonApi { }; const body = { text: request?.text, + config_key: request?.config_key, + config_team: request?.config_team, user_id: request?.user_id, custom: request?.custom, user: request?.user, @@ -1263,6 +1271,8 @@ export class CommonApi { const body = { id: request?.id, text: request?.text, + config_key: request?.config_key, + config_team: request?.config_team, user_id: request?.user_id, custom: request?.custom, user: request?.user, diff --git a/src/gen/feeds/FeedsApi.ts b/src/gen/feeds/FeedsApi.ts index 6331934..583cf11 100644 --- a/src/gen/feeds/FeedsApi.ts +++ b/src/gen/feeds/FeedsApi.ts @@ -209,6 +209,7 @@ export class FeedsApi { poll_id: request?.poll_id, restrict_replies: request?.restrict_replies, skip_enrich_url: request?.skip_enrich_url, + skip_existing: request?.skip_existing, skip_push: request?.skip_push, text: request?.text, user_id: request?.user_id, @@ -246,6 +247,7 @@ export class FeedsApi { create_users: request?.create_users, enrich_own_fields: request?.enrich_own_fields, force_moderation: request?.force_moderation, + skip_existing: request?.skip_existing, }; const response = await this.apiClient.sendRequest( @@ -511,6 +513,8 @@ export class FeedsApi { poll_id: request?.poll_id, }; const body = { + config_key: request?.config_key, + config_team: request?.config_team, user_id: request?.user_id, user: request?.user, vote: request?.vote, @@ -975,9 +979,11 @@ export class FeedsApi { async deleteCollections(request: { collection_refs: Array; + hard_delete?: boolean; }): Promise> { const queryParams = { collection_refs: request?.collection_refs, + hard_delete: request?.hard_delete, }; const response = @@ -2697,6 +2703,7 @@ export class FeedsApi { ): Promise> { const body = { follows: request?.follows, + async: request?.async, create_users: request?.create_users, enrich_own_fields: request?.enrich_own_fields, }; @@ -2719,6 +2726,7 @@ export class FeedsApi { ): Promise> { const body = { follows: request?.follows, + async: request?.async, create_users: request?.create_users, enrich_own_fields: request?.enrich_own_fields, }; @@ -2740,6 +2748,7 @@ export class FeedsApi { request?: QueryFollowsRequest, ): Promise> { const body = { + include_group_counts: request?.include_group_counts, limit: request?.limit, next: request?.next, prev: request?.prev, @@ -3077,6 +3086,7 @@ export class FeedsApi { ): Promise> { const body = { follows: request?.follows, + async: request?.async, delete_notification_activity: request?.delete_notification_activity, enrich_own_fields: request?.enrich_own_fields, }; @@ -3099,6 +3109,7 @@ export class FeedsApi { ): Promise> { const body = { follows: request?.follows, + async: request?.async, delete_notification_activity: request?.delete_notification_activity, enrich_own_fields: request?.enrich_own_fields, }; diff --git a/src/gen/model-decoders/decoders.ts b/src/gen/model-decoders/decoders.ts index 4272d08..46369ef 100644 --- a/src/gen/model-decoders/decoders.ts +++ b/src/gen/model-decoders/decoders.ts @@ -1424,6 +1424,30 @@ decoders['ChangeFeedVisibilityResponse'] = (input?: { [key: string]: any }) => { return decode(typeMappings, input); }; +decoders['ChannelBanResponse'] = (input?: { [key: string]: any }) => { + const typeMappings: TypeMapping = { + created_at: { type: 'DatetimeType', isSingle: true }, + + channel_ban: { type: 'ChannelBanScopeResponse', isSingle: true }, + + future_channel_ban: { type: 'ChannelBanScopeResponse', isSingle: true }, + + user: { type: 'UserResponse', isSingle: true }, + }; + return decode(typeMappings, input); +}; + +decoders['ChannelBanScopeResponse'] = (input?: { [key: string]: any }) => { + const typeMappings: TypeMapping = { + created_at: { type: 'DatetimeType', isSingle: true }, + + expires: { type: 'DatetimeType', isSingle: true }, + + banned_by: { type: 'UserResponse', isSingle: true }, + }; + return decode(typeMappings, input); +}; + decoders['ChannelBatchCompletedEvent'] = (input?: { [key: string]: any }) => { const typeMappings: TypeMapping = { batch_created_at: { type: 'DatetimeType', isSingle: true }, @@ -1644,6 +1668,8 @@ decoders['ChannelStateResponse'] = (input?: { [key: string]: any }) => { read: { type: 'ReadStateResponse', isSingle: false }, + scheduled_messages: { type: 'ScheduledMessageResponse', isSingle: false }, + watchers: { type: 'UserResponse', isSingle: false }, channel: { type: 'ChannelResponse', isSingle: true }, @@ -2346,6 +2372,15 @@ decoders['DeleteReactionResponse'] = (input?: { [key: string]: any }) => { return decode(typeMappings, input); }; +decoders['DeleteScheduledMessageResponse'] = (input?: { + [key: string]: any; +}) => { + const typeMappings: TypeMapping = { + scheduled_message: { type: 'ScheduledMessageResponse', isSingle: true }, + }; + return decode(typeMappings, input); +}; + decoders['DeviceResponse'] = (input?: { [key: string]: any }) => { const typeMappings: TypeMapping = { created_at: { type: 'DatetimeType', isSingle: true }, @@ -3360,15 +3395,6 @@ decoders['IngressStoppedEvent'] = (input?: { [key: string]: any }) => { return decode(typeMappings, input); }; -decoders['IntentDetectedEvent'] = (input?: { [key: string]: any }) => { - const typeMappings: TypeMapping = { - created_at: { type: 'DatetimeType', isSingle: true }, - - received_at: { type: 'DatetimeType', isSingle: true }, - }; - return decode(typeMappings, input); -}; - decoders['KickedUserEvent'] = (input?: { [key: string]: any }) => { const typeMappings: TypeMapping = { created_at: { type: 'DatetimeType', isSingle: true }, @@ -4260,6 +4286,28 @@ decoders['PolicyTestSetResponse'] = (input?: { [key: string]: any }) => { return decode(typeMappings, input); }; +decoders['PollClosedEvent'] = (input?: { [key: string]: any }) => { + const typeMappings: TypeMapping = { + created_at: { type: 'DatetimeType', isSingle: true }, + + poll: { type: 'PollResponseData', isSingle: true }, + + received_at: { type: 'DatetimeType', isSingle: true }, + }; + return decode(typeMappings, input); +}; + +decoders['PollDeletedEvent'] = (input?: { [key: string]: any }) => { + const typeMappings: TypeMapping = { + created_at: { type: 'DatetimeType', isSingle: true }, + + poll: { type: 'PollResponseData', isSingle: true }, + + received_at: { type: 'DatetimeType', isSingle: true }, + }; + return decode(typeMappings, input); +}; + decoders['PollResponse'] = (input?: { [key: string]: any }) => { const typeMappings: TypeMapping = { poll: { type: 'PollResponseData', isSingle: true }, @@ -4282,6 +4330,56 @@ decoders['PollResponseData'] = (input?: { [key: string]: any }) => { return decode(typeMappings, input); }; +decoders['PollUpdatedEvent'] = (input?: { [key: string]: any }) => { + const typeMappings: TypeMapping = { + created_at: { type: 'DatetimeType', isSingle: true }, + + poll: { type: 'PollResponseData', isSingle: true }, + + received_at: { type: 'DatetimeType', isSingle: true }, + }; + return decode(typeMappings, input); +}; + +decoders['PollVoteCastedEvent'] = (input?: { [key: string]: any }) => { + const typeMappings: TypeMapping = { + created_at: { type: 'DatetimeType', isSingle: true }, + + poll: { type: 'PollResponseData', isSingle: true }, + + poll_vote: { type: 'PollVoteResponseData', isSingle: true }, + + received_at: { type: 'DatetimeType', isSingle: true }, + }; + return decode(typeMappings, input); +}; + +decoders['PollVoteChangedEvent'] = (input?: { [key: string]: any }) => { + const typeMappings: TypeMapping = { + created_at: { type: 'DatetimeType', isSingle: true }, + + poll: { type: 'PollResponseData', isSingle: true }, + + poll_vote: { type: 'PollVoteResponseData', isSingle: true }, + + received_at: { type: 'DatetimeType', isSingle: true }, + }; + return decode(typeMappings, input); +}; + +decoders['PollVoteRemovedEvent'] = (input?: { [key: string]: any }) => { + const typeMappings: TypeMapping = { + created_at: { type: 'DatetimeType', isSingle: true }, + + poll: { type: 'PollResponseData', isSingle: true }, + + poll_vote: { type: 'PollVoteResponseData', isSingle: true }, + + received_at: { type: 'DatetimeType', isSingle: true }, + }; + return decode(typeMappings, input); +}; + decoders['PollVoteResponse'] = (input?: { [key: string]: any }) => { const typeMappings: TypeMapping = { poll: { type: 'PollResponseData', isSingle: true }, @@ -4564,6 +4662,13 @@ decoders['QueryCampaignsResponse'] = (input?: { [key: string]: any }) => { return decode(typeMappings, input); }; +decoders['QueryChannelBansResponse'] = (input?: { [key: string]: any }) => { + const typeMappings: TypeMapping = { + bans: { type: 'ChannelBanResponse', isSingle: false }, + }; + return decode(typeMappings, input); +}; + decoders['QueryChannelsResponse'] = (input?: { [key: string]: any }) => { const typeMappings: TypeMapping = { channels: { type: 'ChannelStateResponseFields', isSingle: false }, @@ -4762,6 +4867,15 @@ decoders['QueryRevisionHistoryResponse'] = (input?: { [key: string]: any }) => { return decode(typeMappings, input); }; +decoders['QueryScheduledMessagesResponse'] = (input?: { + [key: string]: any; +}) => { + const typeMappings: TypeMapping = { + scheduled_messages: { type: 'ScheduledMessageResponse', isSingle: false }, + }; + return decode(typeMappings, input); +}; + decoders['QuerySegmentTargetsResponse'] = (input?: { [key: string]: any }) => { const typeMappings: TypeMapping = { targets: { type: 'SegmentTargetResponse', isSingle: false }, @@ -5104,6 +5218,8 @@ decoders['ReviewQueueItemResponse'] = (input?: { [key: string]: any }) => { message: { type: 'ChatMessageResponse', isSingle: true }, + poll: { type: 'PollResponseData', isSingle: true }, + reaction: { type: 'Reaction', isSingle: true }, }; return decode(typeMappings, input); @@ -5199,6 +5315,65 @@ decoders['SIPTrunkResponse'] = (input?: { [key: string]: any }) => { return decode(typeMappings, input); }; +decoders['ScheduledMessageContentResponse'] = (input?: { + [key: string]: any; +}) => { + const typeMappings: TypeMapping = { + pin_expires: { type: 'DatetimeType', isSingle: true }, + + shared_location: { type: 'ScheduledMessageLocation', isSingle: true }, + }; + return decode(typeMappings, input); +}; + +decoders['ScheduledMessageFailedEvent'] = (input?: { [key: string]: any }) => { + const typeMappings: TypeMapping = { + created_at: { type: 'DatetimeType', isSingle: true }, + + user: { type: 'UserResponseCommonFields', isSingle: true }, + + received_at: { type: 'DatetimeType', isSingle: true }, + + scheduled_message: { type: 'ScheduledMessageResponse', isSingle: true }, + }; + return decode(typeMappings, input); +}; + +decoders['ScheduledMessageLocation'] = (input?: { [key: string]: any }) => { + const typeMappings: TypeMapping = { + end_at: { type: 'DatetimeType', isSingle: true }, + }; + return decode(typeMappings, input); +}; + +decoders['ScheduledMessageResponse'] = (input?: { [key: string]: any }) => { + const typeMappings: TypeMapping = { + created_at: { type: 'DatetimeType', isSingle: true }, + + scheduled_at: { type: 'DatetimeType', isSingle: true }, + + updated_at: { type: 'DatetimeType', isSingle: true }, + + message: { type: 'ScheduledMessageContentResponse', isSingle: true }, + + user: { type: 'UserResponse', isSingle: true }, + }; + return decode(typeMappings, input); +}; + +decoders['ScheduledMessageSentEvent'] = (input?: { [key: string]: any }) => { + const typeMappings: TypeMapping = { + created_at: { type: 'DatetimeType', isSingle: true }, + + user: { type: 'UserResponseCommonFields', isSingle: true }, + + received_at: { type: 'DatetimeType', isSingle: true }, + + scheduled_message: { type: 'ScheduledMessageResponse', isSingle: true }, + }; + return decode(typeMappings, input); +}; + decoders['SearchResponse'] = (input?: { [key: string]: any }) => { const typeMappings: TypeMapping = { results: { type: 'SearchResult', isSingle: false }, @@ -5306,6 +5481,8 @@ decoders['SendMessageResponse'] = (input?: { [key: string]: any }) => { message: { type: 'MessageResponse', isSingle: true }, channel_context: { type: 'ChannelContextResponse', isSingle: true }, + + scheduled_message: { type: 'ScheduledMessageResponse', isSingle: true }, }; return decode(typeMappings, input); }; @@ -5319,6 +5496,15 @@ decoders['SendReactionResponse'] = (input?: { [key: string]: any }) => { return decode(typeMappings, input); }; +decoders['SendScheduledMessageNowResponse'] = (input?: { + [key: string]: any; +}) => { + const typeMappings: TypeMapping = { + scheduled_message: { type: 'ScheduledMessageResponse', isSingle: true }, + }; + return decode(typeMappings, input); +}; + decoders['SessionWarningResponse'] = (input?: { [key: string]: any }) => { const typeMappings: TypeMapping = { time: { type: 'DatetimeType', isSingle: true }, @@ -5885,6 +6071,15 @@ decoders['UpdateSIPTrunkResponse'] = (input?: { [key: string]: any }) => { return decode(typeMappings, input); }; +decoders['UpdateScheduledMessageResponse'] = (input?: { + [key: string]: any; +}) => { + const typeMappings: TypeMapping = { + scheduled_message: { type: 'ScheduledMessageResponse', isSingle: true }, + }; + return decode(typeMappings, input); +}; + decoders['UpdateSegmentResponse'] = (input?: { [key: string]: any }) => { const typeMappings: TypeMapping = { segment: { type: 'SegmentResponse', isSingle: true }, diff --git a/src/gen/models/index.ts b/src/gen/models/index.ts index 1beb5f3..d2cc8b9 100644 --- a/src/gen/models/index.ts +++ b/src/gen/models/index.ts @@ -93,6 +93,10 @@ export interface APIError { * Additional error-specific information */ details: Array; + /** + * Milliseconds until the user's slow mode cool down period ends. Only set on code 60 (cool down) errors + */ + cooldown_remaining_ms?: number; /** * Flag that indicates if the error is unrecoverable, requests that return unrecoverable errors should not be retried, this error only applies to the request that caused it */ @@ -1054,6 +1058,7 @@ export interface AddActivityRequest { * Whether to skip URL enrichment for the activity */ skip_enrich_url?: boolean; + skip_existing?: boolean; /** * Whether to skip push notifications */ @@ -1116,6 +1121,10 @@ export interface AddActivityResponse { * Number of mention notification activities created for mentioned users */ mention_notifications_created?: number; + /** + * Contains the activity ID when skip_existing is true and the activity already existed, so it was left unchanged. + */ + skipped_existing?: Array; } export interface AddBookmarkRequest { @@ -1566,6 +1575,14 @@ export interface AnalyzeResponse { * `complete` (all fields screened), `partial` (mix of verdicts and per-field errors), or `pending` (async). */ status: string; + /** + * ID of the LLM model that scored the content (e.g. gpt-4o-mini). Omitted when no LLM verdict was used (e.g. Bodyguard-only, or `pending`). + */ + llm_model?: string; + /** + * reasoning_effort sent with the LLM request. Omitted when the request did not send one. + */ + llm_reasoning_effort?: string; /** * Per-image moderation verdicts keyed by caller label. */ @@ -1603,6 +1620,17 @@ export interface AnalyzeTextField { classifications?: Array; } +export interface AppDefaults { + /** + * Defaults applied by the get-or-create channel endpoint. + */ + get_or_create_channel: GetOrCreateChannelDefaults; + /** + * Defaults applied by the query channels endpoint. + */ + query_channels: QueryChannelsDefaults; +} + export interface AppResponseFields { allow_multi_user_devices: boolean; /** @@ -1660,6 +1688,10 @@ export interface AppResponseFields { webhook_events: Array; call_types: Record; channel_configs: Record; + /** + * Request limit defaults applied by the server when the corresponding field is omitted. + */ + defaults: AppDefaults; file_upload_config: FileUploadConfig; grants: Record>; image_upload_config: FileUploadConfig; @@ -3777,6 +3809,7 @@ export interface CallSettingsRequest { geofencing?: GeofenceSettingsRequest; individual_recording?: IndividualRecordingSettingsRequest; ingress?: IngressSettingsRequest; + lifecycle?: LifecycleSettingsRequest; limits?: LimitsSettingsRequest; raw_recording?: RawRecordingSettingsRequest; recording?: RecordSettingsRequest; @@ -3802,6 +3835,10 @@ export interface CallSettingsResponse { frame_recording: FrameRecordingSettingsResponse; geofencing: GeofenceSettingsResponse; individual_recording: IndividualRecordingSettingsResponse; + /** + * LifecycleSettings is the payload for call lifecycle settings + */ + lifecycle: LifecycleSettingsResponse; limits: LimitsSettingsResponse; raw_recording: RawRecordingSettingsResponse; /** @@ -4228,6 +4265,14 @@ export interface CancelImportV2TaskResponse { } export interface CastPollVoteRequest { + /** + * Key of the moderation configuration to use. Server-side only. + */ + config_key?: string; + /** + * Team associated with the configuration. Server-side only. + */ + config_team?: string; user_id?: string; /** * User request object @@ -4252,6 +4297,33 @@ export interface ChangeFeedVisibilityResponse { feed: FeedResponse; } +export interface ChannelBanResponse { + created_at: Date; + scopes: Array; + channel_ban?: ChannelBanScopeResponse; + future_channel_ban?: ChannelBanScopeResponse; + /** + * User response object + */ + user?: UserResponse; +} + +export interface ChannelBanScopeResponse { + created_at: Date; + shadow: boolean; + expires?: Date; + reason?: string; + /** + * User response object + */ + banned_by?: UserResponse; +} + +export interface ChannelBansScopeTotals { + channel: number; + future_channel: number; +} + export interface ChannelBatchCompletedEvent { batch_created_at: Date; created_at: Date; @@ -4808,6 +4880,7 @@ export interface ChannelMemberResponse { * Date/time of the last update */ updated_at: Date; + user_id: string; custom: Record; archived_at?: Date; /** @@ -4845,7 +4918,6 @@ export interface ChannelMemberResponse { */ role?: string; status?: string; - user_id?: string; deleted_messages?: Array; /** * User response object @@ -4946,6 +5018,7 @@ export const ChannelOwnCapability = { QUERY_POLL_VOTES: 'query-poll-votes', QUOTE_MESSAGE: 'quote-message', READ_EVENTS: 'read-events', + SCHEDULE_MESSAGE: 'schedule-message', SEARCH_MESSAGES: 'search-messages', SEND_CUSTOM_EVENTS: 'send-custom-events', SEND_LINKS: 'send-links', @@ -5094,16 +5167,54 @@ export interface ChannelResponse { export interface ChannelStateResponse { duration: string; + /** + * List of channel members + */ members: Array; + /** + * List of channel messages + */ messages: Array; + /** + * List of pinned messages in the channel + */ pinned_messages: Array; threads: Array; + /** + * Milliseconds until the current user's slow mode cool down period ends. Only set on client-side get or create channel and get channel requests while the user is under cool down + */ + cooldown_remaining_ms?: number; + /** + * Whether this channel is hidden or not + */ hidden?: boolean; + /** + * Messages before this date are hidden from the user + */ hide_messages_before?: Date; + /** + * Number of channel watchers + */ watcher_count?: number; + /** + * Active live locations in the channel + */ active_live_locations?: Array; + /** + * Pending messages that this user has sent + */ pending_messages?: Array; + /** + * List of read states + */ read?: Array; + /** + * The caller's own scheduled, sending and failed messages in this channel. Set only by a client-side GetOrCreateChannel with include_scheduled_messages; absent when not requested or not known, in which case use the scheduled messages query + */ + scheduled_messages?: Array; + /** + * List of user who is watching the channel + */ watchers?: Array; /** * Represents channel in chat @@ -5131,6 +5242,10 @@ export interface ChannelStateResponseFields { */ pinned_messages: Array; threads: Array; + /** + * Milliseconds until the current user's slow mode cool down period ends. Only set on client-side get or create channel and get channel requests while the user is under cool down + */ + cooldown_remaining_ms?: number; /** * Whether this channel is hidden or not */ @@ -5625,14 +5740,20 @@ export interface CheckPushRequest { */ apn_template?: string; /** - * Type of event for push templates (default: message.new). One of: message.new, message.updated, reaction.new, reaction.updated, notification.reminder_due + * Type of event for push templates (default: message.new). One of: message.new, message.updated, reaction.new, reaction.updated, notification.reminder_due, feeds.activity.added, feeds.comment.added, feeds.activity.reaction.added, feeds.comment.reaction.added, feeds.follow.created, feeds.notification_feed.updated */ event_type?: | 'message.new' | 'message.updated' | 'reaction.new' | 'reaction.updated' - | 'notification.reminder_due'; + | 'notification.reminder_due' + | 'feeds.activity.added' + | 'feeds.comment.added' + | 'feeds.activity.reaction.added' + | 'feeds.comment.reaction.added' + | 'feeds.follow.created' + | 'feeds.notification_feed.updated'; /** * Push message data template for Firebase */ @@ -5744,25 +5865,21 @@ export interface CheckResponse { */ status: string; /** - * Intent topic label matched by this request's text (test mode only; omitted when no topic matched) + * ID of the LLM model that produced the verdict (e.g. gpt-4o-mini). Omitted when no LLM ran synchronously (e.g. Bodyguard-only checks or async moderation) */ - intent_matched_topic?: string; + llm_model?: string; /** - * Stage 2 conversation score (0-100) computed synchronously against this request's texts (test mode only). Omitted -- not zero -- when intent_matched_topic is set but scoring could not be completed (matched topic disabled/removed, or the scoring call itself failed); only present when a real score was computed + * reasoning_effort sent with the LLM request that produced the verdict. Omitted when the request did not send one */ - intent_score?: number; - /** - * The matched topic's configured score_threshold, for comparison against intent_score (test mode only). Same omitted-not-zero rule as intent_score - */ - intent_score_threshold?: number; - /** - * Whether intent_score clears intent_score_threshold, i.e. whether this would fire moderation.intent_detected in production (test mode only). Same omitted-not-zero rule as intent_score - */ - intent_would_fire?: boolean; + llm_reasoning_effort?: string; /** * ID of the running moderation task */ task_id?: string; + /** + * Score (0-100) of each policy intent topic against this request's text, in policy order (test mode only; omitted when the policy has no topics or scoring failed) + */ + intent_scores?: Array; /** * All moderation rules triggered by this check (content, user, and call rules), with their resolved actions */ @@ -5900,6 +6017,14 @@ export interface ClientEvent { * Reason the client initiated the join. Optional on CoordinatorJoin events; empty when not provided. */ join_reason?: string; + /** + * Source of the leave that aborted a join: user, app, callkit, remote_event, sdk_error, or unknown. Not validated against this set, so SDKs may report new values. Optional; sent on failure events. Maximum 32 characters. + */ + leave_initiator?: string; + /** + * Internal reason or triggering event for the leave that aborted a join. Optional; sent on failure events. Maximum 200 characters. + */ + leave_reason?: string; /** * Microphone permission status: INITIATED, FAILED, GRANTED, or NOT_INITIATED. Required on every MediaDevicePermission event. */ @@ -7234,6 +7359,14 @@ export interface CreatePollOptionRequest { * Option text */ text: string; + /** + * Key of the moderation configuration to use. Server-side only. + */ + config_key?: string; + /** + * Team associated with the configuration. Server-side only. + */ + config_team?: string; user_id?: string; /** * Custom data for this object @@ -7255,6 +7388,14 @@ export interface CreatePollRequest { */ allow_answers?: boolean; allow_user_suggested_options?: boolean; + /** + * Key of the moderation configuration to use. Server-side only. + */ + config_key?: string; + /** + * Team associated with the configuration. Server-side only. + */ + config_team?: string; /** * A description of the poll */ @@ -8023,6 +8164,31 @@ export interface DeleteModerationTemplateResponse { duration: string; } +export interface DeletePollAnswerRequestPayload { + /** + * Reason for deletion + */ + reason?: string; +} + +export interface DeletePollOptionRequestPayload { + /** + * Option to delete. Required on an item for a whole poll (create or edit); defaults to the option an add_option / update_option item was raised for + */ + option_id?: string; + /** + * Reason for deletion + */ + reason?: string; +} + +export interface DeletePollRequestPayload { + /** + * Reason for deletion + */ + reason?: string; +} + export interface DeleteQueueRequest { user_id?: string; /** @@ -8095,6 +8261,17 @@ export interface DeleteSIPTrunkResponse { duration: string; } +export interface DeleteScheduledMessageResponse { + /** + * Duration of the request in milliseconds + */ + duration: string; + /** + * A message scheduled to be sent later + */ + scheduled_message: ScheduledMessageResponse; +} + export interface DeleteSegmentTargetsRequest { /** * Target IDs @@ -8535,6 +8712,10 @@ export interface EnrichmentOptions { * Controls the top-level flat 'activities' array for aggregated feeds. For new apps, defaults to false (excluded); set to true to include. For older apps, defaults to true (included) for backward compatibility; set to false to exclude. */ include_flat_activities?: boolean; + /** + * Default: false. Server-side only. When true, the response includes ranking_config: the ranking configuration (from the feed view, or the feed group as fallback) used to rank this read. + */ + include_ranking_config?: boolean; /** * Default: false. When true, includes score_vars in activity responses containing variable values used at ranking time. */ @@ -9514,6 +9695,7 @@ export interface FeedsNotificationComment { comment: string; id: string; user_id: string; + parent_id?: string; attachments?: Array; } @@ -9978,6 +10160,10 @@ export interface FollowBatchRequest { * List of follow relationships to create */ follows: Array; + /** + * If true, the batch is queued as a background task, paced per app, and the response has empty follows and a task_id. Server-side only. Supported by the get-or-create endpoint (GetOrCreateFollows); FollowBatch rejects it. Async batches can apply out of order with other follow writes. Defaults to false. + */ + async?: boolean; /** * If true, auto-creates users referenced by source/target FIDs in the batch when they don't already exist. Server-side only. Defaults to false. This top-level field is the only supported batch/upsert create_users control. */ @@ -9998,6 +10184,10 @@ export interface FollowBatchResponse { * List of current follow relationships */ follows: Array; + /** + * ID of the background task when the request was sent with async: true + */ + task_id?: string; } export interface FollowCreatedEvent { @@ -10814,6 +11004,17 @@ export interface GetOrCreateCallResponse { call: CallResponse; } +export interface GetOrCreateChannelDefaults { + /** + * Resolved defaults for a nested pagination object. + */ + members: PagerDefaults; + /** + * Resolved defaults for a nested pagination object. + */ + messages: PagerDefaults; +} + export interface GetOrCreateFeedGroupRequest { /** * Role new followers of feeds in this group are given. Either a built-in (feed_follower, feed_member_viewer) or any role your app has defined. Empty means feed_follower. Applied when the follow is accepted, so a follow that starts pending picks it up on approval @@ -10912,6 +11113,7 @@ export interface GetOrCreateFeedResponse { following_pagination?: PagerResponse; member_pagination?: PagerResponse; notification_status?: NotificationStatusResponse; + ranking_config?: RankingConfig; } export interface GetOrCreateFeedViewRequest { @@ -11180,15 +11382,28 @@ export interface GroupedChannelsBucket { */ prev?: string; /** - * Unread channels currently classified into this bucket + * Total unread channels matching this bucket and its filters, independent of page size */ unread_channels?: number; } export interface GroupedChannelsGroupRequest { + /** + * Max channels for this group; omitted or zero uses the request limit + */ limit?: number; + /** + * Cursor for the next page; only allowed when requesting one group + */ next?: string; + /** + * Cursor for the previous page; only allowed when requesting one group + */ prev?: string; + /** + * Optional query_timestamp $gte bound for a stored group, requiring query_timestamp sort; do not repeat its group name. For all, combine group equality/$in and date bounds with $or, or use one standalone group $ne exclusion. An empty object matches a stored group; omitted or null preserves legacy grouping. + */ + filter_conditions?: Record; } export interface GroupedQueryChannelsRequest { @@ -11198,7 +11413,11 @@ export interface GroupedQueryChannelsRequest { limit?: number; user_id?: string; /** - * Groups to return, keyed by group name. Each group can define limit, next, or prev. 'next' and 'prev' cursors are only allowed when the request contains exactly one group; multi-group pagination is rejected. + * Optional query_timestamp descending with NULLS LAST when enabled. Omitted sort preserves existing last_updated ordering and cursor formats + */ + sort?: Array; + /** + * Groups to return, keyed by stored group name. Each entry can define limit, next, prev, and optional filter_conditions: date bounds for stored groups; all supports combined group/date branches or one group $ne exclusion. Cursors are only allowed when requesting exactly one group. Omitted or null filters preserve legacy grouping, including all. */ groups?: Record; /** @@ -11213,7 +11432,7 @@ export interface GroupedQueryChannelsResponse { */ duration: string; /** - * Predefined channel groups keyed by group name + * Groups keyed by the requested stored group name */ groups: Record; } @@ -11671,23 +11890,23 @@ export interface InsertActionLogResponse { duration: string; } -export interface IntentBufferedItem { +export interface IntentConditionInfo { /** - * The ID of the user who authored the buffered message or comment + * Whether the score reached the threshold. */ - author_user_id: string; + passed: boolean; /** - * When the buffered message or comment was created + * Final (damped) score of the topic in this analysis; 0 when the topic is not defined in the policy. */ - created_at: Date; + score: number; /** - * The ID of the buffered message or comment + * Minimum score (1-100) the condition requires. */ - id: string; + threshold: number; /** - * The text of the buffered message or comment + * Policy intent topic label the condition references. */ - text: string; + topic: string; } export interface IntentConfigRequest { @@ -11704,39 +11923,37 @@ export interface IntentConfigResponse { topics: Array; } -export interface IntentDetectedEvent { +export interface IntentEvaluationInfo { /** - * The channel CID (chat) or feed ID (feeds) the buffered conversation belongs to + * The analyzed conversation: the channel CID for chat, the object ID for feeds. */ conversation_id: string; - created_at: Date; /** - * The ID of the most recently buffered entity + * Number of conversation messages sent to the model. */ - entity_id: string; + message_count: number; /** - * The type of the most recently buffered entity (chat message or feed comment) + * One entry per `intent_rule` condition of the rule, flat conditions first, then group conditions. */ - entity_type: string; + conditions: Array; /** - * The configured intent topic label that started the buffer + * Score (0-100) the model gave every topic in the analysis call, keyed by topic label, before message-count damping. */ - matched_topic: string; + raw_scores: Record; /** - * The Stage 2 conversation score (0-100) that cleared score_threshold + * Final score (0-100) of every topic after message-count damping, keyed by topic label. Conditions compare against these. */ + scores: Record; +} + +export interface IntentRuleParameters { + topic: string; + threshold?: number; +} + +export interface IntentScoreResponse { score: number; - /** - * The ID of the user whose conversation was scored - */ - user_id: string; - /** - * The buffered items that were scored, in the order they were captured - */ - items: Array; - custom: Record; - type: string; - received_at?: Date; + topic: string; } export interface IntentTopicRequest { @@ -11744,61 +11961,21 @@ export interface IntentTopicRequest { * Unique topic label (e.g. purchase_intent) */ label: string; - /** - * How long the buffer collects items before scoring runs - */ - analysis_cooldown_seconds?: number; /** * Optional description used in the classification prompt; the label alone is used when empty */ description?: string; - /** - * Whether this topic is evaluated - */ - enabled?: boolean; - /** - * Items buffered per conversation before scoring runs early - */ - max_captured_items?: number; - /** - * Suppresses this topic for a user and conversation after it fires; 0 uses the default - */ - refire_cooldown_seconds?: number; - /** - * Conversation score (0-100) required to fire moderation.intent_detected - */ - score_threshold?: number; } export interface IntentTopicResponse { - /** - * How long the buffer collects items before scoring runs - */ - analysis_cooldown_seconds: number; - /** - * Whether this topic is evaluated - */ - enabled: boolean; /** * Unique topic label (e.g. purchase_intent) */ label: string; - /** - * Items buffered per conversation before scoring runs early - */ - max_captured_items: number; - /** - * Conversation score (0-100) required to fire moderation.intent_detected - */ - score_threshold: number; /** * Optional description used in the classification prompt; the label alone is used when empty */ description?: string; - /** - * Suppresses this topic for a user and conversation after it fires; 0 uses the default - */ - refire_cooldown_seconds?: number; } export interface InterestTagResponse { @@ -12085,6 +12262,20 @@ export interface LayoutSettingsResponse { options?: Record; } +export interface LifecycleSettingsRequest { + /** + * Call lifecycle mode. One of: reusable, single_use. A single_use call cannot be reused once it has ended; the server ends it when its ring settles without an answer (currently: when the caller cancels the ring). Fixed at call creation + */ + mode?: 'reusable' | 'single_use'; +} + +export interface LifecycleSettingsResponse { + /** + * Call lifecycle mode. One of: reusable, single_use. A single_use call cannot be reused once it has ended; the server ends it when its ring settles without an answer (currently: when the caller cancels the ring). Fixed at call creation + */ + mode: 'reusable' | 'single_use'; +} + export interface LimitInfoResponse { /** * The maximum number of API calls allowed per time window @@ -14108,6 +14299,7 @@ export interface ModerationRulesTriggeredEvent { * Ordered list of contents whose verdicts contributed to an aggregation rule's threshold. Populated only for aggregation rules when callers supplied `content_ids`. */ matched_contents?: Array; + intent?: IntentEvaluationInfo; } export interface ModerationTextAnalysisCompleteEvent { @@ -14243,9 +14435,25 @@ export interface NoiseCancellationSettings { } export interface NotificationComment { + /** + * The text of the comment + */ comment: string; + /** + * The ID of the comment + */ id: string; + /** + * The ID of the user who wrote the comment + */ user_id: string; + /** + * The ID of the parent comment when this comment is a reply; omitted for top-level comments + */ + parent_id?: string; + /** + * Attachments on the comment + */ attachments?: Array; } @@ -14644,6 +14852,7 @@ export interface OwnUserResponse { unread_count: number; unread_threads: number; updated_at: Date; + blocked_user_ids: Array; channel_mutes: Array; devices: Array; mutes: Array; @@ -14656,7 +14865,6 @@ export interface OwnUserResponse { last_active?: Date; name?: string; revoke_tokens_issued_before?: Date; - blocked_user_ids?: Array; latest_hidden_channels?: Array; /** * The privacy settings of the user. @@ -14670,6 +14878,13 @@ export interface OwnUserResponse { total_unread_count_by_team?: Record; } +export interface PagerDefaults { + /** + * Number of records returned when `limit` is omitted. + */ + limit: number; +} + export interface PagerRequest { limit?: number; next?: string; @@ -15150,28 +15365,74 @@ export interface PolicyTestTotals { unscored: number; } -export interface PollOptionInput { - text?: string; - custom?: Record; -} - -export interface PollOptionRequest { - id: string; - text?: string; - custom?: Record; -} - -export interface PollOptionResponse { +export interface PollClosedEvent { /** - * Duration of the request in milliseconds + * Date/time of creation */ - duration: string; - poll_option: PollOptionResponseData; -} - -export interface PollOptionResponseData { - id: string; - text: string; + created_at: Date; + custom: Record; + poll: PollResponseData; + /** + * The type of event: "poll.closed" in this case + */ + type: string; + activity_id?: string; + /** + * The CID of the channel containing the poll + */ + cid?: string; + /** + * The ID of the message containing the poll + */ + message_id?: string; + received_at?: Date; +} + +export interface PollDeletedEvent { + /** + * Date/time of creation + */ + created_at: Date; + custom: Record; + poll: PollResponseData; + /** + * The type of event: "poll.deleted" in this case + */ + type: string; + activity_id?: string; + /** + * The CID of the channel containing the poll + */ + cid?: string; + /** + * The ID of the message containing the poll + */ + message_id?: string; + received_at?: Date; +} + +export interface PollOptionInput { + text?: string; + custom?: Record; +} + +export interface PollOptionRequest { + id: string; + text?: string; + custom?: Record; +} + +export interface PollOptionResponse { + /** + * Duration of the request in milliseconds + */ + duration: string; + poll_option: PollOptionResponseData; +} + +export interface PollOptionResponseData { + id: string; + text: string; custom: Record; text_i18n?: Record; } @@ -15216,6 +15477,101 @@ export interface PollResponseData { name_i18n?: Record; } +export interface PollUpdatedEvent { + /** + * Date/time of creation + */ + created_at: Date; + custom: Record; + poll: PollResponseData; + /** + * The type of event: "poll.updated" in this case + */ + type: string; + activity_id?: string; + /** + * The CID of the channel containing the poll + */ + cid?: string; + /** + * The ID of the message containing the poll + */ + message_id?: string; + received_at?: Date; +} + +export interface PollVoteCastedEvent { + /** + * Date/time of creation + */ + created_at: Date; + custom: Record; + poll: PollResponseData; + poll_vote: PollVoteResponseData; + /** + * The type of event: "poll.vote_casted" in this case + */ + type: string; + activity_id?: string; + /** + * The CID of the channel containing the poll + */ + cid?: string; + /** + * The ID of the message containing the poll + */ + message_id?: string; + received_at?: Date; +} + +export interface PollVoteChangedEvent { + /** + * Date/time of creation + */ + created_at: Date; + custom: Record; + poll: PollResponseData; + poll_vote: PollVoteResponseData; + /** + * The type of event: "poll.vote_changed" in this case + */ + type: string; + activity_id?: string; + /** + * The CID of the channel containing the poll + */ + cid?: string; + /** + * The ID of the message containing the poll + */ + message_id?: string; + received_at?: Date; +} + +export interface PollVoteRemovedEvent { + /** + * Date/time of creation + */ + created_at: Date; + custom: Record; + poll: PollResponseData; + poll_vote: PollVoteResponseData; + /** + * The type of event: "poll.vote_removed" in this case + */ + type: string; + activity_id?: string; + /** + * The CID of the channel containing the poll + */ + cid?: string; + /** + * The ID of the message containing the poll + */ + message_id?: string; + received_at?: Date; +} + export interface PollVoteResponse { /** * Duration of the request in milliseconds @@ -16093,6 +16449,66 @@ export interface QueryCampaignsResponse { prev?: string; } +export interface QueryChannelBansRequest { + /** + * Whether to exclude expired bans or not + */ + exclude_expired_bans?: boolean; + /** + * When true, the response includes total and total_by_scope: the number of banned users overall and per scope, independent of paging + */ + include_total?: boolean; + limit?: number; + next?: string; + prev?: string; + user_id?: string; + /** + * Filter conditions to apply to the query + */ + filter_conditions?: Record; + /** + * User request object + */ + user?: UserRequest; +} + +export interface QueryChannelBansResponse { + /** + * Duration of the request in milliseconds + */ + duration: string; + /** + * Users banned from the channel, one entry per user, newest ban first + */ + bans: Array; + next?: string; + prev?: string; + /** + * Number of banned users, each counted once, ignoring paging. Counted per scope with a cap of 100000 each, so it can reach 200000. Only present when include_total is set on the request; omitted when counting timed out + */ + total?: number; + total_by_scope?: ChannelBansScopeTotals; +} + +export interface QueryChannelsDefaults { + /** + * Number of channels returned when `limit` is omitted. + */ + limit: number; + /** + * Largest number of channels returned for one request. A bigger `limit` is silently clamped to this value rather than rejected. An app with no per-app override gets a higher ceiling for the narrow case of a request asking for at most one message and one member per channel. + */ + max_limit: number; + /** + * Number of members returned per channel when `member_limit` is omitted. + */ + member_limit: number; + /** + * Number of messages returned per channel when `message_limit` is omitted. + */ + message_limit: number; +} + export interface QueryChannelsRequest { /** * Number of channels to limit @@ -16401,6 +16817,10 @@ export interface QueryFeedsUsageStatsResponse { } export interface QueryFollowsRequest { + /** + * When true (server-side only), the response includes group_counts: accepted following counts keyed by the followed feed's group. Requires exactly one source_feed / source_fid string equality. HTTP 400 if target_feed appears, if two source FIDs are given, or if $in / $or / $nor mentions those keys. Independent of paging and of other filters, including status. + */ + include_group_counts?: boolean; limit?: number; next?: string; prev?: string; @@ -16428,6 +16848,10 @@ export interface QueryFollowsResponse { * Cursor for previous page */ prev?: string; + /** + * Accepted following counts keyed by followed feed group. Present only when include_group_counts is set with a source_feed equality. + */ + group_counts?: Record; } export interface QueryFutureChannelBansPayload { @@ -17008,6 +17432,45 @@ export interface QueryRevisionHistoryResponse { prev?: string; } +export interface QueryScheduledMessagesRequest { + /** + * Page size, 1 to 100. Defaults to 20 + */ + limit?: number; + /** + * Cursor from the previous page + */ + next?: string; + user_id?: string; + /** + * Only scheduled_at ascending is supported. Pending messages come before failed ones + */ + sort?: Array; + /** + * Filter for querying scheduled messages + */ + filter?: ScheduledMessagesFilter; + /** + * User request object + */ + user?: UserRequest; +} + +export interface QueryScheduledMessagesResponse { + /** + * Duration of the request in milliseconds + */ + duration: string; + /** + * Pending messages first, then failed ones, each by scheduled_at + */ + scheduled_messages: Array; + /** + * Cursor for the next page; empty on the last page + */ + next?: string; +} + export interface QuerySegmentTargetsRequest { /** * Limit @@ -18237,6 +18700,7 @@ export interface ReviewQueueItemResponse { * Content payload for moderation */ moderation_payload?: ModerationPayloadResponse; + poll?: PollResponseData; reaction?: Reaction; } @@ -18503,6 +18967,10 @@ export interface RuleBuilderCondition { flood_similar_params?: FloodSimilarRuleParameters; image_content_params?: ImageContentParameters; image_rule_params?: ImageRuleParameters; + /** + * intent_rule params: policy intent topic label and the minimum final score (1-100) that fires the condition + */ + intent_rule_params?: IntentRuleParameters; ip_content_count_rule_params?: IPContentCountRuleParameters; ip_flag_count_rule_params?: IPFlagCountRuleParameters; keyframe_ocr_rule_params?: KeyframeOCRRuleParameters; @@ -18510,6 +18978,7 @@ export interface RuleBuilderCondition { ocr_content_params?: OCRContentParameters; text_content_params?: TextContentParameters; text_rule_params?: TextRuleParameters; + user_channel_ban_count_params?: UserChannelBanCountRuleParameters; user_channel_count_params?: UserChannelCountRuleParameters; user_created_within_params?: UserCreatedWithinParameters; user_custom_property_params?: UserCustomPropertyParameters; @@ -18934,6 +19403,228 @@ export interface SRTIngress { address: string; } +export interface ScheduledMessageChannelResponse { + /** + * Channel CID (:) + */ + cid: string; + /** + * Channel ID + */ + id: string; + /** + * Channel type + */ + type: string; + /** + * Channel image, from its custom data + */ + image?: string; + /** + * Channel name, from its custom data + */ + name?: string; +} + +export interface ScheduledMessageContentResponse { + /** + * Text of the message + */ + text: string; + custom: Record; + /** + * Contains HTML markup of the message + */ + html?: string; + /** + * Whether the message mentions the whole channel + */ + mentioned_channel?: boolean; + /** + * Whether the message mentions the online channel members + */ + mentioned_here?: boolean; + /** + * MML content of the message + */ + mml?: string; + /** + * ID of parent message (thread) + */ + parent_id?: string; + /** + * Date/time the pin expires + */ + pin_expires?: Date; + /** + * Whether the message will be pinned when sent + */ + pinned?: boolean; + /** + * Identifier of the poll to include in the message + */ + poll_id?: string; + quoted_message_id?: string; + /** + * Whether thread reply should be shown in the channel as well + */ + show_in_channel?: boolean; + /** + * Whether message is silent or not + */ + silent?: boolean; + /** + * Contains type of the message. One of: regular, system + */ + type?: string; + /** + * Array of message attachments + */ + attachments?: Array; + /** + * IDs of the user groups mentioned in the message + */ + mentioned_group_ids?: Array; + /** + * Roles mentioned in the message + */ + mentioned_roles?: Array; + /** + * IDs of the users mentioned in the message + */ + mentioned_users?: Array; + /** + * IDs of the users the message will be visible to + */ + restricted_visibility?: Array; + /** + * The location a scheduled message will share + */ + shared_location?: ScheduledMessageLocation; +} + +export interface ScheduledMessageFailedEvent { + /** + * Date/time of creation + */ + created_at: Date; + custom: Record; + user: UserResponseCommonFields; + /** + * The type of event: "scheduled_message.failed" in this case + */ + type: string; + /** + * The CID of the channel the message is scheduled in + */ + cid?: string; + received_at?: Date; + /** + * A message scheduled to be sent later + */ + scheduled_message?: ScheduledMessageResponse; +} + +export interface ScheduledMessageLocation { + /** + * The ID of the device that created the location. + */ + created_by_device_id: string; + /** + * The date when the location sharing ends. + * If it's empty, it means the location sharing is static instead of live. + */ + end_at?: Date; + /** + * The latitude of the location. + */ + latitude?: number; + /** + * The longitude of the location. + */ + longitude?: number; +} + +export interface ScheduledMessageResponse { + /** + * The CID of the channel the message will be sent to + */ + cid: string; + /** + * Date/time of creation + */ + created_at: Date; + /** + * Unique identifier of the scheduled message + */ + id: string; + /** + * Date/time the message is scheduled to be sent + */ + scheduled_at: Date; + /** + * Status of the scheduled message. One of: scheduled, sending, failed, canceled, sent + */ + status: string; + /** + * Date/time of the last update + */ + updated_at: Date; + /** + * The message a scheduled message will send + */ + message: ScheduledMessageContentResponse; + /** + * User response object + */ + user: UserResponse; + /** + * Why sending the message failed. Only set when status is failed. One of: banned, no_permission, channel_frozen, channel_deleted, user_deleted, moderation_blocked, hook_rejected, expired, internal_error, invalid_message, pending_not_supported + */ + failure_reason?: string; + /** + * The channel of a scheduled message + */ + channel?: ScheduledMessageChannelResponse; +} + +export interface ScheduledMessageSentEvent { + /** + * Date/time of creation + */ + created_at: Date; + /** + * The ID of the message that was sent + */ + message_id: string; + custom: Record; + user: UserResponseCommonFields; + /** + * The type of event: "scheduled_message.sent" in this case + */ + type: string; + /** + * The CID of the channel the message was sent to + */ + cid?: string; + received_at?: Date; + /** + * A message scheduled to be sent later + */ + scheduled_message?: ScheduledMessageResponse; +} + +export interface ScheduledMessagesFilter { + /** + * Only scheduled messages of this channel + */ + cid?: string; + /** + * Only these statuses. One or more of: scheduled, sending, failed + */ + status?: Array; +} + export interface ScoreBands { good?: number; ok?: number; @@ -19217,6 +19908,10 @@ export interface SendMessageRequest { include_mentioned_members?: boolean; keep_channel_hidden?: boolean; pending?: boolean; + /** + * When set, the message is not sent now: it is stored and sent at this time (UTC). The response then carries scheduled_message. Must be at least 1 minute and at most the app's maximum lead time (120 days by default) from now. Slash commands cannot be scheduled + */ + scheduled_at?: Date; skip_enrich_url?: boolean; skip_push?: boolean; pending_message_metadata?: Record; @@ -19243,6 +19938,10 @@ export interface SendMessageResponse { * Pending message metadata */ pending_message_metadata?: Record; + /** + * A message scheduled to be sent later + */ + scheduled_message?: ScheduledMessageResponse; } export interface SendReactionRequest { @@ -19272,6 +19971,19 @@ export interface SendReactionResponse { reaction: ReactionResponse; } +export interface SendScheduledMessageNowRequest {} + +export interface SendScheduledMessageNowResponse { + /** + * Duration of the request in milliseconds + */ + duration: string; + /** + * A message scheduled to be sent later + */ + scheduled_message: ScheduledMessageResponse; +} + export interface SendUserCustomEventRequest { event: UserCustomEventRequest; } @@ -19871,7 +20583,7 @@ export interface StoriesFeedUpdatedEvent { export interface SubmitActionRequest { /** - * Type of moderation action to perform. One of: mark_reviewed, delete_message, delete_activity, delete_comment, delete_reaction, ban, custom, unban, restore, delete_user, delete_user_messages, unblock, block, shadow_block, unmask, kick_user, end_call, escalate, de_escalate + * Type of moderation action to perform. One of: mark_reviewed, delete_message, delete_activity, delete_comment, delete_reaction, delete_poll, delete_poll_option, delete_poll_answer, ban, custom, unban, restore, delete_user, delete_user_messages, unblock, block, shadow_block, unmask, kick_user, end_call, escalate, de_escalate */ action_type: | 'flag' @@ -19880,6 +20592,9 @@ export interface SubmitActionRequest { | 'delete_activity' | 'delete_comment' | 'delete_reaction' + | 'delete_poll' + | 'delete_poll_option' + | 'delete_poll_answer' | 'ban' | 'custom' | 'unban' @@ -19930,6 +20645,18 @@ export interface SubmitActionRequest { * Configuration for message deletion action */ delete_message?: DeleteMessageRequestPayload; + /** + * Configuration for poll deletion action. Poll deletion is always permanent. + */ + delete_poll?: DeletePollRequestPayload; + /** + * Configuration for deleting the free-text poll answer a review item was raised for. Chat polls only. Deletion is permanent; the poll and other votes are kept. + */ + delete_poll_answer?: DeletePollAnswerRequestPayload; + /** + * Configuration for deleting the single poll option a review item was raised for. Deletion is permanent; the rest of the poll is kept. + */ + delete_poll_option?: DeletePollOptionRequestPayload; /** * Configuration for reaction deletion action */ @@ -20911,6 +21638,10 @@ export interface UnfollowBatchRequest { * List of follow relationships to remove, each with optional keep_history */ follows: Array; + /** + * If true, the batch is queued as a background task, paced per app, and the response has empty follows and a task_id. Server-side only. Supported by the get-or-create endpoint (GetOrCreateUnfollows); UnfollowBatch rejects it. Async batches can apply out of order with other follow writes. Defaults to false. + */ + async?: boolean; /** * Whether to delete the corresponding notification activity (default: false) */ @@ -20927,6 +21658,10 @@ export interface UnfollowBatchResponse { * List of follow relationships that were removed */ follows: Array; + /** + * ID of the background task when the request was sent with async: true + */ + task_id?: string; } export interface UnfollowPair { @@ -22246,6 +22981,14 @@ export interface UpdatePollOptionRequest { * Option text */ text: string; + /** + * Key of the moderation configuration to use. Server-side only. + */ + config_key?: string; + /** + * Team associated with the configuration. Server-side only. + */ + config_team?: string; user_id?: string; /** * Custom data for this object @@ -22258,6 +23001,14 @@ export interface UpdatePollOptionRequest { } export interface UpdatePollPartialRequest { + /** + * Key of the moderation configuration to use. Server-side only. + */ + config_key?: string; + /** + * Team associated with the configuration. Server-side only. + */ + config_team?: string; user_id?: string; /** * Array of field names to unset @@ -22290,6 +23041,14 @@ export interface UpdatePollRequest { * Allow user suggested options */ allow_user_suggested_options?: boolean; + /** + * Key of the moderation configuration to use. Server-side only. + */ + config_key?: string; + /** + * Team associated with the configuration. Server-side only. + */ + config_team?: string; /** * Poll description */ @@ -22453,6 +23212,28 @@ export interface UpdateSIPTrunkResponse { sip_trunk?: SIPTrunkResponse; } +export interface UpdateScheduledMessageRequest { + /** + * New send time (UTC). Must be at least 1 minute and at most the app's maximum lead time from now + */ + scheduled_at?: Date; + /** + * Message data for creating or updating a message + */ + message?: MessageRequest; +} + +export interface UpdateScheduledMessageResponse { + /** + * Duration of the request in milliseconds + */ + duration: string; + /** + * A message scheduled to be sent later + */ + scheduled_message: ScheduledMessageResponse; +} + export interface UpdateSegmentRequest { /** * The description of the segment (max 256 characters) @@ -22709,6 +23490,10 @@ export interface UpsertActivitiesRequest { * If true, forces moderation to run for server-side requests. By default, server-side requests skip moderation. Client-side requests always run moderation regardless of this field. */ force_moderation?: boolean; + /** + * Server-side only. If true, activities whose id already exists are left unchanged instead of updated: no write, events or notifications. They are listed in skipped_existing and returned as stored. Soft-deleted activities count as existing and are returned with deleted_at set. Default: false. + */ + skip_existing?: boolean; } export interface UpsertActivitiesResponse { @@ -22721,6 +23506,10 @@ export interface UpsertActivitiesResponse { * Total number of mention notification activities created for mentioned users across all activities */ mention_notifications_created?: number; + /** + * IDs of activities left unchanged because they already existed. Only set when skip_existing is true. + */ + skipped_existing?: Array; } export interface UpsertCollectionsRequest { @@ -23073,6 +23862,12 @@ export interface UserBannedEvent { created_by?: UserResponseCommonFields; } +export interface UserChannelBanCountRuleParameters { + banned_by?: string; + threshold?: number; + time_window?: string; +} + export interface UserChannelCountRuleParameters { threshold?: number; time_window?: string; @@ -23970,7 +24765,6 @@ export type WHEvent = | ({ type: 'moderation.image_analysis.complete'; } & ModerationImageAnalysisCompleteEvent) - | ({ type: 'moderation.intent_detected' } & IntentDetectedEvent) | ({ type: 'moderation.mark_reviewed' } & ModerationMarkReviewedEvent) | ({ type: 'moderation.text_analysis.complete'; @@ -23982,6 +24776,12 @@ export type WHEvent = | ({ type: 'notification.thread_message_new'; } & NotificationThreadMessageNewEvent) + | ({ type: 'poll.closed' } & PollClosedEvent) + | ({ type: 'poll.deleted' } & PollDeletedEvent) + | ({ type: 'poll.updated' } & PollUpdatedEvent) + | ({ type: 'poll.vote_casted' } & PollVoteCastedEvent) + | ({ type: 'poll.vote_changed' } & PollVoteChangedEvent) + | ({ type: 'poll.vote_removed' } & PollVoteRemovedEvent) | ({ type: 'reaction.deleted' } & ReactionDeletedEvent) | ({ type: 'reaction.new' } & ReactionNewEvent) | ({ type: 'reaction.updated' } & ReactionUpdatedEvent) @@ -23990,6 +24790,8 @@ export type WHEvent = | ({ type: 'reminder.updated' } & ReminderUpdatedEvent) | ({ type: 'review_queue_item.new' } & ReviewQueueItemNewEvent) | ({ type: 'review_queue_item.updated' } & ReviewQueueItemUpdatedEvent) + | ({ type: 'scheduled_message.failed' } & ScheduledMessageFailedEvent) + | ({ type: 'scheduled_message.sent' } & ScheduledMessageSentEvent) | ({ type: 'thread.updated' } & ThreadUpdatedEvent) | ({ type: 'user.banned' } & UserBannedEvent) | ({ type: 'user.deactivated' } & UserDeactivatedEvent) diff --git a/src/gen/moderation/ModerationApi.ts b/src/gen/moderation/ModerationApi.ts index bfb8901..4667a9f 100644 --- a/src/gen/moderation/ModerationApi.ts +++ b/src/gen/moderation/ModerationApi.ts @@ -1313,6 +1313,9 @@ export class ModerationApi { delete_activity: request?.delete_activity, delete_comment: request?.delete_comment, delete_message: request?.delete_message, + delete_poll: request?.delete_poll, + delete_poll_answer: request?.delete_poll_answer, + delete_poll_option: request?.delete_poll_option, delete_reaction: request?.delete_reaction, delete_user: request?.delete_user, delete_user_messages: request?.delete_user_messages, From 9c4ac52d0015d199d735994fd887cc92fb737018 Mon Sep 17 00:00:00 2001 From: nijeeshjoshy Date: Thu, 15 Oct 2026 11:28:33 +0200 Subject: [PATCH 2/2] chore: regenerate from protocol openapi-v239.72.0 Co-Authored-By: Claude Opus 5.5 --- src/gen/models/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gen/models/index.ts b/src/gen/models/index.ts index d2cc8b9..0fb90f3 100644 --- a/src/gen/models/index.ts +++ b/src/gen/models/index.ts @@ -19563,7 +19563,7 @@ export interface ScheduledMessageResponse { */ scheduled_at: Date; /** - * Status of the scheduled message. One of: scheduled, sending, failed, canceled, sent + * Status of the scheduled message. One of: scheduled, sending, failed, canceled, sent. A message is sending from its first send attempt until it is sent or fails, including while it waits to retry a failed attempt; it cannot be edited, canceled or sent now while sending */ status: string; /** @@ -19620,7 +19620,7 @@ export interface ScheduledMessagesFilter { */ cid?: string; /** - * Only these statuses. One or more of: scheduled, sending, failed + * Only these statuses, as reported in each scheduled message's status. One or more of: scheduled, sending, failed */ status?: Array; }