@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.
Files changed (46) hide show
  1. package/CHANGELOG.md +177 -0
  2. package/LICENSE +21 -0
  3. package/PERMITS.md +10 -17
  4. package/README.md +8 -4
  5. package/agents/slack/conversation.js +15 -0
  6. package/agents/slack/conversation.ts +17 -0
  7. package/agents/slack/messages.js +4 -0
  8. package/agents/slack/messages.ts +4 -0
  9. package/agents/slack/skills/slack-channels/tools/archive_channel/index.js +6 -7
  10. package/agents/slack/skills/slack-channels/tools/archive_channel/index.ts +7 -10
  11. package/agents/slack/skills/slack-channels/tools/invite_to_channel/index.js +5 -5
  12. package/agents/slack/skills/slack-channels/tools/invite_to_channel/index.ts +5 -6
  13. package/agents/slack/skills/slack-channels/tools/set_purpose/index.js +5 -5
  14. package/agents/slack/skills/slack-channels/tools/set_purpose/index.ts +5 -6
  15. package/agents/slack/skills/slack-channels/tools/set_topic/index.js +5 -5
  16. package/agents/slack/skills/slack-channels/tools/set_topic/index.ts +5 -6
  17. package/agents/slack/skills/slack-channels/tools/unarchive/index.js +2 -3
  18. package/agents/slack/skills/slack-channels/tools/unarchive/index.ts +2 -3
  19. package/agents/slack/skills/slack-messages/tools/add_reaction/index.js +5 -4
  20. package/agents/slack/skills/slack-messages/tools/add_reaction/index.ts +5 -5
  21. package/agents/slack/skills/slack-messages/tools/edit_message/index.js +6 -5
  22. package/agents/slack/skills/slack-messages/tools/edit_message/index.ts +6 -6
  23. package/agents/slack/skills/slack-messages/tools/pin_message/index.js +5 -5
  24. package/agents/slack/skills/slack-messages/tools/pin_message/index.ts +5 -6
  25. package/agents/slack/skills/slack-messages/tools/remove_reaction/index.js +5 -4
  26. package/agents/slack/skills/slack-messages/tools/remove_reaction/index.ts +5 -5
  27. package/agents/slack/skills/slack-messages/tools/unpin_message/index.js +5 -5
  28. package/agents/slack/skills/slack-messages/tools/unpin_message/index.ts +5 -6
  29. package/lib/index.d.ts +2 -2
  30. package/lib/index.js +2 -2
  31. package/lib/platform-permit.d.ts +4 -12
  32. package/lib/platform-permit.js +7 -41
  33. package/lib/protocol.d.ts +1 -5
  34. package/lib/protocol.js +1 -19
  35. package/lib/slack-message-ref.d.ts +0 -1
  36. package/lib/slack-message-ref.js +0 -3
  37. package/lib/webhook.d.ts +1 -2
  38. package/lib/webhook.js +12 -29
  39. package/package.json +24 -26
  40. package/plugin.js +0 -6
  41. package/schema.json +0 -56
  42. package/src/index.ts +1 -7
  43. package/src/platform-permit.ts +5 -54
  44. package/src/protocol.ts +2 -23
  45. package/src/slack-message-ref.ts +0 -4
  46. 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: '给 Slack 消息添加表情反应',
8
+ description: '给当前 Slack 频道(或私信)中的消息添加表情反应',
8
9
  inputSchema: z.object({
9
- channel: z.string().describe('频道 ID'),
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({ channel, timestamp, emoji }, context) {
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: '给 Slack 消息添加表情反应',
11
+ description: '给当前 Slack 频道(或私信)中的消息添加表情反应',
12
12
  inputSchema: z.object({
13
- channel: z.string().describe('频道 ID'),
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({ channel, timestamp, emoji }, context) {
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: '编辑 Slack 消息',
8
+ description: '编辑当前 Slack 频道(或私信)中你发出的消息',
8
9
  inputSchema: z.object({
9
- channel: z.string().describe('频道 ID'),
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({ channel, message_ts, text }, context) {
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: channel, ts: message_ts, content: [
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: '编辑 Slack 消息',
11
+ description: '编辑当前 Slack 频道(或私信)中你发出的消息',
12
12
  inputSchema: z.object({
13
- channel: z.string().describe('频道 ID'),
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({ channel, message_ts, text }, context) {
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: channel, ts: message_ts, content: [
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: '置顶 Slack 消息',
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: [platformPermission('slack', 'channel_manager')],
15
- async execute({ channel, timestamp }, context) {
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: '置顶 Slack 消息',
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: [platformPermission('slack', 'channel_manager')],
18
- async execute({ channel, timestamp }, context) {
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: '移除 Slack 消息上的表情反应',
8
+ description: '移除当前 Slack 频道(或私信)中消息上的表情反应',
8
9
  inputSchema: z.object({
9
- channel_id: z.string().describe('频道 ID'),
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({ channel_id, timestamp, name }, context) {
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: '移除 Slack 消息上的表情反应',
11
+ description: '移除当前 Slack 频道(或私信)中消息上的表情反应',
12
12
  inputSchema: z.object({
13
- channel_id: z.string().describe('频道 ID'),
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({ channel_id, timestamp, name }, context) {
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: '取消 Slack 频道中消息的置顶',
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: [platformPermission('slack', 'channel_manager')],
15
- async execute({ channel_id, timestamp }, context) {
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: '取消 Slack 频道中消息的置顶',
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: [platformPermission('slack', 'channel_manager')],
18
- async execute({ channel_id, timestamp }, context) {
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, readTextBody, 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';
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 { checkSlackPlatformPermit, normalizeSlackSenderForPermit, platformPermit, slackGroupPermitResolver, } from './platform-permit.js';
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, readTextBody, resolveSlackChannelType, resolveSlackConfig, slackInboundConversation, verifySlackSignature, } from './protocol.js';
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 { checkSlackPlatformPermit, normalizeSlackSenderForPermit, platformPermit, slackGroupPermitResolver, } from './platform-permit.js';
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';
@@ -1,15 +1,7 @@
1
1
  /**
2
- * Slack platform permit — workspace + channel 权限
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;
@@ -1,43 +1,9 @@
1
- const ADAPTER = 'slack';
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(${ADAPTER},${perm})`;
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 readTextBody(request: IncomingMessage, options?: {
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
- const raw = headers[name.toLowerCase()];
285
- if (Array.isArray(raw))
286
- return raw[0] ?? '';
287
- return raw ?? '';
269
+ return headers.get(name) ?? '';
288
270
  }
@@ -4,4 +4,3 @@ export declare function parseSlackMessageRef(ref: string): {
4
4
  channel: string;
5
5
  ts: string;
6
6
  } | null;
7
- export declare function slackMessageTs(ref: string): string;
@@ -12,6 +12,3 @@ export function parseSlackMessageRef(ref) {
12
12
  return null;
13
13
  return { channel, ts };
14
14
  }
15
- export function slackMessageTs(ref) {
16
- return parseSlackMessageRef(ref)?.ts ?? ref;
17
- }
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: IncomingMessage, response: ServerResponse, handler: SlackWebhookHandler): Promise<void>;
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, readTextBody, verifySlackSignature, } from './protocol.js';
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, async (request, response) => {
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, response, handler) {
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
- response.writeHead(401, { 'Content-Type': 'text/plain' });
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
- response.writeHead(200);
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
- response.writeHead(200, { 'Content-Type': 'application/json' });
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
- response.writeHead(200);
63
- response.end('');
49
+ return new Response('', { status: 200 });
64
50
  }
65
51
  catch (error) {
66
52
  logger.error('Slack webhook error:', error);
67
- if (!response.headersSent) {
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.26",
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
- "@zhin.js/adapter": "1.1.32",
37
- "@zhin.js/agent-feature": "1.1.16",
38
- "@zhin.js/console-contract": "1.1.5",
39
- "@zhin.js/core": "1.1.60",
40
- "@zhin.js/feature-kit": "1.1.15",
41
- "@zhin.js/host-http": "1.1.17",
42
- "@zhin.js/im-contract": "1.1.13",
43
- "@zhin.js/logger": "1.1.2",
44
- "@zhin.js/page": "1.1.17",
45
- "@zhin.js/skill": "1.1.16",
46
- "@zhin.js/tool": "1.1.18"
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
- "zod": "^4.0.0",
50
- "@zhin.js/adapter": "^1.1.32",
51
- "@zhin.js/command": "^1.1.17",
52
- "@zhin.js/core": "^1.1.60",
53
- "@zhin.js/host-http": "^1.1.17",
54
- "@zhin.js/permission": "^1.1.15",
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
- "zod": "^4.4.3",
73
- "zhin.js": "1.1.25"
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": "NODE_OPTIONS=--experimental-strip-types vitest run --root ../../.. plugins/adapters/slack/tests"
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
  });