@frogbotai/piece-slack 0.29.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/actions.d.ts +2 -2
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +285 -193
- package/dist/actions.js.map +1 -1
- package/dist/client.js +47 -35
- package/dist/client.js.map +1 -1
- package/dist/config.js +17 -5
- package/dist/config.js.map +1 -1
- package/dist/define.js +1 -0
- package/dist/define.js.map +1 -1
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +25 -15
- package/dist/files.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +45 -39
- package/dist/index.js.map +1 -1
- package/dist/options.js +36 -21
- package/dist/options.js.map +1 -1
- package/dist/questions/blocks.js +148 -74
- package/dist/questions/blocks.js.map +1 -1
- package/dist/questions/index.js +2 -1
- package/dist/questions/index.js.map +1 -1
- package/dist/questions/notify.js +19 -13
- package/dist/questions/notify.js.map +1 -1
- package/dist/questions/parse.js +110 -59
- package/dist/questions/parse.js.map +1 -1
- package/dist/questions/render.js +16 -7
- package/dist/questions/render.js.map +1 -1
- package/dist/questions/settled.js +9 -3
- package/dist/questions/settled.js.map +1 -1
- package/dist/questions/slackThread.js +12 -6
- package/dist/questions/slackThread.js.map +1 -1
- package/dist/questions/state.js +18 -5
- package/dist/questions/state.js.map +1 -1
- package/dist/questions/updated.js +32 -24
- package/dist/questions/updated.js.map +1 -1
- package/dist/triggers.js +150 -126
- package/dist/triggers.js.map +1 -1
- package/dist/webhook.js +28 -43
- package/dist/webhook.js.map +1 -1
- package/package.json +4 -4
package/dist/actions.js
CHANGED
|
@@ -1,29 +1,33 @@
|
|
|
1
|
+
import { filesCollectionSlug } from 'frogbot/pieces';
|
|
1
2
|
import { z } from 'zod';
|
|
2
|
-
import { slackApiResult, slackResponse, slackValue, slackValues
|
|
3
|
+
import { slackApiResult, slackResponse, slackValue, slackValues } from './client.js';
|
|
3
4
|
import { defineAction } from './define.js';
|
|
4
5
|
import { loadSlackFile, slackFile } from './files.js';
|
|
5
6
|
import { channelOptions, userOptions } from './options.js';
|
|
6
|
-
const channel = z.string().min(1).meta({
|
|
7
|
-
|
|
7
|
+
const channel = z.string().min(1).meta({
|
|
8
|
+
label: 'Channel'
|
|
9
|
+
});
|
|
10
|
+
const user = z.string().min(1).meta({
|
|
11
|
+
label: 'User'
|
|
12
|
+
});
|
|
8
13
|
const timestamp = z.string().regex(/^(?:.*\/p\d{16}|\d+\.\d{6})$/, 'Invalid Slack timestamp.');
|
|
9
14
|
const blocks = z.array(slackValue).default([]);
|
|
10
15
|
const messageResult = slackResponse.extend({
|
|
11
16
|
channel: z.string().optional(),
|
|
12
|
-
ts: z.string().optional()
|
|
17
|
+
ts: z.string().optional()
|
|
13
18
|
});
|
|
14
19
|
function normalizeTimestamp(value) {
|
|
15
20
|
const link = value.match(/\/p(\d+)(\d{6})$/);
|
|
16
21
|
return link ? `${link[1]}.${link[2]}` : value;
|
|
17
22
|
}
|
|
18
|
-
async function upload({ client, file, channelId, title, initialComment, threadTimestamp, token = 'bot', signal
|
|
19
|
-
const created = await client.request('files.getUploadURLExternal', {
|
|
23
|
+
async function upload({ client, file, channelId, title, initialComment, threadTimestamp, token = 'bot', signal }) {
|
|
24
|
+
const created = await client.request('files.getUploadURLExternal', {
|
|
25
|
+
filename: file.name,
|
|
26
|
+
length: file.data.size
|
|
27
|
+
}, token);
|
|
20
28
|
const uploadUrl = typeof created.upload_url === 'string' ? new URL(created.upload_url) : undefined;
|
|
21
29
|
const fileId = typeof created.file_id === 'string' ? created.file_id : undefined;
|
|
22
|
-
if (!uploadUrl ||
|
|
23
|
-
!fileId ||
|
|
24
|
-
uploadUrl.protocol !== 'https:' ||
|
|
25
|
-
uploadUrl.username ||
|
|
26
|
-
uploadUrl.password) {
|
|
30
|
+
if (!uploadUrl || !fileId || uploadUrl.protocol !== 'https:' || uploadUrl.username || uploadUrl.password) {
|
|
27
31
|
throw new Error('Slack returned an invalid file upload target.');
|
|
28
32
|
}
|
|
29
33
|
if (uploadUrl.hostname !== 'files.slack.com' && !uploadUrl.hostname.endsWith('.slack.com')) {
|
|
@@ -33,15 +37,19 @@ async function upload({ client, file, channelId, title, initialComment, threadTi
|
|
|
33
37
|
method: 'POST',
|
|
34
38
|
body: file.data,
|
|
35
39
|
redirect: 'error',
|
|
36
|
-
signal
|
|
40
|
+
signal
|
|
37
41
|
});
|
|
38
|
-
if (!response.ok)
|
|
39
|
-
throw new Error(`Slack file upload failed (${response.status}).`);
|
|
42
|
+
if (!response.ok) throw new Error(`Slack file upload failed (${response.status}).`);
|
|
40
43
|
return client.request('files.completeUploadExternal', {
|
|
41
|
-
files: [
|
|
44
|
+
files: [
|
|
45
|
+
{
|
|
46
|
+
id: fileId,
|
|
47
|
+
title
|
|
48
|
+
}
|
|
49
|
+
],
|
|
42
50
|
channel_id: channelId,
|
|
43
51
|
initial_comment: initialComment,
|
|
44
|
-
thread_ts: threadTimestamp
|
|
52
|
+
thread_ts: threadTimestamp
|
|
45
53
|
}, token);
|
|
46
54
|
}
|
|
47
55
|
const messageFields = {
|
|
@@ -50,17 +58,22 @@ const messageFields = {
|
|
|
50
58
|
profilePicture: z.url().optional(),
|
|
51
59
|
iconEmoji: z.string().optional(),
|
|
52
60
|
blocks,
|
|
53
|
-
unfurlLinks: z.boolean().default(true)
|
|
61
|
+
unfurlLinks: z.boolean().default(true)
|
|
54
62
|
};
|
|
55
|
-
const sendDirectMessageInput = z.object({
|
|
63
|
+
const sendDirectMessageInput = z.object({
|
|
64
|
+
userId: user,
|
|
65
|
+
...messageFields
|
|
66
|
+
});
|
|
56
67
|
export const sendDirectMessage = defineAction({
|
|
57
68
|
slug: 'sendDirectMessage',
|
|
58
69
|
description: 'Send a direct message to a Slack user.',
|
|
59
70
|
input: sendDirectMessageInput,
|
|
60
71
|
output: messageResult,
|
|
61
72
|
idempotent: false,
|
|
62
|
-
options: {
|
|
63
|
-
|
|
73
|
+
options: {
|
|
74
|
+
userId: userOptions
|
|
75
|
+
},
|
|
76
|
+
async run ({ client, input }) {
|
|
64
77
|
return client.request('chat.postMessage', {
|
|
65
78
|
channel: input.userId,
|
|
66
79
|
text: input.text,
|
|
@@ -68,12 +81,11 @@ export const sendDirectMessage = defineAction({
|
|
|
68
81
|
icon_url: input.profilePicture,
|
|
69
82
|
icon_emoji: input.iconEmoji,
|
|
70
83
|
blocks: input.blocks,
|
|
71
|
-
unfurl_links: input.unfurlLinks
|
|
84
|
+
unfurl_links: input.unfurlLinks
|
|
72
85
|
});
|
|
73
|
-
}
|
|
86
|
+
}
|
|
74
87
|
});
|
|
75
|
-
const sendChannelInput = z
|
|
76
|
-
.object({
|
|
88
|
+
const sendChannelInput = z.object({
|
|
77
89
|
channel,
|
|
78
90
|
text: z.string().optional(),
|
|
79
91
|
sendAsBot: z.boolean().default(true),
|
|
@@ -84,10 +96,9 @@ const sendChannelInput = z
|
|
|
84
96
|
file: slackFile.optional(),
|
|
85
97
|
replyBroadcast: z.boolean().default(false),
|
|
86
98
|
unfurlLinks: z.boolean().default(true),
|
|
87
|
-
blocks
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
message: 'A message or Block Kit blocks are required.',
|
|
99
|
+
blocks
|
|
100
|
+
}).refine(({ text, blocks: value })=>Boolean(text) || value.length > 0, {
|
|
101
|
+
message: 'A message or Block Kit blocks are required.'
|
|
91
102
|
});
|
|
92
103
|
export const sendChannelMessage = defineAction({
|
|
93
104
|
slug: 'sendChannelMessage',
|
|
@@ -95,8 +106,10 @@ export const sendChannelMessage = defineAction({
|
|
|
95
106
|
input: sendChannelInput,
|
|
96
107
|
output: slackResponse,
|
|
97
108
|
idempotent: false,
|
|
98
|
-
options: {
|
|
99
|
-
|
|
109
|
+
options: {
|
|
110
|
+
channel: channelOptions
|
|
111
|
+
},
|
|
112
|
+
async run ({ client, input, req }) {
|
|
100
113
|
const token = input.sendAsBot ? 'bot' : 'user';
|
|
101
114
|
if (input.file) {
|
|
102
115
|
const file = await loadSlackFile(req, input.file);
|
|
@@ -105,11 +118,9 @@ export const sendChannelMessage = defineAction({
|
|
|
105
118
|
file,
|
|
106
119
|
channelId: input.channel,
|
|
107
120
|
initialComment: input.text,
|
|
108
|
-
threadTimestamp: input.threadTimestamp
|
|
109
|
-
? normalizeTimestamp(input.threadTimestamp)
|
|
110
|
-
: undefined,
|
|
121
|
+
threadTimestamp: input.threadTimestamp ? normalizeTimestamp(input.threadTimestamp) : undefined,
|
|
111
122
|
token,
|
|
112
|
-
signal: req.signal
|
|
123
|
+
signal: req.signal
|
|
113
124
|
});
|
|
114
125
|
}
|
|
115
126
|
return client.request('chat.postMessage', {
|
|
@@ -121,15 +132,15 @@ export const sendChannelMessage = defineAction({
|
|
|
121
132
|
icon_emoji: input.iconEmoji,
|
|
122
133
|
reply_broadcast: input.replyBroadcast,
|
|
123
134
|
unfurl_links: input.unfurlLinks,
|
|
124
|
-
blocks: input.blocks
|
|
135
|
+
blocks: input.blocks
|
|
125
136
|
}, token);
|
|
126
|
-
}
|
|
137
|
+
}
|
|
127
138
|
});
|
|
128
139
|
const addReactionInput = z.object({
|
|
129
140
|
channel,
|
|
130
141
|
timestamp,
|
|
131
142
|
reaction: z.string().min(1),
|
|
132
|
-
reactAsUser: z.boolean().default(false)
|
|
143
|
+
reactAsUser: z.boolean().default(false)
|
|
133
144
|
});
|
|
134
145
|
export const addReaction = defineAction({
|
|
135
146
|
slug: 'addReaction',
|
|
@@ -137,20 +148,22 @@ export const addReaction = defineAction({
|
|
|
137
148
|
input: addReactionInput,
|
|
138
149
|
output: slackResponse,
|
|
139
150
|
idempotent: true,
|
|
140
|
-
options: {
|
|
141
|
-
|
|
151
|
+
options: {
|
|
152
|
+
channel: channelOptions
|
|
153
|
+
},
|
|
154
|
+
async run ({ client, input }) {
|
|
142
155
|
return client.request('reactions.add', {
|
|
143
156
|
channel: input.channel,
|
|
144
157
|
timestamp: normalizeTimestamp(input.timestamp),
|
|
145
|
-
name: input.reaction
|
|
158
|
+
name: input.reaction
|
|
146
159
|
}, input.reactAsUser ? 'user' : 'bot');
|
|
147
|
-
}
|
|
160
|
+
}
|
|
148
161
|
});
|
|
149
162
|
const uploadFileInput = z.object({
|
|
150
163
|
file: slackFile,
|
|
151
164
|
title: z.string().optional(),
|
|
152
165
|
filename: z.string().optional(),
|
|
153
|
-
channel: channel.optional()
|
|
166
|
+
channel: channel.optional()
|
|
154
167
|
});
|
|
155
168
|
export const uploadFile = defineAction({
|
|
156
169
|
slug: 'uploadFile',
|
|
@@ -158,65 +171,68 @@ export const uploadFile = defineAction({
|
|
|
158
171
|
input: uploadFileInput,
|
|
159
172
|
output: slackResponse,
|
|
160
173
|
idempotent: false,
|
|
161
|
-
options: {
|
|
162
|
-
|
|
174
|
+
options: {
|
|
175
|
+
channel: channelOptions
|
|
176
|
+
},
|
|
177
|
+
async run ({ client, input, req }) {
|
|
163
178
|
const loaded = await loadSlackFile(req, {
|
|
164
179
|
...input.file,
|
|
165
|
-
name: input.filename ?? input.file.name
|
|
180
|
+
name: input.filename ?? input.file.name
|
|
166
181
|
});
|
|
167
182
|
return upload({
|
|
168
183
|
client,
|
|
169
184
|
file: loaded,
|
|
170
185
|
channelId: input.channel,
|
|
171
186
|
title: input.title,
|
|
172
|
-
signal: req.signal
|
|
187
|
+
signal: req.signal
|
|
173
188
|
});
|
|
174
|
-
}
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
const getFileInput = z.object({
|
|
192
|
+
fileId: z.string().min(1)
|
|
175
193
|
});
|
|
176
|
-
const getFileInput = z.object({ fileId: z.string().min(1) });
|
|
177
194
|
export const getFile = defineAction({
|
|
178
195
|
slug: 'getFile',
|
|
179
196
|
description: 'Get Slack file metadata and safely download its contents.',
|
|
180
197
|
input: getFileInput,
|
|
181
198
|
output: slackValue,
|
|
182
199
|
idempotent: true,
|
|
183
|
-
async run({ client, input, req }) {
|
|
184
|
-
const response = await client.request('files.info', {
|
|
200
|
+
async run ({ client, input, req }) {
|
|
201
|
+
const response = await client.request('files.info', {
|
|
202
|
+
file: input.fileId
|
|
203
|
+
});
|
|
185
204
|
const file = response.file;
|
|
186
|
-
if (!file ||
|
|
187
|
-
typeof file !== 'object' ||
|
|
188
|
-
!('url_private_download' in file) ||
|
|
189
|
-
typeof file.url_private_download !== 'string') {
|
|
205
|
+
if (!file || typeof file !== 'object' || !('url_private_download' in file) || typeof file.url_private_download !== 'string') {
|
|
190
206
|
throw new Error('Slack file has no download URL.');
|
|
191
207
|
}
|
|
192
208
|
const url = new URL(file.url_private_download);
|
|
193
|
-
if (url.protocol !== 'https:' ||
|
|
194
|
-
url.hostname !== 'files.slack.com' ||
|
|
195
|
-
url.username ||
|
|
196
|
-
url.password) {
|
|
209
|
+
if (url.protocol !== 'https:' || url.hostname !== 'files.slack.com' || url.username || url.password) {
|
|
197
210
|
throw new Error('Slack file download URL is untrusted.');
|
|
198
211
|
}
|
|
199
212
|
const downloaded = await fetch(url, {
|
|
200
|
-
headers: {
|
|
213
|
+
headers: {
|
|
214
|
+
authorization: `Bearer ${client.token()}`
|
|
215
|
+
},
|
|
201
216
|
redirect: 'error',
|
|
202
|
-
signal: req.signal
|
|
217
|
+
signal: req.signal
|
|
203
218
|
});
|
|
204
|
-
if (!downloaded.ok)
|
|
205
|
-
throw new Error(`Slack file download failed (${downloaded.status}).`);
|
|
219
|
+
if (!downloaded.ok) throw new Error(`Slack file download failed (${downloaded.status}).`);
|
|
206
220
|
const data = Buffer.from(await downloaded.arrayBuffer());
|
|
207
221
|
const name = 'name' in file && typeof file.name === 'string' ? file.name : `slack-${input.fileId}`;
|
|
208
222
|
const mimeType = downloaded.headers.get('content-type')?.split(';')[0] || 'application/octet-stream';
|
|
209
|
-
const collection = req
|
|
210
|
-
if (!collection) {
|
|
211
|
-
throw new Error('[frogbot] Slack file downloads require the files collection.');
|
|
212
|
-
}
|
|
223
|
+
const collection = filesCollectionSlug(req, 'Slack');
|
|
213
224
|
req.signal?.throwIfAborted();
|
|
214
225
|
const saved = await req.frogbot.create({
|
|
215
226
|
collection,
|
|
216
227
|
data: {},
|
|
217
|
-
file: {
|
|
228
|
+
file: {
|
|
229
|
+
data,
|
|
230
|
+
name,
|
|
231
|
+
mimetype: mimeType,
|
|
232
|
+
size: data.length
|
|
233
|
+
},
|
|
218
234
|
req,
|
|
219
|
-
overrideAccess: false
|
|
235
|
+
overrideAccess: false
|
|
220
236
|
});
|
|
221
237
|
return {
|
|
222
238
|
...file,
|
|
@@ -225,96 +241,104 @@ export const getFile = defineAction({
|
|
|
225
241
|
name,
|
|
226
242
|
mimeType,
|
|
227
243
|
size: data.length,
|
|
228
|
-
url: typeof saved.url === 'string' ? saved.url : undefined
|
|
229
|
-
}
|
|
244
|
+
url: typeof saved.url === 'string' ? saved.url : undefined
|
|
245
|
+
}
|
|
230
246
|
};
|
|
231
|
-
}
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
const searchMessagesInput = z.object({
|
|
250
|
+
query: z.string().min(1)
|
|
232
251
|
});
|
|
233
|
-
const searchMessagesInput = z.object({ query: z.string().min(1) });
|
|
234
252
|
export const searchMessages = defineAction({
|
|
235
253
|
slug: 'searchMessages',
|
|
236
254
|
description: 'Search all Slack messages matching a query.',
|
|
237
255
|
input: searchMessagesInput,
|
|
238
256
|
output: slackValues,
|
|
239
257
|
idempotent: true,
|
|
240
|
-
async run({ client, input }) {
|
|
258
|
+
async run ({ client, input }) {
|
|
241
259
|
const matches = [];
|
|
242
260
|
let cursor = '*';
|
|
243
261
|
do {
|
|
244
|
-
const response = await client.request('search.messages', {
|
|
262
|
+
const response = await client.request('search.messages', {
|
|
263
|
+
query: input.query,
|
|
264
|
+
count: 100,
|
|
265
|
+
cursor
|
|
266
|
+
}, 'user');
|
|
245
267
|
const messages = response.messages;
|
|
246
|
-
if (!messages || typeof messages !== 'object')
|
|
247
|
-
break;
|
|
268
|
+
if (!messages || typeof messages !== 'object') break;
|
|
248
269
|
if ('matches' in messages && Array.isArray(messages.matches)) {
|
|
249
|
-
for (const match of messages.matches)
|
|
270
|
+
for (const match of messages.matches){
|
|
250
271
|
if (match && typeof match === 'object' && !Array.isArray(match)) {
|
|
251
272
|
matches.push(Object.fromEntries(Object.entries(match)));
|
|
252
273
|
}
|
|
253
274
|
}
|
|
254
275
|
}
|
|
255
276
|
const pagination = 'pagination' in messages ? messages.pagination : undefined;
|
|
256
|
-
cursor =
|
|
257
|
-
|
|
258
|
-
? String(pagination.next_cursor || '') || undefined
|
|
259
|
-
: undefined;
|
|
260
|
-
} while (cursor);
|
|
277
|
+
cursor = pagination && typeof pagination === 'object' && 'next_cursor' in pagination ? String(pagination.next_cursor || '') || undefined : undefined;
|
|
278
|
+
}while (cursor)
|
|
261
279
|
return matches;
|
|
262
|
-
}
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
const emailInput = z.object({
|
|
283
|
+
email: z.email()
|
|
263
284
|
});
|
|
264
|
-
const emailInput = z.object({ email: z.email() });
|
|
265
285
|
export const findUserByEmail = defineAction({
|
|
266
286
|
slug: 'findUserByEmail',
|
|
267
287
|
description: 'Find a Slack user by exact email address.',
|
|
268
288
|
input: emailInput,
|
|
269
289
|
output: slackResponse,
|
|
270
290
|
idempotent: true,
|
|
271
|
-
async run({ client, input }) {
|
|
291
|
+
async run ({ client, input }) {
|
|
272
292
|
return client.request('users.lookupByEmail', input);
|
|
273
|
-
}
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
const handleInput = z.object({
|
|
296
|
+
handle: z.string().min(1)
|
|
274
297
|
});
|
|
275
|
-
const handleInput = z.object({ handle: z.string().min(1) });
|
|
276
298
|
export const findUserByHandle = defineAction({
|
|
277
299
|
slug: 'findUserByHandle',
|
|
278
300
|
description: 'Find a Slack user by display-name handle.',
|
|
279
301
|
input: handleInput,
|
|
280
302
|
output: slackValue,
|
|
281
303
|
idempotent: true,
|
|
282
|
-
async run({ client, input }) {
|
|
304
|
+
async run ({ client, input }) {
|
|
283
305
|
const handle = input.handle.replace(/^@/, '');
|
|
284
306
|
const members = await client.paginate({
|
|
285
307
|
path: 'users.list',
|
|
286
308
|
item: 'members',
|
|
287
|
-
body: {
|
|
309
|
+
body: {
|
|
310
|
+
limit: 1000
|
|
311
|
+
}
|
|
288
312
|
});
|
|
289
|
-
const found = members.find((member)
|
|
290
|
-
if (!member || typeof member !== 'object' || !('profile' in member))
|
|
291
|
-
return false;
|
|
313
|
+
const found = members.find((member)=>{
|
|
314
|
+
if (!member || typeof member !== 'object' || !('profile' in member)) return false;
|
|
292
315
|
const profile = member.profile;
|
|
293
|
-
return
|
|
294
|
-
typeof profile === 'object' &&
|
|
295
|
-
'display_name' in profile &&
|
|
296
|
-
profile.display_name === handle);
|
|
316
|
+
return profile && typeof profile === 'object' && 'display_name' in profile && profile.display_name === handle;
|
|
297
317
|
});
|
|
298
318
|
if (!found || typeof found !== 'object') {
|
|
299
319
|
throw new Error(`Could not find user with handle @${handle}`);
|
|
300
320
|
}
|
|
301
321
|
return found;
|
|
302
|
-
}
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
const findUserByIdInput = z.object({
|
|
325
|
+
id: z.string().min(1)
|
|
303
326
|
});
|
|
304
|
-
const findUserByIdInput = z.object({ id: z.string().min(1) });
|
|
305
327
|
export const findUserById = defineAction({
|
|
306
328
|
slug: 'findUserById',
|
|
307
329
|
description: 'Find a Slack user profile by ID.',
|
|
308
330
|
input: findUserByIdInput,
|
|
309
331
|
output: slackResponse,
|
|
310
332
|
idempotent: true,
|
|
311
|
-
async run({ client, input }) {
|
|
312
|
-
return client.request('users.profile.get', {
|
|
313
|
-
|
|
333
|
+
async run ({ client, input }) {
|
|
334
|
+
return client.request('users.profile.get', {
|
|
335
|
+
user: input.id
|
|
336
|
+
});
|
|
337
|
+
}
|
|
314
338
|
});
|
|
315
339
|
const listUsersInput = z.object({
|
|
316
340
|
includeBots: z.boolean().default(false),
|
|
317
|
-
includeDisabled: z.boolean().default(false)
|
|
341
|
+
includeDisabled: z.boolean().default(false)
|
|
318
342
|
});
|
|
319
343
|
export const listUsers = defineAction({
|
|
320
344
|
slug: 'listUsers',
|
|
@@ -322,60 +346,79 @@ export const listUsers = defineAction({
|
|
|
322
346
|
input: listUsersInput,
|
|
323
347
|
output: slackValues,
|
|
324
348
|
idempotent: true,
|
|
325
|
-
async run({ client, input }) {
|
|
349
|
+
async run ({ client, input }) {
|
|
326
350
|
const members = await client.paginate({
|
|
327
351
|
path: 'users.list',
|
|
328
352
|
item: 'members',
|
|
329
|
-
body: {
|
|
353
|
+
body: {
|
|
354
|
+
limit: 1000
|
|
355
|
+
}
|
|
330
356
|
});
|
|
331
|
-
return members.filter((member)
|
|
332
|
-
if (!member || typeof member !== 'object')
|
|
333
|
-
|
|
334
|
-
if (!input.
|
|
335
|
-
return false;
|
|
336
|
-
if (!input.includeDisabled && 'deleted' in member && member.deleted === true)
|
|
337
|
-
return false;
|
|
357
|
+
return members.filter((member)=>{
|
|
358
|
+
if (!member || typeof member !== 'object') return false;
|
|
359
|
+
if (!input.includeBots && 'is_bot' in member && member.is_bot === true) return false;
|
|
360
|
+
if (!input.includeDisabled && 'deleted' in member && member.deleted === true) return false;
|
|
338
361
|
return true;
|
|
339
362
|
});
|
|
340
|
-
}
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
const updateMessageInput = z.object({
|
|
366
|
+
channel,
|
|
367
|
+
timestamp,
|
|
368
|
+
text: z.string().min(1),
|
|
369
|
+
blocks
|
|
341
370
|
});
|
|
342
|
-
const updateMessageInput = z.object({ channel, timestamp, text: z.string().min(1), blocks });
|
|
343
371
|
export const updateMessage = defineAction({
|
|
344
372
|
slug: 'updateMessage',
|
|
345
373
|
description: 'Update an existing Slack message.',
|
|
346
374
|
input: updateMessageInput,
|
|
347
375
|
output: slackResponse,
|
|
348
376
|
idempotent: true,
|
|
349
|
-
options: {
|
|
350
|
-
|
|
377
|
+
options: {
|
|
378
|
+
channel: channelOptions
|
|
379
|
+
},
|
|
380
|
+
async run ({ client, input }) {
|
|
351
381
|
return client.request('chat.update', {
|
|
352
382
|
channel: input.channel,
|
|
353
383
|
ts: normalizeTimestamp(input.timestamp),
|
|
354
384
|
text: input.text,
|
|
355
|
-
blocks: input.blocks
|
|
385
|
+
blocks: input.blocks
|
|
356
386
|
});
|
|
357
|
-
}
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
const deleteMessageInput = z.object({
|
|
390
|
+
channel,
|
|
391
|
+
timestamp
|
|
358
392
|
});
|
|
359
|
-
const deleteMessageInput = z.object({ channel, timestamp });
|
|
360
393
|
export const deleteMessage = defineAction({
|
|
361
394
|
slug: 'deleteMessage',
|
|
362
395
|
description: 'Delete a Slack message after confirming it exists.',
|
|
363
396
|
input: deleteMessageInput,
|
|
364
397
|
output: slackResponse,
|
|
365
398
|
idempotent: false,
|
|
366
|
-
options: {
|
|
367
|
-
|
|
399
|
+
options: {
|
|
400
|
+
channel: channelOptions
|
|
401
|
+
},
|
|
402
|
+
async run ({ client, input }) {
|
|
368
403
|
const ts = normalizeTimestamp(input.timestamp);
|
|
369
|
-
const history = await client.request('conversations.history', {
|
|
404
|
+
const history = await client.request('conversations.history', {
|
|
405
|
+
channel: input.channel,
|
|
406
|
+
oldest: ts,
|
|
407
|
+
limit: 1,
|
|
408
|
+
inclusive: true
|
|
409
|
+
}, 'user');
|
|
370
410
|
if (!Array.isArray(history.messages) || history.messages.length === 0) {
|
|
371
411
|
throw new Error('No message found for the provided timestamp.');
|
|
372
412
|
}
|
|
373
|
-
return client.request('chat.delete', {
|
|
374
|
-
|
|
413
|
+
return client.request('chat.delete', {
|
|
414
|
+
channel: input.channel,
|
|
415
|
+
ts
|
|
416
|
+
}, 'user');
|
|
417
|
+
}
|
|
375
418
|
});
|
|
376
419
|
const createChannelInput = z.object({
|
|
377
420
|
channelName: z.string().min(1),
|
|
378
|
-
isPrivate: z.boolean().default(false)
|
|
421
|
+
isPrivate: z.boolean().default(false)
|
|
379
422
|
});
|
|
380
423
|
export const createChannel = defineAction({
|
|
381
424
|
slug: 'createChannel',
|
|
@@ -383,18 +426,18 @@ export const createChannel = defineAction({
|
|
|
383
426
|
input: createChannelInput,
|
|
384
427
|
output: slackResponse,
|
|
385
428
|
idempotent: false,
|
|
386
|
-
async run({ client, input }) {
|
|
429
|
+
async run ({ client, input }) {
|
|
387
430
|
return client.request('conversations.create', {
|
|
388
431
|
name: input.channelName,
|
|
389
|
-
is_private: input.isPrivate
|
|
432
|
+
is_private: input.isPrivate
|
|
390
433
|
});
|
|
391
|
-
}
|
|
434
|
+
}
|
|
392
435
|
});
|
|
393
436
|
const updateProfileInput = z.object({
|
|
394
437
|
firstName: z.string().optional(),
|
|
395
438
|
lastName: z.string().optional(),
|
|
396
439
|
email: z.email().optional(),
|
|
397
|
-
userId: z.string().optional()
|
|
440
|
+
userId: z.string().optional()
|
|
398
441
|
});
|
|
399
442
|
export const updateProfile = defineAction({
|
|
400
443
|
slug: 'updateProfile',
|
|
@@ -402,19 +445,23 @@ export const updateProfile = defineAction({
|
|
|
402
445
|
input: updateProfileInput,
|
|
403
446
|
output: slackResponse,
|
|
404
447
|
idempotent: true,
|
|
405
|
-
async run({ client, input }) {
|
|
448
|
+
async run ({ client, input }) {
|
|
406
449
|
return client.request('users.profile.set', {
|
|
407
|
-
profile: {
|
|
408
|
-
|
|
450
|
+
profile: {
|
|
451
|
+
first_name: input.firstName,
|
|
452
|
+
last_name: input.lastName,
|
|
453
|
+
email: input.email
|
|
454
|
+
},
|
|
455
|
+
user: input.userId
|
|
409
456
|
}, 'user');
|
|
410
|
-
}
|
|
457
|
+
}
|
|
411
458
|
});
|
|
412
459
|
const getChannelHistoryInput = z.object({
|
|
413
460
|
channel,
|
|
414
461
|
oldest: z.number().optional(),
|
|
415
462
|
latest: z.number().optional(),
|
|
416
463
|
inclusive: z.boolean().default(false),
|
|
417
|
-
includeAllMetadata: z.boolean().default(false)
|
|
464
|
+
includeAllMetadata: z.boolean().default(false)
|
|
418
465
|
});
|
|
419
466
|
export const getChannelHistory = defineAction({
|
|
420
467
|
slug: 'getChannelHistory',
|
|
@@ -422,8 +469,10 @@ export const getChannelHistory = defineAction({
|
|
|
422
469
|
input: getChannelHistoryInput,
|
|
423
470
|
output: slackValues,
|
|
424
471
|
idempotent: true,
|
|
425
|
-
options: {
|
|
426
|
-
|
|
472
|
+
options: {
|
|
473
|
+
channel: channelOptions
|
|
474
|
+
},
|
|
475
|
+
async run ({ client, input }) {
|
|
427
476
|
return client.paginate({
|
|
428
477
|
path: 'conversations.history',
|
|
429
478
|
item: 'messages',
|
|
@@ -433,15 +482,15 @@ export const getChannelHistory = defineAction({
|
|
|
433
482
|
latest: input.latest,
|
|
434
483
|
inclusive: input.inclusive,
|
|
435
484
|
include_all_metadata: input.includeAllMetadata,
|
|
436
|
-
limit: 200
|
|
437
|
-
}
|
|
485
|
+
limit: 200
|
|
486
|
+
}
|
|
438
487
|
});
|
|
439
|
-
}
|
|
488
|
+
}
|
|
440
489
|
});
|
|
441
490
|
const setUserStatusInput = z.object({
|
|
442
491
|
text: z.string().max(100),
|
|
443
492
|
emoji: z.string().optional(),
|
|
444
|
-
expiration: z.number().int().optional()
|
|
493
|
+
expiration: z.number().int().optional()
|
|
445
494
|
});
|
|
446
495
|
export const setUserStatus = defineAction({
|
|
447
496
|
slug: 'setUserStatus',
|
|
@@ -449,88 +498,118 @@ export const setUserStatus = defineAction({
|
|
|
449
498
|
input: setUserStatusInput,
|
|
450
499
|
output: slackResponse,
|
|
451
500
|
idempotent: true,
|
|
452
|
-
async run({ client, input }) {
|
|
501
|
+
async run ({ client, input }) {
|
|
453
502
|
return client.request('users.profile.set', {
|
|
454
503
|
profile: {
|
|
455
504
|
status_text: input.text,
|
|
456
505
|
status_emoji: input.emoji,
|
|
457
|
-
status_expiration: input.expiration
|
|
458
|
-
}
|
|
506
|
+
status_expiration: input.expiration
|
|
507
|
+
}
|
|
459
508
|
}, 'user');
|
|
460
|
-
}
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
const markdownToSlackInput = z.object({
|
|
512
|
+
markdown: z.string()
|
|
513
|
+
});
|
|
514
|
+
const markdownToSlackOutput = z.object({
|
|
515
|
+
text: z.string()
|
|
461
516
|
});
|
|
462
|
-
const markdownToSlackInput = z.object({ markdown: z.string() });
|
|
463
|
-
const markdownToSlackOutput = z.object({ text: z.string() });
|
|
464
517
|
export const markdownToSlack = defineAction({
|
|
465
518
|
slug: 'markdownToSlack',
|
|
466
519
|
description: 'Convert Markdown text to Slack mrkdwn.',
|
|
467
520
|
input: markdownToSlackInput,
|
|
468
521
|
output: markdownToSlackOutput,
|
|
469
522
|
idempotent: true,
|
|
470
|
-
async run({ input }) {
|
|
471
|
-
const text = input.markdown
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
523
|
+
async run ({ input }) {
|
|
524
|
+
const text = input.markdown.replace(/\[([^\]]+)]\((https?:\/\/[^)]+)\)/g, '<$2|$1>').replace(/\*\*([^*]+)\*\*/g, '*$1*').replace(/^[-+] /gm, '• ');
|
|
525
|
+
return {
|
|
526
|
+
text
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
const listThreadMessagesInput = z.object({
|
|
531
|
+
channel,
|
|
532
|
+
threadTimestamp: timestamp
|
|
477
533
|
});
|
|
478
|
-
const listThreadMessagesInput = z.object({ channel, threadTimestamp: timestamp });
|
|
479
534
|
export const listThreadMessages = defineAction({
|
|
480
535
|
slug: 'listThreadMessages',
|
|
481
536
|
description: 'Retrieve all messages in a Slack thread.',
|
|
482
537
|
input: listThreadMessagesInput,
|
|
483
538
|
output: slackValues,
|
|
484
539
|
idempotent: true,
|
|
485
|
-
options: {
|
|
486
|
-
|
|
540
|
+
options: {
|
|
541
|
+
channel: channelOptions
|
|
542
|
+
},
|
|
543
|
+
async run ({ client, input }) {
|
|
487
544
|
return client.paginate({
|
|
488
545
|
path: 'conversations.replies',
|
|
489
546
|
item: 'messages',
|
|
490
|
-
body: {
|
|
547
|
+
body: {
|
|
548
|
+
channel: input.channel,
|
|
549
|
+
ts: normalizeTimestamp(input.threadTimestamp)
|
|
550
|
+
}
|
|
491
551
|
});
|
|
492
|
-
}
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
const setChannelTopicInput = z.object({
|
|
555
|
+
channel,
|
|
556
|
+
topic: z.string()
|
|
493
557
|
});
|
|
494
|
-
const setChannelTopicInput = z.object({ channel, topic: z.string() });
|
|
495
558
|
export const setChannelTopic = defineAction({
|
|
496
559
|
slug: 'setChannelTopic',
|
|
497
560
|
description: 'Set a Slack channel topic.',
|
|
498
561
|
input: setChannelTopicInput,
|
|
499
562
|
output: slackResponse,
|
|
500
563
|
idempotent: true,
|
|
501
|
-
options: {
|
|
502
|
-
|
|
503
|
-
return client.request('conversations.setTopic', input);
|
|
564
|
+
options: {
|
|
565
|
+
channel: channelOptions
|
|
504
566
|
},
|
|
567
|
+
async run ({ client, input }) {
|
|
568
|
+
return client.request('conversations.setTopic', input);
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
const getMessageInput = z.object({
|
|
572
|
+
channel,
|
|
573
|
+
timestamp
|
|
505
574
|
});
|
|
506
|
-
const getMessageInput = z.object({ channel, timestamp });
|
|
507
575
|
export const getMessage = defineAction({
|
|
508
576
|
slug: 'getMessage',
|
|
509
577
|
description: 'Get a Slack message by channel and timestamp.',
|
|
510
578
|
input: getMessageInput,
|
|
511
579
|
output: slackResponse,
|
|
512
580
|
idempotent: true,
|
|
513
|
-
options: {
|
|
514
|
-
|
|
581
|
+
options: {
|
|
582
|
+
channel: channelOptions
|
|
583
|
+
},
|
|
584
|
+
async run ({ client, input }) {
|
|
515
585
|
return client.request('conversations.history', {
|
|
516
586
|
channel: input.channel,
|
|
517
587
|
oldest: normalizeTimestamp(input.timestamp),
|
|
518
588
|
limit: 1,
|
|
519
|
-
inclusive: true
|
|
589
|
+
inclusive: true
|
|
520
590
|
});
|
|
521
|
-
}
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
const inviteUserToChannelInput = z.object({
|
|
594
|
+
channel,
|
|
595
|
+
userId: user
|
|
522
596
|
});
|
|
523
|
-
const inviteUserToChannelInput = z.object({ channel, userId: user });
|
|
524
597
|
export const inviteUserToChannel = defineAction({
|
|
525
598
|
slug: 'inviteUserToChannel',
|
|
526
599
|
description: 'Invite an existing user to a Slack channel.',
|
|
527
600
|
input: inviteUserToChannelInput,
|
|
528
601
|
output: slackResponse,
|
|
529
602
|
idempotent: false,
|
|
530
|
-
options: {
|
|
531
|
-
|
|
532
|
-
|
|
603
|
+
options: {
|
|
604
|
+
channel: channelOptions,
|
|
605
|
+
userId: userOptions
|
|
533
606
|
},
|
|
607
|
+
async run ({ client, input }) {
|
|
608
|
+
return client.request('conversations.invite', {
|
|
609
|
+
channel: input.channel,
|
|
610
|
+
users: input.userId
|
|
611
|
+
});
|
|
612
|
+
}
|
|
534
613
|
});
|
|
535
614
|
export const getUserGroupByHandle = defineAction({
|
|
536
615
|
slug: 'getUserGroupByHandle',
|
|
@@ -538,18 +617,15 @@ export const getUserGroupByHandle = defineAction({
|
|
|
538
617
|
input: handleInput,
|
|
539
618
|
output: slackValue,
|
|
540
619
|
idempotent: true,
|
|
541
|
-
async run({ client, input }) {
|
|
620
|
+
async run ({ client, input }) {
|
|
542
621
|
return findUserGroup(client, input.handle);
|
|
543
|
-
}
|
|
622
|
+
}
|
|
544
623
|
});
|
|
545
624
|
async function findUserGroup(client, value) {
|
|
546
625
|
const handle = value.replace(/^@/, '').toLowerCase();
|
|
547
626
|
const response = await client.request('usergroups.list');
|
|
548
627
|
const groups = Array.isArray(response.usergroups) ? response.usergroups : [];
|
|
549
|
-
const found = groups.find((group)
|
|
550
|
-
typeof group === 'object' &&
|
|
551
|
-
'handle' in group &&
|
|
552
|
-
String(group.handle).toLowerCase() === handle);
|
|
628
|
+
const found = groups.find((group)=>group && typeof group === 'object' && 'handle' in group && String(group.handle).toLowerCase() === handle);
|
|
553
629
|
if (!found || typeof found !== 'object') {
|
|
554
630
|
throw new Error(`User group with handle '@${handle}' not found.`);
|
|
555
631
|
}
|
|
@@ -557,7 +633,7 @@ async function findUserGroup(client, value) {
|
|
|
557
633
|
}
|
|
558
634
|
const updateUserGroupMembersInput = handleInput.extend({
|
|
559
635
|
userIds: z.array(z.string()).optional(),
|
|
560
|
-
appendUsers: z.boolean().default(true)
|
|
636
|
+
appendUsers: z.boolean().default(true)
|
|
561
637
|
});
|
|
562
638
|
export const updateUserGroupMembers = defineAction({
|
|
563
639
|
slug: 'updateUserGroupMembers',
|
|
@@ -565,23 +641,39 @@ export const updateUserGroupMembers = defineAction({
|
|
|
565
641
|
input: updateUserGroupMembersInput,
|
|
566
642
|
output: slackResponse,
|
|
567
643
|
idempotent: false,
|
|
568
|
-
async run({ client, input }) {
|
|
644
|
+
async run ({ client, input }) {
|
|
569
645
|
const group = await findUserGroup(client, input.handle);
|
|
570
646
|
const id = 'id' in group ? String(group.id) : '';
|
|
571
|
-
const existing = input.appendUsers && 'users' in group && Array.isArray(group.users)
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
647
|
+
const existing = input.appendUsers && 'users' in group && Array.isArray(group.users) ? group.users.map(String) : [];
|
|
648
|
+
const users = [
|
|
649
|
+
...new Set([
|
|
650
|
+
...existing,
|
|
651
|
+
...(input.userIds ?? []).filter(Boolean)
|
|
652
|
+
])
|
|
653
|
+
].join(', ');
|
|
654
|
+
return client.request('usergroups.users.update', {
|
|
655
|
+
usergroup: id,
|
|
656
|
+
users
|
|
657
|
+
}, 'user');
|
|
658
|
+
}
|
|
577
659
|
});
|
|
578
660
|
const customApiInput = z.object({
|
|
579
|
-
method: z.enum([
|
|
661
|
+
method: z.enum([
|
|
662
|
+
'GET',
|
|
663
|
+
'POST',
|
|
664
|
+
'PUT',
|
|
665
|
+
'PATCH',
|
|
666
|
+
'DELETE'
|
|
667
|
+
]),
|
|
580
668
|
path: z.string().regex(/^[a-zA-Z][a-zA-Z0-9._-]*$/),
|
|
581
669
|
headers: z.record(z.string(), z.string()).default({}),
|
|
582
|
-
queryParams: z.record(z.string(), z.union([
|
|
670
|
+
queryParams: z.record(z.string(), z.union([
|
|
671
|
+
z.string(),
|
|
672
|
+
z.number(),
|
|
673
|
+
z.boolean()
|
|
674
|
+
])).default({}),
|
|
583
675
|
body: z.record(z.string(), z.unknown()).optional(),
|
|
584
|
-
useUserToken: z.boolean().default(false)
|
|
676
|
+
useUserToken: z.boolean().default(false)
|
|
585
677
|
});
|
|
586
678
|
export const customApiCall = defineAction({
|
|
587
679
|
slug: 'customApiCall',
|
|
@@ -589,10 +681,9 @@ export const customApiCall = defineAction({
|
|
|
589
681
|
input: customApiInput,
|
|
590
682
|
output: slackApiResult,
|
|
591
683
|
idempotent: false,
|
|
592
|
-
async run({ client, input }) {
|
|
684
|
+
async run ({ client, input }) {
|
|
593
685
|
const query = new URLSearchParams();
|
|
594
|
-
for (const [key, value] of Object.entries(input.queryParams))
|
|
595
|
-
query.set(key, String(value));
|
|
686
|
+
for (const [key, value] of Object.entries(input.queryParams))query.set(key, String(value));
|
|
596
687
|
const suffix = query.size ? `?${query}` : '';
|
|
597
688
|
const headers = new Headers(input.headers);
|
|
598
689
|
headers.delete('authorization');
|
|
@@ -606,9 +697,9 @@ export const customApiCall = defineAction({
|
|
|
606
697
|
method: input.method,
|
|
607
698
|
headers,
|
|
608
699
|
body: input.body === undefined ? undefined : JSON.stringify(input.body),
|
|
609
|
-
token: input.useUserToken ? 'user' : 'bot'
|
|
700
|
+
token: input.useUserToken ? 'user' : 'bot'
|
|
610
701
|
});
|
|
611
|
-
}
|
|
702
|
+
}
|
|
612
703
|
});
|
|
613
704
|
export const slackActions = [
|
|
614
705
|
addReaction,
|
|
@@ -634,6 +725,7 @@ export const slackActions = [
|
|
|
634
725
|
inviteUserToChannel,
|
|
635
726
|
getUserGroupByHandle,
|
|
636
727
|
updateUserGroupMembers,
|
|
637
|
-
customApiCall
|
|
728
|
+
customApiCall
|
|
638
729
|
];
|
|
730
|
+
|
|
639
731
|
//# sourceMappingURL=actions.js.map
|