@bubblelab/bubble-core 0.1.83 → 0.1.85

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 (116) hide show
  1. package/dist/bubble-bundle.d.ts +114 -114
  2. package/dist/bubbles/service-bubble/agi-inc.d.ts +52 -52
  3. package/dist/bubbles/service-bubble/ai-agent.d.ts +20 -20
  4. package/dist/bubbles/service-bubble/airtable.d.ts +138 -138
  5. package/dist/bubbles/service-bubble/apify/actors/google-maps-scraper.d.ts +2 -2
  6. package/dist/bubbles/service-bubble/apify/actors/instagram-hashtag-scraper.d.ts +20 -20
  7. package/dist/bubbles/service-bubble/apify/actors/instagram-scraper.d.ts +30 -30
  8. package/dist/bubbles/service-bubble/apify/actors/linkedin-posts-search.d.ts +26 -26
  9. package/dist/bubbles/service-bubble/apify/actors/linkedin-profile-posts.d.ts +56 -56
  10. package/dist/bubbles/service-bubble/apify/actors/tiktok-scraper.d.ts +16 -16
  11. package/dist/bubbles/service-bubble/apify/actors/twitter-scraper.d.ts +31 -31
  12. package/dist/bubbles/service-bubble/apify/actors/youtube-scraper.d.ts +8 -8
  13. package/dist/bubbles/service-bubble/apify/apify-scraper.schema.d.ts +153 -153
  14. package/dist/bubbles/service-bubble/apify/apify.d.ts +12 -12
  15. package/dist/bubbles/service-bubble/ashby/ashby.d.ts +18 -18
  16. package/dist/bubbles/service-bubble/ashby/ashby.schema.d.ts +18 -18
  17. package/dist/bubbles/service-bubble/browserbase/browserbase.d.ts +20 -20
  18. package/dist/bubbles/service-bubble/browserbase/browserbase.schema.d.ts +20 -20
  19. package/dist/bubbles/service-bubble/crustdata/crustdata.d.ts +12 -12
  20. package/dist/bubbles/service-bubble/crustdata/crustdata.schema.d.ts +16 -16
  21. package/dist/bubbles/service-bubble/eleven-labs.d.ts +24 -24
  22. package/dist/bubbles/service-bubble/firecrawl.d.ts +68 -68
  23. package/dist/bubbles/service-bubble/followupboss.d.ts +124 -124
  24. package/dist/bubbles/service-bubble/fullenrich/fullenrich.d.ts +12 -12
  25. package/dist/bubbles/service-bubble/fullenrich/fullenrich.schema.d.ts +12 -12
  26. package/dist/bubbles/service-bubble/github.d.ts +36 -36
  27. package/dist/bubbles/service-bubble/gmail.d.ts +64 -64
  28. package/dist/bubbles/service-bubble/google-calendar.d.ts +24 -24
  29. package/dist/bubbles/service-bubble/google-drive.d.ts +48 -48
  30. package/dist/bubbles/service-bubble/google-sheets/google-sheets.d.ts +22 -22
  31. package/dist/bubbles/service-bubble/google-sheets/google-sheets.schema.d.ts +22 -22
  32. package/dist/bubbles/service-bubble/hello-world.d.ts +4 -4
  33. package/dist/bubbles/service-bubble/http.d.ts +8 -8
  34. package/dist/bubbles/service-bubble/insforge-db.d.ts +10 -10
  35. package/dist/bubbles/service-bubble/jira/jira.d.ts +20 -20
  36. package/dist/bubbles/service-bubble/jira/jira.schema.d.ts +20 -20
  37. package/dist/bubbles/service-bubble/notion/notion.d.ts +68 -68
  38. package/dist/bubbles/service-bubble/notion/property-schemas.d.ts +36 -36
  39. package/dist/bubbles/service-bubble/postgresql.d.ts +10 -10
  40. package/dist/bubbles/service-bubble/resend.d.ts +8 -8
  41. package/dist/bubbles/service-bubble/slack/slack.d.ts +97 -97
  42. package/dist/bubbles/service-bubble/slack/slack.d.ts.map +1 -1
  43. package/dist/bubbles/service-bubble/slack/slack.js +0 -133
  44. package/dist/bubbles/service-bubble/slack/slack.js.map +1 -1
  45. package/dist/bubbles/service-bubble/storage.d.ts +20 -20
  46. package/dist/bubbles/service-bubble/stripe/stripe.d.ts +38 -38
  47. package/dist/bubbles/service-bubble/stripe/stripe.schema.d.ts +38 -38
  48. package/dist/bubbles/service-bubble/telegram.d.ts +52 -52
  49. package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.d.ts +14 -14
  50. package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.schema.d.ts +14 -14
  51. package/dist/bubbles/tool-bubble/bubbleflow-validation-tool.d.ts +4 -4
  52. package/dist/bubbles/tool-bubble/chart-js-tool.d.ts +4 -4
  53. package/dist/bubbles/tool-bubble/code-edit-tool.d.ts +4 -4
  54. package/dist/bubbles/tool-bubble/company-enrichment-tool.d.ts +4 -4
  55. package/dist/bubbles/tool-bubble/get-bubble-details-tool.d.ts +4 -4
  56. package/dist/bubbles/tool-bubble/get-trigger-detail-tool.d.ts +12 -12
  57. package/dist/bubbles/tool-bubble/google-maps-tool.d.ts +4 -4
  58. package/dist/bubbles/tool-bubble/instagram-tool.d.ts +4 -4
  59. package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.d.ts +2 -2
  60. package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.schema.d.ts +2 -2
  61. package/dist/bubbles/tool-bubble/linkedin-tool.d.ts +30 -30
  62. package/dist/bubbles/tool-bubble/list-airtable-bases-tool.d.ts +4 -4
  63. package/dist/bubbles/tool-bubble/list-airtable-tables-tool.d.ts +12 -12
  64. package/dist/bubbles/tool-bubble/list-bubbles-tool.d.ts +4 -4
  65. package/dist/bubbles/tool-bubble/people-search-tool.d.ts +4 -4
  66. package/dist/bubbles/tool-bubble/reddit-scrape-tool.d.ts +4 -4
  67. package/dist/bubbles/tool-bubble/research-agent-tool.d.ts +12 -4
  68. package/dist/bubbles/tool-bubble/research-agent-tool.d.ts.map +1 -1
  69. package/dist/bubbles/tool-bubble/research-agent-tool.js +168 -15
  70. package/dist/bubbles/tool-bubble/research-agent-tool.js.map +1 -1
  71. package/dist/bubbles/tool-bubble/sql-query-tool.d.ts +12 -12
  72. package/dist/bubbles/tool-bubble/tiktok-tool.d.ts +12 -12
  73. package/dist/bubbles/tool-bubble/tool-template.d.ts +4 -4
  74. package/dist/bubbles/tool-bubble/twitter-tool.d.ts +40 -40
  75. package/dist/bubbles/tool-bubble/web-crawl-tool.d.ts +8 -8
  76. package/dist/bubbles/tool-bubble/web-extract-tool.d.ts +8 -8
  77. package/dist/bubbles/tool-bubble/web-scrape-tool.d.ts +8 -8
  78. package/dist/bubbles/tool-bubble/web-search-tool.d.ts +4 -4
  79. package/dist/bubbles/tool-bubble/youtube-tool.d.ts +14 -14
  80. package/dist/bubbles/workflow-bubble/database-analyzer.workflow.d.ts +4 -4
  81. package/dist/bubbles/workflow-bubble/generate-document.workflow.d.ts +4 -4
  82. package/dist/bubbles/workflow-bubble/parse-document.workflow.d.ts +4 -4
  83. package/dist/bubbles/workflow-bubble/pdf-form-operations.workflow.d.ts +24 -24
  84. package/dist/bubbles/workflow-bubble/pdf-ocr.workflow.d.ts +8 -8
  85. package/dist/bubbles/workflow-bubble/slack-data-assistant.workflow.d.ts +4 -4
  86. package/dist/bubbles/workflow-bubble/slack-formatter-agent.d.ts +52 -52
  87. package/dist/bubbles/workflow-bubble/slack-notifier.workflow.d.ts +4 -4
  88. package/dist/bubbles.json +1 -1
  89. package/dist/index.d.ts +1 -1
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +1 -1
  92. package/dist/index.js.map +1 -1
  93. package/dist/utils/json-parsing.d.ts +9 -0
  94. package/dist/utils/json-parsing.d.ts.map +1 -1
  95. package/dist/utils/json-parsing.js +61 -2
  96. package/dist/utils/json-parsing.js.map +1 -1
  97. package/dist/utils/zod-schema.d.ts.map +1 -1
  98. package/dist/utils/zod-schema.js +16 -8
  99. package/dist/utils/zod-schema.js.map +1 -1
  100. package/package.json +2 -2
  101. package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.d.ts +0 -31
  102. package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.d.ts.map +0 -1
  103. package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.js +0 -184
  104. package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.js.map +0 -1
  105. package/dist/bubbles/service-bubble/google-sheets.d.ts +0 -1811
  106. package/dist/bubbles/service-bubble/google-sheets.d.ts.map +0 -1
  107. package/dist/bubbles/service-bubble/google-sheets.js +0 -904
  108. package/dist/bubbles/service-bubble/google-sheets.js.map +0 -1
  109. package/dist/bubbles/service-bubble/slack.d.ts +0 -5869
  110. package/dist/bubbles/service-bubble/slack.d.ts.map +0 -1
  111. package/dist/bubbles/service-bubble/slack.js +0 -1536
  112. package/dist/bubbles/service-bubble/slack.js.map +0 -1
  113. package/dist/recording/types.d.ts +0 -68
  114. package/dist/recording/types.d.ts.map +0 -1
  115. package/dist/recording/types.js +0 -13
  116. package/dist/recording/types.js.map +0 -1
@@ -1,1536 +0,0 @@
1
- import { z } from 'zod';
2
- import { ServiceBubble } from '../../types/service-bubble-class.js';
3
- import { CredentialType } from '@bubblelab/shared-schemas';
4
- // Slack API base URL
5
- const SLACK_API_BASE = 'https://slack.com/api';
6
- // Slack operation types are defined inline in the discriminated union below
7
- // Define Slack channel types
8
- const ChannelTypes = z
9
- .enum(['public_channel', 'private_channel', 'mpim', 'im'])
10
- .describe('Types of Slack channels: public_channel, private_channel, mpim (multi-person direct message), im (direct message)');
11
- // Define message attachment schema
12
- const MessageAttachmentSchema = z.object({
13
- color: z
14
- .string()
15
- .optional()
16
- .describe('Color bar accent (hex color or good/warning/danger)'),
17
- pretext: z
18
- .string()
19
- .optional()
20
- .describe('Text that appears before the main attachment content'),
21
- author_name: z
22
- .string()
23
- .optional()
24
- .describe('Author name displayed at the top'),
25
- author_link: z
26
- .string()
27
- .url()
28
- .optional()
29
- .describe('URL to link the author name'),
30
- author_icon: z.string().url().optional().describe('Author icon image URL'),
31
- title: z.string().optional().describe('Attachment title text'),
32
- title_link: z.string().url().optional().describe('URL to link the title'),
33
- text: z.string().optional().describe('Main attachment text content'),
34
- fields: z
35
- .array(z.object({
36
- title: z.string().describe('Field title'),
37
- value: z.string().describe('Field value'),
38
- short: z
39
- .boolean()
40
- .optional()
41
- .describe('Whether field should be displayed side-by-side'),
42
- }))
43
- .optional()
44
- .describe('Array of field objects for structured data'),
45
- image_url: z.string().url().optional().describe('URL of image to display'),
46
- thumb_url: z.string().url().optional().describe('URL of thumbnail image'),
47
- footer: z.string().optional().describe('Footer text'),
48
- footer_icon: z.string().url().optional().describe('Footer icon URL'),
49
- ts: z.number().optional().describe('Timestamp for the attachment'),
50
- });
51
- // Define block kit elements (simplified)
52
- const BlockElementSchema = z
53
- .object({
54
- type: z
55
- .string()
56
- .describe('Block element type (section, divider, button, etc.)'),
57
- text: z
58
- .object({
59
- type: z.enum(['plain_text', 'mrkdwn']).describe('Text formatting type'),
60
- text: z.string().describe('The actual text content'),
61
- emoji: z.boolean().optional(),
62
- verbatim: z.boolean().optional(),
63
- })
64
- .optional()
65
- .describe('Text object for the block element'),
66
- // Add elements field for context blocks
67
- elements: z
68
- .array(z.object({
69
- type: z
70
- .enum(['plain_text', 'mrkdwn', 'image'])
71
- .describe('Element type'),
72
- text: z.string().optional().describe('Text content'),
73
- image_url: z
74
- .string()
75
- .optional()
76
- .describe('Image URL for image elements'),
77
- alt_text: z
78
- .string()
79
- .optional()
80
- .describe('Alt text for image elements'),
81
- emoji: z.boolean().optional(),
82
- verbatim: z.boolean().optional(),
83
- }))
84
- .optional()
85
- .describe('Elements array for context blocks'),
86
- })
87
- .passthrough() // Allow additional properties for different block types
88
- .describe('Block Kit element for rich message formatting');
89
- // Define the parameters schema for different Slack operations
90
- const SlackParamsSchema = z.discriminatedUnion('operation', [
91
- // Send message operation
92
- z.object({
93
- operation: z
94
- .literal('send_message')
95
- .describe('Send a message to a Slack channel or DM'),
96
- channel: z
97
- .string()
98
- .min(1, 'Channel ID or name is required')
99
- .describe('Channel ID (e.g., C1234567890), channel name (e.g., general or #general), or user ID for DM'),
100
- text: z
101
- .string()
102
- .min(1, 'Message text is required')
103
- .describe('Message text content'),
104
- username: z
105
- .string()
106
- .optional()
107
- .describe('Override bot username for this message'),
108
- icon_emoji: z
109
- .string()
110
- .optional()
111
- .describe('Override bot icon with emoji (e.g., :robot_face:)'),
112
- icon_url: z
113
- .string()
114
- .url()
115
- .optional()
116
- .describe('Override bot icon with custom image URL'),
117
- attachments: z
118
- .array(MessageAttachmentSchema)
119
- .optional()
120
- .describe('Legacy message attachments'),
121
- blocks: z
122
- .array(BlockElementSchema)
123
- .optional()
124
- .describe('Block Kit structured message blocks'),
125
- thread_ts: z
126
- .string()
127
- .optional()
128
- .describe('Timestamp of parent message to reply in thread'),
129
- reply_broadcast: z
130
- .boolean()
131
- .optional()
132
- .default(false)
133
- .describe('Broadcast thread reply to channel'),
134
- credentials: z
135
- .record(z.nativeEnum(CredentialType), z.string())
136
- .optional()
137
- .describe('Object mapping credential types to values (injected at runtime)'),
138
- unfurl_links: z
139
- .boolean()
140
- .optional()
141
- .default(true)
142
- .describe('Enable automatic link unfurling'),
143
- unfurl_media: z
144
- .boolean()
145
- .optional()
146
- .default(true)
147
- .describe('Enable automatic media unfurling'),
148
- }),
149
- // List channels operation
150
- z.object({
151
- operation: z
152
- .literal('list_channels')
153
- .describe('List all channels in the Slack workspace'),
154
- types: z
155
- .array(ChannelTypes)
156
- .optional()
157
- .default(['public_channel', 'private_channel'])
158
- .describe('Types of channels to include in results'),
159
- exclude_archived: z
160
- .boolean()
161
- .optional()
162
- .default(true)
163
- .describe('Exclude archived channels from results'),
164
- limit: z
165
- .number()
166
- .min(1)
167
- .max(1000)
168
- .optional()
169
- .default(50)
170
- .describe('Maximum number of channels to return (1-1000)'),
171
- cursor: z
172
- .string()
173
- .optional()
174
- .describe('Cursor for pagination to get next set of results'),
175
- credentials: z
176
- .record(z.nativeEnum(CredentialType), z.string())
177
- .optional()
178
- .describe('Object mapping credential types to values (injected at runtime)'),
179
- }),
180
- // Get channel info operation
181
- z.object({
182
- operation: z
183
- .literal('get_channel_info')
184
- .describe('Get detailed information about a specific channel'),
185
- channel: z
186
- .string()
187
- .min(1, 'Channel ID or name is required')
188
- .describe('Channel ID (e.g., C1234567890) or channel name (e.g., general or #general)'),
189
- include_locale: z
190
- .boolean()
191
- .optional()
192
- .default(false)
193
- .describe('Include locale information in the response'),
194
- credentials: z
195
- .record(z.nativeEnum(CredentialType), z.string())
196
- .optional()
197
- .describe('Object mapping credential types to values (injected at runtime)'),
198
- }),
199
- // Get user info operation
200
- z.object({
201
- operation: z
202
- .literal('get_user_info')
203
- .describe('Get detailed information about a specific user'),
204
- user: z
205
- .string()
206
- .min(1, 'User ID is required')
207
- .describe('User ID to get information about'),
208
- include_locale: z
209
- .boolean()
210
- .optional()
211
- .default(false)
212
- .describe('Include locale information in the response'),
213
- credentials: z
214
- .record(z.nativeEnum(CredentialType), z.string())
215
- .optional()
216
- .describe('Object mapping credential types to values (injected at runtime)'),
217
- }),
218
- // List users operation
219
- z.object({
220
- operation: z
221
- .literal('list_users')
222
- .describe('List all users in the Slack workspace'),
223
- limit: z
224
- .number()
225
- .min(1)
226
- .max(1000)
227
- .optional()
228
- .default(50)
229
- .describe('Maximum number of users to return (1-1000)'),
230
- cursor: z
231
- .string()
232
- .optional()
233
- .describe('Cursor for pagination to get next set of results'),
234
- include_locale: z
235
- .boolean()
236
- .optional()
237
- .default(false)
238
- .describe('Include locale information in the response'),
239
- credentials: z
240
- .record(z.nativeEnum(CredentialType), z.string())
241
- .optional()
242
- .describe('Object mapping credential types to values (injected at runtime)'),
243
- }),
244
- // Get conversation history operation
245
- z.object({
246
- operation: z
247
- .literal('get_conversation_history')
248
- .describe('Retrieve message history from a channel or direct message'),
249
- channel: z
250
- .string()
251
- .min(1, 'Channel ID or name is required')
252
- .describe('Channel ID (e.g., C1234567890) or channel name (e.g., general or #general)'),
253
- latest: z
254
- .string()
255
- .optional()
256
- .describe('End of time range of messages to include (timestamp)'),
257
- oldest: z
258
- .string()
259
- .optional()
260
- .describe('Start of time range of messages to include (timestamp)'),
261
- inclusive: z
262
- .boolean()
263
- .optional()
264
- .default(false)
265
- .describe('Include messages with latest or oldest timestamps in results'),
266
- limit: z
267
- .number()
268
- .min(1)
269
- .max(1000)
270
- .optional()
271
- .default(20)
272
- .describe('Maximum number of messages to return (1-1000)'),
273
- cursor: z
274
- .string()
275
- .optional()
276
- .describe('Cursor for pagination to get next set of results'),
277
- credentials: z
278
- .record(z.nativeEnum(CredentialType), z.string())
279
- .optional()
280
- .describe('Object mapping credential types to values (injected at runtime)'),
281
- }),
282
- // Get thread replies operation
283
- z.object({
284
- operation: z
285
- .literal('get_thread_replies')
286
- .describe('Retrieve all replies to a thread in a channel'),
287
- channel: z
288
- .string()
289
- .min(1, 'Channel ID is required')
290
- .describe('Channel ID where the thread exists'),
291
- ts: z
292
- .string()
293
- .min(1, 'Thread timestamp is required')
294
- .describe('Timestamp of the parent message to get replies for'),
295
- latest: z
296
- .string()
297
- .optional()
298
- .describe('End of time range of messages to include (timestamp)'),
299
- oldest: z
300
- .string()
301
- .optional()
302
- .describe('Start of time range of messages to include (timestamp)'),
303
- inclusive: z
304
- .boolean()
305
- .optional()
306
- .default(false)
307
- .describe('Include messages with latest or oldest timestamps in results'),
308
- limit: z
309
- .number()
310
- .min(1)
311
- .max(1000)
312
- .optional()
313
- .default(100)
314
- .describe('Maximum number of messages to return (1-1000)'),
315
- cursor: z
316
- .string()
317
- .optional()
318
- .describe('Cursor for pagination to get next set of results'),
319
- credentials: z
320
- .record(z.nativeEnum(CredentialType), z.string())
321
- .optional()
322
- .describe('Object mapping credential types to values (injected at runtime)'),
323
- }),
324
- // Update message operation
325
- z.object({
326
- operation: z
327
- .literal('update_message')
328
- .describe('Update an existing message in a channel'),
329
- channel: z
330
- .string()
331
- .min(1, 'Channel ID or name is required')
332
- .describe('Channel ID (e.g., C1234567890) or channel name (e.g., general or #general) where the message is located'),
333
- ts: z
334
- .string()
335
- .min(1, 'Message timestamp is required')
336
- .describe('Timestamp of the message to update'),
337
- text: z.string().optional().describe('New text content for the message'),
338
- attachments: z
339
- .array(MessageAttachmentSchema)
340
- .optional()
341
- .describe('New legacy message attachments'),
342
- blocks: z
343
- .array(BlockElementSchema)
344
- .optional()
345
- .describe('New Block Kit structured message blocks'),
346
- credentials: z
347
- .record(z.nativeEnum(CredentialType), z.string())
348
- .optional()
349
- .describe('Object mapping credential types to values (injected at runtime)'),
350
- }),
351
- // Delete message operation
352
- z.object({
353
- operation: z
354
- .literal('delete_message')
355
- .describe('Delete a message from a channel'),
356
- channel: z
357
- .string()
358
- .min(1, 'Channel ID or name is required')
359
- .describe('Channel ID (e.g., C1234567890) or channel name (e.g., general or #general) where the message is located'),
360
- ts: z
361
- .string()
362
- .min(1, 'Message timestamp is required')
363
- .describe('Timestamp of the message to delete'),
364
- credentials: z
365
- .record(z.nativeEnum(CredentialType), z.string())
366
- .optional()
367
- .describe('Object mapping credential types to values (injected at runtime)'),
368
- }),
369
- // Add reaction operation
370
- z.object({
371
- operation: z
372
- .literal('add_reaction')
373
- .describe('Add an emoji reaction to a message'),
374
- name: z
375
- .string()
376
- .min(1, 'Emoji name is required')
377
- .describe('Emoji name without colons (e.g., thumbsup, heart)'),
378
- channel: z
379
- .string()
380
- .min(1, 'Channel ID or name is required')
381
- .describe('Channel ID (e.g., C1234567890) or channel name (e.g., general or #general) where the message is located'),
382
- timestamp: z
383
- .string()
384
- .min(1, 'Message timestamp is required')
385
- .describe('Timestamp of the message to react to'),
386
- credentials: z
387
- .record(z.nativeEnum(CredentialType), z.string())
388
- .optional()
389
- .describe('Object mapping credential types to values (injected at runtime)'),
390
- }),
391
- // Remove reaction operation
392
- z.object({
393
- operation: z
394
- .literal('remove_reaction')
395
- .describe('Remove an emoji reaction from a message'),
396
- name: z
397
- .string()
398
- .min(1, 'Emoji name is required')
399
- .describe('Emoji name without colons (e.g., thumbsup, heart)'),
400
- channel: z
401
- .string()
402
- .min(1, 'Channel ID or name is required')
403
- .describe('Channel ID (e.g., C1234567890) or channel name (e.g., general or #general) where the message is located'),
404
- timestamp: z
405
- .string()
406
- .min(1, 'Message timestamp is required')
407
- .describe('Timestamp of the message to remove reaction from'),
408
- credentials: z
409
- .record(z.nativeEnum(CredentialType), z.string())
410
- .optional()
411
- .describe('Object mapping credential types to values (injected at runtime)'),
412
- }),
413
- // Upload file operation
414
- z.object({
415
- operation: z
416
- .literal('upload_file')
417
- .describe('Upload a file to a Slack channel'),
418
- channel: z
419
- .string()
420
- .min(1, 'Channel ID or name is required')
421
- .describe('Channel ID (e.g., C1234567890), channel name (e.g., general or #general), or user ID for DM'),
422
- file_path: z
423
- .string()
424
- .min(1, 'File path is required')
425
- .describe('Local file path to upload'),
426
- filename: z
427
- .string()
428
- .optional()
429
- .describe('Override filename for the upload'),
430
- title: z.string().optional().describe('Title for the file'),
431
- initial_comment: z
432
- .string()
433
- .optional()
434
- .describe('Initial comment to post with the file'),
435
- thread_ts: z
436
- .string()
437
- .optional()
438
- .describe('Timestamp of parent message to upload file in thread'),
439
- credentials: z
440
- .record(z.nativeEnum(CredentialType), z.string())
441
- .optional()
442
- .describe('Object mapping credential types to values (injected at runtime)'),
443
- }),
444
- ]);
445
- // Define Slack API response schemas for type safety
446
- const SlackChannelSchema = z
447
- .object({
448
- id: z.string().describe('Unique channel identifier'),
449
- name: z.string().describe('Channel name without # prefix'),
450
- is_channel: z
451
- .boolean()
452
- .optional()
453
- .describe('True if this is a public channel'),
454
- is_group: z
455
- .boolean()
456
- .optional()
457
- .describe('True if this is a private channel'),
458
- is_im: z.boolean().optional().describe('True if this is a direct message'),
459
- is_mpim: z
460
- .boolean()
461
- .optional()
462
- .describe('True if this is a multi-person direct message'),
463
- is_private: z
464
- .boolean()
465
- .optional()
466
- .describe('True if this is a private channel'),
467
- created: z.number().describe('Unix timestamp when channel was created'),
468
- is_archived: z.boolean().describe('True if channel is archived'),
469
- is_general: z
470
- .boolean()
471
- .optional()
472
- .describe('True if this is the #general channel'),
473
- unlinked: z
474
- .number()
475
- .optional()
476
- .describe('Unix timestamp when channel was unlinked'),
477
- name_normalized: z.string().optional().describe('Normalized channel name'),
478
- is_shared: z
479
- .boolean()
480
- .optional()
481
- .describe('True if channel is shared with other workspaces'),
482
- is_ext_shared: z
483
- .boolean()
484
- .optional()
485
- .describe('True if channel is shared externally'),
486
- is_org_shared: z
487
- .boolean()
488
- .optional()
489
- .describe('True if channel is shared across organization'),
490
- shared_team_ids: z
491
- .array(z.string())
492
- .optional()
493
- .describe('IDs of teams this channel is shared with'),
494
- pending_shared: z
495
- .array(z.string())
496
- .optional()
497
- .describe('Pending shared connections'),
498
- pending_connected_team_ids: z
499
- .array(z.string())
500
- .optional()
501
- .describe('Pending team connection IDs'),
502
- is_pending_ext_shared: z
503
- .boolean()
504
- .optional()
505
- .describe('True if external sharing is pending'),
506
- is_member: z
507
- .boolean()
508
- .optional()
509
- .describe('True if the bot is a member of this channel'),
510
- is_open: z.boolean().optional().describe('True if the channel is open'),
511
- topic: z
512
- .object({
513
- value: z.string().describe('Topic text'),
514
- creator: z.string().describe('User ID who set the topic'),
515
- last_set: z.number().describe('Unix timestamp when topic was last set'),
516
- })
517
- .optional()
518
- .describe('Channel topic information'),
519
- purpose: z
520
- .object({
521
- value: z.string().describe('Purpose text'),
522
- creator: z.string().describe('User ID who set the purpose'),
523
- last_set: z
524
- .number()
525
- .describe('Unix timestamp when purpose was last set'),
526
- })
527
- .optional()
528
- .describe('Channel purpose information'),
529
- num_members: z
530
- .number()
531
- .optional()
532
- .describe('Number of members in the channel'),
533
- })
534
- .describe('Slack channel object with metadata');
535
- const SlackUserSchema = z
536
- .object({
537
- id: z.string().describe('Unique user identifier'),
538
- team_id: z.string().optional().describe('Team/workspace ID'),
539
- name: z.string().describe('Username (handle without @)'),
540
- deleted: z.boolean().optional().describe('True if user account is deleted'),
541
- color: z.string().optional().describe('Color code for user in UI'),
542
- real_name: z.string().optional().describe('Users real name'),
543
- tz: z.string().optional().describe('Timezone identifier'),
544
- tz_label: z.string().optional().describe('Human-readable timezone label'),
545
- tz_offset: z
546
- .number()
547
- .optional()
548
- .describe('Timezone offset from UTC in seconds'),
549
- profile: z
550
- .object({
551
- title: z.string().optional().describe('Job title'),
552
- phone: z.string().optional().describe('Phone number'),
553
- skype: z.string().optional().describe('Skype username'),
554
- real_name: z.string().optional().describe('Real name from profile'),
555
- real_name_normalized: z
556
- .string()
557
- .optional()
558
- .describe('Normalized real name'),
559
- display_name: z.string().optional().describe('Display name'),
560
- display_name_normalized: z
561
- .string()
562
- .optional()
563
- .describe('Normalized display name'),
564
- fields: z
565
- .record(z.unknown())
566
- .optional()
567
- .describe('Custom profile fields'),
568
- status_text: z.string().optional().describe('Current status text'),
569
- status_emoji: z.string().optional().describe('Current status emoji'),
570
- status_expiration: z
571
- .number()
572
- .optional()
573
- .describe('Unix timestamp when status expires'),
574
- avatar_hash: z.string().optional().describe('Hash for avatar image'),
575
- image_original: z
576
- .string()
577
- .optional()
578
- .describe('URL of original avatar image'),
579
- is_custom_image: z
580
- .boolean()
581
- .optional()
582
- .describe('True if using custom avatar'),
583
- email: z.string().optional().describe('Email address'),
584
- first_name: z.string().optional().describe('First name'),
585
- last_name: z.string().optional().describe('Last name'),
586
- image_24: z.string().optional().describe('24x24 pixel avatar URL'),
587
- image_32: z.string().optional().describe('32x32 pixel avatar URL'),
588
- image_48: z.string().optional().describe('48x48 pixel avatar URL'),
589
- image_72: z.string().optional().describe('72x72 pixel avatar URL'),
590
- image_192: z.string().optional().describe('192x192 pixel avatar URL'),
591
- image_512: z.string().optional().describe('512x512 pixel avatar URL'),
592
- image_1024: z
593
- .string()
594
- .optional()
595
- .describe('1024x1024 pixel avatar URL'),
596
- })
597
- .optional()
598
- .describe('User profile information'),
599
- is_admin: z
600
- .boolean()
601
- .optional()
602
- .describe('True if user is workspace admin'),
603
- is_owner: z
604
- .boolean()
605
- .optional()
606
- .describe('True if user is workspace owner'),
607
- is_primary_owner: z
608
- .boolean()
609
- .optional()
610
- .describe('True if user is primary workspace owner'),
611
- is_restricted: z
612
- .boolean()
613
- .optional()
614
- .describe('True if user is restricted (single-channel guest)'),
615
- is_ultra_restricted: z
616
- .boolean()
617
- .optional()
618
- .describe('True if user is ultra restricted (multi-channel guest)'),
619
- is_bot: z.boolean().optional().describe('True if this is a bot user'),
620
- is_app_user: z.boolean().optional().describe('True if this is an app user'),
621
- updated: z
622
- .number()
623
- .optional()
624
- .describe('Unix timestamp when user was last updated'),
625
- has_2fa: z
626
- .boolean()
627
- .optional()
628
- .describe('True if user has two-factor authentication enabled'),
629
- })
630
- .describe('Slack user object with profile and permissions');
631
- const SlackMessageSchema = z
632
- .object({
633
- type: z.string().describe('Message type (usually "message")'),
634
- ts: z.string().describe('Message timestamp (unique identifier)'),
635
- user: z.string().optional().describe('User ID who sent the message'),
636
- bot_id: z
637
- .string()
638
- .optional()
639
- .describe('Bot ID if message was sent by a bot'),
640
- bot_profile: z
641
- .object({
642
- name: z.string().optional().describe('Bot display name'),
643
- })
644
- .optional()
645
- .describe('Bot profile information if message was sent by a bot'),
646
- username: z
647
- .string()
648
- .optional()
649
- .describe('Username of the bot or user who sent the message'),
650
- text: z.string().optional().describe('Message text content'),
651
- thread_ts: z
652
- .string()
653
- .optional()
654
- .describe('Timestamp of parent message if this is a thread reply'),
655
- parent_user_id: z
656
- .string()
657
- .optional()
658
- .describe('User ID of thread parent message author'),
659
- reply_count: z
660
- .number()
661
- .optional()
662
- .describe('Number of replies in this thread'),
663
- reply_users_count: z
664
- .number()
665
- .optional()
666
- .describe('Number of unique users who replied in thread'),
667
- latest_reply: z
668
- .string()
669
- .optional()
670
- .describe('Timestamp of most recent reply in thread'),
671
- reply_users: z
672
- .array(z.string())
673
- .optional()
674
- .describe('Array of user IDs who replied in thread'),
675
- is_locked: z.boolean().optional().describe('True if thread is locked'),
676
- subscribed: z
677
- .boolean()
678
- .optional()
679
- .describe('True if current user is subscribed to thread'),
680
- attachments: z
681
- .array(z.unknown())
682
- .optional()
683
- .describe('Legacy message attachments'),
684
- blocks: z
685
- .array(z.unknown())
686
- .optional()
687
- .describe('Block Kit structured content'),
688
- reactions: z
689
- .array(z.object({
690
- name: z.string().describe('Emoji name without colons'),
691
- users: z
692
- .array(z.string())
693
- .describe('User IDs who reacted with this emoji'),
694
- count: z.number().describe('Total count of this reaction'),
695
- }))
696
- .optional()
697
- .describe('Array of emoji reactions on this message'),
698
- })
699
- .describe('Slack message object with content and metadata');
700
- // Define result schemas for different operations
701
- const SlackResultSchema = z.discriminatedUnion('operation', [
702
- z.object({
703
- operation: z
704
- .literal('send_message')
705
- .describe('Send a message to a Slack channel or DM'),
706
- ok: z.boolean().describe('Whether the Slack API call was successful'),
707
- channel: z
708
- .string()
709
- .optional()
710
- .describe('Channel ID where the message was sent'),
711
- ts: z.string().optional().describe('Timestamp of the sent message'),
712
- message: SlackMessageSchema.optional().describe('Details of the sent message'),
713
- error: z.string().describe('Error message if operation failed'),
714
- success: z.boolean().describe('Whether the operation was successful'),
715
- }),
716
- z.object({
717
- operation: z
718
- .literal('list_channels')
719
- .describe('List all channels in the Slack workspace'),
720
- ok: z.boolean().describe('Whether the Slack API call was successful'),
721
- channels: z
722
- .array(SlackChannelSchema)
723
- .optional()
724
- .describe('Array of channel objects'),
725
- response_metadata: z
726
- .object({
727
- next_cursor: z
728
- .string()
729
- .describe('Cursor for pagination to get next set of results'),
730
- })
731
- .optional()
732
- .describe('Metadata for pagination'),
733
- error: z.string().describe('Error message if operation failed'),
734
- success: z.boolean().describe('Whether the operation was successful'),
735
- }),
736
- z.object({
737
- operation: z
738
- .literal('get_channel_info')
739
- .describe('Get detailed information about a specific channel'),
740
- ok: z.boolean().describe('Whether the Slack API call was successful'),
741
- channel: SlackChannelSchema.optional().describe('Channel information object'),
742
- error: z.string().describe('Error message if operation failed'),
743
- success: z.boolean().describe('Whether the operation was successful'),
744
- }),
745
- z.object({
746
- operation: z
747
- .literal('get_user_info')
748
- .describe('Get detailed information about a specific user'),
749
- ok: z.boolean().describe('Whether the Slack API call was successful'),
750
- user: SlackUserSchema.optional().describe('User information object'),
751
- error: z.string().describe('Error message if operation failed'),
752
- success: z.boolean().describe('Whether the operation was successful'),
753
- }),
754
- z.object({
755
- operation: z
756
- .literal('list_users')
757
- .describe('List all users in the Slack workspace'),
758
- ok: z.boolean().describe('Whether the Slack API call was successful'),
759
- members: z
760
- .array(SlackUserSchema)
761
- .optional()
762
- .describe('Array of user objects'),
763
- response_metadata: z
764
- .object({
765
- next_cursor: z
766
- .string()
767
- .describe('Cursor for pagination to get next set of results'),
768
- })
769
- .optional()
770
- .describe('Metadata for pagination'),
771
- error: z.string().describe('Error message if operation failed'),
772
- success: z.boolean().describe('Whether the operation was successful'),
773
- }),
774
- z.object({
775
- operation: z
776
- .literal('get_conversation_history')
777
- .describe('Retrieve message history from a channel or direct message'),
778
- ok: z.boolean().describe('Whether the Slack API call was successful'),
779
- messages: z
780
- .array(SlackMessageSchema)
781
- .optional()
782
- .describe('Array of message objects'),
783
- has_more: z
784
- .boolean()
785
- .optional()
786
- .describe('Whether there are more messages to retrieve'),
787
- response_metadata: z
788
- .object({
789
- next_cursor: z
790
- .string()
791
- .describe('Cursor for pagination to get next set of results'),
792
- })
793
- .optional()
794
- .describe('Metadata for pagination'),
795
- error: z.string().describe('Error message if operation failed'),
796
- success: z.boolean().describe('Whether the operation was successful'),
797
- }),
798
- z.object({
799
- operation: z
800
- .literal('get_thread_replies')
801
- .describe('Retrieve all replies to a thread in a channel'),
802
- ok: z.boolean().describe('Whether the Slack API call was successful'),
803
- messages: z
804
- .array(SlackMessageSchema)
805
- .optional()
806
- .describe('Array of message objects in the thread'),
807
- has_more: z
808
- .boolean()
809
- .optional()
810
- .describe('Whether there are more messages to retrieve'),
811
- response_metadata: z
812
- .object({
813
- next_cursor: z
814
- .string()
815
- .describe('Cursor for pagination to get next set of results'),
816
- })
817
- .optional()
818
- .describe('Metadata for pagination'),
819
- error: z.string().describe('Error message if operation failed'),
820
- success: z.boolean().describe('Whether the operation was successful'),
821
- }),
822
- z.object({
823
- operation: z
824
- .literal('update_message')
825
- .describe('Update an existing message in a channel'),
826
- ok: z.boolean().describe('Whether the Slack API call was successful'),
827
- channel: z
828
- .string()
829
- .optional()
830
- .describe('Channel ID where the message was updated'),
831
- ts: z.string().optional().describe('Timestamp of the updated message'),
832
- text: z.string().optional().describe('Updated text content of the message'),
833
- message: SlackMessageSchema.optional().describe('Details of the updated message'),
834
- error: z.string().describe('Error message if operation failed'),
835
- success: z.boolean().describe('Whether the operation was successful'),
836
- }),
837
- z.object({
838
- operation: z
839
- .literal('delete_message')
840
- .describe('Delete a message from a channel'),
841
- ok: z.boolean().describe('Whether the Slack API call was successful'),
842
- channel: z
843
- .string()
844
- .optional()
845
- .describe('Channel ID where the message was deleted'),
846
- ts: z.string().optional().describe('Timestamp of the deleted message'),
847
- error: z.string().describe('Error message if operation failed'),
848
- success: z.boolean().describe('Whether the operation was successful'),
849
- }),
850
- z.object({
851
- operation: z
852
- .literal('add_reaction')
853
- .describe('Add an emoji reaction to a message'),
854
- ok: z.boolean().describe('Whether the Slack API call was successful'),
855
- error: z.string().describe('Error message if operation failed'),
856
- success: z.boolean().describe('Whether the operation was successful'),
857
- }),
858
- z.object({
859
- operation: z
860
- .literal('remove_reaction')
861
- .describe('Remove an emoji reaction from a message'),
862
- ok: z.boolean().describe('Whether the Slack API call was successful'),
863
- error: z.string().describe('Error message if operation failed'),
864
- success: z.boolean().describe('Whether the operation was successful'),
865
- }),
866
- z.object({
867
- operation: z
868
- .literal('upload_file')
869
- .describe('Upload a file to a Slack channel'),
870
- ok: z.boolean().describe('Whether the Slack API call was successful'),
871
- file: z
872
- .object({
873
- id: z.string().describe('Unique file identifier'),
874
- created: z.number().describe('Unix timestamp when file was created'),
875
- timestamp: z.number().describe('Unix timestamp when file was uploaded'),
876
- name: z.string().describe('Original filename'),
877
- title: z.string().optional().describe('File title'),
878
- mimetype: z.string().describe('MIME type of the file'),
879
- filetype: z.string().describe('File type extension'),
880
- pretty_type: z.string().describe('Human-readable file type'),
881
- user: z.string().describe('User ID who uploaded the file'),
882
- editable: z.boolean().describe('Whether the file is editable'),
883
- size: z.number().describe('File size in bytes'),
884
- mode: z.string().describe('File sharing mode'),
885
- is_external: z
886
- .boolean()
887
- .describe('Whether file is from external source'),
888
- external_type: z.string().describe('External file type if applicable'),
889
- is_public: z.boolean().describe('Whether file is publicly accessible'),
890
- public_url_shared: z.boolean().describe('Whether public URL is shared'),
891
- display_as_bot: z
892
- .boolean()
893
- .describe('Whether file is displayed as uploaded by bot'),
894
- username: z.string().describe('Username of uploader'),
895
- url_private: z.string().describe('Private URL to access file'),
896
- url_private_download: z.string().describe('Private download URL'),
897
- permalink: z.string().describe('Permanent link to file'),
898
- permalink_public: z
899
- .string()
900
- .optional()
901
- .describe('Public permanent link'),
902
- shares: z
903
- .object({
904
- public: z
905
- .record(z.array(z.object({
906
- reply_users: z
907
- .array(z.string())
908
- .describe('User IDs who replied'),
909
- reply_users_count: z
910
- .number()
911
- .describe('Number of unique users who replied'),
912
- reply_count: z.number().describe('Total number of replies'),
913
- ts: z.string().describe('Timestamp of the share'),
914
- channel_name: z.string().describe('Name of the channel'),
915
- team_id: z.string().describe('Team ID'),
916
- })))
917
- .optional()
918
- .describe('Public channel shares'),
919
- private: z
920
- .record(z.array(z.object({
921
- reply_users: z
922
- .array(z.string())
923
- .describe('User IDs who replied'),
924
- reply_users_count: z
925
- .number()
926
- .describe('Number of unique users who replied'),
927
- reply_count: z.number().describe('Total number of replies'),
928
- ts: z.string().describe('Timestamp of the share'),
929
- channel_name: z.string().describe('Name of the channel'),
930
- team_id: z.string().describe('Team ID'),
931
- })))
932
- .optional()
933
- .describe('Private channel shares'),
934
- })
935
- .optional()
936
- .describe('Information about where file is shared'),
937
- channels: z
938
- .array(z.string())
939
- .optional()
940
- .describe('Channel IDs where file is shared'),
941
- groups: z
942
- .array(z.string())
943
- .optional()
944
- .describe('Private group IDs where file is shared'),
945
- ims: z
946
- .array(z.string())
947
- .optional()
948
- .describe('Direct message IDs where file is shared'),
949
- has_rich_preview: z
950
- .boolean()
951
- .optional()
952
- .describe('Whether file has rich preview'),
953
- })
954
- .optional()
955
- .describe('File information object'),
956
- error: z.string().describe('Error message if operation failed'),
957
- success: z.boolean().describe('Whether the operation was successful'),
958
- }),
959
- ]);
960
- export class SlackBubble extends ServiceBubble {
961
- async testCredential() {
962
- // Make a test API call to the Slack API
963
- const response = await this.makeSlackApiCall('auth.test', {});
964
- if (response.ok) {
965
- return true;
966
- }
967
- return false;
968
- }
969
- static type = 'service';
970
- static service = 'slack';
971
- static authType = 'apikey';
972
- static bubbleName = 'slack';
973
- static schema = SlackParamsSchema;
974
- static resultSchema = SlackResultSchema;
975
- static shortDescription = 'Slack integration for messaging and workspace management';
976
- static longDescription = `
977
- Comprehensive Slack integration bubble for managing messages, channels, and users.
978
- Use cases:
979
- - Send messages to channels or direct messages
980
- - Retrieve channel information and list channels
981
- - Get user information and list workspace members
982
- - Manage conversation history and message operations
983
- - Add/remove reactions and manage message interactions
984
-
985
- Security Features:
986
- - Token-based authentication
987
- - Parameter validation and sanitization
988
- - Rate limiting awareness
989
- - Comprehensive error handling
990
- `;
991
- static alias = 'slack';
992
- constructor(params = {
993
- operation: 'list_channels',
994
- }, context, instanceId) {
995
- super(params, context, instanceId);
996
- }
997
- async performAction(context) {
998
- // Context is available but not currently used in this implementation
999
- void context;
1000
- const { operation } = this.params;
1001
- try {
1002
- const result = await (async () => {
1003
- switch (operation) {
1004
- case 'send_message':
1005
- return await this.sendMessage(this.params);
1006
- case 'list_channels':
1007
- return await this.listChannels(this.params);
1008
- case 'get_channel_info':
1009
- return await this.getChannelInfo(this.params);
1010
- case 'get_user_info':
1011
- return await this.getUserInfo(this.params);
1012
- case 'list_users':
1013
- return await this.listUsers(this.params);
1014
- case 'get_conversation_history':
1015
- return await this.getConversationHistory(this.params);
1016
- case 'get_thread_replies':
1017
- return await this.getThreadReplies(this.params);
1018
- case 'update_message':
1019
- return await this.updateMessage(this.params);
1020
- case 'delete_message':
1021
- return await this.deleteMessage(this.params);
1022
- case 'add_reaction':
1023
- return await this.addReaction(this.params);
1024
- case 'remove_reaction':
1025
- return await this.removeReaction(this.params);
1026
- case 'upload_file':
1027
- return await this.uploadFile(this.params);
1028
- default:
1029
- throw new Error(`Unsupported operation: ${operation}`);
1030
- }
1031
- })();
1032
- // The result is guaranteed to match T['operation'] because of the discriminated union
1033
- return result;
1034
- }
1035
- catch (error) {
1036
- const failedOperation = this.params.operation;
1037
- return {
1038
- success: false,
1039
- ok: false,
1040
- operation: failedOperation,
1041
- error: error instanceof Error
1042
- ? error.message
1043
- : 'Unknown error occurred in SlackBubble',
1044
- };
1045
- }
1046
- }
1047
- /**
1048
- * Helper method to resolve channel names to channel IDs.
1049
- * If the input looks like a channel ID (starts with C, G, or D), returns it as-is.
1050
- * Otherwise, searches for a channel with the given name.
1051
- */
1052
- async resolveChannelId(channelInput) {
1053
- // Check if input is already a channel ID (starts with C, G, D, etc.)
1054
- if (/^[CGD][A-Z0-9]+$/i.test(channelInput)) {
1055
- return channelInput;
1056
- }
1057
- // Remove # prefix if present
1058
- const channelName = channelInput.replace(/^#/, '');
1059
- // Get all channels to find the matching name
1060
- const response = await this.makeSlackApiCall('conversations.list', {
1061
- types: 'public_channel,private_channel',
1062
- exclude_archived: 'true',
1063
- limit: '1000', // Get a large batch to find the channel
1064
- }, 'GET');
1065
- if (!response.ok) {
1066
- throw new Error(`Failed to list channels: ${response.error}`);
1067
- }
1068
- const channels = response.channels;
1069
- const matchedChannel = channels.find((channel) => channel.name.toLowerCase() === channelName.toLowerCase());
1070
- if (!matchedChannel) {
1071
- throw new Error(`Channel "${channelName}" not found. Available channels: ${channels.map((c) => c.name).join(', ')}`);
1072
- }
1073
- return matchedChannel.id;
1074
- }
1075
- async sendMessage(params) {
1076
- const { channel, text, username, icon_emoji, icon_url, attachments, blocks, thread_ts, reply_broadcast, unfurl_links, unfurl_media, } = params;
1077
- // Resolve channel name to ID if needed
1078
- const resolvedChannel = await this.resolveChannelId(channel);
1079
- const body = {
1080
- channel: resolvedChannel,
1081
- text,
1082
- unfurl_links,
1083
- unfurl_media,
1084
- };
1085
- if (username)
1086
- body.username = username;
1087
- if (icon_emoji)
1088
- body.icon_emoji = icon_emoji;
1089
- if (icon_url)
1090
- body.icon_url = icon_url;
1091
- if (attachments)
1092
- body.attachments = JSON.stringify(attachments);
1093
- if (blocks)
1094
- body.blocks = JSON.stringify(blocks);
1095
- if (thread_ts) {
1096
- body.thread_ts = thread_ts;
1097
- body.reply_broadcast = reply_broadcast;
1098
- }
1099
- console.log('sending blocks', body.blocks);
1100
- const response = await this.makeSlackApiCall('chat.postMessage', body);
1101
- return {
1102
- operation: 'send_message',
1103
- ok: response.ok,
1104
- channel: response.ok ? response.channel : undefined,
1105
- ts: response.ok ? response.ts : undefined,
1106
- message: response.ok && response.message
1107
- ? SlackMessageSchema.parse(response.message)
1108
- : undefined,
1109
- error: !response.ok ? JSON.stringify(response, null, 2) : '',
1110
- success: response.ok,
1111
- };
1112
- }
1113
- async listChannels(params) {
1114
- // Parse the params to apply defaults
1115
- const parsed = SlackParamsSchema.parse(params);
1116
- const { types, exclude_archived, limit, cursor } = parsed;
1117
- const queryParams = {
1118
- types: types.join(','),
1119
- exclude_archived: exclude_archived.toString(),
1120
- limit: limit.toString(),
1121
- };
1122
- if (cursor)
1123
- queryParams.cursor = cursor;
1124
- const response = await this.makeSlackApiCall('conversations.list', queryParams, 'GET');
1125
- return {
1126
- operation: 'list_channels',
1127
- ok: response.ok,
1128
- channels: response.ok && response.channels
1129
- ? z.array(SlackChannelSchema).parse(response.channels)
1130
- : undefined,
1131
- response_metadata: response.ok && response.response_metadata
1132
- ? {
1133
- next_cursor: response.response_metadata.next_cursor,
1134
- }
1135
- : undefined,
1136
- error: !response.ok ? JSON.stringify(response, null, 2) : '',
1137
- success: response.ok,
1138
- };
1139
- }
1140
- async getChannelInfo(params) {
1141
- // Parse the params to apply defaults
1142
- const parsed = SlackParamsSchema.parse(params);
1143
- const { channel, include_locale } = parsed;
1144
- // Resolve channel name to ID if needed
1145
- const resolvedChannel = await this.resolveChannelId(channel);
1146
- const queryParams = {
1147
- channel: resolvedChannel,
1148
- include_locale: include_locale.toString(),
1149
- };
1150
- const response = await this.makeSlackApiCall('conversations.info', queryParams, 'GET');
1151
- return {
1152
- operation: 'get_channel_info',
1153
- ok: response.ok,
1154
- channel: response.ok && response.channel
1155
- ? SlackChannelSchema.parse(response.channel)
1156
- : undefined,
1157
- error: !response.ok ? JSON.stringify(response, null, 2) : '',
1158
- success: response.ok,
1159
- };
1160
- }
1161
- async getUserInfo(params) {
1162
- // Parse the params to apply defaults
1163
- const parsed = SlackParamsSchema.parse(params);
1164
- const { user, include_locale } = parsed;
1165
- const queryParams = {
1166
- user,
1167
- include_locale: include_locale.toString(),
1168
- };
1169
- const response = await this.makeSlackApiCall('users.info', queryParams, 'GET');
1170
- return {
1171
- operation: 'get_user_info',
1172
- ok: response.ok,
1173
- user: response.ok && response.user
1174
- ? SlackUserSchema.parse(response.user)
1175
- : undefined,
1176
- error: !response.ok ? JSON.stringify(response, null, 2) : '',
1177
- success: response.ok,
1178
- };
1179
- }
1180
- async listUsers(params) {
1181
- // Parse the params to apply defaults
1182
- const parsed = SlackParamsSchema.parse(params);
1183
- const { limit, cursor, include_locale } = parsed;
1184
- const queryParams = {
1185
- limit: limit.toString(),
1186
- include_locale: include_locale.toString(),
1187
- };
1188
- if (cursor)
1189
- queryParams.cursor = cursor;
1190
- const response = await this.makeSlackApiCall('users.list', queryParams, 'GET');
1191
- return {
1192
- operation: 'list_users',
1193
- ok: response.ok,
1194
- members: response.ok && response.members
1195
- ? z.array(SlackUserSchema).parse(response.members)
1196
- : undefined,
1197
- response_metadata: response.ok && response.response_metadata
1198
- ? {
1199
- next_cursor: response.response_metadata.next_cursor,
1200
- }
1201
- : undefined,
1202
- error: !response.ok ? JSON.stringify(response, null, 2) : '',
1203
- success: response.ok,
1204
- };
1205
- }
1206
- async getConversationHistory(params) {
1207
- // Parse the params to apply defaults
1208
- const parsed = SlackParamsSchema.parse(params);
1209
- const { channel, latest, oldest, inclusive, limit, cursor } = parsed;
1210
- // Resolve channel name to ID if needed
1211
- const resolvedChannel = await this.resolveChannelId(channel);
1212
- const queryParams = {
1213
- channel: resolvedChannel,
1214
- inclusive: inclusive.toString(),
1215
- limit: limit.toString(),
1216
- };
1217
- if (latest)
1218
- queryParams.latest = latest;
1219
- if (oldest)
1220
- queryParams.oldest = oldest;
1221
- if (cursor)
1222
- queryParams.cursor = cursor;
1223
- const response = await this.makeSlackApiCall('conversations.history', queryParams, 'GET');
1224
- return {
1225
- operation: 'get_conversation_history',
1226
- ok: response.ok,
1227
- messages: response.ok && response.messages
1228
- ? z.array(SlackMessageSchema).parse(response.messages)
1229
- : undefined,
1230
- has_more: response.ok ? response.has_more : undefined,
1231
- response_metadata: response.ok && response.response_metadata
1232
- ? {
1233
- next_cursor: response.response_metadata.next_cursor,
1234
- }
1235
- : undefined,
1236
- error: !response.ok ? JSON.stringify(response, null, 2) : '',
1237
- success: response.ok,
1238
- };
1239
- }
1240
- async getThreadReplies(params) {
1241
- // Parse the params to apply defaults
1242
- const parsed = SlackParamsSchema.parse(params);
1243
- const { channel, ts, latest, oldest, inclusive, limit, cursor } = parsed;
1244
- // Resolve channel name to ID if needed
1245
- const resolvedChannel = await this.resolveChannelId(channel);
1246
- const queryParams = {
1247
- channel: resolvedChannel,
1248
- ts: ts,
1249
- };
1250
- if (latest)
1251
- queryParams.latest = latest;
1252
- if (oldest)
1253
- queryParams.oldest = oldest;
1254
- if (inclusive !== undefined)
1255
- queryParams.inclusive = inclusive.toString();
1256
- if (limit !== undefined)
1257
- queryParams.limit = limit.toString();
1258
- if (cursor)
1259
- queryParams.cursor = cursor;
1260
- const response = await this.makeSlackApiCall('conversations.replies', queryParams, 'GET');
1261
- return {
1262
- operation: 'get_thread_replies',
1263
- ok: response.ok,
1264
- messages: response.ok && response.messages
1265
- ? z.array(SlackMessageSchema).parse(response.messages)
1266
- : undefined,
1267
- has_more: response.ok ? response.has_more : undefined,
1268
- response_metadata: response.ok && response.response_metadata
1269
- ? {
1270
- next_cursor: response.response_metadata.next_cursor,
1271
- }
1272
- : undefined,
1273
- error: !response.ok ? JSON.stringify(response, null, 2) : '',
1274
- success: response.ok,
1275
- };
1276
- }
1277
- async updateMessage(params) {
1278
- const { channel, ts, text, attachments, blocks } = params;
1279
- // Resolve channel name to ID if needed
1280
- const resolvedChannel = await this.resolveChannelId(channel);
1281
- const body = {
1282
- channel: resolvedChannel,
1283
- ts,
1284
- };
1285
- if (text)
1286
- body.text = text;
1287
- if (attachments)
1288
- body.attachments = JSON.stringify(attachments);
1289
- if (blocks)
1290
- body.blocks = JSON.stringify(blocks);
1291
- const response = await this.makeSlackApiCall('chat.update', body);
1292
- return {
1293
- operation: 'update_message',
1294
- ok: response.ok,
1295
- channel: response.ok ? response.channel : undefined,
1296
- ts: response.ok ? response.ts : undefined,
1297
- text: response.ok ? response.text : undefined,
1298
- message: response.ok && response.message
1299
- ? SlackMessageSchema.parse(response.message)
1300
- : undefined,
1301
- error: !response.ok ? JSON.stringify(response, null, 2) : '',
1302
- success: response.ok,
1303
- };
1304
- }
1305
- async deleteMessage(params) {
1306
- const { channel, ts } = params;
1307
- // Resolve channel name to ID if needed
1308
- const resolvedChannel = await this.resolveChannelId(channel);
1309
- const body = {
1310
- channel: resolvedChannel,
1311
- ts,
1312
- };
1313
- const response = await this.makeSlackApiCall('chat.delete', body);
1314
- return {
1315
- operation: 'delete_message',
1316
- ok: response.ok,
1317
- channel: response.ok ? response.channel : undefined,
1318
- ts: response.ok ? response.ts : undefined,
1319
- error: !response.ok ? JSON.stringify(response, null, 2) : '',
1320
- success: response.ok,
1321
- };
1322
- }
1323
- async addReaction(params) {
1324
- const { name, channel, timestamp } = params;
1325
- // Resolve channel name to ID if needed
1326
- const resolvedChannel = await this.resolveChannelId(channel);
1327
- const body = {
1328
- name,
1329
- channel: resolvedChannel,
1330
- timestamp,
1331
- };
1332
- const response = await this.makeSlackApiCall('reactions.add', body);
1333
- return {
1334
- operation: 'add_reaction',
1335
- ok: response.ok,
1336
- error: !response.ok ? JSON.stringify(response, null, 2) : '',
1337
- success: response.ok,
1338
- };
1339
- }
1340
- async removeReaction(params) {
1341
- const { name, channel, timestamp } = params;
1342
- // Resolve channel name to ID if needed
1343
- const resolvedChannel = await this.resolveChannelId(channel);
1344
- const body = {
1345
- name,
1346
- channel: resolvedChannel,
1347
- timestamp,
1348
- };
1349
- const response = await this.makeSlackApiCall('reactions.remove', body);
1350
- return {
1351
- operation: 'remove_reaction',
1352
- ok: response.ok,
1353
- error: !response.ok ? JSON.stringify(response, null, 2) : '',
1354
- success: response.ok,
1355
- };
1356
- }
1357
- async uploadFile(params) {
1358
- const { channel, file_path, filename, title, initial_comment, thread_ts } = params;
1359
- // Resolve channel name to ID if needed
1360
- const resolvedChannel = await this.resolveChannelId(channel);
1361
- // Read the file
1362
- const fs = await import('fs/promises');
1363
- const path = await import('path');
1364
- try {
1365
- const fileBuffer = await fs.readFile(file_path);
1366
- const actualFilename = filename || path.basename(file_path);
1367
- const fileSize = fileBuffer.length;
1368
- // Step 1: Get upload URL
1369
- const uploadUrlResponse = await this.makeSlackApiCall('files.getUploadURLExternal', {
1370
- filename: actualFilename,
1371
- length: fileSize.toString(),
1372
- });
1373
- if (!uploadUrlResponse.ok) {
1374
- throw new Error(`Failed to get upload URL: ${uploadUrlResponse.error}`);
1375
- }
1376
- const { upload_url, file_id } = uploadUrlResponse;
1377
- // Step 2: Upload file to the URL
1378
- const uploadResponse = await fetch(upload_url, {
1379
- method: 'POST',
1380
- body: fileBuffer,
1381
- headers: {
1382
- 'Content-Type': 'application/octet-stream',
1383
- },
1384
- });
1385
- if (!uploadResponse.ok) {
1386
- throw new Error(`Failed to upload file: ${uploadResponse.statusText}`);
1387
- }
1388
- // Step 3: Complete the upload
1389
- const completeParams = {
1390
- files: JSON.stringify([
1391
- {
1392
- id: file_id,
1393
- title: title || actualFilename,
1394
- },
1395
- ]),
1396
- };
1397
- // Add optional parameters
1398
- if (resolvedChannel)
1399
- completeParams.channel_id = resolvedChannel;
1400
- if (initial_comment)
1401
- completeParams.initial_comment = initial_comment;
1402
- if (thread_ts)
1403
- completeParams.thread_ts = thread_ts;
1404
- const completeResponse = await this.makeSlackApiCall('files.completeUploadExternal', completeParams);
1405
- if (!completeResponse.ok) {
1406
- throw new Error(`Failed to complete upload: ${completeResponse.error}`);
1407
- }
1408
- // Extract file info from response
1409
- const files = completeResponse.files || [];
1410
- const uploadedFile = files[0] || {};
1411
- return {
1412
- operation: 'upload_file',
1413
- ok: true,
1414
- file: {
1415
- id: uploadedFile.id || file_id,
1416
- created: uploadedFile.created || Date.now() / 1000,
1417
- timestamp: uploadedFile.timestamp || Date.now() / 1000,
1418
- name: uploadedFile.name || actualFilename,
1419
- title: uploadedFile.title || title || actualFilename,
1420
- mimetype: uploadedFile.mimetype || 'image/png',
1421
- filetype: uploadedFile.filetype || 'png',
1422
- pretty_type: uploadedFile.pretty_type || 'PNG',
1423
- user: uploadedFile.user || '',
1424
- editable: uploadedFile.editable || false,
1425
- size: uploadedFile.size || fileSize,
1426
- mode: uploadedFile.mode || 'hosted',
1427
- is_external: uploadedFile.is_external || false,
1428
- external_type: uploadedFile.external_type || '',
1429
- is_public: uploadedFile.is_public || false,
1430
- public_url_shared: uploadedFile.public_url_shared || false,
1431
- display_as_bot: uploadedFile.display_as_bot || false,
1432
- username: uploadedFile.username || '',
1433
- url_private: uploadedFile.url_private || '',
1434
- url_private_download: uploadedFile.url_private_download || '',
1435
- permalink: uploadedFile.permalink || '',
1436
- permalink_public: uploadedFile.permalink_public || '',
1437
- shares: uploadedFile.shares || {},
1438
- channels: uploadedFile.channels || [resolvedChannel],
1439
- groups: uploadedFile.groups || [],
1440
- ims: uploadedFile.ims || [],
1441
- has_rich_preview: uploadedFile.has_rich_preview || false,
1442
- },
1443
- error: '',
1444
- success: true,
1445
- };
1446
- }
1447
- catch (error) {
1448
- return {
1449
- operation: 'upload_file',
1450
- ok: false,
1451
- error: error instanceof Error ? error.message : 'Unknown file upload error',
1452
- success: false,
1453
- };
1454
- }
1455
- }
1456
- chooseCredential() {
1457
- const { credentials } = this.params;
1458
- // If no credentials were injected, return undefined
1459
- if (!credentials || typeof credentials !== 'object') {
1460
- throw new Error('No slack credentials provided');
1461
- }
1462
- // Slack bubble always uses Slack credentials
1463
- return credentials[CredentialType.SLACK_CRED];
1464
- }
1465
- async makeSlackApiCall(endpoint, params, method = 'POST') {
1466
- const url = `${SLACK_API_BASE}/${endpoint}`;
1467
- // Use chooseCredential to get the appropriate credential
1468
- const authToken = this.chooseCredential();
1469
- if (!authToken) {
1470
- throw new Error('Slack authentication token is required but was not provided');
1471
- }
1472
- const headers = {
1473
- Authorization: `Bearer ${authToken}`,
1474
- 'Content-Type': method === 'POST'
1475
- ? 'application/json'
1476
- : 'application/x-www-form-urlencoded',
1477
- };
1478
- let fetchConfig;
1479
- if (method === 'GET') {
1480
- const searchParams = new URLSearchParams();
1481
- for (const [key, value] of Object.entries(params)) {
1482
- if (value !== undefined && value !== null) {
1483
- searchParams.append(key, String(value));
1484
- }
1485
- }
1486
- fetchConfig = {
1487
- method: 'GET',
1488
- headers,
1489
- };
1490
- const urlWithParams = `${url}?${searchParams.toString()}`;
1491
- const response = await fetch(urlWithParams, fetchConfig);
1492
- const data = (await response.json());
1493
- if (!response.ok && !data.ok) {
1494
- throw new Error(`Slack API error: ${data.error || 'Unknown error'}`);
1495
- }
1496
- return data;
1497
- }
1498
- else {
1499
- // Most Slack POST endpoints expect form-encoded data, not JSON
1500
- // Only specific endpoints like chat.postMessage with blocks expect JSON
1501
- const needsJson = ['chat.postMessage', 'chat.update'].includes(endpoint) &&
1502
- (params.blocks || params.attachments);
1503
- if (needsJson) {
1504
- fetchConfig = {
1505
- method: 'POST',
1506
- headers,
1507
- body: JSON.stringify(params),
1508
- };
1509
- }
1510
- else {
1511
- // Use form-encoded for most endpoints
1512
- const formData = new URLSearchParams();
1513
- for (const [key, value] of Object.entries(params)) {
1514
- if (value !== undefined && value !== null) {
1515
- formData.append(key, String(value));
1516
- }
1517
- }
1518
- fetchConfig = {
1519
- method: 'POST',
1520
- headers: {
1521
- ...headers,
1522
- 'Content-Type': 'application/x-www-form-urlencoded',
1523
- },
1524
- body: formData.toString(),
1525
- };
1526
- }
1527
- const response = await fetch(url, fetchConfig);
1528
- const data = (await response.json());
1529
- if (!response.ok && !data.ok) {
1530
- throw new Error(`Slack API error: ${data.error || 'Unknown error'}`);
1531
- }
1532
- return data;
1533
- }
1534
- }
1535
- }
1536
- //# sourceMappingURL=slack.js.map