Skip to content

Commit 1c23db3

Browse files
authored
Add Slack membership and DM writes (#157)
* Add Slack membership and DM writes - Implement invite, kick, open, close, mark, and conversation type filtering. - Model IM and MPIM conversations and support DM posting by user ID. - Cover routes, Slack SDK calls, events, docs, and coverage matrix. * Address Slack DM review findings * Fix Slack direct conversation visibility * Fix Slack direct conversation write guards * Fix Slack private conversation guards * Fix Slack membership review issues * Fix Slack scheduled and legacy membership guards * Fix Slack skill DM examples * Fix Slack reaction access guards * Fix Slack DM events and leave guards
1 parent a815676 commit 1c23db3

14 files changed

Lines changed: 1863 additions & 56 deletions

File tree

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -598,11 +598,11 @@ OAuth 2.0, OpenID Connect, and mutable Google Workspace-style surfaces for local
598598

599599
## Slack API
600600

601-
Fully stateful Slack Web API emulation with channels, messages, threads, reactions, 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 lifecycle writes update archive state, names, topics, and purposes.
601+
Fully stateful Slack Web API emulation with channels, messages, threads, reactions, 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.
602602

603603
### Auth & Chat
604604
- `POST /api/auth.test` - test authentication
605-
- `POST /api/chat.postMessage` - post message with text or rich payload fields (supports threads via `thread_ts`)
605+
- `POST /api/chat.postMessage` - post message with text or rich payload fields (supports threads via `thread_ts` and DM user IDs)
606606
- `POST /api/chat.postEphemeral` - post ephemeral message outside channel history
607607
- `POST /api/chat.update` - update message text and rich payload fields
608608
- `POST /api/chat.delete` - delete message
@@ -613,7 +613,7 @@ Fully stateful Slack Web API emulation with channels, messages, threads, reactio
613613
- `POST /api/chat.meMessage` - /me message
614614

615615
### Conversations
616-
- `POST /api/conversations.list` - list channels (cursor pagination)
616+
- `POST /api/conversations.list` - list conversations (cursor pagination, `types`, `exclude_archived`)
617617
- `POST /api/conversations.info` - get channel info
618618
- `POST /api/conversations.create` - create channel
619619
- `POST /api/conversations.archive` / `conversations.unarchive` - archive/restore channel
@@ -622,6 +622,9 @@ Fully stateful Slack Web API emulation with channels, messages, threads, reactio
622622
- `POST /api/conversations.history` - channel history with rich message fields
623623
- `POST /api/conversations.replies` - thread replies with rich message fields
624624
- `POST /api/conversations.join` / `conversations.leave` - join/leave
625+
- `POST /api/conversations.invite` / `conversations.kick` - manage membership
626+
- `POST /api/conversations.open` / `conversations.close` - open/close DMs and MPIMs
627+
- `POST /api/conversations.mark` - mark read cursor
625628
- `POST /api/conversations.members` - list members
626629

627630
### Users & Reactions

apps/web/app/docs/slack/page.mdx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# Slack API
22

3-
Fully stateful Slack Web API emulation with channels, messages, threads, reactions, 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 lifecycle writes update archive state, names, topics, and purposes. State changes dispatch `event_callback` payloads to configured webhook URLs.
3+
Fully stateful Slack Web API emulation with channels, messages, threads, reactions, 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. State changes dispatch `event_callback` payloads to configured webhook URLs.
44

55
## Auth
66

77
- `POST /api/auth.test` - test authentication
88

99
## Chat
1010

11-
- `POST /api/chat.postMessage` - post message with text or rich payload fields (supports threads via `thread_ts`)
11+
- `POST /api/chat.postMessage` - post message with text or rich payload fields (supports threads via `thread_ts` and DM user IDs)
1212
- `POST /api/chat.postEphemeral` - post ephemeral message outside channel history
1313
- `POST /api/chat.update` - update message text and rich payload fields
1414
- `POST /api/chat.delete` - delete message
@@ -20,7 +20,7 @@ Fully stateful Slack Web API emulation with channels, messages, threads, reactio
2020

2121
## Conversations
2222

23-
- `POST /api/conversations.list` - list channels (cursor pagination)
23+
- `POST /api/conversations.list` - list conversations (cursor pagination, `types`, `exclude_archived`)
2424
- `POST /api/conversations.info` - get channel info
2525
- `POST /api/conversations.create` - create channel
2626
- `POST /api/conversations.archive` - archive channel
@@ -32,6 +32,11 @@ Fully stateful Slack Web API emulation with channels, messages, threads, reactio
3232
- `POST /api/conversations.replies` - thread replies with rich message fields
3333
- `POST /api/conversations.join` - join channel
3434
- `POST /api/conversations.leave` - leave channel
35+
- `POST /api/conversations.invite` - invite user to a channel
36+
- `POST /api/conversations.kick` - remove user from a channel
37+
- `POST /api/conversations.open` - open or resume DM/MPIM
38+
- `POST /api/conversations.close` - close DM/MPIM
39+
- `POST /api/conversations.mark` - set read cursor
3540
- `POST /api/conversations.members` - list members
3641

3742
## Users
@@ -77,3 +82,5 @@ When messages are posted, updated, deleted, or reactions change, the emulator di
7782
- `group_archive` / `group_unarchive` for private lifecycle archive writes
7883
- `channel_rename` / `group_rename` and matching name message subtypes on `conversations.rename`
7984
- `message` with public `channel_topic` / `channel_purpose` or private `group_topic` / `group_purpose` subtypes on topic and purpose writes
85+
- `member_joined_channel` / `member_left_channel` on invite, join, leave, and kick writes
86+
- `im_created`, `im_open`, `im_close`, `im_marked`, and group open/close/marked events for DM and MPIM writes

packages/@emulators/slack/README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# @emulators/slack
22

3-
Fully stateful Slack Web API emulation with channels, messages, threads, reactions, 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 lifecycle writes update archive state, names, topics, and purposes.
3+
Fully stateful Slack Web API emulation with channels, messages, threads, reactions, 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.
44

55
Part of [emulate](https://github.com/vercel-labs/emulate) — local drop-in replacement services for CI and no-network sandboxes.
66

@@ -14,7 +14,7 @@ npm install @emulators/slack
1414

1515
### Auth & Chat
1616
- `POST /api/auth.test` — test authentication
17-
- `POST /api/chat.postMessage` — post message with text or rich payload fields (supports threads via `thread_ts`)
17+
- `POST /api/chat.postMessage` — post message with text or rich payload fields (supports threads via `thread_ts` and DM user IDs)
1818
- `POST /api/chat.postEphemeral` — post ephemeral message outside channel history
1919
- `POST /api/chat.update` — update message text and rich payload fields
2020
- `POST /api/chat.delete` — delete message
@@ -25,7 +25,7 @@ npm install @emulators/slack
2525
- `POST /api/chat.meMessage` — /me message
2626

2727
### Conversations
28-
- `POST /api/conversations.list` — list channels (cursor pagination)
28+
- `POST /api/conversations.list` — list conversations (cursor pagination, `types`, `exclude_archived`)
2929
- `POST /api/conversations.info` — get channel info
3030
- `POST /api/conversations.create` — create channel
3131
- `POST /api/conversations.archive` / `conversations.unarchive` — archive/restore channel
@@ -34,6 +34,9 @@ npm install @emulators/slack
3434
- `POST /api/conversations.history` — channel history with rich message fields
3535
- `POST /api/conversations.replies` — thread replies with rich message fields
3636
- `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
3740
- `POST /api/conversations.members` — list members
3841

3942
### Users & Reactions

packages/@emulators/slack/src/__tests__/slack-coverage.ts

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const slackCoverageMatrix: SlackCoverageEntry[] = [
2525
status: "partial",
2626
testedBy: ["slack.test.ts", "slack-sdk.test.ts", "slack-events.test.ts"],
2727
notes:
28-
"Text, thread replies, blocks, attachments, metadata, formatting flags, unfurl flags, and client message ids round trip. DMs and membership checks are future work.",
28+
"Text, thread replies, blocks, attachments, metadata, formatting flags, unfurl flags, client message ids, and DM user id posting round trip. Full membership checks are future work.",
2929
},
3030
{
3131
family: "chat",
@@ -97,7 +97,8 @@ export const slackCoverageMatrix: SlackCoverageEntry[] = [
9797
route: "POST /api/conversations.list",
9898
status: "partial",
9999
testedBy: ["slack.test.ts", "slack-sdk.test.ts"],
100-
notes: "Lists channels with simple cursor pagination and supports exclude_archived. Type filtering is future work.",
100+
notes:
101+
"Lists conversations with simple cursor pagination, exclude_archived, and basic public/private/IM/MPIM type filtering.",
101102
},
102103
{
103104
family: "conversations",
@@ -200,6 +201,47 @@ export const slackCoverageMatrix: SlackCoverageEntry[] = [
200201
testedBy: ["slack.test.ts", "slack-sdk.test.ts"],
201202
notes: "Returns channel member ids with empty next cursor.",
202203
},
204+
{
205+
family: "conversations",
206+
method: "conversations.invite",
207+
route: "POST /api/conversations.invite",
208+
status: "partial",
209+
testedBy: ["slack.test.ts", "slack-sdk.test.ts", "slack-events.test.ts"],
210+
notes:
211+
"Adds users to public/private channels and MPIMs, with basic membership errors and member_joined_channel events.",
212+
},
213+
{
214+
family: "conversations",
215+
method: "conversations.kick",
216+
route: "POST /api/conversations.kick",
217+
status: "partial",
218+
testedBy: ["slack.test.ts", "slack-sdk.test.ts", "slack-events.test.ts"],
219+
notes: "Removes users from public/private channels and MPIMs, with basic errors and member_left_channel events.",
220+
},
221+
{
222+
family: "conversations",
223+
method: "conversations.open",
224+
route: "POST /api/conversations.open",
225+
status: "partial",
226+
testedBy: ["slack.test.ts", "slack-sdk.test.ts", "slack-events.test.ts"],
227+
notes: "Opens or resumes IM and MPIM conversations by user list or existing conversation id.",
228+
},
229+
{
230+
family: "conversations",
231+
method: "conversations.close",
232+
route: "POST /api/conversations.close",
233+
status: "partial",
234+
testedBy: ["slack.test.ts", "slack-sdk.test.ts", "slack-events.test.ts"],
235+
notes: "Closes IM and MPIM conversations and reports already_closed no-op responses.",
236+
},
237+
{
238+
family: "conversations",
239+
method: "conversations.mark",
240+
route: "POST /api/conversations.mark",
241+
status: "partial",
242+
testedBy: ["slack.test.ts", "slack-sdk.test.ts", "slack-events.test.ts"],
243+
notes: "Stores per-user read cursors for conversations and dispatches marked events.",
244+
},
203245
{
204246
family: "users",
205247
method: "users.list",

0 commit comments

Comments
 (0)