@pipedream/slack_v2 0.7.0 → 1.0.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/actions/add-emoji-reaction/add-emoji-reaction.mjs +2 -2
- package/actions/add-reaction/add-reaction.mjs +2 -1
- package/actions/archive-channel/archive-channel.mjs +3 -10
- package/actions/browse-files/browse-files.mjs +2 -1
- package/actions/common/build-blocks.mjs +44 -106
- package/actions/common/send-message.mjs +5 -59
- package/actions/create-channel/create-channel.mjs +2 -1
- package/actions/create-reminder/create-reminder.mjs +2 -1
- package/actions/delete-file/delete-file.mjs +2 -4
- package/actions/delete-message/delete-message.mjs +8 -6
- package/actions/edit-message/edit-message.mjs +21 -2
- package/actions/find-message/find-message.mjs +2 -1
- package/actions/find-user-by-email/find-user-by-email.mjs +2 -1
- package/actions/find-user-by-id/find-user-by-id.mjs +4 -3
- package/actions/get-channel-details/get-channel-details.mjs +3 -2
- package/actions/get-channel-history/get-channel-history.mjs +8 -6
- package/actions/get-current-user/get-current-user.mjs +3 -2
- package/actions/get-file/get-file.mjs +2 -12
- package/actions/get-thread-replies/get-thread-replies.mjs +2 -1
- package/actions/get-user-details/get-user-details.mjs +2 -1
- package/actions/invite-user-to-channel/invite-user-to-channel.mjs +2 -1
- package/actions/kick-user/kick-user.mjs +2 -12
- package/actions/list-channels/list-channels.mjs +29 -10
- package/actions/list-emojis/list-emojis.mjs +2 -1
- package/actions/list-files/list-files.mjs +6 -11
- package/actions/list-group-conversations/list-group-conversations.mjs +86 -0
- package/actions/list-group-members/list-group-members.mjs +3 -2
- package/actions/list-icon-emoji-options/list-icon-emoji-options.mjs +6 -3
- package/actions/list-members-in-channel/list-members-in-channel.mjs +2 -1
- package/actions/list-messages/list-messages.mjs +8 -3
- package/actions/list-reminder-options/list-reminder-options.mjs +10 -3
- package/actions/list-replies/list-replies.mjs +2 -9
- package/actions/list-teams/list-teams.mjs +88 -0
- package/actions/list-user-group-options/list-user-group-options.mjs +10 -3
- package/actions/list-users/list-users.mjs +2 -1
- package/actions/post-message/post-message.mjs +30 -3
- package/actions/reply-to-a-message/reply-to-a-message.mjs +13 -12
- package/actions/search/search.mjs +2 -1
- package/actions/send-block-kit-message/send-block-kit-message.mjs +2 -1
- package/actions/send-large-message/send-large-message.mjs +2 -1
- package/actions/send-message/send-message.mjs +5 -15
- package/actions/send-message-advanced/send-message-advanced.mjs +46 -4
- package/actions/send-message-to-channel/send-message-to-channel.mjs +10 -10
- package/actions/send-message-to-user-or-group/send-message-to-user-or-group.mjs +4 -9
- package/actions/set-channel-description/set-channel-description.mjs +2 -1
- package/actions/set-channel-topic/set-channel-topic.mjs +2 -1
- package/actions/set-status/set-status.mjs +4 -3
- package/actions/update-group-members/update-group-members.mjs +5 -4
- package/actions/update-message/update-message.mjs +3 -2
- package/actions/update-profile/update-profile.mjs +3 -2
- package/actions/upload-file/upload-file.mjs +7 -2
- package/actions/verify-slack-signature/verify-slack-signature.mjs +4 -3
- package/common/constants.mjs +16 -0
- package/package.json +2 -2
- package/slack_v2.app.mjs +43 -370
- package/sources/new-channel-created/new-channel-created.mjs +1 -1
- package/sources/new-interaction-event-received/new-interaction-event-received.mjs +1 -1
- package/sources/new-keyword-mention/new-keyword-mention.mjs +1 -1
- package/sources/new-message-in-channels/new-message-in-channels.mjs +1 -1
- package/sources/new-private-channel-created/new-private-channel-created.mjs +1 -1
- package/sources/new-reaction-added/new-reaction-added.mjs +1 -1
- package/sources/new-saved-message/new-saved-message.mjs +1 -1
- package/sources/new-user-added/new-user-added.mjs +1 -1
- package/sources/new-user-mention/new-user-mention.mjs +1 -1
package/slack_v2.app.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
// x-pd-ai: optimized
|
|
2
|
+
import { WebClient } from "@slack/web-api@8.0.0";
|
|
2
3
|
import constants from "./common/constants.mjs";
|
|
3
4
|
import get from "lodash/get.js";
|
|
4
5
|
import retry from "async-retry";
|
|
@@ -11,305 +12,37 @@ export default {
|
|
|
11
12
|
user: {
|
|
12
13
|
type: "string",
|
|
13
14
|
label: "User",
|
|
14
|
-
description: "
|
|
15
|
-
useQuery: true,
|
|
16
|
-
async options({
|
|
17
|
-
prevContext, channelId, query,
|
|
18
|
-
}) {
|
|
19
|
-
let nameQuery = query
|
|
20
|
-
?.trim()
|
|
21
|
-
.toLowerCase()
|
|
22
|
-
.replace(/^@/, "");
|
|
23
|
-
if (/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(nameQuery ?? "")) {
|
|
24
|
-
try {
|
|
25
|
-
const { user } = await this.lookupUserByEmail({
|
|
26
|
-
email: nameQuery,
|
|
27
|
-
throwRateLimitError: true,
|
|
28
|
-
});
|
|
29
|
-
return {
|
|
30
|
-
options: [
|
|
31
|
-
{
|
|
32
|
-
label: user.profile?.real_name || user.name,
|
|
33
|
-
value: user.id,
|
|
34
|
-
},
|
|
35
|
-
],
|
|
36
|
-
};
|
|
37
|
-
} catch {
|
|
38
|
-
// Token may lack `users:read.email`, or no member has this email.
|
|
39
|
-
// Fall back to matching names below with the email's local part.
|
|
40
|
-
nameQuery = nameQuery.split("@")[0].replace(/[._-]+/g, " ");
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
let channelMembers;
|
|
44
|
-
if (channelId) {
|
|
45
|
-
const { members } = await this.listChannelMembers({
|
|
46
|
-
channel: channelId,
|
|
47
|
-
throwRateLimitError: true,
|
|
48
|
-
});
|
|
49
|
-
channelMembers = new Set(members);
|
|
50
|
-
}
|
|
51
|
-
const options = [];
|
|
52
|
-
let cursor = prevContext?.cursor;
|
|
53
|
-
let pages = 0;
|
|
54
|
-
do {
|
|
55
|
-
const {
|
|
56
|
-
members,
|
|
57
|
-
response_metadata: { next_cursor: nextCursor },
|
|
58
|
-
} = await this.usersList({
|
|
59
|
-
limit: constants.LIMIT,
|
|
60
|
-
cursor,
|
|
61
|
-
throwRateLimitError: true,
|
|
62
|
-
});
|
|
63
|
-
for (const member of members) {
|
|
64
|
-
const isSelectable = !member.deleted
|
|
65
|
-
&& !member.is_bot
|
|
66
|
-
&& member.id !== "USLACKBOT"
|
|
67
|
-
&& (!channelMembers || channelMembers.has(member.id));
|
|
68
|
-
if (isSelectable) {
|
|
69
|
-
const names = [
|
|
70
|
-
member.profile?.real_name,
|
|
71
|
-
member.profile?.display_name,
|
|
72
|
-
member.name,
|
|
73
|
-
];
|
|
74
|
-
if (!nameQuery || names.some((name) => name?.toLowerCase().includes(nameQuery))) {
|
|
75
|
-
options.push({
|
|
76
|
-
label: names.find(Boolean) ?? member.id,
|
|
77
|
-
value: member.id,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
cursor = nextCursor;
|
|
83
|
-
} while (cursor
|
|
84
|
-
&& options.length < constants.LIMIT
|
|
85
|
-
&& ++pages < constants.MAX_NAME_LOOKUP_PAGES);
|
|
86
|
-
return {
|
|
87
|
-
options,
|
|
88
|
-
context: {
|
|
89
|
-
cursor,
|
|
90
|
-
},
|
|
91
|
-
};
|
|
92
|
-
},
|
|
15
|
+
description: "The user's ID (e.g. `U1234567890`). Use **Find User by Email** to resolve an ID from an email address, or **List Users** to browse all users.",
|
|
93
16
|
},
|
|
94
17
|
group: {
|
|
95
18
|
type: "string",
|
|
96
19
|
label: "Group",
|
|
97
|
-
description: "
|
|
98
|
-
async options({ prevContext }) {
|
|
99
|
-
let { cursor } = prevContext;
|
|
100
|
-
const types = [
|
|
101
|
-
"mpim",
|
|
102
|
-
];
|
|
103
|
-
const resp = await this.availableConversations(types.join(), cursor, true);
|
|
104
|
-
return {
|
|
105
|
-
options: resp.conversations.map((c) => {
|
|
106
|
-
return {
|
|
107
|
-
label: c.purpose.value,
|
|
108
|
-
value: c.id,
|
|
109
|
-
};
|
|
110
|
-
}),
|
|
111
|
-
context: {
|
|
112
|
-
cursor: resp.cursor,
|
|
113
|
-
},
|
|
114
|
-
};
|
|
115
|
-
},
|
|
20
|
+
description: "The ID of a multi-person direct message (group DM) conversation (e.g. `G1234567890`). Use **List Group Conversations** to find valid IDs.",
|
|
116
21
|
},
|
|
117
22
|
userGroup: {
|
|
118
23
|
type: "string",
|
|
119
24
|
label: "User Group",
|
|
120
|
-
description: "The encoded ID of the User Group.",
|
|
121
|
-
async options() {
|
|
122
|
-
const { usergroups } = await this.usergroupsList({
|
|
123
|
-
throwRateLimitError: true,
|
|
124
|
-
});
|
|
125
|
-
return usergroups.map((c) => ({
|
|
126
|
-
label: c.name,
|
|
127
|
-
value: c.id,
|
|
128
|
-
}));
|
|
129
|
-
},
|
|
25
|
+
description: "The encoded ID of the User Group (e.g. `S1234567890`). Use **List User Group Options** to find valid IDs.",
|
|
130
26
|
},
|
|
131
27
|
reminder: {
|
|
132
28
|
type: "string",
|
|
133
29
|
label: "Reminder",
|
|
134
|
-
description: "
|
|
135
|
-
async options() {
|
|
136
|
-
const { reminders } = await this.remindersList({
|
|
137
|
-
throwRateLimitError: true,
|
|
138
|
-
});
|
|
139
|
-
return reminders.map((c) => ({
|
|
140
|
-
label: c.text,
|
|
141
|
-
value: c.id,
|
|
142
|
-
}));
|
|
143
|
-
},
|
|
30
|
+
description: "The encoded ID of the reminder (e.g. `Rm1234567890`). Use **List Reminder Options** to find valid IDs.",
|
|
144
31
|
},
|
|
145
32
|
conversation: {
|
|
146
33
|
type: "string",
|
|
147
34
|
label: "Channel",
|
|
148
|
-
description: "
|
|
149
|
-
async options({
|
|
150
|
-
prevContext, types,
|
|
151
|
-
}) {
|
|
152
|
-
let { cursor } = prevContext;
|
|
153
|
-
if (prevContext?.types) {
|
|
154
|
-
types = prevContext.types;
|
|
155
|
-
}
|
|
156
|
-
if (types == null) {
|
|
157
|
-
const { response_metadata: { scopes } } = await this.authTest({
|
|
158
|
-
throwRateLimitError: true,
|
|
159
|
-
});
|
|
160
|
-
types = [
|
|
161
|
-
"public_channel",
|
|
162
|
-
];
|
|
163
|
-
if (scopes.includes("groups:read")) {
|
|
164
|
-
types.push("private_channel");
|
|
165
|
-
}
|
|
166
|
-
if (scopes.includes("mpim:read")) {
|
|
167
|
-
types.push("mpim");
|
|
168
|
-
}
|
|
169
|
-
if (scopes.includes("im:read")) {
|
|
170
|
-
types.push("im");
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
const conversationsResp = await this.availableConversations(types.join(), cursor, true);
|
|
174
|
-
let conversations, userIds, userNames, realNames;
|
|
175
|
-
if (types.includes("im")) {
|
|
176
|
-
conversations = conversationsResp.conversations;
|
|
177
|
-
userIds = conversations.map(({ user }) => user).filter(Boolean);
|
|
178
|
-
} else {
|
|
179
|
-
conversations = conversationsResp.conversations.filter((c) => !c.is_im);
|
|
180
|
-
}
|
|
181
|
-
if (types.includes("mpim")) {
|
|
182
|
-
userNames = [
|
|
183
|
-
...new Set(conversations.filter((c) => c.is_mpim).map((c) => c.purpose.value)
|
|
184
|
-
.map((v) => v.match(/@[\w.-]+/g) || [])
|
|
185
|
-
.flat()
|
|
186
|
-
.map((u) => u.slice(1))),
|
|
187
|
-
];
|
|
188
|
-
}
|
|
189
|
-
if ((userIds?.length > 0) || (userNames?.length > 0)) {
|
|
190
|
-
// Look up real names for userIds and userNames at the same time to
|
|
191
|
-
// minimize number of API calls.
|
|
192
|
-
realNames = await this.realNameLookup(userIds, userNames);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return {
|
|
196
|
-
options: conversations.map((c) => {
|
|
197
|
-
if (c.is_im) {
|
|
198
|
-
return {
|
|
199
|
-
label: `Direct messaging with: ${realNames?.[c.user] ?? c.user}`,
|
|
200
|
-
value: c.id,
|
|
201
|
-
};
|
|
202
|
-
} else if (c.is_mpim) {
|
|
203
|
-
const usernames = c.purpose.value.match(/@[\w.-]+/g) || [];
|
|
204
|
-
const realnames = usernames.map((u) => realNames?.[u.slice(1)] || u);
|
|
205
|
-
return {
|
|
206
|
-
label: realnames.length
|
|
207
|
-
? `Group messaging with: ${realnames.join(", ")}`
|
|
208
|
-
: c.purpose.value,
|
|
209
|
-
value: c.id,
|
|
210
|
-
};
|
|
211
|
-
} else {
|
|
212
|
-
return {
|
|
213
|
-
label: `${c.is_private
|
|
214
|
-
? "Private"
|
|
215
|
-
: "Public"} channel: ${c.name}`,
|
|
216
|
-
value: c.id,
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
}),
|
|
220
|
-
context: {
|
|
221
|
-
types,
|
|
222
|
-
cursor: conversationsResp.cursor,
|
|
223
|
-
},
|
|
224
|
-
};
|
|
225
|
-
},
|
|
35
|
+
description: "A channel ID (e.g. `C1234567890`), or, depending on the action, a user ID (opens a direct message) or a group DM ID. Use **List Channels** to look up channel IDs, **Find User by Email** / **Find User by ID** to resolve a user ID, or **List Group Conversations** for group DM IDs.",
|
|
226
36
|
},
|
|
227
37
|
channelId: {
|
|
228
38
|
type: "string",
|
|
229
39
|
label: "Channel ID",
|
|
230
|
-
description: "
|
|
231
|
-
async options({
|
|
232
|
-
prevContext,
|
|
233
|
-
types = Object.values(constants.CHANNEL_TYPE),
|
|
234
|
-
channelsFilter = (channel) => channel,
|
|
235
|
-
excludeArchived = true,
|
|
236
|
-
}) {
|
|
237
|
-
const {
|
|
238
|
-
channels,
|
|
239
|
-
response_metadata: { next_cursor: cursor },
|
|
240
|
-
} = await this.conversationsList({
|
|
241
|
-
types: types.join(),
|
|
242
|
-
cursor: prevContext.cursor,
|
|
243
|
-
limit: constants.LIMIT,
|
|
244
|
-
exclude_archived: excludeArchived,
|
|
245
|
-
throwRateLimitError: true,
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
let userNames;
|
|
249
|
-
if (types.includes("im")) {
|
|
250
|
-
const userIds = channels.filter(({ is_im }) => is_im).map(({ user }) => user);
|
|
251
|
-
userNames = await this.userNameLookup(userIds);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
const options = channels
|
|
255
|
-
.filter(channelsFilter)
|
|
256
|
-
.map((c) => {
|
|
257
|
-
if (c.is_im) {
|
|
258
|
-
const userName = userNames?.[c.user];
|
|
259
|
-
return {
|
|
260
|
-
label: `Direct messaging with: ${userName
|
|
261
|
-
? `@${userName}`
|
|
262
|
-
: c.user}`,
|
|
263
|
-
value: c.id,
|
|
264
|
-
};
|
|
265
|
-
} else if (c.is_mpim) {
|
|
266
|
-
return {
|
|
267
|
-
label: c.purpose.value,
|
|
268
|
-
value: c.id,
|
|
269
|
-
};
|
|
270
|
-
} else {
|
|
271
|
-
return {
|
|
272
|
-
label: `${c.is_private
|
|
273
|
-
? "Private"
|
|
274
|
-
: "Public"} channel: ${c.name}`,
|
|
275
|
-
value: c.id,
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
return {
|
|
281
|
-
options,
|
|
282
|
-
context: {
|
|
283
|
-
cursor,
|
|
284
|
-
},
|
|
285
|
-
};
|
|
286
|
-
},
|
|
40
|
+
description: "The channel's ID (e.g. `C1234567890`). Use **List Channels** to find valid IDs.",
|
|
287
41
|
},
|
|
288
42
|
team: {
|
|
289
43
|
type: "string",
|
|
290
44
|
label: "Team",
|
|
291
|
-
description: "
|
|
292
|
-
async options({ prevContext }) {
|
|
293
|
-
const {
|
|
294
|
-
teams,
|
|
295
|
-
response_metadata: { next_cursor: cursor },
|
|
296
|
-
} = await this.authTeamsList({
|
|
297
|
-
cursor: prevContext.cursor,
|
|
298
|
-
limit: constants.LIMIT,
|
|
299
|
-
throwRateLimitError: true,
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
return {
|
|
303
|
-
options: teams.map((team) => ({
|
|
304
|
-
label: team.name,
|
|
305
|
-
value: team.id,
|
|
306
|
-
})),
|
|
307
|
-
|
|
308
|
-
context: {
|
|
309
|
-
cursor,
|
|
310
|
-
},
|
|
311
|
-
};
|
|
312
|
-
},
|
|
45
|
+
description: "The encoded team ID (e.g. `T1234567890`). Only required when the connected token spans multiple teams (Enterprise Grid); omit otherwise. Use **List Teams** to find valid IDs.",
|
|
313
46
|
},
|
|
314
47
|
messageTs: {
|
|
315
48
|
type: "string",
|
|
@@ -324,38 +57,22 @@ export default {
|
|
|
324
57
|
topic: {
|
|
325
58
|
type: "string",
|
|
326
59
|
label: "Topic",
|
|
327
|
-
description: "
|
|
60
|
+
description: "The new topic text to display in the channel header (e.g. `Q3 roadmap discussion`). Slack truncates topics longer than 250 characters.",
|
|
328
61
|
},
|
|
329
62
|
purpose: {
|
|
330
63
|
type: "string",
|
|
331
64
|
label: "Purpose",
|
|
332
|
-
description: "
|
|
65
|
+
description: "The new purpose/description text for the channel, shown in the channel details panel (e.g. `Channel for engineering incident coordination`). Limited to 250 characters by Slack.",
|
|
333
66
|
},
|
|
334
67
|
query: {
|
|
335
68
|
type: "string",
|
|
336
69
|
label: "Query",
|
|
337
|
-
description: "
|
|
70
|
+
description: "The search query. Supports Slack search modifiers, e.g. `from:@user`, `in:#channel`, `before:2025-01-01`, `has:link`. Combine terms and modifiers as needed, e.g. `budget in:#finance from:@jane`.",
|
|
338
71
|
},
|
|
339
72
|
file: {
|
|
340
73
|
type: "string",
|
|
341
74
|
label: "File ID",
|
|
342
|
-
description: "
|
|
343
|
-
async options({
|
|
344
|
-
channel, page,
|
|
345
|
-
}) {
|
|
346
|
-
const { files } = await this.listFiles({
|
|
347
|
-
channel,
|
|
348
|
-
page: page + 1,
|
|
349
|
-
count: constants.LIMIT,
|
|
350
|
-
throwRateLimitError: true,
|
|
351
|
-
});
|
|
352
|
-
return files?.map(({
|
|
353
|
-
id: value, name: label,
|
|
354
|
-
}) => ({
|
|
355
|
-
value,
|
|
356
|
-
label,
|
|
357
|
-
})) || [];
|
|
358
|
-
},
|
|
75
|
+
description: "The file's ID (e.g. `F1234567890`). Use **List Files** to find valid IDs.",
|
|
359
76
|
},
|
|
360
77
|
attachments: {
|
|
361
78
|
type: "string",
|
|
@@ -418,13 +135,8 @@ export default {
|
|
|
418
135
|
icon_emoji: {
|
|
419
136
|
type: "string",
|
|
420
137
|
label: "Icon (emoji)",
|
|
421
|
-
description: "Optionally provide an emoji to use as the icon for this message. E.g., `:fire
|
|
138
|
+
description: "Optionally provide an emoji to use as the icon for this message, wrapped in colons. E.g., `:fire:`. Overrides `icon_url`. Must be used in conjunction with `Send as User` set to `false`, otherwise ignored. Use **List Icon (emoji) Options** to look up valid emoji names for this workspace, including custom emoji.",
|
|
422
139
|
optional: true,
|
|
423
|
-
async options() {
|
|
424
|
-
return await this.getCustomEmojis({
|
|
425
|
-
throwRateLimitError: true,
|
|
426
|
-
});
|
|
427
|
-
},
|
|
428
140
|
},
|
|
429
141
|
content: {
|
|
430
142
|
label: "File Path or URL",
|
|
@@ -435,7 +147,7 @@ export default {
|
|
|
435
147
|
link_names: {
|
|
436
148
|
type: "boolean",
|
|
437
149
|
label: "Link Names",
|
|
438
|
-
description: "
|
|
150
|
+
description: "If `true`, automatically converts plain-text `@name` and `#channel` mentions in `text` into linked Slack mentions. If `false` (default), mentions are left as plain text and won't notify or link. Has no effect when using `blocks`.",
|
|
439
151
|
optional: true,
|
|
440
152
|
},
|
|
441
153
|
thread_broadcast: {
|
|
@@ -519,6 +231,12 @@ export default {
|
|
|
519
231
|
default: 1,
|
|
520
232
|
optional: true,
|
|
521
233
|
},
|
|
234
|
+
cursor: {
|
|
235
|
+
type: "string",
|
|
236
|
+
label: "Cursor",
|
|
237
|
+
description: "Resume from a previous call's `next_cursor` to fetch the following page.",
|
|
238
|
+
optional: true,
|
|
239
|
+
},
|
|
522
240
|
addToChannel: {
|
|
523
241
|
type: "boolean",
|
|
524
242
|
label: "Add app to channel automatically?",
|
|
@@ -651,34 +369,6 @@ export default {
|
|
|
651
369
|
}
|
|
652
370
|
}, retryOpts);
|
|
653
371
|
},
|
|
654
|
-
/**
|
|
655
|
-
* Returns a list of channel-like conversations in a workspace. The
|
|
656
|
-
* "channels" returned depend on what the calling token has access to and
|
|
657
|
-
* the directives placed in the types parameter.
|
|
658
|
-
*
|
|
659
|
-
* @param {string} [types] - a comma-separated list of channel types to get.
|
|
660
|
-
* Any combination of: `public_channel`, `private_channel`, `mpim`, `im`
|
|
661
|
-
* @param {string} [cursor] - a cursor returned by the previous API call,
|
|
662
|
-
* used to paginate through collections of data
|
|
663
|
-
* @returns an object containing a list of conversations and the cursor for the next
|
|
664
|
-
* page of conversations
|
|
665
|
-
*/
|
|
666
|
-
async availableConversations(types, cursor, throwRateLimitError = false) {
|
|
667
|
-
const {
|
|
668
|
-
channels: conversations,
|
|
669
|
-
response_metadata: { next_cursor: nextCursor },
|
|
670
|
-
} = await this.usersConversations({
|
|
671
|
-
types,
|
|
672
|
-
cursor,
|
|
673
|
-
limit: constants.LIMIT,
|
|
674
|
-
exclude_archived: true,
|
|
675
|
-
throwRateLimitError,
|
|
676
|
-
});
|
|
677
|
-
return {
|
|
678
|
-
cursor: nextCursor,
|
|
679
|
-
conversations,
|
|
680
|
-
};
|
|
681
|
-
},
|
|
682
372
|
// Resolves user names by scanning `users.list`, capped at
|
|
683
373
|
// MAX_NAME_LOOKUP_PAGES pages per call: some ids may be unresolvable
|
|
684
374
|
// (e.g. external Slack Connect users), so callers must handle missing
|
|
@@ -710,44 +400,6 @@ export default {
|
|
|
710
400
|
&& Object.keys(userNames).length < ids.length);
|
|
711
401
|
return userNames;
|
|
712
402
|
},
|
|
713
|
-
// Resolves real names by scanning `users.list`, capped at
|
|
714
|
-
// MAX_NAME_LOOKUP_PAGES pages per call: some ids/usernames may be
|
|
715
|
-
// unresolvable (e.g. external Slack Connect users, or stale usernames in
|
|
716
|
-
// mpim purpose text), so callers must handle missing entries in the
|
|
717
|
-
// result.
|
|
718
|
-
async realNameLookup(ids = [], usernames = [], throwRateLimitError = true, args = {}) {
|
|
719
|
-
const idSet = new Set(ids);
|
|
720
|
-
const usernameSet = new Set(usernames);
|
|
721
|
-
let cursor;
|
|
722
|
-
let pages = 0;
|
|
723
|
-
const realNames = {};
|
|
724
|
-
const targetCount = ids.length + usernames.length;
|
|
725
|
-
do {
|
|
726
|
-
const {
|
|
727
|
-
members: users,
|
|
728
|
-
response_metadata: { next_cursor: nextCursor },
|
|
729
|
-
} = await this.usersList({
|
|
730
|
-
limit: constants.LIMIT,
|
|
731
|
-
cursor,
|
|
732
|
-
throwRateLimitError,
|
|
733
|
-
...args,
|
|
734
|
-
});
|
|
735
|
-
|
|
736
|
-
for (const user of users) {
|
|
737
|
-
if (idSet.has(user.id)) {
|
|
738
|
-
realNames[user.id] = user.profile.real_name;
|
|
739
|
-
}
|
|
740
|
-
if (usernameSet.has(user.name)) {
|
|
741
|
-
realNames[user.name] = user.profile.real_name;
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
cursor = nextCursor;
|
|
746
|
-
} while (cursor
|
|
747
|
-
&& ++pages < constants.MAX_NAME_LOOKUP_PAGES
|
|
748
|
-
&& Object.keys(realNames).length < targetCount);
|
|
749
|
-
return realNames;
|
|
750
|
-
},
|
|
751
403
|
async maybeAddAppToChannels(channelIds = []) {
|
|
752
404
|
if (!this.getBotToken()) {
|
|
753
405
|
console.log("Skipping adding app to channels: bot unavailable.");
|
|
@@ -1110,6 +762,12 @@ export default {
|
|
|
1110
762
|
...args,
|
|
1111
763
|
});
|
|
1112
764
|
},
|
|
765
|
+
openConversation(args = {}) {
|
|
766
|
+
return this.makeRequest({
|
|
767
|
+
method: "conversations.open",
|
|
768
|
+
...args,
|
|
769
|
+
});
|
|
770
|
+
},
|
|
1113
771
|
inviteToConversation(args = {}) {
|
|
1114
772
|
return this.makeRequest({
|
|
1115
773
|
method: "conversations.invite",
|
|
@@ -1278,7 +936,22 @@ export default {
|
|
|
1278
936
|
* @returns {Promise<string>} The resolved channel ID
|
|
1279
937
|
*/
|
|
1280
938
|
async resolveChannelId(input) {
|
|
1281
|
-
|
|
939
|
+
// Slack ids are UPPERCASE-only (e.g. `C0123ABCD`, `U0123ABCD`). Match case-sensitively:
|
|
940
|
+
// channel names are lowercased by Slack, so a `/i` match would misclassify an all-alnum
|
|
941
|
+
// name like `welcomeaboard` or `developers` (no hyphen, 9+ chars) as an id.
|
|
942
|
+
// Channel, private-group, and DM ids are already conversation ids — pass through.
|
|
943
|
+
if (/^[CDG][A-Z0-9]{8,}$/.test(input)) return input;
|
|
944
|
+
// A user id is NOT a conversation id — conversations.* answers `channel_not_found`
|
|
945
|
+
// for it. Open (idempotently) the DM with that user and use the returned IM channel.
|
|
946
|
+
// This is the read-side counterpart to chat.postMessage accepting a user id: an agent
|
|
947
|
+
// asked to read "my DMs" resolves its own user id and passes it here, and history,
|
|
948
|
+
// thread replies, and reactions now accept it the way posting already does.
|
|
949
|
+
if (/^[UW][A-Z0-9]{8,}$/.test(input)) {
|
|
950
|
+
const { channel } = await this.openConversation({
|
|
951
|
+
users: input,
|
|
952
|
+
});
|
|
953
|
+
return channel.id;
|
|
954
|
+
}
|
|
1282
955
|
const name = input.replace(/^#/, "").toLowerCase();
|
|
1283
956
|
let cursor;
|
|
1284
957
|
do {
|
|
@@ -3,7 +3,7 @@ import sampleEmit from "./test-event.mjs";
|
|
|
3
3
|
|
|
4
4
|
export default {
|
|
5
5
|
name: "New Interaction Events (Instant)",
|
|
6
|
-
version: "0.0.
|
|
6
|
+
version: "0.0.28",
|
|
7
7
|
key: "slack_v2-new-interaction-event-received",
|
|
8
8
|
description: "Emit new events on new Slack [interactivity events](https://api.slack.com/interactivity) sourced from [Block Kit interactive elements](https://api.slack.com/interactivity/components), [Slash commands](https://api.slack.com/interactivity/slash-commands), or [Shortcuts](https://api.slack.com/interactivity/shortcuts).",
|
|
9
9
|
type: "source",
|
|
@@ -7,7 +7,7 @@ export default {
|
|
|
7
7
|
...common,
|
|
8
8
|
key: "slack_v2-new-keyword-mention",
|
|
9
9
|
name: "New Keyword Mention (Instant)",
|
|
10
|
-
version: "0.1.
|
|
10
|
+
version: "0.1.7",
|
|
11
11
|
description: "Emit new event when a specific keyword is mentioned in a channel",
|
|
12
12
|
type: "source",
|
|
13
13
|
dedupe: "unique",
|
|
@@ -7,7 +7,7 @@ export default {
|
|
|
7
7
|
...common,
|
|
8
8
|
key: "slack_v2-new-message-in-channels",
|
|
9
9
|
name: "New Message In Channels (Instant)",
|
|
10
|
-
version: "1.1.
|
|
10
|
+
version: "1.1.7",
|
|
11
11
|
description: "Emit new event when a new message is posted to one or more channels",
|
|
12
12
|
type: "source",
|
|
13
13
|
dedupe: "unique",
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
...common,
|
|
5
5
|
key: "slack_v2-new-private-channel-created",
|
|
6
6
|
name: "New Private Channel Created",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.7",
|
|
8
8
|
description: "Emit new event when a new private channel is created. [See the documentation](https://api.slack.com/methods/conversations.list)",
|
|
9
9
|
type: "source",
|
|
10
10
|
dedupe: "unique",
|
|
@@ -5,7 +5,7 @@ export default {
|
|
|
5
5
|
...common,
|
|
6
6
|
key: "slack_v2-new-reaction-added",
|
|
7
7
|
name: "New Reaction Added (Instant)",
|
|
8
|
-
version: "1.2.
|
|
8
|
+
version: "1.2.7",
|
|
9
9
|
description: "Emit new event when a member has added an emoji reaction to a message",
|
|
10
10
|
type: "source",
|
|
11
11
|
dedupe: "unique",
|
|
@@ -5,7 +5,7 @@ export default {
|
|
|
5
5
|
...common,
|
|
6
6
|
key: "slack_v2-new-saved-message",
|
|
7
7
|
name: "New Saved Message (Instant)",
|
|
8
|
-
version: "0.0.
|
|
8
|
+
version: "0.0.13",
|
|
9
9
|
description: "Emit new event when a message is saved. Note: The endpoint is marked as deprecated, and Slack might shut this off at some point down the line.",
|
|
10
10
|
type: "source",
|
|
11
11
|
dedupe: "unique",
|
|
@@ -7,7 +7,7 @@ export default {
|
|
|
7
7
|
...common,
|
|
8
8
|
key: "slack_v2-new-user-mention",
|
|
9
9
|
name: "New User Mention (Instant)",
|
|
10
|
-
version: "0.1.
|
|
10
|
+
version: "0.1.7",
|
|
11
11
|
description: "Emit new event when a username or specific keyword is mentioned in a channel",
|
|
12
12
|
type: "source",
|
|
13
13
|
dedupe: "unique",
|