@crvouga/mockingbird-service-slack 1.5.1 → 1.6.1
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/CHANGELOG.md +18 -4
- package/README.md +24 -7
- package/dist/{chunk-OVHCSYG6.js → chunk-6NKJ75J3.js} +340 -28
- package/dist/chunk-6NKJ75J3.js.map +7 -0
- package/dist/{chunk-3NVCQXOC.js → chunk-PKYQRMRQ.js} +299 -3
- package/dist/chunk-PKYQRMRQ.js.map +7 -0
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +34 -4
- package/dist/index.js +1 -1
- package/dist/server.d.ts +41 -9
- package/dist/server.js +2 -2
- package/package.json +15 -13
- package/dist/chunk-3NVCQXOC.js.map +0 -7
- package/dist/chunk-OVHCSYG6.js.map +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
# Changelog — @crvouga/mockingbird-service-slack
|
|
2
2
|
|
|
3
|
-
## 1.
|
|
3
|
+
## 1.6.1 (2026-09-30)
|
|
4
4
|
|
|
5
5
|
### Fixes and improvements
|
|
6
6
|
|
|
7
|
-
- keep
|
|
7
|
+
- keep admin buttons pressed until the action finishes ([0aabfcb](https://github.com/crvouga/mockingbird/commit/0aabfcb5f392aa51e193f9c3f817d5877d92bc6a))
|
|
8
|
+
- size admin select fields like the text inputs beside them ([0fb3ef2](https://github.com/crvouga/mockingbird/commit/0fb3ef2ddbf43376c93a2ae6d87c6c9bf890dafc))
|
|
9
|
+
- keep admin section tabs wired when boot is renamed ([4eda25e](https://github.com/crvouga/mockingbird/commit/4eda25eacd59da048d196f7cc8369d7a02b47bfc))
|
|
10
|
+
|
|
11
|
+
## 1.6.0 (2026-09-29)
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
- boot Bolt over Socket Mode ([01322df](https://github.com/crvouga/mockingbird/commit/01322df315c66b1f2f5b53094cbbeeeef6d3ae6c))
|
|
8
16
|
|
|
9
|
-
###
|
|
17
|
+
### Fixes and improvements
|
|
10
18
|
|
|
11
|
-
-
|
|
19
|
+
- keep merged kill-bill and slack checks green ([5de12bf](https://github.com/crvouga/mockingbird/commit/5de12bf20b6b209769c632ccd4b9ec24b680a07a))
|
|
20
|
+
|
|
21
|
+
## 1.5.1 (2026-09-29)
|
|
22
|
+
|
|
23
|
+
### Fixes and improvements
|
|
24
|
+
|
|
25
|
+
- keep hosted pages inside narrow hosts and popups ([6512323](https://github.com/crvouga/mockingbird/commit/6512323198cb00b99005f3d2cfa5b9f1e6e321a7))
|
|
12
26
|
|
|
13
27
|
## 1.5.0 (2026-09-29)
|
|
14
28
|
|
package/README.md
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
> Familiar calls. Faithful echoes. Part of [Mockingbird](https://github.com/crvouga/mockingbird).
|
|
4
4
|
|
|
5
|
-
Stateful mock of **Slack** for test suites: incoming webhooks
|
|
6
|
-
call,
|
|
5
|
+
Stateful mock of **Slack** for test suites: incoming webhooks, the Web API methods our apps
|
|
6
|
+
call, and the Socket Mode control plane Bolt needs in order to boot, with an **outbox** of
|
|
7
|
+
everything the app "sent". A suite asserts that an alert fired
|
|
7
8
|
(`GET /__admin/outbox?webhook=…` or `?channel=…`) without a real workspace, and drives the
|
|
8
9
|
retry paths (429 with `retry-after`, 5xx) and the terminal ones (`no_text`, `no_service`,
|
|
9
10
|
`channel_not_found`) with named presets.
|
|
@@ -30,6 +31,9 @@ Point every `SLACK_*_WEBHOOK_URL` (`SLACK_PIPELINE_ALERT_WEBHOOK_URL`,
|
|
|
30
31
|
`http://127.0.0.1:8808/services/T000/B000/<anything>`. Any path is accepted until you register
|
|
31
32
|
hooks. The Web API callers hardcode `https://slack.com/api/…`; point them at
|
|
32
33
|
`http://127.0.0.1:8808/api/…` (for `@slack/web-api`, `slackApiUrl: "http://127.0.0.1:8808/api/"`).
|
|
34
|
+
Bolt in Socket Mode uses that same `clientOptions.slackApiUrl` (Bolt copies it into
|
|
35
|
+
`SocketModeReceiver`) plus an `xapp-` app token. `apps.connections.open` returns a `ws://` URL
|
|
36
|
+
on this process.
|
|
33
37
|
|
|
34
38
|
```bash
|
|
35
39
|
npx mockingbird-slack serve --port 8808
|
|
@@ -61,7 +65,7 @@ const outbox = await slack.fetch(
|
|
|
61
65
|
| Route | Behaviour |
|
|
62
66
|
| --- | --- |
|
|
63
67
|
| `POST /services/{T}/{B}/{X}` | Incoming webhook. JSON `{text, blocks?, attachments?, thread_ts?}` (or form `payload=<json>`) → `200 ok` (text/plain). `400 invalid_payload` (not a JSON object), `400 no_text` (no text, blocks or attachments), `400 invalid_blocks`, `400 too_many_attachments`, `404 no_service` (unregistered hook, once any hook is registered), `404 channel_not_found`, `410 channel_is_archived`. |
|
|
64
|
-
| `POST /api/chat.postMessage` | `{channel, text?, blocks?, attachments?, thread_ts?}` → `{ok, channel, ts, message}`. `channel` is an id or `#name`; unknown channels are created on first use unless `strictChannels`. Errors: `channel_not_found`, `no_text`, `invalid_blocks`, `invalid_blocks_format`, `msg_too_long`, `is_archived`. |
|
|
68
|
+
| `POST /api/chat.postMessage` | `{channel, text?, blocks?, attachments?, thread_ts?, unfurl_links?}` → `{ok, channel, ts, message}`. `channel` is an id or `#name`; unknown channels are created on first use unless `strictChannels`. The outbox keeps `text`, `blocks`, `unfurl_links`, `thread_ts`, and `workspace` (the team id). Errors: `channel_not_found`, `no_text`, `invalid_blocks`, `invalid_blocks_format`, `msg_too_long`, `is_archived`. |
|
|
65
69
|
| `POST /api/chat.update` | `{channel, ts, text?, blocks?}` → `{ok, channel, ts, text, message}` with `edited`; `message_not_found`, `cant_update_message` (webhook posts). Omitted blocks are kept. |
|
|
66
70
|
| `POST /api/chat.postEphemeral` | `{channel, user, text}` → `{ok, message_ts}`; `user_not_found`. Recorded in the outbox with `ephemeral: true`. |
|
|
67
71
|
| `GET\|POST /api/chat.getPermalink` | `channel`, `message_ts` → `{ok, channel, permalink}` (`https://<domain>.slack.com/archives/C…/p…`); `message_not_found`. |
|
|
@@ -71,6 +75,8 @@ const outbox = await slack.fetch(
|
|
|
71
75
|
| `GET\|POST /api/users.info`, `/users.lookupByEmail` | `{ok, user}` with `profile.email`/`real_name`; `user_not_found`, `users_not_found`. Seeded: `U0ADA` (`ada@example.com`) and the bot. |
|
|
72
76
|
| `GET\|POST /api/files.info` | `{ok, file}` with `url_private_download` on `files.slack.com`; `file_not_found`. Seeded: `F0REPORT`. |
|
|
73
77
|
| `POST /api/views.open` | `{trigger_id, view}` → `{ok, view: {id: "V…", hash, state, …}}`; `invalid_arguments`. |
|
|
78
|
+
| `POST /api/apps.connections.open` | `Authorization: Bearer xapp-…` (header only) → `{ok, url}` where `url` is `ws://<this host>/link/?ticket=…&app_id=…`. One WebSocket per ticket; a second upgrade or a closed ticket is rejected. Missing token → `not_authed`; a bot token → `not_allowed_token_type`; malformed → `invalid_auth`; a token in `revokedAppTokens` → `token_revoked`; an app token that is not in this namespace's `appTokens` (when that list is non-empty) → `invalid_auth`. |
|
|
79
|
+
| WebSocket `/link/?ticket=` | On upgrade, one JSON `hello` (`type`, `connection_info.app_id`, `num_connections`, `debug_info.approximate_connection_time`). No events are pushed. Client pings are ponged; the server pings every 2s. `{envelope_id}` acks are accepted and not answered. `disconnect` reasons `warning`, `refresh_requested`, and `link_disabled` match Slack's envelope (no reconnect URL: `@slack/socket-mode@2.0.4` calls `apps.connections.open` again). |
|
|
74
80
|
|
|
75
81
|
Web API bodies may be JSON or form-encoded (structures JSON-encoded in form fields), as Slack
|
|
76
82
|
accepts both; read methods also take query arguments. Auth is `Authorization: Bearer xox…` (or a
|
|
@@ -82,10 +88,12 @@ a JSON post without `charset` succeeds with Slack's `missing_charset` warning.
|
|
|
82
88
|
|
|
83
89
|
| Route | Effect |
|
|
84
90
|
| --- | --- |
|
|
85
|
-
| `GET /__admin/outbox?webhook=<path>&channel=<id\|#name>&thread_ts=&source=webhook\|api&since=&limit=` | Every message sent, oldest first: `text`, `blocks`, `attachments`, `thread_ts`, `ts`, `channel`, `webhook`, `method`, `ephemeral`, `edited`, `reactions`. `webhook` takes `/services/T/B/X`, `T/B/X` or a full URL. `GET /__admin/outbox/:id` reads one. |
|
|
91
|
+
| `GET /__admin/outbox?webhook=<path>&channel=<id\|#name>&thread_ts=&source=webhook\|api&since=&limit=` | Every message sent, oldest first: `text`, `blocks`, `attachments`, `thread_ts`, `ts`, `channel`, `webhook`, `method`, `ephemeral`, `edited`, `reactions`, `unfurl_links`, `workspace`. `webhook` takes `/services/T/B/X`, `T/B/X` or a full URL. `GET /__admin/outbox/:id` reads one. |
|
|
86
92
|
| `POST /__admin/hooks` | `{path, channel?}` or `{hooks: [...]}`: register webhooks (and route them to a channel). Once any hook exists, unknown hooks answer `404 no_service`. `GET` lists, `DELETE [?path=]` removes. |
|
|
87
93
|
| `POST /__admin/channels`, `/users`, `/files` | Seed workspace records (`{id?, name, is_private?, is_archived?, is_member?}`, `{id, name?, real_name?, email?}`, `{id, name?, mimetype?, size?}`). `GET /__admin/channels`, `/users`, `/views` list them. |
|
|
88
|
-
| `PUT /__admin/settings` | `{teamId?, teamName?, teamDomain?, botUserId?, botId?, appId?, tokens?, strictChannels?}` for the calling namespace. |
|
|
94
|
+
| `PUT /__admin/settings` | `{teamId?, teamName?, teamDomain?, botUserId?, botId?, appId?, tokens?, appTokens?, revokedAppTokens?, socketLifetimeMs?, strictChannels?}` for the calling namespace. `socketLifetimeMs` closes an open Socket Mode connection with `reason: "warning"`. |
|
|
95
|
+
| `GET /__admin/socket/connections` | Open and closed Socket Mode sockets for the calling namespace: `namespace`, `appId`, `ticket`, `connectedAt`, `state`, `reconnectCount`. Never tokens. |
|
|
96
|
+
| `POST /__admin/socket/disconnect` | `{reason?: "warning"\|"refresh_requested"\|"link_disabled", code?: 1000}`. Sends Slack's `disconnect` envelope, then closes. `code: 1006` drops the TCP connection instead. |
|
|
89
97
|
|
|
90
98
|
Fault presets (`POST /__admin/faults {"preset": "<name>", "count"?: n, "params"?: {...}}`):
|
|
91
99
|
|
|
@@ -97,6 +105,12 @@ Fault presets (`POST /__admin/faults {"preset": "<name>", "count"?: n, "params"?
|
|
|
97
105
|
| `channel_not_found` | Webhooks `404 channel_not_found`; Web API channel methods `{ok: false, error: "channel_not_found"}`. |
|
|
98
106
|
| `no_service` | Webhooks `404 no_service` (a revoked hook). |
|
|
99
107
|
| `invalid_auth` | Web API `{ok: false, error: "invalid_auth"}` (a revoked token). |
|
|
108
|
+
| `connections_open_invalid_auth` | `apps.connections.open` answers `{ok:false, error:"invalid_auth"}` and mints no ticket. |
|
|
109
|
+
| `connections_open_429` | `apps.connections.open` answers `429 {ok:false, error:"ratelimited"}` with `retry-after` (`params.retryAfter`, default 1). |
|
|
110
|
+
| `connections_open_5xx` | `apps.connections.open` answers `500 internal_error` (`params.status: 503` gives `service_unavailable`). |
|
|
111
|
+
| `socket_close_after_hello` | The next Socket Mode socket sends `hello`, then a normal close. |
|
|
112
|
+
| `socket_abnormal_close` | The next Socket Mode socket sends `hello`, then drops the connection (code 1006). |
|
|
113
|
+
| `socket_hello_latency` | Delay `hello` by `params.latencyMs` milliseconds. The HTTP response itself is not delayed. |
|
|
100
114
|
|
|
101
115
|
### Namespaces
|
|
102
116
|
|
|
@@ -106,8 +120,11 @@ maps a bot token or a webhook's `T/B/X` path to a namespace.
|
|
|
106
120
|
|
|
107
121
|
### Deliberately not modelled
|
|
108
122
|
|
|
109
|
-
-
|
|
110
|
-
|
|
123
|
+
- Inbound Events API and interactivity delivery. Socket Mode's connection lifecycle is
|
|
124
|
+
modelled (`apps.connections.open`, `hello`, ping/pong, `disconnect`) so Bolt can boot and
|
|
125
|
+
shut down; the mock does not push events on connect. A `disconnect` envelope has no
|
|
126
|
+
reconnect URL, matching Slack's documented shape and `@slack/socket-mode@2.0.4`, which
|
|
127
|
+
calls `apps.connections.open` again.
|
|
111
128
|
- File uploads and downloads: `files.info` answers seeded metadata; the `files.slack.com` URLs
|
|
112
129
|
are not served.
|
|
113
130
|
- Real per-method rate-limit tiers: 429s come only from the `rate_limited` preset.
|