stream-chat
Version:
JS SDK for the Stream Chat API
5,311 lines • 136 kB
text/typescript
import type { EVENT_MAP } from './events';
import type { Channel } from './channel';
import type { AxiosRequestConfig, AxiosResponse } from 'axios';
import type { StableWSConnection } from './connection';
import type { Role } from './permissions';
import type {
CustomAttachmentData,
CustomChannelData,
CustomCommandData,
CustomEventData,
CustomEventTypes,
CustomMemberData,
CustomMessageData,
CustomPollData,
CustomPollOptionData,
CustomReactionData,
CustomThreadData,
CustomUserData,
} from './custom_types';
import type { NotificationManager } from './notifications';
import type { RESERVED_UPDATED_MESSAGE_FIELDS } from './constants';
/**
* Utility Types
*/
export type Readable<T> = {
[key in keyof T]: T[key];
} & {};
export type ArrayOneOrMore<T> = {
0: T;
} & Array<T>;
export type ArrayTwoOrMore<T> = {
0: T;
1: T;
} & Array<T>;
export type KnownKeys<T> = {
[K in keyof T]: string extends K ? never : number extends K ? never : K;
} extends { [_ in keyof T]: infer U }
? U
: never;
export type RequireAtLeastOne<T> = {
[K in keyof T]-?: Required<Pick<T, K>> & Partial<Omit<T, K>>;
}[keyof T];
export type RequireOnlyOne<T, Keys extends keyof T = keyof T> = Omit<T, Keys> &
{
[K in Keys]-?: Required<Pick<T, K>> & Partial<Record<Exclude<Keys, K>, undefined>>;
}[Keys];
export type PartializeKeys<T, K extends keyof T> = Partial<Pick<T, K>> & Omit<T, K>;
/* Unknown Record */
export type UR = Record<string, unknown>;
export type UnknownType = UR; //alias to avoid breaking change
export type Unpacked<T> = T extends (infer U)[]
? U // eslint-disable-next-line @typescript-eslint/no-explicit-any
: T extends (...args: any[]) => infer U
? U
: T extends Promise<infer U>
? U
: T;
/**
* Response Types
*/
export type APIResponse = {
duration: string;
blocklist?: BlockListResponse;
};
export type TranslateResponse = {
language: string;
translated_text: string;
};
export type AppSettingsAPIResponse = APIResponse & {
app?: {
id?: string | number;
allow_multi_user_devices?: boolean;
feed_audit_logs_enabled?: boolean;
moderation_onboarding_complete?: boolean | null;
// TODO
// eslint-disable-next-line @typescript-eslint/no-explicit-any
call_types: any;
channel_configs: Record<
string,
{
reminders: boolean;
automod?: ChannelConfigAutomod;
automod_behavior?: ChannelConfigAutomodBehavior;
automod_thresholds?: ChannelConfigAutomodThresholds;
blocklist_behavior?: ChannelConfigAutomodBehavior;
commands?: CommandVariants[];
connect_events?: boolean;
created_at?: string;
custom_events?: boolean;
delivery_events?: boolean;
mark_messages_pending?: boolean;
max_message_length?: number;
message_retention?: string;
mutes?: boolean;
name?: string;
polls?: boolean;
push_notifications?: boolean;
quotes?: boolean;
reactions?: boolean;
read_events?: boolean;
replies?: boolean;
search?: boolean;
shared_locations?: boolean;
skip_last_msg_update_for_system_msgs?: boolean;
count_messages?: boolean;
typing_events?: boolean;
updated_at?: string;
uploads?: boolean;
url_enrichment?: boolean;
user_message_reminders?: boolean;
push_level?:
| 'all'
| 'all_mentions'
| 'direct_mentions'
| 'mentions'
| 'none'
| '';
}
>;
reminders_interval: number;
async_moderation_config?: AsyncModerationOptions;
async_url_enrich_enabled?: boolean;
auto_translation_enabled?: boolean;
before_message_send_hook_url?: string;
before_message_send_hook_attempt_timeout_ms?: number;
campaign_enabled?: boolean;
cdn_expiration_seconds?: number;
custom_action_handler_url?: string;
datadog_info?: {
api_key: string;
site: string;
enabled?: boolean;
};
disable_auth_checks?: boolean;
disable_permissions_checks?: boolean;
enforce_unique_usernames?: 'no' | 'app' | 'team';
event_hooks?: Array<EventHook>;
file_upload_config?: FileUploadConfig;
geofences?: Array<{
country_codes: Array<string>;
description: string;
name: string;
type: string;
}>;
grants?: Record<string, string[]>;
guest_user_creation_disabled?: boolean;
image_moderation_enabled?: boolean;
image_moderation_labels?: string[];
image_upload_config?: FileUploadConfig;
allowed_flag_reasons?: string[];
max_aggregated_activities_length?: number;
moderation_bulk_submit_action_enabled?: boolean;
moderation_dashboard_preferences?: Record<string, unknown> | null;
moderation_audio_call_moderation_enabled?: boolean;
moderation_enabled?: boolean;
moderation_flood_rules_enabled?: boolean;
moderation_llm_configurability_enabled?: boolean;
moderation_multitenant_blocklist_enabled?: boolean;
moderation_video_call_moderation_enabled?: boolean;
moderation_webhook_url?: string;
multi_tenant_enabled?: boolean;
name?: string;
organization?: string;
permission_version?: string;
/**
* The placement of the app in the form of `${region}.${shard}`.
* Examples: "us-east.c1", "dublin.c3", "singapore.c2"
* Note: The backend may add/remove regions or shards occasionally.
*/
placement?: string;
policies?: Record<string, Policy[]>;
poll_enabled?: boolean;
push_notifications?: {
offline_only: boolean;
version: string;
apn?: APNConfig;
firebase?: FirebaseConfig;
huawei?: HuaweiConfig;
providers?: PushProviderConfig[];
xiaomi?: XiaomiConfig;
};
revoke_tokens_issued_before?: string | null;
search_backend?: 'disabled' | 'elasticsearch' | 'postgres';
sns_key?: string;
sns_secret?: string;
sns_topic_arn?: string;
sqs_key?: string;
sqs_secret?: string;
sqs_url?: string;
suspended?: boolean;
suspended_explanation?: string;
use_hook_v2?: boolean;
user_response_time_enabled?: boolean;
user_search_disallowed_roles?: string[] | null;
video_provider?: string;
webhook_events?: Array<string>;
webhook_url?: string;
};
};
export type ModerationResult = {
action: string;
created_at: string;
message_id: string;
updated_at: string;
user_bad_karma: boolean;
user_karma: number;
blocked_word?: string;
blocklist_name?: string;
moderated_by?: string;
};
export type AutomodDetails = {
action?: string;
image_labels?: Array<string>;
original_message_type?: string;
result?: ModerationResult;
};
export type FlagDetails = {
automod?: AutomodDetails;
};
export type Flag = {
created_at: string;
created_by_automod: boolean;
updated_at: string;
details?: FlagDetails;
target_message?: MessageResponse;
target_user?: UserResponse;
user?: UserResponse;
};
export type FlagsResponse = APIResponse & {
flags?: Array<Flag>;
};
export type MessageFlagsResponse = APIResponse & {
flags?: Array<{
message: MessageResponse;
user: UserResponse;
approved_at?: string;
created_at?: string;
created_by_automod?: boolean;
moderation_result?: ModerationResult;
rejected_at?: string;
reviewed_at?: string;
reviewed_by?: UserResponse;
updated_at?: string;
}>;
};
export type FlagReport = {
flags_count: number;
id: string;
message: MessageResponse;
user: UserResponse;
created_at?: string;
details?: FlagDetails;
first_reporter?: UserResponse;
review_result?: string;
reviewed_at?: string;
reviewed_by?: UserResponse;
updated_at?: string;
};
export type FlagReportsResponse = APIResponse & {
flag_reports: Array<FlagReport>;
};
export type ReviewFlagReportResponse = APIResponse & {
flag_report: FlagReport;
};
export type BannedUsersResponse = APIResponse & {
bans?: Array<{
user: UserResponse;
banned_by?: UserResponse;
channel?: ChannelResponse;
expires?: string;
ip_ban?: boolean;
reason?: string;
timeout?: number;
}>;
};
export type FutureChannelBan = {
user: UserResponse;
expires?: string;
reason?: string;
shadow?: boolean;
created_at: string;
};
export type FutureChannelBansResponse = APIResponse & {
bans: FutureChannelBan[];
};
export type QueryFutureChannelBansOptions = {
user_id?: string;
target_user_id?: string;
exclude_expired_bans?: boolean;
limit?: number;
offset?: number;
};
export type BlockListResponse = BlockList & {
created_at?: string;
id?: string;
owner_user_id?: string;
type?: string;
updated_at?: string;
};
export type ChannelResponse = CustomChannelData & {
cid: string;
disabled: boolean;
frozen: boolean;
id: string;
type: string;
blocked?: boolean;
auto_translation_enabled?: boolean;
auto_translation_language?: TranslationLanguages;
hide_messages_before?: string;
config?: ChannelConfigWithInfo;
cooldown?: number;
created_at?: string;
created_by?: UserResponse | null;
created_by_id?: string;
deleted_at?: string;
filter_tags?: string[];
hidden?: boolean;
invites?: string[];
joined?: boolean;
last_message_at?: string;
member_count?: number;
members?: ChannelMemberResponse[];
message_count?: number;
muted?: boolean;
mute_expires_at?: string;
own_capabilities?: string[];
team?: string;
truncated_at?: string;
truncated_by?: UserResponse;
truncated_by_id?: string;
updated_at?: string;
};
export type QueryReactionsOptions = Pager;
export type QueryReactionsAPIResponse = APIResponse & {
reactions: ReactionResponse[];
next?: string;
};
export type QueryChannelsAPIResponse = APIResponse & {
channels: Omit<ChannelAPIResponse, keyof APIResponse>[];
predefined_filter?: ParsedPredefinedFilterResponse;
};
export type QueryChannelAPIResponse = APIResponse & ChannelAPIResponse;
export type ChannelAPIResponse = {
channel: ChannelResponse;
members: ChannelMemberResponse[];
messages: MessageResponse[];
pinned_messages: MessageResponse[];
draft?: DraftResponse;
hidden?: boolean;
membership?: ChannelMemberResponse | null;
pending_messages?: PendingMessageResponse[];
push_preferences?: ChannelPushPreference;
read?: ReadResponse[];
threads?: ThreadResponse[];
watcher_count?: number;
watchers?: UserResponse[];
active_live_locations?: SharedLocationResponse[];
};
export type ChannelUpdateOptions = {
hide_history?: boolean;
hide_history_before?: string | Date;
skip_push?: boolean;
};
export type ChannelMemberAPIResponse = APIResponse & {
members: ChannelMemberResponse[];
};
export type ChannelMemberUpdates = CustomMemberData & {
archived?: boolean;
channel_role?: Role;
pinned?: boolean;
};
export type ChannelMemberResponse = CustomMemberData & {
archived_at?: string | null;
ban_expires?: string;
banned?: boolean;
channel_role?: Role;
created_at?: string;
invite_accepted_at?: string;
invite_rejected_at?: string;
invited?: boolean;
is_moderator?: boolean;
notifications_muted?: boolean;
pinned_at?: string | null;
role?: string;
shadow_banned?: boolean;
status?: InviteStatus;
updated_at?: string;
user?: UserResponse;
user_id?: string;
};
export type PartialUpdateMemberAPIResponse = APIResponse & {
channel_member: ChannelMemberResponse;
};
export type CheckPushResponse = APIResponse & {
device_errors?: {
[deviceID: string]: {
error_message?: string;
provider?: PushProvider;
provider_name?: string;
};
};
general_errors?: string[];
rendered_apn_template?: string;
rendered_firebase_template?: string;
rendered_message?: {};
skip_devices?: boolean;
};
export type CheckSQSResponse = APIResponse & {
status: string;
data?: {};
error?: string;
};
export type CheckSNSResponse = APIResponse & {
status: string;
data?: {};
error?: string;
};
export type CommandResponse = Partial<CreatedAtUpdatedAt> & {
args?: string;
description?: string;
name?: CommandVariants;
set?: CommandVariants;
};
export type ConnectAPIResponse = Promise<void | ConnectionOpen>;
export type CreateChannelResponse = APIResponse &
Omit<CreateChannelOptions, 'client_id' | 'connection_id'> & {
created_at: string;
updated_at: string;
grants?: Record<string, string[]>;
};
export type CreateCommandResponse = APIResponse & {
command: CreateCommandOptions & CreatedAtUpdatedAt;
};
export type DeleteChannelAPIResponse = APIResponse & {
channel: ChannelResponse;
};
export type DeleteCommandResponse = APIResponse & {
name?: CommandVariants;
};
export type EventAPIResponse = APIResponse & {
event: Event;
};
export type ExportChannelResponse = {
task_id: string;
};
export type ExportUsersResponse = {
task_id: string;
};
export type ExportChannelStatusResponse = {
created_at?: string;
error?: {};
result?: {};
updated_at?: string;
};
export type FlagMessageResponse = APIResponse & {
flag: {
created_at: string;
created_by_automod: boolean;
target_message_id: string;
updated_at: string;
user: UserResponse;
approved_at?: string;
channel_cid?: string;
details?: object; // Any JSON
message_user_id?: string;
rejected_at?: string;
reviewed_at?: string;
reviewed_by?: string;
};
review_queue_item_id?: string;
};
export type FlagUserResponse = APIResponse & {
flag: {
created_at: string;
created_by_automod: boolean;
target_user: UserResponse;
updated_at: string;
user: UserResponse;
approved_at?: string;
details?: object; // Any JSON
rejected_at?: string;
reviewed_at?: string;
reviewed_by?: string;
};
review_queue_item_id?: string;
};
export type LocalMessageBase = Omit<
MessageResponseBase,
'created_at' | 'deleted_at' | 'pinned_at' | 'status' | 'updated_at'
> & {
created_at: Date;
deleted_at: Date | null;
pinned_at: Date | null;
status: string;
updated_at: Date;
};
export type LocalMessage = LocalMessageBase & {
error?: ErrorFromResponse<APIErrorResponse> | null;
quoted_message?: LocalMessageBase | null;
};
/**
* @deprecated in favor of LocalMessage
*/
export type FormatMessageResponse = LocalMessage;
export type GetCommandResponse = APIResponse & CreateCommandOptions & CreatedAtUpdatedAt;
export type GetMessageAPIResponse = SendMessageAPIResponse;
export interface ThreadResponse extends CustomThreadData {
// FIXME: according to OpenAPI, `channel` could be undefined but since cid is provided I'll asume that it's wrong
channel: ChannelResponse;
channel_cid: string;
created_at: string;
created_by_user_id: string;
latest_replies: Array<MessageResponse>;
parent_message: MessageResponse;
parent_message_id: string;
title: string;
updated_at: string;
active_participant_count?: number;
created_by?: UserResponse;
deleted_at?: string;
draft?: DraftResponse;
last_message_at?: string;
participant_count?: number;
read?: Array<ReadResponse>;
reply_count?: number;
thread_participants?: Array<{
channel_cid: string;
created_at: string;
last_read_at: string;
last_thread_message_at?: string;
left_thread_at?: string;
thread_id?: string;
user?: UserResponse;
user_id?: string;
}>;
// TODO: when moving to API v2 we should do this instead
// custom: CustomThreadType;
}
// TODO: Figure out a way to strongly type set and unset.
export type PartialThreadUpdate = {
set?: Partial<Record<string, unknown>>;
unset?: Array<string>;
};
export type QueryThreadsOptions = {
filter?: ThreadFilters;
limit?: number;
member_limit?: number;
next?: string;
participant_limit?: number;
reply_limit?: number;
sort?: ThreadSort;
watch?: boolean;
};
export type QueryThreadsAPIResponse = APIResponse & {
threads: ThreadResponse[];
next?: string;
};
export type GetThreadOptions = {
member_limit?: number;
participant_limit?: number;
reply_limit?: number;
watch?: boolean;
};
export type GetThreadAPIResponse = APIResponse & {
thread: ThreadResponse;
};
export type GetMultipleMessagesAPIResponse = APIResponse & {
messages: MessageResponse[];
};
export type GetRateLimitsResponse = APIResponse & {
android?: RateLimitsMap;
ios?: RateLimitsMap;
server_side?: RateLimitsMap;
web?: RateLimitsMap;
};
export enum Product {
Chat = 'chat',
Video = 'video',
Moderation = 'moderation',
Feeds = 'feeds',
}
export type HookEvent = {
name: string;
description: string;
products: Product[];
};
export type GetHookEventsResponse = APIResponse & {
events: HookEvent[];
};
export type GetReactionsAPIResponse = APIResponse & {
reactions: ReactionResponse[];
};
export type GetRepliesAPIResponse = APIResponse & {
messages: MessageResponse[];
};
export type GetUnreadCountAPIResponse = APIResponse & {
channel_type: {
channel_count: number;
channel_type: string;
unread_count: number;
}[];
channels: {
channel_id: string;
last_read: string;
unread_count: number;
}[];
threads: {
last_read: string;
last_read_message_id: string;
parent_message_id: string;
unread_count: number;
}[];
total_unread_count: number;
total_unread_threads_count: number;
total_unread_count_by_team?: Record<string, number>;
};
export type ChatLevelPushPreference =
| 'all'
| 'mentions' // deprecated by the API in favor of 'direct_mentions'
| 'direct_mentions'
| 'all_mentions'
| 'none'
| 'default'
| (string & {});
export type CallLevelPushPreference = 'all' | 'none' | 'default' | (string & {});
/** Granular all/none toggle used by the chat sub-preferences. */
export type PushPreferenceLevel = 'all' | 'none' | (string & {});
/** Per-mention-type chat push preferences (matches OpenAPI `ChatPreferencesInput`). */
export type ChatPreferences = {
channel_mentions?: PushPreferenceLevel;
default_preference?: PushPreferenceLevel;
direct_mentions?: PushPreferenceLevel;
group_mentions?: PushPreferenceLevel;
here_mentions?: PushPreferenceLevel;
role_mentions?: PushPreferenceLevel;
thread_replies?: PushPreferenceLevel;
};
/**
* Input accepted by {@link StreamChat.setPushPreferences} (matches OpenAPI `PushPreferenceInput`).
*
* Set `channel_cid` to scope the preference to a single channel; leave it empty to
* set the user-level default. `user_id` is required for server-side auth and
* defaults to the connected user for client-side auth.
*/
export type PushPreference = {
call_level?: CallLevelPushPreference;
channel_cid?: string;
chat_level?: ChatLevelPushPreference;
chat_preferences?: ChatPreferences;
disabled_until?: string; // snooze until this time
remove_disable?: boolean; // stop snoozing (clears disabled_until)
user_id?: string;
};
/** Per-user push preferences returned by the API (matches OpenAPI `PushPreferencesResponse`). */
export type PushPreferencesResponse = {
call_level?: CallLevelPushPreference;
chat_level?: ChatLevelPushPreference;
chat_preferences?: ChatPreferences;
disabled_until?: string;
};
/** Per-channel push preferences returned by the API (matches OpenAPI `ChannelPushPreferencesResponse`). */
export type ChannelPushPreference = {
chat_level?: ChatLevelPushPreference; // "all", "mentions", "direct_mentions", "all_mentions", "none", "default" or other custom strings
disabled_until?: string;
};
export type UpsertPushPreferencesResponse = APIResponse & {
// Mapping of user id -> channel cid -> channel push preferences
user_channel_preferences: Record<string, Record<string, ChannelPushPreference>>;
// Mapping of user id -> user push preferences
user_preferences: Record<string, PushPreferencesResponse>;
};
export type GetUnreadCountBatchAPIResponse = APIResponse & {
counts_by_user: { [userId: string]: GetUnreadCountAPIResponse };
};
export type ListChannelResponse = APIResponse & {
channel_types: Record<
string,
Omit<CreateChannelOptions, 'client_id' | 'connection_id' | 'commands'> & {
commands: CommandResponse[];
created_at: string;
updated_at: string;
grants?: Record<string, string[]>;
}
>;
};
export type ListChannelTypesAPIResponse = ListChannelResponse;
export type ListCommandsResponse = APIResponse & {
commands: Array<CreateCommandOptions & Partial<CreatedAtUpdatedAt>>;
};
export type MuteChannelAPIResponse = APIResponse & {
channel_mute: ChannelMute;
own_user: OwnUserResponse;
channel_mutes?: ChannelMute[];
mute?: MuteResponse;
};
export type MessageResponse = MessageResponseBase & {
quoted_message?: MessageResponseBase;
};
export type MessageResponseBase = MessageBase & {
type: MessageLabel;
args?: string;
before_message_send_failed?: boolean;
channel?: ChannelResponse;
cid?: string;
command?: string;
command_info?: { name?: string };
created_at?: string;
deleted_at?: string;
deleted_reply_count?: number;
i18n?: RequireAtLeastOne<Record<`${TranslationLanguages}_text`, string>> & {
language: TranslationLanguages;
};
latest_reactions?: ReactionResponse[];
member?: ChannelMemberResponse;
mentioned_users?: UserResponse[];
mentioned_channel?: boolean;
mentioned_here?: boolean;
mentioned_group_ids?: string[];
mentioned_groups?: UserGroupResponse[];
mentioned_roles?: string[];
message_text_updated_at?: string;
moderation?: ModerationResponse; // present only with Moderation v2
moderation_details?: ModerationDetailsResponse; // present only with Moderation v1
own_reactions?: ReactionResponse[] | null;
pin_expires?: string | null;
pinned_at?: string | null;
pinned_by?: UserResponse | null;
poll?: PollResponse;
reaction_counts?: { [key: string]: number } | null;
reaction_groups?: { [key: string]: ReactionGroupResponse } | null;
reaction_scores?: { [key: string]: number } | null;
reminder?: ReminderResponseBase;
reply_count?: number;
shadowed?: boolean;
shared_location?: SharedLocationResponse;
status?: string;
thread_participants?: UserResponse[];
updated_at?: string;
deleted_for_me?: boolean;
};
export type ReactionGroupResponse = {
count: number;
sum_scores: number;
first_reaction_at?: string;
last_reaction_at?: string;
latest_reactions_by?: ReactionGroupUserResponse[];
};
export type ReactionGroupUserResponse = {
created_at: string;
user_id: string;
user?: UserResponse;
};
export type ModerationDetailsResponse = {
action: 'MESSAGE_RESPONSE_ACTION_BOUNCE' | (string & {});
error_msg: string;
harms: ModerationHarmResponse[];
original_text: string;
};
export type ModerationHarmResponse = {
name: string;
phrase_list_ids: number[];
};
export type ModerationAction = 'bounce' | 'flag' | 'remove' | 'shadow';
export type ModerationResponse = {
action: ModerationAction;
original_text: string;
};
export type MuteResponse = {
user: UserResponse;
created_at?: string;
expires?: string;
target?: UserResponse;
updated_at?: string;
};
export type MuteUserResponse = APIResponse & {
mute?: MuteResponse;
mutes?: Array<Mute>;
own_user?: OwnUserResponse;
non_existing_users?: string[];
};
export type UnmuteUserResponse = APIResponse & {
non_existing_users?: string[];
};
export type BlockUserAPIResponse = APIResponse & {
blocked_at: string;
blocked_by_user_id: string;
blocked_user_id: string;
};
export type GetBlockedUsersAPIResponse = APIResponse & {
blocks: BlockedUserDetails[];
};
export type BlockedUserDetails = APIResponse & {
blocked_user: UserResponse;
blocked_user_id: string;
created_at: string;
user: UserResponse;
user_id: string;
};
export type OwnUserBase = {
channel_mutes: ChannelMute[];
devices: Device[];
mutes: Mute[];
total_unread_count: number;
unread_channels: number;
unread_count: number;
unread_threads: number;
invisible?: boolean;
privacy_settings?: PrivacySettings;
push_preferences?: PushPreferencesResponse;
roles?: string[];
total_unread_count_by_team?: Record<string, number> | null;
};
export type OwnUserResponse = UserResponse & OwnUserBase;
export type PartialUpdateChannelAPIResponse = APIResponse & {
channel: ChannelResponse;
members: ChannelMemberResponse[];
};
export type PermissionAPIResponse = APIResponse & {
permission?: PermissionAPIObject;
};
export type PermissionsAPIResponse = APIResponse & {
permissions?: PermissionAPIObject[];
};
export type ReactionAPIResponse = APIResponse & {
message: MessageResponse;
reaction: ReactionResponse;
};
export type ReactionResponse = Reaction & {
created_at: string;
message_id: string;
updated_at: string;
};
export type ReadResponse = {
last_read: string;
user: UserResponse;
last_read_message_id?: string;
unread_messages?: number;
last_delivered_at?: string;
last_delivered_message_id?: string;
};
export type SearchAPIResponse = APIResponse & {
results: {
message: MessageResponse;
}[];
next?: string;
previous?: string;
results_warning?: SearchWarning | null;
};
export type RoleResponse = {
name: Role;
custom: boolean;
scopes: string[];
created_at: string;
updated_at: string;
};
export type CreateRoleAPIResponse = APIResponse & {
role: RoleResponse;
};
export type ListRolesAPIResponse = APIResponse & {
roles: RoleResponse[];
};
export type SearchRolesAPIResponse = APIResponse & {
roles: RoleResponse[];
};
export type SearchRolesOptions = {
query: string;
include_global_roles?: boolean;
limit?: number;
name_gt?: string;
// If not provided, the default is search performed both in user-assignable + channel-assignable roles
role_type?: 'user' | 'channel';
};
export type SearchWarning = {
channel_search_cids: string[];
channel_search_count: number;
warning_code: number;
warning_description: string;
};
// Thumb URL(thumb_url) is added considering video attachments as the backend will return the thumbnail in the response.
export type SendFileAPIResponse = APIResponse & { file: string; thumb_url?: string };
export type SendMessageAPIResponse = APIResponse & {
message: MessageResponse;
pending_message_metadata?: Record<string, string> | null;
};
export type SyncResponse = APIResponse & {
events: Event[];
inaccessible_cids?: string[];
};
export type TruncateChannelAPIResponse = APIResponse & {
channel: ChannelResponse;
message?: MessageResponse;
};
export type UpdateChannelAPIResponse = APIResponse & {
channel: ChannelResponse;
members: ChannelMemberResponse[];
message?: MessageResponse;
};
export type UpdateChannelResponse = APIResponse &
Omit<CreateChannelOptions, 'client_id' | 'connection_id'> & {
created_at: string;
updated_at: string;
};
export type UpdateCommandResponse = APIResponse & {
command: UpdateCommandOptions &
CreatedAtUpdatedAt & {
name: CommandVariants;
};
};
export type UpdateMessageAPIResponse = APIResponse & {
message: MessageResponse;
};
export type UsersAPIResponse = APIResponse & {
users: Array<UserResponse>;
membership_deletion_task_id?: string;
};
export type UpdateUsersAPIResponse = APIResponse & {
users: { [key: string]: UserResponse };
membership_deletion_task_id?: string;
};
export type UserResponse = CustomUserData & {
id: string;
anon?: boolean;
banned?: boolean;
blocked_user_ids?: string[];
/** Set on the user of a read event, marking when they last read the event's channel. */
channel_last_read_at?: string;
created_at?: string;
deactivated_at?: string;
deleted_at?: string;
image?: string;
language?: TranslationLanguages | '';
last_active?: string;
name?: string;
notifications_muted?: boolean;
online?: boolean;
privacy_settings?: PrivacySettings;
push_notifications?: PushNotificationSettings;
revoke_tokens_issued_before?: string;
role?: string;
shadow_banned?: boolean;
teams?: string[];
teams_role?: TeamsRole | null;
updated_at?: string;
username?: string;
avg_response_time?: number;
};
export type TeamsRole = { [team: string]: string };
export type PrivacySettings = {
read_receipts?: {
enabled?: boolean;
};
typing_indicators?: {
enabled?: boolean;
};
delivery_receipts?: {
enabled?: boolean;
};
};
export type PushNotificationSettings = {
disabled?: boolean;
disabled_until?: string | null;
};
/**
* Option Types
*/
export type MessageFlagsPaginationOptions = {
limit?: number;
offset?: number;
};
export type FlagsPaginationOptions = {
limit?: number;
offset?: number;
};
export type FlagReportsPaginationOptions = {
limit?: number;
offset?: number;
};
export type ReviewFlagReportOptions = {
review_details?: object;
user_id?: string;
};
export type BannedUsersPaginationOptions = Omit<
PaginationOptions,
'id_gt' | 'id_gte' | 'id_lt' | 'id_lte'
> & {
exclude_expired_bans?: boolean;
};
export type BanUserOptions = UnBanUserOptions & {
ban_from_future_channels?: boolean;
banned_by?: UserResponse;
banned_by_id?: string;
ip_ban?: boolean;
reason?: string;
timeout?: number;
delete_messages?: MessageDeletionStrategy;
delete_reactions?: boolean;
};
export type ChannelOptions = {
limit?: number;
member_limit?: number;
message_limit?: number;
offset?: number;
presence?: boolean;
state?: boolean;
user_id?: string;
watch?: boolean;
/**
* Name of a predefined filter to use instead of sending raw
* `filter_conditions`.
*
* The backend resolves the filter template by name and interpolates it using
* `filter_values`.
*
* A regular `sort` can still be passed to `queryChannels()`, but backend
* precedence rules apply:
*
* - if the predefined filter has its own stored sort template, that stored
* sort takes precedence and the request `sort` is ignored
* - if the predefined filter does not define a sort template, the request
* `sort` can still be used
*/
predefined_filter?: string;
/**
* Values used to interpolate placeholders inside the predefined filter's
* `filter` template.
*
* Example: a template value like `{{user_id}}` can be resolved with
* `{ user_id: 'alice' }`.
*
* Only used when `predefined_filter` is provided.
*/
filter_values?: Record<string, unknown>;
/**
* Values to interpolate into the predefined filter sort template placeholders.
* Only used when predefined_filter is provided.
*/
sort_values?: Record<string, unknown>;
};
export type ChannelQueryOptions = {
client_id?: string;
connection_id?: string;
created_by?: UserResponse | null;
created_by_id?: UserResponse['id'];
data?: ChannelResponse;
hide_for_creator?: boolean;
members?: PaginationOptions;
messages?: MessagePaginationOptions;
presence?: boolean;
state?: boolean;
watch?: boolean;
watchers?: PaginationOptions;
};
export type ChannelStateOptions = {
offlineMode?: boolean;
skipInitialization?: string[];
skipHydration?: boolean;
/**
* Returns the full query response with hydrated channels from `queryChannels()`.
*
* This is a compatibility bridge for internal callers that need response level
* metadata such as `predefined_filter`. The default `queryChannels()` return value
* remains `Channel[]` to avoid a breaking change. This should be folded into a
* single full response API in the next major release.
*/
withResponse?: boolean;
};
export type CreateChannelOptions = {
automod?: ChannelConfigAutomod;
automod_behavior?: ChannelConfigAutomodBehavior;
automod_thresholds?: ChannelConfigAutomodThresholds;
blocklist?: string;
blocklist_behavior?: ChannelConfigAutomodBehavior;
client_id?: string;
commands?: CommandVariants[];
connect_events?: boolean;
connection_id?: string;
custom_events?: boolean;
delivery_events?: boolean;
grants?: Record<string, string[]>;
mark_messages_pending?: boolean;
max_message_length?: number;
message_retention?: string;
mutes?: boolean;
name?: string;
permissions?: PermissionObject[];
polls?: boolean;
push_notifications?: boolean;
quotes?: boolean;
reactions?: boolean;
read_events?: boolean;
reminders?: boolean;
replies?: boolean;
search?: boolean;
shared_locations?: boolean;
skip_last_msg_update_for_system_msgs?: boolean;
typing_events?: boolean;
uploads?: boolean;
url_enrichment?: boolean;
user_message_reminders?: boolean;
count_messages?: boolean;
push_level?: 'all' | 'all_mentions' | 'direct_mentions' | 'mentions' | 'none';
};
export type CreateCommandOptions = {
description: string;
name: CommandVariants;
args?: string;
set?: CommandVariants;
};
export type CustomPermissionOptions = {
action: string;
condition: object;
id: string;
name: string;
description?: string;
owner?: boolean;
same_team?: boolean;
};
export type DeactivateUsersOptions = {
created_by_id?: string;
mark_messages_deleted?: boolean;
};
export type NewMemberPayload = CustomMemberData &
Pick<ChannelMemberResponse, 'user_id' | 'channel_role'>;
export type Thresholds = Partial<
Record<'explicit' | 'spam' | 'toxic', Partial<{ block: number; flag: number }>>
>;
export type BlockListOptions = {
behavior: BlocklistBehavior;
blocklist: string;
};
export type PolicyRequest = {
action: 'Deny' | 'Allow' | (string & {});
/**
* @description User-friendly policy name
*/
name: string;
/**
* @description Whether policy applies to resource owner or not
*/
owner: boolean;
priority: number;
/**
* @description List of resources to apply policy to
*/
resources: string[];
/**
* @description List of roles to apply policy to
*/
roles: string[];
};
export type Automod = 'disabled' | 'simple' | 'AI' | (string & {});
export type AutomodBehavior = 'flag' | 'block' | 'shadow_block' | (string & {});
export type BlocklistBehavior = AutomodBehavior;
export type Command = {
args: string;
description: string;
name: string;
set: string;
created_at?: string;
updated_at?: string;
};
export type UpdateChannelTypeRequest =
// these three properties are required in OpenAPI spec but omitted in some QA tests
Partial<{
automod: Automod;
automod_behavior: AutomodBehavior;
max_message_length: number;
}> & {
allowed_flag_reasons?: string[];
automod_thresholds?: Thresholds;
blocklist?: string;
blocklist_behavior?: BlocklistBehavior;
blocklists?: BlockListOptions[];
commands?: CommandVariants[];
connect_events?: boolean;
custom_events?: boolean;
delivery_events?: boolean;
grants?: Record<string, string[]>;
mark_messages_pending?: boolean;
mutes?: boolean;
partition_size?: number;
/**
* @example 24h
*/
partition_ttl?: string | null;
permissions?: PolicyRequest[];
polls?: boolean;
push_notifications?: boolean;
quotes?: boolean;
reactions?: boolean;
read_events?: boolean;
reminders?: boolean;
replies?: boolean;
search?: boolean;
skip_last_msg_update_for_system_msgs?: boolean;
typing_events?: boolean;
uploads?: boolean;
url_enrichment?: boolean;
count_messages?: boolean;
push_level?: 'all' | 'all_mentions' | 'direct_mentions' | 'mentions' | 'none';
};
export type UpdateChannelTypeResponse = {
automod: Automod;
automod_behavior: AutomodBehavior;
commands: CommandVariants[];
connect_events: boolean;
created_at: string;
custom_events: boolean;
delivery_events: boolean;
duration: string;
grants: Record<string, string[]>;
mark_messages_pending: boolean;
max_message_length: number;
mutes: boolean;
name: string;
permissions: PolicyRequest[];
polls: boolean;
push_notifications: boolean;
quotes: boolean;
reactions: boolean;
read_events: boolean;
reminders: boolean;
replies: boolean;
search: boolean;
shared_locations: boolean;
skip_last_msg_update_for_system_msgs: boolean;
typing_events: boolean;
updated_at: string;
uploads: boolean;
url_enrichment: boolean;
allowed_flag_reasons?: string[];
automod_thresholds?: Thresholds;
blocklist?: string;
blocklist_behavior?: BlocklistBehavior;
blocklists?: BlockListOptions[];
message_retention?: string;
partition_size?: number;
partition_ttl?: string;
count_messages?: boolean;
user_message_reminders?: boolean;
push_level?: string;
};
export type GetChannelTypeResponse = {
automod: Automod;
automod_behavior: AutomodBehavior;
commands: Command[];
connect_events: boolean;
created_at: string;
custom_events: boolean;
delivery_events: boolean;
duration: string;
grants: Record<string, string[]>;
mark_messages_pending: boolean;
max_message_length: number;
mutes: boolean;
name: string;
permissions: PolicyRequest[];
polls: boolean;
push_notifications: boolean;
quotes: boolean;
reactions: boolean;
read_events: boolean;
reminders: boolean;
replies: boolean;
search: boolean;
shared_locations: boolean;
skip_last_msg_update_for_system_msgs: boolean;
typing_events: boolean;
updated_at: string;
uploads: boolean;
url_enrichment: boolean;
allowed_flag_reasons?: string[];
automod_thresholds?: Thresholds;
blocklist?: string;
blocklist_behavior?: BlocklistBehavior;
blocklists?: BlockListOptions[];
message_retention?: string;
partition_size?: number;
partition_ttl?: string;
count_messages?: boolean;
user_message_reminders?: boolean;
push_level?: string;
};
export type UpdateChannelOptions = Partial<{
accept_invite: boolean;
add_members: string[];
add_moderators: string[];
client_id: string;
connection_id: string;
data: Omit<ChannelResponse, 'id' | 'cid'>;
demote_moderators: string[];
invites: string[];
message: MessageResponse;
reject_invite: boolean;
remove_members: string[];
user: UserResponse;
user_id: string;
}>;
export type MarkChannelsReadOptions = {
client_id?: string;
connection_id?: string;
read_by_channel?: Record<string, string>;
user?: UserResponse;
user_id?: string;
};
export type MarkReadOptions = {
client_id?: string;
connection_id?: string;
thread_id?: string;
user?: UserResponse;
user_id?: string;
};
export type MarkUnreadOptions = {
client_id?: string;
connection_id?: string;
message_id?: string;
thread_id?: string;
message_timestamp?: string | Date;
user?: UserResponse;
user_id?: string;
};
export type DeliveredMessageConfirmation = {
cid: string;
id: string;
parent_id?: string; // todo: should we include parent_id if thread delivery receipts are not yet supported?
};
export type MarkDeliveredOptions = {
latest_delivered_messages: DeliveredMessageConfirmation[];
user?: UserResponse;
user_id?: string;
};
export type MuteUserOptions = {
client_id?: string;
connection_id?: string;
id?: string;
reason?: string;
target_user_id?: string;
timeout?: number;
type?: string;
user?: UserResponse;
user_id?: string;
};
export type PaginationOptions = {
created_at_after?: string | Date;
created_at_after_or_equal?: string | Date;
created_at_before?: string | Date;
created_at_before_or_equal?: string | Date;
id_gt?: string;
id_gte?: string;
id_lt?: string;
id_lte?: string;
limit?: number;
offset?: number; // should be avoided with channel.query()
};
export type MessagePaginationOptions = PaginationOptions & {
created_at_around?: string | Date;
id_around?: string;
};
export type PinnedMessagePaginationOptions = {
id_around?: string;
id_gt?: string;
id_gte?: string;
id_lt?: string;
id_lte?: string;
limit?: number;
offset?: number;
pinned_at_after?: string | Date;
pinned_at_after_or_equal?: string | Date;
pinned_at_around?: string | Date;
pinned_at_before?: string | Date;
pinned_at_before_or_equal?: string | Date;
};
export type QueryMembersOptions = {
// Pagination option: select members created after the date (RFC399)
created_at_after?: string;
// Pagination option: select members created after or equal the date (RFC399)
created_at_after_or_equal?: string;
// Pagination option: select members created before the date (RFC399)
created_at_before?: string;
// Pagination option: select members created before or equal the date (RFC399)
created_at_before_or_equal?: string;
// Number of members to return, default 100
limit?: number;
// Offset (max is 1000)
offset?: number;
// Pagination option: excludes members with ID less or equal the value
user_id_gt?: string;
// Pagination option: excludes members with ID less than the value
user_id_gte?: string;
// Pagination option: excludes members with ID greater or equal the value
user_id_lt?: string;
// Pagination option: excludes members with ID greater than the value
user_id_lte?: string;
};
export type ReactivateUserOptions = {
created_by_id?: string;
name?: string;
restore_messages?: boolean;
};
export type ReactivateUsersOptions = {
created_by_id?: string;
restore_messages?: boolean;
};
export type SearchOptions = {
limit?: number;
next?: string;
offset?: number;
sort?: SearchMessageSort;
};
export type StreamChatOptions = AxiosRequestConfig & {
/**
* Used to disable warnings that are triggered by using connectUser or connectAnonymousUser server-side.
*/
allowServerSideConnect?: boolean;
axiosRequestConfig?: AxiosRequestConfig;
/**
* Base url to use for API
* such as https://chat-proxy-dublin.stream-io-api.com
*/
baseURL?: string;
browser?: boolean;
device?: BaseDeviceFields;
/**
* Disables the hydration of all caches within the JS Client. This includes this.activeChannels,
* this.polls.pollCache and this.config.
* It is mainly meant to be used for integrations where stream-chat is used as a server-side service
* interacting with Stream's REST API, not depending on any state and purely serving as a wrapper
* around HTTP requests. Using this property on either the client side or a backend implementation
* that also relies on WS events will break these functionalities, so please use carefully.
*/
disableCache?: boolean;
enableInsights?: boolean;
/**
* When true, maintains a client-local unread count on channels that have read events disabled
* (e.g. livestreams). The count increments on incoming messages and is reset via
* `channel.markReadLocally()`. It is never sent to the backend, but is persisted to the offline DB.
*/
isLocalUnreadCountEnabled?: boolean;
/** experimental feature, please contact support if you want this feature enabled for you */
enableWSFallback?: boolean;
logger?: Logger;
/**
* Custom notification manager service to use for the client.
* If not provided, a default notification manager will be created.
* Notifications are used to communicate events like errors, warnings, info, etc. Other services can publish notifications or subscribe to the NotificationManager state changes.
*/
notifications?: NotificationManager;
/**
* When true, user will be persisted on client. Otherwise if `connectUser` call fails, then you need to
* call `connectUser` again to retry.
* This is mainly useful for chat application working in offline mode, where you will need client.user to
* persist even if connectUser call fails.
*/
persistUserOnConnectionFailure?: boolean;
/**
* When network is recovered, we re-query the active channels on client. But in single query, you can recover
* only 30 channels. So its not guaranteed that all the channels in activeChannels object have updated state.
* Thus in UI sdks, state recovery is managed by components themselves, they don't rely on js client for this.
*
* `recoverStateOnReconnect` parameter can be used in such cases, to disable state recovery within js client.
* When false, user/consumer of this client will need to make sure all the channels present on UI by
* manually calling queryChannels endpoint.
*/
recoverStateOnReconnect?: boolean;
warmUp?: boolean;
/**
* Set the instance of StableWSConnection on chat client. Its purely for testing purpose and should
* not be used in production apps.
*/
wsConnection?: StableWSConnection;
/**
* Sets a suffix to the wsUrl when it is being built in `wsConnection`. Is meant to be
* used purely in testing suites and should not be used in production apps.
*/
wsUrlParams?: URLSearchParams;
};
export type SyncOptions = {
/**
* This will behave as queryChannels option.
*/
watch?: boolean;
/**
* Return channels from request that user does not have access to in a separate
* field in the response called 'inaccessible_cids' instead of
* adding them as 'notification.removed_from_channel' events.
*/
with_inaccessible_cids?: boolean;
};
export type UnBanUserOptions = {
client_id?: string;
connection_id?: string;
id?: string;
remove_future_channels_ban?: boolean;
shadow?: boolean;
target_user_id?: string;
type?: string;
};
export type UpdateCommandOptions = {
description: string;
args?: string;
set?: CommandVariants;
};
export type UserOptions = {
include_deactivated_users?: boolean;
limit?: number;
offset?: number;
presence?: boolean;
};
/**
* Event Types
*/
export type ConnectionChangeEvent = {
type: EventTypes;
online?: boolean;
};
export type Event = CustomEventData & {
type: EventTypes;
ai_message?: string;
ai_state?: AIState;
channel?: ChannelResponse;
channel_custom?: CustomChannelData;
channel_id?: string;
channel_member_count?: number;
channel_type?: string;
cid?: string;
clear_history?: boolean;
connection_id?: string;
// event creation timestamp, format Date ISO string
created_at?: string;
deleted_for_me?: boolean;
draft?: DraftResponse;
// id of the message that was marked as unread - all the following messages are considered unread. (notification.mark_unread)
first_unread_message_id?: string;
hard_delete?: boolean;
last_delivered_at?: string;
last_delivered_message_id?: string;
// creation date of a message with last_read_message_id, formatted as Date ISO string
last_read_at?: string;
last_read_message_id?: string;
live_location?: SharedLocationResponse;
mark_messages_deleted?: boolean;
me?: OwnUserResponse;
member?: ChannelMemberResponse;
message?: MessageResponse;
message_id?: string;
mode?: string;
online?: boolean;
own_capabilities?: string[];
parent_id?: string;
poll?: PollResponse;
poll_vote?: PollVote | PollAnswer;
queriedChannels?: {
channels: ChannelAPIResponse[];
isLatestMessageSet?: boolean;
};
offlineReactions?: ReactionResponse[];
reaction?: ReactionResponse;
received_at?: string | Date;
reminder?: ReminderResponse;
shadow?: boolean;
team?: string;
thread?: ThreadResponse;
// @deprecated number of all unread messages across all current user's unread channels, equals unread_count
total_unread_count?: number;
// number of all current user's channels with at least one unread message including the channel in this event
unread_channels?: number;
// number of all unread messages across all current user's unread channels
unread_count?: number;
// number of unread messages in the channel from this event (notification.mark_unread)
unread_messages?: number;
unread_thread_messages?: number;
unread_threads?: number;
user?: UserResponse;
user_id?: string;
watcher_count?: number;
channel_last_message_at?: string;
app?: Record<string, unknown>; // TODO: further specify type
thread_id?: string;
};
export type UserCustomEvent = CustomEventData & {
type: string;
};
export type EventHandler = (event: Event) => void;
export type EventTypes = 'all' | keyof typeof EVENT_MAP | keyof CustomEventTypes;
/**
* Filter Types
*/
export type AscDesc = 1 | -1;
export type MessageFlagsFiltersOptions = {
channel_cid?: string;
is_reviewed?: boolean;
team?: string;
user_id?: string;
};
export type MessageFlagsFilters = QueryFilters<
{
channel_cid?:
| RequireOnlyOne<
Pick<QueryFilter<MessageFlagsFiltersOptions['channel_cid']>, '$eq' | '$in'>
>
| PrimitiveFilter<MessageFlagsFiltersOptions['channel_cid']>;
} & {
team?:
| RequireOnlyOne<
Pick<QueryFilter<MessageFlagsFiltersOptions['team']>, '$eq' | '$in'>
>
| PrimitiveFilter<MessageFlagsFiltersOptions['team']>;
} & {
user_id?:
| RequireOnlyOne<
Pick<QueryFilter<MessageFlagsFiltersOptions['user_id']>, '$eq' | '$in'>
>
| PrimitiveFilter<MessageFlagsFiltersOptions['user_id']>;
} & {
[Key in keyof Omit<
MessageFlagsFiltersOptions,
'channel_cid' | 'user_id' | 'is_reviewed'
>]:
| RequireOnlyOne<QueryFilter<MessageFlagsFiltersOptions[Key]>>
| PrimitiveFilter<MessageFlagsFiltersOptions[Key]>;
}
>;
export type FlagsFiltersOptions = {
channel_cid?: string;
message_id?: string;
message_user_id?: string;
reporter_id?: string;
team?: string;
user_id?: string;
};
export type FlagsFilters = QueryFilters<
{
user_id?:
| RequireOnlyOne<Pick<QueryFilter<FlagsFiltersOptions['user_id']>, '$eq' | '$in'>>
| PrimitiveFilter<FlagsFiltersOptions['user_id']>;
} & {
message_id?:
| RequireOnlyOne<
Pick<QueryFilter<FlagsFiltersOptions['message_id']>, '$eq' | '$in'>
>
| PrimitiveFilter<FlagsFiltersOptions['message_id']>;
} & {
message_user_id?:
| RequireOnlyOne<
Pick<QueryFilter<FlagsFiltersOptions['message_user_id']>, '$eq' | '$in'>
>
| PrimitiveFilter<FlagsFiltersOptions['message_user_id']>;
} & {
channel_cid?:
| RequireOnlyOne<
Pick<QueryFilter<FlagsFiltersOptions['channel_cid']>, '$eq' | '$in'>
>
| PrimitiveFilter<FlagsFiltersOptions['channel_cid']>;
} & {
reporter_id?:
| RequireOnlyOne<
Pick<QueryFilter<FlagsFiltersOptions['reporter_id']>, '$eq' | '$in'>
>
| PrimitiveFilter<FlagsFiltersOptions['reporter_id']>;
} & {
team?:
| RequireOnlyOne<Pick<QueryFilter<FlagsFiltersOptions['team']>, '$eq' | '$in'>>
| PrimitiveFilter<FlagsFiltersOptions['team']>;
}
>;
export type FlagReportsFiltersOptions = {
channel_cid?: string;
is_reviewed?: boolean;
message_id?: string;
message_user_id?: string;
report_id?: string;
review_result?: string;
reviewed_by?: string;
team?: string;
user_id?: string;
};
export type FlagReportsFilters = QueryFilters<
{
report_id?:
| RequireOnlyOne<
Pick<QueryFilter<FlagReportsFiltersOptions['report_id']>, '$eq' | '$in'>
>
| PrimitiveFilter<FlagReportsFiltersOptions['report_id']>;
} & {
review_result?:
| RequireOnlyOne<
Pick<QueryFilter<FlagReportsFiltersOptions['review_result']>, '$eq' | '$in'>
>
| PrimitiveFilter<FlagReportsFiltersOptions['review_result']>;
} & {
reviewed_by?:
| RequireOnlyOne<
Pick<QueryFilter<FlagReportsFiltersOptions['reviewed_by']>, '$eq' | '$in'>
>
| PrimitiveFilter<FlagReportsFiltersOptions['reviewed_by']>;
} & {
user_id?:
| RequireOnlyOne<
Pick<QueryFilter<FlagReportsFiltersOptions['user_id']>, '$eq' | '$in'>
>
| PrimitiveFilter<FlagReportsFiltersOptions['user_id']>;
} & {
message_id?:
| RequireOnlyOne<
Pick<QueryFilter<FlagReportsFiltersOptions['message_id']>, '$eq' | '$in'>
>
| PrimitiveFilter<FlagReportsFiltersOptions['message_id']>;
} & {
message_user_id?:
| RequireOnlyOne<
Pick<QueryFilter<FlagReportsFiltersOptions['message_user_id']>, '$eq' | '$in'>
>
| PrimitiveFilter<FlagReportsFiltersOptions['message_user_id']>;
} & {
channel_cid?:
| RequireOnlyOne<
Pick<QueryFilter<FlagReportsFiltersOptions['channel_cid']>, '$eq' | '$in'>
>
| PrimitiveFilter<FlagReportsFiltersOptions['channel_cid']>;
} & {
team?:
| RequireOnlyOne<
Pick<QueryFilter<FlagReportsFiltersOptions['team']>, '$eq' | '$in'>
>
| PrimitiveFilter<FlagReportsFiltersOptions['team']>;
} & {
[Key in keyof Omit<
FlagReportsFiltersOptions,
'report_id' | 'user_id' | 'message_id' | 'review_result' | 'reviewed_by'
>]:
| RequireOnlyOne<QueryFilter<FlagReportsFiltersOptions[Key]>>
| PrimitiveFilter<FlagReportsFiltersOptions[Key]>;
}
>;
export type BannedUsersFilterOptions = {
banned_by_id?: string;
channel_cid?: string;
created_at?: string;
reason?: string;
user_id?: string;
};
export type BannedUsersFilters = QueryFilters<
{
channel_cid?:
| RequireOnlyOne<
Pick<QueryFilter<BannedUsersFilterOptions['channel_cid']>, '$eq' | '$in'>
>
| PrimitiveFilter<BannedUsersFilterOptions['channel_cid']>;
} & {
reason?:
| RequireOnlyOne<
{
$autocomplete?: BannedUsersFilterOptions['reason'];
} & QueryFilter<BannedUsersFilterOptions['reason']>
>
| PrimitiveFilter<BannedUsersFilterOptions['reason']>;
} & {
[Key in keyof Omit<BannedUsersFilterOptions, 'channel_cid' | 'reason'>]:
| RequireOnlyOne<QueryFilter<BannedUsersFilterOptions[Key]>>
| PrimitiveFilter<BannedUsersFilterOptions[Key]>;
}
>;
export type ReactionFilters = QueryFilters<
{
user_id?:
| RequireOnlyOne<Pick<QueryFilter<ReactionResponse['user_id']>, '$eq' | '$in'>>
| PrimitiveFilter<ReactionResponse['user_id']>;
} & {
type?:
| RequireOnlyOne<Pick<QueryFilter<ReactionResponse['type']>, '$eq'>>
| PrimitiveFilter<ReactionResponse['type']>;
} & {
created_at?:
| RequireOnlyOne<
Pick<
QueryFilter<PollResponse['created_at']>,
'$eq' | '$gt' | '$lt' | '$gte' | '$lte'
>
>
| PrimitiveFilter<PollResponse['created_at']>;
}
>;
export type ChannelFilters = QueryFilters<
ContainsOperator<Omit<CustomChannelData, 'name'>> & {
app_banned?: 'only' | 'excluded';
has_unread?: boolean;
archived?: boolean;
'member.user.name'?:
| RequireOnlyOne<{
$autocomplete?: string;
$eq?: string;
}>
| string;
members?:
| RequireOnlyOne<Pick<QueryFilter<string>, '$in'>>
| RequireOnlyOne<Pick<QueryFilter<string[]>, '$eq'>>
| PrimitiveFilter<string[]>;
name?:
| RequireOnlyOne<
{
$autocomplete?: string;
} & QueryFilter<string>
>
| PrimitiveFilter<string>;
pinned?: boolean;
last_updated?:
| RequireOnlyOne<Pick<QueryFilter<string>, '$eq' | '$gt' | '$gte' | '$lt' | '$lte'>>
| PrimitiveFilter<string>;
} & {
[Key in keyof Omit<ChannelResponse, 'name' | 'members' | keyof CustomChannelData>]:
| RequireOnlyOne<QueryFilter<ChannelResponse[Key]>>
| PrimitiveFilter<ChannelResponse[Key]>;
}
>;
export type DraftFilters = {
channel_cid?:
| RequireOnlyOne<Pick<QueryFilter<DraftResponse['channel_cid']>, '$in' | '$eq'>>
| PrimitiveFilter<DraftResponse['channel_cid']>;
created_at?:
| RequireOnlyOne<
Pick<
QueryFilter<DraftResponse['created_at']>,
'$eq' | '$gt' | '$lt' | '$gte' | '$lte'
>
>
| PrimitiveFilter<DraftResponse['created_at']>;
parent_id?:
| RequireOnlyOne<
Pick<QueryFilter<DraftResponse['created_at']>, '$in' | '$eq' | '$exists'>
>
| PrimitiveFilter<DraftResponse['parent_id']>;
};
export type QueryPollsParams = {
filter?: QueryPollsFilters;
options?: QueryPollsOptions;
sort?: PollSort;
};
export type QueryPollsOptions = Pager;
export type VotesFiltersOptions = {
is_answer?: boolean;
option_id?: string;
user_id?: string;
};
export type QueryVotesOptions = Pager;
export type QueryPollsFilters = QueryFilters<
{
id?:
| RequireOnlyOne<Pick<QueryFilter<PollResponse['id']>, '$eq' | '$in'>>
| PrimitiveFilter<PollResponse['id']>;
} & {
user_id?:
| RequireOnlyOne<Pick<QueryFilter<VotesFiltersOptions['user_id']>, '$eq' | '$in'>>
| PrimitiveFilter<VotesFiltersOptions['user_id']>;
} & {
is_closed?:
| RequireOnlyOne<Pick<QueryFilter<PollResponse['is_closed']>, '$eq'>>
| PrimitiveFilter<PollResponse['is_closed']>;
} & {
max_votes_allowed?:
| RequireOnlyOne<
Pick<
QueryFilter<PollResponse['max_votes_allowed']>,
'$eq' | '$gt' | '$lt' | '$gte' | '$lte'
>
>
| PrimitiveFilter<PollResponse['max_votes_allowed']>;
} & {
allow_answers?:
| RequireOnlyOne<Pick<QueryFilter<PollResponse['allow_answers']>, '$eq'>>
| PrimitiveFilter<PollResponse['allow_answers']>;
} & {
allow_user_suggested_options?:
| RequireOnlyOne<
Pick<QueryFilter<PollResponse['allow_user_suggested_options']>, '$eq'>
>
| PrimitiveFilter<PollResponse['allow_user_suggested_options']>;
} & {
voting_visibility?:
| RequireOnlyOne<Pick<QueryFilter<PollResponse['voting_visibility']>, '$eq'>>
| PrimitiveFilter<PollResponse['voting_visibility']>;
} & {
created_at?:
| RequireOnlyOne<
Pick<
QueryFilter<PollResponse['created_at']>,
'$eq' | '$gt' | '$lt' | '$gte' | '$lte'
>
>
| PrimitiveFilter<PollResponse['created_at']>;
} & {
created_by_id?:
| RequireOnlyOne<Pick<QueryFilter<PollResponse['created_by_id']>, '$eq' | '$in'>>
| PrimitiveFilter<PollResponse['created_by_id']>;
} & {
updated_at?:
| RequireOnlyOne<
Pick<
QueryFilter<PollResponse['updated_at']>,
'$eq' | '$gt' | '$lt' | '$gte' | '$lte'
>
>
| PrimitiveFilter<PollResponse['updated_at']>;
} & {
name?:
| RequireOnlyOne<Pick<QueryFilter<PollResponse['name']>, '$eq' | '$in'>>
| PrimitiveFilter<PollResponse['name']>;
}
>;
export type QueryVotesFilters = QueryFilters<
{
id?:
| RequireOnlyOne<Pick<QueryFilter<PollResponse['id']>, '$eq' | '$in'>>
| PrimitiveFilter<PollResponse['id']>;
} & {
option_id?:
| RequireOnlyOne<Pick<QueryFilter<VotesFiltersOptions['option_id']>, '$eq' | '$in'>>
| PrimitiveFilter<VotesFiltersOptions['option_id']>;
} & {
is_answer?:
| RequireOnlyOne<Pick<QueryFilter<VotesFiltersOptions['is_answer']>, '$eq'>>
| PrimitiveFilter<VotesFiltersOptions['is_answer']>;
} & {
user_id?:
| RequireOnlyOne<Pick<QueryFilter<VotesFiltersOptions['user_id']>, '$eq' | '$in'>>
| PrimitiveFilter<VotesFiltersOptions['user_id']>;
} & {
created_at?:
| RequireOnlyOne<
Pick<
QueryFilter<PollResponse['created_at']>,
'$eq' | '$gt' | '$lt' | '$gte' | '$lte'
>
>
| PrimitiveFilter<PollResponse['created_at']>;
} & {
created_by_id?:
| RequireOnlyOne<Pick<QueryFilter<PollResponse['created_by_id']>, '$eq' | '$in'>>
| PrimitiveFilter<PollResponse['created_by_id']>;
} & {
updated_at?:
| RequireOnlyOne<
Pick<
QueryFilter<PollResponse['updated_at']>,
'$eq' | '$gt' | '$lt' | '$gte' | '$lte'
>
>
| PrimitiveFilter<PollResponse['updated_at']>;
}
>;
export type ContainsOperator<CustomType = {}> = {
[Key in keyof CustomType]?: CustomType[Key] extends (infer ContainType)[]
?
| RequireOnlyOne<
{
$contains?: ContainType extends object
? PrimitiveFilter<RequireAtLeastOne<ContainType>>
: PrimitiveFilter<ContainType>;
} & QueryFilter<PrimitiveFilter<ContainType>[]>
>
| PrimitiveFilter<PrimitiveFilter<ContainType>[]>
: RequireOnlyOne<QueryFilter<CustomType[Key]>> | PrimitiveFilter<CustomType[Key]>;
};
export type MessageFilters = QueryFilters<
ContainsOperator<CustomMessageData> & {
'attachments.type'?:
| RequireOnlyOne<{
$eq: PrimitiveFilter<Attachment['type']>;
$in: PrimitiveFilter<Attachment['type']>[];
}>
| PrimitiveFilter<Attachment['type']>;
'mentioned_users.id'?: RequireOnlyOne<{
$contains: PrimitiveFilter<UserResponse['id']>;
}>;
text?:
| RequireOnlyOne<
{
$autocomplete?: MessageResponse['text'];
$q?: MessageResponse['text'];
} & QueryFilter<MessageResponse['text']>
>
| PrimitiveFilter<MessageResponse['text']>;
'user.id'?:
| RequireOnlyOne<
{
$autocomplete?: UserResponse['id'];
} & QueryFilter<UserResponse['id']>
>
| PrimitiveFilter<UserResponse['id']>;
} & {
[Key in keyof Omit<MessageResponse, 'text' | keyof CustomMessageData>]?:
| RequireOnlyOne<QueryFilter<MessageResponse[Key]>>
| PrimitiveFilter<MessageResponse[Key]>;
}
>;
export type MessageOptions = {
include_thread_participants?: boolean;
};
export type PrimitiveFilter<ObjectType> = ObjectType | null;
export type QueryFilter<ObjectType = string> =
NonNullable<ObjectType> extends string | number | boolean
? {
$eq?: PrimitiveFilter<ObjectType>;
$exists?: boolean;
$gt?: PrimitiveFilter<ObjectType>;
$gte?: PrimitiveFilter<ObjectType>;
$in?: PrimitiveFilter<ObjectType>[];
$lt?: PrimitiveFilter<ObjectType>;
$lte?: PrimitiveFilter<ObjectType>;
}
: {
$eq?: PrimitiveFilter<ObjectType>;
$exists?: boolean;
$in?: PrimitiveFilter<Unpacked<ObjectType>>[];
};
export type QueryFilters<Operators = {}> = {
[Key in keyof Operators]?: Operators[Key];
} & QueryLogicalOperators<Operators>;
export type QueryLogicalOperators<Operators> = {
$and?: ArrayOneOrMore<QueryFilters<Operators>>;
$nor?: ArrayOneOrMore<QueryFilters<Operators>>;
$or?: ArrayTwoOrMore<QueryFilters<Operators>>;
};
export type UserFilters = QueryFilters<
ContainsOperator<CustomUserData> & {
id?:
| RequireOnlyOne<
{ $autocomplete?: UserResponse['id'] } & QueryFilter<UserResponse['id']>
>
| PrimitiveFilter<UserResponse['id']>;
name?:
| RequireOnlyOne<
{ $autocomplete?: UserResponse['name'] } & QueryFilter<UserResponse['name']>
>
| PrimitiveFilter<UserResponse['name']>;
notifications_muted?:
| RequireOnlyOne<{
$eq?: PrimitiveFilter<UserResponse['notifications_muted']>;
}>
| boolean;
teams?:
| RequireOnlyOne<{
$contains?: PrimitiveFilter<string>;
$eq?: PrimitiveFilter<UserResponse['teams']>;
$in?: PrimitiveFilter<UserResponse['teams']>;
}>
| PrimitiveFilter<UserResponse['teams']>;
username?:
| RequireOnlyOne<
{ $autocomplete?: UserResponse['username'] } & QueryFilter<
UserResponse['username']
>
>
| PrimitiveFilter<UserResponse['username']>;
} & {
[Key in keyof Omit<
UserResponse,
'id' | 'name' | 'teams' | 'username' | keyof CustomUserData
>]?:
| RequireOnlyOne<QueryFilter<UserResponse[Key]>>
| PrimitiveFilter<UserResponse[Key]>;
}
>;
export type InviteStatus = 'pending' | 'accepted' | 'rejected' | 'member';
// https://getstream.io/chat/docs/react/channel_member/#update-channel-members
export type MemberFilters = QueryFilters<
{
banned?: { $eq?: ChannelMemberResponse['banned'] } | ChannelMemberResponse['banned'];
channel_role?:
| { $eq?: ChannelMemberResponse['channel_role'] }
| ChannelMemberResponse['channel_role'];
cid?: { $eq?: ChannelResponse['cid'] } | ChannelResponse['cid'];
created_at?:
| {
$eq?: ChannelMemberResponse['created_at'];
$gt?: ChannelMemberResponse['created_at'];
$gte?: ChannelMemberResponse['created_at'];
$lt?: ChannelMemberResponse['created_at'];
$lte?: ChannelMemberResponse['created_at'];
}
| ChannelMemberResponse['created_at'];
id?:
| RequireOnlyOne<{
$eq?: UserResponse['id'];
$in?: UserResponse['id'][];
}>
| UserResponse['id'];
invite?: { $eq?: ChannelMemberResponse['status'] } | ChannelMemberResponse['status'];
is_moderator?:
| RequireOnlyOne<{ $eq?: ChannelMemberResponse['is_moderator'] }>
| ChannelMemberResponse['is_moderator'];
joined?: { $eq?: boolean } | boolean;
last_active?:
| {
$eq?: UserResponse['last_active'];
$gt?: UserResponse['last_active'];
$gte?: UserResponse['last_active'];
$lt?: UserResponse['last_active'];
$lte?: UserResponse['last_active'];
}
| UserResponse['last_active'];
name?:
| RequireOnlyOne<{
$autocomplete?: NonNullable<ChannelMemberResponse['user']>['name'];
$eq?: NonNullable<ChannelMemberResponse['user']>['name'];
$in?: NonNullable<ChannelMemberResponse['user']>['name'][];
$q?: NonNullable<ChannelMemberResponse['user']>['name'];
}>
| PrimitiveFilter<NonNullable<ChannelMemberResponse['user']>['name']>;
notifications_muted?:
| RequireOnlyOne<{ $eq?: ChannelMemberResponse['notifications_muted'] }>
| ChannelMemberResponse['notifications_muted'];
updated_at?:
| {
$eq?: ChannelMemberResponse['updated_at'];
$gt?: ChannelMemberResponse['updated_at'];
$gte?: ChannelMemberResponse['updated_at'];
$lt?: ChannelMemberResponse['updated_at'];
$lte?: ChannelMemberResponse['updated_at'];
}
| ChannelMemberResponse['updated_at'];
'user.email'?:
| RequireOnlyOne<{
$autocomplete?: string;
$eq?: string;
$in?: string;
}>
| string;
user_id?:
| RequireOnlyOne<{
$eq?: ChannelMemberResponse['user_id'];
$in?: ChannelMemberResponse['user_id'][];
}>
| PrimitiveFilter<ChannelMemberResponse['user_id']>;
} & {
[Key in keyof ContainsOperator<CustomMemberData>]?:
| RequireOnlyOne<QueryFilter<ContainsOperator<CustomMemberData>[Key]>>
| PrimitiveFilter<ContainsOperator<CustomMemberData>[Key]>;
}
>;
/**
* Sort Types
*/
export type BannedUsersSort = BannedUsersSortBase | Array<BannedUsersSortBase>;
export type BannedUsersSortBase = { created_at?: AscDesc };
export type ReactionSort = ReactionSortBase | Array<ReactionSortBase>;
export type ReactionSortBase = Sort<CustomReactionData> & {
created_at?: AscDesc;
};
export type ChannelSort = ChannelSortBase | Array<ChannelSortBase>;
export type ChannelSortBase = Sort<CustomChannelData> & {
created_at?: AscDesc;
has_unread?: AscDesc;
last_message_at?: AscDesc;
last_updated?: AscDesc;
member_count?: AscDesc;
pinned_at?: AscDesc;
unread_count?: AscDesc;
updated_at?: AscDesc;
};
export type PinnedMessagesSort = PinnedMessagesSortBase | Array<PinnedMessagesSortBase>;
export type PinnedMessagesSortBase = { pinned_at?: AscDesc };
export type Sort<T> = {
[P in keyof T]?: AscDesc;
};
export type UserSort = Sort<UserResponse> | Array<Sort<UserResponse>>;
export type MemberSort =
| Sort<
Pick<UserResponse, 'created_at' | 'last_active' | 'name' | 'updated_at'> & {
user_id?: string;
}
>
| Array<
Sort<
Pick<UserResponse, 'created_at' | 'last_active' | 'name' | 'updated_at'> & {
user_id?: string;
}
>
>;
export type SearchMessageSortBase = Sort<CustomMessageData> & {
attachments?: AscDesc;
'attachments.type'?: AscDesc;
created_at?: AscDesc;
id?: AscDesc;
'mentioned_users.id'?: AscDesc;
parent_id?: AscDesc;
pinned?: AscDesc;
relevance?: AscDesc;
reply_count?: AscDesc;
text?: AscDesc;
type?: AscDesc;
updated_at?: AscDesc;
'user.id'?: AscDesc;
};
export type SearchMessageSort = SearchMessageSortBase | Array<SearchMessageSortBase>;
export type QuerySort = BannedUsersSort | ChannelSort | SearchMessageSort | UserSort;
export type DraftSortBase = {
created_at?: AscDesc;
};
export type DraftSort = DraftSortBase | Array<DraftSortBase>;
export type PollSort = PollSortBase | Array<PollSortBase>;
export type PollSortBase = {
created_at?: AscDesc;
id?: AscDesc;
is_closed?: AscDesc;
name?: AscDesc;
updated_at?: AscDesc;
};
export type VoteSort = VoteSortBase | Array<VoteSortBase>;
export type VoteSortBase = {
created_at?: AscDesc;
id?: AscDesc;
is_closed?: AscDesc;
name?: AscDesc;
updated_at?: AscDesc;
};
/**
* Base Types
*/
export type Action = {
name?: string;
style?: string;
text?: string;
type?: string;
value?: string;
};
export type AnonUserType = {};
export type APNConfig = {
auth_key?: string;
auth_type?: string;
bundle_id?: string;
development?: boolean;
enabled?: boolean;
host?: string;
key_id?: string;
notification_template?: string;
p12_cert?: string;
team_id?: string;
};
export type AsyncModerationOptions = {
callback?: {
mode?: 'CALLBACK_MODE_NONE' | 'CALLBACK_MODE_REST' | 'CALLBACK_MODE_TWIRP';
server_url?: string;
};
timeout_ms?: number;
};
export type AppSettings = {
allowed_flag_reasons?: string[];
apn_config?: {
auth_key?: string;
auth_type?: string;
bundle_id?: string;
development?: boolean;
host?: string;
key_id?: string;
notification_template?: string;
p12_cert?: string;
team_id?: string;
};
async_moderation_config?: AsyncModerationOptions;
async_url_enrich_enabled?: boolean;
auto_translation_enabled?: boolean;
before_message_send_hook_url?: string;
before_message_send_hook_attempt_timeout_ms?: number;
cdn_expiration_seconds?: number;
custom_action_handler_url?: string;
disable_auth_checks?: boolean;
disable_permissions_checks?: boolean;
enforce_unique_usernames?: 'no' | 'app' | 'team';
event_hooks?: Array<EventHook> | null;
explicit_event_hooks_deletion?: boolean;
// all possible file mime types are https://www.iana.org/assignments/media-types/media-types.xhtml
file_upload_config?: FileUploadConfig;
firebase_config?: {
apn_template?: string;
credentials_json?: string;
data_template?: string;
notification_template?: string;
server_key?: string;
};
grants?: Record<string, string[]>;
huawei_config?: {
id: string;
secret: string;
};
image_moderation_enabled?: boolean;
image_upload_config?: FileUploadConfig;
migrate_permissions_to_v2?: boolean;
multi_tenant_enabled?: boolean;
permission_version?: 'v1' | 'v2';
push_config?: {
offline_only?: boolean;
version?: string;
};
reminders_interval?: number;
revoke_tokens_issued_before?: string | null;
sns_key?: string;
sns_secret?: string;
sns_topic_arn?: string;
sqs_key?: string;
sqs_secret?: string;
sqs_url?: string;
user_response_time_enabled?: boolean;
video_provider?: string;
webhook_events?: Array<string> | null;
webhook_url?: string;
xiaomi_config?: {
package_name: string;
secret: string;
};
};
export type Attachment = CustomAttachmentData & {
actions?: Action[];
asset_url?: string;
author_icon?: string;
author_link?: string;
author_name?: string;
color?: string;
duration?: number;
fallback?: string;
fields?: Field[];
file_size?: number | string;
footer?: string;
footer_icon?: string;
giphy?: GiphyData;
image_url?: string;
latitude?: number;
longitude?: number;
mime_type?: string;
og_scrape_url?: string;
original_height?: number;
original_width?: number;
pretext?: string;
text?: string;
thumb_url?: string;
title?: string;
title_link?: string;
type?: string;
waveform_data?: Array<number>;
};
export type OGAttachment = {
og_scrape_url: string;
asset_url?: string; // og:video | og:audio
author_link?: string; // og:site
author_name?: string; // og:site_name
image_url?: string; // og:image
text?: string; // og:description
thumb_url?: string; // og:image
title?: string; // og:title
title_link?: string; // og:url
type?: string | 'video' | 'audio' | 'image';
};
export type BlockList = {
name: string;
words: string[];
team?: string;
type?: string;
validate?: boolean;
is_confusable_folding_enabled?: boolean;
is_leet_check_enabled?: boolean;
is_plural_check_enabled?: boolean;
is_substring_matching_enabled?: boolean;
};
export type ChannelConfig = ChannelConfigFields &
CreatedAtUpdatedAt & {
commands?: CommandVariants[];
};
export type ChannelConfigAutomod = Automod;
export type ChannelConfigAutomodBehavior = AutomodBehavior;
export type ChannelConfigAutomodThresholds = null | Thresholds;
export type ChannelConfigFields = {
reminders: boolean;
automod?: ChannelConfigAutomod;
automod_behavior?: ChannelConfigAutomodBehavior;
automod_thresholds?: ChannelConfigAutomodThresholds;
blocklist_behavior?: ChannelConfigAutomodBehavior;
connect_events?: boolean;
custom_events?: boolean;
delivery_events?: boolean;
mark_messages_pending?: boolean;
max_message_length?: number;
message_retention?: string;
mutes?: boolean;
name?: string;
polls?: boolean;
push_notifications?: boolean;
quotes?: boolean;
reactions?: boolean;
read_events?: boolean;
replies?: boolean;
search?: boolean;
shared_locations?: boolean;
skip_last_msg_update_for_system_msgs?: boolean;
count_messages?: boolean;
typing_events?: boolean;
uploads?: boolean;
url_enrichment?: boolean;
user_message_reminders?: boolean; // Feature flag for user message reminders
push_level?: 'all' | 'all_mentions' | 'direct_mentions' | 'mentions' | 'none' | '';
};
export type ChannelConfigWithInfo = ChannelConfigFields &
CreatedAtUpdatedAt & {
commands?: CommandResponse[];
};
export type ChannelData = CustomChannelData &
Partial<{
blocked: boolean;
created_by: UserResponse | null;
created_by_id: UserResponse['id'];
members: string[] | Array<NewMemberPayload>;
blocklist_behavior: AutomodBehavior;
automod: Automod;
filter_tags: string[];
team?: string;
}>;
export type ChannelMute = {
user: UserResponse;
channel?: ChannelResponse;
created_at?: string;
expires?: string;
updated_at?: string;
};
export type ChannelRole = {
custom?: boolean;
name?: string;
owner?: boolean;
resource?: string;
same_team?: boolean;
};
export type CheckPushInput = {
apn_template?: string;
client_id?: string;
connection_id?: string;
firebase_data_template?: string;
firebase_template?: string;
message_id?: string;
user?: UserResponse;
user_id?: string;
};
export type PushProvider = 'apn' | 'firebase' | 'huawei' | 'xiaomi';
export type PushProviderConfig = PushProviderCommon &
PushProviderID &
PushProviderAPN &
PushProviderFirebase &
PushProviderHuawei &
PushProviderXiaomi;
export type PushProviderID = {
name: string;
type: PushProvider;
};
export type PushProviderCommon = {
created_at: string;
updated_at: string;
description?: string;
disabled_at?: string;
disabled_reason?: string;
};
export type PushProviderAPN = {
apn_auth_key?: string;
apn_auth_type?: 'token' | 'certificate';
apn_development?: boolean;
apn_host?: string;
apn_key_id?: string;
apn_notification_template?: string;
apn_p12_cert?: string;
apn_team_id?: string;
apn_topic?: string;
};
export type PushProviderFirebase = {
firebase_apn_template?: string;
firebase_credentials?: string;
firebase_data_template?: string;
firebase_notification_template?: string;
firebase_server_key?: string;
};
export type PushProviderHuawei = {
huawei_app_id?: string;
huawei_app_secret?: string;
};
export type PushProviderXiaomi = {
xiaomi_package_name?: string;
xiaomi_secret?: string;
};
export type CommandVariants =
| 'all'
| 'ban'
| 'fun_set'
| 'giphy'
| 'moderation_set'
| 'mute'
| 'unban'
| 'unmute'
| keyof CustomCommandData;
export type Configs = Record<string, ChannelConfigWithInfo | undefined>;
export type ConnectionOpen = {
connection_id: string;
cid?: string;
created_at?: string;
received_at?: string;
me?: OwnUserResponse;
type?: string;
};
export type CreatedAtUpdatedAt = {
created_at: string;
updated_at: string;
};
export type Device = DeviceFields & {
provider?: string;
user?: UserResponse;
user_id?: string;
};
export type BaseDeviceFields = {
id: string;
push_provider: PushProvider;
push_provider_name?: string;
};
export type DeviceFields = BaseDeviceFields & {
created_at: string;
disabled?: boolean;
disabled_reason?: string;
};
export type EndpointName =
| 'Connect'
| 'LongPoll'
| 'DeleteFile'
| 'DeleteImage'
| 'DeleteMessage'
| 'DeleteUser'
| 'DeleteUsers'
| 'DeactivateUser'
| 'ExportUser'
| 'DeleteReaction'
| 'UpdateChannel'
| 'UpdateChannelPartial'
| 'UpdateMessage'
| 'UpdateMessagePartial'
| 'GetMessage'
| 'GetManyMessages'
| 'UpdateUsers'
| 'UpdateUsersPartial'
| 'CreateGuest'
| 'GetOrCreateChannel'
| 'StopWatchingChannel'
| 'QueryChannels'
| 'Search'
| 'QueryUsers'
| 'QueryMembers'
| 'QueryBannedUsers'
| 'QueryFlags'
| 'QueryMessageFlags'
| 'GetReactions'
| 'GetReplies'
| 'GetPinnedMessages'
| 'Ban'
| 'Unban'
| 'MuteUser'
| 'MuteChannel'
| 'UnmuteChannel'
| 'UnmuteUser'
| 'RunMessageAction'
| 'SendEvent'
| 'SendUserCustomEvent'
| 'MarkRead'
| 'MarkChannelsRead'
| 'SendMessage'
| 'ImportChannelMessages'
| 'UploadFile'
| 'UploadImage'
| 'UpdateApp'
| 'GetApp'
| 'CreateDevice'
| 'DeleteDevice'
| 'SendReaction'
| 'Flag'
| 'Unflag'
| 'Unblock'
| 'QueryFlagReports'
| 'FlagReportReview'
| 'CreateChannelType'
| 'DeleteChannel'
| 'DeleteChannels'
| 'DBDeleteChannelType'
| 'GetChannelType'
| 'ListChannelTypes'
| 'ListDevices'
| 'TruncateChannel'
| 'UpdateChannelType'
| 'CheckPush'
| 'PrivateSubmitModeration'
| 'ReactivateUser'
| 'HideChannel'
| 'ShowChannel'
| 'CreatePermission'
| 'UpdatePermission'
| 'GetPermission'
| 'DeletePermission'
| 'ListPermissions'
| 'CreateRole'
| 'DeleteRole'
| 'ListRoles'
| 'ListCustomRoles'
| 'Sync'
| 'TranslateMessage'
| 'CreateCommand'
| 'GetCommand'
| 'UpdateCommand'
| 'DeleteCommand'
| 'ListCommands'
| 'CreateBlockList'
| 'UpdateBlockList'
| 'GetBlockList'
| 'ListBlockLists'
| 'DeleteBlockList'
| 'ExportChannels'
| 'GetExportChannelsStatus'
| 'CheckSQS'
| 'GetRateLimits'
| 'CreateSegment'
| 'GetSegment'
| 'QuerySegments'
| 'UpdateSegment'
| 'DeleteSegment'
| 'CreateCampaign'
| 'GetCampaign'
| 'ListCampaigns'
| 'UpdateCampaign'
| 'DeleteCampaign'
| 'ScheduleCampaign'
| 'StopCampaign'
| 'ResumeCampaign'
| 'TestCampaign'
| 'GetOG'
| 'GetTask'
| 'ExportUsers'
| 'CreateImport'
| 'CreateImportURL'
| 'GetImport'
| 'ListImports'
| 'UpsertPushProvider'
| 'DeletePushProvider'
| 'ListPushProviders'
| 'CreatePoll';
export type ExportChannelRequest = (
| {
id: string;
type: string;
}
| {
cid: string;
}
) & { messages_since?: Date; messages_until?: Date };
export type ExportChannelOptions = {
clear_deleted_message_text?: boolean;
export_users?: boolean;
include_soft_deleted_channels?: boolean;
include_truncated_messages?: boolean;
version?: string;
};
export type ExportUsersRequest = {
user_ids: string[];
};
export type Field = {
short?: boolean;
title?: string;
value?: string;
};
export type FileUploadConfig = {
allowed_file_extensions?: string[] | null;
allowed_mime_types?: string[] | null;
blocked_file_extensions?: string[] | null;
blocked_mime_types?: string[] | null;
size_limit?: number | null;
};
export type FirebaseConfig = {
apn_template?: string;
credentials_json?: string;
data_template?: string;
enabled?: boolean;
notification_template?: string;
server_key?: string;
};
type GiphyVersionInfo = {
height: string;
url: string;
width: string;
frames?: string;
size?: string;
};
export type GiphyVersions =
| 'original'
| 'fixed_height'
| 'fixed_height_still'
| 'fixed_height_downsampled'
| 'fixed_width'
| 'fixed_width_still'
| 'fixed_width_downsampled';
export type GiphyData = {
[key in GiphyVersions]: GiphyVersionInfo;
};
export type HuaweiConfig = {
enabled?: boolean;
id?: string;
secret?: string;
};
export type XiaomiConfig = {
enabled?: boolean;
package_name?: string;
secret?: string;
};
export type LiteralStringForUnion = string & {};
export type LogLevel = 'info' | 'error' | 'warn';
export type Logger = (
logLevel: LogLevel,
message: string,
extraData?: Record<string, unknown>,
) => void;
export type Message = Partial<
MessageBase & {
mentioned_users: string[];
shared_location?: StaticLocationPayload | LiveLocationPayload;
mentioned_channel?: boolean;
mentioned_here?: boolean;
mentioned_group_ids?: string[];
mentioned_roles?: string[];
}
>;
export type MessageBase = CustomMessageData & {
id: string;
attachments?: Attachment[];
html?: string;
mml?: string;
parent_id?: string;
pin_expires?: string | null;
pinned?: boolean;
pinned_at?: string | null;
poll_id?: string;
quoted_message_id?: string;
restricted_visibility?: string[];
show_in_channel?: boolean;
silent?: boolean;
text?: string;
type?: MessageLabel;
user?: UserResponse | null;
user_id?: string;
};
export type MessageLabel =
| 'deleted'
| 'ephemeral'
| 'error'
| 'regular'
| 'reply'
| 'system';
export type SendMessageOptions = {
force_moderation?: boolean;
// @deprecated use `pending` instead
is_pending_message?: boolean;
keep_channel_hidden?: boolean;
pending?: boolean;
pending_message_metadata?: Record<string, string>;
skip_enrich_url?: boolean;
skip_push?: boolean;
};
export type UpdateMessageOptions = {
skip_enrich_url?: boolean;
skip_push?: boolean;
};
export type SendReactionOptions = {
enforce_unique?: boolean;
skip_push?: boolean;
};
export type GetMessageOptions = {
show_deleted_message?: boolean;
};
export type Mute = {
created_at: string;
target: UserResponse;
updated_at: string;
user: UserResponse;
};
export type PartialUpdateChannelFields = Partial<ChannelResponse> & {
config_overrides?: Partial<ChannelConfigFields>;
};
export type PartialUpdateChannel = {
set?: PartialUpdateChannelFields;
unset?: Array<keyof PartialUpdateChannelFields>;
};
export type PartialUpdateMember = {
set?: ChannelMemberUpdates;
unset?: Array<keyof ChannelMemberUpdates>;
};
export type PartialUserUpdate = {
id: string;
set?: Partial<UserResponse>;
unset?: Array<keyof UserResponse>;
};
export type MessageUpdatableFields = Omit<
MessageResponse,
'cid' | 'created_at' | 'updated_at' | 'deleted_at' | 'user' | 'user_id'
>;
export type PartialMessageUpdate = {
set?: Partial<MessageUpdatableFields>;
unset?: Array<keyof MessageUpdatableFields>;
};
export type PendingMessageResponse = {
message: MessageResponse;
pending_message_metadata?: Record<string, string>;
};
export type PermissionAPIObject = {
action?: string;
condition?: object;
custom?: boolean;
description?: string;
id?: string;
level?: string;
name?: string;
owner?: boolean;
/** Resource type that defines ownership for this permission's action, e.g. 'Channel' for CreateMessage. */
owner_resource?: string;
same_team?: boolean;
tags?: string[];
};
export type PermissionObject = {
action?: 'Deny' | 'Allow';
name?: string;
owner?: boolean;
priority?: number;
resources?: string[];
roles?: string[];
};
export type Policy = {
action?: 0 | 1;
created_at?: string;
name?: string;
owner?: boolean;
priority?: number;
resources?: string[];
roles?: string[] | null;
updated_at?: string;
};
export type RateLimitsInfo = {
limit: number;
remaining: number;
reset: number;
};
export type RateLimitsMap = Record<EndpointName, RateLimitsInfo>;
export type Reaction = CustomReactionData & {
type: string;
message_id?: string;
score?: number;
user?: UserResponse | null;
user_id?: string;
emoji_code?: string;
};
export type Resource =
| 'AddLinks'
| 'BanUser'
| 'CreateChannel'
| 'CreateMessage'
| 'CreateReaction'
| 'DeleteAttachment'
| 'DeleteChannel'
| 'DeleteMessage'
| 'DeleteReaction'
| 'EditUser'
| 'MuteUser'
| 'ReadChannel'
| 'RunMessageAction'
| 'UpdateChannel'
| 'UpdateChannelMembers'
| 'UpdateMessage'
| 'UpdateUser'
| 'UploadAttachment';
export type SearchPayload = Omit<SearchOptions, 'sort'> & {
client_id?: string;
connection_id?: string;
filter_conditions?: ChannelFilters;
message_filter_conditions?: MessageFilters;
message_options?: MessageOptions;
query?: string;
sort?: Array<{
direction: AscDesc;
field: keyof SearchMessageSortBase;
}>;
};
export type TestPushDataInput = {
apnTemplate?: string;
firebaseDataTemplate?: string;
firebaseTemplate?: string;
messageID?: string;
pushProviderName?: string;
pushProviderType?: PushProvider;
skipDevices?: boolean;
};
export type TestSQSDataInput = {
sqs_key?: string;
sqs_secret?: string;
sqs_url?: string;
};
export type TestSNSDataInput = {
sns_key?: string;
sns_secret?: string;
sns_topic_arn?: string;
};
export type TokenOrProvider = null | string | TokenProvider | undefined;
export type TokenProvider = () => Promise<string>;
export type TranslationLanguages =
| 'af'
| 'am'
| 'ar'
| 'az'
| 'bg'
| 'bn'
| 'bs'
| 'cs'
| 'da'
| 'de'
| 'el'
| 'en'
| 'es'
| 'es-MX'
| 'et'
| 'fa'
| 'fa-AF'
| 'fi'
| 'fr'
| 'fr-CA'
| 'ha'
| 'he'
| 'hi'
| 'hr'
| 'hu'
| 'id'
| 'it'
| 'ja'
| 'ka'
| 'ko'
| 'lt'
| 'lv'
| 'ms'
| 'nl'
| 'no'
| 'pl'
| 'ps'
| 'pt'
| 'ro'
| 'ru'
| 'sk'
| 'sl'
| 'so'
| 'sq'
| 'sr'
| 'sv'
| 'sw'
| 'ta'
| 'th'
| 'tl'
| 'tr'
| 'uk'
| 'ur'
| 'vi'
| 'zh'
| 'zh-TW'
| (string & {});
export type TypingStartEvent = Event;
export type ReservedUpdatedMessageFields = keyof typeof RESERVED_UPDATED_MESSAGE_FIELDS;
export type UpdatedMessage = Omit<
MessageResponse,
ReservedUpdatedMessageFields | 'mentioned_groups'
> & {
mentioned_users?: string[];
mentioned_channel?: boolean;
mentioned_here?: boolean;
mentioned_group_ids?: string[];
mentioned_roles?: string[];
type?: MessageLabel;
};
/**
* @description type alias for UserResponse
*/
export type User = UserResponse;
export type TaskResponse = {
task_id: string;
};
export type DeleteChannelsResponse = {
result: Record<string, string>;
} & Partial<TaskResponse>;
export type DeleteType = 'soft' | 'hard' | 'pruning';
/*
DeleteUserOptions specifies a collection of one or more `user_ids` to be deleted.
`user`:
- soft: marks user as deleted and retains all user data
- pruning: marks user as deleted and nullifies user information
- hard: deletes user completely - this requires hard option for messages and conversation as well
`conversations`:
- soft: marks all conversation channels as deleted (same effect as Delete Channels with 'hard' option disabled)
- hard: deletes channel and all its data completely including messages (same effect as Delete Channels with 'hard' option enabled)
`messages`:
- soft: marks all user messages as deleted without removing any related message data
- pruning: marks all user messages as deleted, nullifies message information and removes some message data such as reactions and flags
- hard: deletes messages completely with all related information
`new_channel_owner_id`: any channels owned by the hard-deleted user will be transferred to this user ID
*/
export type DeleteUserOptions = {
conversations?: Exclude<DeleteType, 'pruning'>;
messages?: DeleteType;
new_channel_owner_id?: string;
user?: DeleteType;
};
export type SegmentType = 'channel' | 'user';
export type SegmentData = {
all_sender_channels?: boolean;
all_users?: boolean;
description?: string;
filter?: {};
name?: string;
};
export type SegmentResponse = {
created_at: string;
deleted_at: string;
id: string;
locked: boolean;
size: number;
task_id: string;
type: SegmentType;
updated_at: string;
} & SegmentData;
export type UpdateSegmentData = {
name: string;
} & SegmentData;
export type SegmentTargetsResponse = {
created_at: string;
segment_id: string;
target_id: string;
};
export type SortParam = {
field: string;
direction?: AscDesc;
};
export type Pager = {
limit?: number;
next?: string;
prev?: string;
};
export type QuerySegmentsOptions = Pager;
export type QuerySegmentTargetsFilter = {
target_id?: {
$eq?: string;
$gte?: string;
$in?: string[];
$lte?: string;
};
};
export type QuerySegmentTargetsOptions = Pick<Pager, 'next' | 'limit'>;
export type GetCampaignOptions = {
users?: { limit?: number; next?: string; prev?: string };
};
export type CampaignSort = {
field: string;
direction?: number;
}[];
export type CampaignQueryOptions = {
limit?: number;
next?: string;
prev?: string;
sort?: CampaignSort;
user_limit?: number;
};
export type SegmentQueryOptions = CampaignQueryOptions;
// TODO: add better typing
export type CampaignFilters = {};
export type CampaignData = {
channel_template?: {
type: string;
custom?: {};
id?: string;
members?: string[];
members_template?: Array<{
user_id: string;
channel_role?: string;
custom?: Record<string, unknown>;
}>;
team?: string;
};
create_channels?: boolean;
deleted_at?: string;
description?: string;
id?: string | null;
message_template?: {
text: string;
attachments?: Attachment[];
custom?: {};
poll_id?: string;
};
name?: string;
segment_ids?: string[];
sender_id?: string;
sender_mode?: 'exclude' | 'include' | null;
sender_visibility?: 'hidden' | 'archived' | null;
show_channels?: boolean;
skip_push?: boolean;
skip_webhook?: boolean;
user_ids?: string[];
};
export type CampaignStats = {
progress?: number;
stats_channels_created?: number;
stats_completed_at?: string;
stats_messages_sent?: number;
stats_started_at?: string;
stats_users_read?: number;
stats_users_sent?: number;
};
export type CampaignResponse = {
created_at: string;
id: string;
segments: SegmentResponse[];
sender: UserResponse;
stats: CampaignStats;
status: 'draft' | 'scheduled' | 'in_progress' | 'completed' | 'stopped';
updated_at: string;
users: UserResponse[];
scheduled_for?: string;
} & CampaignData;
export type DeleteCampaignOptions = {};
export type TaskStatus = {
created_at: string;
status: string;
task_id: string;
updated_at: string;
error?: {
description: string;
type: string;
};
result?: UR;
};
export type TruncateOptions = {
hard_delete?: boolean;
message?: Message;
skip_push?: boolean;
truncated_at?: Date;
user?: UserResponse;
user_id?: string;
};
export type CreateImportURLResponse = {
path: string;
upload_url: string;
};
export type CreateImportResponse = {
import_task: ImportTask;
};
export type GetImportResponse = {
import_task: ImportTask;
};
export type CreateImportOptions = {
mode: 'insert' | 'upsert';
};
export type ListImportsPaginationOptions = {
limit?: number;
offset?: number;
};
export type ListImportsResponse = {
import_tasks: ImportTask[];
};
export type ImportTaskHistory = {
created_at: string;
next_state: string;
prev_state: string;
};
export type ImportTask = {
created_at: string;
history: ImportTaskHistory[];
id: string;
path: string;
state: string;
updated_at: string;
result?: UR;
size?: number;
};
export type MessageSetType = 'latest' | 'current' | 'new';
export type MessageSet = {
isCurrent: boolean;
isLatest: boolean;
messages: LocalMessage[];
pagination: { hasNext: boolean; hasPrev: boolean };
};
export type PushProviderUpsertResponse = {
push_provider: PushProvider;
};
export type PushProviderListResponse = {
push_providers: PushProvider[];
};
type ErrorResponseDetails = {
code: number;
messages: string[];
};
export type APIErrorResponse = {
duration: string;
message: string;
more_info: string;
StatusCode: number;
code?: number;
details?: ErrorResponseDetails;
};
export class ErrorFromResponse<T> extends Error {
public code: number | null;
public status: number;
public response: AxiosResponse<T>;
public name = 'ErrorFromResponse';
constructor(
message: string,
{
code,
status,
response,
}: {
code: ErrorFromResponse<T>['code'];
response: ErrorFromResponse<T>['response'];
status: ErrorFromResponse<T>['status'];
},
) {
super(message);
this.code = code;
this.response = response;
this.status = status;
}
// Vitest helper (serialized errors are too large to read)
// https://github.com/vitest-dev/vitest/blob/v3.1.3/packages/utils/src/error.ts#L60-L62
toJSON() {
const extra = [
['status', this.status],
['code', this.code],
] as const;
const joinable = [];
for (const [key, value] of extra) {
if (typeof value !== 'undefined' && value !== null) {
joinable.push(`${key}: ${value}`);
}
}
return {
message: `(${joinable.join(', ')}) - ${this.message}`,
stack: this.stack,
name: this.name,
code: this.code,
status: this.status,
} as const;
}
}
export type QueryPollsResponse = {
polls: PollResponse[];
next?: string;
};
export type CreatePollAPIResponse = {
poll: PollResponse;
};
export type GetPollAPIResponse = {
poll: PollResponse;
};
export type UpdatePollAPIResponse = {
poll: PollResponse;
};
export type PollResponse = CustomPollData &
PollEnrichData & {
created_at: string;
created_by: UserResponse | null;
created_by_id: string;
enforce_unique_vote: boolean;
id: string;
max_votes_allowed: number;
name: string;
options: PollOption[];
updated_at: string;
allow_answers?: boolean;
allow_user_suggested_options?: boolean;
description?: string;
is_closed?: boolean;
voting_visibility?: VotingVisibility;
};
export type PollOption = {
created_at: string;
id: string;
poll_id: string;
text: string;
updated_at: string;
vote_count: number;
votes?: PollVote[];
};
export enum VotingVisibility {
anonymous = 'anonymous',
public = 'public',
}
export type PollEnrichData = {
answers_count: number;
latest_answers: PollAnswer[]; // not updated with WS events, ordered DESC by created_at, seems like updated_at cannot be different from created_at
latest_votes_by_option: Record<string, PollVote[]>; // not updated with WS events; always null in anonymous polls
vote_count: number;
vote_counts_by_option: Record<string, number>;
own_votes?: (PollVote | PollAnswer)[]; // not updated with WS events
};
export type PollData = CustomPollData & {
id: string;
name: string;
allow_answers?: boolean;
allow_user_suggested_options?: boolean;
description?: string;
enforce_unique_vote?: boolean;
is_closed?: boolean;
max_votes_allowed?: number;
options?: PollOptionData[];
user_id?: string;
voting_visibility?: VotingVisibility;
};
export type CreatePollData = Partial<PollData> & Pick<PollData, 'name'>;
export type PartialPollUpdate = {
set?: Partial<PollData>;
unset?: Array<keyof PollData>;
};
export type PollOptionData = CustomPollOptionData & {
text: string;
id?: string;
position?: number;
};
export type PartialPollOptionUpdate = {
set?: Partial<PollOptionResponse>;
unset?: Array<keyof PollOptionResponse>;
};
export type PollVoteData = {
answer_text?: string;
is_answer?: boolean;
option_id?: string;
};
export type PollPaginationOptions = {
limit?: number;
next?: string;
};
export type CreatePollOptionAPIResponse = {
poll_option: PollOptionResponse;
};
export type GetPollOptionAPIResponse = CreatePollOptionAPIResponse;
export type UpdatePollOptionAPIResponse = CreatePollOptionAPIResponse;
export type PollOptionResponse = CustomPollData & {
created_at: string;
id: string;
poll_id: string;
position: number;
text: string;
updated_at: string;
vote_count: number;
votes?: PollVote[];
};
export type PollVote = {
created_at: string;
id: string;
poll_id: string;
updated_at: string;
option_id?: string;
user?: UserResponse;
user_id?: string;
};
export type PollAnswer = Exclude<PollVote, 'option_id'> & {
answer_text: string;
is_answer: boolean; // this is absolutely redundant prop as answer_text indicates that a vote is an answer
};
export type PollVotesAPIResponse = {
votes: (PollVote | PollAnswer)[];
next?: string;
};
export type PollAnswersAPIResponse = {
votes: PollAnswer[]; // todo: should be changes to answers?
next?: string;
};
export type CastVoteAPIResponse = {
vote: PollVote | PollAnswer;
};
export type QueryMessageHistoryFilters = QueryFilters<
{
message_id?:
| RequireOnlyOne<
Pick<QueryFilter<MessageHistoryEntry['message_id']>, '$eq' | '$in'>
>
| PrimitiveFilter<MessageHistoryEntry['message_id']>;
} & {
user_id?:
| RequireOnlyOne<
Pick<QueryFilter<MessageHistoryEntry['message_updated_by_id']>, '$eq' | '$in'>
>
| PrimitiveFilter<MessageHistoryEntry['message_updated_by_id']>;
} & {
created_at?:
| RequireOnlyOne<
Pick<
QueryFilter<MessageHistoryEntry['message_updated_at']>,
'$eq' | '$gt' | '$lt' | '$gte' | '$lte'
>
>
| PrimitiveFilter<MessageHistoryEntry['message_updated_at']>;
}
>;
export type QueryMessageHistorySort =
| QueryMessageHistorySortBase
| Array<QueryMessageHistorySortBase>;
export type QueryMessageHistorySortBase = {
message_updated_at?: AscDesc;
message_updated_by_id?: AscDesc;
};
export type QueryMessageHistoryOptions = Pager;
export type MessageHistoryEntry = {
message_id: string;
message_updated_at: string;
attachments?: Attachment[];
message_updated_by_id?: string;
text?: string;
};
export type QueryMessageHistoryResponse = {
message_history: MessageHistoryEntry[];
next?: string;
prev?: string;
};
// Moderation v2
export type ModerationPayload = {
created_at: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
custom?: Record<string, any>;
images?: string[];
texts?: string[];
videos?: string[];
};
export type ModV2ReviewStatus = 'complete' | 'flagged' | 'partial';
export type ModerationFlag = {
created_at: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
custom: Record<string, any>;
entity_creator_id: string;
entity_id: string;
entity_type: string;
id: string;
reason: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
result: Record<string, any>[];
review_queue_item_id: string;
updated_at: string;
user: UserResponse;
moderation_payload?: ModerationPayload;
moderation_payload_hash?: string;
};
export type ReviewQueueItem = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
actions_taken: any[];
appealed_by: string;
assigned_to: string;
completed_at: string;
config_key: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
context: any[];
created_at: string;
created_by: string;
entity_id: string;
entity_type: string;
entity_creator_id?: string;
flags: ModerationFlag[];
has_image: boolean;
has_text: boolean;
has_video: boolean;
id: string;
moderation_payload: ModerationPayload;
moderation_payload_hash: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
options: any;
recommended_action: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
results: any;
reviewed_at: string;
status: string;
updated_at: string;
latest_moderator_action?: string;
};
export type CustomCheckFlag = {
type: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
custom?: Record<string, any>[];
labels?: string[];
reason?: string;
};
export type MessageDeletionStrategy = 'soft' | 'hard' | 'pruning';
// @deprecated use type MessageDeletionStrategy instead
export type DeleteMessagesOptions = MessageDeletionStrategy;
export type DeleteMessageOptions = {
deleteForMe?: boolean;
hardDelete?: boolean;
};
export type SubmitActionOptions = {
appeal_id?: string;
ban?: {
target_user_id?: string;
shadow?: boolean;
reason?: string;
channel_ban_only?: boolean;
channel_cid?: string;
ip_ban?: boolean;
delete_messages?: MessageDeletionStrategy;
delete_reactions?: boolean;
timeout?: number;
};
block?: {
reason?: string;
};
custom?: {
id: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
options?: Record<string, any>;
};
delete_activity?: {
hard_delete?: boolean;
reason?: string;
entity_id?: string;
entity_type?: string;
};
delete_comment?: {
hard_delete?: boolean;
reason?: string;
entity_id?: string;
entity_type?: string;
};
delete_message?: {
hard_delete?: boolean;
reason?: string;
entity_id?: string;
entity_type?: string;
};
delete_reaction?: {
hard_delete?: boolean;
reason?: string;
entity_id?: string;
entity_type?: string;
};
delete_user?: {
hard_delete?: boolean;
reason?: string;
mark_messages_deleted?: boolean;
delete_conversation_channels?: boolean;
delete_feeds_content?: boolean;
entity_id?: string;
entity_type?: string;
};
end_call?: Record<string, never>;
escalate?: {
reason: string;
category: string;
priority: string;
};
flag?: {
entity_type: string;
entity_id: string;
entity_creator_id?: string;
reason?: string;
moderation_payload?: ModerationPayload;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
custom?: Record<string, any>;
};
kick_user?: Record<string, never>;
mark_reviewed?: {
disable_marking_content_as_reviewed?: boolean;
content_to_mark_as_reviewed_limit?: number;
decision_reason?: string;
};
reject_appeal?: {
decision_reason: string;
};
restore?: {
decision_reason?: string;
};
shadow_block?: {
reason?: string;
};
unban?: {
channel_cid?: string;
decision_reason?: string;
};
unblock?: {
decision_reason?: string;
};
user_id?: string;
};
export type SubmitActionResponse = APIResponse & {
item?: ReviewQueueItem;
};
export type GetUserModerationReportResponse = {
user: UserResponse;
user_blocks?: Array<{
blocked_at: string;
blocked_by_user_id: string;
blocked_user_id: string;
}>;
user_mutes?: Mute[];
};
export type CheckResponse = APIResponse & {
status: string;
task_id?: string;
recommended_action: string;
item?: ReviewQueueItem;
};
export type CustomCheckResponse = APIResponse & {
id: string;
item: ReviewQueueItem;
status: string;
};
export type QueryModerationConfigsFilters = QueryFilters<
{
key?: string;
} & {
created_at?: PrimitiveFilter<string>;
} & {
updated_at?: PrimitiveFilter<string>;
} & {
team?: string;
}
>;
export type ReviewQueueFilters = QueryFilters<
{
assigned_to?:
| RequireOnlyOne<Pick<QueryFilter<ReviewQueueItem['assigned_to']>, '$eq' | '$in'>>
| PrimitiveFilter<ReviewQueueItem['assigned_to']>;
} & {
completed_at?:
| RequireOnlyOne<
Pick<
QueryFilter<ReviewQueueItem['completed_at']>,
'$eq' | '$gt' | '$lt' | '$gte' | '$lte'
>
>
| PrimitiveFilter<ReviewQueueItem['completed_at']>;
} & {
config_key?:
| RequireOnlyOne<Pick<QueryFilter<ReviewQueueItem['config_key']>, '$eq' | '$in'>>
| PrimitiveFilter<ReviewQueueItem['config_key']>;
} & {
entity_type?:
| RequireOnlyOne<Pick<QueryFilter<ReviewQueueItem['entity_type']>, '$eq' | '$in'>>
| PrimitiveFilter<ReviewQueueItem['entity_type']>;
} & {
created_at?:
| RequireOnlyOne<
Pick<
QueryFilter<ReviewQueueItem['created_at']>,
'$eq' | '$gt' | '$lt' | '$gte' | '$lte'
>
>
| PrimitiveFilter<ReviewQueueItem['created_at']>;
} & {
id?:
| RequireOnlyOne<Pick<QueryFilter<ReviewQueueItem['id']>, '$eq' | '$in'>>
| PrimitiveFilter<ReviewQueueItem['id']>;
} & {
entity_id?:
| RequireOnlyOne<Pick<QueryFilter<ReviewQueueItem['entity_id']>, '$eq' | '$in'>>
| PrimitiveFilter<ReviewQueueItem['entity_id']>;
} & {
entity_creator_id?:
| RequireOnlyOne<
Pick<QueryFilter<ReviewQueueItem['entity_creator_id']>, '$eq' | '$in'>
>
| PrimitiveFilter<ReviewQueueItem['entity_creator_id']>;
} & {
reviewed?: boolean;
} & {
reviewed_at?:
| RequireOnlyOne<
Pick<
QueryFilter<ReviewQueueItem['reviewed_at']>,
'$eq' | '$gt' | '$lt' | '$gte' | '$lte'
>
>
| PrimitiveFilter<ReviewQueueItem['reviewed_at']>;
} & {
status?:
| RequireOnlyOne<Pick<QueryFilter<ReviewQueueItem['status']>, '$eq' | '$in'>>
| PrimitiveFilter<ReviewQueueItem['status']>;
} & {
updated_at?:
| RequireOnlyOne<
Pick<
QueryFilter<ReviewQueueItem['updated_at']>,
'$eq' | '$gt' | '$lt' | '$gte' | '$lte'
>
>
| PrimitiveFilter<ReviewQueueItem['updated_at']>;
} & {
has_image?: boolean;
} & {
has_text?: boolean;
} & {
has_video?: boolean;
} & {
has_media?: boolean;
} & {
language?: RequireOnlyOne<{
$contains?: string;
$eq?: string;
$in?: string[];
}>;
} & {
teams?:
| RequireOnlyOne<{
$contains?: PrimitiveFilter<string>;
$eq?: PrimitiveFilter<string>;
$in?: PrimitiveFilter<string>;
}>
| PrimitiveFilter<string>;
} & {
user_report_reason?: RequireOnlyOne<{
$eq?: string;
}>;
} & {
recommended_action?: RequireOnlyOne<{
$eq?: string;
$in?: string[];
}>;
} & {
flagged_user_id?: RequireOnlyOne<{
$eq?: string;
}>;
} & {
category?: RequireOnlyOne<{
$eq?: string;
}>;
} & {
label?: RequireOnlyOne<{
$eq?: string;
$in?: string[];
}>;
} & {
reporter_type?: RequireOnlyOne<{
$eq?: 'automod' | 'user' | 'moderator' | 'admin' | 'velocity_filter';
}>;
} & {
reporter_id?: RequireOnlyOne<{
$eq?: string;
$in?: string[];
}>;
} & {
date_range?: RequireOnlyOne<{
$eq?: string; // Format: "date1_date2"
}>;
} & {
latest_moderator_action?:
| RequireOnlyOne<
Pick<QueryFilter<ReviewQueueItem['latest_moderator_action']>, '$eq' | '$in'>
>
| PrimitiveFilter<ReviewQueueItem['latest_moderator_action']>;
} & {
flags_count?: RequireOnlyOne<{
$eq?: number;
}>;
} & {
ai_text_severity?: RequireOnlyOne<{
$eq?: string;
}>;
} & {
channel_cid?: RequireOnlyOne<{
$eq?: string;
}>;
}
>;
export type ReviewQueueSort =
| Sort<Pick<ReviewQueueItem, 'id' | 'created_at' | 'updated_at'>>
| Array<Sort<Pick<ReviewQueueItem, 'id' | 'created_at' | 'updated_at'>>>;
export type QueryModerationConfigsSort = Array<Sort<'key' | 'created_at' | 'updated_at'>>;
export type ReviewQueuePaginationOptions = Pager;
export type FilterConfigResponse = {
llm_labels: string[];
ai_text_labels?: string[];
};
export type ModerationActionConfig = {
entity_type: string;
order: number;
action: string;
icon: string;
description: string;
custom?: Record<string, unknown>;
};
export type ReviewQueueResponse = {
items: ReviewQueueItem[];
action_config?: Record<string, ModerationActionConfig[]>;
filter_config?: FilterConfigResponse;
stats?: Record<string, unknown>;
next?: string;
prev?: string;
};
export type ModerationConfig = {
key: string;
ai_image_config?: AIImageConfig;
ai_text_config?: AITextConfig;
ai_video_config?: AIVideoConfig;
automod_platform_circumvention_config?: AutomodPlatformCircumventionConfig;
automod_semantic_filters_config?: AutomodSemanticFiltersConfig;
automod_toxicity_config?: AutomodToxicityConfig;
block_list_config?: BlockListConfig;
llm_config?: LLMConfig;
team?: string;
};
export type ModerationConfigResponse = ModerationConfig & {
created_at: string;
updated_at: string;
};
export type GetConfigResponse = {
config: ModerationConfigResponse;
};
export type QueryConfigsResponse = {
configs: ModerationConfigResponse[];
next?: string;
prev?: string;
};
export type UpsertConfigResponse = {
config: ModerationConfigResponse;
};
// Moderation Rule Builder Types
export type ModerationRule = {
id: string;
name: string;
description: string;
config_keys: string[];
team: string;
rule: RuleBuilderRule;
enabled: boolean;
created_at: string;
updated_at: string;
};
export type ModerationRuleRequest = {
name: string;
description: string;
config_keys: string[];
team: string;
rule: RuleBuilderRule;
enabled: boolean;
};
export type RuleBuilderRule = {
id: string;
rule_type: 'user' | 'content';
conditions?: RuleBuilderCondition[];
logic?: 'AND' | 'OR';
groups?: RuleBuilderConditionGroup[];
action: RuleBuilderAction;
cooldown_period?: string;
};
export type RuleBuilderCondition = {
type: string;
confidence?: number;
text_rule_params?: TextRuleParameters;
image_rule_params?: ImageRuleParameters;
video_rule_params?: VideoRuleParameters;
user_rule_params?: UserRuleParameters;
content_count_rule_params?: ContentCountRuleParameters;
text_content_params?: TextContentParameters;
image_content_params?: ImageContentParameters;
video_content_params?: VideoContentParameters;
user_created_within_params?: UserCreatedWithinParameters;
user_custom_property_params?: UserCustomPropertyParameters;
};
export type RuleBuilderConditionGroup = {
logic: 'AND' | 'OR';
conditions: RuleBuilderCondition[];
};
export type RuleBuilderAction = {
type: string;
ban_options?: BanOptions;
flag_user_options?: FlagUserOptions;
};
export type TextRuleParameters = {
threshold: number;
time_window: string;
harm_labels?: string[];
llm_harm_labels?: Record<string, string>;
contains_url?: boolean;
severity?: string;
blocklist_match?: string[];
};
export type ImageRuleParameters = {
threshold: number;
time_window: string;
harm_labels: string[];
};
export type VideoRuleParameters = {
threshold: number;
time_window: string;
harm_labels: string[];
};
export type UserRuleParameters = {
max_age: string;
};
export type ContentCountRuleParameters = {
threshold: number;
time_window: string;
};
export type TextContentParameters = {
harm_labels?: string[];
llm_harm_labels?: Record<string, string>;
contains_url?: boolean;
severity?: string;
blocklist_match?: string[];
};
export type ImageContentParameters = {
harm_labels: string[];
};
export type VideoContentParameters = {
harm_labels: string[];
};
export type UserCreatedWithinParameters = {
max_age: string;
};
export type UserCustomPropertyParameters = {
property_key: string;
operator: string;
expected_value: string;
};
export type BanOptions = {
duration: number;
reason: string;
shadow_ban: boolean;
ip_ban: boolean;
};
export type FlagUserOptions = {
reason: string;
};
export type QueryModerationRulesFilters = QueryFilters<{
name?: string;
team?: string;
enabled?: boolean;
rule_type?: string;
created_at?: PrimitiveFilter<string>;
updated_at?: PrimitiveFilter<string>;
}>;
export type QueryModerationRulesSort = Array<
Sort<'name' | 'enabled' | 'team' | 'created_at' | 'updated_at'>
>;
export type QueryModerationRulesResponse = {
rules: ModerationRule[];
default_llm_labels: Record<string, string>;
next?: string;
prev?: string;
};
export type UpsertModerationRuleResponse = {
rule: ModerationRule;
};
export type ModerationFlagOptions = {
custom?: Record<string, unknown>;
moderation_payload?: ModerationPayload;
user_id?: string;
};
export type ModerationMuteOptions = {
timeout?: number;
user_id?: string;
};
export type GetUserModerationReportOptions = {
create_user_if_not_exists?: boolean;
include_user_blocks?: boolean;
include_user_mutes?: boolean;
};
export type AIState =
| 'AI_STATE_ERROR'
| 'AI_STATE_CHECKING_SOURCES'
| 'AI_STATE_THINKING'
| 'AI_STATE_GENERATING'
| (string & {});
export type ModerationActionType =
| 'flag'
| 'shadow'
| 'remove'
| 'bounce'
| 'bounce_flag'
| 'bounce_remove';
export type ModerationSeverity = 'low' | 'medium' | 'high' | 'critical';
export type AutomodRule = {
action: ModerationActionType;
label: string;
threshold: number;
};
export type BlockListRule = {
action: ModerationActionType;
name?: string;
};
export type BlockListConfig = {
enabled: boolean;
rules: BlockListRule[];
async?: boolean;
};
export type LLMConfig = {
rules: LLMRule[];
severity_descriptions?: Record<ModerationSeverity, string>;
app_context?: string;
};
export type LLMRule = {
label: string;
description: string;
action: ModerationActionType;
severity_rules?: LLMSeverityRule[];
};
export type LLMSeverityRule = {
severity: ModerationSeverity;
action: ModerationActionType;
};
export type AutomodToxicityConfig = {
enabled: boolean;
rules: AutomodRule[];
async?: boolean;
};
export type AutomodPlatformCircumventionConfig = {
enabled: boolean;
rules: AutomodRule[];
async?: boolean;
};
export type AutomodSemanticFiltersRule = {
action: ModerationActionType;
name: string;
threshold: number;
};
export type AutomodSemanticFiltersConfig = {
enabled: boolean;
rules: AutomodSemanticFiltersRule[];
async?: boolean;
};
export type AITextSeverityRule = {
action: ModerationActionType;
severity: ModerationSeverity;
};
export type AITextRule = {
label: string;
action?: ModerationActionType;
severity_rules?: AITextSeverityRule[];
};
export type AITextConfig = {
enabled: boolean;
rules: AITextRule[];
async?: boolean;
profile?: string;
severity_rules?: AITextSeverityRule[]; // Deprecated: use rules instead
};
export type AIImageRule = {
action: ModerationActionType;
label: string;
min_confidence?: number;
};
export type AIImageConfig = {
enabled: boolean;
rules: AIImageRule[];
async?: boolean;
};
export type AIVideoRule = {
action: ModerationActionType;
label: string;
min_confidence?: number;
};
export type AIVideoConfig = {
enabled: boolean;
rules: AIVideoRule[];
async?: boolean;
};
export type VelocityFilterConfigRule = {
action: 'flag' | 'shadow' | 'remove' | 'ban';
ban_duration?: number;
cascading_action?: 'flag' | 'shadow' | 'remove' | 'ban';
cascading_threshold?: number;
check_message_context?: boolean;
fast_spam_threshold?: number;
fast_spam_ttl?: number;
ip_ban?: boolean;
shadow_ban?: boolean;
slow_spam_ban_duration?: number;
slow_spam_threshold?: number;
slow_spam_ttl?: number;
};
export type VelocityFilterConfig = {
cascading_actions: boolean;
enabled: boolean;
first_message_only: boolean;
rules: VelocityFilterConfigRule[];
async?: boolean;
};
export type PromoteChannelParams = {
channels: Array<Channel>;
channelToMove: Channel;
sort: ChannelSort;
/**
* If the index of the channel within `channels` list which is being moved upwards
* (`channelToMove`) is known, you can supply it to skip extra calculation.
*/
channelToMoveIndexWithinChannels?: number;
};
/**
* An identifier containing information about the downstream SDK using stream-chat. It
* is used to resolve the user agent.
*/
export type SdkIdentifier = {
name: 'react' | 'react-native' | 'expo' | 'angular';
version: string;
};
/**
* An identifier containing information about the downstream device using stream-chat, if
* available. Is used by the react-native SDKs to enrich the user agent further.
*/
export type DeviceIdentifier = { os: string; model?: string };
/**
* An identifier containing information about the downstream application integrating
* stream-chat, if available. `name` is reported as `app` and `version` as `app_version`
* in the user agent. Distinct from the SDK ({@link SdkIdentifier}) and device
* ({@link DeviceIdentifier}) identifiers.
*/
export type AppIdentifier = { name: string; version?: string };
export type DraftResponse = {
channel_cid: string;
created_at: string;
message: DraftMessage;
channel?: ChannelResponse;
parent_id?: string;
parent_message?: MessageResponseBase;
quoted_message?: MessageResponseBase;
};
export type CreateDraftResponse = APIResponse & {
draft: DraftResponse;
};
export type GetDraftResponse = APIResponse & {
draft: DraftResponse;
};
export type QueryDraftsResponse = APIResponse & {
drafts: DraftResponse[];
} & Omit<Pager, 'limit'>;
export type DraftMessagePayload = PartializeKeys<
Omit<DraftMessage, 'mentioned_groups'>,
'id'
> & {
user_id?: string;
};
export type DraftMessage = {
id: string;
text: string;
attachments?: Attachment[];
custom?: {};
html?: string;
mentioned_users?: string[];
mentioned_channel?: boolean;
mentioned_here?: boolean;
mentioned_group_ids?: string[];
mentioned_groups?: UserGroupResponse[];
mentioned_roles?: string[];
mml?: string;
parent_id?: string;
poll_id?: string;
quoted_message_id?: string;
shared_location?: StaticLocationPayload | LiveLocationPayload; // todo: live-location verify if possible
show_in_channel?: boolean;
silent?: boolean;
type?: MessageLabel;
};
export type ActiveLiveLocationsAPIResponse = APIResponse & {
active_live_locations: SharedLiveLocationResponse[];
};
export type SharedLocationResponse = {
channel_cid: string;
created_at: string;
created_by_device_id: string;
end_at?: string;
latitude: number;
longitude: number;
message_id: string;
updated_at: string;
user_id: string;
};
export type SharedStaticLocationResponse = {
channel_cid: string;
created_at: string;
created_by_device_id: string;
latitude: number;
longitude: number;
message_id: string;
updated_at: string;
user_id: string;
};
export type SharedLiveLocationResponse = {
channel_cid: string;
created_at: string;
created_by_device_id: string;
end_at: string;
latitude: number;
longitude: number;
message_id: string;
updated_at: string;
user_id: string;
};
export type UpdateLocationPayload = {
message_id: string;
created_by_device_id?: string;
end_at?: string;
latitude?: number;
longitude?: number;
user?: { id: string };
user_id?: string;
};
export type StaticLocationPayload = {
created_by_device_id: string;
latitude: number;
longitude: number;
message_id: string;
};
export type LiveLocationPayload = {
created_by_device_id: string;
end_at: string;
latitude: number;
longitude: number;
message_id: string;
};
export type ThreadSort = ThreadSortBase | Array<ThreadSortBase>;
export type ThreadSortBase = {
active_participant_count?: AscDesc;
created_at?: AscDesc;
last_message_at?: AscDesc;
parent_message_id?: AscDesc;
participant_count?: AscDesc;
reply_count?: AscDesc;
updated_at?: AscDesc;
};
export type ThreadFilters = QueryFilters<
{
channel_cid?:
| RequireOnlyOne<Pick<QueryFilter<string>, '$eq' | '$in'>>
| PrimitiveFilter<string>;
} & {
parent_message_id?:
| RequireOnlyOne<
Pick<QueryFilter<ThreadResponse['parent_message_id']>, '$eq' | '$in'>
>
| PrimitiveFilter<ThreadResponse['parent_message_id']>;
} & {
created_by_user_id?:
| RequireOnlyOne<
Pick<QueryFilter<ThreadResponse['created_by_user_id']>, '$eq' | '$in'>
>
| PrimitiveFilter<ThreadResponse['created_by_user_id']>;
} & {
created_at?:
| RequireOnlyOne<
Pick<
QueryFilter<ThreadResponse['created_at']>,
'$eq' | '$gt' | '$lt' | '$gte' | '$lte'
>
>
| PrimitiveFilter<ThreadResponse['created_at']>;
} & {
updated_at?:
| RequireOnlyOne<
Pick<
QueryFilter<ThreadResponse['updated_at']>,
'$eq' | '$gt' | '$lt' | '$gte' | '$lte'
>
>
| PrimitiveFilter<ThreadResponse['updated_at']>;
} & {
last_message_at?:
| RequireOnlyOne<
Pick<
QueryFilter<ThreadResponse['last_message_at']>,
'$eq' | '$gt' | '$lt' | '$gte' | '$lte'
>
>
| PrimitiveFilter<ThreadResponse['last_message_at']>;
}
>;
export type ReminderResponseBase = {
channel_cid: string;
created_at: string;
message_id: string;
updated_at: string;
user_id: string;
remind_at?: string;
};
export type ReminderResponse = ReminderResponseBase & {
user: UserResponse;
message: MessageResponse;
channel?: ChannelResponse;
};
export type ReminderAPIResponse = APIResponse & {
reminder: ReminderResponse;
};
export type CreateReminderOptions = {
messageId: string;
remind_at?: string | null;
user_id?: string;
};
export type UpdateReminderOptions = CreateReminderOptions;
export type ReminderFilters = QueryFilters<{
channel_cid?:
| RequireOnlyOne<
Pick<QueryFilter<ReminderResponseBase['channel_cid']>, '$eq' | '$in'>
>
| PrimitiveFilter<ReminderResponseBase['channel_cid']>;
created_at?:
| RequireOnlyOne<
Pick<
QueryFilter<ReminderResponseBase['created_at']>,
'$eq' | '$gt' | '$lt' | '$gte' | '$lte'
>
>
| PrimitiveFilter<ReminderResponseBase['created_at']>;
message_id?:
| RequireOnlyOne<Pick<QueryFilter<ReminderResponseBase['message_id']>, '$eq' | '$in'>>
| PrimitiveFilter<ReminderResponseBase['message_id']>;
remind_at?:
| RequireOnlyOne<
Pick<
QueryFilter<ReminderResponseBase['remind_at']>,
'$exists' | '$eq' | '$gt' | '$lt' | '$gte' | '$lte'
>
>
| PrimitiveFilter<ReminderResponseBase['remind_at']>;
user_id?:
| RequireOnlyOne<Pick<QueryFilter<ReminderResponseBase['user_id']>, '$eq' | '$in'>>
| PrimitiveFilter<ReminderResponseBase['user_id']>;
}>;
export type ReminderSort =
| Sort<
Pick<
ReminderResponseBase,
'channel_cid' | 'created_at' | 'remind_at' | 'updated_at'
>
>
| Array<
Sort<
Pick<
ReminderResponseBase,
'channel_cid' | 'created_at' | 'remind_at' | 'updated_at'
>
>
>;
export type QueryRemindersOptions = Pager & {
filter?: ReminderFilters;
sort?: ReminderSort;
};
export type QueryRemindersResponse = {
reminders: ReminderResponse[];
prev?: string;
next?: string;
};
export type UserGroupMemberResponse = {
group_id: string;
user_id: string;
is_admin: boolean;
created_at: string;
};
export type UserGroupResponse = {
id: string;
name: string;
created_at: string;
updated_at: string;
description?: string;
team_id?: string;
members?: UserGroupMemberResponse[];
created_by?: string;
};
export type CreateUserGroupOptions = {
/** Human-readable user group name */
name: string;
/** Optional user group description shown to members */
description?: string;
/** Optional custom user group ID. If omitted, the backend generates one */
id?: string;
/** Optional list of user IDs to add as members when the group is created */
member_ids?: string[];
/** Optional team ID that scopes the user group to a specific team */
team_id?: string;
};
export type CreateUserGroupResponse = APIResponse & {
user_group: UserGroupResponse;
};
export type GetUserGroupOptions = {
team_id?: string;
};
export type GetUserGroupResponse = APIResponse & {
user_group: UserGroupResponse;
};
export type QueryUserGroupsOptions = {
limit?: number;
id_gt?: string;
created_at_gt?: string;
team_id?: string;
};
export type QueryUserGroupsResponse = APIResponse & {
user_groups: UserGroupResponse[];
};
export type SearchUserGroupsOptions = {
query: string;
limit?: number;
id_gt?: string;
name_gt?: string;
team_id?: string;
};
export type SearchUserGroupsResponse = APIResponse & {
user_groups: UserGroupResponse[];
};
export type UpdateUserGroupOptions = {
description?: string;
name?: string;
team_id?: string;
};
export type UpdateUserGroupResponse = APIResponse & {
user_group: UserGroupResponse;
};
export type DeleteUserGroupOptions = {
team_id?: string;
};
export type AddUserGroupMembersOptions = {
member_ids: string[];
as_admin?: boolean;
team_id?: string;
};
export type AddUserGroupMembersResponse = APIResponse & {
user_group: UserGroupResponse;
};
export type RemoveUserGroupMembersOptions = {
member_ids: string[];
team_id?: string;
};
export type RemoveUserGroupMembersResponse = APIResponse & {
user_group: UserGroupResponse;
};
export type HookType = 'webhook' | 'sqs' | 'sns' | 'pending_message';
export type EventHook = {
id?: string;
hook_type?: HookType;
enabled?: boolean;
product?: Product | 'all'; // optional, default is 'all'
event_types?: Array<string>;
webhook_url?: string;
sqs_queue_url?: string;
sqs_region?: string;
sqs_auth_type?: string;
sqs_key?: string;
sqs_secret?: string;
sqs_role_arn?: string;
sns_topic_arn?: string;
sns_region?: string;
sns_auth_type?: string;
sns_key?: string;
sns_secret?: string;
sns_role_arn?: string;
should_send_custom_events?: boolean;
// pending message config
timeout_ms?: number;
callback?: {
mode: 'CALLBACK_MODE_NONE' | 'CALLBACK_MODE_REST' | 'CALLBACK_MODE_TWIRP';
};
delete?: boolean;
created_at?: string;
updated_at?: string;
};
export type BatchUpdateOperation =
| 'addMembers'
| 'removeMembers'
| 'inviteMembers'
| 'assignRoles'
| 'addModerators'
| 'demoteModerators'
| 'hide'
| 'show'
| 'archive'
| 'unarchive'
| 'updateData';
export type BatchChannelDataUpdate = {
frozen?: boolean;
disabled?: boolean;
custom?: Record<string, unknown>;
team?: string;
config_overrides?: Record<string, unknown>;
auto_translation_enabled?: boolean;
auto_translation_language?: string;
};
export type UpdateChannelsBatchOptions = {
operation: BatchUpdateOperation;
filter: UpdateChannelsBatchFilters;
members?: string[] | Array<NewMemberPayload>;
data?: BatchChannelDataUpdate;
};
export type UpdateChannelsBatchFilters = QueryFilters<{
cids?:
| RequireOnlyOne<Pick<QueryFilter<string>, '$in' | '$eq'>>
| PrimitiveFilter<string[]>;
types?:
| RequireOnlyOne<Pick<QueryFilter<string>, '$in' | '$eq'>>
| PrimitiveFilter<string[]>;
}>;
export type UpdateChannelsBatchResponse = {
result: Record<string, string>;
} & Partial<TaskResponse>;
/**
* Predefined Filter Types
*/
export type PredefinedFilterOperation = 'QueryChannels';
export type PredefinedFilterSortParam = {
/**
* Field name to sort by.
*
* This may be a literal field name such as `created_at`, or a placeholder
* template such as `{{sort_field}}` that will be interpolated server-side.
*/
field: string;
/**
* Sort direction. `1` means ascending and `-1` means descending.
*
* The backend defaults this to `1` when omitted.
*/
direction?: AscDesc;
/**
* Optional server-side hint describing how the sort field value should be
* interpreted.
*
* This is mainly relevant for predefined-filter sort templates and is not
* part of the regular `queryChannels()` sort shape. Omitting it uses the
* backend default string behavior. Known backend values include:
*
* - `number`: cast custom-field values to numeric before sorting
* - `boolean`: cast custom-field values to boolean before sorting
*
* Other values are backend-defined. In most cases this should be omitted
* unless you are sorting by a custom field whose stored JSON value is not
* string-like.
*/
type?: string;
};
/**
* Stored predefined filter definition as returned by the server.
*
* `F` represents the raw filter template shape. It defaults to a generic record
* because predefined filters are server-managed templates and may include
* placeholders or app-specific structures.
*/
export type PredefinedFilter<
F extends Record<string, unknown> = Record<string, unknown>,
> = {
/**
* Unique predefined filter name within the app.
*/
name: string;
/**
* Operation this predefined filter is valid for.
*/
operation: PredefinedFilterOperation;
/**
* Filter template stored on the server.
*
* This is not necessarily the fully interpolated runtime filter; placeholder
* values such as `{{user_id}}` may still be present.
*/
filter: F;
/**
* Server creation timestamp in ISO-8601 format.
*/
created_at: string;
/**
* Server update timestamp in ISO-8601 format.
*/
updated_at: string;
/**
* Optional human-readable description.
*/
description?: string;
/**
* Optional sort template stored with the predefined filter.
*/
sort?: PredefinedFilterSortParam[];
/**
* Query identifier generated by the backend for the filter/sort pattern.
*
* The exact value is backend-generated and primarily useful for correlating
* predefined filters with query analysis / query performance data.
*/
query_id?: number;
};
export type CreatePredefinedFilterOptions<
F extends Record<string, unknown> = Record<string, unknown>,
> = {
/**
* Unique predefined filter name.
*/
name: string;
/**
* Operation this predefined filter will be used with.
*/
operation: PredefinedFilterOperation;
/**
* Filter template to store on the server.
*/
filter: F;
/**
* Optional human-readable description.
*/
description?: string;
/**
* Optional sort template stored with the predefined filter.
*/
sort?: PredefinedFilterSortParam[];
};
export type UpdatePredefinedFilterOptions<
F extends Record<string, unknown> = Record<string, unknown>,
> = Omit<CreatePredefinedFilterOptions<F>, 'name'>;
export type PredefinedFilterResponse<
F extends Record<string, unknown> = Record<string, unknown>,
> = APIResponse & {
predefined_filter: PredefinedFilter<F>;
};
/**
* Paginated response returned when listing predefined filters.
*/
export type ListPredefinedFiltersResponse<
F extends Record<string, unknown> = Record<string, unknown>,
> = APIResponse & {
predefined_filters: PredefinedFilter<F>[];
next?: string;
prev?: string;
};
/**
* Contains the interpolated filter and sort from a predefined filter.
* This is returned in the QueryChannels response when using a predefined filter.
*/
export type ParsedPredefinedFilterResponse<
F extends Record<string, unknown> = Record<string, unknown>,
> = {
/**
* Name of the predefined filter that was resolved.
*/
name: string;
/**
* Fully interpolated filter that the backend executed.
*/
filter: F;
/**
* Fully interpolated sort parameters resolved from the predefined filter.
*/
sort?: PredefinedFilterSortParam[];
};
export type PredefinedFilterSort = SortParam[];
export type ListPredefinedFiltersOptions = Pager & {
sort?: PredefinedFilterSort;
};
/**
* Team Usage Stats Types
*/
/**
* Represents a metric value for a specific date
*/
export type DailyValue = {
/** Date in YYYY-MM-DD format */
date: string;
/** Metric value for this date */
value: number;
};
/**
* Statistics for a single metric with optional daily breakdown
*/
export type MetricStats = {
/** Per-day values (only present in daily mode) */
daily?: DailyValue[];
/** Aggregated total value */
total: number;
};
/**
* Usage statistics for a single team containing all 16 metrics
*/
export type TeamUsageStats = {
/** Team identifier (empty string for users not assigned to any team) */
team: string;
// Daily activity metrics (total = SUM of daily values)
/** Daily active users */
users_daily: MetricStats;
/** Daily messages sent */
messages_daily: MetricStats;
/** Daily translations */
translations_daily: MetricStats;
/** Daily image moderations */
image_moderations_daily: MetricStats;
// Peak metrics (total = MAX of daily values)
/** Peak concurrent users */
concurrent_users: MetricStats;
/** Peak concurrent connections */
concurrent_connections: MetricStats;
// Rolling/cumulative metrics (total = LATEST daily value)
/** Total users */
users_total: MetricStats;
/** Users active in last 24 hours */
users_last_24_hours: MetricStats;
/** MAU - users active in last 30 days */
users_last_30_days: MetricStats;
/** Users active this month */
users_month_to_date: MetricStats;
/** Engaged MAU */
users_engaged_last_30_days: MetricStats;
/** Engaged users this month */
users_engaged_month_to_date: MetricStats;
/** Total messages */
messages_total: MetricStats;
/** Messages in last 24 hours */
messages_last_24_hours: MetricStats;
/** Messages in last 30 days */
messages_last_30_days: MetricStats;
/** Messages this month */
messages_month_to_date: MetricStats;
};
/**
* Options for querying team-level usage statistics
*/
export type QueryTeamUsageStatsOptions = {
/**
* Month in YYYY-MM format (e.g., '2026-01').
* Mutually exclusive with start_date/end_date.
* Returns aggregated monthly values.
*/
month?: string;
/**
* Start date in YYYY-MM-DD format.
* Used with end_date for custom date range.
* Returns daily breakdown.
*/
start_date?: string;
/**
* End date in YYYY-MM-DD format.
* Used with start_date for custom date range.
* Returns daily breakdown.
*/
end_date?: string;
/** Maximum number of teams to return per page (default: 30, max: 30) */
limit?: number;
/** Cursor for pagination to fetch next page of teams */
next?: string;
};
/**
* Response containing team-level usage statistics
*/
export type QueryTeamUsageStatsResponse = APIResponse & {
/** Array of team usage statistics */
teams: TeamUsageStats[];
/** Cursor for pagination to fetch next page */
next?: string;
};
export type RetentionPolicyConfig = {
max_age_hours: number;
};
export type RetentionPolicy = {
app_pk: number;
policy: string;
config: RetentionPolicyConfig;
enabled_at: string;
};
export type SetRetentionPolicyResponse = APIResponse & {
policy: RetentionPolicy;
};
export type DeleteRetentionPolicyResponse = APIResponse;
export type GetRetentionPolicyResponse = APIResponse & {
policies: RetentionPolicy[];
};
export type RetentionRunStats = {
channels_deleted?: number;
messages_deleted?: number;
};
export type RetentionRunResponse = {
app_pk: number;
policy: string;
date: string;
stats: RetentionRunStats;
};
export type GetRetentionPolicyRunsOptions = {
filter_conditions?: Record<string, unknown>;
sort?: Array<{ field: string; direction: 1 | -1 }>;
next?: string;
prev?: string;
limit?: number;
};
export type GetRetentionPolicyRunsResponse = APIResponse & {
runs: RetentionRunResponse[];
next?: string;
prev?: string;
};