@pipedream/slack_v2 1.3.0 → 1.5.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 +1 -1
- package/actions/add-reaction/add-reaction.mjs +1 -1
- package/actions/archive-channel/archive-channel.mjs +1 -1
- package/actions/browse-files/browse-files.mjs +1 -1
- package/actions/create-channel/create-channel.mjs +1 -1
- package/actions/create-reminder/create-reminder.mjs +1 -1
- package/actions/delete-file/delete-file.mjs +1 -1
- package/actions/delete-message/delete-message.mjs +1 -1
- package/actions/download-file/download-file.mjs +83 -0
- package/actions/edit-message/edit-message.mjs +1 -1
- package/actions/find-message/find-message.mjs +1 -1
- package/actions/find-user-by-email/find-user-by-email.mjs +1 -1
- package/actions/find-user-by-id/find-user-by-id.mjs +1 -1
- package/actions/get-channel-details/get-channel-details.mjs +1 -1
- package/actions/get-channel-history/get-channel-history.mjs +1 -1
- package/actions/get-current-user/get-current-user.mjs +1 -1
- package/actions/get-file/get-file.mjs +1 -1
- package/actions/get-thread-replies/get-thread-replies.mjs +1 -1
- package/actions/get-user-details/get-user-details.mjs +1 -1
- package/actions/invite-user-to-channel/invite-user-to-channel.mjs +1 -1
- package/actions/kick-user/kick-user.mjs +1 -1
- package/actions/leave-channel/leave-channel.mjs +1 -1
- package/actions/list-channels/list-channels.mjs +1 -1
- package/actions/list-emojis/list-emojis.mjs +1 -1
- package/actions/list-files/list-files.mjs +1 -1
- package/actions/list-group-conversations/list-group-conversations.mjs +1 -1
- package/actions/list-group-members/list-group-members.mjs +1 -1
- package/actions/list-icon-emoji-options/list-icon-emoji-options.mjs +1 -1
- package/actions/list-members-in-channel/list-members-in-channel.mjs +1 -1
- package/actions/list-messages/list-messages.mjs +1 -1
- package/actions/list-reminder-options/list-reminder-options.mjs +1 -1
- package/actions/list-replies/list-replies.mjs +1 -1
- package/actions/list-teams/list-teams.mjs +1 -1
- package/actions/list-user-group-options/list-user-group-options.mjs +1 -1
- package/actions/list-users/list-users.mjs +1 -1
- package/actions/post-message/post-message.mjs +1 -1
- package/actions/reply-to-a-message/reply-to-a-message.mjs +1 -1
- package/actions/search/search.mjs +110 -8
- package/actions/send-block-kit-message/send-block-kit-message.mjs +1 -1
- package/actions/send-large-message/send-large-message.mjs +1 -1
- package/actions/send-message/send-message.mjs +1 -1
- package/actions/send-message-advanced/send-message-advanced.mjs +1 -1
- package/actions/send-message-to-channel/send-message-to-channel.mjs +1 -1
- package/actions/send-message-to-user-or-group/send-message-to-user-or-group.mjs +1 -1
- package/actions/set-channel-description/set-channel-description.mjs +1 -1
- package/actions/set-channel-topic/set-channel-topic.mjs +1 -1
- package/actions/set-status/set-status.mjs +1 -1
- package/actions/update-group-members/update-group-members.mjs +1 -1
- package/actions/update-message/update-message.mjs +1 -1
- package/actions/update-profile/update-profile.mjs +1 -1
- package/actions/upload-file/upload-file.mjs +1 -1
- package/actions/verify-slack-signature/verify-slack-signature.mjs +1 -1
- package/common/constants.mjs +26 -0
- package/common/utils.mjs +16 -0
- package/package.json +1 -1
- package/slack_v2.app.mjs +133 -10
- 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
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-add-emoji-reaction",
|
|
5
5
|
name: "Add Emoji Reaction",
|
|
6
6
|
description: "Add an emoji reaction to a message. [See the documentation](https://api.slack.com/methods/reactions.add)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.31",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: false,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -11,7 +11,7 @@ export default {
|
|
|
11
11
|
+ " Use **Get Channel History** or **Search** to find the message timestamp."
|
|
12
12
|
+ " Emoji name should be without colons (e.g. `thumbsup`, `fire`, `heart`)."
|
|
13
13
|
+ " [See the documentation](https://api.slack.com/methods/reactions.add)",
|
|
14
|
-
version: "0.0.
|
|
14
|
+
version: "0.0.11",
|
|
15
15
|
type: "action",
|
|
16
16
|
ai: "optimized",
|
|
17
17
|
annotations: {
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-archive-channel",
|
|
5
5
|
name: "Archive Channel",
|
|
6
6
|
description: "Archive a public or private channel. Direct messages and group DMs can't be archived — pass a channel ID (e.g. `C1234567890`), not a user or group ID. [See the documentation](https://api.slack.com/methods/conversations.archive)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.39",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: true,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -11,7 +11,7 @@ export default {
|
|
|
11
11
|
+ " Filter by file type (e.g. `images`, `pdfs`, `snippets`)."
|
|
12
12
|
+ " Returns file metadata including name, type, size, and download URL."
|
|
13
13
|
+ " [See the documentation](https://api.slack.com/methods/files.list)",
|
|
14
|
-
version: "0.0.
|
|
14
|
+
version: "0.0.11",
|
|
15
15
|
type: "action",
|
|
16
16
|
ai: "optimized",
|
|
17
17
|
annotations: {
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-create-channel",
|
|
5
5
|
name: "Create a Channel",
|
|
6
6
|
description: "Create a new channel. [See the documentation](https://api.slack.com/methods/conversations.create)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.39",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: false,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-create-reminder",
|
|
5
5
|
name: "Create Reminder",
|
|
6
6
|
description: "Create a reminder. [See the documentation](https://api.slack.com/methods/reminders.add)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.40",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: false,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-delete-file",
|
|
5
5
|
name: "Delete File",
|
|
6
6
|
description: "Delete a file. [See the documentation](https://api.slack.com/methods/files.delete)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.39",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: true,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -14,7 +14,7 @@ export default {
|
|
|
14
14
|
+ " lets an identity delete its own messages, so this deletes as whichever identity posted:"
|
|
15
15
|
+ " it retries automatically with the other identity if the first attempt returns"
|
|
16
16
|
+ " `cant_delete_message`. [See the documentation](https://api.slack.com/methods/chat.delete)",
|
|
17
|
-
version: "0.2.
|
|
17
|
+
version: "0.2.9",
|
|
18
18
|
annotations: {
|
|
19
19
|
destructiveHint: true,
|
|
20
20
|
openWorldHint: true,
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import slack from "../../slack_v2.app.mjs";
|
|
3
|
+
import constants from "../../common/constants.mjs";
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
key: "slack_v2-download-file",
|
|
7
|
+
name: "Download File",
|
|
8
|
+
description: "Download the content of a Slack file (e.g. an image, PDF or snippet shared in a channel) to the file-stash directory, returning the saved path plus the file metadata (`name`, `mimetype`, `size`). Canvases download as HTML. Get the file ID from a message's `files[].id` via **Get Channel History**, or from **List Files** / **Browse Files**. Works for files in private channels the authenticated user is a member of. Example: passing `file` `F0123456789` downloads `diagram.png` to `/tmp/F0123456789-diagram.png` and returns `{ \"filedata\": [\"F0123456789-diagram.png\", \"/tmp/F0123456789-diagram.png\"], \"file\": { \"id\": \"F0123456789\", \"name\": \"diagram.png\", \"mimetype\": \"image/png\", \"size\": 84213 } }`. [See the documentation](https://docs.slack.dev/reference/objects/file-object#access)",
|
|
9
|
+
version: "0.0.2",
|
|
10
|
+
type: "action",
|
|
11
|
+
ai: "optimized",
|
|
12
|
+
annotations: {
|
|
13
|
+
destructiveHint: false,
|
|
14
|
+
openWorldHint: true,
|
|
15
|
+
readOnlyHint: true,
|
|
16
|
+
},
|
|
17
|
+
props: {
|
|
18
|
+
slack,
|
|
19
|
+
file: {
|
|
20
|
+
propDefinition: [
|
|
21
|
+
slack,
|
|
22
|
+
"file",
|
|
23
|
+
],
|
|
24
|
+
description: "The file's ID (e.g. `F1234567890`). Run **Get Channel History** (a message's `files[].id`), **List Files** or **Browse Files** first to obtain it.",
|
|
25
|
+
},
|
|
26
|
+
syncDir: {
|
|
27
|
+
type: "dir",
|
|
28
|
+
accessMode: "write",
|
|
29
|
+
sync: true,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
async run({ $ }) {
|
|
33
|
+
const {
|
|
34
|
+
response: { file: metadata }, asBot,
|
|
35
|
+
} = await this.slack.makeFilesReadRequest({
|
|
36
|
+
method: "files.info",
|
|
37
|
+
file: this.file,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const url = metadata.url_private_download || metadata.url_private;
|
|
41
|
+
if (!url) {
|
|
42
|
+
throw new Error(`File "${this.file}" has no downloadable content. Slack only hosts content for files uploaded to Slack and canvases, so external files (e.g. Google Drive links) and deleted files can't be downloaded.`);
|
|
43
|
+
}
|
|
44
|
+
if (metadata.size > constants.MAX_DOWNLOAD_SIZE_BYTES) {
|
|
45
|
+
throw new Error(`File "${metadata.name}" is ${metadata.size} bytes, which exceeds the ${constants.MAX_DOWNLOAD_SIZE_BYTES}-byte (2GB) /tmp disk limit for this execution, so it cannot be downloaded.`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let safeFilename = path.basename(metadata.name ?? "");
|
|
49
|
+
if (!safeFilename || safeFilename === "." || safeFilename === "..") {
|
|
50
|
+
throw new Error(`Invalid filename "${metadata.name}" returned by Slack.`);
|
|
51
|
+
}
|
|
52
|
+
if (metadata.filetype === constants.CANVAS_FILETYPE && !path.extname(safeFilename)) {
|
|
53
|
+
safeFilename += ".html";
|
|
54
|
+
}
|
|
55
|
+
const savedFilename = `${metadata.id}-${safeFilename}`;
|
|
56
|
+
const stashDir = process.env.STASH_DIR || "/tmp";
|
|
57
|
+
const downloadedFilepath = path.join(stashDir, savedFilename);
|
|
58
|
+
|
|
59
|
+
const bytesWritten = await this.slack.downloadFileContent({
|
|
60
|
+
$,
|
|
61
|
+
url,
|
|
62
|
+
asBot,
|
|
63
|
+
filepath: downloadedFilepath,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
$.export("$summary", `Downloaded ${metadata.name} (${bytesWritten} bytes)`);
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
filedata: [
|
|
70
|
+
savedFilename,
|
|
71
|
+
downloadedFilepath,
|
|
72
|
+
],
|
|
73
|
+
file: {
|
|
74
|
+
id: metadata.id,
|
|
75
|
+
name: metadata.name,
|
|
76
|
+
title: metadata.title,
|
|
77
|
+
mimetype: metadata.mimetype,
|
|
78
|
+
filetype: metadata.filetype,
|
|
79
|
+
size: bytesWritten,
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
};
|
|
@@ -11,7 +11,7 @@ export default {
|
|
|
11
11
|
+ " Requires the message timestamp (`ts`) from **Get Channel History** or **Post Message**."
|
|
12
12
|
+ " You can only edit messages posted by the same token/user."
|
|
13
13
|
+ " [See the documentation](https://api.slack.com/methods/chat.update)",
|
|
14
|
-
version: "0.0.
|
|
14
|
+
version: "0.0.12",
|
|
15
15
|
type: "action",
|
|
16
16
|
ai: "optimized",
|
|
17
17
|
annotations: {
|
|
@@ -15,7 +15,7 @@ export default {
|
|
|
15
15
|
+ " omitted when no mention carried a name."
|
|
16
16
|
+ " Do NOT splice a name back inline: Slack renders `<@U123|Name>` as literal text, not a mention."
|
|
17
17
|
+ " [See the documentation](https://api.slack.com/methods/assistant.search.context)",
|
|
18
|
-
version: "0.2.
|
|
18
|
+
version: "0.2.6",
|
|
19
19
|
annotations: {
|
|
20
20
|
destructiveHint: false,
|
|
21
21
|
openWorldHint: true,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-find-user-by-email",
|
|
5
5
|
name: "Find User by Email",
|
|
6
6
|
description: "Find a user by matching against their email. [See the documentation](https://api.slack.com/methods/users.lookupByEmail)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.38",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: false,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-find-user-by-id",
|
|
5
5
|
name: "Find User by ID",
|
|
6
6
|
description: "Find a user by their ID — including a specific user you already have the Slack ID for, whether or not it's your own. Returns user profile information including name, email (requires `users:read.email` scope), timezone, and status. If you only have an email address, use **Find User by Email** instead. [See the documentation](https://api.slack.com/methods/users.info)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.15",
|
|
8
8
|
type: "action",
|
|
9
9
|
ai: "optimized",
|
|
10
10
|
annotations: {
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-get-channel-details",
|
|
5
5
|
name: "Get Channel Details",
|
|
6
6
|
description: "Retrieve details for a Slack channel, specified by ID (preferred — resolves instantly) or by name (resolved by scanning the workspace's channel list, which can be slow). [See the documentation](https://api.slack.com/methods/conversations.info)",
|
|
7
|
-
version: "0.1.
|
|
7
|
+
version: "0.1.9",
|
|
8
8
|
type: "action",
|
|
9
9
|
ai: "optimized",
|
|
10
10
|
annotations: {
|
|
@@ -17,7 +17,7 @@ export default {
|
|
|
17
17
|
+ " messages carry blocks, attachments and edit metadata, so a busy channel can run to tens"
|
|
18
18
|
+ " of thousands of characters and be truncated before you see any of it."
|
|
19
19
|
+ " [See the documentation](https://api.slack.com/methods/conversations.history)",
|
|
20
|
-
version: "0.2.
|
|
20
|
+
version: "0.2.8",
|
|
21
21
|
type: "action",
|
|
22
22
|
ai: "optimized",
|
|
23
23
|
annotations: {
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-get-current-user",
|
|
5
5
|
name: "Get Current User",
|
|
6
6
|
description: "Do NOT use for a plain \"who am I\" / \"what's my user ID\" question — call **Get User Details** for that; it answers the same question with a far smaller payload. Do NOT use to look up a DIFFERENT, specifically-identified user (by ID or email) — this only ever describes the authenticated caller; use **Find User by ID** / **Find User by Email** for someone else. Do NOT use to enumerate multiple teams/workspaces (e.g. Enterprise Grid) — use **List Teams** for that; this returns only the caller's own current team. Use this ONLY when you specifically need the full member profile: locale, timezone, presence/status, admin and owner flags, name variants, or workspace domain and enterprise metadata. Combines `auth.test`, `users.info`, `users.profile.get` and `team.info`. [See Slack API docs](https://api.slack.com/methods/auth.test).",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.14",
|
|
8
8
|
type: "action",
|
|
9
9
|
ai: "optimized",
|
|
10
10
|
annotations: {
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-get-file",
|
|
5
5
|
name: "Get File",
|
|
6
6
|
description: "Return information about a file. [See the documentation](https://api.slack.com/methods/files.info)",
|
|
7
|
-
version: "0.1.
|
|
7
|
+
version: "0.1.14",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: false,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -17,7 +17,7 @@ export default {
|
|
|
17
17
|
+ " Slack messages carry blocks, attachments and edit metadata, so a long thread can run"
|
|
18
18
|
+ " to tens of thousands of characters and be truncated before you see any of it."
|
|
19
19
|
+ " [See the documentation](https://api.slack.com/methods/conversations.replies)",
|
|
20
|
-
version: "0.1.
|
|
20
|
+
version: "0.1.9",
|
|
21
21
|
type: "action",
|
|
22
22
|
ai: "optimized",
|
|
23
23
|
annotations: {
|
|
@@ -13,7 +13,7 @@ export default {
|
|
|
13
13
|
+ " Prefer this over **Get Current User**, which returns a much larger payload and is only"
|
|
14
14
|
+ " needed for full profile detail (locale, status, admin flags)."
|
|
15
15
|
+ " [See the documentation](https://api.slack.com/methods/auth.test)",
|
|
16
|
-
version: "0.0.
|
|
16
|
+
version: "0.0.11",
|
|
17
17
|
type: "action",
|
|
18
18
|
ai: "optimized",
|
|
19
19
|
annotations: {
|
|
@@ -5,7 +5,7 @@ export default {
|
|
|
5
5
|
key: "slack_v2-invite-user-to-channel",
|
|
6
6
|
name: "Invite User to Channel",
|
|
7
7
|
description: "Invite one or more users to an existing channel. Accepts a channel ID (preferred — resolves instantly) or NAME (resolved by scanning up to 5 pages, ~5,000 channels, of the workspace's channel list — a name beyond that bound will not be found), and a user ID, EMAIL address or display name — all resolved automatically. Pass several users as a comma-separated list. [See the documentation](https://api.slack.com/methods/conversations.invite)",
|
|
8
|
-
version: "0.1.
|
|
8
|
+
version: "0.1.9",
|
|
9
9
|
annotations: {
|
|
10
10
|
destructiveHint: false,
|
|
11
11
|
openWorldHint: true,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-kick-user",
|
|
5
5
|
name: "Kick User",
|
|
6
6
|
description: "Remove a user from a conversation. [See the documentation](https://api.slack.com/methods/conversations.kick)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.39",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: true,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-leave-channel",
|
|
5
5
|
name: "Leave Channel",
|
|
6
6
|
description: "Remove the authenticated user from a public or private channel. Leaving a channel the user is not a member of is a no-op, reported as `not_in_channel: true`. To leave several channels (e.g. every channel matching a pattern), use **List Channels** with `memberOnly: true` to find them, then call this action once per channel ID. [See the documentation](https://docs.slack.dev/reference/methods/conversations.leave/)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.3",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: false,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -18,7 +18,7 @@ export default {
|
|
|
18
18
|
+ " fetched — when you see that, raise `numPages` (or pass `cursor`) before answering"
|
|
19
19
|
+ " any 'how many' or 'list every' question, otherwise your answer is silently incomplete."
|
|
20
20
|
+ " [See the documentation](https://api.slack.com/methods/conversations.list)",
|
|
21
|
-
version: "0.4.
|
|
21
|
+
version: "0.4.3",
|
|
22
22
|
annotations: {
|
|
23
23
|
destructiveHint: false,
|
|
24
24
|
openWorldHint: true,
|
|
@@ -5,7 +5,7 @@ export default {
|
|
|
5
5
|
name: "List Emojis",
|
|
6
6
|
description:
|
|
7
7
|
"List all available emojis in the Slack workspace. Optionally include emoji image URLs. [See the documentation](https://api.slack.com/methods/emoji.list)",
|
|
8
|
-
version: "0.0.
|
|
8
|
+
version: "0.0.13",
|
|
9
9
|
annotations: {
|
|
10
10
|
destructiveHint: false,
|
|
11
11
|
openWorldHint: true,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-list-files",
|
|
5
5
|
name: "List Files",
|
|
6
6
|
description: "Return a list of files within a team. [See the documentation](https://api.slack.com/methods/files.list)",
|
|
7
|
-
version: "0.1.
|
|
7
|
+
version: "0.1.14",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: false,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -10,7 +10,7 @@ export default {
|
|
|
10
10
|
+ " Returns `has_more: true` and `next_cursor` when more conversations exist than were"
|
|
11
11
|
+ " fetched — raise `numPages` (or pass `cursor`) to see the rest."
|
|
12
12
|
+ " [See the documentation](https://api.slack.com/methods/conversations.list)",
|
|
13
|
-
version: "0.0.
|
|
13
|
+
version: "0.0.8",
|
|
14
14
|
annotations: {
|
|
15
15
|
destructiveHint: false,
|
|
16
16
|
openWorldHint: true,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-list-group-members",
|
|
5
5
|
name: "List Group Members",
|
|
6
6
|
description: "List all users in a User Group. [See the documentation](https://api.slack.com/methods/usergroups.users.list)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.23",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: false,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-list-icon-emoji-options",
|
|
5
5
|
name: "List Icon (emoji) Options",
|
|
6
6
|
description: "Retrieves available options for the Icon (emoji) field. [See the documentation](https://api.slack.com/methods/emoji.list)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.11",
|
|
8
8
|
type: "action",
|
|
9
9
|
ai: "optimized",
|
|
10
10
|
annotations: {
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-list-members-in-channel",
|
|
5
5
|
name: "List Members in Channel",
|
|
6
6
|
description: "Retrieve members of a channel. Accepts a channel ID (preferred — resolves instantly) or NAME (e.g. general or #general), resolved by scanning up to 5 pages (~5,000 channels) of the workspace's channel list — a name beyond that bound will not be found. [See the documentation](https://api.slack.com/methods/conversations.members)",
|
|
7
|
-
version: "0.1.
|
|
7
|
+
version: "0.1.9",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: false,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -9,7 +9,7 @@ export default {
|
|
|
9
9
|
+ " selection to keep responses small, and returns the same message data."
|
|
10
10
|
+ " This legacy tool remains only for existing workflows: it accepts a raw conversation ID and"
|
|
11
11
|
+ " returns full, untrimmed message objects. [See the documentation](https://api.slack.com/methods/conversations.history)",
|
|
12
|
-
version: "0.0.
|
|
12
|
+
version: "0.0.14",
|
|
13
13
|
annotations: {
|
|
14
14
|
destructiveHint: false,
|
|
15
15
|
openWorldHint: true,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-list-reminder-options",
|
|
5
5
|
name: "List Reminder Options",
|
|
6
6
|
description: "Retrieves available options for the Reminder field. [See the documentation](https://docs.slack.dev/reference/methods/reminders.list)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.11",
|
|
8
8
|
type: "action",
|
|
9
9
|
ai: "optimized",
|
|
10
10
|
annotations: {
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-list-replies",
|
|
5
5
|
name: "List Replies",
|
|
6
6
|
description: "Retrieve a thread of messages posted to a conversation. [See the documentation](https://api.slack.com/methods/conversations.replies)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.39",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: false,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -14,7 +14,7 @@ export default {
|
|
|
14
14
|
+ " Returns `has_more: true` and `next_cursor` when more teams exist than were"
|
|
15
15
|
+ " fetched — raise `numPages` (or pass `cursor`) to see the rest."
|
|
16
16
|
+ " [See the documentation](https://api.slack.com/methods/auth.teams.list)",
|
|
17
|
-
version: "0.0.
|
|
17
|
+
version: "0.0.8",
|
|
18
18
|
annotations: {
|
|
19
19
|
destructiveHint: false,
|
|
20
20
|
openWorldHint: true,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-list-user-group-options",
|
|
5
5
|
name: "List User Group Options",
|
|
6
6
|
description: "Retrieves available options for the User Group field. [See the documentation](https://docs.slack.dev/reference/methods/usergroups.list)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.11",
|
|
8
8
|
type: "action",
|
|
9
9
|
ai: "optimized",
|
|
10
10
|
annotations: {
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-list-users",
|
|
5
5
|
name: "List Users",
|
|
6
6
|
description: "Return a list of all users in a workspace. [See the documentation](https://api.slack.com/methods/users.list)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.38",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: false,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -12,7 +12,7 @@ export default {
|
|
|
12
12
|
+ " Supports plain text with Slack mrkdwn formatting and Block Kit blocks."
|
|
13
13
|
+ " Posts as the authenticated user by default; set `sendAsBot` to `true` to post as the Slack app's bot user instead."
|
|
14
14
|
+ " [See the documentation](https://api.slack.com/methods/chat.postMessage)",
|
|
15
|
-
version: "0.1.
|
|
15
|
+
version: "0.1.3",
|
|
16
16
|
type: "action",
|
|
17
17
|
ai: "optimized",
|
|
18
18
|
annotations: {
|
|
@@ -13,7 +13,7 @@ export default {
|
|
|
13
13
|
+ " (e.g. `1403051575.000407`); get it from **Get Channel History** or an incoming event's"
|
|
14
14
|
+ " `ts` field. For a plain, non-threaded message use **Post Message** instead."
|
|
15
15
|
+ " [See the documentation](https://api.slack.com/methods/chat.postMessage)",
|
|
16
|
-
version: "0.2.
|
|
16
|
+
version: "0.2.14",
|
|
17
17
|
annotations: {
|
|
18
18
|
destructiveHint: false,
|
|
19
19
|
openWorldHint: true,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ConfigurationError } from "@pipedream/platform";
|
|
2
|
+
import constants from "../../common/constants.mjs";
|
|
1
3
|
import utils from "../../common/utils.mjs";
|
|
2
4
|
import slack from "../../slack_v2.app.mjs";
|
|
3
5
|
|
|
@@ -5,16 +7,25 @@ export default {
|
|
|
5
7
|
key: "slack_v2-search",
|
|
6
8
|
name: "Search",
|
|
7
9
|
description:
|
|
8
|
-
"Search Slack messages and
|
|
10
|
+
"Search Slack messages, files, channels, and users using the Real-Time Search API."
|
|
9
11
|
+ " Supports keyword and semantic search across public and private channels."
|
|
10
12
|
+ " Use **Get User Details** first to find your user ID for filtering by 'my' messages."
|
|
11
|
-
+ "
|
|
13
|
+
+ " Set `contentTypes` to choose what to search: any combination of `messages` (default), `files`, `channels`, `users`."
|
|
14
|
+
+ " Returns a single array; each item has a `content_type` of `message`, `file`, `channel`, or `user`."
|
|
15
|
+
+ " Messages include channel context, timestamps, and permalinks;"
|
|
16
|
+
+ " files, channels, and users are returned as Slack sends them"
|
|
17
|
+
+ " (files include `file_id`, `title`, `file_type`, `author_name`, `date_created`, `permalink`, and extracted `content`;"
|
|
18
|
+
+ " channels additionally include `channel_id`, extracted from `permalink` for use with other channel actions)."
|
|
19
|
+
+ " `Max Results` applies per content type, so selecting more types can return proportionally more items."
|
|
20
|
+
+ ` \`Max Results\` is capped at ${constants.MAX_SEARCH_RESULTS}.`
|
|
21
|
+
+ " Paging for a content type stops as soon as a page returns fewer than a full page of it,"
|
|
22
|
+
+ " and paging overall stops after a fixed page budget, so a sparse type can come back with fewer than `Max Results`."
|
|
12
23
|
+ " User mentions come back in the canonical `<@U123>` form; echo it verbatim to post a real mention."
|
|
13
24
|
+ " Display names are returned separately as `mentions`, an array of `{ id, name }` objects,"
|
|
14
25
|
+ " omitted when no mention carried a name."
|
|
15
26
|
+ " Do NOT splice a name back inline: Slack renders `<@U123|Name>` as literal text, not a mention."
|
|
16
27
|
+ " [See the documentation](https://api.slack.com/methods/assistant.search.context)",
|
|
17
|
-
version: "0.
|
|
28
|
+
version: "0.2.0",
|
|
18
29
|
type: "action",
|
|
19
30
|
ai: "optimized",
|
|
20
31
|
annotations: {
|
|
@@ -36,30 +47,121 @@ export default {
|
|
|
36
47
|
default: "public_channel,private_channel",
|
|
37
48
|
optional: true,
|
|
38
49
|
},
|
|
50
|
+
contentTypes: {
|
|
51
|
+
type: "string[]",
|
|
52
|
+
label: "Content Types",
|
|
53
|
+
description: "Which kinds of results to return. Select any combination of `messages`, `files`, `channels`, `users`, e.g. `[\"messages\", \"files\"]`. Default: `messages`.",
|
|
54
|
+
options: [
|
|
55
|
+
"messages",
|
|
56
|
+
"files",
|
|
57
|
+
"channels",
|
|
58
|
+
"users",
|
|
59
|
+
],
|
|
60
|
+
default: [
|
|
61
|
+
"messages",
|
|
62
|
+
],
|
|
63
|
+
optional: true,
|
|
64
|
+
},
|
|
39
65
|
limit: {
|
|
40
66
|
type: "integer",
|
|
41
67
|
label: "Max Results",
|
|
42
|
-
description:
|
|
68
|
+
description: `Maximum number of results to return per content type, up to ${constants.MAX_SEARCH_RESULTS}, e.g. \`20\`.`,
|
|
43
69
|
default: 20,
|
|
70
|
+
min: 1,
|
|
71
|
+
max: constants.MAX_SEARCH_RESULTS,
|
|
44
72
|
optional: true,
|
|
45
73
|
},
|
|
46
74
|
},
|
|
47
75
|
async run({ $ }) {
|
|
48
76
|
const maxResults = Math.max(this.limit ?? 20, 1);
|
|
49
|
-
|
|
77
|
+
if (maxResults > constants.MAX_SEARCH_RESULTS) {
|
|
78
|
+
throw new ConfigurationError(`\`Max Results\` must be ${constants.MAX_SEARCH_RESULTS} or less.`);
|
|
79
|
+
}
|
|
80
|
+
const contentTypes = this.contentTypes?.length
|
|
81
|
+
? this.contentTypes
|
|
82
|
+
: [
|
|
83
|
+
"messages",
|
|
84
|
+
];
|
|
85
|
+
const wantMessages = contentTypes.includes("messages");
|
|
86
|
+
const wantFiles = contentTypes.includes("files");
|
|
87
|
+
const wantChannels = contentTypes.includes("channels");
|
|
88
|
+
const wantUsers = contentTypes.includes("users");
|
|
89
|
+
const messages = [];
|
|
90
|
+
const files = [];
|
|
91
|
+
const channels = [];
|
|
92
|
+
const users = [];
|
|
93
|
+
// Marks a content type done once a page returns less than a full page of
|
|
94
|
+
// it, since that means Slack has no more results of that type — without
|
|
95
|
+
// this, a sparse type (e.g. files) below `Max Results` would keep the
|
|
96
|
+
// whole loop paging through an already-exhausted type until the page
|
|
97
|
+
// budget ran out.
|
|
98
|
+
const exhausted = {};
|
|
99
|
+
let pages = 0;
|
|
50
100
|
let cursor;
|
|
51
101
|
|
|
102
|
+
const needsMore = (want, list, type) => want && !exhausted[type] && list.length < maxResults;
|
|
103
|
+
|
|
52
104
|
do {
|
|
53
105
|
const response = await this.slack.assistantSearch({
|
|
54
106
|
query: this.query,
|
|
55
107
|
channel_types: this.channelTypes,
|
|
108
|
+
content_types: contentTypes.join(","),
|
|
56
109
|
cursor,
|
|
57
110
|
});
|
|
58
|
-
|
|
111
|
+
|
|
112
|
+
const newMessages = response.results?.messages || [];
|
|
113
|
+
const newFiles = response.results?.files || [];
|
|
114
|
+
const newChannels = response.results?.channels || [];
|
|
115
|
+
const newUsers = response.results?.users || [];
|
|
116
|
+
|
|
117
|
+
if (wantMessages) {
|
|
118
|
+
messages.push(...newMessages);
|
|
119
|
+
exhausted.messages ||= newMessages.length < constants.SEARCH_PAGE_SIZE;
|
|
120
|
+
}
|
|
121
|
+
if (wantFiles) {
|
|
122
|
+
files.push(...newFiles);
|
|
123
|
+
exhausted.files ||= newFiles.length < constants.SEARCH_PAGE_SIZE;
|
|
124
|
+
}
|
|
125
|
+
if (wantChannels) {
|
|
126
|
+
channels.push(...newChannels);
|
|
127
|
+
exhausted.channels ||= newChannels.length < constants.SEARCH_PAGE_SIZE;
|
|
128
|
+
}
|
|
129
|
+
if (wantUsers) {
|
|
130
|
+
users.push(...newUsers);
|
|
131
|
+
exhausted.users ||= newUsers.length < constants.SEARCH_PAGE_SIZE;
|
|
132
|
+
}
|
|
133
|
+
|
|
59
134
|
cursor = response.response_metadata?.next_cursor;
|
|
60
|
-
|
|
135
|
+
pages++;
|
|
136
|
+
} while (
|
|
137
|
+
cursor
|
|
138
|
+
&& pages < constants.MAX_SEARCH_PAGES
|
|
139
|
+
&& (needsMore(wantMessages, messages, "messages")
|
|
140
|
+
|| needsMore(wantFiles, files, "files")
|
|
141
|
+
|| needsMore(wantChannels, channels, "channels")
|
|
142
|
+
|| needsMore(wantUsers, users, "users"))
|
|
143
|
+
);
|
|
61
144
|
|
|
62
|
-
const results =
|
|
145
|
+
const results = [
|
|
146
|
+
...utils.normalizeSearchMessages(messages.slice(0, maxResults))
|
|
147
|
+
.map((message) => ({
|
|
148
|
+
...message,
|
|
149
|
+
content_type: "message",
|
|
150
|
+
})),
|
|
151
|
+
...files.slice(0, maxResults).map((file) => ({
|
|
152
|
+
...file,
|
|
153
|
+
content_type: "file",
|
|
154
|
+
})),
|
|
155
|
+
...channels.slice(0, maxResults).map((channel) => ({
|
|
156
|
+
...channel,
|
|
157
|
+
channel_id: utils.channelIdFromPermalink(channel.permalink),
|
|
158
|
+
content_type: "channel",
|
|
159
|
+
})),
|
|
160
|
+
...users.slice(0, maxResults).map((user) => ({
|
|
161
|
+
...user,
|
|
162
|
+
content_type: "user",
|
|
163
|
+
})),
|
|
164
|
+
];
|
|
63
165
|
|
|
64
166
|
$.export("$summary", `Found ${results.length} result${results.length === 1
|
|
65
167
|
? ""
|
|
@@ -7,7 +7,7 @@ export default {
|
|
|
7
7
|
key: "slack_v2-send-block-kit-message",
|
|
8
8
|
name: "Build and Send a Block Kit Message",
|
|
9
9
|
description: "Configure custom blocks and send to a channel, group, or user. [See the documentation](https://api.slack.com/tools/block-kit-builder).",
|
|
10
|
-
version: "0.5.
|
|
10
|
+
version: "0.5.14",
|
|
11
11
|
annotations: {
|
|
12
12
|
destructiveHint: false,
|
|
13
13
|
openWorldHint: true,
|
|
@@ -5,7 +5,7 @@ export default {
|
|
|
5
5
|
key: "slack_v2-send-large-message",
|
|
6
6
|
name: "Send a Large Message (3000+ characters)",
|
|
7
7
|
description: "Send a large message (more than 3000 characters) to a channel, group or user. See [postMessage](https://api.slack.com/methods/chat.postMessage) or [scheduleMessage](https://api.slack.com/methods/chat.scheduleMessage) docs here",
|
|
8
|
-
version: "0.1.
|
|
8
|
+
version: "0.1.14",
|
|
9
9
|
annotations: {
|
|
10
10
|
destructiveHint: false,
|
|
11
11
|
openWorldHint: true,
|
|
@@ -6,7 +6,7 @@ export default {
|
|
|
6
6
|
key: "slack_v2-send-message",
|
|
7
7
|
name: "Send Message",
|
|
8
8
|
description: "Send a message to a user, group, private channel or public channel. [See the documentation](https://api.slack.com/methods/chat.postMessage)",
|
|
9
|
-
version: "0.2.
|
|
9
|
+
version: "0.2.7",
|
|
10
10
|
annotations: {
|
|
11
11
|
destructiveHint: false,
|
|
12
12
|
openWorldHint: true,
|
|
@@ -8,7 +8,7 @@ export default {
|
|
|
8
8
|
key: "slack_v2-send-message-advanced",
|
|
9
9
|
name: "Send Message (Advanced)",
|
|
10
10
|
description: "Customize advanced settings and send a message to a channel, group or user. See [postMessage](https://api.slack.com/methods/chat.postMessage) or [scheduleMessage](https://api.slack.com/methods/chat.scheduleMessage) docs here",
|
|
11
|
-
version: "0.1.
|
|
11
|
+
version: "0.1.14",
|
|
12
12
|
annotations: {
|
|
13
13
|
destructiveHint: false,
|
|
14
14
|
openWorldHint: true,
|
|
@@ -11,7 +11,7 @@ export default {
|
|
|
11
11
|
+ " replies and unfurl settings. Use this tool only if a workflow specifically needs to"
|
|
12
12
|
+ " target a channel exclusively, without the user/group support **Post Message** offers."
|
|
13
13
|
+ " [See the documentation](https://api.slack.com/methods/chat.postMessage)",
|
|
14
|
-
version: "0.2.
|
|
14
|
+
version: "0.2.7",
|
|
15
15
|
annotations: {
|
|
16
16
|
destructiveHint: false,
|
|
17
17
|
openWorldHint: true,
|
|
@@ -6,7 +6,7 @@ export default {
|
|
|
6
6
|
key: "slack_v2-send-message-to-user-or-group",
|
|
7
7
|
name: "Send Message to User or Group",
|
|
8
8
|
description: "Send a message to a user or group. [See the documentation](https://api.slack.com/methods/chat.postMessage)",
|
|
9
|
-
version: "0.2.
|
|
9
|
+
version: "0.2.7",
|
|
10
10
|
annotations: {
|
|
11
11
|
destructiveHint: false,
|
|
12
12
|
openWorldHint: true,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-set-channel-description",
|
|
5
5
|
name: "Set Channel Description",
|
|
6
6
|
description: "Change the description or purpose of a channel. [See the documentation](https://api.slack.com/methods/conversations.setPurpose)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.24",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: false,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-set-channel-topic",
|
|
5
5
|
name: "Set Channel Topic",
|
|
6
6
|
description: "Set the topic on a channel, specified by ID (preferred — resolves instantly) or by name (resolved by scanning up to 5 pages, ~5,000 channels, of the workspace's channel list — a name beyond that bound will not be found). [See the documentation](https://api.slack.com/methods/conversations.setTopic)",
|
|
7
|
-
version: "0.1.
|
|
7
|
+
version: "0.1.9",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: true,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-set-status",
|
|
5
5
|
name: "Set Status",
|
|
6
6
|
description: "Set the current status for a user. [See the documentation](https://api.slack.com/methods/users.profile.set)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.23",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: true,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-update-group-members",
|
|
5
5
|
name: "Update Group Members",
|
|
6
6
|
description: "Update the list of users for a User Group. [See the documentation](https://api.slack.com/methods/usergroups.users.update)",
|
|
7
|
-
version: "0.0.
|
|
7
|
+
version: "0.0.24",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: true,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
key: "slack_v2-update-message",
|
|
5
5
|
name: "Update Message",
|
|
6
6
|
description: "Update a message. [See the documentation](https://api.slack.com/methods/chat.update)",
|
|
7
|
-
version: "0.2.
|
|
7
|
+
version: "0.2.14",
|
|
8
8
|
annotations: {
|
|
9
9
|
destructiveHint: true,
|
|
10
10
|
openWorldHint: true,
|
|
@@ -5,7 +5,7 @@ export default {
|
|
|
5
5
|
key: "slack_v2-update-profile",
|
|
6
6
|
name: "Update Profile",
|
|
7
7
|
description: "Update basic profile field such as name or title. [See the documentation](https://api.slack.com/methods/users.profile.set)",
|
|
8
|
-
version: "0.0.
|
|
8
|
+
version: "0.0.39",
|
|
9
9
|
annotations: {
|
|
10
10
|
destructiveHint: true,
|
|
11
11
|
openWorldHint: true,
|
|
@@ -8,7 +8,7 @@ export default {
|
|
|
8
8
|
key: "slack_v2-upload-file",
|
|
9
9
|
name: "Upload File",
|
|
10
10
|
description: "Upload a file. [See the documentation](https://api.slack.com/messaging/files#uploading_files)",
|
|
11
|
-
version: "0.1.
|
|
11
|
+
version: "0.1.18",
|
|
12
12
|
annotations: {
|
|
13
13
|
destructiveHint: false,
|
|
14
14
|
openWorldHint: true,
|
|
@@ -5,7 +5,7 @@ export default {
|
|
|
5
5
|
key: "slack_v2-verify-slack-signature",
|
|
6
6
|
name: "Verify Slack Signature",
|
|
7
7
|
description: "Verifying requests from Slack, slack signs its requests using a secret that's unique to your app. `Request Body` must be the raw request body as a string (not a parsed object) — Slack computes its signature over the exact raw bytes it sent, so re-serializing a parsed object will not match. [See the documentation](https://api.slack.com/authentication/verifying-requests-from-slack)",
|
|
8
|
-
version: "1.0.
|
|
8
|
+
version: "1.0.7",
|
|
9
9
|
annotations: {
|
|
10
10
|
destructiveHint: false,
|
|
11
11
|
openWorldHint: true,
|
package/common/constants.mjs
CHANGED
|
@@ -9,6 +9,25 @@ const MAX_NAME_LOOKUP_PAGES = 5;
|
|
|
9
9
|
// that doesn't exist (typo, wrong workspace) forces a full workspace scan —
|
|
10
10
|
// on a large workspace that alone can exhaust conversations.list's rate limit.
|
|
11
11
|
const MAX_CHANNEL_RESOLVE_PAGES = 5;
|
|
12
|
+
// Page budget for `assistant.search.context` in the Search action. When several
|
|
13
|
+
// content types are selected, one sparse type (e.g. files) would otherwise keep
|
|
14
|
+
// the loop paging through the other type until the cursor runs out, and this
|
|
15
|
+
// method rate-limits readily. Slack returns at most SEARCH_PAGE_SIZE items per
|
|
16
|
+
// page, so Max Results is capped at what the budget can fill for one type.
|
|
17
|
+
const MAX_SEARCH_PAGES = 5;
|
|
18
|
+
const SEARCH_PAGE_SIZE = 20;
|
|
19
|
+
const MAX_SEARCH_RESULTS = MAX_SEARCH_PAGES * SEARCH_PAGE_SIZE;
|
|
20
|
+
// User-token errors on which file reads retry with the bot token.
|
|
21
|
+
const FILES_READ_BOT_FALLBACK_ERRORS = [
|
|
22
|
+
"missing_scope",
|
|
23
|
+
"file_not_found",
|
|
24
|
+
"channel_not_found",
|
|
25
|
+
"not_in_channel",
|
|
26
|
+
];
|
|
27
|
+
// Pipedream's /tmp limit: https://pipedream.com/docs/workflows/limits#disk
|
|
28
|
+
const MAX_DOWNLOAD_SIZE_BYTES = 2 * 1024 * 1024 * 1024;
|
|
29
|
+
const STREAM_RESPONSE_TYPE = "stream";
|
|
30
|
+
const CANVAS_FILETYPE = "quip";
|
|
12
31
|
|
|
13
32
|
const CHANNEL_TYPE = {
|
|
14
33
|
PUBLIC: "public_channel",
|
|
@@ -51,6 +70,13 @@ export default {
|
|
|
51
70
|
LIMIT,
|
|
52
71
|
MAX_NAME_LOOKUP_PAGES,
|
|
53
72
|
MAX_CHANNEL_RESOLVE_PAGES,
|
|
73
|
+
MAX_SEARCH_PAGES,
|
|
74
|
+
SEARCH_PAGE_SIZE,
|
|
75
|
+
MAX_SEARCH_RESULTS,
|
|
76
|
+
FILES_READ_BOT_FALLBACK_ERRORS,
|
|
77
|
+
MAX_DOWNLOAD_SIZE_BYTES,
|
|
78
|
+
STREAM_RESPONSE_TYPE,
|
|
79
|
+
CANVAS_FILETYPE,
|
|
54
80
|
CHANNEL_TYPE,
|
|
55
81
|
CHANNEL_TYPE_OPTIONS,
|
|
56
82
|
BLOCK_TYPES,
|
package/common/utils.mjs
CHANGED
|
@@ -140,10 +140,26 @@ export function normalizeSearchMessages(messages) {
|
|
|
140
140
|
});
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Channel search results carry no `id` field, only a `permalink` like
|
|
145
|
+
* `https://workspace.slack.com/archives/C0123456789`. Extracting it here lets
|
|
146
|
+
* callers pass the result straight into other channel actions the same way
|
|
147
|
+
* file/user results already do with `file_id`/`user_id`.
|
|
148
|
+
*
|
|
149
|
+
* @param {string} permalink - the channel's permalink
|
|
150
|
+
* @returns {string|undefined} the channel ID, or undefined if it can't be parsed
|
|
151
|
+
*/
|
|
152
|
+
export function channelIdFromPermalink(permalink) {
|
|
153
|
+
return typeof permalink === "string"
|
|
154
|
+
? permalink.split("/archives/")[1]?.split("/")[0]
|
|
155
|
+
: undefined;
|
|
156
|
+
}
|
|
157
|
+
|
|
143
158
|
export default {
|
|
144
159
|
parseFields,
|
|
145
160
|
pickFields,
|
|
146
161
|
projectFields,
|
|
147
162
|
normalizeUserMentions,
|
|
148
163
|
normalizeSearchMessages,
|
|
164
|
+
channelIdFromPermalink,
|
|
149
165
|
};
|
package/package.json
CHANGED
package/slack_v2.app.mjs
CHANGED
|
@@ -3,7 +3,12 @@ import { WebClient } from "@slack/web-api";
|
|
|
3
3
|
import constants from "./common/constants.mjs";
|
|
4
4
|
import get from "lodash/get.js";
|
|
5
5
|
import retry from "async-retry";
|
|
6
|
-
import
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import { Transform } from "stream";
|
|
8
|
+
import { pipeline } from "stream/promises";
|
|
9
|
+
import {
|
|
10
|
+
ConfigurationError, axios,
|
|
11
|
+
} from "@pipedream/platform";
|
|
7
12
|
|
|
8
13
|
export default {
|
|
9
14
|
type: "app",
|
|
@@ -682,16 +687,50 @@ export default {
|
|
|
682
687
|
...args,
|
|
683
688
|
});
|
|
684
689
|
},
|
|
685
|
-
listFiles(args = {}) {
|
|
690
|
+
async listFiles(args = {}) {
|
|
686
691
|
args.count ||= constants.LIMIT;
|
|
692
|
+
const {
|
|
693
|
+
response, asBot,
|
|
694
|
+
} = await this.makeFilesReadRequest({
|
|
695
|
+
method: "files.list",
|
|
696
|
+
...args,
|
|
697
|
+
});
|
|
698
|
+
// files.list returns no files, not an error, for channels the user can't see
|
|
699
|
+
if (asBot
|
|
700
|
+
|| !args.channel
|
|
701
|
+
|| args.page > 1
|
|
702
|
+
|| response.files?.length
|
|
703
|
+
|| await this._userCanSeeChannel(args.channel)) {
|
|
704
|
+
return response;
|
|
705
|
+
}
|
|
706
|
+
const notVisibleError = new ConfigurationError(`Channel "${args.channel}" was not found, or neither the connected user nor the bot is a member of it.`);
|
|
707
|
+
if (!this.getBotToken()) {
|
|
708
|
+
throw notVisibleError;
|
|
709
|
+
}
|
|
687
710
|
return this.makeRequest({
|
|
688
711
|
method: "files.list",
|
|
689
|
-
// Use bot token, if available, since the required `files:read` scope
|
|
690
|
-
// is only requested for bot tokens in the Pipedream app.
|
|
691
|
-
asBot: true,
|
|
692
712
|
...args,
|
|
713
|
+
asBot: true,
|
|
714
|
+
}).catch((error) => {
|
|
715
|
+
if (constants.FILES_READ_BOT_FALLBACK_ERRORS.some((code) => `${error}`.includes(code))) {
|
|
716
|
+
throw notVisibleError;
|
|
717
|
+
}
|
|
718
|
+
throw error;
|
|
693
719
|
});
|
|
694
720
|
},
|
|
721
|
+
async _userCanSeeChannel(channel) {
|
|
722
|
+
try {
|
|
723
|
+
await this.conversationsInfo({
|
|
724
|
+
channel,
|
|
725
|
+
});
|
|
726
|
+
return true;
|
|
727
|
+
} catch (error) {
|
|
728
|
+
if (error?.data?.error === "channel_not_found") {
|
|
729
|
+
return false;
|
|
730
|
+
}
|
|
731
|
+
throw error;
|
|
732
|
+
}
|
|
733
|
+
},
|
|
695
734
|
listGroupMembers(args = {}) {
|
|
696
735
|
args.limit ||= constants.LIMIT;
|
|
697
736
|
return this.makeRequest({
|
|
@@ -699,14 +738,98 @@ export default {
|
|
|
699
738
|
...args,
|
|
700
739
|
});
|
|
701
740
|
},
|
|
702
|
-
getFileInfo(args = {}) {
|
|
703
|
-
|
|
741
|
+
async getFileInfo(args = {}) {
|
|
742
|
+
const { response } = await this.makeFilesReadRequest({
|
|
704
743
|
method: "files.info",
|
|
705
|
-
// Use bot token, if available, since the required `files:read` scope
|
|
706
|
-
// is only requested for bot tokens in the Pipedream app.
|
|
707
|
-
asBot: true,
|
|
708
744
|
...args,
|
|
709
745
|
});
|
|
746
|
+
return response;
|
|
747
|
+
},
|
|
748
|
+
// User token first, so files in private channels the bot hasn't joined resolve
|
|
749
|
+
async makeFilesReadRequest(args = {}) {
|
|
750
|
+
let userError;
|
|
751
|
+
try {
|
|
752
|
+
const response = await this.makeRequest({
|
|
753
|
+
...args,
|
|
754
|
+
asBot: false,
|
|
755
|
+
});
|
|
756
|
+
return {
|
|
757
|
+
response,
|
|
758
|
+
asBot: false,
|
|
759
|
+
};
|
|
760
|
+
} catch (error) {
|
|
761
|
+
if (!this.getBotToken()
|
|
762
|
+
|| !constants.FILES_READ_BOT_FALLBACK_ERRORS.includes(error?.data?.error)) {
|
|
763
|
+
throw error;
|
|
764
|
+
}
|
|
765
|
+
userError = error;
|
|
766
|
+
}
|
|
767
|
+
try {
|
|
768
|
+
const response = await this.makeRequest({
|
|
769
|
+
...args,
|
|
770
|
+
asBot: true,
|
|
771
|
+
});
|
|
772
|
+
return {
|
|
773
|
+
response,
|
|
774
|
+
asBot: true,
|
|
775
|
+
};
|
|
776
|
+
} catch (error) {
|
|
777
|
+
throw userError.data.error === "missing_scope"
|
|
778
|
+
? error
|
|
779
|
+
: userError;
|
|
780
|
+
}
|
|
781
|
+
},
|
|
782
|
+
_makeDownloadRequest({
|
|
783
|
+
$, url, asBot,
|
|
784
|
+
}) {
|
|
785
|
+
return axios($, {
|
|
786
|
+
url,
|
|
787
|
+
headers: {
|
|
788
|
+
Authorization: `Bearer ${this.getToken({
|
|
789
|
+
asBot,
|
|
790
|
+
})}`,
|
|
791
|
+
},
|
|
792
|
+
responseType: constants.STREAM_RESPONSE_TYPE,
|
|
793
|
+
// Slack redirects unauthorized downloads to its sign-in page
|
|
794
|
+
maxRedirects: 0,
|
|
795
|
+
}).catch((error) => {
|
|
796
|
+
const status = error?.response?.status;
|
|
797
|
+
if (status >= 300 && status < 400) {
|
|
798
|
+
throw new Error(`Slack redirected the download to its sign-in page (HTTP ${status}): the connected account's ${asBot
|
|
799
|
+
? "bot"
|
|
800
|
+
: "user"} token can't access this file's content.`);
|
|
801
|
+
}
|
|
802
|
+
throw error;
|
|
803
|
+
});
|
|
804
|
+
},
|
|
805
|
+
async downloadFileContent({
|
|
806
|
+
$, url, asBot, filepath,
|
|
807
|
+
}) {
|
|
808
|
+
const contentStream = await this._makeDownloadRequest({
|
|
809
|
+
$,
|
|
810
|
+
url,
|
|
811
|
+
asBot,
|
|
812
|
+
});
|
|
813
|
+
let bytesWritten = 0;
|
|
814
|
+
const enforceSizeLimit = new Transform({
|
|
815
|
+
transform(chunk, encoding, callback) {
|
|
816
|
+
bytesWritten += chunk.length;
|
|
817
|
+
if (bytesWritten > constants.MAX_DOWNLOAD_SIZE_BYTES) {
|
|
818
|
+
callback(new Error(`File exceeds the ${constants.MAX_DOWNLOAD_SIZE_BYTES}-byte (2GB) /tmp disk limit for this execution.`));
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
callback(null, chunk);
|
|
822
|
+
},
|
|
823
|
+
});
|
|
824
|
+
try {
|
|
825
|
+
await pipeline(contentStream, enforceSizeLimit, fs.createWriteStream(filepath));
|
|
826
|
+
} catch (error) {
|
|
827
|
+
await fs.promises.rm(filepath, {
|
|
828
|
+
force: true,
|
|
829
|
+
}).catch(() => {});
|
|
830
|
+
throw error;
|
|
831
|
+
}
|
|
832
|
+
return bytesWritten;
|
|
710
833
|
},
|
|
711
834
|
getUserProfile(args = {}) {
|
|
712
835
|
return this.makeRequest({
|
|
@@ -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.34",
|
|
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.13",
|
|
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.13",
|
|
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.13",
|
|
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.13",
|
|
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.19",
|
|
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.13",
|
|
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",
|