diff --git a/packages/types/src/common/bot-profile.ts b/packages/types/src/common/bot-profile.ts new file mode 100644 index 000000000..3b9441b95 --- /dev/null +++ b/packages/types/src/common/bot-profile.ts @@ -0,0 +1,11 @@ +export interface BotProfile { + id: string; + name: string; + app_id: string; + team_id: string; + icons: { + [size: string]: string; + }; + updated: number; + deleted: boolean; +} diff --git a/packages/types/src/common/status-emoji-display-info.ts b/packages/types/src/common/status-emoji-display-info.ts new file mode 100644 index 000000000..09d6d6e1c --- /dev/null +++ b/packages/types/src/common/status-emoji-display-info.ts @@ -0,0 +1,5 @@ +export interface StatusEmojiDisplayInfo { + emoji_name?: string; + display_alias?: string; + display_url?: string; +} diff --git a/packages/types/src/events/app.ts b/packages/types/src/events/app.ts new file mode 100644 index 000000000..311c2f3c5 --- /dev/null +++ b/packages/types/src/events/app.ts @@ -0,0 +1,166 @@ +import { Block, KnownBlock } from '../block-kit/blocks'; +import { BotProfile } from '../common/bot-profile'; +import { MessageAttachment } from '../message-attachments'; +import { View } from '../views'; + +export interface AppRequestedEvent { + type: 'app_requested'; + app_request: { + id: string; + app: { + id: string; + name: string; + description: string; + help_url: string; + privacy_policy_url: string; + app_homepage_url: string; + app_directory_url: string; + is_app_directory_approved: boolean; + is_internal: boolean; + additional_info: string; + icons?: { + image_32?: string; + image_36?: string; + image_48?: string; + image_64?: string; + image_72?: string; + image_96?: string; + image_128?: string; + image_192?: string; + image_512?: string; + image_1024?: string; + image_original?: string; + } + }; + }; + previous_resolution: { + status: 'approved' | 'restricted'; + scopes: { + name: string; + description: string; + is_dangerous: boolean; + token_type: 'bot' | 'user' | 'app' | null; + }; + } | null; + is_user_app_collaborator: boolean; + user: { + id: string; + name: string; + email: string; + }; + team: { + id: string; + name: string; + domain: string; + }; + scopes: { + name: string; + description: string; + is_dangerous: boolean; + token_type: 'bot' | 'user' | 'app' | null; + }; + message: string; + date_created: number; +} + +export interface AppHomeOpenedEvent { + type: 'app_home_opened'; + user: string; + channel: string; + tab?: 'home' | 'messages'; + view?: View; + event_ts: string; +} + +export interface AppInstalledEvent { + type: 'app_installed'; + app_id: string; + app_name: string; + app_owner_id: string; + user_id: string; + team_id: string; + team_domain: string; + event_ts: string; +} + +export interface AppDeletedEvent { + type: 'app_deleted'; + app_id: string; + app_name: string; + app_owner_id: string; + team_id: string; + team_domain: string; + event_ts: string; +} + +export interface AppUninstalledTeamEvent { + type: 'app_uninstalled_team'; + app_id: string; + app_name: string; + app_owner_id: string; + team_id: string; + team_domain: string; + user_id: string; + event_ts: string; +} + +// TODO: this is essentially the same as the `message` event, except for the type and that this uses `event_ts` instead +// of `ts` +export interface AppMentionEvent { + type: 'app_mention'; + subtype?: string; + bot_id?: string; + bot_profile?: BotProfile; + username?: string; + team?: string; + // user_team, source_team, and user_profile + // can exist when the user who mentioned this bot is in a different workspace/org + user_team?: string; + source_team?: string; + user_profile?: { + name: string; + first_name: string; + real_name: string; + display_name: string; + team: string; + is_restricted?: boolean; + is_ultra_restricted?: boolean; + avatar_hash?: string; + image_72?: string; + }; + user?: string; + text: string; + attachments?: MessageAttachment[]; + blocks?: (KnownBlock | Block)[]; + // TODO: Add more properties once the types library has a file object definition + files?: { id: string }[]; + upload?: boolean; + display_as_bot?: boolean; + edited?: { + user: string; + ts: string; + }; + ts: string; + channel: string; + event_ts: string; + thread_ts?: string; + client_msg_id?: string; +} + +export interface AppRateLimitedEvent { + type: 'app_rate_limited'; + token: string; + team_id: string; + minute_rate_limited: number; + api_app_id: string; +} + +// TODO: this event doesn't use the envelope. write test cases to make sure its works without breaking, and figure out +// what exceptions need to be made to the related types to make this work +// https://api.slack.com/events/app_rate_limited +// export interface AppRateLimitedEvent { +// } + +export interface AppUninstalledEvent { + type: 'app_uninstalled'; +} diff --git a/packages/types/src/events/call.ts b/packages/types/src/events/call.ts new file mode 100644 index 000000000..83c29fa41 --- /dev/null +++ b/packages/types/src/events/call.ts @@ -0,0 +1,7 @@ +export interface CallRejectedEvent { + type: 'call_rejected'; + call_id: string; + user_id: string; + channel_id: string; + external_unique_id: string; +} diff --git a/packages/types/src/events/channel-membership.ts b/packages/types/src/events/channel-membership.ts new file mode 100644 index 000000000..149aaaa5c --- /dev/null +++ b/packages/types/src/events/channel-membership.ts @@ -0,0 +1,18 @@ +export interface MemberJoinedChannelEvent { + type: 'member_joined_channel'; + user: string; + channel: string; + channel_type: string; + team: string; + inviter?: string; + event_ts: string; +} + +export interface MemberLeftChannelEvent { + type: 'member_left_channel'; + user: string; + channel: string; + channel_type: string; + team: string; + event_ts: string; +} diff --git a/packages/types/src/events/channel.ts b/packages/types/src/events/channel.ts new file mode 100644 index 000000000..7c41d854a --- /dev/null +++ b/packages/types/src/events/channel.ts @@ -0,0 +1,93 @@ +export interface ChannelArchiveEvent { + type: 'channel_archive'; + channel: string; + user: string; + is_moved?: number; + event_ts: string; +} + +export interface ChannelCreatedEvent { + type: 'channel_created'; + event_ts: string; + channel: { + id: string; + is_channel: boolean; + name: string; + name_normalized: string; + created: number; + creator: string; // user ID + is_shared: boolean; + is_org_shared: boolean; + context_team_id: string, + is_archived: boolean; + is_frozen: boolean, + is_general: boolean, + is_group: boolean, + is_private: boolean, + is_ext_shared: boolean, + is_im: boolean, + is_mpim: boolean, + is_pending_ext_shared: boolean, + }; +} + +export interface ChannelDeletedEvent { + type: 'channel_deleted'; + channel: string; +} + +export interface ChannelHistoryChangedEvent { + type: 'channel_history_changed'; + latest: string; + ts: string; + event_ts: string; +} + +export interface ChannelIDChangedEvent { + type: 'channel_id_changed'; + old_channel_id: string; + new_channel_id: string; + event_ts: string; +} + +export interface ChannelLeftEvent { + type: 'channel_left'; + channel: string; + actor_id: string; + event_ts: string; +} + +export interface ChannelRenameEvent { + type: 'channel_rename'; + channel: { + id: string; + name: string; + name_normalized: string; + created: number; + is_channel: boolean; + is_mpim: boolean; + }; + event_ts: string; +} + +export interface ChannelSharedEvent { + type: 'channel_shared'; + connected_team_id: string; + channel: string; + event_ts: string; +} + +export interface ChannelUnarchiveEvent { + type: 'channel_unarchive'; + channel: string; + user: string; + event_ts: string; +} + +export interface ChannelUnsharedEvent { + type: 'channel_unshared'; + previously_connected_team_id: string; + channel: string; + is_ext_shared: boolean; + event_ts: string; +} diff --git a/packages/types/src/events/dnd.ts b/packages/types/src/events/dnd.ts new file mode 100644 index 000000000..1e6675062 --- /dev/null +++ b/packages/types/src/events/dnd.ts @@ -0,0 +1,24 @@ +export interface DNDUpdatedEvent { + type: 'dnd_updated'; + user: string; + dnd_status: { + dnd_enabled: boolean; + next_dnd_start_ts: number; + next_dnd_end_ts: number; + snooze_enabled: boolean; + snooze_endtime: number; + snooze_remaining: number; + }; + event_ts: string; +} + +export interface DNDUpdatedUserEvent { + type: 'dnd_updated_user'; + user: string; + dnd_status: { + dnd_enabled: boolean; + next_dnd_start_ts: number; + next_dnd_end_ts: number; + }; + event_ts: string; +} diff --git a/packages/types/src/events/email.ts b/packages/types/src/events/email.ts new file mode 100644 index 000000000..1e1f1b879 --- /dev/null +++ b/packages/types/src/events/email.ts @@ -0,0 +1,5 @@ +export interface EmailDomainChangedEvent { + type: 'email_domain_changed'; + email_domain: string; + event_ts: string; +} diff --git a/packages/types/src/events/emoji.ts b/packages/types/src/events/emoji.ts new file mode 100644 index 000000000..be14ddbd7 --- /dev/null +++ b/packages/types/src/events/emoji.ts @@ -0,0 +1,11 @@ +// TODO: breaking change: this should probably be broken into its two subtypes +export interface EmojiChangedEvent { + type: 'emoji_changed'; + subtype: 'add' | 'remove' | 'rename'; + names?: string[]; // only for remove + name?: string; // only for add + value?: string; // only for add + old_name?: string; + new_name?: string; + event_ts: string; +} diff --git a/packages/types/src/events/file.ts b/packages/types/src/events/file.ts new file mode 100644 index 000000000..b7cc49847 --- /dev/null +++ b/packages/types/src/events/file.ts @@ -0,0 +1,67 @@ +// NOTE: `file_comment_added` and `file_comment_edited` are left out because they are discontinued + +export interface FileChangeEvent { + type: 'file_change'; + file_id: string; + file: { + id: string; + }; +} + +export interface FileCommentDeletedEvent { + type: 'file_comment_deleted'; + comment: string; // this is an ID + file_id: string; + file: { + id: string; + }; +} + +export interface FileCreatedEvent { + type: 'file_created'; + file_id: string; + user_id: string; + file: { + id: string; + }; + event_ts: string; +} + +export interface FileDeletedEvent { + type: 'file_deleted'; + file_id: string; + channel_ids?: string[]; + event_ts: string; +} + +export interface FilePublicEvent { + type: 'file_public'; + file_id: string; + user_id: string; + file: { + id: string; + }; + event_ts: string; +} + +export interface FileSharedEvent { + type: 'file_shared'; + file_id: string; + user_id: string; + file: { + id: string; + }; + channel_id: string; + event_ts: string; +} + +export interface FileUnsharedEvent { + type: 'file_unshared'; + file_id: string; + user_id: string; + file: { + id: string; + }; + channel_id: string; + event_ts: string; +} diff --git a/packages/types/src/events/function.ts b/packages/types/src/events/function.ts new file mode 100644 index 000000000..d8e3278e6 --- /dev/null +++ b/packages/types/src/events/function.ts @@ -0,0 +1,33 @@ +interface FunctionParams { + type: string; + name: string; + description?: string; + title?: string; + is_required: boolean; +} + +interface FunctionInputs { + [key: string]: unknown; +} + +export interface FunctionExecutedEvent { + type: 'function_executed'; + function: { + id: string; + callback_id: string; + title: string; + description?: string; + type: string; + input_parameters: FunctionParams[]; + output_parameters: FunctionParams[]; + app_id: string; + date_created: number; + date_updated: number; + date_deleted: number + }; + inputs: FunctionInputs; + function_execution_id: string; + workflow_execution_id: string; + event_ts: string; + bot_access_token: string; +} diff --git a/packages/types/src/events/grid-migration.ts b/packages/types/src/events/grid-migration.ts new file mode 100644 index 000000000..ad3ed93ed --- /dev/null +++ b/packages/types/src/events/grid-migration.ts @@ -0,0 +1,9 @@ +export interface GridMigrationFinishedEvent { + type: 'grid_migration_finished'; + enterprise_id: string; +} + +export interface GridMigrationStartedEvent { + type: 'grid_migration_started'; + enterprise_id: string; +} diff --git a/packages/types/src/events/group.ts b/packages/types/src/events/group.ts new file mode 100644 index 000000000..88c26ff77 --- /dev/null +++ b/packages/types/src/events/group.ts @@ -0,0 +1,61 @@ +export interface GroupArchiveEvent { + type: 'group_archive'; + channel: string; + user: string; + is_moved: number; + event_ts: string; +} + +export interface GroupCloseEvent { + type: 'group_close'; + user: string; + channel: string; +} + +export interface GroupDeletedEvent { + type: 'group_deleted'; + channel: string; + date_deleted: number; + actor_id: string; + event_ts: string; +} + +export interface GroupHistoryChangedEvent { + type: 'group_history_changed'; + latest: string; + ts: string; + event_ts: string; +} + +export interface GroupLeftEvent { + type: 'group_left'; + channel: string; + actor_id: string; + event_ts: string; +} + +export interface GroupOpenEvent { + type: 'group_open'; + user: string; + channel: string; +} + +export interface GroupRenameEvent { + type: 'group_rename'; + channel: { + id: string; + name: string; + name_normalized: string; + created: number; + is_channel: boolean; + is_mpim: boolean; + }; + event_ts: string; +} + +export interface GroupUnarchiveEvent { + type: 'group_unarchive'; + channel: string; + actor_id: string; + event_ts: string; +} diff --git a/packages/types/src/events/im.ts b/packages/types/src/events/im.ts new file mode 100644 index 000000000..51fb28d6f --- /dev/null +++ b/packages/types/src/events/im.ts @@ -0,0 +1,31 @@ +export interface IMCloseEvent { + type: 'im_close'; + user: string; + channel: string; + event_ts: string; +} + +export interface IMCreatedEvent { + type: 'im_created'; + user: string; + // TODO: incomplete, this should probably be a reference to a IM shape from @slack/types. can it just be a + // Conversation shape? or should it be a Channel shape? + // https://api.slack.com/types/im + channel: { + id: string; + }; +} + +export interface IMHistoryChangedEvent { + type: 'im_history_changed'; + latest: string; + ts: string; + event_ts: string; +} + +export interface IMOpenEvent { + type: 'im_open'; + user: string; + channel: string; + event_ts: string; +} diff --git a/packages/types/src/events/index.ts b/packages/types/src/events/index.ts new file mode 100644 index 000000000..00a345771 --- /dev/null +++ b/packages/types/src/events/index.ts @@ -0,0 +1,261 @@ +import { + AppDeletedEvent, + AppHomeOpenedEvent, + AppInstalledEvent, + AppMentionEvent, + AppRateLimitedEvent, + AppRequestedEvent, + AppUninstalledEvent, + AppUninstalledTeamEvent, +} from './app'; +import { CallRejectedEvent } from './call'; +import { + ChannelArchiveEvent, + ChannelCreatedEvent, + ChannelDeletedEvent, + ChannelHistoryChangedEvent, + ChannelIDChangedEvent, + ChannelLeftEvent, + ChannelRenameEvent, + ChannelSharedEvent, + ChannelUnarchiveEvent, + ChannelUnsharedEvent, +} from './channel'; +import { MemberJoinedChannelEvent, MemberLeftChannelEvent } from './channel-membership'; +import { DNDUpdatedEvent, DNDUpdatedUserEvent } from './dnd'; +import { EmailDomainChangedEvent } from './email'; +import { EmojiChangedEvent } from './emoji'; +import { + FileChangeEvent, + FileCommentDeletedEvent, + FileCreatedEvent, + FileDeletedEvent, + FilePublicEvent, + FileSharedEvent, + FileUnsharedEvent, +} from './file'; +import { FunctionExecutedEvent } from './function'; +import { GridMigrationFinishedEvent, GridMigrationStartedEvent } from './grid-migration'; +import { + GroupArchiveEvent, + GroupCloseEvent, + GroupDeletedEvent, + GroupHistoryChangedEvent, + GroupLeftEvent, + GroupOpenEvent, + GroupRenameEvent, + GroupUnarchiveEvent, +} from './group'; +import { IMCloseEvent, IMCreatedEvent, IMHistoryChangedEvent, IMOpenEvent } from './im'; +import { InviteRequestedEvent } from './invite'; +import { LinkSharedEvent } from './link-shared'; +import { AllMessageEvents } from './message'; +import { AllMessageMetadataEvents } from './message-metadata'; +import { PinAddedEvent, PinRemovedEvent } from './pin'; +import { ReactionAddedEvent, ReactionRemovedEvent } from './reaction'; +import { + SharedChannelInviteAcceptedEvent, + SharedChannelInviteApprovedEvent, + SharedChannelInviteDeclinedEvent, + SharedChannelInviteReceivedEvent, + SharedChannelInviteRequestedEvent, +} from './shared-channel'; +import { StarAddedEvent, StarRemovedEvent } from './star'; +import { + WorkflowDeletedEvent, + WorkflowPublishedEvent, + WorkflowStepDeletedEvent, + WorkflowStepExecuteEvent, + WorkflowUnpublishedEvent, +} from './steps-from-apps'; +import { + SubteamCreatedEvent, + SubteamMembersChangedEvent, + SubteamSelfAddedEvent, + SubteamSelfRemovedEvent, + SubteamUpdatedEvent, +} from './subteam'; +import { + TeamAccessGrantedEvent, + TeamAccessRevokedEvent, + TeamDomainChangedEvent, + TeamJoinEvent, + TeamRenameEvent, +} from './team'; +import { TokensRevokedEvent } from './token'; +import { UserChangeEvent, UserHuddleChangedEvent, UserProfileChangedEvent, UserStatusChangedEvent } from './user'; + +export { AppDeletedEvent, AppHomeOpenedEvent, AppInstalledEvent, AppMentionEvent, AppRateLimitedEvent, AppRequestedEvent, AppUninstalledEvent, AppUninstalledTeamEvent } from './app'; +export { CallRejectedEvent } from './call'; +export { + ChannelArchiveEvent, + ChannelCreatedEvent, + ChannelDeletedEvent, + ChannelHistoryChangedEvent, + ChannelIDChangedEvent, + ChannelLeftEvent, + ChannelRenameEvent, + ChannelSharedEvent, + ChannelUnarchiveEvent, + ChannelUnsharedEvent, +} from './channel'; +export { DNDUpdatedEvent, DNDUpdatedUserEvent } from './dnd'; +export { EmailDomainChangedEvent } from './email'; +export { EmojiChangedEvent } from './emoji'; +export { + FileChangeEvent, + FileCommentDeletedEvent, + FileCreatedEvent, + FileDeletedEvent, + FilePublicEvent, + FileSharedEvent, + FileUnsharedEvent, +} from './file'; +export { FunctionExecutedEvent } from './function'; +export { GridMigrationFinishedEvent, GridMigrationStartedEvent } from './grid-migration'; +export { + GroupArchiveEvent, + GroupCloseEvent, + GroupDeletedEvent, + GroupHistoryChangedEvent, + GroupLeftEvent, + GroupOpenEvent, + GroupRenameEvent, + GroupUnarchiveEvent, +} from './group'; +export { IMCloseEvent, IMCreatedEvent, IMHistoryChangedEvent, IMOpenEvent } from './im'; +export { InviteRequestedEvent } from './invite'; +export { LinkSharedEvent } from './link-shared'; +export { MemberJoinedChannelEvent, MemberLeftChannelEvent } from './channel-membership'; +export { AllMessageEvents, BotMessageEvent, ChannelArchiveMessageEvent, ChannelJoinMessageEvent, ChannelLeaveMessageEvent, ChannelNameMessageEvent, ChannelPostingPermissionsMessageEvent, ChannelPurposeMessageEvent, ChannelTopicMessageEvent, ChannelUnarchiveMessageEvent, EKMAccessDeniedMessageEvent, FileShareMessageEvent, GenericMessageEvent, MeMessageEvent, MessageChangedEvent, MessageDeletedEvent, MessageRepliedEvent, ThreadBroadcastMessageEvent } from './message'; +export { AllMessageMetadataEvents, MessageMetadataDeletedEvent, MessageMetadataPostedEvent, MessageMetadataUpdatedEvent } from './message-metadata'; +export { PinAddedEvent, PinRemovedEvent } from './pin'; +export { ReactionAddedEvent, ReactionRemovedEvent } from './reaction'; +export { + SharedChannelInviteAccepted, + SharedChannelInviteAcceptedEvent, + SharedChannelInviteApproved, + SharedChannelInviteApprovedEvent, + SharedChannelInviteDeclined, + SharedChannelInviteDeclinedEvent, + SharedChannelInviteReceived, + SharedChannelInviteReceivedEvent, + SharedChannelInviteRequestedEvent, +} from './shared-channel'; +export { StarAddedEvent, StarRemovedEvent } from './star'; +export { + SubteamCreated, + SubteamCreatedEvent, + SubteamMembersChanged, + SubteamMembersChangedEvent, + SubteamSelfAddedEvent, + SubteamSelfRemovedEvent, + SubteamUpdatedEvent, +} from './subteam'; +export { + TeamAccessGrantedEvent, + TeamAccessRevokedEvent, + TeamDomainChangedEvent, + TeamJoinEvent, + TeamRenameEvent, +} from './team'; +export { TokensRevokedEvent } from './token'; +export { UserChangeEvent, UserHuddleChangedEvent, UserProfileChangedEvent, UserStatusChangedEvent } from './user'; +export { + WorkflowDeletedEvent, + WorkflowPublishedEvent, + WorkflowStepDeletedEvent, + WorkflowStepExecuteEvent, + WorkflowUnpublishedEvent, +} from './steps-from-apps'; + +/** + * All known event types in Slack's Events API + * Please refer to https://api.slack.com/events?filter=Events for more details + * This is a discriminated union. The discriminant is the `type` property. + */ +export type SlackEvent = + | AppDeletedEvent + | AppHomeOpenedEvent + | AppInstalledEvent + | AppMentionEvent + | AppRateLimitedEvent + | AppRequestedEvent + | AppUninstalledTeamEvent + | AppUninstalledEvent + | CallRejectedEvent + | ChannelArchiveEvent + | ChannelCreatedEvent + | ChannelDeletedEvent + | ChannelHistoryChangedEvent + | ChannelIDChangedEvent + | ChannelLeftEvent + | ChannelRenameEvent + | ChannelSharedEvent + | ChannelUnarchiveEvent + | ChannelUnsharedEvent + | DNDUpdatedEvent + | DNDUpdatedUserEvent + | EmailDomainChangedEvent + | EmojiChangedEvent + | FileChangeEvent + | FileCommentDeletedEvent + | FileCreatedEvent + | FileDeletedEvent + | FilePublicEvent + | FileSharedEvent + | FileUnsharedEvent + | FunctionExecutedEvent + | GridMigrationFinishedEvent + | GridMigrationStartedEvent + | GroupArchiveEvent + | GroupCloseEvent + | GroupDeletedEvent + | GroupHistoryChangedEvent + | GroupLeftEvent + | GroupOpenEvent + | GroupRenameEvent + | GroupUnarchiveEvent + | IMCloseEvent + | IMCreatedEvent + | IMHistoryChangedEvent + | IMOpenEvent + | InviteRequestedEvent + | LinkSharedEvent + | MemberJoinedChannelEvent + | MemberLeftChannelEvent + | AllMessageEvents // includes the generic message event as well as subtypes + | AllMessageMetadataEvents // includes all metadata-related events + | PinAddedEvent + | PinRemovedEvent + | ReactionAddedEvent + | ReactionRemovedEvent + | SharedChannelInviteAcceptedEvent + | SharedChannelInviteApprovedEvent + | SharedChannelInviteDeclinedEvent + | SharedChannelInviteReceivedEvent + | SharedChannelInviteRequestedEvent + | StarAddedEvent + | StarRemovedEvent + | SubteamCreatedEvent + | SubteamMembersChangedEvent + | SubteamSelfAddedEvent + | SubteamSelfRemovedEvent + | SubteamUpdatedEvent + | TeamAccessGrantedEvent + | TeamAccessRevokedEvent + | TeamDomainChangedEvent + | TeamJoinEvent + | TeamRenameEvent + | TokensRevokedEvent + // TODO: url_verification event is missing, but maybe we don't need it? + // NOTE: url_verification does not use the envelope, but its also not interesting for an app developer. its omitted. + | UserChangeEvent + | UserHuddleChangedEvent + | UserProfileChangedEvent + | UserStatusChangedEvent + | WorkflowDeletedEvent + | WorkflowPublishedEvent + | WorkflowUnpublishedEvent + | WorkflowStepDeletedEvent + | WorkflowStepExecuteEvent; diff --git a/packages/types/src/events/invite.ts b/packages/types/src/events/invite.ts new file mode 100644 index 000000000..8ec1f43ff --- /dev/null +++ b/packages/types/src/events/invite.ts @@ -0,0 +1,19 @@ +export interface InviteRequestedEvent { + type: 'invite_requested'; + invite_request: { + id: string; + email: string; + date_created: number; + requester_ids: string[]; + channel_ids: string[]; + invite_type: 'restricted' | 'ultra_restricted' | 'full_member'; + real_name: string; + date_expire: number; + request_reason: string; + team: { + id: string; + name: string; + domain: string; + }; + }; +} diff --git a/packages/types/src/events/link-shared.ts b/packages/types/src/events/link-shared.ts new file mode 100644 index 000000000..3856504ec --- /dev/null +++ b/packages/types/src/events/link-shared.ts @@ -0,0 +1,15 @@ +export interface LinkSharedEvent { + type: 'link_shared'; + channel: string; + is_bot_user_member: boolean; + user: string; + message_ts: string; + thread_ts?: string; + links: { + domain: string; + url: string; + }[]; + unfurl_id?: string; + source?: string; + event_ts: string; +} diff --git a/packages/types/src/events/message-metadata.ts b/packages/types/src/events/message-metadata.ts new file mode 100644 index 000000000..a7772438a --- /dev/null +++ b/packages/types/src/events/message-metadata.ts @@ -0,0 +1,44 @@ +import { MessageMetadata } from '../message-metadata'; + +export type AllMessageMetadataEvents = +| MessageMetadataDeletedEvent +| MessageMetadataPostedEvent +| MessageMetadataUpdatedEvent; + +export interface MessageMetadataPostedEvent { + type: 'message_metadata_posted'; + app_id: string; + bot_id?: string; + user_id: string; + team_id: string; + channel_id: string; + metadata: MessageMetadata; + message_ts: string; + event_ts: string; +} + +export interface MessageMetadataUpdatedEvent { + type: 'message_metadata_updated'; + channel_id: string; + event_ts: string; + previous_metadata: MessageMetadata; + app_id: string; + bot_id?: string; + user_id: string; + team_id: string; + message_ts: string; + metadata: MessageMetadata; +} + +export interface MessageMetadataDeletedEvent { + type: 'message_metadata_deleted'; + channel_id: string; + event_ts: string; + previous_metadata: MessageMetadata; + app_id: string; + bot_id?: string; + user_id: string; + team_id: string; + message_ts: string; + deleted_ts: string; +} diff --git a/packages/types/src/events/message.ts b/packages/types/src/events/message.ts new file mode 100644 index 000000000..fcba240fd --- /dev/null +++ b/packages/types/src/events/message.ts @@ -0,0 +1,368 @@ +import { Block, KnownBlock } from '../block-kit/blocks'; +import { MessageAttachment } from '../message-attachments'; + +type ChannelTypes = 'channel' | 'group' | 'im' | 'mpim' | 'app_home'; + +export type AllMessageEvents = + | GenericMessageEvent + | BotMessageEvent + | ChannelArchiveMessageEvent + | ChannelJoinMessageEvent + | ChannelLeaveMessageEvent + | ChannelNameMessageEvent + | ChannelPostingPermissionsMessageEvent + | ChannelPurposeMessageEvent + | ChannelTopicMessageEvent + | ChannelUnarchiveMessageEvent + | EKMAccessDeniedMessageEvent + | FileShareMessageEvent + | MeMessageEvent + | MessageChangedEvent + | MessageDeletedEvent + | MessageRepliedEvent + // | ReminderAddEvent // TODO: missing + | ThreadBroadcastMessageEvent; + +export interface GenericMessageEvent { + type: 'message'; + subtype: undefined; + event_ts: string; + team?: string; + channel: string; + user: string; + bot_id?: string; + bot_profile?: BotProfile; + text?: string; + ts: string; + thread_ts?: string; + channel_type: ChannelTypes; + attachments?: MessageAttachment[]; + blocks?: (KnownBlock | Block)[]; + files?: File[]; + edited?: { + user: string; + ts: string; + }; + client_msg_id?: string; + parent_user_id?: string; + + // TODO: optional types that maybe should flow into other subtypes? + is_starred?: boolean; + pinned_to?: string[]; + reactions?: { + name: string; + count: number; + users: string[]; + }[]; +} + +export interface BotMessageEvent { + type: 'message'; + subtype: 'bot_message'; + event_ts: string; + channel: string; + channel_type: ChannelTypes; + ts: string; + text: string; + bot_id: string; + username?: string; + icons?: { + [size: string]: string; + }; + + // copied from MessageEvent + // TODO: is a user really optional? likely for things like IncomingWebhook authored messages + user?: string; + attachments?: MessageAttachment[]; + blocks?: (KnownBlock | Block)[]; + edited?: { + user: string; + ts: string; + }; + thread_ts?: string; +} + +export interface ChannelArchiveMessageEvent { + type: 'message'; + subtype: 'channel_archive'; + team: string; + user: string; + channel: string; + channel_type: ChannelTypes; + text: string; + ts: string; + event_ts: string; +} + +export interface ChannelJoinMessageEvent { + type: 'message'; + subtype: 'channel_join'; + team: string; + user: string; + inviter: string; + channel: string; + channel_type: ChannelTypes; + text: string; + ts: string; + event_ts: string; +} + +export interface ChannelLeaveMessageEvent { + type: 'message'; + subtype: 'channel_leave'; + team: string; + user: string; + channel: string; + channel_type: ChannelTypes; + text: string; + ts: string; + event_ts: string; +} + +export interface ChannelNameMessageEvent { + type: 'message'; + subtype: 'channel_name'; + team: string; + user: string; + name: string; + old_name: string; + channel: string; + channel_type: ChannelTypes; + text: string; + ts: string; + event_ts: string; +} + +export interface ChannelPostingPermissionsMessageEvent { + type: 'message'; + subtype: 'channel_posting_permissions'; + user: string; + channel: string; + channel_type: ChannelTypes; + text: string; + ts: string; + event_ts: string; +} + +export interface ChannelPurposeMessageEvent { + type: 'message'; + subtype: 'channel_purpose'; + user: string; + channel: string; + channel_type: ChannelTypes; + text: string; + purpose: string; + ts: string; + event_ts: string; +} + +export interface ChannelTopicMessageEvent { + type: 'message'; + subtype: 'channel_topic'; + user: string; + channel: string; + channel_type: ChannelTypes; + text: string; + topic: string; + ts: string; + event_ts: string; +} + +export interface ChannelUnarchiveMessageEvent { + type: 'message'; + subtype: 'channel_unarchive'; + team: string; + user: string; + channel: string; + channel_type: ChannelTypes; + text: string; + ts: string; + event_ts: string; +} + +export interface EKMAccessDeniedMessageEvent { + type: 'message'; + subtype: 'ekm_access_denied'; + event_ts: string; + channel: string; + channel_type: ChannelTypes; + ts: string; + text: string; // This will not have any meaningful content within + user: 'UREVOKEDU'; +} + +export interface FileShareMessageEvent { + type: 'message'; + subtype: 'file_share'; + text: string; + attachments?: MessageAttachment[]; + blocks?: (KnownBlock | Block)[]; + files?: File[]; + upload?: boolean; + display_as_bot?: boolean; + x_files?: string[]; + user: string; + parent_user_id?: string; + ts: string; + thread_ts?: string; + channel: string; + channel_type: ChannelTypes; + event_ts: string; +} + +export interface MeMessageEvent { + type: 'message'; + subtype: 'me_message'; + event_ts: string; + channel: string; + channel_type: ChannelTypes; + user: string; + text: string; + ts: string; +} + +export interface MessageChangedEvent { + type: 'message'; + subtype: 'message_changed'; + event_ts: string; + hidden: true; + channel: string; + channel_type: ChannelTypes; + ts: string; + message: MessageEvent; + previous_message: MessageEvent; +} + +export interface MessageDeletedEvent { + type: 'message'; + subtype: 'message_deleted'; + event_ts: string; + hidden: true; + channel: string; + channel_type: ChannelTypes; + ts: string; + deleted_ts: string; + previous_message: MessageEvent; +} + +export interface MessageRepliedEvent { + type: 'message'; + subtype: 'message_replied'; + event_ts: string; + hidden: true; + channel: string; + channel_type: ChannelTypes; + ts: string; + message: MessageEvent & { + // TODO: should this be the union of all message events with type 'message'? + thread_ts: string; + reply_count: number; + replies: MessageEvent[]; // TODO: should this be the union of all message events with type 'message'? + }; +} + +// the `reply_broadcast` message subtype is omitted because it is discontinued + +export interface ThreadBroadcastMessageEvent { + type: 'message'; + subtype: 'thread_broadcast'; + event_ts: string; + text: string; + attachments?: MessageAttachment[]; + blocks?: (KnownBlock | Block)[]; + user: string; + ts: string; + thread_ts?: string; + root: (GenericMessageEvent | BotMessageEvent) & { + thread_ts: string; + reply_count: number; + reply_users_count: number; + latest_reply: string; + reply_users: string[]; + }; + client_msg_id: string; + channel: string; + channel_type: ChannelTypes; +} + +interface BotProfile { + id: string; + name: string; + app_id: string; + team_id: string; + icons: { + [size: string]: string; + }; + updated: number; + deleted: boolean; +} + +interface File { + id: string; + created: number; + name: string | null; + title: string | null; + mimetype: string; + filetype: string; + pretty_type: string; + user?: string; + editable: boolean; + size: number; + mode: 'hosted' | 'external' | 'snippet' | 'post'; + is_external: boolean; + external_type: string | null; + is_public: boolean; + public_url_shared: boolean; + display_as_bot: boolean; + username: string | null; + + // Authentication required + url_private?: string; + url_private_download?: string; + + // Thumbnails (authentication still required) + thumb_64?: string; + thumb_80?: string; + thumb_160?: string; + thumb_360?: string; + thumb_360_w?: number; + thumb_360_h?: number; + thumb_360_gif?: string; + thumb_480?: string; + thumb_720?: string; + thumb_960?: string; + thumb_1024?: string; + permalink: string; + permalink_public?: string; + edit_link?: string; + image_exif_rotation?: number; + original_w?: number; + original_h?: number; + deanimate_gif?: string; + + // Posts + preview?: string; + preview_highlight?: string; + lines?: string; + lines_more?: string; + preview_is_truncated?: boolean; + has_rich_preview?: boolean; + + shares?: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + [key: string]: any; + }; + channels: string[] | null; + groups: string[] | null; + users?: string[]; + pinned_to?: string[]; + reactions?: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + [key: string]: any; + }[]; + is_starred?: boolean; + num_stars?: number; + + initial_comment?: string; + comments_count?: string; +} diff --git a/packages/types/src/events/pin.ts b/packages/types/src/events/pin.ts new file mode 100644 index 000000000..59fbaf2d1 --- /dev/null +++ b/packages/types/src/events/pin.ts @@ -0,0 +1,60 @@ +import { Block, KnownBlock } from '../block-kit/blocks'; +import { BotProfile } from '../common/bot-profile'; +import { MessageAttachment } from '../message-attachments'; + +interface PinnedMessageItem { + client_msg_id?: string; + type: string; + app_id?: string; + team?: string; + user: string; + bot_id?: string; + bot_profile?: BotProfile; + text?: string; + attachments?: MessageAttachment[]; + blocks?: (KnownBlock | Block)[]; + pinned_to?: string[]; + permalink: string; + ts: string +} +interface PinnedFileItem { + id: string; + // TODO: Add all other possible properties here +} +interface PinnedItem { + type: string; + channel: string; + created_by: string; + created: number; + message?: PinnedMessageItem; + file?: PinnedFileItem; +} +export interface PinAddedEvent { + type: 'pin_added'; + user: string; + channel_id: string; + item: PinnedItem; + item_user: string; + pin_count: string; + pinned_info: { + channel: string; + pinned_by: string; + pinned_ts: number; + }; + event_ts: string; +} +export interface PinRemovedEvent { + type: 'pin_removed'; + user: string; + channel_id: string; + item: PinnedItem; + item_user: string; + pin_count: string; + pinned_info: { + channel: string; + pinned_by: string; + pinned_ts: number; + }; + has_pins: boolean; + event_ts: string; +} diff --git a/packages/types/src/events/reaction.ts b/packages/types/src/events/reaction.ts new file mode 100644 index 000000000..d0ed4d34d --- /dev/null +++ b/packages/types/src/events/reaction.ts @@ -0,0 +1,23 @@ +interface ReactionMessageItem { + type: 'message'; + channel: string; + ts: string; +} + +export interface ReactionAddedEvent { + type: 'reaction_added'; + user: string; + reaction: string; + item_user: string; + item: ReactionMessageItem; + event_ts: string; +} + +export interface ReactionRemovedEvent { + type: 'reaction_removed'; + user: string; + reaction: string; + item_user: string; + item: ReactionMessageItem; + event_ts: string; +} diff --git a/packages/types/src/events/shared-channel.ts b/packages/types/src/events/shared-channel.ts new file mode 100644 index 000000000..c64900034 --- /dev/null +++ b/packages/types/src/events/shared-channel.ts @@ -0,0 +1,135 @@ +interface SharedChannelTeamItem { + id: string; + name: string; + icon: Record; + is_verified: boolean; + domain: string; + date_created: number; +} +interface SharedChannelUserItem { + id: string; + team_id: string; + name: string; + updated: number; + profile: { + real_name: string; + display_name: string; + real_name_normalized: string; + display_name_normalized: string; + team: string; + avatar_hash: string; + email: string; + image_24: string; + image_32: string; + image_48: string; + image_72: string; + image_192: string; + image_512: string; + }; +} +interface SharedChannelInviteItem { + id: string; + date_created: number; + date_invalid: number; + inviting_team: SharedChannelTeamItem; + inviting_user: SharedChannelUserItem; + recipient_email?: string; + recipient_user_id?: string; +} + +interface SharedChannelItem { + id: string; + is_private: boolean; + is_im: boolean; + name: string; +} +export interface SharedChannelInviteAcceptedEvent { + type: 'shared_channel_invite_accepted'; + approval_required: boolean; + invite: SharedChannelInviteItem; + channel: SharedChannelItem; + teams_in_channel: SharedChannelTeamItem[]; + accepting_user: SharedChannelUserItem; + event_ts: string; +} +// TODO: (breaking change) for backward-compatibility; remove non-Event-suffix type in next major version. +/** + * @deprecated Will be removed in next major version. Use the `SharedChannelInviteAcceptedEvent` interface instead. + */ +export type SharedChannelInviteAccepted = SharedChannelInviteAcceptedEvent; + +export interface SharedChannelInviteApprovedEvent { + type: 'shared_channel_invite_approved'; + invite: SharedChannelInviteItem; + channel: SharedChannelItem; + approving_team_id: string; + teams_in_channel: SharedChannelTeamItem[]; + approving_user: SharedChannelUserItem; + event_ts: string; +} +// TODO: (breaking change) for backward-compatibility; remove non-Event-suffix type in next major version. +/** + * @deprecated Will be removed in next major version. Use the `SharedChannelInviteApprovedEvent` interface instead. + */ +export type SharedChannelInviteApproved = SharedChannelInviteApprovedEvent; + +export interface SharedChannelInviteDeclinedEvent { + type: 'shared_channel_invite_declined'; + invite: SharedChannelInviteItem; + channel: SharedChannelItem; + declining_team_id: string; + teams_in_channel: SharedChannelTeamItem[]; + declining_user: SharedChannelUserItem; + event_ts: string; +} +// TODO: (breaking change) for backward-compatibility; remove non-Event-suffix type in next major version. +/** + * @deprecated Will be removed in next major version. Use the `SharedChannelInviteDeclinedEvent` interface instead. + */ +export type SharedChannelInviteDeclined = SharedChannelInviteDeclinedEvent; + +export interface SharedChannelInviteReceivedEvent { + type: 'shared_channel_invite_received'; + invite: SharedChannelInviteItem; + channel: SharedChannelItem; + event_ts: string; +} +// TODO: (breaking change) for backward-compatibility; remove non-Event-suffix type in next major version. +/** + * @deprecated Will be removed in next major version. Use the `SharedChannelInviteReceivedEvent` interface instead. + */ +export type SharedChannelInviteReceived = SharedChannelInviteReceivedEvent; + +export interface SharedChannelInviteRequestedEvent { + type: 'shared_channel_invite_requested'; + actor: { + id: string; + name: string; + is_bot: boolean; + team_id: string; + timezone: string; + real_name: string; + display_name: string; + }; + channel_id: string; + event_type: 'slack#/events/shared_channel_invite_requested'; + channel_name: string; + channel_type: 'public' | 'private'; + target_users: [{ email: string; invite_id: string }]; + teams_in_channel: [ + { + id: string; + icon: { image_34: string; image_default: boolean }; + name: string; + domain: string; + is_verified: boolean; + date_created: number; + avatar_base_url: string; + requires_sponsorship: boolean; + }, + ]; + is_external_limited: boolean; + channel_date_created: number; + channel_message_latest_counted_timestamp: number; + event_ts: string; +} diff --git a/packages/types/src/events/star.ts b/packages/types/src/events/star.ts new file mode 100644 index 000000000..ec0ece41e --- /dev/null +++ b/packages/types/src/events/star.ts @@ -0,0 +1,17 @@ +export interface StarAddedEvent { + type: 'star_added'; + user: string; + // TODO: incomplete, items are of type message | file | file comment (deprecated) | channel | im | group + // https://api.slack.com/events/star_added, https://api.slack.com/methods/stars.list + item: Record; + event_ts: string; +} + +export interface StarRemovedEvent { + type: 'star_removed'; + user: string; + // TODO: incomplete, items are of type message | file | file comment (deprecated) | channel | im | group + // https://api.slack.com/events/star_removed, https://api.slack.com/methods/stars.list + item: Record; + event_ts: string; +} diff --git a/packages/types/src/events/steps-from-apps.ts b/packages/types/src/events/steps-from-apps.ts new file mode 100644 index 000000000..395f4b112 --- /dev/null +++ b/packages/types/src/events/steps-from-apps.ts @@ -0,0 +1,86 @@ +export interface WorkflowDeletedEvent { + type: 'workflow_deleted'; + workflow_id: string; + workflow_draft_configuration: { + version_id: string; + app_steps: { + app_id: string; + workflow_step_id: string; + callback_id: string; + }[]; + }; + event_ts: string; +} + +export interface WorkflowPublishedEvent { + type: 'workflow_published'; + workflow_id: string; + workflow_published_configuration: { + version_id: string; + app_steps: { + app_id: string; + workflow_step_id: string; + callback_id: string; + }[]; + }; + event_ts: string; +} + +export interface WorkflowUnpublishedEvent { + type: 'workflow_unpublished'; + workflow_id: string; + workflow_draft_configuration: { + version_id: string; + app_steps: { + app_id: string; + workflow_step_id: string; + callback_id: string; + }[]; + }; + event_ts: string; +} + +export interface WorkflowStepDeletedEvent { + type: 'workflow_step_deleted'; + workflow_id: string; + workflow_draft_configuration: { + version_id: string; + app_steps: { + app_id: string; + workflow_step_id: string; + callback_id: string; + }[]; + }; + workflow_published_configuration?: { + version_id: string; + app_steps: { + app_id: string; + workflow_step_id: string; + callback_id: string; + }[]; + }; + event_ts: string; +} + +export interface WorkflowStepExecuteEvent { + type: 'workflow_step_execute'; + callback_id: string; + workflow_step: { + workflow_step_execute_id: string; + workflow_id: string; + workflow_instance_id: string; + step_id: string; + inputs: { + [key: string]: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + value: any; + }; + }; + outputs: { + name: string; + type: string; + label: string; + }[]; + }; + event_ts: string; +} diff --git a/packages/types/src/events/subteam.ts b/packages/types/src/events/subteam.ts new file mode 100644 index 000000000..2f1365b08 --- /dev/null +++ b/packages/types/src/events/subteam.ts @@ -0,0 +1,71 @@ +interface Subteam { + id: string; + team_id?: string; + is_usergroup: boolean; + is_subteam: boolean; + name: string; + description?: string; + handle: string; + is_external: boolean; + date_create: number; + date_update?: number; + date_delete?: number; + auto_provision: boolean; + enterprise_subteam_id?: string; + created_by: string; + updated_by?: string; + prefs?: { + channels?: string[]; + groups?: string[]; + }; + users: string[]; + user_count: number; + channel_count?: number; +} + +export interface SubteamCreatedEvent { + type: 'subteam_created'; + subteam: Subteam; + event_ts: string; +} +// TODO: (breaking change) for backward-compatibility; remove non-Event-suffix type in next major version. +/** + * @deprecated Will be removed in next major version. Use the `SubteamCreatedEvent` interface instead. + */ +export type SubteamCreated = SubteamCreatedEvent; + +export interface SubteamMembersChangedEvent { + type: 'subteam_members_changed'; + subteam_id: string; + team_id: string; + date_previous_update: number; + date_update: number; + added_users?: string[]; + added_users_count?: number; + removed_users?: string[]; + removed_users_count?: number; + event_ts: string; +} +// TODO: (breaking change) for backward-compatibility; remove non-Event-suffix type in next major version. +/** + * @deprecated Will be removed in next major version. Use the `SubteamMembersChangedEvent` interface instead. + */ +export type SubteamMembersChanged = SubteamMembersChangedEvent; + +export interface SubteamSelfAddedEvent { + type: 'subteam_self_added'; + subteam_id: string; + event_ts: string; +} + +export interface SubteamSelfRemovedEvent { + type: 'subteam_self_removed'; + subteam_id: string; + event_ts: string; +} + +export interface SubteamUpdatedEvent { + type: 'subteam_updated'; + subteam: Subteam; + event_ts: string; +} diff --git a/packages/types/src/events/team.ts b/packages/types/src/events/team.ts new file mode 100644 index 000000000..ea084e07d --- /dev/null +++ b/packages/types/src/events/team.ts @@ -0,0 +1,106 @@ +import { StatusEmojiDisplayInfo } from '../common/status-emoji-display-info'; + +export interface TeamAccessGrantedEvent { + type: 'team_access_granted'; + team_ids: string[]; + event_ts: string; +} + +export interface TeamAccessRevokedEvent { + type: 'team_access_revoked'; + team_ids: string[]; + event_ts: string; +} + +export interface TeamDomainChangedEvent { + type: 'team_domain_changed'; + url: string; + domain: string; +} + +export interface TeamJoinEvent { + type: 'team_join'; + user: { + id: string; + team_id: string; + name: string; + deleted: boolean; + color: string; + real_name: string; + tz: string; + tz_label: string; + tz_offset: number; + profile: { + title: string; + phone: string; + skype: string; + real_name: string; + real_name_normalized: string; + display_name: string; + display_name_normalized: string; + status_text: string; + status_text_canonical: string; + status_emoji: string; + status_emoji_display_info: StatusEmojiDisplayInfo[]; + status_expiration: number; + avatar_hash: string; + huddle_state?: string; + huddle_state_expiration_ts?: number; + first_name: string; + last_name: string; + email?: string; + image_original?: string; + is_custom_image?: boolean; + image_24: string; + image_32: string; + image_48: string; + image_72: string; + image_192: string; + image_512: string; + image_1024?: string; + team: string; + fields: + | { + [key: string]: { + value: string; + alt: string; + }; + } + | [] + | null; + }; + is_admin: boolean; + is_owner: boolean; + is_primary_owner: boolean; + is_restricted: boolean; + is_ultra_restricted: boolean; + is_bot: boolean; + is_stranger?: boolean; + updated: number; + is_email_confirmed: boolean; + is_app_user: boolean; + is_invited_user?: boolean; + has_2fa?: boolean; + locale: string; + presence?: string; + enterprise_user?: { + id: string; + enterprise_id: string; + enterprise_name: string; + is_admin: boolean; + is_owner: boolean; + teams: string[]; + }; + two_factor_type?: string; + has_files?: boolean; + is_workflow_bot?: boolean; + who_can_share_contact_card: string; + }; + cache_ts: number; + event_ts: string; +} + +export interface TeamRenameEvent { + type: 'team_rename'; + name: string; +} diff --git a/packages/types/src/events/token.ts b/packages/types/src/events/token.ts new file mode 100644 index 000000000..162177739 --- /dev/null +++ b/packages/types/src/events/token.ts @@ -0,0 +1,7 @@ +export interface TokensRevokedEvent { + type: 'tokens_revoked'; + tokens: { + oauth?: string[]; + bot?: string[]; + }; +} diff --git a/packages/types/src/events/user.ts b/packages/types/src/events/user.ts new file mode 100644 index 000000000..928af13bf --- /dev/null +++ b/packages/types/src/events/user.ts @@ -0,0 +1,327 @@ +import { StatusEmojiDisplayInfo } from '../common/status-emoji-display-info'; + +export interface UserChangeEvent { + type: 'user_change'; + user: { + id: string; + team_id: string; + name: string; + deleted: boolean; + color: string; + real_name: string; + tz: string; + tz_label: string; + tz_offset: number; + profile: { + title: string; + phone: string; + skype: string; + real_name: string; + real_name_normalized: string; + display_name: string; + display_name_normalized: string; + status_text: string; + status_text_canonical: string; + status_emoji: string; + status_emoji_display_info: StatusEmojiDisplayInfo[]; + status_expiration: number; + avatar_hash: string; + huddle_state?: string; + huddle_state_expiration_ts?: number; + first_name: string; + last_name: string; + email?: string; + image_original?: string; + is_custom_image?: boolean; + image_24: string; + image_32: string; + image_48: string; + image_72: string; + image_192: string; + image_512: string; + image_1024?: string; + team: string; + fields: + | { + [key: string]: { + value: string; + alt: string; + }; + } + | [] + | null; + }; + is_admin: boolean; + is_owner: boolean; + is_primary_owner: boolean; + is_restricted: boolean; + is_ultra_restricted: boolean; + is_bot: boolean; + is_stranger?: boolean; + updated: number; + is_email_confirmed: boolean; + is_app_user: boolean; + is_invited_user?: boolean; + has_2fa?: boolean; + locale: string; + presence?: string; + enterprise_user?: { + id: string; + enterprise_id: string; + enterprise_name: string; + is_admin: boolean; + is_owner: boolean; + teams: string[]; + }; + two_factor_type?: string; + has_files?: boolean; + is_workflow_bot?: boolean; + who_can_share_contact_card: string; + }; + cache_ts: number; + event_ts: string; +} + +export interface UserHuddleChangedEvent { + type: 'user_huddle_changed'; + user: { + id: string; + team_id: string; + name: string; + deleted: boolean; + color: string; + real_name: string; + tz: string; + tz_label: string; + tz_offset: number; + profile: { + title: string; + phone: string; + skype: string; + real_name: string; + real_name_normalized: string; + display_name: string; + display_name_normalized: string; + status_text: string; + status_text_canonical: string; + status_emoji: string; + status_emoji_display_info: StatusEmojiDisplayInfo[]; + status_expiration: number; + avatar_hash: string; + huddle_state: string; + huddle_state_expiration_ts: number; + first_name: string; + last_name: string; + email?: string; + image_original?: string; + is_custom_image?: boolean; + image_24: string; + image_32: string; + image_48: string; + image_72: string; + image_192: string; + image_512: string; + image_1024?: string; + team: string; + fields: + | { + [key: string]: { + value: string; + alt: string; + }; + } + | [] + | null; + }; + is_admin: boolean; + is_owner: boolean; + is_primary_owner: boolean; + is_restricted: boolean; + is_ultra_restricted: boolean; + is_bot: boolean; + is_stranger?: boolean; + updated: number; + is_email_confirmed: boolean; + is_app_user: boolean; + is_invited_user?: boolean; + has_2fa?: boolean; + locale: string; + presence?: string; + enterprise_user?: { + id: string; + enterprise_id: string; + enterprise_name: string; + is_admin: boolean; + is_owner: boolean; + teams: string[]; + }; + two_factor_type?: string; + has_files?: boolean; + is_workflow_bot?: boolean; + who_can_share_contact_card: string; + }; + cache_ts: number; + event_ts: string; +} + +export interface UserProfileChangedEvent { + type: 'user_profile_changed'; + user: { + id: string; + team_id: string; + name: string; + deleted: boolean; + color: string; + real_name: string; + tz: string; + tz_label: string; + tz_offset: number; + profile: { + title: string; + phone: string; + skype: string; + real_name: string; + real_name_normalized: string; + display_name: string; + display_name_normalized: string; + status_text: string; + status_text_canonical: string; + status_emoji: string; + status_emoji_display_info: StatusEmojiDisplayInfo[]; + status_expiration: number; + avatar_hash: string; + huddle_state: string; + huddle_state_expiration_ts: number; + first_name: string; + last_name: string; + email?: string; + image_original?: string; + is_custom_image?: boolean; + image_24: string; + image_32: string; + image_48: string; + image_72: string; + image_192: string; + image_512: string; + image_1024?: string; + team: string; + fields: + | { + [key: string]: { + value: string; + alt: string; + }; + } + | [] + | null; + }; + is_admin: boolean; + is_owner: boolean; + is_primary_owner: boolean; + is_restricted: boolean; + is_ultra_restricted: boolean; + is_bot: boolean; + is_stranger?: boolean; + updated: number; + is_email_confirmed: boolean; + is_app_user: boolean; + is_invited_user?: boolean; + has_2fa?: boolean; + locale: string; + presence?: string; + enterprise_user?: { + id: string; + enterprise_id: string; + enterprise_name: string; + is_admin: boolean; + is_owner: boolean; + teams: string[]; + }; + two_factor_type?: string; + has_files?: boolean; + is_workflow_bot?: boolean; + who_can_share_contact_card: string; + }; + cache_ts: number; + event_ts: string; +} + +export interface UserStatusChangedEvent { + type: 'user_status_changed'; + user: { + id: string; + team_id: string; + name: string; + deleted: boolean; + color: string; + real_name: string; + tz: string; + tz_label: string; + tz_offset: number; + profile: { + title: string; + phone: string; + skype: string; + real_name: string; + real_name_normalized: string; + display_name: string; + display_name_normalized: string; + status_text: string; + status_text_canonical: string; + status_emoji: string; + status_emoji_display_info: StatusEmojiDisplayInfo[], + status_expiration: number; + avatar_hash: string; + first_name: string; + last_name: string; + email?: string; + image_original?: string; + is_custom_image?: boolean; + image_24: string; + image_32: string; + image_48: string; + image_72: string; + image_192: string; + image_512: string; + image_1024?: string; + team: string; + fields: + | { + [key: string]: { + value: string; + alt: string; + }; + } + | [] + | null; + }; + is_admin: boolean; + is_owner: boolean; + is_primary_owner: boolean; + is_restricted: boolean; + is_ultra_restricted: boolean; + is_bot: boolean; + is_stranger?: boolean; + updated: number; + is_email_confirmed: boolean; + is_app_user: boolean; + is_invited_user?: boolean; + has_2fa?: boolean; + locale: string; + presence?: string; + enterprise_user?: { + id: string; + enterprise_id: string; + enterprise_name: string; + is_admin: boolean; + is_owner: boolean; + teams: string[]; + }; + two_factor_type?: string; + has_files?: boolean; + is_workflow_bot?: boolean; + who_can_share_contact_card: string; + }; + cache_ts: number; + event_ts: string; +}