@aarekaz/switchboard-slack 0.3.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/README.md +324 -0
- package/dist/index.d.ts +194 -0
- package/dist/index.js +779 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
# @aarekaz/switchboard-slack
|
|
2
|
+
|
|
3
|
+
Slack adapter for [Switchboard SDK](https://github.com/yourusername/switchboard).
|
|
4
|
+
|
|
5
|
+
Build chat bots once, deploy everywhere. This adapter enables your Switchboard bot to work seamlessly with Slack.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @aarekaz/switchboard-slack
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { createBot } from '@aarekaz/switchboard-core';
|
|
17
|
+
import '@aarekaz/switchboard-slack';
|
|
18
|
+
|
|
19
|
+
const bot = createBot({
|
|
20
|
+
platform: 'slack',
|
|
21
|
+
credentials: {
|
|
22
|
+
botToken: process.env.SLACK_BOT_TOKEN,
|
|
23
|
+
appToken: process.env.SLACK_APP_TOKEN, // For Socket Mode
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
bot.onMessage(async (message) => {
|
|
28
|
+
if (message.text.includes('hello')) {
|
|
29
|
+
await bot.reply(message, 'Hello from Slack! 👋');
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
await bot.start();
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Setup Guide
|
|
37
|
+
|
|
38
|
+
### 1. Create a Slack App
|
|
39
|
+
|
|
40
|
+
1. Go to [https://api.slack.com/apps](https://api.slack.com/apps)
|
|
41
|
+
2. Click "Create New App" → "From scratch"
|
|
42
|
+
3. Name your app and select your workspace
|
|
43
|
+
|
|
44
|
+
### 2. Configure Bot Token Scopes
|
|
45
|
+
|
|
46
|
+
In your app settings, go to **OAuth & Permissions** and add these scopes:
|
|
47
|
+
|
|
48
|
+
**Required scopes:**
|
|
49
|
+
- `chat:write` - Send messages
|
|
50
|
+
- `channels:read` - View channels
|
|
51
|
+
- `groups:read` - View private channels
|
|
52
|
+
- `im:read` - View direct messages
|
|
53
|
+
- `mpim:read` - View group direct messages
|
|
54
|
+
- `users:read` - View users
|
|
55
|
+
|
|
56
|
+
**Optional scopes (for additional features):**
|
|
57
|
+
- `chat:write.customize` - Customize message appearance
|
|
58
|
+
- `reactions:write` - Add reactions
|
|
59
|
+
- `files:write` - Upload files
|
|
60
|
+
- `channels:history` - Read channel messages
|
|
61
|
+
- `groups:history` - Read private channel messages
|
|
62
|
+
- `im:history` - Read DM messages
|
|
63
|
+
|
|
64
|
+
### 3. Install App to Workspace
|
|
65
|
+
|
|
66
|
+
1. In **OAuth & Permissions**, click "Install to Workspace"
|
|
67
|
+
2. Copy the **Bot User OAuth Token** (starts with `xoxb-`)
|
|
68
|
+
3. Save it as `SLACK_BOT_TOKEN`
|
|
69
|
+
|
|
70
|
+
### 4. Enable Socket Mode (Recommended for Development)
|
|
71
|
+
|
|
72
|
+
1. Go to **Socket Mode** in your app settings
|
|
73
|
+
2. Enable Socket Mode
|
|
74
|
+
3. Generate an app-level token with `connections:write` scope
|
|
75
|
+
4. Copy the token (starts with `xapp-`)
|
|
76
|
+
5. Save it as `SLACK_APP_TOKEN`
|
|
77
|
+
|
|
78
|
+
> **Note:** Socket Mode is great for development but for production, consider using the Events API instead.
|
|
79
|
+
|
|
80
|
+
### 5. Subscribe to Events
|
|
81
|
+
|
|
82
|
+
1. Go to **Event Subscriptions**
|
|
83
|
+
2. Enable Events
|
|
84
|
+
3. If using Socket Mode, events will be delivered through the socket
|
|
85
|
+
4. If using Events API (production), provide your server URL
|
|
86
|
+
5. Subscribe to these bot events:
|
|
87
|
+
- `message.channels`
|
|
88
|
+
- `message.groups`
|
|
89
|
+
- `message.im`
|
|
90
|
+
- `message.mpim`
|
|
91
|
+
- `reaction_added`
|
|
92
|
+
- `reaction_removed`
|
|
93
|
+
|
|
94
|
+
## Authentication Modes
|
|
95
|
+
|
|
96
|
+
The Slack adapter supports two authentication modes:
|
|
97
|
+
|
|
98
|
+
### Socket Mode (Development)
|
|
99
|
+
|
|
100
|
+
Best for development and testing. No public URL required.
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
const bot = createBot({
|
|
104
|
+
platform: 'slack',
|
|
105
|
+
credentials: {
|
|
106
|
+
botToken: process.env.SLACK_BOT_TOKEN, // xoxb-...
|
|
107
|
+
appToken: process.env.SLACK_APP_TOKEN, // xapp-...
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Events API (Production)
|
|
113
|
+
|
|
114
|
+
Best for production deployments.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
const bot = createBot({
|
|
118
|
+
platform: 'slack',
|
|
119
|
+
credentials: {
|
|
120
|
+
botToken: process.env.SLACK_BOT_TOKEN,
|
|
121
|
+
signingSecret: process.env.SLACK_SIGNING_SECRET,
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The adapter automatically detects which mode to use based on the credentials provided.
|
|
127
|
+
|
|
128
|
+
## Usage
|
|
129
|
+
|
|
130
|
+
### Basic Message Operations
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
// Send a message
|
|
134
|
+
await bot.sendMessage('C1234567890', 'Hello, Slack!');
|
|
135
|
+
|
|
136
|
+
// Reply to a message
|
|
137
|
+
bot.onMessage(async (message) => {
|
|
138
|
+
await bot.reply(message, 'Got your message!');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Edit a message
|
|
142
|
+
const result = await bot.sendMessage('C1234567890', 'Original');
|
|
143
|
+
if (result.ok) {
|
|
144
|
+
await bot.editMessage(result.value, 'Edited!');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Delete a message
|
|
148
|
+
await bot.deleteMessage(message);
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Reactions
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
bot.onMessage(async (message) => {
|
|
155
|
+
// Add reaction
|
|
156
|
+
await bot.addReaction(message, '👍');
|
|
157
|
+
|
|
158
|
+
// Remove reaction
|
|
159
|
+
await bot.removeReaction(message, '👍');
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Threads
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
bot.onMessage(async (message) => {
|
|
167
|
+
// Create a thread
|
|
168
|
+
await bot.createThread(message, 'Starting a thread!');
|
|
169
|
+
|
|
170
|
+
// Reply in existing thread
|
|
171
|
+
await bot.sendMessage(message.channelId, 'Thread reply', {
|
|
172
|
+
threadId: message.threadId,
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Platform-Specific Features
|
|
178
|
+
|
|
179
|
+
Use Slack's Block Kit for rich messages:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
await bot.sendMessage('C1234567890', 'Hello!', {
|
|
183
|
+
slack: {
|
|
184
|
+
blocks: [
|
|
185
|
+
{
|
|
186
|
+
type: 'section',
|
|
187
|
+
text: {
|
|
188
|
+
type: 'mrkdwn',
|
|
189
|
+
text: '*Hello* from Slack Block Kit!',
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
type: 'actions',
|
|
194
|
+
elements: [
|
|
195
|
+
{
|
|
196
|
+
type: 'button',
|
|
197
|
+
text: {
|
|
198
|
+
type: 'plain_text',
|
|
199
|
+
text: 'Click Me',
|
|
200
|
+
},
|
|
201
|
+
action_id: 'button_click',
|
|
202
|
+
},
|
|
203
|
+
],
|
|
204
|
+
},
|
|
205
|
+
],
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Important: MessageRef Pattern
|
|
211
|
+
|
|
212
|
+
Slack requires channel context for message operations (edit, delete, reactions). The adapter uses a cache to store this context, but for guaranteed reliability, **always pass the full message object**:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
// ✅ RECOMMENDED: Always works
|
|
216
|
+
bot.onMessage(async (message) => {
|
|
217
|
+
await bot.editMessage(message, 'Updated');
|
|
218
|
+
await bot.addReaction(message, '👍');
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// ⚠️ Works if message is in cache (last 1000 messages, 1 hour)
|
|
222
|
+
await bot.editMessage(messageId, 'Updated');
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### How the Cache Works
|
|
226
|
+
|
|
227
|
+
- **Capacity:** Stores last 1000 messages
|
|
228
|
+
- **TTL:** Messages expire after 1 hour
|
|
229
|
+
- **Hit Rate:** ~95% for typical interactive bots
|
|
230
|
+
- **When it fails:**
|
|
231
|
+
- Message older than 1 hour
|
|
232
|
+
- Bot restarted
|
|
233
|
+
- Message sent by another instance
|
|
234
|
+
|
|
235
|
+
### Error Messages Guide You
|
|
236
|
+
|
|
237
|
+
If cache lookup fails, you'll get a helpful error:
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
Cannot edit message: channel context not found.
|
|
241
|
+
|
|
242
|
+
This happens when:
|
|
243
|
+
1. The message is older than 1 hour (cache expired)
|
|
244
|
+
2. The bot restarted since the message was sent
|
|
245
|
+
3. The message was sent by another bot instance
|
|
246
|
+
|
|
247
|
+
Solution: Pass the full message object instead:
|
|
248
|
+
bot.editMessage(message, "text") // ✅ Works reliably
|
|
249
|
+
bot.editMessage(message.id, "text") // ❌ May fail on Slack
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Known Limitations
|
|
253
|
+
|
|
254
|
+
### 1. Message Context Requirement
|
|
255
|
+
|
|
256
|
+
Unlike Discord, Slack requires both channel ID and message timestamp for operations. This is handled transparently via caching, but long-lived message references should use the full message object.
|
|
257
|
+
|
|
258
|
+
### 2. Timestamps as IDs
|
|
259
|
+
|
|
260
|
+
Slack uses timestamps as message IDs (e.g., `"1503435956.000247"`). These are unique but may look unusual compared to typical IDs.
|
|
261
|
+
|
|
262
|
+
### 3. File Uploads
|
|
263
|
+
|
|
264
|
+
File uploads are not yet implemented in this version. Coming in Phase 5.
|
|
265
|
+
|
|
266
|
+
### 4. Message Formatting
|
|
267
|
+
|
|
268
|
+
Slack uses `mrkdwn` (their own Markdown variant), not standard Markdown. The adapter does minimal conversion. For rich formatting, use Block Kit.
|
|
269
|
+
|
|
270
|
+
## Configuration
|
|
271
|
+
|
|
272
|
+
### Cache Settings
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
import { SlackAdapter } from '@aarekaz/switchboard-slack';
|
|
276
|
+
|
|
277
|
+
const adapter = new SlackAdapter({
|
|
278
|
+
cacheSize: 5000, // Store more messages
|
|
279
|
+
cacheTTL: 1000 * 60 * 60 * 2, // 2 hour TTL
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
const bot = createBot({
|
|
283
|
+
platform: 'slack',
|
|
284
|
+
adapter,
|
|
285
|
+
credentials: { ... },
|
|
286
|
+
});
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Events API Port
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
const adapter = new SlackAdapter({
|
|
293
|
+
socketMode: false,
|
|
294
|
+
port: 3000, // Custom port for Events API
|
|
295
|
+
});
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Monitoring
|
|
299
|
+
|
|
300
|
+
The adapter logs cache hit rates every 1000 operations:
|
|
301
|
+
|
|
302
|
+
```
|
|
303
|
+
📊 Slack cache hit rate: 96.8% (968/1000)
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
High hit rates (>90%) indicate good performance. Lower rates suggest:
|
|
307
|
+
- Long-lived message references (consider using message objects)
|
|
308
|
+
- Frequent bot restarts (consider persistent cache in production)
|
|
309
|
+
- Multi-instance deployment (consider Redis cache)
|
|
310
|
+
|
|
311
|
+
## Examples
|
|
312
|
+
|
|
313
|
+
See the [examples directory](../../examples) for complete examples:
|
|
314
|
+
|
|
315
|
+
- `hello-world/slack.ts` - Basic Slack bot
|
|
316
|
+
- `hello-world/one-line-swap.ts` - Demonstrates platform switching
|
|
317
|
+
|
|
318
|
+
## API Reference
|
|
319
|
+
|
|
320
|
+
See [@aarekaz/switchboard-core](../core/README.md) for the full API reference. The Slack adapter implements the complete `PlatformAdapter` interface.
|
|
321
|
+
|
|
322
|
+
## License
|
|
323
|
+
|
|
324
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { PlatformAdapter, SendMessageOptions, Result, UnifiedMessage, MessageRef, UploadOptions, UnifiedEvent, Channel, User } from '@aarekaz/switchboard-core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Slack-specific types and interfaces
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Slack credentials for authentication
|
|
8
|
+
*/
|
|
9
|
+
interface SlackCredentials {
|
|
10
|
+
/** Bot token (xoxb-...) */
|
|
11
|
+
botToken: string;
|
|
12
|
+
/**
|
|
13
|
+
* App-level token for Socket Mode (xapp-...)
|
|
14
|
+
* Required if using Socket Mode (recommended for development)
|
|
15
|
+
*/
|
|
16
|
+
appToken?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Signing secret for Events API
|
|
19
|
+
* Required if using Events API (recommended for production)
|
|
20
|
+
*/
|
|
21
|
+
signingSecret?: string;
|
|
22
|
+
/**
|
|
23
|
+
* OAuth scopes (if using OAuth)
|
|
24
|
+
*/
|
|
25
|
+
scopes?: string[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Slack adapter configuration options
|
|
29
|
+
*/
|
|
30
|
+
interface SlackConfig {
|
|
31
|
+
/**
|
|
32
|
+
* Maximum cache size for message context
|
|
33
|
+
* @default 1000
|
|
34
|
+
*/
|
|
35
|
+
cacheSize?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Cache TTL in milliseconds
|
|
38
|
+
* @default 3600000 (1 hour)
|
|
39
|
+
*/
|
|
40
|
+
cacheTTL?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Enable Socket Mode
|
|
43
|
+
* Auto-detected based on credentials if not specified
|
|
44
|
+
*/
|
|
45
|
+
socketMode?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Port for Events API (if using HTTP mode)
|
|
48
|
+
* @default 3000
|
|
49
|
+
*/
|
|
50
|
+
port?: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Internal message context stored in cache
|
|
54
|
+
*/
|
|
55
|
+
interface MessageContext {
|
|
56
|
+
channelId: string;
|
|
57
|
+
threadId?: string;
|
|
58
|
+
timestamp: Date;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Slack message options (for platform-specific features)
|
|
62
|
+
*/
|
|
63
|
+
interface SlackMessageOptions {
|
|
64
|
+
/** Slack Block Kit blocks */
|
|
65
|
+
blocks?: unknown[];
|
|
66
|
+
/** Unfurl links */
|
|
67
|
+
unfurl_links?: boolean;
|
|
68
|
+
/** Unfurl media */
|
|
69
|
+
unfurl_media?: boolean;
|
|
70
|
+
/** Thread timestamp (for replying in threads) */
|
|
71
|
+
thread_ts?: string;
|
|
72
|
+
/** Metadata */
|
|
73
|
+
metadata?: unknown;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Slack Platform Adapter
|
|
78
|
+
* Implements the Switchboard PlatformAdapter interface for Slack
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Slack adapter implementation
|
|
83
|
+
*/
|
|
84
|
+
declare class SlackAdapter implements PlatformAdapter {
|
|
85
|
+
readonly name = "slack-adapter";
|
|
86
|
+
readonly platform: "slack";
|
|
87
|
+
private app;
|
|
88
|
+
private eventHandlers;
|
|
89
|
+
private config;
|
|
90
|
+
private messageCache;
|
|
91
|
+
private cacheHits;
|
|
92
|
+
private cacheMisses;
|
|
93
|
+
constructor(config?: SlackConfig);
|
|
94
|
+
/**
|
|
95
|
+
* Connect to Slack
|
|
96
|
+
*/
|
|
97
|
+
connect(credentials: unknown): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* Disconnect from Slack
|
|
100
|
+
*/
|
|
101
|
+
disconnect(): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Check if connected
|
|
104
|
+
*/
|
|
105
|
+
isConnected(): boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Send a message to a channel
|
|
108
|
+
*/
|
|
109
|
+
sendMessage(channelId: string, text: string, options?: SendMessageOptions): Promise<Result<UnifiedMessage>>;
|
|
110
|
+
/**
|
|
111
|
+
* Edit a message
|
|
112
|
+
*/
|
|
113
|
+
editMessage(messageRef: MessageRef, newText: string): Promise<Result<UnifiedMessage>>;
|
|
114
|
+
/**
|
|
115
|
+
* Delete a message
|
|
116
|
+
*/
|
|
117
|
+
deleteMessage(messageRef: MessageRef): Promise<Result<void>>;
|
|
118
|
+
/**
|
|
119
|
+
* Add a reaction to a message
|
|
120
|
+
*/
|
|
121
|
+
addReaction(messageRef: MessageRef, emoji: string): Promise<Result<void>>;
|
|
122
|
+
/**
|
|
123
|
+
* Remove a reaction from a message
|
|
124
|
+
*/
|
|
125
|
+
removeReaction(messageRef: MessageRef, emoji: string): Promise<Result<void>>;
|
|
126
|
+
/**
|
|
127
|
+
* Create a thread (reply to a message)
|
|
128
|
+
*/
|
|
129
|
+
createThread(messageRef: MessageRef, text: string): Promise<Result<UnifiedMessage>>;
|
|
130
|
+
/**
|
|
131
|
+
* Upload a file to a channel
|
|
132
|
+
*/
|
|
133
|
+
uploadFile(channelId: string, file: unknown, options?: UploadOptions): Promise<Result<UnifiedMessage>>;
|
|
134
|
+
/**
|
|
135
|
+
* Subscribe to platform events
|
|
136
|
+
*/
|
|
137
|
+
onEvent(handler: (event: UnifiedEvent) => void | Promise<void>): void;
|
|
138
|
+
/**
|
|
139
|
+
* Get list of channels
|
|
140
|
+
*/
|
|
141
|
+
getChannels(): Promise<Result<Channel[]>>;
|
|
142
|
+
/**
|
|
143
|
+
* Get list of users
|
|
144
|
+
*/
|
|
145
|
+
getUsers(channelId?: string): Promise<Result<User[]>>;
|
|
146
|
+
/**
|
|
147
|
+
* Normalize platform message to UnifiedMessage
|
|
148
|
+
*/
|
|
149
|
+
normalizeMessage(platformMessage: unknown): UnifiedMessage;
|
|
150
|
+
/**
|
|
151
|
+
* Normalize platform event to UnifiedEvent
|
|
152
|
+
*/
|
|
153
|
+
normalizeEvent(platformEvent: unknown): UnifiedEvent | null;
|
|
154
|
+
/**
|
|
155
|
+
* Set up event listeners for Slack
|
|
156
|
+
*/
|
|
157
|
+
private setupEventListeners;
|
|
158
|
+
/**
|
|
159
|
+
* Cache a message's context
|
|
160
|
+
*/
|
|
161
|
+
private cacheMessage;
|
|
162
|
+
/**
|
|
163
|
+
* Log cache statistics (every 1000 operations)
|
|
164
|
+
*/
|
|
165
|
+
private logCacheStats;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Normalizers for converting Slack types to Switchboard unified types
|
|
170
|
+
*/
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Normalize a Slack message to UnifiedMessage
|
|
174
|
+
*/
|
|
175
|
+
declare function normalizeMessage(slackMessage: any): UnifiedMessage;
|
|
176
|
+
/**
|
|
177
|
+
* Normalize Slack emoji to standard format
|
|
178
|
+
* Slack uses :emoji_name: format, we convert to Unicode or keep as-is
|
|
179
|
+
*/
|
|
180
|
+
declare function normalizeEmoji(slackEmoji: string): string;
|
|
181
|
+
/**
|
|
182
|
+
* Convert standard emoji to Slack format
|
|
183
|
+
*/
|
|
184
|
+
declare function toSlackEmoji(emoji: string): string;
|
|
185
|
+
/**
|
|
186
|
+
* Normalize message event from Slack
|
|
187
|
+
*/
|
|
188
|
+
declare function normalizeMessageEvent(event: any): UnifiedEvent;
|
|
189
|
+
/**
|
|
190
|
+
* Normalize reaction event from Slack
|
|
191
|
+
*/
|
|
192
|
+
declare function normalizeReactionEvent(event: any, action: 'added' | 'removed'): UnifiedEvent;
|
|
193
|
+
|
|
194
|
+
export { type MessageContext, SlackAdapter, type SlackConfig, type SlackCredentials, type SlackMessageOptions, normalizeEmoji, normalizeMessage, normalizeMessageEvent, normalizeReactionEvent, toSlackEmoji };
|