@zhin.js/adapter-wechat-mp 3.0.2 → 3.0.3
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 +32 -0
- package/README.md +32 -86
- package/adapters/wechat-mp.ts +26 -0
- package/lib/endpoint.d.ts +37 -72
- package/lib/endpoint.js +126 -757
- package/lib/index.d.ts +4 -15
- package/lib/index.js +4 -25
- package/lib/passive-reply.d.ts +0 -1
- package/lib/passive-reply.js +0 -1
- package/lib/protocol.d.ts +118 -0
- package/lib/protocol.js +324 -0
- package/lib/webhook.d.ts +19 -0
- package/lib/webhook.js +149 -0
- package/package.json +38 -11
- package/plugin.ts +8 -0
- package/schema.json +38 -0
- package/src/endpoint.ts +176 -918
- package/src/index.ts +42 -36
- package/src/protocol.ts +477 -0
- package/src/webhook.ts +229 -0
- package/lib/adapter.d.ts +0 -16
- package/lib/adapter.d.ts.map +0 -1
- package/lib/adapter.js +0 -19
- package/lib/adapter.js.map +0 -1
- package/lib/endpoint.d.ts.map +0 -1
- package/lib/endpoint.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/passive-reply.d.ts.map +0 -1
- package/lib/passive-reply.js.map +0 -1
- package/lib/segment-mapper.d.ts +0 -2
- package/lib/segment-mapper.d.ts.map +0 -1
- package/lib/segment-mapper.js +0 -2
- package/lib/segment-mapper.js.map +0 -1
- package/lib/types.d.ts +0 -58
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js +0 -2
- package/lib/types.js.map +0 -1
- package/src/adapter.ts +0 -24
- package/src/segment-mapper.ts +0 -1
- package/src/types.ts +0 -60
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# @zhin.js/adapter-wechat-mp
|
|
2
2
|
|
|
3
|
+
## 3.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- cc5c94d: 约定式插件运行时迁移(breaking):插件与适配器由 `usePlugin()` / `extends Adapter` 迁移为 `definePlugin` / `defineAdapter` + `plugin.ts` + 约定目录(`adapters/`、`commands/`、`components/`、`tools/` 等)。
|
|
8
|
+
|
|
9
|
+
- 新增约定式运行时包:`@zhin.js/plugin-runtime`、`@zhin.js/adapter`、`@zhin.js/runtime`、`@zhin.js/host-http`(首版 1.0.0 走 init-publish,不在本 changeset 内 bump)。
|
|
10
|
+
- 全部 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 推迟的连接模式已补齐。
|
|
11
|
+
- 游戏 / 工具 / 服务插件同步迁移到约定目录结构。
|
|
12
|
+
- CLI 增加 plugin-runtime host installer(http/database/outbound/schedule/console 等)。
|
|
13
|
+
|
|
14
|
+
后续加固(同批):
|
|
15
|
+
|
|
16
|
+
- CLI:`zhin runtime start --daemon`(pidfile/崩溃拉起/风暴保护),orphan watchdog 防僵尸进程;legacy `zhin dev` / `zhin start` 已移除(含 `zhin restart`),`zhin stop` 兼容新 daemon。
|
|
17
|
+
- 安全:builtin 工具统一走 `security/policy-facade.ts` 的 `runToolPolicies`(声明式策略表,deny 优先);审计日志 close flush + 背压队列;`splitCompoundCommand` 引号感知、`extractCommandName` 去引号堵绕过。
|
|
18
|
+
- 日志:Logger 双堆栈修复、本地时区、`getLogger` 挂树(`setLevel` 递归生效)、第三方库(log4js/discord)桥接、启动人读总结。
|
|
19
|
+
- 结构:`plugins/games/shared` 迁为 `packages/game-kit`(`@zhin.js/game-kit`);死目录 `plugins/adapters/common` 删除。
|
|
20
|
+
- 脚手架:`create-zhin-app` / `zhin new` / scaffold-wizard 生成物改为 Plugin Runtime 形态(minimal-bot 同构,新配置格式)。
|
|
21
|
+
- Console:endpoint.list 真实名称与 phase、schema:get-all 按 instanceKey 映射、db:\* 接 DatabaseHost。
|
|
22
|
+
|
|
23
|
+
注:按仓库发布惯例(见 1bb345dd2),本次 breaking 迁移统一使用 patch,避免 zhin.js 5.0 级联。
|
|
24
|
+
|
|
25
|
+
- Updated dependencies [16ec4e8]
|
|
26
|
+
- Updated dependencies [cc5c94d]
|
|
27
|
+
- Updated dependencies [447f3e2]
|
|
28
|
+
- @zhin.js/core@1.3.5
|
|
29
|
+
- @zhin.js/host-http@1.0.1
|
|
30
|
+
- zhin.js@4.1.3
|
|
31
|
+
- @zhin.js/logger@1.0.75
|
|
32
|
+
- @zhin.js/plugin-runtime@1.0.1
|
|
33
|
+
- @zhin.js/adapter@1.0.1
|
|
34
|
+
|
|
3
35
|
## 3.0.2
|
|
4
36
|
|
|
5
37
|
### 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
|
|
8
|
-
-
|
|
7
|
+
- Webhook 事件接收(`httpHostToken` GET 验签 + POST 消息)
|
|
8
|
+
- 签名验证与可选 AES 加解密
|
|
9
9
|
- Access Token 自动刷新
|
|
10
10
|
- XML 消息解析
|
|
11
|
-
-
|
|
11
|
+
- 约定式 `defineAdapter` / `definePlugin`(无需 `usePlugin`)
|
|
12
12
|
|
|
13
13
|
## 安装
|
|
14
14
|
|
|
@@ -16,28 +16,36 @@ 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-
|
|
36
|
+
| **host-http** | **必需** — Runtime Host 提供 HTTP;适配器在 `path` 上注册 GET/POST |
|
|
26
37
|
| **响应时限** | 微信要求 **5 秒内**响应;超时会导致接入失败 |
|
|
27
|
-
| **回复模式** | 默认 `replyMode: passive
|
|
28
|
-
| **消息加密** | 可选;`encrypt: true` + `encodingAESKey`;`encryptMode: compatible
|
|
38
|
+
| **回复模式** | 默认 `replyMode: passive`(订阅号被动回复);服务号可设 `customer_service` |
|
|
39
|
+
| **消息加密** | 可选;`encrypt: true` + `encodingAESKey`;`encryptMode: compatible`(默认)或 `secure` |
|
|
29
40
|
|
|
30
|
-
|
|
41
|
+
必填字段:`appId`、`appSecret`、`token`。
|
|
31
42
|
|
|
32
43
|
## 最小配置
|
|
33
44
|
|
|
34
45
|
```yaml
|
|
46
|
+
# zhin.config.yml(Plugin Runtime)
|
|
35
47
|
plugins:
|
|
36
|
-
|
|
37
|
-
- "@zhin.js/host-router"
|
|
38
|
-
|
|
39
|
-
endpoints:
|
|
40
|
-
- context: wechat-mp
|
|
48
|
+
wechat-mp:
|
|
41
49
|
name: my-wechat-bot
|
|
42
50
|
appId: "${WECHAT_APP_ID}"
|
|
43
51
|
appSecret: "${WECHAT_APP_SECRET}"
|
|
@@ -45,76 +53,15 @@ endpoints:
|
|
|
45
53
|
path: /wechat/webhook
|
|
46
54
|
```
|
|
47
55
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
- `@zhin.js/host-router` — HTTP 服务(提供 Webhook 路由)
|
|
51
|
-
|
|
52
|
-
## 配置
|
|
53
|
-
|
|
54
|
-
### TypeScript 配置
|
|
56
|
+
根插件 `zhin.plugins`(或项目图)需引用 `@zhin.js/adapter-wechat-mp`(`instanceKey: wechat-mp`)。
|
|
57
|
+
Runtime Host(`http`)须已 listen,Webhook 才可达。
|
|
55
58
|
|
|
56
|
-
|
|
59
|
+
### 可选字段
|
|
57
60
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
```
|
|
87
|
-
|
|
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
|
-
```
|
|
61
|
+
- `path`:Webhook 路径,默认 `/wechat/webhook`
|
|
62
|
+
- `replyMode`:`passive`(默认)| `customer_service`
|
|
63
|
+
- `passiveReplyTimeoutMs`:被动回复等待上限,默认 `4500`
|
|
64
|
+
- `encrypt` / `encodingAESKey` / `encryptMode`
|
|
118
65
|
|
|
119
66
|
## 微信公众号配置
|
|
120
67
|
|
|
@@ -128,16 +75,15 @@ root.addMiddleware(async (message, next) => {
|
|
|
128
75
|
|
|
129
76
|
| 现象 | 排查 |
|
|
130
77
|
|------|------|
|
|
131
|
-
| 服务器配置验证失败 | `token` 与公众平台一致;URL 为 `https://<host>/wechat/webhook`;Host
|
|
132
|
-
| 收不到用户消息 | 公众号类型是否支持消息接口;用户是否已关注;`path` 与公众平台 URL
|
|
133
|
-
| 回复超时 / 无回复 | 默认被动回复须在 **~4.5s**
|
|
78
|
+
| 服务器配置验证失败 | `token` 与公众平台一致;URL 为 `https://<host>/wechat/webhook`;Runtime Host 已 listen 且公网可达 |
|
|
79
|
+
| 收不到用户消息 | 公众号类型是否支持消息接口;用户是否已关注;`path` 与公众平台 URL 一致;endpoint 已 `open()` |
|
|
80
|
+
| 回复超时 / 无回复 | 默认被动回复须在 **~4.5s** 内完成;可改 `replyMode: customer_service`(需客服接口权限) |
|
|
134
81
|
| `48001 api unauthorized` | 未认证订阅号无客服 API;保持默认 `replyMode: passive` |
|
|
135
82
|
| 加密模式报错 | `encodingAESKey`、`encrypt` 与公众平台「安全模式」设置一致 |
|
|
136
83
|
|
|
137
84
|
## AI 工具
|
|
138
85
|
|
|
139
|
-
技能说明见 `agent/skills/wechat-mp.md
|
|
140
|
-
|
|
86
|
+
技能说明见 `agent/skills/wechat-mp.md`。
|
|
141
87
|
|
|
142
88
|
## 文档链接
|
|
143
89
|
|
|
@@ -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 {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import type {
|
|
5
|
-
import type
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
private
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|