@zhin.js/adapter-weixin-ilink 5.0.1 → 5.0.2

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,19 @@
1
1
  # @zhin.js/adapter-weixin-ilink
2
2
 
3
+ ## 5.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [afc0e66]
8
+ - Updated dependencies [2e41ad5]
9
+ - Updated dependencies [9f57124]
10
+ - @zhin.js/core@1.5.2
11
+ - @zhin.js/adapter@1.1.5
12
+ - @zhin.js/im-contract@1.0.1
13
+ - @zhin.js/plugin-runtime@1.1.3
14
+ - @zhin.js/command@1.0.7
15
+ - zhin.js@6.0.2
16
+
3
17
  ## 5.0.1
4
18
 
5
19
  ### Patch Changes
package/README.md CHANGED
@@ -52,7 +52,7 @@ data/weixin-ilink/<bot-name>.json
52
52
 
53
53
  回复必须携带入站时缓存的 `context_token`(按 `endpointId + peerUserId`)。若用户久未发消息导致 token 缺失,出站会拒绝并打 warn。
54
54
 
55
- 出站经 Runtime:`MessageGateway` → `endpoint.send({ target, payload })`。
55
+ 出站经 Runtime:`MessageGateway` → `endpoint.send({ conversation, payload })`(`conversation` 为入站归一化出的 `ConversationRef`,kind 恒为 `private`,`id` 即对端 user_id)。
56
56
 
57
57
  **图文限制**:微信单条消息不支持图文混排。适配器会自动:
58
58
 
package/lib/endpoint.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { EndpointInstance, EndpointManagement } from '@zhin.js/adapter';
1
+ import type { EndpointInstance, EndpointManagement, EndpointSendRequest } from '@zhin.js/adapter';
2
2
  import type { MessageGateway } from '@zhin.js/core/runtime';
3
3
  import type { CapabilityId } from '@zhin.js/plugin-runtime';
4
4
  import { getUpdates, notifyStart, notifyStop } from './ilink-api.js';
@@ -33,10 +33,7 @@ export declare class WeixinIlinkEndpoint implements EndpointInstance {
33
33
  open(): void;
34
34
  close(): void;
35
35
  stop(): Promise<void>;
36
- send({ target, payload }: {
37
- readonly target: string;
38
- readonly payload: unknown;
39
- }): Promise<string>;
36
+ send({ conversation, payload }: EndpointSendRequest): Promise<string>;
40
37
  /** Test / internal: admit a parsed message when the endpoint is open. */
41
38
  admit(msg: WeixinMessageWithMedia): void;
42
39
  sendTypingToUser(userId: string, status: number): Promise<void>;
package/lib/endpoint.js CHANGED
@@ -18,7 +18,7 @@ import { sendWeixinMediaFile } from './weixin-send-media.js';
18
18
  import { materializeOutboundMedia } from './outbound-media.js';
19
19
  import { MessageItemType } from './ilink-types.js';
20
20
  import { getExtensionFromMime, sniffMimeFromBuffer } from './mime.js';
21
- import { formatInboundContent, formatOutboundSegments, inboundMessageId, segmentLocalPath, sleep, } from './protocol.js';
21
+ import { formatInboundContent, formatOutboundSegments, inboundMessageId, segmentLocalPath, sleep, weixinIlinkInboundConversation, } from './protocol.js';
22
22
  const logger = getLogger('weixin-ilink');
23
23
  const MAX_CONSECUTIVE_FAILURES = 3;
24
24
  const BACKOFF_DELAY_MS = 30_000;
@@ -130,10 +130,12 @@ export class WeixinIlinkEndpoint {
130
130
  endpoint: this.#options.config.name,
131
131
  }));
132
132
  }
133
- async send({ target, payload }) {
133
+ async send({ conversation, payload }) {
134
134
  if (!this.#creds?.botToken) {
135
135
  throw new Error('weixin-ilink bot not authenticated');
136
136
  }
137
+ // 个人微信仅 private 会话,对端 user_id 即 conversation.id
138
+ const target = conversation.id;
137
139
  const contextToken = getContextToken(this.#options.config.name, target);
138
140
  if (!contextToken) {
139
141
  logger.warn(formatCompact({
@@ -215,12 +217,12 @@ export class WeixinIlinkEndpoint {
215
217
  if (msg.context_token && userId) {
216
218
  setContextToken(this.#options.config.name, userId, msg.context_token);
217
219
  }
220
+ const conversation = weixinIlinkInboundConversation(String(this.#options.id), userId);
218
221
  void this.#options.gateway.receive({
219
- adapter: this.#options.id,
220
- target: userId,
222
+ conversation,
223
+ message: { conversation, id: inboundMessageId(msg) },
221
224
  content: formatInboundContent(msg),
222
225
  sender: userId,
223
- id: inboundMessageId(msg),
224
226
  metadata: Object.freeze({
225
227
  endpoint: this.#options.config.name,
226
228
  messageType: msg.message_type,
package/lib/protocol.d.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  * Weixin iLink protocol helpers (no legacy Adapter/Endpoint / segment-mapper).
3
3
  * Canonicalization is owned by gateway/core before endpoint.send.
4
4
  */
5
+ import type { ConversationRef } from '@zhin.js/im-contract';
5
6
  import type { WeixinMessage } from './ilink-types.js';
6
7
  /** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
7
8
  export interface WeixinIlinkAdapterConfig {
@@ -43,6 +44,11 @@ export declare function resolveWeixinIlinkConfig(config?: WeixinIlinkAdapterConf
43
44
  /** Build inbound text for MessageGateway.receive (gateway owns reply routing). */
44
45
  export declare function formatInboundContent(msg: WeixinMessageWithMedia): string;
45
46
  export declare function inboundMessageId(msg: WeixinMessage): string;
47
+ /**
48
+ * 入站归一化 → ConversationRef:个人微信无群/频道概念,全部会话都是
49
+ * 与 `from_user_id` 的 private 会话(无 parent)。
50
+ */
51
+ export declare function weixinIlinkInboundConversation(endpointId: string, userId: string): ConversationRef;
46
52
  /**
47
53
  * Wire-encode an already-rendered outbound payload into Weixin wire segments.
48
54
  * Segment canonicalization is intentionally not done here.
package/lib/protocol.js CHANGED
@@ -55,6 +55,17 @@ export function formatInboundContent(msg) {
55
55
  export function inboundMessageId(msg) {
56
56
  return String(msg.message_id ?? msg.client_id ?? msg.seq ?? Date.now());
57
57
  }
58
+ /**
59
+ * 入站归一化 → ConversationRef:个人微信无群/频道概念,全部会话都是
60
+ * 与 `from_user_id` 的 private 会话(无 parent)。
61
+ */
62
+ export function weixinIlinkInboundConversation(endpointId, userId) {
63
+ return {
64
+ endpoint: { id: endpointId, adapter: endpointId.split('\0')[0] ?? endpointId },
65
+ kind: 'private',
66
+ id: userId,
67
+ };
68
+ }
58
69
  /**
59
70
  * Wire-encode an already-rendered outbound payload into Weixin wire segments.
60
71
  * Segment canonicalization is intentionally not done here.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/adapter-weixin-ilink",
3
- "version": "5.0.1",
3
+ "version": "5.0.2",
4
4
  "type": "module",
5
5
  "description": "Zhin.js Weixin iLink (ClawBot) adapter for Plugin Runtime (long-poll)",
6
6
  "main": "./lib/index.js",
@@ -48,17 +48,18 @@
48
48
  }
49
49
  },
50
50
  "dependencies": {
51
- "@zhin.js/adapter": "1.1.4",
52
- "@zhin.js/command": "1.0.6",
53
- "@zhin.js/core": "1.5.1",
51
+ "@zhin.js/adapter": "1.1.5",
52
+ "@zhin.js/command": "1.0.7",
53
+ "@zhin.js/core": "1.5.2",
54
+ "@zhin.js/im-contract": "1.0.1",
54
55
  "@zhin.js/logger": "1.0.75",
55
- "@zhin.js/plugin-runtime": "1.1.2"
56
+ "@zhin.js/plugin-runtime": "1.1.3"
56
57
  },
57
58
  "peerDependencies": {
58
- "@zhin.js/adapter": "1.1.4",
59
- "@zhin.js/core": "1.5.1",
60
- "@zhin.js/plugin-runtime": "1.1.2",
61
- "zhin.js": "6.0.1"
59
+ "@zhin.js/adapter": "1.1.5",
60
+ "@zhin.js/core": "1.5.2",
61
+ "@zhin.js/plugin-runtime": "1.1.3",
62
+ "zhin.js": "6.0.2"
62
63
  },
63
64
  "peerDependenciesMeta": {
64
65
  "zhin.js": {
package/src/endpoint.ts CHANGED
@@ -4,7 +4,12 @@
4
4
  import crypto from 'node:crypto';
5
5
  import fs from 'node:fs';
6
6
  import path from 'node:path';
7
- import type { EndpointFriend, EndpointInstance, EndpointManagement } from '@zhin.js/adapter';
7
+ import type {
8
+ EndpointFriend,
9
+ EndpointInstance,
10
+ EndpointManagement,
11
+ EndpointSendRequest,
12
+ } from '@zhin.js/adapter';
8
13
  import type { MessageGateway } from '@zhin.js/core/runtime';
9
14
  import { formatCompact, getLogger } from '@zhin.js/logger';
10
15
  import type { CapabilityId } from '@zhin.js/plugin-runtime';
@@ -44,6 +49,7 @@ import {
44
49
  inboundMessageId,
45
50
  segmentLocalPath,
46
51
  sleep,
52
+ weixinIlinkInboundConversation,
47
53
  type ResolvedWeixinIlinkConfig,
48
54
  type WeixinMessageWithMedia,
49
55
  type WeixinWireSegment,
@@ -197,10 +203,12 @@ export class WeixinIlinkEndpoint implements EndpointInstance {
197
203
  }));
198
204
  }
199
205
 
200
- async send({ target, payload }: { readonly target: string; readonly payload: unknown }): Promise<string> {
206
+ async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
201
207
  if (!this.#creds?.botToken) {
202
208
  throw new Error('weixin-ilink bot not authenticated');
203
209
  }
210
+ // 个人微信仅 private 会话,对端 user_id 即 conversation.id
211
+ const target = conversation.id;
204
212
  const contextToken = getContextToken(this.#options.config.name, target);
205
213
  if (!contextToken) {
206
214
  logger.warn(formatCompact({
@@ -288,12 +296,12 @@ export class WeixinIlinkEndpoint implements EndpointInstance {
288
296
  if (msg.context_token && userId) {
289
297
  setContextToken(this.#options.config.name, userId, msg.context_token);
290
298
  }
299
+ const conversation = weixinIlinkInboundConversation(String(this.#options.id), userId);
291
300
  void this.#options.gateway.receive({
292
- adapter: this.#options.id,
293
- target: userId,
301
+ conversation,
302
+ message: { conversation, id: inboundMessageId(msg) },
294
303
  content: formatInboundContent(msg),
295
304
  sender: userId,
296
- id: inboundMessageId(msg),
297
305
  metadata: Object.freeze({
298
306
  endpoint: this.#options.config.name,
299
307
  messageType: msg.message_type,
package/src/protocol.ts CHANGED
@@ -5,6 +5,7 @@
5
5
 
6
6
  import { pickCredential } from '@zhin.js/adapter';
7
7
  import { isMediaRef } from '@zhin.js/core';
8
+ import type { ConversationRef } from '@zhin.js/im-contract';
8
9
  import { bodyFromItemList, isMediaItem } from './weixin-inbound.js';
9
10
  import { DEFAULT_API_BASE_URL, DEFAULT_CDN_BASE_URL } from './ilink-meta.js';
10
11
  import type { WeixinMessage } from './ilink-types.js';
@@ -107,6 +108,18 @@ export function inboundMessageId(msg: WeixinMessage): string {
107
108
  return String(msg.message_id ?? msg.client_id ?? msg.seq ?? Date.now());
108
109
  }
109
110
 
111
+ /**
112
+ * 入站归一化 → ConversationRef:个人微信无群/频道概念,全部会话都是
113
+ * 与 `from_user_id` 的 private 会话(无 parent)。
114
+ */
115
+ export function weixinIlinkInboundConversation(endpointId: string, userId: string): ConversationRef {
116
+ return {
117
+ endpoint: { id: endpointId, adapter: endpointId.split('\0')[0] ?? endpointId },
118
+ kind: 'private',
119
+ id: userId,
120
+ };
121
+ }
122
+
110
123
  /**
111
124
  * Wire-encode an already-rendered outbound payload into Weixin wire segments.
112
125
  * Segment canonicalization is intentionally not done here.