@zhin.js/adapter-wechat-mp 3.0.2 → 4.0.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 CHANGED
@@ -1,5 +1,57 @@
1
1
  # @zhin.js/adapter-wechat-mp
2
2
 
3
+ ## 4.0.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 7db69c1: 命令前缀改为适配器配置项:`MessageDispatcher` 不再硬编码 `/`,默认按消息所属适配器实例 config 的 `commandPrefix` 解析(默认 `''` 无前缀,任意文本按命令匹配),`endpoints[i].commandPrefix` 逐项覆盖;`ImRuntime({ commandPrefix })` 仍可设全局静态前缀。全部 20 个平台适配器 schema 新增 `commandPrefix` 属性。
8
+
9
+ BREAKING(行为变化):未配置时命令不再需要 `/` 前缀——原 `/zt` 写法不再命中,直接发 `zt` 即可;需要斜杠风格的适配器请在配置里显式设 `commandPrefix: '/'`。
10
+
11
+ - 713445c: 适配器配置格式定稿(不兼容旧格式):`plugins.<adapter>` 顶层仅共享字段 + `commandPrefix`,`endpoints[i]` 携带 endpoint 级字段(`name` + 凭据,各 schema 已类型化),`endpoints` 为必填(icqq 另需顶层 `master`);icqq 新增 `trusted` 列表(顶层/逐项均可)。scaffold-wizard 全部字段式与自定义 configure() 产出改为新格式,examples(full-bot / qq-games-bot)与 20 个适配器 README 同步迁移。
12
+ - Updated dependencies [7db69c1]
13
+ - Updated dependencies [e5c84ed]
14
+ - Updated dependencies [3ea84a0]
15
+ - Updated dependencies [1ddcd70]
16
+ - Updated dependencies [ac9da66]
17
+ - @zhin.js/core@1.4.0
18
+ - @zhin.js/adapter@1.1.0
19
+ - @zhin.js/plugin-runtime@1.1.0
20
+ - @zhin.js/host-http@1.0.2
21
+ - zhin.js@5.0.0
22
+
23
+ ## 3.0.3
24
+
25
+ ### Patch Changes
26
+
27
+ - cc5c94d: 约定式插件运行时迁移(breaking):插件与适配器由 `usePlugin()` / `extends Adapter` 迁移为 `definePlugin` / `defineAdapter` + `plugin.ts` + 约定目录(`adapters/`、`commands/`、`components/`、`tools/` 等)。
28
+
29
+ - 新增约定式运行时包:`@zhin.js/plugin-runtime`、`@zhin.js/adapter`、`@zhin.js/runtime`、`@zhin.js/host-http`(首版 1.0.0 走 init-publish,不在本 changeset 内 bump)。
30
+ - 全部 20 个平台适配器改为约定式 `defineAdapter`,旧 `usePlugin` / `extends Adapter` / `segment-mapper` 生产入口已删除;onebot11 反向 WSS、onebot12 webhook/wss、milky sse/webhook/wss、satori webhook、kook webhook、qq webhook/middleware 等 slice 1 推迟的连接模式已补齐。
31
+ - 游戏 / 工具 / 服务插件同步迁移到约定目录结构。
32
+ - CLI 增加 plugin-runtime host installer(http/database/outbound/schedule/console 等)。
33
+
34
+ 后续加固(同批):
35
+
36
+ - CLI:`zhin runtime start --daemon`(pidfile/崩溃拉起/风暴保护),orphan watchdog 防僵尸进程;legacy `zhin dev` / `zhin start` 已移除(含 `zhin restart`),`zhin stop` 兼容新 daemon。
37
+ - 安全:builtin 工具统一走 `security/policy-facade.ts` 的 `runToolPolicies`(声明式策略表,deny 优先);审计日志 close flush + 背压队列;`splitCompoundCommand` 引号感知、`extractCommandName` 去引号堵绕过。
38
+ - 日志:Logger 双堆栈修复、本地时区、`getLogger` 挂树(`setLevel` 递归生效)、第三方库(log4js/discord)桥接、启动人读总结。
39
+ - 结构:`plugins/games/shared` 迁为 `packages/game-kit`(`@zhin.js/game-kit`);死目录 `plugins/adapters/common` 删除。
40
+ - 脚手架:`create-zhin-app` / `zhin new` / scaffold-wizard 生成物改为 Plugin Runtime 形态(minimal-bot 同构,新配置格式)。
41
+ - Console:endpoint.list 真实名称与 phase、schema:get-all 按 instanceKey 映射、db:\* 接 DatabaseHost。
42
+
43
+ 注:按仓库发布惯例(见 1bb345dd2),本次 breaking 迁移统一使用 patch,避免 zhin.js 5.0 级联。
44
+
45
+ - Updated dependencies [16ec4e8]
46
+ - Updated dependencies [cc5c94d]
47
+ - Updated dependencies [447f3e2]
48
+ - @zhin.js/core@1.3.5
49
+ - @zhin.js/host-http@1.0.1
50
+ - zhin.js@4.1.3
51
+ - @zhin.js/logger@1.0.75
52
+ - @zhin.js/plugin-runtime@1.0.1
53
+ - @zhin.js/adapter@1.0.1
54
+
3
55
  ## 3.0.2
4
56
 
5
57
  ### Patch Changes
package/README.md CHANGED
@@ -1,14 +1,14 @@
1
1
  # @zhin.js/adapter-wechat-mp
2
2
 
3
- Zhin.js 微信公众号适配器,支持微信公众号的消息收发。
3
+ Zhin.js 微信公众号适配器(Plugin Runtime),通过 Runtime Host HTTP Webhook 收发消息。
4
4
 
5
5
  ## 功能特性
6
6
 
7
- - Webhook 事件接收(HTTP 回调)
8
- - 签名验证
7
+ - Webhook 事件接收(`httpHostToken` GET 验签 + POST 消息)
8
+ - 签名验证与可选 AES 加解密
9
9
  - Access Token 自动刷新
10
10
  - XML 消息解析
11
- - 可选消息加密(AES)
11
+ - 约定式 `defineAdapter` / `definePlugin`(无需 `usePlugin`)
12
12
 
13
13
  ## 安装
14
14
 
@@ -16,105 +16,53 @@ Zhin.js 微信公众号适配器,支持微信公众号的消息收发。
16
16
  pnpm add @zhin.js/adapter-wechat-mp
17
17
  ```
18
18
 
19
+ ## Plugin Runtime
20
+
21
+ - `@zhin.js/adapter` — 约定式 `adapters/wechat-mp.ts`(`defineAdapter`)
22
+ - `@zhin.js/core` — `messageGatewayToken` 入站/出站
23
+ - `@zhin.js/host-http` — `httpHostToken` 注册 Webhook 路由(**非** legacy host-router/Koa)
24
+ - `@zhin.js/plugin-runtime` — `plugin.ts`(`definePlugin`)
25
+ - 配置经插件 `schema.json` 落到 `plugins.<instanceKey>`
26
+
27
+ 入站:`gateway.receive({ adapter, target: openid, content: text, sender, metadata })`
28
+ 出站:`send({ target, payload })` → 被动回复 XML(默认)或客服消息 API(`replyMode: customer_service`)
29
+
19
30
  ## 前置条件
20
31
 
21
32
  | 要求 | 说明 |
22
33
  |------|------|
23
34
  | **公众号** | 已注册微信公众号,并在 [微信公众平台](https://mp.weixin.qq.com/) 获取 `AppID`、`AppSecret` |
24
35
  | **服务器配置** | 配置 Token(与 `token` 字段一致);服务器 URL 须公网可访问 |
25
- | **host-router** | **必需** — 适配器在 `path` 上注册 GET/POST Webhook 路由 |
36
+ | **host-http** | **必需** — Runtime Host 提供 HTTP;适配器在 `path` 上注册 GET/POST |
26
37
  | **响应时限** | 微信要求 **5 秒内**响应;超时会导致接入失败 |
27
- | **回复模式** | 默认 `replyMode: passive`(订阅号被动回复,在 webhook 响应里返回 XML);服务号可设 `customer_service` 走客服 API |
28
- | **消息加密** | 可选;`encrypt: true` + `encodingAESKey`;`encryptMode: compatible`(默认,被动回复明文)或 `secure`(被动回复也加密) |
38
+ | **回复模式** | 默认 `replyMode: passive`(订阅号被动回复);服务号可设 `customer_service` |
39
+ | **消息加密** | 可选;`encrypt: true` + `encodingAESKey`;`encryptMode: compatible`(默认)或 `secure` |
29
40
 
30
- 必填字段见 `WeChatMPConfig`:`context`、`name`、`appId`、`appSecret`、`token`、`path`。
41
+ 必填字段(`endpoints[i]`):`name`、`appId`、`appSecret`、`token`。
31
42
 
32
43
  ## 最小配置
33
44
 
34
45
  ```yaml
46
+ # zhin.config.yml(Plugin Runtime)
35
47
  plugins:
36
- - "@zhin.js/adapter-wechat-mp"
37
- - "@zhin.js/host-router"
38
-
39
- endpoints:
40
- - context: wechat-mp
41
- name: my-wechat-bot
42
- appId: "${WECHAT_APP_ID}"
43
- appSecret: "${WECHAT_APP_SECRET}"
44
- token: "${WECHAT_TOKEN}"
48
+ wechat-mp:
45
49
  path: /wechat/webhook
50
+ endpoints:
51
+ - name: my-wechat-bot
52
+ appId: "${WECHAT_APP_ID}"
53
+ appSecret: "${WECHAT_APP_SECRET}"
54
+ token: "${WECHAT_TOKEN}"
46
55
  ```
47
56
 
48
- ## 依赖
49
-
50
- - `@zhin.js/host-router` — HTTP 服务(提供 Webhook 路由)
51
-
52
- ## 配置
53
-
54
- ### TypeScript 配置
57
+ 根插件 `zhin.plugins`(或项目图)需引用 `@zhin.js/adapter-wechat-mp`(`instanceKey: wechat-mp`)。
58
+ Runtime Host(`http`)须已 listen,Webhook 才可达。
55
59
 
56
- 完整选项示例(含可选加密字段):
57
-
58
- ```yaml
59
- endpoints:
60
- - context: wechat-mp
61
- name: my-wechat-bot
62
- appId: ${WECHAT_APP_ID}
63
- appSecret: ${WECHAT_APP_SECRET}
64
- token: ${WECHAT_TOKEN}
65
- path: /wechat/webhook
66
- # encodingAESKey: your-aes-key
67
- # encrypt: false
68
- ```
69
-
70
- ```typescript
71
- import { defineConfig } from 'zhin.js'
72
-
73
- export default defineConfig({
74
- endpoints: [
75
- {
76
- context: 'wechat-mp',
77
- name: 'my-wechat-bot',
78
- appId: process.env.WECHAT_APP_ID!,
79
- appSecret: process.env.WECHAT_APP_SECRET!,
80
- token: process.env.WECHAT_TOKEN!,
81
- path: '/wechat/webhook',
82
- }
83
- ],
84
- plugins: ['@zhin.js/adapter-wechat-mp', '@zhin.js/host-router']
85
- })
86
- ```
60
+ ### 可选字段
87
61
 
88
- ## 使用示例
89
-
90
- ### 注册命令
91
-
92
- ```typescript
93
- import { usePlugin, MessageCommand } from 'zhin.js'
94
-
95
- const { addCommand } = usePlugin()
96
-
97
- addCommand(
98
- new MessageCommand('hello')
99
- .desc('微信问候')
100
- .action((message) => `你好,${message.$sender.name}!`)
101
- )
102
- ```
103
-
104
- ### 消息中间件
105
-
106
- ```typescript
107
- import { usePlugin } from 'zhin.js'
108
-
109
- const { root } = usePlugin()
110
-
111
- root.addMiddleware(async (message, next) => {
112
- if (message.$adapter === 'wechat-mp') {
113
- console.log('收到微信消息:', message.$content)
114
- }
115
- await next()
116
- })
117
- ```
62
+ - `path`:Webhook 路径,默认 `/wechat/webhook`
63
+ - `replyMode`:`passive`(默认)| `customer_service`
64
+ - `passiveReplyTimeoutMs`:被动回复等待上限,默认 `4500`
65
+ - `encrypt` / `encodingAESKey` / `encryptMode`
118
66
 
119
67
  ## 微信公众号配置
120
68
 
@@ -128,16 +76,15 @@ root.addMiddleware(async (message, next) => {
128
76
 
129
77
  | 现象 | 排查 |
130
78
  |------|------|
131
- | 服务器配置验证失败 | `token` 与公众平台一致;URL 为 `https://<host>/wechat/webhook`;Host 已启动且公网可达 |
132
- | 收不到用户消息 | 公众号类型是否支持消息接口;用户是否已关注;`path` 与公众平台 URL 一致 |
133
- | 回复超时 / 无回复 | 默认被动回复须在 **~4.5s** 内完成;AI 过慢会返回 `success` 无正文,可改 `replyMode: customer_service`(需客服接口权限) |
79
+ | 服务器配置验证失败 | `token` 与公众平台一致;URL 为 `https://<host>/wechat/webhook`;Runtime Host listen 且公网可达 |
80
+ | 收不到用户消息 | 公众号类型是否支持消息接口;用户是否已关注;`path` 与公众平台 URL 一致;endpoint 已 `open()` |
81
+ | 回复超时 / 无回复 | 默认被动回复须在 **~4.5s** 内完成;可改 `replyMode: customer_service`(需客服接口权限) |
134
82
  | `48001 api unauthorized` | 未认证订阅号无客服 API;保持默认 `replyMode: passive` |
135
83
  | 加密模式报错 | `encodingAESKey`、`encrypt` 与公众平台「安全模式」设置一致 |
136
84
 
137
85
  ## AI 工具
138
86
 
139
- 技能说明见 `agent/skills/wechat-mp.md`。群管与平台工具按公众号能力在 `src/index.ts` 注册。
140
-
87
+ 技能说明见 `agent/skills/wechat-mp.md`。
141
88
 
142
89
  ## 文档链接
143
90
 
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Convention entry: discover `adapters/wechat-mp.ts` → defineAdapter.
3
+ */
4
+ import { defineAdapter } from '@zhin.js/adapter';
5
+ import { messageGatewayToken } from '@zhin.js/core/runtime';
6
+ import { httpHostToken } from '@zhin.js/host-http';
7
+ import { WeChatMpEndpoint } from '../src/endpoint.js';
8
+ import {
9
+ resolveWeChatMpConfig,
10
+ type WeChatMpAdapterConfig,
11
+ } from '../src/protocol.js';
12
+
13
+ export { WeChatMpEndpoint } from '../src/endpoint.js';
14
+ export type { WeChatMpEndpointOptions, WeChatMpFetch } from '../src/endpoint.js';
15
+
16
+ export default defineAdapter<WeChatMpAdapterConfig>({
17
+ capabilities: ['inbound', 'outbound'],
18
+ create(context) {
19
+ return new WeChatMpEndpoint({
20
+ id: context.id,
21
+ gateway: context.use(messageGatewayToken),
22
+ http: context.use(httpHostToken),
23
+ config: resolveWeChatMpConfig(context.config),
24
+ });
25
+ },
26
+ });
package/lib/endpoint.d.ts CHANGED
@@ -1,73 +1,38 @@
1
- import { EventEmitter } from "events";
2
- import { Endpoint, Message, MessageSegment, SendOptions } from 'zhin.js';
3
- import { type Router } from "@zhin.js/host-router/router";
4
- import type { WeChatMPConfig, WeChatMessage } from "./types.js";
5
- import type { WeChatMPAdapter } from "./adapter.js";
6
- export declare class WeChatMPEndpoint extends EventEmitter implements Endpoint<WeChatMPConfig, WeChatMessage> {
7
- adapter: WeChatMPAdapter;
8
- $config: WeChatMPConfig;
9
- $connected: boolean;
10
- router: Router;
11
- private accessToken;
12
- private tokenExpireTime;
13
- get logger(): import("zhin.js").Logger;
14
- get $id(): string;
15
- constructor(adapter: WeChatMPAdapter, router: Router, config: WeChatMPConfig);
16
- private setupRoutes;
17
- $connect(): Promise<void>;
18
- $disconnect(): Promise<void>;
19
- private handleVerification;
20
- private handleMessage;
21
- private computeSignatureHash;
22
- private verifySignature;
23
- private parseXMLMessage;
24
- $formatMessage(wechatMsg: WeChatMessage): Message<WeChatMessage>;
25
- static parseMessageContent(wechatMsg: WeChatMessage): MessageSegment[];
26
- $sendMessage(options: SendOptions): Promise<string>;
27
- $recallMessage(id: string): Promise<void>;
28
- private sendCustomerServiceMessage;
29
- private formatSendContent;
30
- private getReplyMode;
31
- private getEncryptMode;
32
- private usesPassiveReply;
33
- private extractSendText;
34
- private collectPassiveReplyXml;
35
- private handlePassiveReply;
36
- private buildTextReply;
37
- private refreshAccessToken;
38
- private tokenRefreshTimer?;
39
- private startTokenRefreshTimer;
40
- getUserInfo(openid: string): Promise<any>;
41
- /**
42
- * 上传多媒体文件到微信服务器
43
- * @param type 媒体类型:image(图片)、voice(语音)、video(视频)、thumb(缩略图)
44
- * @param buffer 文件 Buffer
45
- * @param filename 文件名(可选,用于确定文件类型)
46
- * @returns 微信服务器返回的 media_id
47
- */
48
- uploadMedia(type: 'image' | 'voice' | 'video' | 'thumb', buffer: Buffer, filename?: string): Promise<string>;
49
- /**
50
- * 获取文件扩展名
51
- */
52
- private getFileExtension;
53
- /**
54
- * 获取 Content-Type
55
- */
56
- private getContentType;
57
- private getAESKey;
58
- /** 微信安全模式加密 echostr 为较长 Base64;明文/兼容模式多为短字符串 */
59
- private isEncryptedEchostr;
60
- /**
61
- * 解密安全模式 URL 验证中的 echostr
62
- */
63
- private decryptEchostr;
64
- /**
65
- * 解密微信推送的加密消息
66
- */
67
- private decryptMessage;
68
- /**
69
- * 加密被动回复消息
70
- */
71
- private encryptMessage;
1
+ import type { EndpointInstance } from '@zhin.js/adapter';
2
+ import type { MessageGateway } from '@zhin.js/core/runtime';
3
+ import type { HttpHost } from '@zhin.js/host-http';
4
+ import type { CapabilityId } from '@zhin.js/plugin-runtime';
5
+ import { type ResolvedWeChatMpConfig, type WeChatMessage } from './protocol.js';
6
+ export type WeChatMpFetch = (url: string, init?: {
7
+ readonly method?: string;
8
+ readonly body?: unknown;
9
+ readonly headers?: Record<string, string>;
10
+ }) => Promise<{
11
+ readonly data: unknown;
12
+ }>;
13
+ export interface WeChatMpEndpointOptions {
14
+ readonly id: CapabilityId;
15
+ readonly gateway: MessageGateway;
16
+ readonly http: HttpHost;
17
+ readonly config: ResolvedWeChatMpConfig;
18
+ readonly fetch?: WeChatMpFetch;
19
+ }
20
+ export declare class WeChatMpEndpoint implements EndpointInstance {
21
+ #private;
22
+ constructor(options: WeChatMpEndpointOptions);
23
+ /** Used by webhook handler. */
24
+ get isOpen(): boolean;
25
+ get config(): ResolvedWeChatMpConfig;
26
+ get id(): CapabilityId;
27
+ get gateway(): MessageGateway;
28
+ start(): Promise<void>;
29
+ open(): void;
30
+ close(): void;
31
+ stop(): Promise<void>;
32
+ send({ target, payload }: {
33
+ readonly target: string;
34
+ readonly payload: unknown;
35
+ }): Promise<string>;
36
+ /** Test / internal: admit a parsed message when open (non-webhook path). */
37
+ admit(msg: WeChatMessage): void;
72
38
  }
73
- //# sourceMappingURL=endpoint.d.ts.map