@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.
- package/dist/bubble-bundle.d.ts +114 -114
- package/dist/bubbles/service-bubble/agi-inc.d.ts +52 -52
- package/dist/bubbles/service-bubble/ai-agent.d.ts +20 -20
- package/dist/bubbles/service-bubble/airtable.d.ts +138 -138
- package/dist/bubbles/service-bubble/apify/actors/google-maps-scraper.d.ts +2 -2
- package/dist/bubbles/service-bubble/apify/actors/instagram-hashtag-scraper.d.ts +20 -20
- package/dist/bubbles/service-bubble/apify/actors/instagram-scraper.d.ts +30 -30
- package/dist/bubbles/service-bubble/apify/actors/linkedin-posts-search.d.ts +26 -26
- package/dist/bubbles/service-bubble/apify/actors/linkedin-profile-posts.d.ts +56 -56
- package/dist/bubbles/service-bubble/apify/actors/tiktok-scraper.d.ts +16 -16
- package/dist/bubbles/service-bubble/apify/actors/twitter-scraper.d.ts +31 -31
- package/dist/bubbles/service-bubble/apify/actors/youtube-scraper.d.ts +8 -8
- package/dist/bubbles/service-bubble/apify/apify-scraper.schema.d.ts +153 -153
- package/dist/bubbles/service-bubble/apify/apify.d.ts +12 -12
- package/dist/bubbles/service-bubble/ashby/ashby.d.ts +18 -18
- package/dist/bubbles/service-bubble/ashby/ashby.schema.d.ts +18 -18
- package/dist/bubbles/service-bubble/browserbase/browserbase.d.ts +20 -20
- package/dist/bubbles/service-bubble/browserbase/browserbase.schema.d.ts +20 -20
- package/dist/bubbles/service-bubble/crustdata/crustdata.d.ts +12 -12
- package/dist/bubbles/service-bubble/crustdata/crustdata.schema.d.ts +16 -16
- package/dist/bubbles/service-bubble/eleven-labs.d.ts +24 -24
- package/dist/bubbles/service-bubble/firecrawl.d.ts +68 -68
- package/dist/bubbles/service-bubble/followupboss.d.ts +124 -124
- package/dist/bubbles/service-bubble/fullenrich/fullenrich.d.ts +12 -12
- package/dist/bubbles/service-bubble/fullenrich/fullenrich.schema.d.ts +12 -12
- package/dist/bubbles/service-bubble/github.d.ts +36 -36
- package/dist/bubbles/service-bubble/gmail.d.ts +64 -64
- package/dist/bubbles/service-bubble/google-calendar.d.ts +24 -24
- package/dist/bubbles/service-bubble/google-drive.d.ts +48 -48
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.d.ts +22 -22
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.schema.d.ts +22 -22
- package/dist/bubbles/service-bubble/hello-world.d.ts +4 -4
- package/dist/bubbles/service-bubble/http.d.ts +8 -8
- package/dist/bubbles/service-bubble/insforge-db.d.ts +10 -10
- package/dist/bubbles/service-bubble/jira/jira.d.ts +20 -20
- package/dist/bubbles/service-bubble/jira/jira.schema.d.ts +20 -20
- package/dist/bubbles/service-bubble/notion/notion.d.ts +68 -68
- package/dist/bubbles/service-bubble/notion/property-schemas.d.ts +36 -36
- package/dist/bubbles/service-bubble/postgresql.d.ts +10 -10
- package/dist/bubbles/service-bubble/resend.d.ts +8 -8
- package/dist/bubbles/service-bubble/slack/slack.d.ts +97 -97
- package/dist/bubbles/service-bubble/slack/slack.d.ts.map +1 -1
- package/dist/bubbles/service-bubble/slack/slack.js +0 -133
- package/dist/bubbles/service-bubble/slack/slack.js.map +1 -1
- package/dist/bubbles/service-bubble/storage.d.ts +20 -20
- package/dist/bubbles/service-bubble/stripe/stripe.d.ts +38 -38
- package/dist/bubbles/service-bubble/stripe/stripe.schema.d.ts +38 -38
- package/dist/bubbles/service-bubble/telegram.d.ts +52 -52
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.d.ts +14 -14
- package/dist/bubbles/tool-bubble/amazon-shopping-tool/amazon-shopping-tool.schema.d.ts +14 -14
- package/dist/bubbles/tool-bubble/bubbleflow-validation-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/chart-js-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/code-edit-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/company-enrichment-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/get-bubble-details-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/get-trigger-detail-tool.d.ts +12 -12
- package/dist/bubbles/tool-bubble/google-maps-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/instagram-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.d.ts +2 -2
- package/dist/bubbles/tool-bubble/linkedin-connection-tool/linkedin-connection-tool.schema.d.ts +2 -2
- package/dist/bubbles/tool-bubble/linkedin-tool.d.ts +30 -30
- package/dist/bubbles/tool-bubble/list-airtable-bases-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/list-airtable-tables-tool.d.ts +12 -12
- package/dist/bubbles/tool-bubble/list-bubbles-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/people-search-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/reddit-scrape-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/research-agent-tool.d.ts +12 -4
- package/dist/bubbles/tool-bubble/research-agent-tool.d.ts.map +1 -1
- package/dist/bubbles/tool-bubble/research-agent-tool.js +168 -15
- package/dist/bubbles/tool-bubble/research-agent-tool.js.map +1 -1
- package/dist/bubbles/tool-bubble/sql-query-tool.d.ts +12 -12
- package/dist/bubbles/tool-bubble/tiktok-tool.d.ts +12 -12
- package/dist/bubbles/tool-bubble/tool-template.d.ts +4 -4
- package/dist/bubbles/tool-bubble/twitter-tool.d.ts +40 -40
- package/dist/bubbles/tool-bubble/web-crawl-tool.d.ts +8 -8
- package/dist/bubbles/tool-bubble/web-extract-tool.d.ts +8 -8
- package/dist/bubbles/tool-bubble/web-scrape-tool.d.ts +8 -8
- package/dist/bubbles/tool-bubble/web-search-tool.d.ts +4 -4
- package/dist/bubbles/tool-bubble/youtube-tool.d.ts +14 -14
- package/dist/bubbles/workflow-bubble/database-analyzer.workflow.d.ts +4 -4
- package/dist/bubbles/workflow-bubble/generate-document.workflow.d.ts +4 -4
- package/dist/bubbles/workflow-bubble/parse-document.workflow.d.ts +4 -4
- package/dist/bubbles/workflow-bubble/pdf-form-operations.workflow.d.ts +24 -24
- package/dist/bubbles/workflow-bubble/pdf-ocr.workflow.d.ts +8 -8
- package/dist/bubbles/workflow-bubble/slack-data-assistant.workflow.d.ts +4 -4
- package/dist/bubbles/workflow-bubble/slack-formatter-agent.d.ts +52 -52
- package/dist/bubbles/workflow-bubble/slack-notifier.workflow.d.ts +4 -4
- package/dist/bubbles.json +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/json-parsing.d.ts +9 -0
- package/dist/utils/json-parsing.d.ts.map +1 -1
- package/dist/utils/json-parsing.js +61 -2
- package/dist/utils/json-parsing.js.map +1 -1
- package/dist/utils/zod-schema.d.ts.map +1 -1
- package/dist/utils/zod-schema.js +16 -8
- package/dist/utils/zod-schema.js.map +1 -1
- package/package.json +2 -2
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.d.ts +0 -31
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.js +0 -184
- package/dist/bubbles/service-bubble/google-sheets/google-sheets.integration.flow.js.map +0 -1
- package/dist/bubbles/service-bubble/google-sheets.d.ts +0 -1811
- package/dist/bubbles/service-bubble/google-sheets.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/google-sheets.js +0 -904
- package/dist/bubbles/service-bubble/google-sheets.js.map +0 -1
- package/dist/bubbles/service-bubble/slack.d.ts +0 -5869
- package/dist/bubbles/service-bubble/slack.d.ts.map +0 -1
- package/dist/bubbles/service-bubble/slack.js +0 -1536
- package/dist/bubbles/service-bubble/slack.js.map +0 -1
- package/dist/recording/types.d.ts +0 -68
- package/dist/recording/types.d.ts.map +0 -1
- package/dist/recording/types.js +0 -13
- 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
|