@betternotify/slack 1.0.0-beta.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/LICENSE +21 -0
- package/README.md +93 -0
- package/dist/index.d.ts +319 -0
- package/dist/index.js +3630 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Better-Notify contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# @betternotify/slack
|
|
2
|
+
|
|
3
|
+
Slack channel for [Better-Notify](https://github.com/better-notify/better-notify). Provides `slackChannel()`, a `mockSlackTransport` for tests, and a `slackTransport` that posts to Slack via incoming webhooks or the Web API.
|
|
4
|
+
|
|
5
|
+
<p>
|
|
6
|
+
<a href="https://better-notify.com">Website</a> ·
|
|
7
|
+
<a href="https://better-notify.com/docs">Docs</a> ·
|
|
8
|
+
<a href="https://github.com/better-notify/better-notify">GitHub</a> ·
|
|
9
|
+
<a href="https://x.com/better_notify">X</a>
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
npm install @betternotify/slack @betternotify/core
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { createNotify, createClient } from '@betternotify/core';
|
|
22
|
+
import { slackChannel, mockSlackTransport } from '@betternotify/slack';
|
|
23
|
+
import { z } from 'zod';
|
|
24
|
+
|
|
25
|
+
const slack = slackChannel();
|
|
26
|
+
const rpc = createNotify({ channels: { slack } });
|
|
27
|
+
|
|
28
|
+
const catalog = rpc.catalog({
|
|
29
|
+
deployAlert: rpc
|
|
30
|
+
.slack()
|
|
31
|
+
.input(z.object({ service: z.string(), version: z.string() }))
|
|
32
|
+
.text(({ input }) => `*${input.service}* deployed v${input.version}`)
|
|
33
|
+
.blocks(({ input }) => [
|
|
34
|
+
{ type: 'header', text: { type: 'plain_text', text: 'Deployment' } },
|
|
35
|
+
{
|
|
36
|
+
type: 'section',
|
|
37
|
+
fields: [
|
|
38
|
+
{ type: 'mrkdwn', text: `*Service:* ${input.service}` },
|
|
39
|
+
{ type: 'mrkdwn', text: `*Version:* ${input.version}` },
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
]),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const notify = createClient({
|
|
46
|
+
catalog,
|
|
47
|
+
channels: { slack },
|
|
48
|
+
transportsByChannel: { slack: mockSlackTransport() },
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
await notify.deployAlert.send({
|
|
52
|
+
to: 'https://hooks.slack.com/services/...',
|
|
53
|
+
input: { service: 'api', version: '2.1.0' },
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Builder slots
|
|
58
|
+
|
|
59
|
+
| Slot | Required | Type |
|
|
60
|
+
| -------- | -------- | ------------------------------------------- |
|
|
61
|
+
| `text` | yes | `string \| ({input}) => string` |
|
|
62
|
+
| `blocks` | no | `SlackBlock[] \| ({input}) => SlackBlock[]` |
|
|
63
|
+
| `file` | no | `SlackFile \| ({input}) => SlackFile` |
|
|
64
|
+
|
|
65
|
+
Plus `.input(schema)` and `.use(mw)`.
|
|
66
|
+
|
|
67
|
+
## Send args
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
notify.deployAlert.send({
|
|
71
|
+
to: string, // Slack webhook URL or channel ID
|
|
72
|
+
input: TInput,
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Transports
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { slackTransport, mockSlackTransport } from '@betternotify/slack';
|
|
80
|
+
|
|
81
|
+
const transport = slackTransport({
|
|
82
|
+
botToken: process.env.SLACK_BOT_TOKEN!,
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- `mockSlackTransport()` — records sent messages for tests.
|
|
87
|
+
- `slackTransport({ botToken })` — sends via Slack Web API / incoming webhooks.
|
|
88
|
+
|
|
89
|
+
Custom transport contract: `Transport<RenderedSlack, SlackTransportData>`.
|
|
90
|
+
|
|
91
|
+
## License
|
|
92
|
+
|
|
93
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import * as _betternotify_core0 from "@betternotify/core";
|
|
2
|
+
import { LoggerLike, Transport as Transport$1 } from "@betternotify/core";
|
|
3
|
+
import { HttpClientBehaviorOptions, MockTransport } from "@betternotify/core/transports";
|
|
4
|
+
|
|
5
|
+
//#region src/types.d.ts
|
|
6
|
+
type SlackPlainText = {
|
|
7
|
+
type: 'plain_text';
|
|
8
|
+
text: string;
|
|
9
|
+
emoji?: boolean;
|
|
10
|
+
};
|
|
11
|
+
type SlackMrkdwn = {
|
|
12
|
+
type: 'mrkdwn';
|
|
13
|
+
text: string;
|
|
14
|
+
verbatim?: boolean;
|
|
15
|
+
};
|
|
16
|
+
type SlackText = SlackPlainText | SlackMrkdwn;
|
|
17
|
+
type SlackOption = {
|
|
18
|
+
text: SlackText;
|
|
19
|
+
value: string;
|
|
20
|
+
description?: SlackPlainText;
|
|
21
|
+
};
|
|
22
|
+
type SlackOptionGroup = {
|
|
23
|
+
label: SlackPlainText;
|
|
24
|
+
options: SlackOption[];
|
|
25
|
+
};
|
|
26
|
+
type SlackConfirmDialog = {
|
|
27
|
+
title: SlackPlainText;
|
|
28
|
+
text: SlackText;
|
|
29
|
+
confirm: SlackPlainText;
|
|
30
|
+
deny: SlackPlainText;
|
|
31
|
+
style?: 'primary' | 'danger';
|
|
32
|
+
};
|
|
33
|
+
type SlackButtonElement = {
|
|
34
|
+
type: 'button';
|
|
35
|
+
text: SlackPlainText;
|
|
36
|
+
action_id: string;
|
|
37
|
+
url?: string;
|
|
38
|
+
value?: string;
|
|
39
|
+
style?: 'primary' | 'danger';
|
|
40
|
+
confirm?: SlackConfirmDialog;
|
|
41
|
+
};
|
|
42
|
+
type SlackImageElement = {
|
|
43
|
+
type: 'image';
|
|
44
|
+
image_url: string;
|
|
45
|
+
alt_text: string;
|
|
46
|
+
};
|
|
47
|
+
type SlackOverflowElement = {
|
|
48
|
+
type: 'overflow';
|
|
49
|
+
action_id: string;
|
|
50
|
+
options: SlackOption[];
|
|
51
|
+
confirm?: SlackConfirmDialog;
|
|
52
|
+
};
|
|
53
|
+
type SlackDatepickerElement = {
|
|
54
|
+
type: 'datepicker';
|
|
55
|
+
action_id: string;
|
|
56
|
+
placeholder?: SlackPlainText;
|
|
57
|
+
initial_date?: string;
|
|
58
|
+
confirm?: SlackConfirmDialog;
|
|
59
|
+
};
|
|
60
|
+
type SlackTimepickerElement = {
|
|
61
|
+
type: 'timepicker';
|
|
62
|
+
action_id: string;
|
|
63
|
+
placeholder?: SlackPlainText;
|
|
64
|
+
initial_time?: string;
|
|
65
|
+
confirm?: SlackConfirmDialog;
|
|
66
|
+
};
|
|
67
|
+
type SlackStaticSelectElement = {
|
|
68
|
+
type: 'static_select';
|
|
69
|
+
action_id: string;
|
|
70
|
+
placeholder?: SlackPlainText;
|
|
71
|
+
options: SlackOption[];
|
|
72
|
+
option_groups?: SlackOptionGroup[];
|
|
73
|
+
initial_option?: SlackOption;
|
|
74
|
+
confirm?: SlackConfirmDialog;
|
|
75
|
+
};
|
|
76
|
+
type SlackMultiStaticSelectElement = {
|
|
77
|
+
type: 'multi_static_select';
|
|
78
|
+
action_id: string;
|
|
79
|
+
placeholder?: SlackPlainText;
|
|
80
|
+
options: SlackOption[];
|
|
81
|
+
option_groups?: SlackOptionGroup[];
|
|
82
|
+
initial_options?: SlackOption[];
|
|
83
|
+
max_selected_items?: number;
|
|
84
|
+
confirm?: SlackConfirmDialog;
|
|
85
|
+
};
|
|
86
|
+
type SlackCheckboxesElement = {
|
|
87
|
+
type: 'checkboxes';
|
|
88
|
+
action_id: string;
|
|
89
|
+
options: SlackOption[];
|
|
90
|
+
initial_options?: SlackOption[];
|
|
91
|
+
confirm?: SlackConfirmDialog;
|
|
92
|
+
};
|
|
93
|
+
type SlackRadioButtonsElement = {
|
|
94
|
+
type: 'radio_buttons';
|
|
95
|
+
action_id: string;
|
|
96
|
+
options: SlackOption[];
|
|
97
|
+
initial_option?: SlackOption;
|
|
98
|
+
confirm?: SlackConfirmDialog;
|
|
99
|
+
};
|
|
100
|
+
type SlackPlainTextInputElement = {
|
|
101
|
+
type: 'plain_text_input';
|
|
102
|
+
action_id: string;
|
|
103
|
+
placeholder?: SlackPlainText;
|
|
104
|
+
initial_value?: string;
|
|
105
|
+
multiline?: boolean;
|
|
106
|
+
min_length?: number;
|
|
107
|
+
max_length?: number;
|
|
108
|
+
};
|
|
109
|
+
type SlackNumberInputElement = {
|
|
110
|
+
type: 'number_input';
|
|
111
|
+
action_id: string;
|
|
112
|
+
is_decimal_allowed: boolean;
|
|
113
|
+
placeholder?: SlackPlainText;
|
|
114
|
+
initial_value?: string;
|
|
115
|
+
min_value?: string;
|
|
116
|
+
max_value?: string;
|
|
117
|
+
};
|
|
118
|
+
type SlackUrlInputElement = {
|
|
119
|
+
type: 'url_text_input';
|
|
120
|
+
action_id: string;
|
|
121
|
+
placeholder?: SlackPlainText;
|
|
122
|
+
initial_value?: string;
|
|
123
|
+
};
|
|
124
|
+
type SlackEmailInputElement = {
|
|
125
|
+
type: 'email_text_input';
|
|
126
|
+
action_id: string;
|
|
127
|
+
placeholder?: SlackPlainText;
|
|
128
|
+
initial_value?: string;
|
|
129
|
+
};
|
|
130
|
+
type SlackRichTextInputElement = {
|
|
131
|
+
type: 'rich_text_input';
|
|
132
|
+
action_id: string;
|
|
133
|
+
placeholder?: SlackPlainText;
|
|
134
|
+
initial_value?: Record<string, unknown>;
|
|
135
|
+
};
|
|
136
|
+
type SlackInteractiveElement = SlackButtonElement | SlackOverflowElement | SlackDatepickerElement | SlackTimepickerElement | SlackStaticSelectElement | SlackMultiStaticSelectElement | SlackCheckboxesElement | SlackRadioButtonsElement;
|
|
137
|
+
type SlackInputElement = SlackPlainTextInputElement | SlackNumberInputElement | SlackUrlInputElement | SlackEmailInputElement | SlackRichTextInputElement | SlackStaticSelectElement | SlackMultiStaticSelectElement | SlackCheckboxesElement | SlackRadioButtonsElement | SlackDatepickerElement | SlackTimepickerElement;
|
|
138
|
+
type SlackAccessoryElement = SlackInteractiveElement | SlackImageElement;
|
|
139
|
+
type SlackHeaderBlock = {
|
|
140
|
+
type: 'header';
|
|
141
|
+
text: SlackPlainText;
|
|
142
|
+
block_id?: string;
|
|
143
|
+
};
|
|
144
|
+
type SlackSectionBlock = {
|
|
145
|
+
type: 'section';
|
|
146
|
+
text?: SlackText;
|
|
147
|
+
fields?: SlackText[];
|
|
148
|
+
accessory?: SlackAccessoryElement;
|
|
149
|
+
expand?: boolean;
|
|
150
|
+
block_id?: string;
|
|
151
|
+
};
|
|
152
|
+
type SlackImageBlock = {
|
|
153
|
+
type: 'image';
|
|
154
|
+
image_url: string;
|
|
155
|
+
alt_text: string;
|
|
156
|
+
title?: SlackPlainText;
|
|
157
|
+
block_id?: string;
|
|
158
|
+
};
|
|
159
|
+
type SlackVideoBlock = {
|
|
160
|
+
type: 'video';
|
|
161
|
+
alt_text: string;
|
|
162
|
+
title: SlackPlainText;
|
|
163
|
+
thumbnail_url: string;
|
|
164
|
+
video_url: string;
|
|
165
|
+
description?: SlackPlainText;
|
|
166
|
+
title_url?: string;
|
|
167
|
+
author_name?: string;
|
|
168
|
+
provider_name?: string;
|
|
169
|
+
provider_icon_url?: string;
|
|
170
|
+
block_id?: string;
|
|
171
|
+
};
|
|
172
|
+
type SlackDividerBlock = {
|
|
173
|
+
type: 'divider';
|
|
174
|
+
block_id?: string;
|
|
175
|
+
};
|
|
176
|
+
type SlackActionsBlock = {
|
|
177
|
+
type: 'actions';
|
|
178
|
+
elements: SlackInteractiveElement[];
|
|
179
|
+
block_id?: string;
|
|
180
|
+
};
|
|
181
|
+
type SlackContextBlock = {
|
|
182
|
+
type: 'context';
|
|
183
|
+
elements: (SlackText | SlackImageElement)[];
|
|
184
|
+
block_id?: string;
|
|
185
|
+
};
|
|
186
|
+
type SlackInputBlock = {
|
|
187
|
+
type: 'input';
|
|
188
|
+
label: SlackPlainText;
|
|
189
|
+
element: SlackInputElement;
|
|
190
|
+
hint?: SlackPlainText;
|
|
191
|
+
optional?: boolean;
|
|
192
|
+
dispatch_action?: boolean;
|
|
193
|
+
block_id?: string;
|
|
194
|
+
};
|
|
195
|
+
type SlackFileBlock = {
|
|
196
|
+
type: 'file';
|
|
197
|
+
external_id: string;
|
|
198
|
+
source: 'remote';
|
|
199
|
+
block_id?: string;
|
|
200
|
+
};
|
|
201
|
+
type SlackRichTextBlock = {
|
|
202
|
+
type: 'rich_text';
|
|
203
|
+
elements: Record<string, unknown>[];
|
|
204
|
+
block_id?: string;
|
|
205
|
+
};
|
|
206
|
+
type SlackBlock = SlackHeaderBlock | SlackSectionBlock | SlackImageBlock | SlackVideoBlock | SlackDividerBlock | SlackActionsBlock | SlackContextBlock | SlackInputBlock | SlackFileBlock | SlackRichTextBlock;
|
|
207
|
+
type SlackFile = {
|
|
208
|
+
data: Buffer | Uint8Array;
|
|
209
|
+
filename: string;
|
|
210
|
+
title?: string;
|
|
211
|
+
altText?: string;
|
|
212
|
+
};
|
|
213
|
+
type SlackSendArgs<TInput = unknown> = {
|
|
214
|
+
to?: string;
|
|
215
|
+
threadTs?: string;
|
|
216
|
+
input: TInput;
|
|
217
|
+
};
|
|
218
|
+
type RenderedSlack = {
|
|
219
|
+
text: string;
|
|
220
|
+
to?: string;
|
|
221
|
+
blocks?: SlackBlock[];
|
|
222
|
+
threadTs?: string;
|
|
223
|
+
file?: SlackFile;
|
|
224
|
+
};
|
|
225
|
+
//#endregion
|
|
226
|
+
//#region src/channel.d.ts
|
|
227
|
+
type TextResolver<TInput> = string | ((args: {
|
|
228
|
+
input: TInput;
|
|
229
|
+
ctx: unknown;
|
|
230
|
+
}) => string);
|
|
231
|
+
type BlocksResolver<TInput> = SlackBlock[] | ((args: {
|
|
232
|
+
input: TInput;
|
|
233
|
+
ctx: unknown;
|
|
234
|
+
}) => SlackBlock[]);
|
|
235
|
+
type FileResolver<TInput> = SlackFile | ((args: {
|
|
236
|
+
input: TInput;
|
|
237
|
+
ctx: unknown;
|
|
238
|
+
}) => SlackFile);
|
|
239
|
+
/**
|
|
240
|
+
* Slack notification channel.
|
|
241
|
+
*
|
|
242
|
+
* Slots:
|
|
243
|
+
* - `.text()` — Required fallback string. Shown in push notifications,
|
|
244
|
+
* desktop alerts, and screen readers. Always sent even when blocks are present.
|
|
245
|
+
* - `.blocks()` — Optional rich layout (sections, headers, images, actions).
|
|
246
|
+
* This is what renders in the Slack client UI. Falls back to `text` if blocks
|
|
247
|
+
* cannot render.
|
|
248
|
+
* - `.file()` — Optional file attachment uploaded alongside the message.
|
|
249
|
+
*/
|
|
250
|
+
declare const slackChannel: () => _betternotify_core0.Channel<"slack", _betternotify_core0.ChannelBuilder<unknown, {
|
|
251
|
+
text: string;
|
|
252
|
+
blocks: SlackBlock[];
|
|
253
|
+
file: SlackFile;
|
|
254
|
+
}, {
|
|
255
|
+
/** Required fallback text for notifications, alerts, and accessibility. */
|
|
256
|
+
text: _betternotify_core0.SlotConfig<"resolver"> & {
|
|
257
|
+
required: true;
|
|
258
|
+
__value?: string | undefined;
|
|
259
|
+
optional: () => _betternotify_core0.SlotConfig<"resolver"> & {
|
|
260
|
+
required: false;
|
|
261
|
+
__value?: string | undefined;
|
|
262
|
+
optional: /*elided*/any;
|
|
263
|
+
};
|
|
264
|
+
};
|
|
265
|
+
/** Rich Block Kit layout rendered in the Slack client; falls back to `text`. */
|
|
266
|
+
blocks: _betternotify_core0.SlotConfig<"resolver"> & {
|
|
267
|
+
required: false;
|
|
268
|
+
__value?: SlackBlock[] | undefined;
|
|
269
|
+
optional: () => _betternotify_core0.SlotConfig<"resolver"> & /*elided*/any;
|
|
270
|
+
};
|
|
271
|
+
/** File attachment uploaded with the message. */
|
|
272
|
+
file: _betternotify_core0.SlotConfig<"resolver"> & {
|
|
273
|
+
required: false;
|
|
274
|
+
__value?: SlackFile | undefined;
|
|
275
|
+
optional: () => _betternotify_core0.SlotConfig<"resolver"> & /*elided*/any;
|
|
276
|
+
};
|
|
277
|
+
}, Omit<{
|
|
278
|
+
input: unknown;
|
|
279
|
+
to?: string | undefined;
|
|
280
|
+
threadTs?: string | undefined;
|
|
281
|
+
}, "input">, RenderedSlack>, {
|
|
282
|
+
input: unknown;
|
|
283
|
+
to?: string | undefined;
|
|
284
|
+
threadTs?: string | undefined;
|
|
285
|
+
}, RenderedSlack, _betternotify_core0.Transport<RenderedSlack, unknown>>;
|
|
286
|
+
//#endregion
|
|
287
|
+
//#region src/is-retriable.d.ts
|
|
288
|
+
declare const isSlackRetriable: (err: unknown) => boolean;
|
|
289
|
+
//#endregion
|
|
290
|
+
//#region src/transports/types.d.ts
|
|
291
|
+
type SlackTransportData = {
|
|
292
|
+
ts: string;
|
|
293
|
+
channel: string;
|
|
294
|
+
};
|
|
295
|
+
type SlackTransportResult = SlackTransportData;
|
|
296
|
+
type Transport = Transport$1<RenderedSlack, SlackTransportData>;
|
|
297
|
+
//#endregion
|
|
298
|
+
//#region src/transports/mock.d.ts
|
|
299
|
+
type MockSlackTransport = MockTransport<RenderedSlack, SlackTransportData> & {
|
|
300
|
+
readonly messages: ReadonlyArray<RenderedSlack & {
|
|
301
|
+
id: string;
|
|
302
|
+
}>;
|
|
303
|
+
};
|
|
304
|
+
declare const mockSlackTransport: () => MockSlackTransport;
|
|
305
|
+
//#endregion
|
|
306
|
+
//#region src/transports/slack.types.d.ts
|
|
307
|
+
/** Configuration options for the Slack transport. */
|
|
308
|
+
type SlackTransportOptions = {
|
|
309
|
+
token: string;
|
|
310
|
+
defaultChannel?: string;
|
|
311
|
+
baseUrl?: string;
|
|
312
|
+
logger?: LoggerLike;
|
|
313
|
+
http?: HttpClientBehaviorOptions;
|
|
314
|
+
};
|
|
315
|
+
//#endregion
|
|
316
|
+
//#region src/transports/slack.d.ts
|
|
317
|
+
declare const slackTransport: (opts: SlackTransportOptions) => Transport;
|
|
318
|
+
//#endregion
|
|
319
|
+
export { type BlocksResolver, type FileResolver, type MockSlackTransport, type RenderedSlack, type SlackAccessoryElement, type SlackActionsBlock, type SlackBlock, type SlackButtonElement, type SlackCheckboxesElement, type SlackConfirmDialog, type SlackContextBlock, type SlackDatepickerElement, type SlackDividerBlock, type SlackEmailInputElement, type SlackFile, type SlackFileBlock, type SlackHeaderBlock, type SlackImageBlock, type SlackImageElement, type SlackInputBlock, type SlackInputElement, type SlackInteractiveElement, type SlackMrkdwn, type SlackMultiStaticSelectElement, type SlackNumberInputElement, type SlackOption, type SlackOptionGroup, type SlackOverflowElement, type SlackPlainText, type SlackPlainTextInputElement, type SlackRadioButtonsElement, type SlackRichTextBlock, type SlackRichTextInputElement, type SlackSectionBlock, type SlackSendArgs, type SlackStaticSelectElement, type SlackText, type SlackTimepickerElement, type SlackTransportData, type SlackTransportOptions, type SlackTransportResult, type SlackUrlInputElement, type SlackVideoBlock, type TextResolver, type Transport, isSlackRetriable, mockSlackTransport, slackChannel, slackTransport };
|