@zhin.js/adapter-onebot12 1.1.18 → 1.1.19
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 +36 -0
- package/README.md +24 -5
- package/adapters/onebot12/index.js +3 -32
- package/adapters/onebot12/index.ts +2 -38
- package/commands/onebot12/endpoint/definition.js +2 -2
- package/commands/onebot12/endpoint/definition.ts +2 -2
- package/lib/adapter.d.ts +21 -0
- package/lib/adapter.js +34 -0
- package/lib/client.d.ts +9 -11
- package/lib/client.js +23 -13
- package/lib/console-spec.js +2 -0
- package/lib/console.d.ts +1 -1
- package/lib/console.js +2 -5
- package/lib/content-port.d.ts +2 -2
- package/lib/content-port.js +1 -1
- package/lib/endpoint-management.d.ts +5 -5
- package/lib/endpoint-management.js +17 -17
- package/lib/identity.d.ts +4 -0
- package/lib/identity.js +53 -0
- package/lib/index.d.ts +3 -2
- package/lib/index.js +2 -1
- package/lib/protocol.d.ts +32 -4
- package/lib/protocol.js +54 -53
- package/lib/response.d.ts +5 -0
- package/lib/response.js +17 -0
- package/lib/side-event-dispatch.d.ts +8 -1
- package/lib/side-event-dispatch.js +2 -1
- package/lib/webhook.d.ts +5 -11
- package/lib/webhook.js +72 -37
- package/lib/ws-endpoint.d.ts +5 -11
- package/lib/ws-endpoint.js +79 -45
- package/lib/ws-transport.d.ts +18 -10
- package/lib/ws-transport.js +26 -45
- package/lib/ws-types.d.ts +0 -6
- package/lib/wss-endpoint.d.ts +5 -11
- package/lib/wss-endpoint.js +82 -48
- package/package.json +15 -15
- package/plugin.js +0 -4
- package/schema.json +15 -3
- package/src/adapter.ts +36 -0
- package/src/client.ts +26 -29
- package/src/console-spec.ts +2 -0
- package/src/console.ts +2 -5
- package/src/content-port.ts +3 -3
- package/src/endpoint-management.ts +25 -24
- package/src/identity.ts +52 -0
- package/src/index.ts +4 -1
- package/src/protocol.ts +71 -62
- package/src/response.ts +19 -0
- package/src/side-event-dispatch.ts +9 -7
- package/src/webhook.ts +70 -55
- package/src/ws-endpoint.ts +75 -63
- package/src/ws-transport.ts +37 -73
- package/src/ws-types.ts +0 -7
- package/src/wss-endpoint.ts +80 -66
- package/lib/onebot12-runtime-state.d.ts +0 -1
- package/lib/onebot12-runtime-state.js +0 -6
- package/src/onebot12-runtime-state.ts +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# @zhin.js/adapter-onebot12
|
|
2
2
|
|
|
3
|
+
## 1.1.19
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 2c3610a: Move account lifecycle ownership into the generic Adapter base and let native Endpoints retain their SDK Client inheritance. Infer platform-specific operation Sessions from a single adapter registry while preserving command parameter, option, configuration and factory inference.
|
|
8
|
+
|
|
9
|
+
Bind message replies, management ports, login challenges and Agent cancellation to the captured account incarnation. Persist runtime account intent with encrypted, revision-checked Host storage; keep account management independent of Root process restarts. Require explicit operator confirmation before importing existing accounts, and give replacement accounts a new identity without inheriting previous Sessions.
|
|
10
|
+
|
|
11
|
+
Expose account save, start, stop, update and replacement through the existing adapter Console, with exact account ownership, truthful pending/unknown outcomes and no startup configuration or environment-file rewrites.
|
|
12
|
+
|
|
13
|
+
Complete the target migration across every adapter, the public authoring API, generators, examples and Console. This intentionally removes the old create factory, inheritable Endpoint/ClientEndpoint classes, Client descriptors and file-rewrite account management; plugin authors must use createAdapter, native Client inheritance and the single AdapterRegistry. Satori and OneBot12 require explicit platform/userId selection, and WeCom requires a separate agentId.
|
|
14
|
+
|
|
15
|
+
Verify opaque credential changes before the same configuration snapshot is committed. Drain admitted native callbacks across close/rollback, cancel target work on stop, and keep raw transport parsing, platform ACK timing and SDK native methods under their existing owners. Account metadata conceals credentials carried in URLs.
|
|
16
|
+
|
|
17
|
+
- a9f4e48: PATCH COMPATIBILITY CUTOVER: this batch intentionally changes plugin APIs. The maintainer explicitly chose patch releases with declared version boundaries. Upgrade the complete tested dependency set; patch numbering does not promise compatibility with the removed interfaces.
|
|
18
|
+
|
|
19
|
+
The first planned floors are zhin.js 1.1.19, Core 1.1.54, Adapter 1.1.26, FeatureKit 1.1.10, Plugin Runtime 1.1.18, Runtime/Isolate 1.1.16 and Agent 1.1.45. Keep old-interface plugins with the earlier locked stack until they are migrated. Adapter's independent Feature API changes from 1.0.0 to 2.0.0; official consumers declare ^2.0.0. Existing Feature API admission rejects explicitly incompatible ranges; omitted API metadata keeps its existing behavior and does not certify compatibility. Runtime engine and patch-only release gates remain unchanged.
|
|
20
|
+
|
|
21
|
+
Use the native-Client Adapter target contract, canonical FeatureKit AdapterRegistry augmentation and named Endpoint control/management requests. Route message controls from canonical message/conversation refs; retain exact source authority and propagate caller/account/explicit-Root-stop cancellation. Replace removed Agent activity feedback exports with source-bound feedback. HMR pause/resume belongs to concrete plugin instances; plugins choose accepted-work policy without changing Controller commit/rollback authority. Cooperative worker/process control cancellation does not kill an isolate or reopen retired business admission.
|
|
22
|
+
|
|
23
|
+
Provide authenticated historical-data preview, exact selected binding, transactional application, authoritative inspection and explicit resumption, including active games. Preserve before-images and journals; never replay an unconfirmed effect, infer an account from an alias, or reuse historical permission grants. Owner V2 approvals remain inactive legacy data, while new writes use V3. Rollback requires matching software, lockfile and verified data; installing old code alone cannot read a new V3 approval file. Conflicting after-images are never overwritten.
|
|
24
|
+
|
|
25
|
+
See docs/plans/adapter-operation-version-boundaries.md and the Chinese/English upgrade guide for the complete version inventory, custom-plugin changes, acceptance and recovery sequence. These code and metadata changes do not authorize merging, publication, deployment, login, production migration or removal of installed workspace patches.
|
|
26
|
+
|
|
27
|
+
- Updated dependencies [2c3610a]
|
|
28
|
+
- Updated dependencies [a9f4e48]
|
|
29
|
+
- Updated dependencies [f8505b0]
|
|
30
|
+
- Updated dependencies [2c3610a]
|
|
31
|
+
- @zhin.js/adapter@1.1.26
|
|
32
|
+
- @zhin.js/feature-kit@1.1.10
|
|
33
|
+
- @zhin.js/core@1.1.54
|
|
34
|
+
- @zhin.js/host-http@1.1.12
|
|
35
|
+
- @zhin.js/client@1.1.22
|
|
36
|
+
- @zhin.js/page@1.1.11
|
|
37
|
+
- @zhin.js/skill@1.1.11
|
|
38
|
+
|
|
3
39
|
## 1.1.18
|
|
4
40
|
|
|
5
41
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
Zhin.js [OneBot 12](https://12.onebot.dev/) 适配器(Plugin Runtime)。默认 **正向 WebSocket 客户端**(`connection: ws`);亦支持 **HTTP Webhook** 与 **反向 WS**(经 `httpHostToken` 注册路由)。
|
|
4
4
|
|
|
5
|
+
账号由 `Onebot12Adapter` 管理。Endpoint 直接继承实际 `OneBotV12Client`,保留原生方法与事件;框架生命周期、规范入站与发送经 `endpointSpec` 和 AdapterIndex 接入,不占用 Client 的原生 `start` / `stop` / `send` 方法。
|
|
6
|
+
|
|
5
7
|
## 功能特性
|
|
6
8
|
|
|
7
9
|
- [OneBot 12 标准](https://12.onebot.dev/) 兼容(事件 + 动作)
|
|
8
10
|
- 约定式 `defineAdapter` / `definePlugin`(无需 `usePlugin`)
|
|
9
11
|
- **正向 WebSocket**(`connection: ws`):应用连 OneBot 实现的 WS 服务器
|
|
10
12
|
- `access_token` 鉴权(Bearer + query)
|
|
11
|
-
- 入站经 `
|
|
13
|
+
- 入站经 `endpointSpec.events`;出站 `send({ conversation, payload })`
|
|
12
14
|
|
|
13
15
|
## 安装
|
|
14
16
|
|
|
@@ -19,19 +21,26 @@ pnpm add @zhin.js/adapter-onebot12
|
|
|
19
21
|
## Plugin Runtime
|
|
20
22
|
|
|
21
23
|
- `@zhin.js/adapter` — 约定式 `adapters/onebot12/index.ts`(`defineAdapter`)
|
|
22
|
-
- `@zhin.js/core` — `
|
|
24
|
+
- `@zhin.js/core` — `endpointSpec.events` 入站、`outboundMessageToken` 出站
|
|
23
25
|
- `zhin.js` — `plugin.ts`(`definePlugin`)
|
|
24
26
|
- 配置经插件 `schema.json` 落到顶层 `<instanceKey>`
|
|
25
27
|
|
|
26
28
|
`AdapterIndex` 会把实例默认值与 `endpoints[]` 的逐项覆盖合并;协议层只接收一个已经展开的 endpoint 配置,不再读取嵌套 endpoint 或从进程环境推断身份。Webhook 配置必须同时提供 `path` 与 `api_url`,从而在启动前建立完整的双向能力。
|
|
27
29
|
|
|
28
|
-
入站:`
|
|
30
|
+
入站:`endpoint[endpointSpec].events.emit('message.receive', { conversation: ConversationRef, message: { conversation, id }, content, sender, metadata })`
|
|
31
|
+
|
|
29
32
|
出站:`send({ conversation, payload })` → WS `send_message`(payload 已由 gateway/core 渲染;无 segment-mapper)
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
Endpoint 直接继承 `@imhelper/onebot-v12` 的 `OneBotV12Client`;当前操作的 `$client` 就是该实际实例。业务代码直接调用
|
|
32
35
|
`$client.call(action, params)` 和 Client 的公开平台能力;Webhook 使用 Client 的
|
|
33
36
|
`acceptHttp()`,双工 WS 则由 Endpoint 分离 `echo` 响应后把事件交给 `ingest()`。
|
|
34
37
|
|
|
38
|
+
## 操作生命周期
|
|
39
|
+
|
|
40
|
+
每个实际 Client 的请求关联、定时器与取消由同一个实例级 RPC 模块持有。停止、删除或替换账号时,先取消该实例的等待,再关闭连接;已提交但未收到结果的请求保持“结果未知”,不会重试。框架发送与内容读取还绑定各自的操作信号,取消单个操作不影响其他操作或账号。原生 SDK 方法和事件重载保持不变。
|
|
41
|
+
|
|
42
|
+
图片上传和发送使用同一操作信号,取消上传后不会继续提交 `send_message`;WS、反向 WS 与 HTTP 出站遵循相同规则。好友、群与成员 ID 保持协议字符串,不转为 JavaScript 数字。
|
|
43
|
+
|
|
35
44
|
## 前置条件
|
|
36
45
|
|
|
37
46
|
1. 启动兼容 OneBot 12 的实现,并确认其支持所选 WS 或 Webhook 模式。
|
|
@@ -51,6 +60,8 @@ onebot12:
|
|
|
51
60
|
heartbeat_interval: 30000
|
|
52
61
|
endpoints:
|
|
53
62
|
- id: ob12-bot
|
|
63
|
+
platform: qq
|
|
64
|
+
userId: "123456789"
|
|
54
65
|
url: "ws://127.0.0.1:6700"
|
|
55
66
|
access_token: "${ONEBOT12_ACCESS_TOKEN}"
|
|
56
67
|
```
|
|
@@ -70,6 +81,14 @@ onebot12:
|
|
|
70
81
|
- **Bearer**:`Authorization: Bearer <access_token>`
|
|
71
82
|
- 正向 WS 在 Upgrade 时附带请求头,并在 URL query 写入 `access_token`
|
|
72
83
|
|
|
84
|
+
## 账号选择
|
|
85
|
+
|
|
86
|
+
每个 Endpoint 必填 `platform` 和 `userId`,精确对应 OneBot12 的 `self.platform` 和 `self.user_id`;`id` 只是本地账号名称。已有配置需明确补齐这两个字段,不能从名称或服务端首个 bot 推断。修改 selector 使用显式账号替换,新身份先停用,旧历史保留。
|
|
87
|
+
|
|
88
|
+
WS、反向 WS 和 Webhook 都在进入原生 SDK 前过滤其他 bot 的事件。每个动作(包括 `$client.call()` 和 SDK 便捷操作)都在顶层携带固定 `self: { platform, user_id }`;调用参数中的 `params.self` 不会改变该目标。服务级无 `self` 帧只处理原有连接/echo 语义,不归入某个 bot 的聊天 Session。
|
|
89
|
+
|
|
90
|
+
只读身份核验从 `get_status.bots` 中精确选择目标,再以相同 `self` 调用 `get_self_info`。同一服务可以承载多个 bot;缺少所选 bot 或无法核验时要求显式替换,接口/HTTP 失败仍是失败,不自动换账号。
|
|
91
|
+
|
|
73
92
|
## 动作与事件
|
|
74
93
|
|
|
75
94
|
- 事件:`type`(meta/message/notice/request)、`detail_type`、`message` 等,见 [事件](https://12.onebot.dev/connect/data-protocol/event/)。
|
|
@@ -90,7 +109,7 @@ onebot12:
|
|
|
90
109
|
启动后打开 Console 的「OneBot 12」页(地址 `/onebot12`),可以:
|
|
91
110
|
|
|
92
111
|
- 查看运行中的连接、点「测试连接」做连通性诊断;
|
|
93
|
-
-
|
|
112
|
+
- 经所属 Adapter 增删持久化账号、启停单个 Endpoint;凭据由 Host 加密仓储保存,不改启动 YAML 或 `.env`,不重启进程;
|
|
94
113
|
- 如果适配器要求登录,页面会显示 LoginAssist 的扫码 / 滑块 / 设备确认待办;
|
|
95
114
|
|
|
96
115
|
读取需要 `onebot12:read`,写操作需要 `onebot12:write`;管理员 full token 不受限。页面里的「添加 endpoint」等价于原来的 `onebot12 endpoint add`。
|
|
@@ -3,12 +3,8 @@
|
|
|
3
3
|
* Convention entry: discover `adapters/onebot12/index.ts` → defineAdapter.
|
|
4
4
|
*/
|
|
5
5
|
import { defineAdapter } from 'zhin.js/adapter';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { OneBot12WsEndpoint } from "../../lib/ws-endpoint.js";
|
|
9
|
-
import { OneBot12WssEndpoint } from "../../lib/wss-endpoint.js";
|
|
10
|
-
import { resolveOneBot12Config, } from "../../lib/protocol.js";
|
|
11
|
-
import { onebot12RuntimeStateToken } from "../../lib/onebot12-runtime-state.js";
|
|
6
|
+
import { Onebot12Adapter } from "../../lib/adapter.js";
|
|
7
|
+
import {} from "../../lib/protocol.js";
|
|
12
8
|
export { OneBot12WebhookEndpoint } from "../../lib/webhook.js";
|
|
13
9
|
export { OneBot12WsEndpoint } from "../../lib/ws-endpoint.js";
|
|
14
10
|
export { OneBot12WssEndpoint } from "../../lib/wss-endpoint.js";
|
|
@@ -21,30 +17,5 @@ export default defineAdapter({
|
|
|
21
17
|
outboundMedia: ['url', 'path', 'base64', 'upload'],
|
|
22
18
|
interactive: 'text',
|
|
23
19
|
},
|
|
24
|
-
|
|
25
|
-
const config = resolveOneBot12Config(context.config);
|
|
26
|
-
// 注册到插件运行时状态(onebot12 endpoint list 的"运行中"数据源)
|
|
27
|
-
context.use(onebot12RuntimeStateToken).endpoints.set(config.id, {
|
|
28
|
-
id: config.id,
|
|
29
|
-
mode: config.connection,
|
|
30
|
-
});
|
|
31
|
-
if (config.connection === 'webhook') {
|
|
32
|
-
return new OneBot12WebhookEndpoint({
|
|
33
|
-
id: context.id,
|
|
34
|
-
http: context.use(httpHostToken),
|
|
35
|
-
config,
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
if (config.connection === 'wss') {
|
|
39
|
-
return new OneBot12WssEndpoint({
|
|
40
|
-
id: context.id,
|
|
41
|
-
http: context.use(httpHostToken),
|
|
42
|
-
config,
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
return new OneBot12WsEndpoint({
|
|
46
|
-
id: context.id,
|
|
47
|
-
config,
|
|
48
|
-
});
|
|
49
|
-
},
|
|
20
|
+
createAdapter: context => new Onebot12Adapter(context),
|
|
50
21
|
});
|
|
@@ -2,15 +2,10 @@
|
|
|
2
2
|
* Convention entry: discover `adapters/onebot12/index.ts` → defineAdapter.
|
|
3
3
|
*/
|
|
4
4
|
import { defineAdapter } from 'zhin.js/adapter';
|
|
5
|
-
import {
|
|
6
|
-
import { OneBot12WebhookEndpoint } from '../../src/webhook.js';
|
|
7
|
-
import { OneBot12WsEndpoint } from '../../src/ws-endpoint.js';
|
|
8
|
-
import { OneBot12WssEndpoint } from '../../src/wss-endpoint.js';
|
|
5
|
+
import { Onebot12Adapter } from '../../src/adapter.js';
|
|
9
6
|
import {
|
|
10
|
-
resolveOneBot12Config,
|
|
11
7
|
type OneBot12EndpointConfig,
|
|
12
8
|
} from '../../src/protocol.js';
|
|
13
|
-
import { onebot12RuntimeStateToken } from '../../src/onebot12-runtime-state.js';
|
|
14
9
|
|
|
15
10
|
export { OneBot12WebhookEndpoint } from '../../src/webhook.js';
|
|
16
11
|
export type { OneBot12WebhookEndpointOptions } from '../../src/webhook.js';
|
|
@@ -20,12 +15,6 @@ export { OneBot12WssEndpoint } from '../../src/wss-endpoint.js';
|
|
|
20
15
|
export type { OneBot12WssEndpointOptions } from '../../src/wss-endpoint.js';
|
|
21
16
|
export type { OneBot12WsSocket, OneBot12WsCreateOptions } from '../../src/ws-types.js';
|
|
22
17
|
|
|
23
|
-
declare module '@zhin.js/core' {
|
|
24
|
-
interface AdapterEndpoints {
|
|
25
|
-
onebot12: import('../../src/ws-endpoint.js').OneBot12WsEndpoint;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
18
|
export default defineAdapter<OneBot12EndpointConfig>({
|
|
30
19
|
capabilities: ['inbound', 'outbound'],
|
|
31
20
|
operations: ['recall'],
|
|
@@ -35,30 +24,5 @@ export default defineAdapter<OneBot12EndpointConfig>({
|
|
|
35
24
|
outboundMedia: ['url', 'path', 'base64', 'upload'],
|
|
36
25
|
interactive: 'text',
|
|
37
26
|
},
|
|
38
|
-
|
|
39
|
-
const config = resolveOneBot12Config(context.config);
|
|
40
|
-
// 注册到插件运行时状态(onebot12 endpoint list 的"运行中"数据源)
|
|
41
|
-
context.use(onebot12RuntimeStateToken).endpoints.set(config.id, {
|
|
42
|
-
id: config.id,
|
|
43
|
-
mode: config.connection,
|
|
44
|
-
});
|
|
45
|
-
if (config.connection === 'webhook') {
|
|
46
|
-
return new OneBot12WebhookEndpoint({
|
|
47
|
-
id: context.id,
|
|
48
|
-
http: context.use(httpHostToken),
|
|
49
|
-
config,
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
if (config.connection === 'wss') {
|
|
53
|
-
return new OneBot12WssEndpoint({
|
|
54
|
-
id: context.id,
|
|
55
|
-
http: context.use(httpHostToken),
|
|
56
|
-
config,
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
return new OneBot12WsEndpoint({
|
|
60
|
-
id: context.id,
|
|
61
|
-
config,
|
|
62
|
-
});
|
|
63
|
-
},
|
|
27
|
+
createAdapter: context => new Onebot12Adapter(context),
|
|
64
28
|
});
|
|
@@ -5,17 +5,17 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { createEndpointCommands } from 'zhin.js/adapter';
|
|
7
7
|
import { defineCommand } from 'zhin.js/command';
|
|
8
|
-
import { onebot12RuntimeStateToken } from "../../../lib/onebot12-runtime-state.js";
|
|
9
8
|
export const onebot12EndpointCommands = createEndpointCommands({
|
|
10
9
|
adapterKey: 'onebot12',
|
|
11
10
|
adapterDisplayName: 'OneBot 12',
|
|
12
11
|
fields: [
|
|
12
|
+
{ key: 'platform', required: true, description: 'Selected OneBot12 bot platform' },
|
|
13
|
+
{ key: 'userId', required: true, description: 'Selected OneBot12 bot user ID' },
|
|
13
14
|
{ key: 'url', description: 'OneBot 实现 WebSocket URL(connection: ws 必填)', descriptionI18n: { en: "OneBot WebSocket URL (required for connection: ws)" } },
|
|
14
15
|
{ key: 'path', description: 'HTTP/WS 路径(webhook / reverse-wss)', descriptionI18n: { en: "HTTP/WS path (webhook / reverse-wss)" } },
|
|
15
16
|
{ key: 'api_url', description: 'HTTP action 端点(connection: webhook 出站必填)', descriptionI18n: { en: "HTTP action endpoint (required for outbound connection: webhook)" } },
|
|
16
17
|
{ key: 'access_token', env: true, description: 'OneBot access token' },
|
|
17
18
|
],
|
|
18
|
-
running: (use) => use(onebot12RuntimeStateToken).endpoints.values(),
|
|
19
19
|
describeEntry: (entry) => {
|
|
20
20
|
if (entry.url)
|
|
21
21
|
return `url: ${String(entry.url)}`;
|
|
@@ -4,18 +4,18 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { createEndpointCommands } from 'zhin.js/adapter';
|
|
6
6
|
import { defineCommand } from 'zhin.js/command';
|
|
7
|
-
import { onebot12RuntimeStateToken } from '../../../src/onebot12-runtime-state.js';
|
|
8
7
|
|
|
9
8
|
export const onebot12EndpointCommands = createEndpointCommands({
|
|
10
9
|
adapterKey: 'onebot12',
|
|
11
10
|
adapterDisplayName: 'OneBot 12',
|
|
12
11
|
fields: [
|
|
12
|
+
{ key: 'platform', required: true, description: 'Selected OneBot12 bot platform' },
|
|
13
|
+
{ key: 'userId', required: true, description: 'Selected OneBot12 bot user ID' },
|
|
13
14
|
{ key: 'url', description: 'OneBot 实现 WebSocket URL(connection: ws 必填)', descriptionI18n: { en: "OneBot WebSocket URL (required for connection: ws)" } },
|
|
14
15
|
{ key: 'path', description: 'HTTP/WS 路径(webhook / reverse-wss)', descriptionI18n: { en: "HTTP/WS path (webhook / reverse-wss)" } },
|
|
15
16
|
{ key: 'api_url', description: 'HTTP action 端点(connection: webhook 出站必填)', descriptionI18n: { en: "HTTP action endpoint (required for outbound connection: webhook)" } },
|
|
16
17
|
{ key: 'access_token', env: true, description: 'OneBot access token' },
|
|
17
18
|
],
|
|
18
|
-
running: (use) => use(onebot12RuntimeStateToken).endpoints.values(),
|
|
19
19
|
describeEntry: (entry) => {
|
|
20
20
|
if (entry.url) return `url: ${String(entry.url)}`;
|
|
21
21
|
if (entry.path) return `path: ${String(entry.path)}`;
|
package/lib/adapter.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Adapter, type AdapterContext, type EndpointCreationContext } from 'zhin.js/adapter';
|
|
2
|
+
import { type OneBot12EndpointConfig } from './protocol.js';
|
|
3
|
+
import { OneBot12WsEndpoint } from './ws-endpoint.js';
|
|
4
|
+
import { OneBot12WssEndpoint } from './wss-endpoint.js';
|
|
5
|
+
import { OneBot12WebhookEndpoint } from './webhook.js';
|
|
6
|
+
import type { Onebot12ClientEventMap } from './client.js';
|
|
7
|
+
export declare class Onebot12Adapter extends Adapter<OneBot12WsEndpoint | OneBot12WssEndpoint | OneBot12WebhookEndpoint, OneBot12EndpointConfig, Onebot12ClientEventMap> {
|
|
8
|
+
#private;
|
|
9
|
+
constructor(context: AdapterContext<OneBot12EndpointConfig>);
|
|
10
|
+
get configurationIdentityFields(): readonly string[];
|
|
11
|
+
get configurationIdentityProbeFields(): readonly string[];
|
|
12
|
+
get configurationUpdateFields(): readonly string[];
|
|
13
|
+
protected validateConfiguration(config: OneBot12EndpointConfig): void;
|
|
14
|
+
protected identifyConfiguration(input: OneBot12EndpointConfig, signal: AbortSignal): Promise<string | undefined>;
|
|
15
|
+
protected createEndpoint(input: OneBot12EndpointConfig, execution: EndpointCreationContext): OneBot12WsEndpoint | OneBot12WssEndpoint | OneBot12WebhookEndpoint;
|
|
16
|
+
}
|
|
17
|
+
declare module '@zhin.js/feature-kit' {
|
|
18
|
+
interface AdapterRegistry {
|
|
19
|
+
readonly onebot12: Onebot12Adapter;
|
|
20
|
+
}
|
|
21
|
+
}
|
package/lib/adapter.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Adapter } from 'zhin.js/adapter';
|
|
2
|
+
import { httpHostToken } from '@zhin.js/host-http';
|
|
3
|
+
import { resolveOneBot12Config } from './protocol.js';
|
|
4
|
+
import { OneBot12WsEndpoint } from './ws-endpoint.js';
|
|
5
|
+
import { OneBot12WssEndpoint } from './wss-endpoint.js';
|
|
6
|
+
import { OneBot12WebhookEndpoint } from './webhook.js';
|
|
7
|
+
import { probeOnebot12Identity, probeOnebot12HttpIdentity } from './identity.js';
|
|
8
|
+
export class Onebot12Adapter extends Adapter {
|
|
9
|
+
#context;
|
|
10
|
+
constructor(context) { super(); this.#context = context; }
|
|
11
|
+
get configurationIdentityFields() { return ['id', 'platform', 'userId']; }
|
|
12
|
+
get configurationIdentityProbeFields() { return ['connection', 'access_token', 'url', 'api_url']; }
|
|
13
|
+
get configurationUpdateFields() {
|
|
14
|
+
return ['connection', 'url', 'path', 'api_url', 'access_token', 'reconnect_interval', 'heartbeat_interval'];
|
|
15
|
+
}
|
|
16
|
+
validateConfiguration(config) { resolveOneBot12Config(config); }
|
|
17
|
+
async identifyConfiguration(input, signal) {
|
|
18
|
+
const config = resolveOneBot12Config(input);
|
|
19
|
+
if (config.connection === 'ws')
|
|
20
|
+
return probeOnebot12Identity(config, signal);
|
|
21
|
+
if (config.connection === 'webhook')
|
|
22
|
+
return probeOnebot12HttpIdentity(config, signal);
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
createEndpoint(input, execution) {
|
|
26
|
+
const config = resolveOneBot12Config(input);
|
|
27
|
+
const id = execution.canonicalId;
|
|
28
|
+
if (config.connection === 'webhook')
|
|
29
|
+
return new OneBot12WebhookEndpoint({ id, signal: execution.signal, http: this.#context.use(httpHostToken), config });
|
|
30
|
+
if (config.connection === 'wss')
|
|
31
|
+
return new OneBot12WssEndpoint({ id, signal: execution.signal, http: this.#context.use(httpHostToken), config });
|
|
32
|
+
return new OneBot12WsEndpoint({ id, signal: execution.signal, config });
|
|
33
|
+
}
|
|
34
|
+
}
|
package/lib/client.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { readOnebot12Response } from './response.js';
|
|
1
2
|
import { OneBotV12Client, type OneBotV12Event as ImHelperOneBot12Event, type OneBotV12Response } from '@imhelper/onebot-v12';
|
|
2
3
|
import { type EventMap, type ImHelperEventMap } from 'imhelper';
|
|
3
4
|
import { type ClientEventPayloads } from 'zhin.js/adapter';
|
|
@@ -6,15 +7,12 @@ export { OneBotV12Client as Onebot12Client } from '@imhelper/onebot-v12';
|
|
|
6
7
|
export type Onebot12ApiCall = (action: string, params?: Record<string, unknown>) => Promise<OneBotV12Response>;
|
|
7
8
|
type Onebot12ClientEvents = ImHelperEventMap<string, ImHelperOneBot12Event, EventMap<string>>;
|
|
8
9
|
export type Onebot12ClientEventMap = ClientEventPayloads<Onebot12ClientEvents>;
|
|
9
|
-
export declare function
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
readonly onebot12: {
|
|
15
|
-
readonly client: OneBotV12Client;
|
|
16
|
-
readonly events: Onebot12ClientEventMap;
|
|
17
|
-
};
|
|
18
|
-
}
|
|
10
|
+
export declare function onebot12ClientOptions(config: ResolvedOneBot12Config, request: Onebot12ApiCall): ConstructorParameters<typeof OneBotV12Client>[0];
|
|
11
|
+
export interface Onebot12ClientRequest {
|
|
12
|
+
readonly client: OneBotV12Client;
|
|
13
|
+
readonly action: string;
|
|
14
|
+
readonly params?: Record<string, unknown>;
|
|
19
15
|
}
|
|
20
|
-
|
|
16
|
+
/** Native methods retain ProtocolError; framework ports preserve the underlying delivery evidence. */
|
|
17
|
+
export declare function callOnebot12Client<T = unknown>(request: Onebot12ClientRequest): Promise<T | undefined>;
|
|
18
|
+
export declare function forwardOnebot12ClientEvents(client: OneBotV12Client, receive: (name: string, payload: unknown) => void): () => void;
|
package/lib/client.js
CHANGED
|
@@ -1,27 +1,38 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import {
|
|
1
|
+
import { readOnebot12Response } from './response.js';
|
|
2
|
+
export { readOnebot12Response } from './response.js';
|
|
3
|
+
import { EndpointDeliveryError } from '@zhin.js/im-contract';
|
|
4
|
+
import { ProtocolError, EventFactory } from 'imhelper';
|
|
5
|
+
import { forwardEndpointClientEvents, } from 'zhin.js/adapter';
|
|
4
6
|
export { OneBotV12Client as Onebot12Client } from '@imhelper/onebot-v12';
|
|
5
|
-
export function
|
|
7
|
+
export function onebot12ClientOptions(config, request) {
|
|
6
8
|
const baseUrl = config.connection === 'ws'
|
|
7
9
|
? config.url.replace(/^ws(s?):/, 'http$1:')
|
|
8
10
|
: config.connection === 'webhook'
|
|
9
11
|
? config.api_url
|
|
10
12
|
: 'http://localhost';
|
|
11
|
-
return
|
|
13
|
+
return {
|
|
12
14
|
baseUrl,
|
|
13
|
-
|
|
15
|
+
platform: config.platform,
|
|
16
|
+
selfId: config.userId,
|
|
14
17
|
accessToken: config.access_token,
|
|
15
18
|
receiveMode: 'manual',
|
|
16
19
|
call: request,
|
|
17
|
-
}
|
|
20
|
+
};
|
|
18
21
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
/** Native methods retain ProtocolError; framework ports preserve the underlying delivery evidence. */
|
|
23
|
+
export async function callOnebot12Client(request) {
|
|
24
|
+
try {
|
|
25
|
+
return readOnebot12Response(await request.client.call(request.action, request.params));
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (error instanceof ProtocolError) {
|
|
29
|
+
if (error.cause instanceof EndpointDeliveryError)
|
|
30
|
+
throw error.cause;
|
|
31
|
+
if (error.response !== undefined)
|
|
32
|
+
readOnebot12Response(error.response);
|
|
33
|
+
}
|
|
34
|
+
throw error;
|
|
23
35
|
}
|
|
24
|
-
return response.data;
|
|
25
36
|
}
|
|
26
37
|
const onebot12ClientEventNames = Object.freeze([
|
|
27
38
|
...EventFactory.getSupportedEventTypes(),
|
|
@@ -30,4 +41,3 @@ const onebot12ClientEventNames = Object.freeze([
|
|
|
30
41
|
export function forwardOnebot12ClientEvents(client, receive) {
|
|
31
42
|
return forwardEndpointClientEvents(client, onebot12ClientEventNames, receive);
|
|
32
43
|
}
|
|
33
|
-
export const onebot12Client = defineEndpointClient('onebot12');
|
package/lib/console-spec.js
CHANGED
|
@@ -2,6 +2,8 @@ export const onebot12ConsoleSpec = {
|
|
|
2
2
|
adapterKey: 'onebot12',
|
|
3
3
|
adapterDisplayName: 'OneBot 12',
|
|
4
4
|
fields: [
|
|
5
|
+
{ key: 'platform', required: true, description: 'Selected OneBot12 bot platform' },
|
|
6
|
+
{ key: 'userId', required: true, description: 'Selected OneBot12 bot user ID' },
|
|
5
7
|
{ key: 'url', description: 'OneBot 实现 WebSocket URL(connection: ws 必填)', descriptionI18n: { en: 'OneBot WebSocket URL (required for connection: ws)' } },
|
|
6
8
|
{ key: 'path', description: 'HTTP/WS 路径(webhook / reverse-wss)', descriptionI18n: { en: 'HTTP/WS path (webhook / reverse-wss)' } },
|
|
7
9
|
{ key: 'api_url', description: 'HTTP action 端点(connection: webhook 出站必填)', descriptionI18n: { en: 'HTTP action endpoint (required for outbound connection: webhook)' } },
|
package/lib/console.d.ts
CHANGED
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { type AdapterConsoleResources } from 'zhin.js/adapter';
|
|
7
7
|
import type { PluginConsoleRpc } from 'zhin.js';
|
|
8
|
-
export declare function createOnebot12ConsoleRpc(
|
|
8
|
+
export declare function createOnebot12ConsoleRpc(_resources: AdapterConsoleResources, getConfig: () => unknown): PluginConsoleRpc;
|
package/lib/console.js
CHANGED
|
@@ -4,13 +4,10 @@
|
|
|
4
4
|
* 页面绑定 `pages/index`,读取 / 写入分别要求 `<adapter>:read` / `<adapter>:write`。
|
|
5
5
|
*/
|
|
6
6
|
import { createAdapterConsoleRpc } from 'zhin.js/adapter';
|
|
7
|
-
import { onebot12RuntimeStateToken } from './onebot12-runtime-state.js';
|
|
8
7
|
import { onebot12ConsoleSpec } from './console-spec.js';
|
|
9
|
-
export function createOnebot12ConsoleRpc(
|
|
10
|
-
const state = resources.use(onebot12RuntimeStateToken);
|
|
8
|
+
export function createOnebot12ConsoleRpc(_resources, getConfig) {
|
|
11
9
|
return createAdapterConsoleRpc({
|
|
12
10
|
...onebot12ConsoleSpec,
|
|
13
|
-
running: () => state.endpoints.values(),
|
|
14
11
|
getConfig,
|
|
15
|
-
}
|
|
12
|
+
});
|
|
16
13
|
}
|
package/lib/content-port.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EndpointContentPort } from 'zhin.js/adapter';
|
|
2
|
-
type CallApi = (
|
|
1
|
+
import type { EndpointContentPort, PendingRpcRequest } from 'zhin.js/adapter';
|
|
2
|
+
type CallApi = (request: PendingRpcRequest) => Promise<unknown>;
|
|
3
3
|
export declare function createOneBot12ContentPort(callApi: CallApi): EndpointContentPort;
|
|
4
4
|
export {};
|
package/lib/content-port.js
CHANGED
|
@@ -11,7 +11,7 @@ export function createOneBot12ContentPort(callApi) {
|
|
|
11
11
|
? Object.freeze({ status: 'unsupported', code: 'onebot12_opaque_media' })
|
|
12
12
|
: Object.freeze({ status: 'resolved', reference, value: reference.media });
|
|
13
13
|
}
|
|
14
|
-
const row = await callApi('get_message', { message_id: reference.message.id });
|
|
14
|
+
const row = await callApi({ action: 'get_message', params: { message_id: reference.message.id }, signal: context.signal });
|
|
15
15
|
context.signal.throwIfAborted();
|
|
16
16
|
const message = (row.message && typeof row.message === 'object' ? row.message : row);
|
|
17
17
|
const segments = normalizeSegments(message.message ?? message.content);
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
* packages/im/adapter/src/endpoint-management.ts)。
|
|
4
4
|
*
|
|
5
5
|
* 动作名对齐 OB12 规范:get_friend_list / get_group_list / get_group_member_list。
|
|
6
|
-
*
|
|
7
|
-
* - friend → {user_id:
|
|
8
|
-
* - group → {group_id:
|
|
6
|
+
* 投影仅归一化展示字段;OB12 账号与会话 ID 始终保留为不透明字符串:
|
|
7
|
+
* - friend → {user_id:string, nickname: user_name, remark: user_displayname ?? ''}
|
|
8
|
+
* - group → {group_id:string, name: group_name ?? name}
|
|
9
9
|
* - 群成员列表保持 OB12 原生形状,仅保证数组
|
|
10
10
|
*/
|
|
11
|
-
import type
|
|
11
|
+
import { type EndpointManagement, type PendingRpcRequest } from 'zhin.js/adapter';
|
|
12
12
|
/** 管理面只依赖 endpoint 的 callApi(ws/wss/webhook 三种传输各自实现)。 */
|
|
13
13
|
export interface OneBot12ManagementCaller {
|
|
14
|
-
callApi(
|
|
14
|
+
callApi(request: PendingRpcRequest): Promise<unknown>;
|
|
15
15
|
}
|
|
16
16
|
export declare function createOneBot12EndpointManagement(endpoint: OneBot12ManagementCaller): EndpointManagement;
|
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
export function createOneBot12EndpointManagement(endpoint) {
|
|
2
2
|
return Object.freeze({
|
|
3
|
-
async listFriends() {
|
|
4
|
-
const data = await endpoint.callApi('get_friend_list');
|
|
3
|
+
async listFriends(request = {}) {
|
|
4
|
+
const data = await endpoint.callApi({ action: 'get_friend_list', signal: request.signal });
|
|
5
5
|
return toArray(data).map((value) => {
|
|
6
6
|
const friend = asRecord(value);
|
|
7
7
|
return {
|
|
8
|
-
user_id:
|
|
8
|
+
user_id: readOpaqueId(friend.user_id, 'user_id'),
|
|
9
9
|
nickname: String(friend.user_name ?? friend.nickname ?? ''),
|
|
10
10
|
remark: String(friend.user_displayname ?? friend.remark ?? ''),
|
|
11
11
|
};
|
|
12
12
|
});
|
|
13
13
|
},
|
|
14
|
-
async listGroups() {
|
|
15
|
-
const data = await endpoint.callApi('get_group_list');
|
|
14
|
+
async listGroups(request = {}) {
|
|
15
|
+
const data = await endpoint.callApi({ action: 'get_group_list', signal: request.signal });
|
|
16
16
|
return toArray(data).map((value) => {
|
|
17
17
|
const group = asRecord(value);
|
|
18
18
|
return {
|
|
19
|
-
group_id:
|
|
19
|
+
group_id: readOpaqueId(group.group_id, 'group_id'),
|
|
20
20
|
name: String(group.group_name ?? group.name ?? ''),
|
|
21
21
|
};
|
|
22
22
|
});
|
|
23
23
|
},
|
|
24
|
-
async listGroupMembers(groupId) {
|
|
25
|
-
const data = await endpoint.callApi('get_group_member_list', {
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
async listGroupMembers({ groupId, signal }) {
|
|
25
|
+
const data = await endpoint.callApi({ action: 'get_group_member_list', signal, params: {
|
|
26
|
+
group_id: groupId,
|
|
27
|
+
} });
|
|
28
28
|
return toArray(data);
|
|
29
29
|
},
|
|
30
30
|
});
|
|
@@ -37,11 +37,11 @@ function asRecord(value) {
|
|
|
37
37
|
function toArray(value) {
|
|
38
38
|
return Array.isArray(value) ? value : [];
|
|
39
39
|
}
|
|
40
|
-
/**
|
|
41
|
-
function
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
/** Platform IDs are addresses, including nonnumeric IDs and integers beyond Number precision. */
|
|
41
|
+
function readOpaqueId(value, label) {
|
|
42
|
+
if (typeof value === 'string' && value.trim())
|
|
43
|
+
return value;
|
|
44
|
+
if (typeof value === 'number' && Number.isSafeInteger(value))
|
|
45
|
+
return String(value);
|
|
46
|
+
throw new TypeError(`onebot12 ${label} must be an opaque string or safe integer platform ID`);
|
|
47
47
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type OneBot12WebhookConfig, type OneBot12WsConfig } from './protocol.js';
|
|
2
|
+
/** Separate read-only connection: never changes credentials or state of the running Endpoint. */
|
|
3
|
+
export declare function probeOnebot12Identity(config: OneBot12WsConfig, signal: AbortSignal): Promise<string | undefined>;
|
|
4
|
+
export declare function probeOnebot12HttpIdentity(config: OneBot12WebhookConfig, signal: AbortSignal): Promise<string | undefined>;
|
package/lib/identity.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import WebSocket from 'ws';
|
|
2
|
+
import { buildWsConnectOptions, callOneBot12Action } from './protocol.js';
|
|
3
|
+
import { createOneBot12Rpc } from './ws-transport.js';
|
|
4
|
+
/** Separate read-only connection: never changes credentials or state of the running Endpoint. */
|
|
5
|
+
export async function probeOnebot12Identity(config, signal) {
|
|
6
|
+
signal.throwIfAborted();
|
|
7
|
+
const { url, headers } = buildWsConnectOptions(config);
|
|
8
|
+
const socket = new WebSocket(url, { headers });
|
|
9
|
+
const rpc = createOneBot12Rpc({ endpointId: config.id, signal, socket: () => socket, self: { platform: config.platform, user_id: config.userId }, });
|
|
10
|
+
let rejectOpen = () => undefined;
|
|
11
|
+
const abort = () => { rejectOpen(signal.reason); rpc.disconnect(); socket.terminate(); };
|
|
12
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
13
|
+
socket.on('message', data => rpc.receive(data, () => undefined));
|
|
14
|
+
socket.on('close', () => { rejectOpen(new Error('Identity connection closed')); rpc.disconnect(); });
|
|
15
|
+
try {
|
|
16
|
+
await new Promise((resolve, reject) => { rejectOpen = reject; socket.once('open', resolve); socket.on('error', reject); });
|
|
17
|
+
signal.throwIfAborted();
|
|
18
|
+
const self = { platform: config.platform, user_id: config.userId };
|
|
19
|
+
return await identifySelectedBot({ selected: self, query: action => rpc.call({ action }), signal });
|
|
20
|
+
}
|
|
21
|
+
finally {
|
|
22
|
+
signal.removeEventListener('abort', abort);
|
|
23
|
+
rpc.dispose();
|
|
24
|
+
socket.terminate();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export async function probeOnebot12HttpIdentity(config, signal) {
|
|
28
|
+
const self = { platform: config.platform, user_id: config.userId };
|
|
29
|
+
return identifySelectedBot({ selected: self, query: action => callOneBot12Action({ url: config.api_url, access_token: config.access_token, signal, self, action }), signal });
|
|
30
|
+
}
|
|
31
|
+
async function identifySelectedBot({ selected, query, signal }) {
|
|
32
|
+
const status = await query('get_status');
|
|
33
|
+
signal.throwIfAborted();
|
|
34
|
+
if (status.status !== 'ok' || status.retcode !== 0)
|
|
35
|
+
throw new Error('OneBot12 identity status lookup failed');
|
|
36
|
+
const data = status.data;
|
|
37
|
+
if (!data || typeof data !== 'object' || !('bots' in data) || !Array.isArray(data.bots))
|
|
38
|
+
return undefined;
|
|
39
|
+
const match = data.bots.some((bot) => {
|
|
40
|
+
if (!bot || typeof bot !== 'object' || !('self' in bot) || !bot.self || typeof bot.self !== 'object')
|
|
41
|
+
return false;
|
|
42
|
+
return 'platform' in bot.self && 'user_id' in bot.self && bot.self.platform === selected.platform && bot.self.user_id === selected.user_id;
|
|
43
|
+
});
|
|
44
|
+
if (!match)
|
|
45
|
+
return undefined;
|
|
46
|
+
const account = await query('get_self_info');
|
|
47
|
+
signal.throwIfAborted();
|
|
48
|
+
if (account.status !== 'ok' || account.retcode !== 0)
|
|
49
|
+
throw new Error('OneBot12 account identity lookup failed');
|
|
50
|
+
if (!account.data || typeof account.data !== 'object' || !('user_id' in account.data) || account.data.user_id !== selected.user_id)
|
|
51
|
+
return undefined;
|
|
52
|
+
return `onebot12:${JSON.stringify([selected.platform, selected.user_id])}`;
|
|
53
|
+
}
|