feat: add Feishu notifier for message notifications
- Implemented a lightweight notification library with support for multiple channels. - Added FeishuNotifier class to send messages via Feishu webhook. - Created README documentation for usage and configuration of Feishu notifier. - Added TypeScript configuration for the project. - Included a test script for verifying Feishu message notifications.
This commit is contained in:
56
.cnb.yml
Normal file
56
.cnb.yml
Normal file
@@ -0,0 +1,56 @@
|
||||
# # .cnb.yml
|
||||
# $:
|
||||
# vscode:
|
||||
# - docker:
|
||||
# image: docker.cnb.cool/kevisual/dev-env:latest
|
||||
# services:
|
||||
# - vscode
|
||||
# - docker
|
||||
# imports: https://cnb.cool/kevisual/env/-/blob/main/env.yml
|
||||
# # 开发环境启动后会执行的任务
|
||||
# # stages:
|
||||
# # - name: pnpm install
|
||||
# # script: pnpm install
|
||||
|
||||
|
||||
# main:
|
||||
# web_trigger_sync_to_gitea:
|
||||
# - services:
|
||||
# - docker
|
||||
# imports:
|
||||
# - https://cnb.cool/kevisual/env/-/blob/main/env.yml
|
||||
# stages:
|
||||
# - name: 'show username'
|
||||
# script: echo "GITEA_USERNAME is ${GITEA_USERNAME} and GITEA_PASSWORD is ${GITEA_PASSWORD}"
|
||||
# - name: sync to gitea
|
||||
# image: tencentcom/git-sync
|
||||
# settings:
|
||||
# target_url: https://git.xiongxiao.me/template/simple-bun.git
|
||||
# auth_type: https
|
||||
# username: "oauth2"
|
||||
# password: ${GITEA_TOKEN}
|
||||
# git_user: "abearxiong"
|
||||
# git_email: "xiongxiao@xiongxiao.me"
|
||||
# sync_mode: rebase
|
||||
# branch: main
|
||||
# web_trigger_sync_from_gitea:
|
||||
# - services:
|
||||
# - docker
|
||||
# imports:
|
||||
# - https://cnb.cool/kevisual/env/-/blob/main/env.yml
|
||||
# stages:
|
||||
# - name: '添加 gitea的origin'
|
||||
# script: |
|
||||
# git remote remove gitea 2>/dev/null || true
|
||||
# git remote add gitea https://oauth2:${GITEA_TOKEN}@git.xiongxiao.me/template/simple-bun.git
|
||||
# - name: '同步gitea代码到当前仓库'
|
||||
# script: git pull gitea main
|
||||
# - name: '提交到原本的origin'
|
||||
# script: git push origin main
|
||||
|
||||
|
||||
# "**":
|
||||
# web_trigger_test:
|
||||
# - stages:
|
||||
# - name: 执行任务
|
||||
# script: echo "job"
|
||||
11
.cnb/web_trigger.yml
Normal file
11
.cnb/web_trigger.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
# .cnb/web_trigger.yml
|
||||
branch:
|
||||
# 如下按钮在分支名以 release 开头的分支详情页面显示
|
||||
- reg: "^main"
|
||||
buttons:
|
||||
- name: 同步代码到gitea
|
||||
desc: 同步代码到gitea
|
||||
event: web_trigger_sync_to_gitea
|
||||
- name: 同步gitea代码到当前仓库
|
||||
desc: 同步gitea代码到当前仓库
|
||||
event: web_trigger_sync_from_gitea
|
||||
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
.env
|
||||
!.env*development
|
||||
|
||||
node_modules
|
||||
|
||||
dist
|
||||
pack-dist
|
||||
|
||||
.DS_Store
|
||||
|
||||
.pnpm-store
|
||||
|
||||
.vite
|
||||
|
||||
.astro
|
||||
2
.npmrc
Normal file
2
.npmrc
Normal file
@@ -0,0 +1,2 @@
|
||||
//npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN}
|
||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||
17
bun.config.ts
Normal file
17
bun.config.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
// @ts-check
|
||||
import { resolvePath } from '@kevisual/use-config';
|
||||
import { execSync } from 'node:child_process';
|
||||
|
||||
const entry = 'src/index.ts';
|
||||
const naming = 'app';
|
||||
const external = ['pm2'];
|
||||
await Bun.build({
|
||||
target: 'node',
|
||||
format: 'esm',
|
||||
entrypoints: [resolvePath(entry, { meta: import.meta })],
|
||||
outdir: resolvePath('./dist', { meta: import.meta }),
|
||||
naming: {
|
||||
entry: `${naming}.js`,
|
||||
},
|
||||
external,
|
||||
});
|
||||
22
kevisual.json
Normal file
22
kevisual.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"metadata": {
|
||||
"name": "kevisual",
|
||||
"share": "public"
|
||||
},
|
||||
"registry": "https://kevisual.cn/root/ai/kevisual/backend/simple-bun",
|
||||
"clone": {
|
||||
".": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"syncd": [
|
||||
{
|
||||
"files": [
|
||||
"**/*"
|
||||
],
|
||||
"registry": ""
|
||||
}
|
||||
],
|
||||
"sync": {
|
||||
}
|
||||
}
|
||||
47
package.json
Normal file
47
package.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "@kevisual/notifier",
|
||||
"version": "0.0.2",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"basename": "/root/notifier",
|
||||
"app": {
|
||||
"type": "system-app",
|
||||
"entry": "app.js",
|
||||
"runtime": [
|
||||
"server"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "bun --watch src/main.ts ",
|
||||
"build": "pnpm run clean && bun run bun.config.mjs",
|
||||
"postbuild": "ev pack",
|
||||
"compile": "bun build --compile ./src/main.ts --outfile router-template",
|
||||
"compile:win": "bun build --compile ./src/main.ts --target=bun-windows-x64 --outfile router-template.exe",
|
||||
"clean": "rm -rf dist && rimraf pack-dist",
|
||||
"pub": "envision pack -p -u"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"src"
|
||||
],
|
||||
"keywords": [],
|
||||
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
||||
"license": "MIT",
|
||||
"packageManager": "pnpm@10.27.0",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"dayjs": "^1.11.19",
|
||||
"es-toolkit": "^1.43.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@kevisual/types": "^0.0.10",
|
||||
"@types/bun": "^1.3.5",
|
||||
"@types/node": "^25.0.3"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
}
|
||||
}
|
||||
1102
pnpm-lock.yaml
generated
Normal file
1102
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
32
readme.md
Normal file
32
readme.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# @kevisual/notifier
|
||||
|
||||
一个轻量级的消息通知库,支持多种推送渠道。
|
||||
|
||||
## 支持的推送渠道
|
||||
|
||||
### 飞书 (Feishu)
|
||||
|
||||
通过 Webhook 将消息推送到飞书群机器人。
|
||||
|
||||
#### 配置
|
||||
|
||||
```typescript
|
||||
import { FeishuNotifier } from '@kevisual/notifier';
|
||||
|
||||
const feishu = new FeishuNotifier({
|
||||
webhook: 'https://open.feishu.cn/open-apis/bot/v2/hook/xxx',
|
||||
});
|
||||
```
|
||||
|
||||
#### 使用
|
||||
|
||||
```typescript
|
||||
await feishu.notify('这是一条测试消息');
|
||||
```
|
||||
|
||||
#### 创建飞书群机器人 Webhook
|
||||
|
||||
1. 打开飞书群设置,点击「群机器人」
|
||||
2. 添加「自定义机器人」
|
||||
3. 复制 Webhook URL
|
||||
4. (可选) 设置安全策略:签名校验或 IP 白名单
|
||||
3
src/core/index.ts
Normal file
3
src/core/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export interface Notification {
|
||||
notify(message: string): void;
|
||||
}
|
||||
1
src/index.ts
Normal file
1
src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './notiify/feishu.ts'
|
||||
34
src/notiify/feishu.ts
Normal file
34
src/notiify/feishu.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Notification } from '../core/index.ts';
|
||||
|
||||
interface FeishuConfig {
|
||||
webhook: string;
|
||||
}
|
||||
|
||||
export class FeishuNotifier implements Notification {
|
||||
private webhook: string;
|
||||
|
||||
constructor(config: FeishuConfig) {
|
||||
this.webhook = config.webhook;
|
||||
}
|
||||
|
||||
async notify(message: string): Promise<void> {
|
||||
const payload = {
|
||||
msg_type: 'text',
|
||||
content: {
|
||||
text: message,
|
||||
},
|
||||
};
|
||||
|
||||
const response = await fetch(this.webhook, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`飞书推送失败: ${response.statusText}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
8
test/feishu.ts
Normal file
8
test/feishu.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { FeishuNotifier } from '../src/notiify/feishu.ts';
|
||||
|
||||
const webhook = 'https://open.feishu.cn/open-apis/bot/v2/hook/c1c32e36-ddc6-4965-8943-fc826f4f5060';
|
||||
|
||||
const feishu = new FeishuNotifier({ webhook });
|
||||
|
||||
await feishu.notify('测试飞书推送消息');
|
||||
console.log('推送成功');
|
||||
24
tsconfig.json
Normal file
24
tsconfig.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"extends": "@kevisual/types/json/backend.json",
|
||||
"compilerOptions": {
|
||||
"module": "NodeNext",
|
||||
"target": "esnext",
|
||||
"baseUrl": ".",
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
"./node_modules/@kevisual/types/index.d.ts"
|
||||
],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
],
|
||||
"@agent/*": [
|
||||
"agent/*"
|
||||
]
|
||||
},
|
||||
},
|
||||
"include": [
|
||||
"src/**/*",
|
||||
"agent/**/*",
|
||||
],
|
||||
}
|
||||
Reference in New Issue
Block a user