@flink-app/slack-plugin (英语)
双向黑消息插件 闪烁。使用自动发现的处理器文件接收并回复Slack消息——与 @flink-app/inbound-email-plugin。 。 。 .
特征
- 接收频道消息、 DMs 、 引用和线索回复
- 向频道和线索发送消息
- 上传和下载已输入的文件
SlackFile元数据 - 添加情感反应
- 获取上下文线索和频道历史
- 自动发现
SlackHandler文件通过 Flink 编译器插件 - 套接字模式( 不需要公共 URL) 和 HTTP 模式
- 防止无限循环的瓶装信件过滤
- 自动
<@BOTID>提及剥离 requestContext用户/许可证注射一体化
安装
pnpm add @flink-app/slack-plugin
设置
1. 配置编译器插件
在你身边 flink.config.js数字 :
const { compilerPlugin } = require("@flink-app/slack-plugin/compiler");
module.exports = {
compilerPlugins: [compilerPlugin()],
};
这让 Flink 编译器扫描 src/slack-handlers/ 用于处理文件.
2. 注册插件
import { slackPlugin } from "@flink-app/slack-plugin";
const app = new FlinkApp<AppCtx>({
plugins: [
slackPlugin<AppCtx>({
connection: {
mode: "socket",
token: process.env.SLACK_BOT_TOKEN!,
appToken: process.env.SLACK_APP_TOKEN!,
signingSecret: process.env.SLACK_SIGNING_SECRET!,
},
// Optional: resolve your app's user from a Slack user ID
resolveUser: async (msg, ctx) => {
return ctx.repos.userRepo.findOne({ slackUserId: msg.userId });
},
}),
],
});
3. 扩展您的应用程序上下文类型
导入 SlackPluginCtx 并把它当作一般论点 FlinkContext。这让你完全安全 ctx.plugins.slack 整个应用程序.
// src/Ctx.ts
import { FlinkContext } from "@flink-app/flink";
import { SlackPluginCtx } from "@flink-app/slack-plugin";
export interface Ctx extends FlinkContext<SlackPluginCtx> {
repos: {
// your repos here
};
}
ctx.plugins.slack 然后完全输入——发送信件、管理连接和访问原始 WebClient。 。 。 .
说明: 导入
SlackPluginCtx(无)SlackApi当扩展您的Ctx。 。 。 .SlackApi是内置的 API 类型,并非用于此目的.
4. 创建处理文件
在 src/slack-handlers/。每个文件导出默认的处理器函数和一个可选 Route。 。 。 .
处理器示例
响应@ mentions
// src/slack-handlers/HandleMention.ts
import { SlackHandler, SlackRouteProps } from "@flink-app/slack-plugin";
export const Route: SlackRouteProps = { isMention: true };
const handler: SlackHandler<AppCtx> = async ({ ctx, message, slack }) => {
const thread = await slack.getThread(message);
await slack.reply(message, `You said: "${message.text}". Thread has ${thread.messages.length} messages.`);
};
export default handler;
处理模式
// src/slack-handlers/HandleDM.ts
import { SlackHandler, SlackRouteProps } from "@flink-app/slack-plugin";
export const Route: SlackRouteProps = { isDM: true };
const handler: SlackHandler<AppCtx> = async ({ message, slack }) => {
await slack.reply(message, `Got your DM: "${message.text}"`);
};
export default handler;
按模式匹配
// src/slack-handlers/HandleHelp.ts
import { SlackHandler, SlackRouteProps } from "@flink-app/slack-plugin";
export const Route: SlackRouteProps = { pattern: /^help$/i };
const handler: SlackHandler<AppCtx> = async ({ message, slack }) => {
await slack.reply(message, "Here's what I can do…");
};
export default handler;
按频道匹配
// src/slack-handlers/HandleSupport.ts
import { SlackHandler, SlackRouteProps } from "@flink-app/slack-plugin";
export const Route: SlackRouteProps = { channel: "support" };
const handler: SlackHandler<AppCtx> = async ({ ctx, message, slack }) => {
await slack.reply(message, "A support agent will be with you shortly.");
};
export default handler;
接通( 无路线)
// src/slack-handlers/Fallback.ts
import { SlackHandler } from "@flink-app/slack-plugin";
const handler: SlackHandler<AppCtx> = async ({ message, slack }) => {
console.log(`Unrouted message from ${message.userId}: ${message.text}`);
};
export default handler;
路由属性
| 财产 | 类型 | 说明 |
|---|---|---|
channel | string | RegExp | (msg) => boolean | 按频道标识匹配 |
pattern | string | RegExp | (msg) => boolean | 匹配信件文本 |
isDM | boolean | 只匹配直接消息 |
isMention | boolean | 仅匹配@mention |
isThread | boolean | 只匹配线索回复 |
connectionId | string | string[] | 只匹配来自特定连接的信件 |
空出或省略 Route 匹配所有信件( 全部抓取) .
插件上下文
插件会曝光 ctx.plugins.slack 采用这些方法:
send(opts)
向任何频道发送消息 .
await ctx.plugins.slack.send({
channel: "general",
text: "Hello from Flink!",
threadTs: "1234567890.123456", // optional: reply in thread
blocks: [], // optional: Block Kit blocks
});
reply(message, text, opts?)
回复一个信息。 如果信件已经包含在内, 则继续线程, 否则将启动新线程 .
await slack.reply(message, "Got it!");
getThread(message)
在线索中获取所有信件 .
const thread = await slack.getThread(message);
// thread.messages: SlackThreadMessage[]
getChannelHistory(opts)
从频道获取最近的消息 .
const history = await slack.getChannelHistory({
channelId: message.channelId,
limit: 10,
});
withConnection(id)
将范围上下文绑定到特定连接上. 用于从工作或HTTP处理器中主动发送.
const acmeSlack = ctx.plugins.slack.withConnection("acme");
await acmeSlack.send({ channel: "general", text: "Hello!" });
addConnection(id, connection)
运行时添加新连接 .
await ctx.plugins.slack.addConnection("acme", {
mode: "socket",
token: "xoxb-...",
appToken: "xapp-...",
signingSecret: "...",
});
removeConnection(id)
停止并删除连接 .
await ctx.plugins.slack.removeConnection("acme");
listConnections()
列出活动连接ID.
const ids = ctx.plugins.slack.listConnections(); // ["default", "acme"]
sendFile(opts)
上传文件到频道或线索中.
await ctx.plugins.slack.sendFile({
channel: message.channelId,
file: Buffer.from("hello world"),
filename: "hello.txt",
title: "My File", // optional
initialComment: "Here you go", // optional: message alongside the file
threadTs: message.threadTs, // optional: upload into thread
});
downloadFile(file)
下载附在信件上的文件 。 由于 Slack 文件 URL 是私有的,所以使用bot 令牌进行认证.
if (message.files?.length) {
const content = await slack.downloadFile(message.files[0]);
// content is a Buffer
}
react(message, emoji)
在消息中加入一个emoji反应.
await slack.react(message, "thumbsup");
client
原始内容 @slack/web-api WebClient 以援助者所不能负担的事物发誓, 返回默认连接的客户端 .
await ctx.plugins.slack.client.reactions.add({
channel: message.channelId,
timestamp: message.ts,
name: "thumbsup",
});
连接模式
套接字模式(建议开发)
不需要公开 URL 。 使用WebSocket通过一个应用级符号.
connection: {
mode: "socket",
token: "xoxb-...",
appToken: "xapp-...",
signingSecret: "...",
}
HTTP 模式
通过HTTP接收事件. 需要在您的 Slack 应用程序中配置一个可公开访问的 URL .
connection: {
mode: "http",
token: "xoxb-...",
signingSecret: "...",
port: 3100, // default
}
插件选项
| 选项 | 类型 | 默认 | 说明 |
|---|---|---|---|
connection | SlackConnectionOptions | —— 说 | 单一连接( 存储于 "default") (中文(简体) ). |
connections | Record<string, SlackConnectionOptions> | —— 说 | 启动时多个命名连接 . |
loadConnections | (ctx) => Promise<Record<string, SlackConnectionOptions>> | —— 说 | 在输入时动态地装入连接( 例如从数据库) . |
stripMention | boolean | true | 删除 <@BOTID> 文本中的前缀. |
resolveUser | (msg, ctx) => Promise<any> | —— 说 | 从 Slack 消息中解析应用程序用户 . |
resolvePermissions | (user, ctx) => Promise<string[]> | —— 说 | 解析已解决的用户权限 . |
onUnhandled | (msg, ctx) => Promise<void> | —— 说 | 没有处理器匹配时调用 . |
你用得着 connection, (中文(简体) ), connections, (中文(简体) ), loadConnections,或者任何组合。 所有这些都是可选的——你可以从零连接开始,并在运行时动态地添加.
多十年/ 动态连接
对于每个租户连接自己Slack工作空间的SaaS应用程序,插件支持多个并发连接. 手持者同样工作—— slack 参数自动被扩展到收到消息的连接.
启动时多个连接
slackPlugin<AppCtx>({
connections: {
acme: {
mode: "socket",
token: process.env.ACME_SLACK_TOKEN!,
appToken: process.env.ACME_SLACK_APP_TOKEN!,
signingSecret: process.env.ACME_SIGNING_SECRET!,
},
beta: {
mode: "socket",
token: process.env.BETA_SLACK_TOKEN!,
appToken: process.env.BETA_SLACK_APP_TOKEN!,
signingSecret: process.env.BETA_SIGNING_SECRET!,
},
},
});
从数据库装入连接
slackPlugin<AppCtx>({
loadConnections: async (ctx) => {
const tenants = await ctx.repos.tenantRepo.findAll({ slackEnabled: true });
return Object.fromEntries(
tenants.map(t => [t.id, {
mode: "socket" as const,
token: t.slackToken,
appToken: t.slackAppToken,
signingSecret: t.signingSecret,
}])
);
},
});
运行时添加/ 重新移动连接
// Add a new tenant's Slack connection
await ctx.plugins.slack.addConnection("acme", {
mode: "socket",
token: "xoxb-...",
appToken: "xapp-...",
signingSecret: "...",
});
// Remove it
await ctx.plugins.slack.removeConnection("acme");
// List active connections
const ids = ctx.plugins.slack.listConnections(); // ["acme", "beta"]
主动发送到特定连接
从工作, HTTP 处理器, 或访问插件上下文的任何地方 :
await ctx.plugins.slack.withConnection("acme").send({
channel: "general",
text: "Hello from Flink!",
});
通过连接过滤路径
Handlers 可以声明他们收听的连接 :
export const Route: SlackRouteProps = {
isMention: true,
connectionId: "acme", // only this connection
// connectionId: ["acme", "beta"], // specific set
// omit connectionId → listen on ALL connections (default)
};
在处理器中访问连接信息
每个 SlackMessage 包含a connectionId 字段识别接收到的连接 :
const handler: SlackHandler<AppCtx> = async ({ message, slack }) => {
console.log(`Message from connection: ${message.connectionId}`);
await slack.reply(message, "Got it!"); // uses the correct connection automatically
};
国 际
从命令行发送测试消息 :
flink-slack send --token xoxb-... --channel general "Hello from CLI"
或使用环境变量:
export SLACK_BOT_TOKEN=xoxb-...
flink-slack send --channel general "Hello from CLI"
Slack 应用程序设置
创建 Slack 应用程序 api.slack.com/应用程序 并配置以下内容。 见 偷懒 Bolt 正在获取指南 详细通过.
1. 瓶子范围
下 授权和权限 − 范围,添加:
| 范围 | 目的 |
|---|---|
chat:write | 发送信件 |
files:read | 从信件下载文件 |
files:write | 上传文件 |
reactions:write | 添加情感反应 |
channels:history | 读取频道消息 |
groups:history | 读取私有频道消息 |
im:history | 读取模式 |
mpim:history | 读取组 |
2. 活动订阅
下 事件订阅 – 订阅机器人事件,添加:
message.channels——频道消息message.groups——私人频道消息message.im——模式app_mention— @ mentions (英语)
3. 套接字模式(建议)
下 设置 ~ 套接字模式,将它切入并生成一个 app 级 符号 connections:write 范围。 这给你 xapp-... 用于 appToken 配置场. 不需要公开的 URL .
见 黑袜子模式文件 详细情况.
4. 安装到工作空间
下 安装 App,单击 安装到工作区复制 Bot 用户 OAuth 托肯 (单位:千美元)xoxb-...)和 签名保密 (从) 基本情况) (中文(简体) ).
多租户设置
对于多租户应用软件,每个租户都会通过Slack应用程序安装到自己的工作空间 OAuth v2 (英语). OAuth 流量完成后,存储每个租户的 token, (中文(简体) ), appToken,以及 signingSecret,然后调用 addConnection() 开始接收消息。 见 黑发应用指南 {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}为OAuth的全流.