@emulators/slack 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @emulators/slack
2
2
 
3
- Fully stateful Slack Web API emulation with channels, messages, threads, reactions, OAuth v2, and incoming webhooks.
3
+ Fully stateful Slack Web API emulation with channels, messages, threads, reactions, user profiles, presence, modern file uploads, pins, bookmarks, views, OAuth v2, and incoming webhooks. Chat writes preserve common rich message fields such as `blocks`, `attachments`, `metadata`, formatting flags, unfurl flags, and client message ids. Conversation writes update archive state, names, topics, purposes, membership, DMs, MPIMs, and read cursors. User writes update profile fields, status, custom fields, and deterministic active or away presence. File writes support the current external upload flow with local upload URLs, file share messages, reads, lists, downloads, and deletes. Pin and bookmark writes support channel message pins and link bookmarks. View writes support App Home publishing and modal stacks. OAuth installs create bot users and installation records. OAuth exchanges and explicit token seeds create scoped token records. Supported write state changes dispatch Slack `event_callback` payloads to configured webhook URLs.
4
4
 
5
5
  Part of [emulate](https://github.com/vercel-labs/emulate) — local drop-in replacement services for CI and no-network sandboxes.
6
6
 
@@ -14,38 +14,88 @@ npm install @emulators/slack
14
14
 
15
15
  ### Auth & Chat
16
16
  - `POST /api/auth.test` — test authentication
17
- - `POST /api/chat.postMessage` — post message (supports threads via `thread_ts`)
18
- - `POST /api/chat.update` — update message
17
+ - `POST /api/chat.postMessage` — post message with text or rich payload fields (supports threads via `thread_ts` and DM user IDs)
18
+ - `POST /api/chat.postEphemeral` — post ephemeral message outside channel history
19
+ - `POST /api/chat.update` — update message text and rich payload fields
19
20
  - `POST /api/chat.delete` — delete message
21
+ - `GET /api/chat.getPermalink` / `POST /api/chat.getPermalink` — get message permalink
22
+ - `POST /api/chat.scheduleMessage` — schedule pending message
23
+ - `POST /api/chat.deleteScheduledMessage` — delete pending scheduled message
24
+ - `POST /api/chat.scheduledMessages.list` — list pending scheduled messages
20
25
  - `POST /api/chat.meMessage` — /me message
21
26
 
22
27
  ### Conversations
23
- - `POST /api/conversations.list` — list channels (cursor pagination)
28
+ - `POST /api/conversations.list` — list conversations (cursor pagination, `types`, `exclude_archived`)
24
29
  - `POST /api/conversations.info` — get channel info
25
30
  - `POST /api/conversations.create` — create channel
26
- - `POST /api/conversations.history` — channel history
27
- - `POST /api/conversations.replies` — thread replies
31
+ - `POST /api/conversations.archive` / `conversations.unarchive` archive/restore channel
32
+ - `POST /api/conversations.rename` — rename channel
33
+ - `POST /api/conversations.setTopic` / `conversations.setPurpose` — update topic/purpose
34
+ - `POST /api/conversations.history` — channel history with rich message fields
35
+ - `POST /api/conversations.replies` — thread replies with rich message fields
28
36
  - `POST /api/conversations.join` / `conversations.leave` — join/leave
37
+ - `POST /api/conversations.invite` / `conversations.kick` — manage membership
38
+ - `POST /api/conversations.open` / `conversations.close` — open/close DMs and MPIMs
39
+ - `POST /api/conversations.mark` — mark read cursor
29
40
  - `POST /api/conversations.members` — list members
30
41
 
31
42
  ### Users & Reactions
32
43
  - `POST /api/users.list` — list users (cursor pagination)
33
44
  - `POST /api/users.info` — get user info
34
45
  - `POST /api/users.lookupByEmail` — lookup by email
46
+ - `GET /api/users.profile.get` / `POST /api/users.profile.get` — get user profile fields
47
+ - `POST /api/users.profile.set` — update profile fields, status, and custom fields
48
+ - `GET /api/users.getPresence` / `POST /api/users.getPresence` — get active or away presence
49
+ - `POST /api/users.setPresence` — set the authed user to away or automatic presence
35
50
  - `POST /api/reactions.add` / `reactions.remove` / `reactions.get` — manage reactions
36
51
 
52
+ ### Files
53
+ - `POST /api/files.getUploadURLExternal` — create a local external upload session
54
+ - `POST /upload/v1/:fileId` — receive raw uploaded file bytes
55
+ - `POST /api/files.completeUploadExternal` — complete uploads and optionally share file messages
56
+ - `GET /api/files.info` / `POST /api/files.info` — get file metadata
57
+ - `GET /api/files.list` / `POST /api/files.list` — list completed files
58
+ - `GET /files-pri/:fileId/:filename` — download file bytes with a bearer token that can access the file
59
+ - `POST /api/files.delete` — delete a completed file
60
+
61
+ ### Pins & Bookmarks
62
+ - `POST /api/pins.add` — pin a message to a channel
63
+ - `GET /api/pins.list` / `POST /api/pins.list` — list pinned message items for a channel
64
+ - `POST /api/pins.remove` — remove a message pin from a channel
65
+ - `POST /api/bookmarks.add` — add a link bookmark to a channel
66
+ - `POST /api/bookmarks.edit` — update a link bookmark
67
+ - `POST /api/bookmarks.list` — list channel bookmarks
68
+ - `POST /api/bookmarks.remove` — remove a bookmark from a channel
69
+
70
+ ### Views
71
+ - `POST /api/views.publish` — publish or update an App Home view for a user
72
+ - `POST /api/views.open` — open a modal view
73
+ - `POST /api/views.update` — update a view by `view_id` or `external_id`
74
+ - `POST /api/views.push` — push a modal view onto the current modal stack
75
+ - `POST /api/views.generateTriggerId` — local helper for tests that need a modal trigger id
76
+
77
+ Modal opens and pushes require values from `/api/views.generateTriggerId`. Pass the returned value as `trigger_id` or `interactivity_pointer`; generate push values with an existing `view_id` and use them within 3 seconds.
78
+
37
79
  ### Team, Bots & Webhooks
38
80
  - `POST /api/team.info` — workspace info
39
81
  - `POST /api/bots.info` — bot info
40
- - `POST /services/:teamId/:botId/:webhookId` — incoming webhook
82
+ - `POST /services/:teamId/:botId/:webhookId` — incoming webhook with text or rich payload fields
41
83
 
42
84
  ### OAuth
43
85
  - `GET /oauth/v2/authorize` — authorization (shows user picker)
86
+ - `POST /oauth/v2/authorize/callback` — local user picker callback that creates the auth code
44
87
  - `POST /api/oauth.v2.access` — token exchange
45
88
 
89
+ ### Inspector
90
+ - `GET /` — tabbed local inspector for conversations, messages, files, views, auth records, incoming webhooks, event subscriptions, and event deliveries
91
+
46
92
  ## Auth
47
93
 
48
- All Web API endpoints require `Authorization: Bearer <token>`. OAuth v2 flow with user picker UI.
94
+ All Web API endpoints require `Authorization: Bearer <token>`. Seeded OAuth apps create local installation state, and the OAuth v2 flow with user picker UI returns Slack-style bot tokens. Scope checks are relaxed by default for local development. Set `strict_scopes: true` in Slack seed config to return Slack-style `missing_scope` errors when a token lacks the required method scope. Strict mode checks `chat:write`, `channels:read`, `channels:history`, `channels:join`, `channels:manage`, `channels:write`, `groups:read`, `groups:history`, `groups:write`, `im:read`, `im:history`, `im:write`, `mpim:read`, `mpim:history`, `mpim:write`, `users:read`, `users:read.email`, `users.profile:read`, `users.profile:write`, `users:write`, `files:read`, `files:write`, `pins:read`, `pins:write`, `bookmarks:read`, `bookmarks:write`, `reactions:read`, `reactions:write`, and `team:read`. Slack lists no method-specific scopes for `views.publish`, `views.open`, `views.update`, or `views.push`, so the emulator requires auth but does not add strict-scope checks for those methods.
95
+
96
+ ## Current Limits
97
+
98
+ Slack Connect, Enterprise Grid admin APIs, Audit Logs API, SCIM, Legal Holds, Socket Mode, slash command and interaction simulation, user groups, reminders, stars, calls, canvases, lists, functions, workflows, chat streaming, legacy `files.upload`, exact rate limiting, and paid-plan behavior are not implemented.
49
99
 
50
100
  ## Seed Configuration
51
101
 
@@ -58,6 +108,11 @@ slack:
58
108
  - name: developer
59
109
  real_name: Developer
60
110
  email: dev@example.com
111
+ profile:
112
+ title: Local Developer
113
+ status_text: Testing locally
114
+ status_emoji: ":computer:"
115
+ presence: active
61
116
  channels:
62
117
  - name: general
63
118
  topic: General discussion
@@ -68,9 +123,78 @@ slack:
68
123
  oauth_apps:
69
124
  - client_id: "12345.67890"
70
125
  client_secret: example_client_secret
126
+ app_id: A000000001
71
127
  name: My Slack App
72
128
  redirect_uris:
73
129
  - http://localhost:3000/api/auth/callback/slack
130
+ scopes:
131
+ - chat:write
132
+ - channels:read
133
+ - channels:history
134
+ - channels:join
135
+ - channels:manage
136
+ - channels:write
137
+ - groups:read
138
+ - groups:history
139
+ - groups:write
140
+ - im:read
141
+ - im:history
142
+ - im:write
143
+ - mpim:read
144
+ - mpim:history
145
+ - mpim:write
146
+ - users:read
147
+ - users:read.email
148
+ - users.profile:read
149
+ - users.profile:write
150
+ - users:write
151
+ - files:read
152
+ - files:write
153
+ - pins:read
154
+ - pins:write
155
+ - bookmarks:read
156
+ - bookmarks:write
157
+ - reactions:read
158
+ - reactions:write
159
+ - team:read
160
+ user_scopes:
161
+ - users:read
162
+ - users.profile:read
163
+ bot_name: my-bot
164
+ tokens:
165
+ - token: xoxb-local-test
166
+ user: developer
167
+ scopes:
168
+ - chat:write
169
+ - channels:read
170
+ - channels:history
171
+ - channels:join
172
+ - channels:manage
173
+ - channels:write
174
+ - groups:read
175
+ - groups:history
176
+ - groups:write
177
+ - im:read
178
+ - im:history
179
+ - im:write
180
+ - mpim:read
181
+ - mpim:history
182
+ - mpim:write
183
+ - users:read
184
+ - users:read.email
185
+ - users.profile:read
186
+ - users.profile:write
187
+ - users:write
188
+ - files:read
189
+ - files:write
190
+ - pins:read
191
+ - pins:write
192
+ - bookmarks:read
193
+ - bookmarks:write
194
+ - reactions:read
195
+ - reactions:write
196
+ - team:read
197
+ strict_scopes: false
74
198
  ```
75
199
 
76
200
  ## Links
package/dist/index.d.ts CHANGED
@@ -5,6 +5,40 @@ interface SlackTeam extends Entity {
5
5
  name: string;
6
6
  domain: string;
7
7
  }
8
+ interface SlackUserProfile {
9
+ display_name: string;
10
+ real_name: string;
11
+ email: string;
12
+ image_48: string;
13
+ image_192: string;
14
+ title?: string;
15
+ phone?: string;
16
+ skype?: string;
17
+ real_name_normalized?: string;
18
+ display_name_normalized?: string;
19
+ fields?: Record<string, {
20
+ value: string;
21
+ alt?: string;
22
+ label?: string;
23
+ }>;
24
+ status_text?: string;
25
+ status_emoji?: string;
26
+ status_emoji_display_info?: Record<string, unknown>[];
27
+ status_expiration?: number;
28
+ avatar_hash?: string;
29
+ start_date?: string;
30
+ pronouns?: string;
31
+ huddle_state?: string;
32
+ huddle_state_expiration_ts?: number;
33
+ first_name?: string;
34
+ last_name?: string;
35
+ image_24?: string;
36
+ image_32?: string;
37
+ image_72?: string;
38
+ image_512?: string;
39
+ }
40
+ type SlackPresence = "active" | "away";
41
+ type SlackManualPresence = "auto" | "away";
8
42
  interface SlackUser extends Entity {
9
43
  user_id: string;
10
44
  team_id: string;
@@ -14,13 +48,11 @@ interface SlackUser extends Entity {
14
48
  is_admin: boolean;
15
49
  is_bot: boolean;
16
50
  deleted: boolean;
17
- profile: {
18
- display_name: string;
19
- real_name: string;
20
- email: string;
21
- image_48: string;
22
- image_192: string;
23
- };
51
+ profile: SlackUserProfile;
52
+ presence?: SlackPresence;
53
+ manual_presence?: SlackManualPresence;
54
+ connection_count?: number;
55
+ last_activity?: number;
24
56
  }
25
57
  interface SlackChannel extends Entity {
26
58
  channel_id: string;
@@ -28,6 +60,11 @@ interface SlackChannel extends Entity {
28
60
  name: string;
29
61
  is_channel: boolean;
30
62
  is_private: boolean;
63
+ is_im?: boolean;
64
+ is_mpim?: boolean;
65
+ is_open?: boolean;
66
+ is_open_by_user?: Record<string, boolean>;
67
+ user?: string;
31
68
  is_archived: boolean;
32
69
  topic: {
33
70
  value: string;
@@ -42,7 +79,9 @@ interface SlackChannel extends Entity {
42
79
  members: string[];
43
80
  creator: string;
44
81
  num_members: number;
82
+ last_read?: Record<string, string>;
45
83
  }
84
+ type SlackJsonObject = Record<string, unknown>;
46
85
  interface SlackMessage extends Entity {
47
86
  ts: string;
48
87
  channel_id: string;
@@ -50,6 +89,31 @@ interface SlackMessage extends Entity {
50
89
  text: string;
51
90
  type: "message";
52
91
  subtype?: string;
92
+ files?: SlackFile[];
93
+ upload?: boolean;
94
+ blocks?: SlackJsonObject[];
95
+ attachments?: SlackJsonObject[];
96
+ metadata?: SlackJsonObject;
97
+ mrkdwn?: boolean;
98
+ parse?: string;
99
+ link_names?: boolean;
100
+ unfurl_links?: boolean;
101
+ unfurl_media?: boolean;
102
+ username?: string;
103
+ icon_url?: string;
104
+ icon_emoji?: string;
105
+ bot_id?: string;
106
+ app_id?: string;
107
+ client_msg_id?: string;
108
+ reply_broadcast?: boolean;
109
+ topic?: string;
110
+ purpose?: string;
111
+ old_name?: string;
112
+ name?: string;
113
+ edited?: {
114
+ user: string;
115
+ ts: string;
116
+ };
53
117
  thread_ts?: string;
54
118
  reply_count: number;
55
119
  reply_users: string[];
@@ -59,8 +123,39 @@ interface SlackMessage extends Entity {
59
123
  count: number;
60
124
  }>;
61
125
  }
126
+ interface SlackEphemeralMessage extends SlackMessage {
127
+ target_user: string;
128
+ }
129
+ interface SlackScheduledMessage extends Entity {
130
+ scheduled_message_id: string;
131
+ channel_id: string;
132
+ user: string;
133
+ text: string;
134
+ type: "delayed_message";
135
+ subtype: "bot_message";
136
+ blocks?: SlackJsonObject[];
137
+ attachments?: SlackJsonObject[];
138
+ metadata?: SlackJsonObject;
139
+ mrkdwn?: boolean;
140
+ parse?: string;
141
+ link_names?: boolean;
142
+ unfurl_links?: boolean;
143
+ unfurl_media?: boolean;
144
+ username?: string;
145
+ icon_url?: string;
146
+ icon_emoji?: string;
147
+ bot_id?: string;
148
+ app_id?: string;
149
+ client_msg_id?: string;
150
+ reply_broadcast?: boolean;
151
+ thread_ts?: string;
152
+ post_at: number;
153
+ date_created: number;
154
+ }
62
155
  interface SlackBot extends Entity {
63
156
  bot_id: string;
157
+ app_id?: string;
158
+ user_id?: string;
64
159
  name: string;
65
160
  deleted: boolean;
66
161
  icons: {
@@ -68,10 +163,42 @@ interface SlackBot extends Entity {
68
163
  };
69
164
  }
70
165
  interface SlackOAuthApp extends Entity {
166
+ app_id?: string;
71
167
  client_id: string;
72
168
  client_secret: string;
73
169
  name: string;
74
170
  redirect_uris: string[];
171
+ scopes?: string[];
172
+ user_scopes?: string[];
173
+ bot_id?: string;
174
+ bot_user_id?: string;
175
+ bot_name?: string;
176
+ }
177
+ interface SlackInstallation extends Entity {
178
+ installation_id: string;
179
+ app_id: string;
180
+ client_id: string;
181
+ team_id: string;
182
+ app_name: string;
183
+ installer_user_id: string;
184
+ bot_id: string;
185
+ bot_user_id: string;
186
+ scopes: string[];
187
+ user_scopes: string[];
188
+ }
189
+ type SlackTokenType = "bot" | "user" | "test";
190
+ interface SlackToken extends Entity {
191
+ token: string;
192
+ token_type: SlackTokenType;
193
+ team_id: string;
194
+ user_id: string;
195
+ scopes: string[];
196
+ app_id?: string;
197
+ client_id?: string;
198
+ installation_id?: string;
199
+ bot_id?: string;
200
+ bot_user_id?: string;
201
+ authed_user_id?: string;
75
202
  }
76
203
  interface SlackIncomingWebhook extends Entity {
77
204
  token: string;
@@ -81,15 +208,150 @@ interface SlackIncomingWebhook extends Entity {
81
208
  label: string;
82
209
  url: string;
83
210
  }
211
+ interface SlackFileShare {
212
+ ts: string;
213
+ channel_name?: string;
214
+ team_id: string;
215
+ share_user_id: string;
216
+ source: "UNKNOWN" | "UPLOAD";
217
+ thread_ts?: string;
218
+ latest_reply?: string;
219
+ reply_count: number;
220
+ reply_users: string[];
221
+ reply_users_count: number;
222
+ is_silent_share: boolean;
223
+ }
224
+ interface SlackFile extends Entity {
225
+ file_id: string;
226
+ team_id: string;
227
+ user: string;
228
+ name: string;
229
+ title: string;
230
+ mimetype: string;
231
+ filetype: string;
232
+ pretty_type: string;
233
+ mode: "hosted" | "snippet";
234
+ size: number;
235
+ created: number;
236
+ timestamp: number;
237
+ url_private: string;
238
+ url_private_download: string;
239
+ permalink: string;
240
+ is_external: boolean;
241
+ external_type: string;
242
+ is_public: boolean;
243
+ public_url_shared: boolean;
244
+ display_as_bot: boolean;
245
+ editable: boolean;
246
+ deleted: boolean;
247
+ channels: string[];
248
+ groups: string[];
249
+ ims: string[];
250
+ shares: {
251
+ public?: Record<string, SlackFileShare[]>;
252
+ private?: Record<string, SlackFileShare[]>;
253
+ };
254
+ initial_comment?: string;
255
+ thread_ts?: string;
256
+ alt_txt?: string;
257
+ snippet_type?: string;
258
+ content_base64?: string;
259
+ }
260
+ interface SlackFileUploadSession extends Entity {
261
+ file_id: string;
262
+ team_id: string;
263
+ user: string;
264
+ filename: string;
265
+ title: string;
266
+ length: number;
267
+ upload_url: string;
268
+ alt_txt?: string;
269
+ snippet_type?: string;
270
+ uploaded: boolean;
271
+ uploaded_size?: number;
272
+ content_base64?: string;
273
+ completed: boolean;
274
+ }
275
+ interface SlackPin extends Entity {
276
+ pin_id: string;
277
+ team_id: string;
278
+ channel_id: string;
279
+ message_ts: string;
280
+ created: number;
281
+ created_by: string;
282
+ }
283
+ interface SlackBookmark extends Entity {
284
+ bookmark_id: string;
285
+ team_id: string;
286
+ channel_id: string;
287
+ title: string;
288
+ type: "link";
289
+ link: string;
290
+ emoji: string;
291
+ icon_url: string;
292
+ entity_id: string | null;
293
+ date_created: number;
294
+ date_updated: number;
295
+ rank: string;
296
+ last_updated_by_user_id: string;
297
+ last_updated_by_team_id: string;
298
+ shortcut_id: string | null;
299
+ app_id: string | null;
300
+ access_level?: "read" | "write";
301
+ parent_id?: string;
302
+ }
303
+ type SlackViewType = "home" | "modal";
304
+ interface SlackView extends Entity {
305
+ view_id: string;
306
+ team_id: string;
307
+ user_id: string;
308
+ type: SlackViewType;
309
+ blocks: SlackJsonObject[];
310
+ private_metadata: string;
311
+ callback_id: string;
312
+ external_id: string;
313
+ title: SlackJsonObject | null;
314
+ submit: SlackJsonObject | null;
315
+ close: SlackJsonObject | null;
316
+ state: SlackJsonObject;
317
+ hash: string;
318
+ clear_on_close: boolean;
319
+ notify_on_close: boolean;
320
+ root_view_id: string;
321
+ previous_view_id?: string;
322
+ app_id: string;
323
+ bot_id: string;
324
+ created: number;
325
+ updated: number;
326
+ }
327
+ interface SlackViewTrigger extends Entity {
328
+ trigger_id: string;
329
+ team_id: string;
330
+ user_id: string;
331
+ app_id: string;
332
+ expires_at: number;
333
+ used: boolean;
334
+ view_id?: string;
335
+ }
84
336
 
85
337
  interface SlackStore {
86
338
  teams: Collection<SlackTeam>;
87
339
  users: Collection<SlackUser>;
88
340
  channels: Collection<SlackChannel>;
89
341
  messages: Collection<SlackMessage>;
342
+ ephemeralMessages: Collection<SlackEphemeralMessage>;
343
+ scheduledMessages: Collection<SlackScheduledMessage>;
90
344
  bots: Collection<SlackBot>;
91
345
  oauthApps: Collection<SlackOAuthApp>;
346
+ installations: Collection<SlackInstallation>;
347
+ tokens: Collection<SlackToken>;
92
348
  incomingWebhooks: Collection<SlackIncomingWebhook>;
349
+ files: Collection<SlackFile>;
350
+ fileUploadSessions: Collection<SlackFileUploadSession>;
351
+ pins: Collection<SlackPin>;
352
+ bookmarks: Collection<SlackBookmark>;
353
+ views: Collection<SlackView>;
354
+ viewTriggers: Collection<SlackViewTrigger>;
93
355
  }
94
356
  declare function getSlackStore(store: Store): SlackStore;
95
357
 
@@ -104,6 +366,8 @@ interface SlackSeedConfig {
104
366
  real_name?: string;
105
367
  email?: string;
106
368
  is_admin?: boolean;
369
+ profile?: Partial<SlackUserProfile>;
370
+ presence?: SlackPresence;
107
371
  }>;
108
372
  channels?: Array<{
109
373
  name: string;
@@ -115,18 +379,40 @@ interface SlackSeedConfig {
115
379
  name: string;
116
380
  }>;
117
381
  oauth_apps?: Array<{
382
+ app_id?: string;
118
383
  client_id: string;
119
384
  client_secret: string;
120
385
  name: string;
121
386
  redirect_uris: string[];
387
+ scopes?: string[] | string;
388
+ user_scopes?: string[] | string;
389
+ bot_id?: string;
390
+ bot_user_id?: string;
391
+ bot_name?: string;
392
+ }>;
393
+ tokens?: Array<{
394
+ token: string;
395
+ type?: SlackTokenType;
396
+ user?: string;
397
+ user_id?: string;
398
+ scopes?: string[] | string;
399
+ app_id?: string;
400
+ client_id?: string;
401
+ team_id?: string;
402
+ bot_id?: string;
403
+ bot_user_id?: string;
404
+ authed_user_id?: string;
122
405
  }>;
123
406
  incoming_webhooks?: Array<{
124
407
  channel: string;
125
408
  label?: string;
126
409
  }>;
410
+ strict_scopes?: boolean;
127
411
  signing_secret?: string;
128
412
  }
129
413
  declare function seedFromConfig(store: Store, _baseUrl: string, config: SlackSeedConfig): void;
130
414
  declare const slackPlugin: ServicePlugin;
131
415
 
132
- export { type SlackBot, type SlackChannel, type SlackIncomingWebhook, type SlackMessage, type SlackOAuthApp, type SlackSeedConfig, type SlackStore, type SlackTeam, type SlackUser, slackPlugin as default, getSlackStore, seedFromConfig, slackPlugin };
416
+ declare function normalizeScopes(value: string[] | string | undefined, fallback?: string[]): string[];
417
+
418
+ export { type SlackBookmark, type SlackBot, type SlackChannel, type SlackEphemeralMessage, type SlackFile, type SlackFileShare, type SlackFileUploadSession, type SlackIncomingWebhook, type SlackInstallation, type SlackJsonObject, type SlackManualPresence, type SlackMessage, type SlackOAuthApp, type SlackPin, type SlackPresence, type SlackScheduledMessage, type SlackSeedConfig, type SlackStore, type SlackTeam, type SlackToken, type SlackTokenType, type SlackUser, type SlackUserProfile, type SlackView, type SlackViewTrigger, type SlackViewType, slackPlugin as default, getSlackStore, normalizeScopes, seedFromConfig, slackPlugin };