@zhin.js/adapter-napcat 1.1.18 → 1.1.20

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 (57) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +8 -5
  3. package/adapters/napcat/index.js +2 -29
  4. package/adapters/napcat/index.ts +3 -35
  5. package/agents/napcat/skills/napcat-account/tools/set_profile/index.js +1 -1
  6. package/agents/napcat/skills/napcat-account/tools/set_profile/index.ts +1 -1
  7. package/agents/napcat/skills/napcat-group-files-history/tools/upload_group_file/index.js +1 -1
  8. package/agents/napcat/skills/napcat-group-files-history/tools/upload_group_file/index.ts +1 -1
  9. package/agents/napcat/skills/napcat-group-settings/tools/set_title/index.js +1 -1
  10. package/agents/napcat/skills/napcat-group-settings/tools/set_title/index.ts +1 -1
  11. package/agents/napcat/skills/napcat-media/tools/get_mini_app_ark/index.js +1 -1
  12. package/agents/napcat/skills/napcat-media/tools/get_mini_app_ark/index.ts +1 -1
  13. package/commands/napcat/endpoint/definition.js +0 -2
  14. package/commands/napcat/endpoint/definition.ts +0 -2
  15. package/lib/adapter.d.ts +23 -0
  16. package/lib/adapter.js +42 -0
  17. package/lib/client.d.ts +53 -16
  18. package/lib/client.js +53 -10
  19. package/lib/console.d.ts +1 -1
  20. package/lib/console.js +2 -5
  21. package/lib/endpoint-management.d.ts +2 -2
  22. package/lib/endpoint-management.js +13 -13
  23. package/lib/http-endpoint.d.ts +5 -15
  24. package/lib/http-endpoint.js +44 -36
  25. package/lib/identity.d.ts +3 -0
  26. package/lib/identity.js +32 -0
  27. package/lib/index.d.ts +3 -2
  28. package/lib/index.js +2 -2
  29. package/lib/onebot-get-msg.d.ts +2 -2
  30. package/lib/onebot-get-msg.js +2 -2
  31. package/lib/protocol.d.ts +5 -0
  32. package/lib/protocol.js +23 -11
  33. package/lib/ws-endpoint.d.ts +6 -16
  34. package/lib/ws-endpoint.js +57 -48
  35. package/lib/ws-transport.d.ts +18 -12
  36. package/lib/ws-transport.js +28 -72
  37. package/lib/ws-types.d.ts +0 -5
  38. package/lib/wss-endpoint.d.ts +7 -15
  39. package/lib/wss-endpoint.js +56 -47
  40. package/package.json +18 -18
  41. package/plugin.js +0 -3
  42. package/src/adapter.ts +45 -0
  43. package/src/client.ts +91 -19
  44. package/src/console.ts +2 -5
  45. package/src/endpoint-management.ts +19 -15
  46. package/src/http-endpoint.ts +47 -45
  47. package/src/identity.ts +29 -0
  48. package/src/index.ts +9 -5
  49. package/src/onebot-get-msg.ts +4 -4
  50. package/src/protocol.ts +26 -14
  51. package/src/ws-endpoint.ts +61 -54
  52. package/src/ws-transport.ts +40 -101
  53. package/src/ws-types.ts +0 -6
  54. package/src/wss-endpoint.ts +60 -54
  55. package/lib/napcat-runtime-state.d.ts +0 -1
  56. package/lib/napcat-runtime-state.js +0 -6
  57. package/src/napcat-runtime-state.ts +0 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,51 @@
1
1
  # @zhin.js/adapter-napcat
2
2
 
3
+ ## 1.1.20
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [5e878ba]
8
+ - @zhin.js/page@1.1.12
9
+
10
+ ## 1.1.19
11
+
12
+ ### Patch Changes
13
+
14
+ - 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.
15
+
16
+ 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.
17
+
18
+ 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.
19
+
20
+ 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.
21
+
22
+ 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.
23
+
24
+ - 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.
25
+
26
+ 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.
27
+
28
+ 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.
29
+
30
+ 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.
31
+
32
+ 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.
33
+
34
+ - Updated dependencies [2c3610a]
35
+ - Updated dependencies [a9f4e48]
36
+ - Updated dependencies [f8505b0]
37
+ - Updated dependencies [2c3610a]
38
+ - @zhin.js/adapter@1.1.26
39
+ - @zhin.js/feature-kit@1.1.10
40
+ - @zhin.js/core@1.1.54
41
+ - @zhin.js/host-http@1.1.12
42
+ - @zhin.js/client@1.1.22
43
+ - @zhin.js/page@1.1.11
44
+ - @zhin.js/agent-feature@1.1.11
45
+ - @zhin.js/skill@1.1.11
46
+ - @zhin.js/tool@1.1.13
47
+ - @zhin.js/permission@1.1.10
48
+
3
49
  ## 1.1.18
4
50
 
5
51
  ### Patch Changes
package/README.md CHANGED
@@ -2,13 +2,15 @@
2
2
 
3
3
  Zhin.js [NapCatQQ](https://github.com/NapNeko/NapCatQQ) 适配器(Plugin Runtime,OneBot 11 + NapCat 扩展)。默认 **正向 WebSocket 客户端**(`connection: ws`);亦支持 **反向 WS** 与 **HTTP POST 上报**(经 `httpHostToken`)。
4
4
 
5
+ 账号由 `NapcatAdapter` 管理。Endpoint 直接继承实际 `NapcatClient`,保留原生方法与事件;框架生命周期、规范入站与发送经 `endpointSpec` 和 AdapterIndex 接入,不占用 Client 的原生 `start` / `stop` / `send` 方法。
6
+
5
7
  ## 功能特性
6
8
 
7
9
  - OneBot 11 + go-cqhttp 扩展 + NapCat 独有 API
8
10
  - 约定式 `defineAdapter` / `definePlugin`(无需 `usePlugin`)
9
11
  - **正向 WebSocket**(`connection: ws`):应用连 NapCat WS
10
12
  - `access_token` 鉴权(Bearer + query)
11
- - 入站经 `Endpoint.emit(...)`(去重 + 自发过滤);出站 `send({ conversation, payload })`
13
+ - 入站经 `endpointSpec.events`(去重 + 自发过滤);出站 `send({ conversation, payload })`
12
14
  - 41 个 AI 工具(`tools/`)
13
15
 
14
16
  ## 安装
@@ -20,11 +22,12 @@ pnpm add @zhin.js/adapter-napcat
20
22
  ## Plugin Runtime
21
23
 
22
24
  - `@zhin.js/adapter` — 约定式 `adapters/napcat/index.ts`(`defineAdapter`)
23
- - `@zhin.js/core` — `Endpoint.emit(...)` 入站、`outboundMessageToken` 出站
25
+ - `@zhin.js/core` — `endpointSpec.events` 入站、`outboundMessageToken` 出站
24
26
  - `zhin.js` — `plugin.ts`(`definePlugin`)
25
27
  - 配置经插件 `schema.json` 落到顶层 `<instanceKey>`
26
28
 
27
- 入站:`gateway.receive({ conversation, message: { conversation, id }, content, sender, metadata })`(`conversation` 为 ConversationRef:私聊 `kind: 'private'`、群聊 `kind: 'group'`,临时会话群容器进 `parent`)
29
+ 入站:`endpoint[endpointSpec].events.emit('message.receive', { conversation, message: { conversation, id }, content, sender, metadata })`(`conversation` 为 ConversationRef:私聊 `kind: 'private'`、群聊 `kind: 'group'`,临时会话群容器进 `parent`)
30
+
28
31
  出站:`send({ conversation, payload })` → WS `send_private_msg` / `send_group_msg`
29
32
 
30
33
  ## 前置条件
@@ -78,7 +81,7 @@ endpoint 配置,不会从环境变量推断 endpoint id。
78
81
 
79
82
  ## 迁移说明(Plugin Runtime)
80
83
 
81
- - **notice / request / meta 侧事件**:经 the unified `Endpoint.emit(...)` ingress 归一后分发到 `handlers`(`notice.receive` / `request.receive` / `system.receive`),请求带 `$approve` / `$reject`。消息仍走 `outboundMessageToken`。
84
+ - **notice / request / meta 侧事件**:经统一 `endpointSpec.events` 归一后分发到 `handlers`(`notice.receive` / `request.receive` / `system.receive`),请求带 `$approve` / `$reject`。消息仍走 `outboundMessageToken`。
82
85
  - **群管工具暂未迁移**:旧 Adapter 经 `createSceneManagementTools` 注册踢人 / 禁言 / 群名片等成套 agent 工具;迁移后 `tools/` 仅覆盖 NapCat 扩展 API,其余群管能力可通过 `callApi`(如 `set_group_kick`、`set_group_ban`)作为逃生舱调用。
83
86
  - **平台权限门禁**:`plugin.ts` setup 通过 generation-owned `permissionHostToken` 调用 `host.registerPlatform('napcat', createSceneRolePlatformChecker())`,`scene_admin` / `scene_owner` 依据入站 metadata 中的 sender `role`(owner / admin)判定。
84
87
 
@@ -92,7 +95,7 @@ endpoint 配置,不会从环境变量推断 endpoint id。
92
95
  启动后打开 Console 的「NapCat」页(地址 `/napcat`),可以:
93
96
 
94
97
  - 查看运行中的连接、点「测试连接」做连通性诊断;
95
- - 增删 `plugins.napcat.endpoints`(凭据写入 `.env`,配置里只保留 `${ENV}` 引用);
98
+ - 经所属 Adapter 增删持久化账号、启停单个 Endpoint;凭据由 Host 加密仓储保存,不改启动 YAML 或 `.env`,不重启进程;
96
99
  - 如果适配器要求登录,页面会显示 LoginAssist 的扫码 / 滑块 / 设备确认待办;
97
100
 
98
101
  读取需要 `napcat:read`,写操作需要 `napcat:write`;管理员 full token 不受限。页面里的「添加 endpoint」等价于原来的 `napcat endpoint add`。
@@ -3,12 +3,7 @@
3
3
  * Convention entry: discover `adapters/napcat/index.ts` → defineAdapter.
4
4
  */
5
5
  import { defineAdapter } from 'zhin.js/adapter';
6
- import { httpHostToken } from '@zhin.js/host-http';
7
- import { NapCatHttpEndpoint } from "../../lib/http-endpoint.js";
8
- import { resolveNapCatConfig } from "../../lib/protocol.js";
9
- import { NapCatWsEndpoint } from "../../lib/ws-endpoint.js";
10
- import { NapCatWssEndpoint } from "../../lib/wss-endpoint.js";
11
- import { napcatRuntimeStateToken } from "../../lib/napcat-runtime-state.js";
6
+ import { NapcatAdapter } from "../../lib/adapter.js";
12
7
  export { NapCatHttpEndpoint, } from "../../lib/http-endpoint.js";
13
8
  export { NapCatWsEndpoint, } from "../../lib/ws-endpoint.js";
14
9
  export { NapCatWssEndpoint, } from "../../lib/wss-endpoint.js";
@@ -21,27 +16,5 @@ export default defineAdapter({
21
16
  outboundMedia: ['url', 'base64', 'path'],
22
17
  interactive: 'text',
23
18
  },
24
- create(context) {
25
- const config = resolveNapCatConfig(context.config);
26
- // 注册到插件运行时状态(napcat endpoint list 的"运行中"数据源)
27
- context.use(napcatRuntimeStateToken).endpoints.set(config.id, {
28
- id: config.id,
29
- mode: config.connection,
30
- });
31
- if (config.connection === 'wss') {
32
- return new NapCatWssEndpoint({
33
- id: context.id,
34
- http: context.use(httpHostToken),
35
- config,
36
- });
37
- }
38
- if (config.connection === 'http') {
39
- return new NapCatHttpEndpoint({
40
- id: context.id,
41
- http: context.use(httpHostToken),
42
- config,
43
- });
44
- }
45
- return new NapCatWsEndpoint({ id: context.id, config });
46
- },
19
+ createAdapter: context => new NapcatAdapter(context),
47
20
  });
@@ -2,12 +2,8 @@
2
2
  * Convention entry: discover `adapters/napcat/index.ts` → defineAdapter.
3
3
  */
4
4
  import { defineAdapter } from 'zhin.js/adapter';
5
- import { httpHostToken } from '@zhin.js/host-http';
6
- import { NapCatHttpEndpoint } from '../../src/http-endpoint.js';
7
- import { resolveNapCatConfig, type NapCatEndpointConfig } from '../../src/protocol.js';
8
- import { NapCatWsEndpoint } from '../../src/ws-endpoint.js';
9
- import { NapCatWssEndpoint } from '../../src/wss-endpoint.js';
10
- import { napcatRuntimeStateToken } from '../../src/napcat-runtime-state.js';
5
+ import { NapcatAdapter } from '../../src/adapter.js';
6
+ import type { NapCatEndpointConfig } from '../../src/protocol.js';
11
7
 
12
8
  export {
13
9
  NapCatHttpEndpoint,
@@ -23,12 +19,6 @@ export {
23
19
  } from '../../src/wss-endpoint.js';
24
20
  export type { NapCatWsSocket, NapCatWsCreateOptions } from '../../src/ws-types.js';
25
21
 
26
- declare module '@zhin.js/core' {
27
- interface AdapterEndpoints {
28
- napcat: import('../../src/ws-endpoint.js').NapCatWsEndpoint;
29
- }
30
- }
31
-
32
22
  export default defineAdapter<NapCatEndpointConfig>({
33
23
  capabilities: ['inbound', 'outbound'],
34
24
  operations: ['recall'],
@@ -38,27 +28,5 @@ export default defineAdapter<NapCatEndpointConfig>({
38
28
  outboundMedia: ['url', 'base64', 'path'],
39
29
  interactive: 'text',
40
30
  },
41
- create(context) {
42
- const config = resolveNapCatConfig(context.config);
43
- // 注册到插件运行时状态(napcat endpoint list 的"运行中"数据源)
44
- context.use(napcatRuntimeStateToken).endpoints.set(config.id, {
45
- id: config.id,
46
- mode: config.connection,
47
- });
48
- if (config.connection === 'wss') {
49
- return new NapCatWssEndpoint({
50
- id: context.id,
51
- http: context.use(httpHostToken),
52
- config,
53
- });
54
- }
55
- if (config.connection === 'http') {
56
- return new NapCatHttpEndpoint({
57
- id: context.id,
58
- http: context.use(httpHostToken),
59
- config,
60
- });
61
- }
62
- return new NapCatWsEndpoint({ id: context.id, config });
63
- },
31
+ createAdapter: context => new NapcatAdapter(context),
64
32
  });
@@ -15,7 +15,7 @@ export default defineAgentTool({
15
15
  keywords: ['修改资料', '设置昵称', 'profile', 'set profile'],
16
16
  async execute({ nickname, company, email, college, personal_note }, context) {
17
17
  const endpoint = context.$client;
18
- await endpoint.setQQProfile(nickname, company, email, college, personal_note);
18
+ await endpoint.setQQProfile({ nickname, company, email, college, personalNote: personal_note });
19
19
  return { success: true };
20
20
  },
21
21
  });
@@ -15,7 +15,7 @@ export default defineAgentTool<{ nickname: string; company?: string; email?: str
15
15
  keywords: ['修改资料', '设置昵称', 'profile', 'set profile'],
16
16
  async execute({ nickname, company, email, college, personal_note }: { nickname: string; company?: string; email?: string; college?: string; personal_note?: string }, context) {
17
17
  const endpoint = context.$client;
18
- await endpoint.setQQProfile(nickname, company, email, college, personal_note);
18
+ await endpoint.setQQProfile({ nickname, company, email, college, personalNote: personal_note });
19
19
  return { success: true };
20
20
  },
21
21
  });
@@ -15,7 +15,7 @@ export default defineAgentTool({
15
15
  scopes: ['group'],
16
16
  async execute({ group_id, file, name, folder }, context) {
17
17
  const endpoint = context.$client;
18
- await endpoint.uploadGroupFile(group_id, file, name, folder);
18
+ await endpoint.uploadGroupFile({ groupId: group_id, file, name, folder });
19
19
  return { success: true };
20
20
  },
21
21
  });
@@ -15,7 +15,7 @@ export default defineAgentTool<{ group_id: number; file: string; name: string; f
15
15
  scopes: ['group'],
16
16
  async execute({ group_id, file, name, folder }: { group_id: number; file: string; name: string; folder?: string }, context) {
17
17
  const endpoint = context.$client;
18
- await endpoint.uploadGroupFile(group_id, file, name, folder);
18
+ await endpoint.uploadGroupFile({ groupId: group_id, file, name, folder });
19
19
  return { success: true };
20
20
  },
21
21
  });
@@ -16,7 +16,7 @@ export default defineAgentTool({
16
16
  scopes: ['group'],
17
17
  async execute({ group_id, user_id, title }, context) {
18
18
  const endpoint = context.$client;
19
- await endpoint.setTitle(group_id, user_id, title);
19
+ await endpoint.setTitle({ groupId: group_id, userId: user_id, title });
20
20
  return { success: true, message: t(context.locale, 'memberTitleSet', { p0: user_id, p1: title }) };
21
21
  },
22
22
  });
@@ -16,7 +16,7 @@ export default defineAgentTool<{ group_id: number; user_id: number; title: strin
16
16
  scopes: ['group'],
17
17
  async execute({ group_id, user_id, title }: { group_id: number; user_id: number; title: string }, context) {
18
18
  const endpoint = context.$client;
19
- await endpoint.setTitle(group_id, user_id, title);
19
+ await endpoint.setTitle({ groupId: group_id, userId: user_id, title });
20
20
  return { success: true, message: t(context.locale, 'memberTitleSet', { p0: user_id, p1: title }) };
21
21
  },
22
22
  });
@@ -15,6 +15,6 @@ export default defineAgentTool({
15
15
  keywords: ['小程序', 'mini app', '卡片', 'ark'],
16
16
  async execute({ type, title, desc, pic_url, jump_url }, context) {
17
17
  const endpoint = context.$client;
18
- return endpoint.getMiniAppArk(type, title, desc, pic_url, jump_url);
18
+ return endpoint.getMiniAppArk({ type, title, desc, picUrl: pic_url, jumpUrl: jump_url });
19
19
  },
20
20
  });
@@ -15,6 +15,6 @@ export default defineAgentTool<{ type: string; title: string; desc: string; pic_
15
15
  keywords: ['小程序', 'mini app', '卡片', 'ark'],
16
16
  async execute({ type, title, desc, pic_url, jump_url }: { type: string; title: string; desc: string; pic_url: string; jump_url: string }, context) {
17
17
  const endpoint = context.$client;
18
- return endpoint.getMiniAppArk(type, title, desc, pic_url, jump_url);
18
+ return endpoint.getMiniAppArk({ type, title, desc, picUrl: pic_url, jumpUrl: jump_url });
19
19
  },
20
20
  });
@@ -5,7 +5,6 @@
5
5
  */
6
6
  import { createEndpointCommands } from 'zhin.js/adapter';
7
7
  import { defineCommand } from 'zhin.js/command';
8
- import { napcatRuntimeStateToken } from "../../../lib/napcat-runtime-state.js";
9
8
  export const napcatEndpointCommands = createEndpointCommands({
10
9
  adapterKey: 'napcat',
11
10
  adapterDisplayName: 'NapCat',
@@ -16,7 +15,6 @@ export const napcatEndpointCommands = createEndpointCommands({
16
15
  { key: 'post_path', description: 'HTTP POST 事件路径(connection: http 入站)', descriptionI18n: { en: "HTTP POST event path (inbound connection: http)" } },
17
16
  { key: 'access_token', env: true, description: 'NapCat access token' },
18
17
  ],
19
- running: (use) => use(napcatRuntimeStateToken).endpoints.values(),
20
18
  describeEntry: (entry) => {
21
19
  if (entry.url)
22
20
  return `url: ${String(entry.url)}`;
@@ -4,7 +4,6 @@
4
4
  */
5
5
  import { createEndpointCommands } from 'zhin.js/adapter';
6
6
  import { defineCommand } from 'zhin.js/command';
7
- import { napcatRuntimeStateToken } from '../../../src/napcat-runtime-state.js';
8
7
 
9
8
  export const napcatEndpointCommands = createEndpointCommands({
10
9
  adapterKey: 'napcat',
@@ -16,7 +15,6 @@ export const napcatEndpointCommands = createEndpointCommands({
16
15
  { key: 'post_path', description: 'HTTP POST 事件路径(connection: http 入站)', descriptionI18n: { en: "HTTP POST event path (inbound connection: http)" } },
17
16
  { key: 'access_token', env: true, description: 'NapCat access token' },
18
17
  ],
19
- running: (use) => use(napcatRuntimeStateToken).endpoints.values(),
20
18
  describeEntry: (entry) => {
21
19
  if (entry.url) return `url: ${String(entry.url)}`;
22
20
  if (entry.path) return `path: ${String(entry.path)}`;
@@ -0,0 +1,23 @@
1
+ import { Adapter, type AdapterContext, type EndpointCreationContext } from 'zhin.js/adapter';
2
+ import { type NapCatEndpointConfig } from './protocol.js';
3
+ import { NapCatWsEndpoint } from './ws-endpoint.js';
4
+ import { NapCatWssEndpoint } from './wss-endpoint.js';
5
+ import { NapCatHttpEndpoint } from './http-endpoint.js';
6
+ import type { NapcatClientEventMap } from './client.js';
7
+ type NapcatEndpoint = NapCatWsEndpoint | NapCatWssEndpoint | NapCatHttpEndpoint;
8
+ export declare class NapcatAdapter extends Adapter<NapcatEndpoint, NapCatEndpointConfig, NapcatClientEventMap> {
9
+ #private;
10
+ constructor(context: AdapterContext<NapCatEndpointConfig>);
11
+ get configurationIdentityFields(): readonly string[];
12
+ get configurationIdentityProbeFields(): readonly string[];
13
+ get configurationUpdateFields(): readonly string[];
14
+ protected validateConfiguration(config: NapCatEndpointConfig): void;
15
+ protected identifyConfiguration(input: NapCatEndpointConfig, signal: AbortSignal): Promise<string | undefined>;
16
+ protected createEndpoint(input: NapCatEndpointConfig, execution: EndpointCreationContext): NapcatEndpoint;
17
+ }
18
+ declare module '@zhin.js/feature-kit' {
19
+ interface AdapterRegistry {
20
+ readonly napcat: NapcatAdapter;
21
+ }
22
+ }
23
+ export {};
package/lib/adapter.js ADDED
@@ -0,0 +1,42 @@
1
+ import { Adapter } from 'zhin.js/adapter';
2
+ import { httpHostToken } from '@zhin.js/host-http';
3
+ import { callNapCatHttpAction, resolveNapCatConfig } from './protocol.js';
4
+ import { NapCatWsEndpoint } from './ws-endpoint.js';
5
+ import { NapCatWssEndpoint } from './wss-endpoint.js';
6
+ import { NapCatHttpEndpoint } from './http-endpoint.js';
7
+ import { probeNapcatIdentity } from './identity.js';
8
+ export class NapcatAdapter extends Adapter {
9
+ #context;
10
+ constructor(context) { super(); this.#context = context; }
11
+ get configurationIdentityFields() { return ['id']; }
12
+ get configurationIdentityProbeFields() { return ['connection', 'access_token', 'url', 'http_url']; }
13
+ get configurationUpdateFields() {
14
+ return ['connection', 'url', 'path', 'http_url', 'post_path', 'access_token', 'reconnect_interval', 'heartbeat_interval', 'poll_interval'];
15
+ }
16
+ validateConfiguration(config) { resolveNapCatConfig(config); }
17
+ async identifyConfiguration(input, signal) {
18
+ const config = resolveNapCatConfig(input);
19
+ if (config.connection === 'ws')
20
+ return probeNapcatIdentity(config, signal);
21
+ if (config.connection === 'wss')
22
+ return undefined;
23
+ signal.throwIfAborted();
24
+ const response = await callNapCatHttpAction({ ...config, signal }, 'get_login_info');
25
+ signal.throwIfAborted();
26
+ const data = response.data;
27
+ if (data?.user_id === 0 || data?.user_id === '0' || (typeof data?.user_id === 'string' && !data.user_id.trim()))
28
+ return undefined;
29
+ if ((typeof data?.user_id !== 'string' && typeof data?.user_id !== 'number') || !String(data.user_id).trim()) {
30
+ throw new Error('NapCat login identity is unavailable');
31
+ }
32
+ return `qq:${data.user_id}`;
33
+ }
34
+ createEndpoint(input, execution) {
35
+ const config = resolveNapCatConfig(input), id = execution.canonicalId, signal = execution.signal;
36
+ switch (config.connection) {
37
+ case 'wss': return new NapCatWssEndpoint({ id, signal, config, http: this.#context.use(httpHostToken) });
38
+ case 'http': return new NapCatHttpEndpoint({ id, signal, config, http: this.#context.use(httpHostToken) });
39
+ case 'ws': return new NapCatWsEndpoint({ id, signal, config });
40
+ }
41
+ }
42
+ }
package/lib/client.d.ts CHANGED
@@ -1,15 +1,61 @@
1
- import type { NapCatEvent } from './protocol.js';
1
+ import { EventEmitter } from 'node:events';
2
+ import { callNapCatHttpAction, type NapCatEvent, type ResolvedNapCatConfig } from './protocol.js';
3
+ import { type NapCatRpc } from './ws-transport.js';
4
+ import type { PendingRpcRequest } from 'zhin.js/adapter';
5
+ import type { NapCatWsSocket } from './ws-types.js';
2
6
  export type NapcatApiCall = (action: string, params?: Record<string, unknown>) => Promise<unknown>;
7
+ /** Platform actions use one named payload; wire field names stay inside this Client. */
8
+ export interface NapcatMemberTitleRequest {
9
+ readonly groupId: number;
10
+ readonly userId: number;
11
+ readonly title: string;
12
+ /** Platform duration; omission retains the existing indefinite value (-1). */
13
+ readonly duration?: number;
14
+ }
15
+ export interface NapcatProfileRequest {
16
+ readonly nickname: string;
17
+ readonly company?: string;
18
+ readonly email?: string;
19
+ readonly college?: string;
20
+ readonly personalNote?: string;
21
+ }
22
+ export interface NapcatGroupFileRequest {
23
+ readonly groupId: number;
24
+ readonly file: string;
25
+ readonly name: string;
26
+ readonly folder?: string;
27
+ }
28
+ export interface NapcatMiniAppRequest {
29
+ readonly type: string;
30
+ readonly title: string;
31
+ readonly desc: string;
32
+ readonly picUrl: string;
33
+ readonly jumpUrl: string;
34
+ }
35
+ export interface NapcatClientOptions {
36
+ readonly config: ResolvedNapCatConfig;
37
+ readonly httpAction?: typeof callNapCatHttpAction;
38
+ readonly signal?: AbortSignal;
39
+ }
3
40
  /** Transport-independent NapCat protocol Client produced by every Endpoint mode. */
4
- export declare class NapcatClient {
41
+ export declare class NapcatClient extends EventEmitter<Record<string, [NapCatEvent]>> {
42
+ #private;
43
+ protected transportSocket?: NapCatWsSocket;
44
+ protected readonly rpc: NapCatRpc;
45
+ protected readonly protocolConfig: ResolvedNapCatConfig;
46
+ constructor(options: NapcatClientOptions);
47
+ ingest(event: NapCatEvent): void;
48
+ protected get actionSocket(): NapCatWsSocket | undefined;
49
+ /** Existing platform methods retain their native action/params calling convention. */
5
50
  readonly callApi: NapcatApiCall;
6
- constructor(callApi: NapcatApiCall);
7
- setTitle(groupId: number, userId: number, title: string, duration?: number): Promise<boolean>;
51
+ /** A semantic operation supplies its caller lifetime to the same native protocol owner. */
52
+ requestApi(request: PendingRpcRequest): Promise<unknown>;
53
+ setTitle({ groupId, userId, title, duration }: NapcatMemberTitleRequest): Promise<boolean>;
8
54
  sendLike(userId: number, times?: number): Promise<unknown>;
9
55
  deleteFriend(userId: number): Promise<unknown>;
10
56
  markMsgAsRead(messageId: number): Promise<unknown>;
11
57
  ocrImage(image: string): Promise<unknown>;
12
- setQQProfile(nickname: string, company?: string, email?: string, college?: string, personalNote?: string): Promise<unknown>;
58
+ setQQProfile({ nickname, company, email, college, personalNote }: NapcatProfileRequest): Promise<unknown>;
13
59
  setGroupPortrait(groupId: number, file: string): Promise<unknown>;
14
60
  setEssenceMsg(messageId: number): Promise<unknown>;
15
61
  deleteEssenceMsg(messageId: number): Promise<unknown>;
@@ -18,7 +64,7 @@ export declare class NapcatClient {
18
64
  sendGroupNotice(groupId: number, content: string, image?: string): Promise<unknown>;
19
65
  getGroupNotice(groupId: number): Promise<unknown>;
20
66
  deleteGroupNotice(groupId: number, noticeId: string): Promise<unknown>;
21
- uploadGroupFile(groupId: number, file: string, name: string, folder?: string): Promise<unknown>;
67
+ uploadGroupFile({ groupId, file, name, folder }: NapcatGroupFileRequest): Promise<unknown>;
22
68
  getGroupRootFiles(groupId: number): Promise<unknown>;
23
69
  getGroupFileUrl(groupId: number, fileId: string, busid: number): Promise<unknown>;
24
70
  downloadFile(url: string, threadCount?: number, headers?: string[]): Promise<unknown>;
@@ -36,17 +82,8 @@ export declare class NapcatClient {
36
82
  sendPoke(userId: number, groupId?: number): Promise<unknown>;
37
83
  ncGetUserStatus(userId: number): Promise<unknown>;
38
84
  getGroupShutList(groupId: number): Promise<unknown>;
39
- getMiniAppArk(type: string, title: string, desc: string, picUrl: string, jumpUrl: string): Promise<unknown>;
85
+ getMiniAppArk({ type, title, desc, picUrl, jumpUrl }: NapcatMiniAppRequest): Promise<unknown>;
40
86
  getAiCharacters(groupId: number): Promise<unknown>;
41
87
  sendGroupAiRecord(groupId: number, characterId: string, text: string): Promise<unknown>;
42
88
  }
43
89
  export type NapcatClientEventMap = Record<string, NapCatEvent>;
44
- declare module '@zhin.js/feature-kit' {
45
- interface AdapterClientRegistry {
46
- readonly napcat: {
47
- readonly client: NapcatClient;
48
- readonly events: NapcatClientEventMap;
49
- };
50
- }
51
- }
52
- export declare const napcatClient: import("@zhin.js/adapter").EndpointClientToken<NapcatClient, NapcatClientEventMap>;
package/lib/client.js CHANGED
@@ -1,11 +1,55 @@
1
- import { defineEndpointClient } from 'zhin.js/adapter';
1
+ import { EventEmitter } from 'node:events';
2
+ import { callNapCatHttpAction, readNapCatActionResponse } from './protocol.js';
3
+ import { createNapCatRpc } from './ws-transport.js';
4
+ import { EndpointDeliveryError } from '@zhin.js/im-contract';
2
5
  /** Transport-independent NapCat protocol Client produced by every Endpoint mode. */
3
- export class NapcatClient {
4
- callApi;
5
- constructor(callApi) {
6
- this.callApi = callApi;
6
+ export class NapcatClient extends EventEmitter {
7
+ transportSocket;
8
+ rpc;
9
+ protocolConfig;
10
+ #httpAction;
11
+ #executionSignal;
12
+ constructor(options) {
13
+ super();
14
+ this.protocolConfig = options.config;
15
+ this.#httpAction = options.httpAction ?? callNapCatHttpAction;
16
+ this.#executionSignal = options.signal;
17
+ this.rpc = createNapCatRpc({ endpointId: options.config.id, signal: options.signal,
18
+ socket: () => this.actionSocket });
7
19
  }
8
- async setTitle(groupId, userId, title, duration = -1) {
20
+ ingest(event) {
21
+ this.emit('event', event);
22
+ const name = [event.post_type, event.message_type ?? event.notice_type ?? event.request_type, event.sub_type].filter(Boolean).join('.');
23
+ if (name && name !== 'event')
24
+ this.emit(name, event);
25
+ }
26
+ get actionSocket() { return this.transportSocket; }
27
+ /** Existing platform methods retain their native action/params calling convention. */
28
+ callApi = (action, params = {}) => this.requestApi({ action, params });
29
+ /** A semantic operation supplies its caller lifetime to the same native protocol owner. */
30
+ async requestApi(request) {
31
+ const signals = [this.#executionSignal, request.signal].filter((signal) => !!signal);
32
+ const signal = signals.length ? AbortSignal.any(signals) : undefined;
33
+ if (signal?.aborted)
34
+ throw new EndpointDeliveryError('endpoint_inactive', 'Endpoint operation ended', 'not_sent');
35
+ if (this.protocolConfig.connection === 'http') {
36
+ try {
37
+ const response = await this.#httpAction({ http_url: this.protocolConfig.http_url,
38
+ access_token: this.protocolConfig.access_token, signal }, request.action, request.params ?? {});
39
+ if (signal?.aborted)
40
+ throw new EndpointDeliveryError('endpoint_inactive', 'Endpoint operation cancelled', 'unknown');
41
+ return readNapCatActionResponse(response).data;
42
+ }
43
+ catch (cause) {
44
+ if (cause instanceof EndpointDeliveryError)
45
+ throw cause;
46
+ throw new EndpointDeliveryError('delivery_unconfirmed', cause instanceof Error ? cause.message : String(cause), 'unknown', { cause });
47
+ }
48
+ }
49
+ const response = await this.rpc.call({ ...request, signal });
50
+ return readNapCatActionResponse(response).data;
51
+ }
52
+ async setTitle({ groupId, userId, title, duration = -1 }) {
9
53
  await this.callApi('set_group_special_title', {
10
54
  group_id: groupId,
11
55
  user_id: userId,
@@ -18,7 +62,7 @@ export class NapcatClient {
18
62
  deleteFriend(userId) { return this.callApi('delete_friend', { user_id: userId }); }
19
63
  markMsgAsRead(messageId) { return this.callApi('mark_msg_as_read', { message_id: messageId }); }
20
64
  ocrImage(image) { return this.callApi('ocr_image', { image }); }
21
- setQQProfile(nickname, company, email, college, personalNote) {
65
+ setQQProfile({ nickname, company, email, college, personalNote }) {
22
66
  return this.callApi('set_qq_profile', { nickname, company, email, college, personal_note: personalNote });
23
67
  }
24
68
  setGroupPortrait(groupId, file) { return this.callApi('set_group_portrait', { group_id: groupId, file }); }
@@ -29,7 +73,7 @@ export class NapcatClient {
29
73
  sendGroupNotice(groupId, content, image) { return this.callApi('_send_group_notice', { group_id: groupId, content, image }); }
30
74
  getGroupNotice(groupId) { return this.callApi('_get_group_notice', { group_id: groupId }); }
31
75
  deleteGroupNotice(groupId, noticeId) { return this.callApi('_del_group_notice', { group_id: groupId, notice_id: noticeId }); }
32
- uploadGroupFile(groupId, file, name, folder) { return this.callApi('upload_group_file', { group_id: groupId, file, name, folder }); }
76
+ uploadGroupFile({ groupId, file, name, folder }) { return this.callApi('upload_group_file', { group_id: groupId, file, name, folder }); }
33
77
  getGroupRootFiles(groupId) { return this.callApi('get_group_root_files', { group_id: groupId }); }
34
78
  getGroupFileUrl(groupId, fileId, busid) { return this.callApi('get_group_file_url', { group_id: groupId, file_id: fileId, busid }); }
35
79
  downloadFile(url, threadCount = 1, headers) { return this.callApi('download_file', { url, thread_count: threadCount, headers }); }
@@ -53,10 +97,9 @@ export class NapcatClient {
53
97
  sendPoke(userId, groupId) { return this.callApi('send_poke', { user_id: userId, group_id: groupId }); }
54
98
  ncGetUserStatus(userId) { return this.callApi('nc_get_user_status', { user_id: userId }); }
55
99
  getGroupShutList(groupId) { return this.callApi('get_group_shut_list', { group_id: groupId }); }
56
- getMiniAppArk(type, title, desc, picUrl, jumpUrl) { return this.callApi('get_mini_app_ark', { type, title, desc, picUrl, jumpUrl }); }
100
+ getMiniAppArk({ type, title, desc, picUrl, jumpUrl }) { return this.callApi('get_mini_app_ark', { type, title, desc, picUrl, jumpUrl }); }
57
101
  getAiCharacters(groupId) { return this.callApi('get_ai_characters', { group_id: groupId }); }
58
102
  sendGroupAiRecord(groupId, characterId, text) {
59
103
  return this.callApi('send_group_ai_record', { group_id: groupId, character: characterId, text });
60
104
  }
61
105
  }
62
- export const napcatClient = defineEndpointClient('napcat');
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 createNapcatConsoleRpc(resources: AdapterConsoleResources, getConfig: () => unknown): PluginConsoleRpc;
8
+ export declare function createNapcatConsoleRpc(_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 { napcatRuntimeStateToken } from './napcat-runtime-state.js';
8
7
  import { napcatConsoleSpec } from './console-spec.js';
9
- export function createNapcatConsoleRpc(resources, getConfig) {
10
- const state = resources.use(napcatRuntimeStateToken);
8
+ export function createNapcatConsoleRpc(_resources, getConfig) {
11
9
  return createAdapterConsoleRpc({
12
10
  ...napcatConsoleSpec,
13
- running: () => state.endpoints.values(),
14
11
  getConfig,
15
- }, resources);
12
+ });
16
13
  }
@@ -7,9 +7,9 @@
7
7
  * - group → {group_id:number, name: group_name ?? name}
8
8
  * - 群成员列表保持 OneBot11 原生形状,仅保证数组
9
9
  */
10
- import type { EndpointManagement } from 'zhin.js/adapter';
10
+ import { type PendingRpcRequest, type EndpointManagement } from 'zhin.js/adapter';
11
11
  /** 管理面只依赖 endpoint 的 callApi(ws/wss/http 三种传输各自实现)。 */
12
12
  export interface NapCatManagementCaller {
13
- callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
13
+ requestApi(request: PendingRpcRequest): Promise<unknown>;
14
14
  }
15
15
  export declare function createNapCatEndpointManagement(endpoint: NapCatManagementCaller): EndpointManagement;