chub-dev 0.1.0 → 0.1.2-beta.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.
Files changed (139) hide show
  1. package/README.md +55 -0
  2. package/bin/chub-mcp +2 -0
  3. package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
  4. package/dist/airtable/docs/database/python/DOC.md +1735 -0
  5. package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
  6. package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
  7. package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
  8. package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
  9. package/dist/asana/docs/tasks/DOC.md +1396 -0
  10. package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
  11. package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
  12. package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
  13. package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
  14. package/dist/auth0/docs/identity/python/DOC.md +1199 -0
  15. package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
  16. package/dist/aws/docs/s3/python/DOC.md +1807 -0
  17. package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
  18. package/dist/binance/docs/trading/python/DOC.md +1454 -0
  19. package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
  20. package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
  21. package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
  22. package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
  23. package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
  24. package/dist/clerk/docs/auth/python/DOC.md +274 -0
  25. package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
  26. package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
  27. package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
  28. package/dist/cohere/docs/llm/DOC.md +1335 -0
  29. package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
  30. package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
  31. package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
  32. package/dist/deepgram/docs/speech/python/DOC.md +685 -0
  33. package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
  34. package/dist/deepl/docs/translation/python/DOC.md +944 -0
  35. package/dist/deepseek/docs/llm/DOC.md +1220 -0
  36. package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
  37. package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
  38. package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
  39. package/dist/discord/docs/bot/python/DOC.md +1130 -0
  40. package/dist/elasticsearch/docs/search/DOC.md +1634 -0
  41. package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
  42. package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
  43. package/dist/firebase/docs/auth/DOC.md +1015 -0
  44. package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
  45. package/dist/gemini/docs/genai/python/DOC.md +555 -0
  46. package/dist/github/docs/octokit/DOC.md +1560 -0
  47. package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
  48. package/dist/google/docs/bigquery/python/DOC.md +1503 -0
  49. package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
  50. package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
  51. package/dist/huggingface/docs/transformers/DOC.md +948 -0
  52. package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
  53. package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
  54. package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
  55. package/dist/jira/docs/issues/python/DOC.md +1492 -0
  56. package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
  57. package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
  58. package/dist/landingai-ade/docs/api/DOC.md +620 -0
  59. package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
  60. package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
  61. package/dist/landingai-ade/skills/SKILL.md +489 -0
  62. package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
  63. package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
  64. package/dist/linear/docs/tracker/DOC.md +1554 -0
  65. package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
  66. package/dist/livekit/docs/realtime/python/DOC.md +163 -0
  67. package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
  68. package/dist/meilisearch/docs/search/DOC.md +1241 -0
  69. package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
  70. package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
  71. package/dist/mongodb/docs/atlas/DOC.md +2041 -0
  72. package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
  73. package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
  74. package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
  75. package/dist/okta/docs/identity/python/DOC.md +1401 -0
  76. package/dist/openai/docs/chat/javascript/DOC.md +407 -0
  77. package/dist/openai/docs/chat/python/DOC.md +568 -0
  78. package/dist/paypal/docs/checkout/DOC.md +278 -0
  79. package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
  80. package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
  81. package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
  82. package/dist/plaid/docs/banking/python/DOC.md +1203 -0
  83. package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
  84. package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
  85. package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
  86. package/dist/prisma/docs/orm/python/DOC.md +1317 -0
  87. package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
  88. package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
  89. package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
  90. package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
  91. package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
  92. package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
  93. package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
  94. package/dist/redis/docs/key-value/python/DOC.md +2054 -0
  95. package/dist/registry.json +2817 -0
  96. package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
  97. package/dist/resend/docs/email/DOC.md +1271 -0
  98. package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
  99. package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
  100. package/dist/search-index.json +1 -0
  101. package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
  102. package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
  103. package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
  104. package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
  105. package/dist/shopify/docs/storefront/DOC.md +457 -0
  106. package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
  107. package/dist/slack/docs/workspace/python/DOC.md +271 -0
  108. package/dist/square/docs/payments/javascript/DOC.md +1855 -0
  109. package/dist/square/docs/payments/python/DOC.md +1728 -0
  110. package/dist/stripe/docs/api/DOC.md +1727 -0
  111. package/dist/stripe/docs/payments/DOC.md +1726 -0
  112. package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
  113. package/dist/stytch/docs/auth/python/DOC.md +1962 -0
  114. package/dist/supabase/docs/client/DOC.md +1606 -0
  115. package/dist/twilio/docs/messaging/python/DOC.md +469 -0
  116. package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
  117. package/dist/vercel/docs/platform/DOC.md +1940 -0
  118. package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
  119. package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
  120. package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
  121. package/dist/zendesk/docs/support/python/DOC.md +2297 -0
  122. package/package.json +22 -6
  123. package/skills/get-api-docs/SKILL.md +84 -0
  124. package/src/commands/annotate.js +83 -0
  125. package/src/commands/build.js +12 -1
  126. package/src/commands/feedback.js +150 -0
  127. package/src/commands/get.js +83 -42
  128. package/src/commands/search.js +7 -0
  129. package/src/index.js +43 -17
  130. package/src/lib/analytics.js +90 -0
  131. package/src/lib/annotations.js +57 -0
  132. package/src/lib/bm25.js +170 -0
  133. package/src/lib/cache.js +69 -6
  134. package/src/lib/config.js +8 -3
  135. package/src/lib/identity.js +99 -0
  136. package/src/lib/registry.js +103 -20
  137. package/src/lib/telemetry.js +86 -0
  138. package/src/mcp/server.js +177 -0
  139. package/src/mcp/tools.js +251 -0
@@ -0,0 +1,933 @@
1
+ ---
2
+ name: workspace
3
+ description: "Slack Node SDK for building bots, handling workspace events, and messaging integrations"
4
+ metadata:
5
+ languages: "javascript"
6
+ versions: "7.12.0"
7
+ updated-on: "2026-03-01"
8
+ source: maintainer
9
+ tags: "slack,bot,workspace,messaging,events-api"
10
+ ---
11
+
12
+ # Slack Node SDK Examples
13
+
14
+ Examples demonstrating the official Slack Node SDK packages for JavaScript/TypeScript applications.
15
+
16
+ ## Examples
17
+
18
+ - **[example/](./example/)** - Production-Ready Slack Bot
19
+ - Socket Mode real-time events with WebSocket connection
20
+ - Message echo and pattern matching
21
+ - User info retrieval (`users.info`)
22
+ - Channel listing (`conversations.list`)
23
+ - Automatic token refresh with OAuth v2
24
+ - Auto-join channels on `not_in_channel` error
25
+ - Comprehensive error handling with retry logic
26
+ - Bot message filtering to prevent infinite loops
27
+ - App mention handling
28
+ - Environment variable validation
29
+ - Graceful shutdown handlers
30
+
31
+ ## Slack Node SDK Guidelines
32
+
33
+ <cite>
34
+
35
+ ## Golden Rule: Use the Correct and Current SDK
36
+
37
+ Always use the official Slack Node SDK packages, which are the standard libraries for all Slack API interactions. Do not use legacy or deprecated packages.
38
+
39
+ - **Primary Package:** `@slack/web-api` - Official library for using the Slack Platform's Web API
40
+ - **OAuth Package:** `@slack/oauth` - For app installation and authentication flows
41
+ - **Socket Mode Package:** `@slack/socket-mode` - For real-time WebSocket connections
42
+ - **Legacy/Deprecated Packages:** `@slack/events-api`, `@slack/interactive-messages`, `@slack/client` should not be used
43
+
44
+ **Installation:**
45
+ - **Correct:** `npm install @slack/web-api`
46
+ - **Correct:** `npm install @slack/socket-mode @slack/oauth`
47
+ - **Deprecated:** `npm install @slack/events-api` (End-of-Life as of May 31st, 2021)
48
+ - **Deprecated:** `npm install @slack/interactive-messages` (End-of-Life as of May 31st, 2021)
49
+
50
+ **APIs and Usage:**
51
+ - **Correct:** `import { WebClient } from '@slack/web-api'`
52
+ - **Correct:** `const web = new WebClient(token)`
53
+ - **Correct:** `await web.chat.postMessage({ ... })`
54
+ - **Correct:** `import { SocketModeClient } from '@slack/socket-mode'`
55
+ - **Correct:** `import { InstallProvider } from '@slack/oauth'`
56
+
57
+ ## System Requirements
58
+
59
+ The Slack Node SDK requires:
60
+ - Node.js v18 or higher
61
+ - npm v8.6.0 or higher
62
+
63
+ ## Initialization and Authentication
64
+
65
+ ### Web API Client
66
+
67
+ The `@slack/web-api` package provides the `WebClient` class for all Web API interactions.
68
+
69
+ ```javascript
70
+ import { WebClient } from '@slack/web-api';
71
+
72
+ // Initialize with bot token
73
+ const web = new WebClient(process.env.SLACK_BOT_TOKEN);
74
+
75
+ // Or with user token
76
+ const web = new WebClient(process.env.SLACK_USER_TOKEN);
77
+ ```
78
+
79
+ ### Socket Mode Client
80
+
81
+ For real-time events without exposing public endpoints:
82
+
83
+ ```javascript
84
+ import { SocketModeClient } from '@slack/socket-mode';
85
+
86
+ const socketMode = new SocketModeClient({
87
+ appToken: process.env.SLACK_APP_TOKEN,
88
+ socketMode: true
89
+ });
90
+ ```
91
+
92
+ ## Core API Methods
93
+
94
+ ### Sending Messages
95
+
96
+ ```javascript
97
+ import { WebClient } from '@slack/web-api';
98
+
99
+ const web = new WebClient(process.env.SLACK_BOT_TOKEN);
100
+
101
+ async function sendMessage() {
102
+ try {
103
+ const result = await web.chat.postMessage({
104
+ channel: 'C1234567890',
105
+ text: 'Hello world!',
106
+ blocks: [
107
+ {
108
+ type: 'section',
109
+ text: {
110
+ type: 'mrkdwn',
111
+ text: 'Hello *world*!'
112
+ }
113
+ }
114
+ ]
115
+ });
116
+ console.log(`Message sent: ${result.ts}`);
117
+ } catch (error) {
118
+ console.error('Error sending message:', error);
119
+ }
120
+ }
121
+ ```
122
+
123
+ ### File Uploads
124
+
125
+ ```javascript
126
+ import { WebClient } from '@slack/web-api';
127
+ import fs from 'fs';
128
+
129
+ const web = new WebClient(process.env.SLACK_BOT_TOKEN);
130
+
131
+ async function uploadFile() {
132
+ try {
133
+ const result = await web.files.uploadV2({
134
+ channel_id: 'C1234567890',
135
+ file: fs.createReadStream('./document.pdf'),
136
+ filename: 'document.pdf',
137
+ initial_comment: 'Here is the document you requested.'
138
+ });
139
+ console.log('File uploaded:', result.file.id);
140
+ } catch (error) {
141
+ console.error('Error uploading file:', error);
142
+ }
143
+ }
144
+ ```
145
+
146
+ ### Getting User Information
147
+
148
+ ```javascript
149
+ async function getUserInfo(userId) {
150
+ try {
151
+ const result = await web.users.info({
152
+ user: userId
153
+ });
154
+ return result.user;
155
+ } catch (error) {
156
+ console.error('Error getting user info:', error);
157
+ }
158
+ }
159
+ ```
160
+
161
+ ### Listing Conversations
162
+
163
+ ```javascript
164
+ async function listChannels() {
165
+ try {
166
+ const result = await web.conversations.list({
167
+ types: 'public_channel,private_channel',
168
+ limit: 100
169
+ });
170
+ return result.channels;
171
+ } catch (error) {
172
+ console.error('Error listing channels:', error);
173
+ }
174
+ }
175
+ ```
176
+
177
+ ## Socket Mode for Real-time Events
178
+
179
+ Socket Mode enables real-time event handling without public endpoints. Always acknowledge events immediately.
180
+
181
+ ### Basic Setup
182
+
183
+ ```javascript
184
+ import { SocketModeClient } from '@slack/socket-mode';
185
+ import { WebClient } from '@slack/web-api';
186
+ import dotenv from 'dotenv';
187
+
188
+ dotenv.config();
189
+
190
+ // Validate required environment variables
191
+ if (!process.env.SLACK_BOT_TOKEN || !process.env.SLACK_APP_TOKEN) {
192
+ console.error('Missing required tokens');
193
+ process.exit(1);
194
+ }
195
+
196
+ let currentBotToken = process.env.SLACK_BOT_TOKEN;
197
+ let web = new WebClient(currentBotToken);
198
+
199
+ const socketMode = new SocketModeClient({
200
+ appToken: process.env.SLACK_APP_TOKEN
201
+ });
202
+ ```
203
+
204
+ ### Message Event Handling
205
+
206
+ Filter bot messages and handle app mentions properly:
207
+
208
+ ```javascript
209
+ socketMode.on('message', async ({ event, ack }) => {
210
+ try {
211
+ await ack(); // Always acknowledge first
212
+
213
+ // Skip bot messages and subtypes
214
+ if (event.type === 'message' && !event.bot_id && event.text && event.subtype !== 'bot_message') {
215
+ // Skip app mentions (handled by app_mention handler)
216
+ if (event.subtype === 'app_mention' || (event.text && event.text.match(/<@[A-Z0-9]+>/))) {
217
+ return;
218
+ }
219
+
220
+ console.log(`Message received: "${event.text}" from user: ${event.user}`);
221
+
222
+ // Process message
223
+ await web.chat.postMessage({
224
+ channel: event.channel,
225
+ text: `You said: "${event.text}"`
226
+ });
227
+ }
228
+ } catch (error) {
229
+ console.error('Error handling message event:', error);
230
+ }
231
+ });
232
+ ```
233
+
234
+ ### App Mention Handling
235
+
236
+ ```javascript
237
+ socketMode.on('app_mention', async ({ event, ack }) => {
238
+ try {
239
+ await ack();
240
+
241
+ console.log(`App mention: "${event.text}" from user: ${event.user}`);
242
+
243
+ await web.chat.postMessage({
244
+ channel: event.channel,
245
+ text: `<@${event.user}> Hello!`
246
+ });
247
+ } catch (error) {
248
+ console.error('Error handling app mention:', error);
249
+ }
250
+ });
251
+ ```
252
+
253
+ ### Error Handling and Startup
254
+
255
+ ```javascript
256
+ socketMode.on('error', (error) => {
257
+ console.error('Socket Mode error:', error);
258
+ });
259
+
260
+ async function startBot() {
261
+ try {
262
+ console.log('Starting Slack bot...');
263
+
264
+ // Test authentication first
265
+ const auth = await web.auth.test();
266
+ console.log(`Connected as: ${auth.user} (${auth.team})`);
267
+
268
+ // Start socket mode
269
+ await socketMode.start();
270
+ console.log('Bot is running successfully!');
271
+ } catch (error) {
272
+ console.error('Error starting bot:', error);
273
+
274
+ if (error.data?.error === 'invalid_auth') {
275
+ console.error('Authentication failed. Check your SLACK_BOT_TOKEN.');
276
+ } else if (error.data?.error === 'token_expired') {
277
+ console.error('Token expired. Attempting refresh...');
278
+ // Implement token refresh logic here
279
+ }
280
+
281
+ process.exit(1);
282
+ }
283
+ }
284
+
285
+ // Graceful shutdown
286
+ process.on('SIGINT', async () => {
287
+ console.log('Shutting down bot...');
288
+ await socketMode.disconnect();
289
+ process.exit(0);
290
+ });
291
+
292
+ process.on('SIGTERM', async () => {
293
+ console.log('Shutting down bot...');
294
+ await socketMode.disconnect();
295
+ process.exit(0);
296
+ });
297
+
298
+ startBot();
299
+ ```
300
+
301
+ ## OAuth Installation Flow
302
+
303
+ ```javascript
304
+ import { InstallProvider } from '@slack/oauth';
305
+ import { WebClient } from '@slack/web-api';
306
+
307
+ const installer = new InstallProvider({
308
+ clientId: process.env.SLACK_CLIENT_ID,
309
+ clientSecret: process.env.SLACK_CLIENT_SECRET,
310
+ stateSecret: 'my-state-secret',
311
+ installationStore: {
312
+ storeInstallation: async (installation) => {
313
+ // Store installation data in your database
314
+ console.log('Installation:', installation);
315
+ },
316
+ fetchInstallation: async (installQuery) => {
317
+ // Fetch installation data from your database
318
+ return installation;
319
+ }
320
+ }
321
+ });
322
+
323
+ // Generate install URL
324
+ const installUrl = await installer.generateInstallUrl({
325
+ scopes: ['chat:write', 'channels:read'],
326
+ userScopes: ['chat:write']
327
+ });
328
+
329
+ // Handle OAuth callback
330
+ app.get('/slack/oauth_redirect', async (req, res) => {
331
+ try {
332
+ const installation = await installer.handleCallback(req, res);
333
+ console.log('Installation successful:', installation);
334
+ } catch (error) {
335
+ console.error('OAuth error:', error);
336
+ }
337
+ });
338
+ ```
339
+
340
+ ## Error Handling and Resilience
341
+
342
+ ### Basic Error Handling
343
+
344
+ All API responses follow a consistent structure:
345
+
346
+ ```javascript
347
+ import { WebClient } from '@slack/web-api';
348
+
349
+ const web = new WebClient(process.env.SLACK_BOT_TOKEN);
350
+
351
+ async function handleApiCall() {
352
+ try {
353
+ const result = await web.chat.postMessage({
354
+ channel: 'C1234567890',
355
+ text: 'Hello!'
356
+ });
357
+
358
+ if (result.ok) {
359
+ console.log('Success:', result.ts);
360
+ } else {
361
+ console.error('API Error:', result.error);
362
+ }
363
+ } catch (error) {
364
+ if (error.code === 'slack_webapi_platform_error') {
365
+ console.error('Slack API Error:', error.data);
366
+ } else {
367
+ console.error('Network/Other Error:', error);
368
+ }
369
+ }
370
+ }
371
+ ```
372
+
373
+ ### Token Refresh Pattern
374
+
375
+ Implement automatic token refresh for OAuth apps:
376
+
377
+ ```javascript
378
+ import fs from 'fs';
379
+
380
+ async function refreshBotToken() {
381
+ try {
382
+ console.log('Refreshing bot token...');
383
+ const response = await fetch('https://slack.com/api/oauth.v2.access', {
384
+ method: 'POST',
385
+ headers: {
386
+ 'Content-Type': 'application/x-www-form-urlencoded',
387
+ },
388
+ body: new URLSearchParams({
389
+ client_id: process.env.SLACK_CLIENT_ID,
390
+ client_secret: process.env.SLACK_CLIENT_SECRET,
391
+ grant_type: 'refresh_token',
392
+ refresh_token: process.env.SLACK_BOT_REFRESH_TOKEN,
393
+ }),
394
+ });
395
+
396
+ const data = await response.json();
397
+
398
+ if (data.ok) {
399
+ currentBotToken = data.access_token;
400
+ web = new WebClient(currentBotToken);
401
+
402
+ // Update .env file with new token
403
+ const envContent = fs.readFileSync('.env', 'utf8');
404
+ const updatedContent = envContent.replace(
405
+ /SLACK_BOT_TOKEN=.*/,
406
+ `SLACK_BOT_TOKEN=${currentBotToken}`
407
+ );
408
+ fs.writeFileSync('.env', updatedContent);
409
+
410
+ console.log('Bot token refreshed successfully');
411
+ return true;
412
+ }
413
+ return false;
414
+ } catch (error) {
415
+ console.error('Error refreshing token:', error);
416
+ return false;
417
+ }
418
+ }
419
+ ```
420
+
421
+ ### Retry Pattern for Token Errors
422
+
423
+ Automatically retry API calls after token refresh:
424
+
425
+ ```javascript
426
+ async function sendMessage(channel, text) {
427
+ try {
428
+ const result = await web.chat.postMessage({
429
+ channel: channel,
430
+ text: text
431
+ });
432
+ console.log(`Message sent: ${text}`);
433
+ return result;
434
+ } catch (error) {
435
+ console.error('Error sending message:', error);
436
+
437
+ // Handle token-related errors with refresh and retry
438
+ if (error.data?.error === 'invalid_auth' ||
439
+ error.data?.error === 'token_revoked' ||
440
+ error.data?.error === 'token_expired') {
441
+ console.log('Token appears invalid, attempting refresh...');
442
+ const refreshed = await refreshBotToken();
443
+ if (refreshed) {
444
+ // Retry the message after token refresh
445
+ try {
446
+ const result = await web.chat.postMessage({
447
+ channel: channel,
448
+ text: text
449
+ });
450
+ console.log(`Message sent after token refresh: ${result.ts}`);
451
+ return result;
452
+ } catch (retryError) {
453
+ console.error('Failed to send message even after token refresh:', retryError);
454
+ }
455
+ }
456
+ }
457
+
458
+ throw error;
459
+ }
460
+ }
461
+ ```
462
+
463
+ ### Auto-Join Channel Pattern
464
+
465
+ Handle `not_in_channel` errors by joining automatically:
466
+
467
+ ```javascript
468
+ async function ensureBotInChannel(channel) {
469
+ try {
470
+ const result = await web.conversations.join({ channel });
471
+ if (result.ok) {
472
+ console.log(`Joined channel ${channel} before sending message`);
473
+ return true;
474
+ }
475
+ } catch (error) {
476
+ if (error.data?.error === 'already_in_channel') {
477
+ return true;
478
+ }
479
+ if (error.data?.error === 'method_not_supported_for_channel_type') {
480
+ console.warn(`Cannot join channel type for ${channel}; proceeding without join.`);
481
+ } else {
482
+ console.error('Error joining channel:', error);
483
+ }
484
+ }
485
+ return false;
486
+ }
487
+
488
+ async function sendMessage(channel, text) {
489
+ try {
490
+ return await web.chat.postMessage({ channel, text });
491
+ } catch (error) {
492
+ // Handle not_in_channel error
493
+ if (error.data?.error === 'not_in_channel') {
494
+ console.log(`Bot is not in channel ${channel}, attempting to join...`);
495
+ const joined = await ensureBotInChannel(channel);
496
+ if (joined) {
497
+ try {
498
+ const result = await web.chat.postMessage({ channel, text });
499
+ console.log(`Message sent after joining channel: ${result.ts}`);
500
+ return result;
501
+ } catch (retryError) {
502
+ console.error('Failed to send message even after joining channel:', retryError);
503
+ }
504
+ }
505
+ }
506
+ throw error;
507
+ }
508
+ }
509
+ ```
510
+
511
+ ### Combined Error Handling Pattern
512
+
513
+ Apply retry logic to all API methods:
514
+
515
+ ```javascript
516
+ async function getUserInfo(userId) {
517
+ try {
518
+ const result = await web.users.info({ user: userId });
519
+ return result.user;
520
+ } catch (error) {
521
+ console.error('Error getting user info:', error);
522
+
523
+ // Retry with token refresh if needed
524
+ if (error.data?.error === 'invalid_auth' ||
525
+ error.data?.error === 'token_revoked' ||
526
+ error.data?.error === 'token_expired') {
527
+ console.log('Token appears invalid, attempting refresh...');
528
+ const refreshed = await refreshBotToken();
529
+ if (refreshed) {
530
+ try {
531
+ const result = await web.users.info({ user: userId });
532
+ return result.user;
533
+ } catch (retryError) {
534
+ console.error('Failed to get user info even after token refresh:', retryError);
535
+ }
536
+ }
537
+ }
538
+ }
539
+ }
540
+
541
+ async function listChannels() {
542
+ try {
543
+ const result = await web.conversations.list({
544
+ types: 'public_channel,private_channel',
545
+ limit: 100
546
+ });
547
+ return result.channels;
548
+ } catch (error) {
549
+ console.error('Error listing channels:', error);
550
+
551
+ // Retry with token refresh if needed
552
+ if (error.data?.error === 'invalid_auth' ||
553
+ error.data?.error === 'token_revoked' ||
554
+ error.data?.error === 'token_expired') {
555
+ console.log('Token appears invalid, attempting refresh...');
556
+ const refreshed = await refreshBotToken();
557
+ if (refreshed) {
558
+ try {
559
+ const result = await web.conversations.list({
560
+ types: 'public_channel,private_channel',
561
+ limit: 100
562
+ });
563
+ return result.channels;
564
+ } catch (retryError) {
565
+ console.error('Failed to list channels even after token refresh:', retryError);
566
+ }
567
+ }
568
+ }
569
+ }
570
+ }
571
+ ```
572
+
573
+ ## Pagination
574
+
575
+ ```javascript
576
+ async function getAllChannels() {
577
+ const channels = [];
578
+ let cursor;
579
+
580
+ do {
581
+ const result = await web.conversations.list({
582
+ types: 'public_channel,private_channel',
583
+ limit: 200,
584
+ cursor: cursor
585
+ });
586
+
587
+ channels.push(...result.channels);
588
+ cursor = result.response_metadata?.next_cursor;
589
+ } while (cursor);
590
+
591
+ return channels;
592
+ }
593
+ ```
594
+
595
+ ## Rate Limiting
596
+
597
+ The SDK automatically handles rate limiting with built-in retry logic:
598
+
599
+ ```javascript
600
+ import { WebClient } from '@slack/web-api';
601
+
602
+ const web = new WebClient(process.env.SLACK_BOT_TOKEN, {
603
+ retryConfig: {
604
+ retries: 3,
605
+ factor: 2
606
+ }
607
+ });
608
+ ```
609
+
610
+ ## TypeScript Support
611
+
612
+ The SDK includes full TypeScript definitions:
613
+
614
+ ```typescript
615
+ import { WebClient, ChatPostMessageResponse } from '@slack/web-api';
616
+
617
+ const web = new WebClient(process.env.SLACK_BOT_TOKEN);
618
+
619
+ async function sendTypedMessage(): Promise<ChatPostMessageResponse> {
620
+ return await web.chat.postMessage({
621
+ channel: 'C1234567890',
622
+ text: 'Hello TypeScript!'
623
+ });
624
+ }
625
+ ```
626
+
627
+ ## Webhook Usage
628
+
629
+ ```javascript
630
+ import { IncomingWebhook } from '@slack/webhook';
631
+
632
+ const webhook = new IncomingWebhook(process.env.SLACK_WEBHOOK_URL);
633
+
634
+ async function sendWebhookMessage() {
635
+ await webhook.send({
636
+ text: 'Hello from webhook!',
637
+ attachments: [
638
+ {
639
+ color: 'good',
640
+ text: 'This is an attachment'
641
+ }
642
+ ]
643
+ });
644
+ }
645
+ ```
646
+
647
+ ## Block Kit Messages
648
+
649
+ ```javascript
650
+ async function sendRichMessage() {
651
+ await web.chat.postMessage({
652
+ channel: 'C1234567890',
653
+ blocks: [
654
+ {
655
+ type: 'header',
656
+ text: {
657
+ type: 'plain_text',
658
+ text: 'Welcome!'
659
+ }
660
+ },
661
+ {
662
+ type: 'section',
663
+ text: {
664
+ type: 'mrkdwn',
665
+ text: 'This is a *rich* message with buttons.'
666
+ },
667
+ accessory: {
668
+ type: 'button',
669
+ text: {
670
+ type: 'plain_text',
671
+ text: 'Click Me'
672
+ },
673
+ action_id: 'button_click'
674
+ }
675
+ }
676
+ ]
677
+ });
678
+ }
679
+ ```
680
+
681
+ ## Production Best Practices
682
+
683
+ ### Environment Variable Validation
684
+
685
+ Always validate required environment variables at startup:
686
+
687
+ ```javascript
688
+ import dotenv from 'dotenv';
689
+
690
+ dotenv.config();
691
+
692
+ // Validate required environment variables
693
+ if (!process.env.SLACK_BOT_TOKEN) {
694
+ console.error('❌ SLACK_BOT_TOKEN is required. Please check your .env file.');
695
+ process.exit(1);
696
+ }
697
+
698
+ if (!process.env.SLACK_APP_TOKEN) {
699
+ console.error('❌ SLACK_APP_TOKEN is required. Please check your .env file.');
700
+ process.exit(1);
701
+ }
702
+ ```
703
+
704
+ ### Token Management
705
+
706
+ Use mutable references for tokens that may need refreshing:
707
+
708
+ ```javascript
709
+ let currentBotToken = process.env.SLACK_BOT_TOKEN;
710
+ let web = new WebClient(currentBotToken);
711
+
712
+ // After refresh, reassign both:
713
+ currentBotToken = data.access_token;
714
+ web = new WebClient(currentBotToken);
715
+ ```
716
+
717
+ ### Comprehensive Startup Flow
718
+
719
+ Test authentication before starting Socket Mode:
720
+
721
+ ```javascript
722
+ async function startBot() {
723
+ try {
724
+ console.log('🤖 Starting Slack bot...');
725
+
726
+ // Test authentication first
727
+ console.log('🔐 Testing authentication...');
728
+ const auth = await web.auth.test();
729
+ console.log(`✅ Connected as: ${auth.user} (${auth.team})`);
730
+
731
+ // Start socket mode connection
732
+ console.log('🔌 Starting Socket Mode connection...');
733
+ await socketMode.start();
734
+
735
+ console.log('🚀 Bot is running successfully!');
736
+ console.log('📝 Available commands:');
737
+ console.log(' - Send messages containing: "hello", "info", "channels"');
738
+ console.log(' - Mention the bot in any channel');
739
+
740
+ } catch (error) {
741
+ console.error('❌ Error starting bot:', error);
742
+
743
+ // Provide helpful error messages based on error type
744
+ if (error.data?.error === 'invalid_auth') {
745
+ console.error('🔑 Authentication failed. Please check your SLACK_BOT_TOKEN.');
746
+ } else if (error.data?.error === 'token_revoked') {
747
+ console.error('🔑 Token has been revoked. Please generate a new SLACK_BOT_TOKEN.');
748
+ } else if (error.data?.error === 'token_expired') {
749
+ console.error('🔑 Token has expired. Attempting to refresh...');
750
+ const refreshed = await refreshBotToken();
751
+ if (refreshed) {
752
+ console.log('✅ Token refreshed successfully. Restarting bot...');
753
+ return startBot(); // Restart with new token
754
+ }
755
+ } else if (error.message?.includes('invalid_app_token')) {
756
+ console.error('🔑 Invalid app token. Please check your SLACK_APP_TOKEN.');
757
+ } else if (error.code === 'ENOTFOUND') {
758
+ console.error('🌐 Network error. Please check your internet connection.');
759
+ }
760
+
761
+ console.log('\n💡 Make sure you have:');
762
+ console.log(' 1. Created a .env file with valid tokens');
763
+ console.log(' 2. Enabled Socket Mode in your Slack app');
764
+ console.log(' 3. Added the required OAuth scopes');
765
+
766
+ process.exit(1);
767
+ }
768
+ }
769
+
770
+ startBot();
771
+ ```
772
+
773
+ ### Graceful Shutdown Handlers
774
+
775
+ Always disconnect Socket Mode cleanly:
776
+
777
+ ```javascript
778
+ process.on('SIGINT', async () => {
779
+ console.log('\nShutting down bot...');
780
+ await socketMode.disconnect();
781
+ process.exit(0);
782
+ });
783
+
784
+ process.on('SIGTERM', async () => {
785
+ console.log('\nShutting down bot...');
786
+ await socketMode.disconnect();
787
+ process.exit(0);
788
+ });
789
+ ```
790
+
791
+ ### Message Filtering Best Practices
792
+
793
+ Prevent infinite loops and duplicate processing:
794
+
795
+ ```javascript
796
+ socketMode.on('message', async ({ event, ack }) => {
797
+ try {
798
+ await ack(); // Always acknowledge first
799
+
800
+ // Filter out bot messages, subtypes, and app mentions
801
+ if (event.type === 'message' &&
802
+ !event.bot_id &&
803
+ event.text &&
804
+ event.subtype !== 'bot_message') {
805
+
806
+ // Skip app mentions (handled by app_mention handler)
807
+ if (event.subtype === 'app_mention' ||
808
+ (event.text && event.text.match(/<@[A-Z0-9]+>/))) {
809
+ return;
810
+ }
811
+
812
+ // Process the message
813
+ // ...
814
+ }
815
+ } catch (error) {
816
+ console.error('Error handling message event:', error);
817
+ }
818
+ });
819
+ ```
820
+
821
+ ### Error Recovery Strategies
822
+
823
+ Implement comprehensive error recovery:
824
+
825
+ ```javascript
826
+ async function sendMessage(channel, text) {
827
+ try {
828
+ const result = await web.chat.postMessage({
829
+ channel: channel,
830
+ text: text
831
+ });
832
+ console.log(`Message sent: ${text}`);
833
+ return result;
834
+ } catch (error) {
835
+ console.error('Error sending message:', error);
836
+
837
+ // 1. Handle token errors
838
+ if (error.data?.error === 'invalid_auth' ||
839
+ error.data?.error === 'token_revoked' ||
840
+ error.data?.error === 'token_expired') {
841
+ const refreshed = await refreshBotToken();
842
+ if (refreshed) {
843
+ return await web.chat.postMessage({ channel, text });
844
+ }
845
+ }
846
+ // 2. Handle channel access errors
847
+ else if (error.data?.error === 'not_in_channel') {
848
+ const joined = await ensureBotInChannel(channel);
849
+ if (joined) {
850
+ return await web.chat.postMessage({ channel, text });
851
+ }
852
+ }
853
+
854
+ // Don't try to send error messages for auth/channel errors
855
+ if (!['invalid_auth', 'token_revoked', 'token_expired', 'not_in_channel'].includes(error.data?.error)) {
856
+ try {
857
+ await web.chat.postMessage({
858
+ channel: channel,
859
+ text: `⚠️ Error occurred: ${error.message}`
860
+ });
861
+ } catch (secondError) {
862
+ console.error('Failed to send error message to channel:', secondError);
863
+ }
864
+ }
865
+
866
+ throw error;
867
+ }
868
+ }
869
+ ```
870
+
871
+ ## Notes
872
+
873
+ The Slack Node SDK is modular and designed for specific use cases. <cite/> The `@slack/web-api` package is the primary interface for most Slack API interactions, while `@slack/socket-mode` enables real-time communication without exposing public endpoints. <cite/> Legacy packages like `@slack/events-api` and `@slack/interactive-messages` reached End-of-Life on May 31st, 2021 and should be migrated to Socket Mode or the Bolt framework. <cite/> The SDK includes comprehensive TypeScript support and handles rate limiting, retries, and pagination automatically. <cite/>
874
+
875
+ Wiki pages you might want to explore:
876
+ - [Overview (slackapi/node-slack-sdk)](/wiki/slackapi/node-slack-sdk#1)
877
+
878
+ ### Citations
879
+
880
+ ```json
881
+ "name": "@slack/web-api",
882
+ "version": "7.9.2",
883
+ "description": "Official library for using the Slack Platform's Web API",
884
+ ```
885
+
886
+ ```json
887
+ "types": "./dist/index.d.ts",
888
+ ```
889
+
890
+ ```json
891
+ "engines": {
892
+ "node": ">= 18",
893
+ "npm": ">= 8.6.0"
894
+ },
895
+ ```
896
+
897
+ ```json
898
+ "version": "2.0.2",
899
+ "description": "Official library for using the Slack Platform's Interactive Buttons, Menus, Dialogs, Actions, and Block Actions",
900
+ "author": "Slack Technologies, LLC",
901
+ "license": "MIT",
902
+ "keywords": [
903
+ "slack",
904
+ "interactive",
905
+ "interactive-messages",
906
+ "interactive-components",
907
+ "dialog",
908
+ "button",
909
+ "menu",
910
+ "action",
911
+ "block-kit",
912
+ "block-actions",
913
+ "bot",
914
+ "server",
915
+ "http",
916
+ "api",
917
+ "verify",
918
+ "signature",
919
+ "request-signing"
920
+ ],
921
+ ```
922
+
923
+ ```typescript
924
+ import type { WebAPICallResult } from '../../WebClient';
925
+ export type AuthTeamsListResponse = WebAPICallResult & {
926
+ error?: string;
927
+ needed?: string;
928
+ ok?: boolean;
929
+ provided?: string;
930
+ response_metadata?: ResponseMetadata;
931
+ teams?: Team[];
932
+ };
933
+ ```