@zhin.js/adapter-slack 1.1.26 → 1.1.27
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/CHANGELOG.md +177 -0
- package/LICENSE +21 -0
- package/PERMITS.md +10 -17
- package/README.md +8 -4
- package/agents/slack/conversation.js +15 -0
- package/agents/slack/conversation.ts +17 -0
- package/agents/slack/messages.js +4 -0
- package/agents/slack/messages.ts +4 -0
- package/agents/slack/skills/slack-channels/tools/archive_channel/index.js +6 -7
- package/agents/slack/skills/slack-channels/tools/archive_channel/index.ts +7 -10
- package/agents/slack/skills/slack-channels/tools/invite_to_channel/index.js +5 -5
- package/agents/slack/skills/slack-channels/tools/invite_to_channel/index.ts +5 -6
- package/agents/slack/skills/slack-channels/tools/set_purpose/index.js +5 -5
- package/agents/slack/skills/slack-channels/tools/set_purpose/index.ts +5 -6
- package/agents/slack/skills/slack-channels/tools/set_topic/index.js +5 -5
- package/agents/slack/skills/slack-channels/tools/set_topic/index.ts +5 -6
- package/agents/slack/skills/slack-channels/tools/unarchive/index.js +2 -3
- package/agents/slack/skills/slack-channels/tools/unarchive/index.ts +2 -3
- package/agents/slack/skills/slack-messages/tools/add_reaction/index.js +5 -4
- package/agents/slack/skills/slack-messages/tools/add_reaction/index.ts +5 -5
- package/agents/slack/skills/slack-messages/tools/edit_message/index.js +6 -5
- package/agents/slack/skills/slack-messages/tools/edit_message/index.ts +6 -6
- package/agents/slack/skills/slack-messages/tools/pin_message/index.js +5 -5
- package/agents/slack/skills/slack-messages/tools/pin_message/index.ts +5 -6
- package/agents/slack/skills/slack-messages/tools/remove_reaction/index.js +5 -4
- package/agents/slack/skills/slack-messages/tools/remove_reaction/index.ts +5 -5
- package/agents/slack/skills/slack-messages/tools/unpin_message/index.js +5 -5
- package/agents/slack/skills/slack-messages/tools/unpin_message/index.ts +5 -6
- package/lib/index.d.ts +2 -2
- package/lib/index.js +2 -2
- package/lib/platform-permit.d.ts +4 -12
- package/lib/platform-permit.js +7 -41
- package/lib/protocol.d.ts +1 -5
- package/lib/protocol.js +1 -19
- package/lib/slack-message-ref.d.ts +0 -1
- package/lib/slack-message-ref.js +0 -3
- package/lib/webhook.d.ts +1 -2
- package/lib/webhook.js +12 -29
- package/package.json +24 -26
- package/plugin.js +0 -6
- package/schema.json +0 -56
- package/src/index.ts +1 -7
- package/src/platform-permit.ts +5 -54
- package/src/protocol.ts +2 -23
- package/src/slack-message-ref.ts +0 -4
- package/src/webhook.ts +12 -32
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { messages as t } from "../../../../messages.js";
|
|
3
|
+
import { currentChannel } from "../../../../conversation.js";
|
|
3
4
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
4
5
|
import { z } from 'zod';
|
|
5
6
|
import { normalizeSlackReactionName } from '@zhin.js/adapter-slack';
|
|
6
7
|
export default defineAgentTool({
|
|
7
|
-
description: '
|
|
8
|
+
description: '给当前 Slack 频道(或私信)中的消息添加表情反应',
|
|
8
9
|
inputSchema: z.object({
|
|
9
|
-
|
|
10
|
-
timestamp: z.string().describe('消息时间戳'),
|
|
10
|
+
timestamp: z.string().describe('当前频道中的消息时间戳'),
|
|
11
11
|
emoji: z.string().describe('表情名称(不含冒号)'),
|
|
12
12
|
}),
|
|
13
13
|
adapter: 'slack',
|
|
14
14
|
tags: ['slack'],
|
|
15
|
-
async execute({
|
|
15
|
+
async execute({ timestamp, emoji }, context) {
|
|
16
|
+
const channel = currentChannel(context, { allowDirect: true });
|
|
16
17
|
const client = context.$client;
|
|
17
18
|
const name = normalizeSlackReactionName(emoji);
|
|
18
19
|
try {
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { messages as t } from "../../../../messages.js";
|
|
2
|
+
import { currentChannel } from "../../../../conversation.js";
|
|
2
3
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
4
|
import { z } from 'zod';
|
|
4
5
|
import { normalizeSlackReactionName } from '@zhin.js/adapter-slack';
|
|
5
6
|
|
|
6
7
|
export default defineAgentTool<{
|
|
7
|
-
channel: string;
|
|
8
8
|
timestamp: string;
|
|
9
9
|
emoji: string;
|
|
10
10
|
}>({
|
|
11
|
-
description: '
|
|
11
|
+
description: '给当前 Slack 频道(或私信)中的消息添加表情反应',
|
|
12
12
|
inputSchema: z.object({
|
|
13
|
-
|
|
14
|
-
timestamp: z.string().describe('消息时间戳'),
|
|
13
|
+
timestamp: z.string().describe('当前频道中的消息时间戳'),
|
|
15
14
|
emoji: z.string().describe('表情名称(不含冒号)'),
|
|
16
15
|
}),
|
|
17
16
|
adapter: 'slack',
|
|
18
17
|
tags: ['slack'],
|
|
19
|
-
async execute({
|
|
18
|
+
async execute({ timestamp, emoji }, context) {
|
|
19
|
+
const channel = currentChannel(context, { allowDirect: true });
|
|
20
20
|
const client = context.$client;
|
|
21
21
|
const name = normalizeSlackReactionName(emoji);
|
|
22
22
|
try {
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { messages as t } from "../../../../messages.js";
|
|
3
|
+
import { currentChannel } from "../../../../conversation.js";
|
|
3
4
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
4
5
|
import { z } from 'zod';
|
|
5
6
|
import { editSlackContent } from '@zhin.js/adapter-slack';
|
|
6
7
|
export default defineAgentTool({
|
|
7
|
-
description: '
|
|
8
|
+
description: '编辑当前 Slack 频道(或私信)中你发出的消息',
|
|
8
9
|
inputSchema: z.object({
|
|
9
|
-
|
|
10
|
-
message_ts: z.string().describe('消息时间戳'),
|
|
10
|
+
message_ts: z.string().describe('当前频道中的消息时间戳'),
|
|
11
11
|
text: z.string().describe('新的消息文本'),
|
|
12
12
|
}),
|
|
13
13
|
adapter: 'slack',
|
|
14
14
|
tags: ['slack'],
|
|
15
|
-
async execute({
|
|
15
|
+
async execute({ message_ts, text }, context) {
|
|
16
|
+
const channel = currentChannel(context, { allowDirect: true });
|
|
16
17
|
const client = context.$client;
|
|
17
|
-
await editSlackContent(client, { channel
|
|
18
|
+
await editSlackContent(client, { channel, ts: message_ts, content: [
|
|
18
19
|
{ type: 'text', data: { text } },
|
|
19
20
|
] });
|
|
20
21
|
return { success: true, message: t(context.locale, 'messageEdited') };
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import { messages as t } from "../../../../messages.js";
|
|
2
|
+
import { currentChannel } from "../../../../conversation.js";
|
|
2
3
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
4
|
import { z } from 'zod';
|
|
4
5
|
import { editSlackContent } from '@zhin.js/adapter-slack';
|
|
5
6
|
|
|
6
7
|
export default defineAgentTool<{
|
|
7
|
-
channel: string;
|
|
8
8
|
message_ts: string;
|
|
9
9
|
text: string;
|
|
10
10
|
}>({
|
|
11
|
-
description: '
|
|
11
|
+
description: '编辑当前 Slack 频道(或私信)中你发出的消息',
|
|
12
12
|
inputSchema: z.object({
|
|
13
|
-
|
|
14
|
-
message_ts: z.string().describe('消息时间戳'),
|
|
13
|
+
message_ts: z.string().describe('当前频道中的消息时间戳'),
|
|
15
14
|
text: z.string().describe('新的消息文本'),
|
|
16
15
|
}),
|
|
17
16
|
adapter: 'slack',
|
|
18
17
|
tags: ['slack'],
|
|
19
|
-
async execute({
|
|
18
|
+
async execute({ message_ts, text }, context) {
|
|
19
|
+
const channel = currentChannel(context, { allowDirect: true });
|
|
20
20
|
const client = context.$client;
|
|
21
|
-
await editSlackContent(client, { channel
|
|
21
|
+
await editSlackContent(client, { channel, ts: message_ts, content: [
|
|
22
22
|
{ type: 'text', data: { text } },
|
|
23
23
|
] });
|
|
24
24
|
return { success: true, message: t(context.locale, 'messageEdited') };
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { messages as t } from "../../../../messages.js";
|
|
3
|
+
import { currentChannel } from "../../../../conversation.js";
|
|
3
4
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
4
5
|
import { z } from 'zod';
|
|
5
|
-
import { platformPermission } from '@zhin.js/permission';
|
|
6
6
|
export default defineAgentTool({
|
|
7
|
-
description: '
|
|
7
|
+
description: '置顶当前 Slack 会话中的消息',
|
|
8
8
|
inputSchema: z.object({
|
|
9
|
-
channel: z.string().describe('频道 ID'),
|
|
10
9
|
timestamp: z.string().describe('消息时间戳'),
|
|
11
10
|
}),
|
|
12
11
|
adapter: 'slack',
|
|
13
12
|
tags: ['slack'],
|
|
14
|
-
permissions: [
|
|
15
|
-
async execute({
|
|
13
|
+
permissions: ['admin'],
|
|
14
|
+
async execute({ timestamp }, context) {
|
|
15
|
+
const channel = currentChannel(context, { allowDirect: true });
|
|
16
16
|
const client = context.$client;
|
|
17
17
|
await client.pins.add({ channel, timestamp });
|
|
18
18
|
const success = true;
|
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import { messages as t } from "../../../../messages.js";
|
|
2
|
+
import { currentChannel } from "../../../../conversation.js";
|
|
2
3
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
4
|
import { z } from 'zod';
|
|
4
|
-
import { platformPermission } from '@zhin.js/permission';
|
|
5
5
|
|
|
6
6
|
export default defineAgentTool<{
|
|
7
|
-
channel: string;
|
|
8
7
|
timestamp: string;
|
|
9
8
|
}>({
|
|
10
|
-
description: '
|
|
9
|
+
description: '置顶当前 Slack 会话中的消息',
|
|
11
10
|
inputSchema: z.object({
|
|
12
|
-
channel: z.string().describe('频道 ID'),
|
|
13
11
|
timestamp: z.string().describe('消息时间戳'),
|
|
14
12
|
}),
|
|
15
13
|
adapter: 'slack',
|
|
16
14
|
tags: ['slack'],
|
|
17
|
-
permissions: [
|
|
18
|
-
async execute({
|
|
15
|
+
permissions: ['admin'],
|
|
16
|
+
async execute({ timestamp }, context) {
|
|
17
|
+
const channel = currentChannel(context, { allowDirect: true });
|
|
19
18
|
const client = context.$client;
|
|
20
19
|
await client.pins.add({ channel, timestamp });
|
|
21
20
|
const success = true;
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { messages as t } from "../../../../messages.js";
|
|
3
|
+
import { currentChannel } from "../../../../conversation.js";
|
|
3
4
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
4
5
|
import { z } from 'zod';
|
|
5
6
|
import { normalizeSlackReactionName } from '@zhin.js/adapter-slack';
|
|
6
7
|
export default defineAgentTool({
|
|
7
|
-
description: '
|
|
8
|
+
description: '移除当前 Slack 频道(或私信)中消息上的表情反应',
|
|
8
9
|
inputSchema: z.object({
|
|
9
|
-
|
|
10
|
-
timestamp: z.string().describe('消息时间戳'),
|
|
10
|
+
timestamp: z.string().describe('当前频道中的消息时间戳'),
|
|
11
11
|
name: z.string().describe('表情名称(如 thumbsup、heart)'),
|
|
12
12
|
}),
|
|
13
13
|
adapter: 'slack',
|
|
14
14
|
tags: ['slack'],
|
|
15
|
-
async execute({
|
|
15
|
+
async execute({ timestamp, name }, context) {
|
|
16
|
+
const channel_id = currentChannel(context, { allowDirect: true });
|
|
16
17
|
const client = context.$client;
|
|
17
18
|
try {
|
|
18
19
|
await client.reactions.remove({
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { messages as t } from "../../../../messages.js";
|
|
2
|
+
import { currentChannel } from "../../../../conversation.js";
|
|
2
3
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
4
|
import { z } from 'zod';
|
|
4
5
|
import { normalizeSlackReactionName } from '@zhin.js/adapter-slack';
|
|
5
6
|
|
|
6
7
|
export default defineAgentTool<{
|
|
7
|
-
channel_id: string;
|
|
8
8
|
timestamp: string;
|
|
9
9
|
name: string;
|
|
10
10
|
}>({
|
|
11
|
-
description: '
|
|
11
|
+
description: '移除当前 Slack 频道(或私信)中消息上的表情反应',
|
|
12
12
|
inputSchema: z.object({
|
|
13
|
-
|
|
14
|
-
timestamp: z.string().describe('消息时间戳'),
|
|
13
|
+
timestamp: z.string().describe('当前频道中的消息时间戳'),
|
|
15
14
|
name: z.string().describe('表情名称(如 thumbsup、heart)'),
|
|
16
15
|
}),
|
|
17
16
|
adapter: 'slack',
|
|
18
17
|
tags: ['slack'],
|
|
19
|
-
async execute({
|
|
18
|
+
async execute({ timestamp, name }, context) {
|
|
19
|
+
const channel_id = currentChannel(context, { allowDirect: true });
|
|
20
20
|
const client = context.$client;
|
|
21
21
|
try {
|
|
22
22
|
await client.reactions.remove({
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { messages as t } from "../../../../messages.js";
|
|
3
|
+
import { currentChannel } from "../../../../conversation.js";
|
|
3
4
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
4
5
|
import { z } from 'zod';
|
|
5
|
-
import { platformPermission } from '@zhin.js/permission';
|
|
6
6
|
export default defineAgentTool({
|
|
7
|
-
description: '
|
|
7
|
+
description: '取消当前 Slack 会话中消息的置顶',
|
|
8
8
|
inputSchema: z.object({
|
|
9
|
-
channel_id: z.string().describe('频道 ID'),
|
|
10
9
|
timestamp: z.string().describe('消息时间戳'),
|
|
11
10
|
}),
|
|
12
11
|
adapter: 'slack',
|
|
13
12
|
tags: ['slack'],
|
|
14
|
-
permissions: [
|
|
15
|
-
async execute({
|
|
13
|
+
permissions: ['admin'],
|
|
14
|
+
async execute({ timestamp }, context) {
|
|
15
|
+
const channel_id = currentChannel(context, { allowDirect: true });
|
|
16
16
|
const client = context.$client;
|
|
17
17
|
await client.pins.remove({ channel: channel_id, timestamp });
|
|
18
18
|
const success = true;
|
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import { messages as t } from "../../../../messages.js";
|
|
2
|
+
import { currentChannel } from "../../../../conversation.js";
|
|
2
3
|
import { defineAgentTool } from '@zhin.js/tool';
|
|
3
4
|
import { z } from 'zod';
|
|
4
|
-
import { platformPermission } from '@zhin.js/permission';
|
|
5
5
|
|
|
6
6
|
export default defineAgentTool<{
|
|
7
|
-
channel_id: string;
|
|
8
7
|
timestamp: string;
|
|
9
8
|
}>({
|
|
10
|
-
description: '
|
|
9
|
+
description: '取消当前 Slack 会话中消息的置顶',
|
|
11
10
|
inputSchema: z.object({
|
|
12
|
-
channel_id: z.string().describe('频道 ID'),
|
|
13
11
|
timestamp: z.string().describe('消息时间戳'),
|
|
14
12
|
}),
|
|
15
13
|
adapter: 'slack',
|
|
16
14
|
tags: ['slack'],
|
|
17
|
-
permissions: [
|
|
18
|
-
async execute({
|
|
15
|
+
permissions: ['admin'],
|
|
16
|
+
async execute({ timestamp }, context) {
|
|
17
|
+
const channel_id = currentChannel(context, { allowDirect: true });
|
|
19
18
|
const client = context.$client;
|
|
20
19
|
await client.pins.remove({ channel: channel_id, timestamp });
|
|
21
20
|
const success = true;
|
package/lib/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { formatInboundContent, formatInteractionContent, formatOutboundWire, formatSlashContent, headerValue, keyboardToBlockKitBlocks, normalizeWebhookPath,
|
|
1
|
+
export { formatInboundContent, formatInteractionContent, formatOutboundWire, formatSlashContent, headerValue, keyboardToBlockKitBlocks, normalizeWebhookPath, resolveSlackChannelType, resolveSlackConfig, slackInboundConversation, verifySlackSignature, type ResolvedSlackConfig, type SlackEndpointConfig, type SlackBlockAction, type SlackEvent, type SlackEventEnvelope, type SlackInteractionPayload, type SlackMessageEvent, type SlackSlashCommand, type SlackUrlVerification, type SlackWireSegment, } from './protocol.js';
|
|
2
2
|
export { SlackEndpoint, type SlackEndpointOptions, type SlackSocketLike, type SlackWebClientLike, } from './endpoint.js';
|
|
3
3
|
export { registerSlackWebhookRoutes, handleSlackWebhookRequest, type SlackWebhookHandler, } from './webhook.js';
|
|
4
4
|
export { type SlackClientEventMap, type SlackUserInfo, } from './client.js';
|
|
5
|
-
export {
|
|
5
|
+
export { platformPermit } from './platform-permit.js';
|
|
6
6
|
export { normalizeSlackReactionName } from './slack-reaction.js';
|
|
7
7
|
export { markdownToMrkdwn, mrkdwnToPlainFallback, splitMrkdwnText } from './markdown-to-mrkdwn.js';
|
|
8
8
|
export { mrkdwnToMarkdown } from './mrkdwn-to-markdown.js';
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { formatInboundContent, formatInteractionContent, formatOutboundWire, formatSlashContent, headerValue, keyboardToBlockKitBlocks, normalizeWebhookPath,
|
|
1
|
+
export { formatInboundContent, formatInteractionContent, formatOutboundWire, formatSlashContent, headerValue, keyboardToBlockKitBlocks, normalizeWebhookPath, resolveSlackChannelType, resolveSlackConfig, slackInboundConversation, verifySlackSignature, } from './protocol.js';
|
|
2
2
|
export { SlackEndpoint, } from './endpoint.js';
|
|
3
3
|
export { registerSlackWebhookRoutes, handleSlackWebhookRequest, } from './webhook.js';
|
|
4
|
-
export {
|
|
4
|
+
export { platformPermit } from './platform-permit.js';
|
|
5
5
|
export { normalizeSlackReactionName } from './slack-reaction.js';
|
|
6
6
|
export { markdownToMrkdwn, mrkdwnToPlainFallback, splitMrkdwnText } from './markdown-to-mrkdwn.js';
|
|
7
7
|
export { mrkdwnToMarkdown } from './mrkdwn-to-markdown.js';
|
package/lib/platform-permit.d.ts
CHANGED
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Slack platform permit
|
|
2
|
+
* Slack platform permit helper(ADR 0056 §5)。
|
|
3
|
+
*
|
|
4
|
+
* 平台身份由适配器上报到 `sender.platform`,permit 由内置评估器(`@zhin.js/permission`)判断;
|
|
5
|
+
* 适配器不再导出自有的 permit 解析器或检查函数。
|
|
3
6
|
*/
|
|
4
|
-
import type { PermissionSubject } from '@zhin.js/permission';
|
|
5
7
|
export declare function platformPermit(perm: string): string;
|
|
6
|
-
export declare function slackGroupPermitResolver(logicalPerm: string): string;
|
|
7
|
-
export declare function normalizeSlackSenderForPermit(input: {
|
|
8
|
-
isWorkspaceOwner?: boolean;
|
|
9
|
-
isWorkspaceAdmin?: boolean;
|
|
10
|
-
isChannelManager?: boolean;
|
|
11
|
-
}): {
|
|
12
|
-
role?: string;
|
|
13
|
-
permissions?: string[];
|
|
14
|
-
};
|
|
15
|
-
export declare function checkSlackPlatformPermit(perm: string, subject: PermissionSubject): boolean;
|
package/lib/platform-permit.js
CHANGED
|
@@ -1,43 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Slack platform permit helper(ADR 0056 §5)。
|
|
3
|
+
*
|
|
4
|
+
* 平台身份由适配器上报到 `sender.platform`,permit 由内置评估器(`@zhin.js/permission`)判断;
|
|
5
|
+
* 适配器不再导出自有的 permit 解析器或检查函数。
|
|
6
|
+
*/
|
|
2
7
|
export function platformPermit(perm) {
|
|
3
|
-
return `platform
|
|
4
|
-
}
|
|
5
|
-
const FACTORY_PERM_MAP = {
|
|
6
|
-
scene_admin: 'channel_manager',
|
|
7
|
-
scene_owner: 'workspace_owner',
|
|
8
|
-
};
|
|
9
|
-
export function slackGroupPermitResolver(logicalPerm) {
|
|
10
|
-
return platformPermit(FACTORY_PERM_MAP[logicalPerm] ?? logicalPerm);
|
|
11
|
-
}
|
|
12
|
-
export function normalizeSlackSenderForPermit(input) {
|
|
13
|
-
const permissions = [];
|
|
14
|
-
if (input.isWorkspaceOwner) {
|
|
15
|
-
permissions.push('workspace_owner', 'workspace_admin', 'channel_manager');
|
|
16
|
-
return { role: 'owner', permissions };
|
|
17
|
-
}
|
|
18
|
-
if (input.isWorkspaceAdmin) {
|
|
19
|
-
permissions.push('workspace_admin', 'channel_manager');
|
|
20
|
-
return { role: 'admin', permissions };
|
|
21
|
-
}
|
|
22
|
-
if (input.isChannelManager) {
|
|
23
|
-
permissions.push('channel_manager');
|
|
24
|
-
return { role: 'channel_admin', permissions };
|
|
25
|
-
}
|
|
26
|
-
return { role: 'member', permissions };
|
|
27
|
-
}
|
|
28
|
-
export function checkSlackPlatformPermit(perm, subject) {
|
|
29
|
-
const role = subject.sender?.role?.[0];
|
|
30
|
-
const permissions = subject.sender?.permissions ?? [];
|
|
31
|
-
const has = (t) => permissions.includes(t);
|
|
32
|
-
switch (perm) {
|
|
33
|
-
case 'workspace_owner':
|
|
34
|
-
return role === 'owner' || has('workspace_owner');
|
|
35
|
-
case 'workspace_admin':
|
|
36
|
-
return role === 'owner' || role === 'admin' || has('workspace_admin') || has('workspace_owner');
|
|
37
|
-
case 'channel_manager':
|
|
38
|
-
return role === 'owner' || role === 'admin' || role === 'channel_admin'
|
|
39
|
-
|| has('channel_manager') || has('workspace_admin') || has('workspace_owner');
|
|
40
|
-
default:
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
8
|
+
return `platform-permission:${perm}`;
|
|
43
9
|
}
|
package/lib/protocol.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { EndpointProfileConfiguration } from 'zhin.js/adapter';
|
|
2
|
-
import type { IncomingMessage } from 'node:http';
|
|
3
2
|
import { type ConversationRef } from '@zhin.js/im-contract';
|
|
4
3
|
/** One endpoint config after AdapterIndex expands `plugins.<instanceKey>.endpoints`. */
|
|
5
4
|
export interface SlackEndpointConfig extends EndpointProfileConfiguration {
|
|
@@ -156,7 +155,4 @@ export declare function formatOutboundWire(payload: unknown): {
|
|
|
156
155
|
};
|
|
157
156
|
export declare function keyboardToBlockKitBlocks(data: Record<string, unknown>): SlackBlock[];
|
|
158
157
|
export declare function verifySlackSignature(signingSecret: string, rawBody: string, timestamp: string, signature: string): boolean;
|
|
159
|
-
export declare function
|
|
160
|
-
readonly limit?: number;
|
|
161
|
-
}): Promise<string>;
|
|
162
|
-
export declare function headerValue(headers: IncomingMessage['headers'], name: string): string;
|
|
158
|
+
export declare function headerValue(headers: Headers, name: string): string;
|
package/lib/protocol.js
CHANGED
|
@@ -265,24 +265,6 @@ export function verifySlackSignature(signingSecret, rawBody, timestamp, signatur
|
|
|
265
265
|
return false;
|
|
266
266
|
return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
|
|
267
267
|
}
|
|
268
|
-
export async function readTextBody(request, options = {}) {
|
|
269
|
-
const limit = options.limit ?? 1_048_576;
|
|
270
|
-
const chunks = [];
|
|
271
|
-
let size = 0;
|
|
272
|
-
for await (const chunk of request) {
|
|
273
|
-
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
274
|
-
size += buffer.length;
|
|
275
|
-
if (size > limit) {
|
|
276
|
-
request.destroy();
|
|
277
|
-
throw new Error(`Request body exceeds ${limit} bytes`);
|
|
278
|
-
}
|
|
279
|
-
chunks.push(buffer);
|
|
280
|
-
}
|
|
281
|
-
return Buffer.concat(chunks).toString('utf8');
|
|
282
|
-
}
|
|
283
268
|
export function headerValue(headers, name) {
|
|
284
|
-
|
|
285
|
-
if (Array.isArray(raw))
|
|
286
|
-
return raw[0] ?? '';
|
|
287
|
-
return raw ?? '';
|
|
269
|
+
return headers.get(name) ?? '';
|
|
288
270
|
}
|
package/lib/slack-message-ref.js
CHANGED
package/lib/webhook.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Slack webhook HTTP: signature → parse → admit.
|
|
3
3
|
*/
|
|
4
|
-
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
5
4
|
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
6
5
|
import { type ResolvedSlackConfig, type SlackInteractionPayload, type SlackSlashCommand } from './protocol.js';
|
|
7
6
|
export interface SlackWebhookHandler {
|
|
@@ -11,4 +10,4 @@ export interface SlackWebhookHandler {
|
|
|
11
10
|
admitSlashCommand(cmd: SlackSlashCommand): void;
|
|
12
11
|
}
|
|
13
12
|
export declare function registerSlackWebhookRoutes(http: HttpHost, handler: SlackWebhookHandler): HttpRouteRegistration[];
|
|
14
|
-
export declare function handleSlackWebhookRequest(request:
|
|
13
|
+
export declare function handleSlackWebhookRequest(request: Request, handler: SlackWebhookHandler): Promise<Response>;
|
package/lib/webhook.js
CHANGED
|
@@ -1,23 +1,20 @@
|
|
|
1
|
+
import { readTextBody } from '@zhin.js/host-http-contract';
|
|
1
2
|
import { getLogger } from '@zhin.js/logger';
|
|
2
|
-
import { headerValue,
|
|
3
|
+
import { headerValue, verifySlackSignature, } from './protocol.js';
|
|
3
4
|
const logger = getLogger('slack');
|
|
4
5
|
export function registerSlackWebhookRoutes(http, handler) {
|
|
5
6
|
const path = handler.config.webhookPath;
|
|
6
7
|
return [
|
|
7
|
-
http.route('POST', path,
|
|
8
|
-
await handleSlackWebhookRequest(request, response, handler);
|
|
9
|
-
}, { summary: 'Slack Events API / Interactivity', tags: ['slack'] }),
|
|
8
|
+
http.route('POST', path, (request) => handleSlackWebhookRequest(request, handler), { summary: 'Slack Events API / Interactivity', tags: ['slack'] }),
|
|
10
9
|
];
|
|
11
10
|
}
|
|
12
|
-
export async function handleSlackWebhookRequest(request,
|
|
11
|
+
export async function handleSlackWebhookRequest(request, handler) {
|
|
13
12
|
try {
|
|
14
13
|
const rawBody = await readTextBody(request);
|
|
15
14
|
const timestamp = headerValue(request.headers, 'x-slack-request-timestamp');
|
|
16
15
|
const signature = headerValue(request.headers, 'x-slack-signature');
|
|
17
16
|
if (!verifySlackSignature(handler.config.signingSecret, rawBody, timestamp, signature)) {
|
|
18
|
-
|
|
19
|
-
response.end('Invalid signature');
|
|
20
|
-
return;
|
|
17
|
+
return new Response('Invalid signature', { status: 401, headers: { 'Content-Type': 'text/plain' } });
|
|
21
18
|
}
|
|
22
19
|
const contentType = headerValue(request.headers, 'content-type');
|
|
23
20
|
if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
@@ -25,17 +22,13 @@ export async function handleSlackWebhookRequest(request, response, handler) {
|
|
|
25
22
|
const payloadStr = params.get('payload');
|
|
26
23
|
if (payloadStr) {
|
|
27
24
|
const payload = JSON.parse(payloadStr);
|
|
28
|
-
response.writeHead(200);
|
|
29
|
-
response.end('');
|
|
30
25
|
handler.admitInteraction(payload);
|
|
31
|
-
return;
|
|
26
|
+
return new Response('', { status: 200 });
|
|
32
27
|
}
|
|
33
28
|
const body = Object.fromEntries(params);
|
|
34
29
|
if (body.command) {
|
|
35
|
-
response.writeHead(200);
|
|
36
|
-
response.end('');
|
|
37
30
|
handler.admitSlashCommand(body);
|
|
38
|
-
return;
|
|
31
|
+
return new Response('', { status: 200 });
|
|
39
32
|
}
|
|
40
33
|
}
|
|
41
34
|
let envelope;
|
|
@@ -43,30 +36,20 @@ export async function handleSlackWebhookRequest(request, response, handler) {
|
|
|
43
36
|
envelope = JSON.parse(rawBody);
|
|
44
37
|
}
|
|
45
38
|
catch {
|
|
46
|
-
|
|
47
|
-
response.end('');
|
|
48
|
-
return;
|
|
39
|
+
return new Response('', { status: 200 });
|
|
49
40
|
}
|
|
50
41
|
if (envelope.type === 'url_verification') {
|
|
51
42
|
const challenge = envelope.challenge;
|
|
52
|
-
|
|
53
|
-
response.end(JSON.stringify({ challenge }));
|
|
54
|
-
return;
|
|
43
|
+
return new Response(JSON.stringify({ challenge }), { status: 200, headers: { 'Content-Type': 'application/json' } });
|
|
55
44
|
}
|
|
56
45
|
if (envelope.type === 'event_callback' && envelope.event) {
|
|
57
|
-
response.writeHead(200);
|
|
58
|
-
response.end('');
|
|
59
46
|
handler.handleEnvelope(envelope);
|
|
60
|
-
return;
|
|
47
|
+
return new Response('', { status: 200 });
|
|
61
48
|
}
|
|
62
|
-
|
|
63
|
-
response.end('');
|
|
49
|
+
return new Response('', { status: 200 });
|
|
64
50
|
}
|
|
65
51
|
catch (error) {
|
|
66
52
|
logger.error('Slack webhook error:', error);
|
|
67
|
-
|
|
68
|
-
response.writeHead(200);
|
|
69
|
-
response.end('');
|
|
70
|
-
}
|
|
53
|
+
return new Response('', { status: 200 });
|
|
71
54
|
}
|
|
72
55
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-slack",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.27",
|
|
4
4
|
"description": "Zhin.js Slack adapter for Plugin Runtime (Socket Mode / HTTP Events)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -33,26 +33,27 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@slack/socket-mode": "^2.0.7",
|
|
35
35
|
"@slack/web-api": "^7.19.0",
|
|
36
|
-
"
|
|
37
|
-
"@zhin.js/
|
|
38
|
-
"@zhin.js/
|
|
39
|
-
"@zhin.js/
|
|
40
|
-
"@zhin.js/
|
|
41
|
-
"@zhin.js/
|
|
42
|
-
"@zhin.js/
|
|
43
|
-
"@zhin.js/
|
|
44
|
-
"@zhin.js/
|
|
45
|
-
"@zhin.js/
|
|
46
|
-
"@zhin.js/
|
|
36
|
+
"zod": "^4.6.7",
|
|
37
|
+
"@zhin.js/adapter": "1.1.33",
|
|
38
|
+
"@zhin.js/agent-feature": "1.1.17",
|
|
39
|
+
"@zhin.js/console-contract": "1.1.6",
|
|
40
|
+
"@zhin.js/core": "1.2.0",
|
|
41
|
+
"@zhin.js/feature-kit": "1.1.16",
|
|
42
|
+
"@zhin.js/host-http": "1.2.0",
|
|
43
|
+
"@zhin.js/host-http-contract": "1.2.0",
|
|
44
|
+
"@zhin.js/im-contract": "1.1.14",
|
|
45
|
+
"@zhin.js/logger": "1.1.3",
|
|
46
|
+
"@zhin.js/page": "1.1.18",
|
|
47
|
+
"@zhin.js/skill": "1.1.17",
|
|
48
|
+
"@zhin.js/tool": "1.1.19"
|
|
47
49
|
},
|
|
48
50
|
"peerDependencies": {
|
|
49
|
-
"
|
|
50
|
-
"@zhin.js/
|
|
51
|
-
"@zhin.js/
|
|
52
|
-
"@zhin.js/
|
|
53
|
-
"@zhin.js/
|
|
54
|
-
"
|
|
55
|
-
"zhin.js": "^1.1.25"
|
|
51
|
+
"@zhin.js/adapter": "^1.1.33",
|
|
52
|
+
"@zhin.js/command": "^1.2.0",
|
|
53
|
+
"@zhin.js/core": "^1.2.0",
|
|
54
|
+
"@zhin.js/host-http": "^1.2.0",
|
|
55
|
+
"@zhin.js/permission": "^1.2.0",
|
|
56
|
+
"zhin.js": "^1.1.26"
|
|
56
57
|
},
|
|
57
58
|
"peerDependenciesMeta": {
|
|
58
59
|
"@zhin.js/command": {
|
|
@@ -60,17 +61,15 @@
|
|
|
60
61
|
},
|
|
61
62
|
"zhin.js": {
|
|
62
63
|
"optional": true
|
|
63
|
-
},
|
|
64
|
-
"zod": {
|
|
65
|
-
"optional": true
|
|
66
64
|
}
|
|
67
65
|
},
|
|
68
66
|
"devDependencies": {
|
|
69
67
|
"@types/node": "^26.1.2",
|
|
68
|
+
"@types/ws": "^8.18.1",
|
|
70
69
|
"typescript": "^6.0.3",
|
|
71
70
|
"vitest": "^4.1.10",
|
|
72
|
-
"
|
|
73
|
-
"zhin.js": "1.1.
|
|
71
|
+
"ws": "^8.21.1",
|
|
72
|
+
"zhin.js": "1.1.26"
|
|
74
73
|
},
|
|
75
74
|
"files": [
|
|
76
75
|
"adapters",
|
|
@@ -80,7 +79,6 @@
|
|
|
80
79
|
"schema.json",
|
|
81
80
|
"src",
|
|
82
81
|
"lib",
|
|
83
|
-
"tools",
|
|
84
82
|
"agents",
|
|
85
83
|
"README.md",
|
|
86
84
|
"CHANGELOG.md",
|
|
@@ -130,6 +128,6 @@
|
|
|
130
128
|
"scripts": {
|
|
131
129
|
"build": "tsc",
|
|
132
130
|
"clean": "rimraf lib",
|
|
133
|
-
"test": "
|
|
131
|
+
"test": "vitest run --root ../../.. plugins/adapters/slack/tests"
|
|
134
132
|
}
|
|
135
133
|
}
|
package/plugin.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { definePlugin } from 'zhin.js';
|
|
3
|
-
import { permissionHostToken } from '@zhin.js/permission';
|
|
4
|
-
import { checkSlackPlatformPermit } from "./lib/platform-permit.js";
|
|
5
3
|
import { createSlackConsoleRpc } from "./lib/console.js";
|
|
6
4
|
export default definePlugin({
|
|
7
5
|
name: 'slack',
|
|
@@ -10,12 +8,8 @@ export default definePlugin({
|
|
|
10
8
|
displayName: 'Slack Adapter',
|
|
11
9
|
},
|
|
12
10
|
setup(context) {
|
|
13
|
-
const dispose = context.resources.has(permissionHostToken)
|
|
14
|
-
? context.resources.use(permissionHostToken).registerPlatform('slack', checkSlackPlatformPermit)
|
|
15
|
-
: undefined;
|
|
16
11
|
return {
|
|
17
12
|
consoleRpc: createSlackConsoleRpc(() => context.config.get()),
|
|
18
|
-
...(dispose ? { dispose } : {}),
|
|
19
13
|
};
|
|
20
14
|
},
|
|
21
15
|
});
|