@zhin.js/adapter-milky 1.0.1 → 1.1.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/CHANGELOG.md +962 -0
- package/README.md +58 -117
- package/adapters/milky.js +51 -0
- package/adapters/milky.ts +74 -0
- package/{skills/milky → agent}/PERMITS.md +2 -2
- package/commands/endpoint/add/[id].js +3 -0
- package/commands/endpoint/add/[id].ts +3 -0
- package/commands/endpoint/list.js +3 -0
- package/commands/endpoint/list.ts +3 -0
- package/commands/endpoint/remove/[id].js +3 -0
- package/commands/endpoint/remove/[id].ts +3 -0
- package/lib/client.d.ts +21 -0
- package/lib/client.js +33 -0
- package/lib/endpoint-management.d.ts +17 -0
- package/lib/endpoint-management.js +47 -0
- package/lib/endpoint.d.ts +7 -0
- package/lib/endpoint.js +6 -0
- package/lib/index.d.ts +6 -20
- package/lib/index.js +4 -35
- package/lib/milky-auth.d.ts +2 -0
- package/lib/milky-auth.js +16 -0
- package/lib/milky-endpoint-commands.d.ts +1 -0
- package/lib/milky-endpoint-commands.js +18 -0
- package/lib/milky-runtime-state.d.ts +1 -0
- package/lib/milky-runtime-state.js +6 -0
- package/lib/protocol.d.ts +174 -0
- package/lib/protocol.js +494 -0
- package/lib/sse-client.d.ts +20 -0
- package/lib/sse-client.js +85 -0
- package/lib/sse-endpoint.d.ts +32 -0
- package/lib/sse-endpoint.js +207 -0
- package/lib/webhook-endpoint.d.ts +22 -0
- package/lib/webhook-endpoint.js +149 -0
- package/lib/ws-endpoint.d.ts +23 -0
- package/lib/ws-endpoint.js +233 -0
- package/lib/ws-types.d.ts +11 -0
- package/lib/ws-types.js +1 -0
- package/lib/wss-endpoint.d.ts +25 -0
- package/lib/wss-endpoint.js +184 -0
- package/package.json +73 -20
- package/plugin.js +14 -0
- package/schema.json +100 -0
- package/src/client.ts +80 -0
- package/src/endpoint-management.ts +74 -0
- package/src/endpoint.ts +26 -0
- package/src/index.ts +63 -47
- package/src/milky-auth.ts +14 -0
- package/src/milky-endpoint-commands.ts +19 -0
- package/src/milky-runtime-state.ts +7 -0
- package/src/protocol.ts +647 -0
- package/src/sse-client.ts +106 -0
- package/src/sse-endpoint.ts +258 -0
- package/src/webhook-endpoint.ts +196 -0
- package/src/ws-endpoint.ts +291 -0
- package/src/ws-types.ts +12 -0
- package/src/wss-endpoint.ts +228 -0
- package/lib/adapter.d.ts +0 -29
- package/lib/adapter.d.ts.map +0 -1
- package/lib/adapter.js +0 -91
- package/lib/adapter.js.map +0 -1
- package/lib/api.d.ts +0 -10
- package/lib/api.d.ts.map +0 -1
- package/lib/api.js +0 -48
- package/lib/api.js.map +0 -1
- package/lib/endpoint-sse.d.ts +0 -31
- package/lib/endpoint-sse.d.ts.map +0 -1
- package/lib/endpoint-sse.js +0 -195
- package/lib/endpoint-sse.js.map +0 -1
- package/lib/endpoint-webhook.d.ts +0 -34
- package/lib/endpoint-webhook.d.ts.map +0 -1
- package/lib/endpoint-webhook.js +0 -187
- package/lib/endpoint-webhook.js.map +0 -1
- package/lib/endpoint-ws.d.ts +0 -35
- package/lib/endpoint-ws.d.ts.map +0 -1
- package/lib/endpoint-ws.js +0 -262
- package/lib/endpoint-ws.js.map +0 -1
- package/lib/endpoint-wss.d.ts +0 -34
- package/lib/endpoint-wss.d.ts.map +0 -1
- package/lib/endpoint-wss.js +0 -225
- package/lib/endpoint-wss.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/types.d.ts +0 -75
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js +0 -5
- package/lib/types.js.map +0 -1
- package/lib/utils.d.ts +0 -35
- package/lib/utils.d.ts.map +0 -1
- package/lib/utils.js +0 -165
- package/lib/utils.js.map +0 -1
- package/plugin.yml +0 -3
- package/src/adapter.ts +0 -103
- package/src/api.ts +0 -63
- package/src/endpoint-sse.ts +0 -228
- package/src/endpoint-webhook.ts +0 -221
- package/src/endpoint-ws.ts +0 -296
- package/src/endpoint-wss.ts +0 -268
- package/src/types.ts +0 -73
- package/src/utils.ts +0 -181
- /package/{skills/milky/SKILL.md → agent/skills/milky.md} +0 -0
package/README.md
CHANGED
|
@@ -1,158 +1,99 @@
|
|
|
1
1
|
# @zhin.js/adapter-milky
|
|
2
2
|
|
|
3
|
-
Zhin.js [Milky](https://milky.ntqqrev.org/)
|
|
3
|
+
Zhin.js [Milky](https://milky.ntqqrev.org/) 协议适配器(Plugin Runtime)。默认 **正向 WebSocket 客户端**(`connection: ws`);亦支持 **Webhook**、**反向 WS**(经 `httpHostToken`)与 **SSE**(HTTP GET `/event`,fetch 解析 `text/event-stream`)。
|
|
4
4
|
|
|
5
5
|
## 功能特性
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
- 🔄 **WebSocket 反向**(`connection: wss`):应用开 WS 服务端,协议端来连
|
|
13
|
-
- 🔐 `access_token` 鉴权(Header 或 query)
|
|
14
|
-
- 📨 群聊 / 私聊消息收发与消息段映射
|
|
15
|
-
- 🛠️ HTTP API 封装,供发消息、撤回、群管等复用
|
|
7
|
+
- [Milky 协议](https://milky.ntqqrev.org/guide/communication) 兼容(事件 + HTTP API)
|
|
8
|
+
- 约定式 `defineAdapter` / `definePlugin`(无需 `usePlugin`)
|
|
9
|
+
- **正向 WebSocket**(`connection: ws`):应用连协议端 `ws(s)://baseUrl/event`
|
|
10
|
+
- `access_token` 鉴权(Bearer + query)
|
|
11
|
+
- 入站经 `Endpoint.emit(...)`;出站 `send({ conversation, payload })` → HTTP `send_*_message`
|
|
16
12
|
|
|
17
13
|
## 安装
|
|
18
14
|
|
|
19
15
|
```bash
|
|
20
|
-
pnpm add @zhin.js/adapter-milky
|
|
16
|
+
pnpm add @zhin.js/adapter-milky
|
|
21
17
|
```
|
|
22
18
|
|
|
23
|
-
|
|
19
|
+
## Plugin Runtime
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
- `@zhin.js/adapter` — 约定式 `adapters/milky.ts`(`defineAdapter`)
|
|
22
|
+
- `@zhin.js/core` — `Endpoint.emit(...)` 入站、`outboundMessageToken` 出站
|
|
23
|
+
- `zhin.js` — `plugin.ts`(`definePlugin`)
|
|
24
|
+
- 配置经插件 `schema.json` 落到 `plugins.<instanceKey>`
|
|
25
|
+
|
|
26
|
+
入站:`gateway.receive({ conversation: ConversationRef(kind: "private"|"group", id), message, content, sender, metadata })`
|
|
27
|
+
出站:`send({ conversation, payload })` → HTTP `send_private_message` / `send_group_message`(payload 已由 gateway/core 渲染;无 segment-mapper)
|
|
28
|
+
|
|
29
|
+
每个 Endpoint 的 `$client` 是 `@imhelper/milky-v1` 的 `MilkyV1Client`。插件可直接调用
|
|
30
|
+
`$client.call()`、`getGroupList()` 等公开能力;`defineHandler({ adapter: 'milky', event: ... })`
|
|
31
|
+
使用 imhelper 的精确事件名与 payload 类型。HTTP、纯事件 WS/WSS 和 `ingest()` 都汇入同一个
|
|
32
|
+
Client 事件流,Endpoint 仍独占账号连接、鉴权、重连和心跳。
|
|
28
33
|
|
|
29
|
-
##
|
|
34
|
+
## 前置条件
|
|
30
35
|
|
|
31
|
-
|
|
36
|
+
1. 启动兼容 Milky 的实现,并记录 HTTP API 与事件连接地址。
|
|
37
|
+
2. 正向 WS/SSE 需 Zhin 主动可达实现端;Webhook/反向 WS 需实现端可达 Zhin HTTP Host。
|
|
38
|
+
3. 两端配置相同的 `access_token`,生产环境不要暴露无鉴权接口。
|
|
32
39
|
|
|
33
|
-
|
|
40
|
+
## 最小配置
|
|
34
41
|
|
|
35
42
|
```yaml
|
|
43
|
+
# zhin.config.yml(Plugin Runtime)
|
|
36
44
|
plugins:
|
|
37
|
-
|
|
38
|
-
- "@zhin.js/adapter-milky"
|
|
39
|
-
|
|
40
|
-
endpoints:
|
|
41
|
-
- context: milky
|
|
45
|
+
milky:
|
|
42
46
|
connection: ws
|
|
43
|
-
name: milky-bot
|
|
44
|
-
baseUrl: "http://127.0.0.1:8080"
|
|
45
|
-
access_token: "${MILKY_ACCESS_TOKEN}"
|
|
46
47
|
reconnect_interval: 5000
|
|
47
48
|
heartbeat_interval: 30000
|
|
49
|
+
endpoints:
|
|
50
|
+
- name: milky-bot
|
|
51
|
+
baseUrl: "http://127.0.0.1:8080"
|
|
52
|
+
access_token: "${MILKY_ACCESS_TOKEN}"
|
|
48
53
|
```
|
|
49
54
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
```yaml
|
|
53
|
-
endpoints:
|
|
54
|
-
- context: milky
|
|
55
|
-
connection: sse
|
|
56
|
-
name: milky-sse-bot
|
|
57
|
-
baseUrl: "http://127.0.0.1:8080"
|
|
58
|
-
access_token: "${MILKY_ACCESS_TOKEN}"
|
|
59
|
-
```
|
|
55
|
+
根插件 `zhin.plugins`(或项目图)需引用 `@zhin.js/adapter-milky`(`instanceKey: milky`)。
|
|
60
56
|
|
|
61
|
-
|
|
57
|
+
## 连接方式
|
|
62
58
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
path: "/milky/webhook" # 应用接收事件的 POST 路径
|
|
70
|
-
access_token: "${MILKY_ACCESS_TOKEN}"
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### WebSocket 反向
|
|
74
|
-
|
|
75
|
-
```yaml
|
|
76
|
-
endpoints:
|
|
77
|
-
- context: milky
|
|
78
|
-
connection: wss
|
|
79
|
-
name: milky-wss-bot
|
|
80
|
-
baseUrl: "http://协议端地址"
|
|
81
|
-
path: "/milky/event" # 应用 WS 服务端路径
|
|
82
|
-
access_token: "${MILKY_ACCESS_TOKEN}"
|
|
83
|
-
heartbeat_interval: 30000
|
|
84
|
-
```
|
|
59
|
+
| connection | 状态 |
|
|
60
|
+
|------------|------|
|
|
61
|
+
| `ws` | 已实现(推荐) |
|
|
62
|
+
| `sse` | HTTP GET `/event`(`Accept: text/event-stream`) |
|
|
63
|
+
| `webhook` | 已实现:POST 入站 + baseUrl HTTP API 出站 |
|
|
64
|
+
| `wss` | 已实现:反向 WS(httpHostToken) |
|
|
85
65
|
|
|
86
66
|
## 鉴权
|
|
87
67
|
|
|
88
|
-
|
|
68
|
+
- **Bearer**:`Authorization: Bearer <access_token>`
|
|
69
|
+
- 正向 WS 在 Upgrade 时附带请求头,并在 URL query 写入 `access_token`
|
|
70
|
+
- HTTP API 同样使用 Header / query 鉴权
|
|
89
71
|
|
|
90
|
-
|
|
91
|
-
- **Query**:`access_token=xxx`
|
|
72
|
+
## 消息 ID
|
|
92
73
|
|
|
93
|
-
|
|
74
|
+
`{message_scene}:{peer_id}:{message_seq}`(如 `group:123456:10001`)。
|
|
94
75
|
|
|
95
|
-
##
|
|
76
|
+
## AI 工具
|
|
96
77
|
|
|
97
|
-
|
|
|
98
|
-
|
|
99
|
-
| `
|
|
100
|
-
|
|
|
101
|
-
| `webhook` | 协议端 POST 到应用配置的 path |
|
|
102
|
-
| `wss` | 协议端连应用提供的 WS path |
|
|
78
|
+
| 类别 | 路径 |
|
|
79
|
+
|------|------|
|
|
80
|
+
| Permit 词汇 | `agent/PERMITS.md` |
|
|
81
|
+
| 技能说明 | `agent/skills/milky.md` |
|
|
103
82
|
|
|
104
|
-
##
|
|
105
|
-
|
|
106
|
-
### 消息处理
|
|
107
|
-
|
|
108
|
-
```typescript
|
|
109
|
-
import { addCommand, MessageCommand } from 'zhin.js'
|
|
110
|
-
|
|
111
|
-
addCommand(new MessageCommand('hello <name:text>')
|
|
112
|
-
.action(async (message, result) => {
|
|
113
|
-
return `你好,${result.params.name}!`
|
|
114
|
-
})
|
|
115
|
-
)
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
### 发送消息段
|
|
119
|
-
|
|
120
|
-
```typescript
|
|
121
|
-
addCommand(new MessageCommand('pic')
|
|
122
|
-
.action(async () => {
|
|
123
|
-
return [
|
|
124
|
-
{ type: 'text', data: { text: '图片:' } },
|
|
125
|
-
{ type: 'image', data: { url: 'https://example.com/img.png' } }
|
|
126
|
-
]
|
|
127
|
-
})
|
|
128
|
-
)
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
发消息、撤回、群管等通过适配器封装的 HTTP API 完成。群管能力通过 `IGroupManagement` 自动注册为工具,详见 [工具与技能](/advanced/tools-skills)。
|
|
132
|
-
|
|
133
|
-
## 消息 ID 格式
|
|
134
|
-
|
|
135
|
-
`{message_scene}:{peer_id}:{message_seq}`(如 `group:123456:10001`)。撤回时使用该 ID。
|
|
136
|
-
|
|
137
|
-
## 协议与 API 参考
|
|
83
|
+
## 文档链接
|
|
138
84
|
|
|
139
85
|
- [Milky 快速开始](https://milky.ntqqrev.org/)
|
|
140
86
|
- [Milky 通信](https://milky.ntqqrev.org/guide/communication)
|
|
141
|
-
- [
|
|
142
|
-
|
|
143
|
-
## 依赖项
|
|
87
|
+
- [适配器概览](https://zhin.js.org/essentials/adapters)
|
|
144
88
|
|
|
145
|
-
|
|
146
|
-
- `eventsource` - SSE 客户端
|
|
147
|
-
- `zhin.js` - Zhin 核心
|
|
148
|
-
- `@zhin.js/host-router` - 提供 router,适配器注册依赖
|
|
89
|
+
## 故障排查
|
|
149
90
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
91
|
+
| 现象 | 排查 |
|
|
92
|
+
| --- | --- |
|
|
93
|
+
| WS/SSE 无事件 | 核对 `baseUrl`、连接模式与实现端事件服务 |
|
|
94
|
+
| 401 或握手失败 | 确认 Bearer/query 中的 `access_token` 与实现端一致 |
|
|
95
|
+
| Webhook/WSS 无法连接 | 检查 HTTP Host、网络可达性与回调路径 |
|
|
96
|
+
| 能收不能发 | 检查 HTTP API 与发送动作支持情况 |
|
|
156
97
|
|
|
157
98
|
## 许可证
|
|
158
99
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
/**
|
|
3
|
+
* Convention entry: discover `adapters/milky.ts` → defineAdapter.
|
|
4
|
+
*/
|
|
5
|
+
import { defineAdapter } from 'zhin.js/adapter';
|
|
6
|
+
import { httpHostToken } from '@zhin.js/host-http';
|
|
7
|
+
import { MilkySseEndpoint, MilkyWebhookEndpoint, MilkyWssEndpoint, MilkyWsEndpoint, } from "../lib/endpoint.js";
|
|
8
|
+
import { resolveMilkyConfig, } from "../lib/protocol.js";
|
|
9
|
+
import { milkyRuntimeStateToken } from "../lib/milky-runtime-state.js";
|
|
10
|
+
export { MilkySseEndpoint, MilkyWebhookEndpoint, MilkyWssEndpoint, MilkyWsEndpoint, } from "../lib/endpoint.js";
|
|
11
|
+
export default defineAdapter({
|
|
12
|
+
capabilities: ['inbound', 'outbound'],
|
|
13
|
+
operations: ['recall'],
|
|
14
|
+
// Milky 协议资源 uri 消费 http(s):// 与 base64:// 形式;无卡片交互面,交互段降级纯文本。
|
|
15
|
+
segments: {
|
|
16
|
+
outboundMedia: ['url', 'base64'],
|
|
17
|
+
interactive: 'text',
|
|
18
|
+
},
|
|
19
|
+
create(context) {
|
|
20
|
+
const config = resolveMilkyConfig(context.config);
|
|
21
|
+
// 注册到插件运行时状态(milky.endpoint list 的"运行中"数据源)
|
|
22
|
+
context.use(milkyRuntimeStateToken).endpoints.set(config.id, {
|
|
23
|
+
id: config.id,
|
|
24
|
+
mode: config.connection,
|
|
25
|
+
});
|
|
26
|
+
if (config.connection === 'webhook') {
|
|
27
|
+
return new MilkyWebhookEndpoint({
|
|
28
|
+
id: context.id,
|
|
29
|
+
http: context.use(httpHostToken),
|
|
30
|
+
config,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
if (config.connection === 'wss') {
|
|
34
|
+
return new MilkyWssEndpoint({
|
|
35
|
+
id: context.id,
|
|
36
|
+
http: context.use(httpHostToken),
|
|
37
|
+
config,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
if (config.connection === 'sse') {
|
|
41
|
+
return new MilkySseEndpoint({
|
|
42
|
+
id: context.id,
|
|
43
|
+
config,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return new MilkyWsEndpoint({
|
|
47
|
+
id: context.id,
|
|
48
|
+
config,
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convention entry: discover `adapters/milky.ts` → defineAdapter.
|
|
3
|
+
*/
|
|
4
|
+
import { defineAdapter } from 'zhin.js/adapter';
|
|
5
|
+
import { httpHostToken } from '@zhin.js/host-http';
|
|
6
|
+
import {
|
|
7
|
+
MilkySseEndpoint,
|
|
8
|
+
MilkyWebhookEndpoint,
|
|
9
|
+
MilkyWssEndpoint,
|
|
10
|
+
MilkyWsEndpoint,
|
|
11
|
+
} from '../src/endpoint.js';
|
|
12
|
+
import {
|
|
13
|
+
resolveMilkyConfig,
|
|
14
|
+
type MilkyAdapterConfig,
|
|
15
|
+
} from '../src/protocol.js';
|
|
16
|
+
import { milkyRuntimeStateToken } from '../src/milky-runtime-state.js';
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
MilkySseEndpoint,
|
|
20
|
+
MilkyWebhookEndpoint,
|
|
21
|
+
MilkyWssEndpoint,
|
|
22
|
+
MilkyWsEndpoint,
|
|
23
|
+
} from '../src/endpoint.js';
|
|
24
|
+
export type {
|
|
25
|
+
CreateMilkySseStream,
|
|
26
|
+
MilkySseEndpointOptions,
|
|
27
|
+
MilkyWebhookEndpointOptions,
|
|
28
|
+
MilkyWssEndpointOptions,
|
|
29
|
+
MilkyWsEndpointOptions,
|
|
30
|
+
MilkyWsCreateOptions,
|
|
31
|
+
MilkyWsSocket,
|
|
32
|
+
} from '../src/endpoint.js';
|
|
33
|
+
|
|
34
|
+
export default defineAdapter<MilkyAdapterConfig>({
|
|
35
|
+
capabilities: ['inbound', 'outbound'],
|
|
36
|
+
operations: ['recall'],
|
|
37
|
+
// Milky 协议资源 uri 消费 http(s):// 与 base64:// 形式;无卡片交互面,交互段降级纯文本。
|
|
38
|
+
segments: {
|
|
39
|
+
outboundMedia: ['url', 'base64'],
|
|
40
|
+
interactive: 'text',
|
|
41
|
+
},
|
|
42
|
+
create(context) {
|
|
43
|
+
const config = resolveMilkyConfig(context.config);
|
|
44
|
+
// 注册到插件运行时状态(milky.endpoint list 的"运行中"数据源)
|
|
45
|
+
context.use(milkyRuntimeStateToken).endpoints.set(config.id, {
|
|
46
|
+
id: config.id,
|
|
47
|
+
mode: config.connection,
|
|
48
|
+
});
|
|
49
|
+
if (config.connection === 'webhook') {
|
|
50
|
+
return new MilkyWebhookEndpoint({
|
|
51
|
+
id: context.id,
|
|
52
|
+
http: context.use(httpHostToken),
|
|
53
|
+
config,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
if (config.connection === 'wss') {
|
|
57
|
+
return new MilkyWssEndpoint({
|
|
58
|
+
id: context.id,
|
|
59
|
+
http: context.use(httpHostToken),
|
|
60
|
+
config,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
if (config.connection === 'sse') {
|
|
64
|
+
return new MilkySseEndpoint({
|
|
65
|
+
id: context.id,
|
|
66
|
+
config,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return new MilkyWsEndpoint({
|
|
70
|
+
id: context.id,
|
|
71
|
+
config,
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
});
|
package/lib/client.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { MilkyV1Client, type MilkyV1Event } from '@imhelper/milky-v1';
|
|
2
|
+
import { type EventMap, type ImHelperEventMap } from 'imhelper';
|
|
3
|
+
import { type ClientEventPayloads } from 'zhin.js/adapter';
|
|
4
|
+
import type { ResolvedMilkyConfig, callApi } from './protocol.js';
|
|
5
|
+
export { MilkyV1Client as MilkyClient } from '@imhelper/milky-v1';
|
|
6
|
+
type MilkyClientEvents = ImHelperEventMap<string, MilkyV1Event, EventMap<string>>;
|
|
7
|
+
export type MilkyClientEventMap = ClientEventPayloads<MilkyClientEvents>;
|
|
8
|
+
/** Construct the exact public imhelper Client without handing it transport ownership. */
|
|
9
|
+
export declare function createMilkyEndpointClient(config: ResolvedMilkyConfig, request: typeof callApi): MilkyV1Client;
|
|
10
|
+
/** Use the Client's complete protocol response while keeping Endpoint internals data-oriented. */
|
|
11
|
+
export declare function callMilkyClient<T = unknown>(client: MilkyV1Client, action: string, params?: Record<string, unknown>): Promise<T | undefined>;
|
|
12
|
+
export declare function forwardMilkyClientEvents(client: MilkyV1Client, receive: (name: string, payload: unknown) => void): () => void;
|
|
13
|
+
declare module '@zhin.js/feature-kit' {
|
|
14
|
+
interface AdapterClientRegistry {
|
|
15
|
+
readonly milky: {
|
|
16
|
+
readonly client: MilkyV1Client;
|
|
17
|
+
readonly events: MilkyClientEventMap;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export declare const milkyClient: import("@zhin.js/adapter").EndpointClientToken<MilkyV1Client, ClientEventPayloads<MilkyClientEvents>>;
|
package/lib/client.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { MilkyV1Client, } from '@imhelper/milky-v1';
|
|
2
|
+
import { EventFactory, } from 'imhelper';
|
|
3
|
+
import { defineEndpointClient, forwardEndpointClientEvents, } from 'zhin.js/adapter';
|
|
4
|
+
export { MilkyV1Client as MilkyClient } from '@imhelper/milky-v1';
|
|
5
|
+
/** Construct the exact public imhelper Client without handing it transport ownership. */
|
|
6
|
+
export function createMilkyEndpointClient(config, request) {
|
|
7
|
+
return new MilkyV1Client({
|
|
8
|
+
baseUrl: config.baseUrl,
|
|
9
|
+
selfId: config.id,
|
|
10
|
+
accessToken: config.access_token,
|
|
11
|
+
receiveMode: 'manual',
|
|
12
|
+
call: (action, params) => request({
|
|
13
|
+
baseUrl: config.baseUrl,
|
|
14
|
+
access_token: config.access_token,
|
|
15
|
+
}, action, params),
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
/** Use the Client's complete protocol response while keeping Endpoint internals data-oriented. */
|
|
19
|
+
export async function callMilkyClient(client, action, params) {
|
|
20
|
+
const response = await client.call(action, params);
|
|
21
|
+
if (response.status !== 'ok') {
|
|
22
|
+
throw new Error(`Milky API ${action}: retcode=${response.retcode}${response.message ? ` ${response.message}` : ''}`);
|
|
23
|
+
}
|
|
24
|
+
return response.data;
|
|
25
|
+
}
|
|
26
|
+
const milkyClientEventNames = Object.freeze([
|
|
27
|
+
...EventFactory.getSupportedEventTypes(),
|
|
28
|
+
'event',
|
|
29
|
+
]);
|
|
30
|
+
export function forwardMilkyClientEvents(client, receive) {
|
|
31
|
+
return forwardEndpointClientEvents(client, milkyClientEventNames, receive);
|
|
32
|
+
}
|
|
33
|
+
export const milkyClient = defineEndpointClient('milky');
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Milky endpoint management 语义端口(Console 社交面 RPC 消费,见
|
|
3
|
+
* packages/im/adapter/src/endpoint-management.ts)。
|
|
4
|
+
*
|
|
5
|
+
* Milky 协议响应 data 为包裹对象:get_friend_list → {friends:[...]}、
|
|
6
|
+
* get_group_list → {groups:[...]}、get_group_member_list → {members:[...]}。
|
|
7
|
+
* 归一化取舍:
|
|
8
|
+
* - friend → {user_id:number, nickname, remark: remark ?? ''}
|
|
9
|
+
* - group → {group_id:number, name: group_name ?? name}
|
|
10
|
+
* - 群成员列表保持 Milky 原生形状,仅保证数组
|
|
11
|
+
*/
|
|
12
|
+
import type { EndpointManagement } from 'zhin.js/adapter';
|
|
13
|
+
/** 管理面只依赖 endpoint 的 callApi(ws/wss/sse/webhook 四种传输各自实现)。 */
|
|
14
|
+
export interface MilkyManagementCaller {
|
|
15
|
+
callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
16
|
+
}
|
|
17
|
+
export declare function createMilkyEndpointManagement(endpoint: MilkyManagementCaller): EndpointManagement;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export function createMilkyEndpointManagement(endpoint) {
|
|
2
|
+
return Object.freeze({
|
|
3
|
+
async listFriends() {
|
|
4
|
+
const data = asRecord(await endpoint.callApi('get_friend_list'));
|
|
5
|
+
return toArray(data.friends).map((value) => {
|
|
6
|
+
const friend = asRecord(value);
|
|
7
|
+
return {
|
|
8
|
+
user_id: toNumberId(friend.user_id, 'user_id'),
|
|
9
|
+
nickname: String(friend.nickname ?? ''),
|
|
10
|
+
remark: String(friend.remark ?? ''),
|
|
11
|
+
};
|
|
12
|
+
});
|
|
13
|
+
},
|
|
14
|
+
async listGroups() {
|
|
15
|
+
const data = asRecord(await endpoint.callApi('get_group_list'));
|
|
16
|
+
return toArray(data.groups).map((value) => {
|
|
17
|
+
const group = asRecord(value);
|
|
18
|
+
return {
|
|
19
|
+
group_id: toNumberId(group.group_id, 'group_id'),
|
|
20
|
+
name: String(group.group_name ?? group.name ?? ''),
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
async listGroupMembers(groupId) {
|
|
25
|
+
const data = asRecord(await endpoint.callApi('get_group_member_list', {
|
|
26
|
+
group_id: toNumberId(groupId, 'group_id'),
|
|
27
|
+
}));
|
|
28
|
+
return toArray(data.members);
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function asRecord(value) {
|
|
33
|
+
return value !== null && typeof value === 'object'
|
|
34
|
+
? value
|
|
35
|
+
: {};
|
|
36
|
+
}
|
|
37
|
+
function toArray(value) {
|
|
38
|
+
return Array.isArray(value) ? value : [];
|
|
39
|
+
}
|
|
40
|
+
/** console RPC 传入的 gid/uid 可能是字符串,统一收敛为数字。 */
|
|
41
|
+
function toNumberId(value, label) {
|
|
42
|
+
const n = Number(value);
|
|
43
|
+
if (!Number.isFinite(n) || String(value ?? '').trim() === '') {
|
|
44
|
+
throw new TypeError(`milky ${label} 必须是数字: ${String(value)}`);
|
|
45
|
+
}
|
|
46
|
+
return n;
|
|
47
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { MilkyWsEndpoint, type MilkyWsEndpointOptions, } from './ws-endpoint.js';
|
|
2
|
+
export { MilkyWebhookEndpoint, type MilkyWebhookEndpointOptions, } from './webhook-endpoint.js';
|
|
3
|
+
export { MilkyWssEndpoint, type MilkyWssEndpointOptions, } from './wss-endpoint.js';
|
|
4
|
+
export { MilkySseEndpoint, type MilkySseEndpointOptions, type CreateMilkySseStream, } from './sse-endpoint.js';
|
|
5
|
+
export type { MilkyWsSocket, MilkyWsCreateOptions } from './ws-types.js';
|
|
6
|
+
export { verifyMilkyAccessToken } from './milky-auth.js';
|
|
7
|
+
export { openSseStream, consumeSseBuffer } from './sse-client.js';
|
package/lib/endpoint.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { MilkyWsEndpoint, } from './ws-endpoint.js';
|
|
2
|
+
export { MilkyWebhookEndpoint, } from './webhook-endpoint.js';
|
|
3
|
+
export { MilkyWssEndpoint, } from './wss-endpoint.js';
|
|
4
|
+
export { MilkySseEndpoint, } from './sse-endpoint.js';
|
|
5
|
+
export { verifyMilkyAccessToken } from './milky-auth.js';
|
|
6
|
+
export { openSseStream, consumeSseBuffer } from './sse-client.js';
|
package/lib/index.d.ts
CHANGED
|
@@ -1,20 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
export {
|
|
4
|
-
export
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
7
|
-
export { MilkyWebhookEndpoint } from './endpoint-webhook.js';
|
|
8
|
-
export { MilkyWssServer } from './endpoint-wss.js';
|
|
9
|
-
export { MilkyAdapter, type MilkyBot } from './adapter.js';
|
|
10
|
-
declare module 'zhin.js' {
|
|
11
|
-
namespace Plugin {
|
|
12
|
-
interface Contexts {
|
|
13
|
-
router: import('@zhin.js/host-router').Router;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
interface Adapters {
|
|
17
|
-
milky: MilkyAdapter;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
//# sourceMappingURL=index.d.ts.map
|
|
1
|
+
export { buildSendAction, buildSseConnectOptions, buildWsConnectOptions, callApi, extractInboundAudioUrl, formatInboundContent, formatOutboundSegments, isMentioned, isMessageReceiveEvent, milkyInboundConversation, parseMessageReceiveData, resolveMilkyConfig, senderNickname, type MilkyAdapterConfig, type MilkyApiClientOptions, type MilkyApiResponse, type MilkyConfigBase, type MilkyEndpointConfig, type MilkyEvent, type MilkyIncomingMessage, type MilkyIncomingSegment, type MilkyOutgoingSegment, type MilkySseConfig, type MilkyWebhookConfig, type MilkyWireSegment, type MilkyWsConfig, type MilkyWssConfig, type ResolvedMilkyConfig, } from './protocol.js';
|
|
2
|
+
export { MilkySseEndpoint, MilkyWebhookEndpoint, MilkyWssEndpoint, MilkyWsEndpoint, consumeSseBuffer, openSseStream, verifyMilkyAccessToken, type CreateMilkySseStream, type MilkySseEndpointOptions, type MilkyWebhookEndpointOptions, type MilkyWssEndpointOptions, type MilkyWsCreateOptions, type MilkyWsEndpointOptions, type MilkyWsSocket, } from './endpoint.js';
|
|
3
|
+
export { MilkyClient, milkyClient, type MilkyClientEventMap, } from './client.js';
|
|
4
|
+
export type { MilkyAdapterConfig as ImHelperMilkyAdapterConfig, MilkyActionUrlResolver, MilkyCall, MilkyMessageReceiveEvent, MilkyMessageRecallEvent, MilkyV1ClientConfig, MilkyV1Event, MilkyV1Response, } from '@imhelper/milky-v1';
|
|
5
|
+
export { ProtocolError } from '@imhelper/milky-v1';
|
|
6
|
+
export type { ProtocolErrorKind, ProtocolErrorOptions } from 'imhelper';
|
package/lib/index.js
CHANGED
|
@@ -1,35 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import { MilkyAdapter } from './adapter.js';
|
|
6
|
-
export * from './types.js';
|
|
7
|
-
export { callApi } from './api.js';
|
|
8
|
-
export * from './utils.js';
|
|
9
|
-
export { MilkyWsClient } from './endpoint-ws.js';
|
|
10
|
-
export { MilkySseClient } from './endpoint-sse.js';
|
|
11
|
-
export { MilkyWebhookEndpoint } from './endpoint-webhook.js';
|
|
12
|
-
export { MilkyWssServer } from './endpoint-wss.js';
|
|
13
|
-
export { MilkyAdapter } from './adapter.js';
|
|
14
|
-
const plugin = usePlugin();
|
|
15
|
-
const { provide, useContext } = plugin;
|
|
16
|
-
provide({
|
|
17
|
-
name: 'milky',
|
|
18
|
-
description: 'Milky Adapter(WS 正向 / SSE / Webhook / 反向 WS)',
|
|
19
|
-
mounted: async (p) => {
|
|
20
|
-
const adapter = new MilkyAdapter(p);
|
|
21
|
-
await adapter.start();
|
|
22
|
-
return adapter;
|
|
23
|
-
},
|
|
24
|
-
dispose: async (adapter) => {
|
|
25
|
-
await adapter.stop();
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
useContext('tool', 'milky', (toolService, milky) => {
|
|
29
|
-
const disposers = [];
|
|
30
|
-
disposers.push(registerDefaultGroupPlatformPermitChecker('milky'));
|
|
31
|
-
const groupTools = createGroupManagementTools(milky, 'milky');
|
|
32
|
-
disposers.push(...groupTools.map(t => toolService.addTool(t, plugin.name)));
|
|
33
|
-
return () => disposers.forEach(d => d());
|
|
34
|
-
});
|
|
35
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
export { buildSendAction, buildSseConnectOptions, buildWsConnectOptions, callApi, extractInboundAudioUrl, formatInboundContent, formatOutboundSegments, isMentioned, isMessageReceiveEvent, milkyInboundConversation, parseMessageReceiveData, resolveMilkyConfig, senderNickname, } from './protocol.js';
|
|
2
|
+
export { MilkySseEndpoint, MilkyWebhookEndpoint, MilkyWssEndpoint, MilkyWsEndpoint, consumeSseBuffer, openSseStream, verifyMilkyAccessToken, } from './endpoint.js';
|
|
3
|
+
export { MilkyClient, milkyClient, } from './client.js';
|
|
4
|
+
export { ProtocolError } from '@imhelper/milky-v1';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function verifyMilkyAccessToken(accessToken, request) {
|
|
2
|
+
if (!accessToken)
|
|
3
|
+
return true;
|
|
4
|
+
const auth = request.headers.authorization ?? '';
|
|
5
|
+
if (auth === `Bearer ${accessToken}`)
|
|
6
|
+
return true;
|
|
7
|
+
try {
|
|
8
|
+
const url = new URL(request.url ?? '/', 'http://localhost');
|
|
9
|
+
if (url.searchParams.get('access_token') === accessToken)
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
/* ignore */
|
|
14
|
+
}
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const milkyEndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage, string | undefined>>>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `milky.endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
|
|
3
|
+
* commands/endpoint/ 下的 list / add / remove 直接默认导出这三项。
|
|
4
|
+
*/
|
|
5
|
+
import { createEndpointCommands } from 'zhin.js/adapter';
|
|
6
|
+
import { defineCommand } from 'zhin.js/command';
|
|
7
|
+
import { milkyRuntimeStateToken } from './milky-runtime-state.js';
|
|
8
|
+
export const milkyEndpointCommands = createEndpointCommands({
|
|
9
|
+
adapterKey: 'milky',
|
|
10
|
+
adapterDisplayName: 'Milky',
|
|
11
|
+
fields: [
|
|
12
|
+
{ key: 'baseUrl', required: true, description: 'Milky HTTP API base URL' },
|
|
13
|
+
{ key: 'path', description: 'webhook / reverse-wss 路径' },
|
|
14
|
+
{ key: 'access_token', env: true, description: 'Milky access token' },
|
|
15
|
+
],
|
|
16
|
+
running: (use) => use(milkyRuntimeStateToken).endpoints.values(),
|
|
17
|
+
describeEntry: (entry) => `baseUrl: ${String(entry.baseUrl)}`,
|
|
18
|
+
}, defineCommand);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const milkyRuntimeStateToken: import("zhin.js").Token<import("@zhin.js/adapter").EndpointRuntimeState>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Milky 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
|
|
3
|
+
* 由 plugin.ts setup() provide,adapter create 与 `milky.endpoint` 命令共享(同一 owner generation)。
|
|
4
|
+
*/
|
|
5
|
+
import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
|
|
6
|
+
export const milkyRuntimeStateToken = defineEndpointRuntimeStateToken('milky');
|