openclaw-wechat-channel 0.2.0 → 0.3.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/dist/index.d.mts CHANGED
@@ -17,6 +17,7 @@ interface WechatAccountConfig {
17
17
  wcId?: string;
18
18
  nickName?: string;
19
19
  configured?: boolean;
20
+ allowUsers?: string[];
20
21
  }
21
22
  interface WechatConfig {
22
23
  enabled?: boolean;
@@ -25,6 +26,7 @@ interface WechatConfig {
25
26
  webhookHost?: string;
26
27
  webhookPort?: number;
27
28
  webhookPath?: string;
29
+ allowUsers?: string[];
28
30
  accounts?: Record<string, WechatAccountConfig | undefined>;
29
31
  }
30
32
  //#endregion
@@ -43,6 +45,7 @@ interface ResolvedWeChatAccount {
43
45
  webhookHost?: string;
44
46
  webhookPort: number;
45
47
  webhookPath: string;
48
+ allowUsers?: string[];
46
49
  config: WechatAccountConfig;
47
50
  }
48
51
  //#endregion
package/dist/index.mjs CHANGED
@@ -107,14 +107,17 @@ function getWeChatRuntime() {
107
107
  //#region src/reply-dispatcher.ts
108
108
  function createWeChatReplyDispatcher(params) {
109
109
  const core = getWeChatRuntime();
110
- const { cfg, agentId, runtime, apiKey, replyTo, accountId } = params;
110
+ const { cfg, agentId, runtime, apiKey, proxyUrl, replyTo, accountId } = params;
111
111
  const prefixContext = createReplyPrefixContext({
112
112
  cfg,
113
113
  agentId
114
114
  });
115
115
  const textChunkLimit = core.channel.text.resolveTextChunkLimit(cfg, "wechat", accountId, { fallbackLimit: 2e3 });
116
116
  const chunkMode = core.channel.text.resolveChunkMode(cfg, "wechat");
117
- const client = new ProxyClient({ apiKey });
117
+ const client = new ProxyClient({
118
+ apiKey,
119
+ baseUrl: proxyUrl
120
+ });
118
121
  const { dispatcher, replyOptions, markDispatchIdle } = core.channel.reply.createReplyDispatcherWithTyping({
119
122
  responsePrefix: prefixContext.responsePrefix,
120
123
  responsePrefixContextProvider: prefixContext.responsePrefixContextProvider,
@@ -157,6 +160,7 @@ const DEDUP_WINDOW_MS = 1800 * 1e3;
157
160
  const DEDUP_MAX_SIZE = 1e3;
158
161
  const DEDUP_CLEANUP_INTERVAL_MS = 300 * 1e3;
159
162
  let lastCleanup = Date.now();
163
+ const notifiedNonWhitelistUsers = /* @__PURE__ */ new Set();
160
164
  function tryRecordMessage(messageId) {
161
165
  const now = Date.now();
162
166
  if (now - lastCleanup > DEDUP_CLEANUP_INTERVAL_MS) {
@@ -179,6 +183,18 @@ async function handleWeChatMessage(params) {
179
183
  log(`wechat: skipping duplicate message ${message.id}`);
180
184
  return;
181
185
  }
186
+ const allowUsers = account.allowUsers;
187
+ if (allowUsers && allowUsers.length > 0 && message.sender.id !== account.wcId && !allowUsers.includes(message.sender.id)) {
188
+ log(`wechat[${accountId}]: ignoring message from ${message.sender.id} (not in allowUsers)`);
189
+ if (account.wcId && !notifiedNonWhitelistUsers.has(message.sender.id)) {
190
+ notifiedNonWhitelistUsers.add(message.sender.id);
191
+ await new ProxyClient({
192
+ apiKey: account.apiKey,
193
+ baseUrl: account.proxyUrl
194
+ }).sendText(account.wcId, `‼️ ${message.sender.id} 不在白名单中,配置 allowUsers 后即可回复`).catch(() => {});
195
+ }
196
+ return;
197
+ }
182
198
  const isGroup = !!message.group;
183
199
  log(`wechat[${accountId}]: received ${message.type} from ${message.sender.id}${isGroup ? ` in group ${message.group.id}` : ""}`);
184
200
  if (message.type !== "text") {
@@ -242,6 +258,7 @@ async function handleWeChatMessage(params) {
242
258
  agentId: route.agentId,
243
259
  runtime,
244
260
  apiKey: account.apiKey,
261
+ proxyUrl: account.proxyUrl,
245
262
  replyTo,
246
263
  accountId: account.accountId
247
264
  });
@@ -403,6 +420,7 @@ function displayLoginSuccess(nickName, wcId) {
403
420
 
404
421
  //#endregion
405
422
  //#region src/channel.ts
423
+ const runningServers = /* @__PURE__ */ new Map();
406
424
  const PLUGIN_META = {
407
425
  id: "wechat",
408
426
  label: "WeChat",
@@ -427,7 +445,8 @@ function resolveWeChatAccount({ cfg, accountId }) {
427
445
  proxyUrl: wechatCfg?.proxyUrl,
428
446
  webhookHost: wechatCfg?.webhookHost,
429
447
  webhookPort: wechatCfg?.webhookPort,
430
- webhookPath: wechatCfg?.webhookPath
448
+ webhookPath: wechatCfg?.webhookPath,
449
+ allowUsers: wechatCfg?.allowUsers
431
450
  };
432
451
  const defaultAccount = wechatCfg?.accounts?.default;
433
452
  accountCfg = {
@@ -455,6 +474,7 @@ function resolveWeChatAccount({ cfg, accountId }) {
455
474
  webhookHost: accountCfg.webhookHost,
456
475
  webhookPort: accountCfg.webhookPort || 18790,
457
476
  webhookPath: accountCfg.webhookPath || "/webhook/wechat",
477
+ allowUsers: accountCfg.allowUsers,
458
478
  config: accountCfg
459
479
  };
460
480
  }
@@ -492,6 +512,10 @@ const wechatPlugin = {
492
512
  webhookHost: { type: "string" },
493
513
  webhookPort: { type: "integer" },
494
514
  webhookPath: { type: "string" },
515
+ allowUsers: {
516
+ type: "array",
517
+ items: { type: "string" }
518
+ },
495
519
  accounts: {
496
520
  type: "object",
497
521
  additionalProperties: {
@@ -506,7 +530,11 @@ const wechatPlugin = {
506
530
  webhookPort: { type: "integer" },
507
531
  webhookPath: { type: "string" },
508
532
  wcId: { type: "string" },
509
- nickName: { type: "string" }
533
+ nickName: { type: "string" },
534
+ allowUsers: {
535
+ type: "array",
536
+ items: { type: "string" }
537
+ }
510
538
  },
511
539
  required: ["apiKey"]
512
540
  }
@@ -784,6 +812,12 @@ const wechatPlugin = {
784
812
  log?.info(`Using webhook URL: ${webhookUrl}`);
785
813
  log?.info(`Registering webhook with proxy service for wcId: ${account.wcId}`);
786
814
  await client.registerWebhook(account.wcId, webhookUrl);
815
+ const prevStop = runningServers.get(accountId);
816
+ if (prevStop) {
817
+ prevStop();
818
+ runningServers.delete(accountId);
819
+ await new Promise((r) => setTimeout(r, 500));
820
+ }
787
821
  const { stop } = await startCallbackServer({
788
822
  port,
789
823
  apiKey: account.apiKey,
@@ -801,10 +835,12 @@ const wechatPlugin = {
801
835
  abortSignal
802
836
  });
803
837
  abortSignal?.addEventListener("abort", stop);
838
+ runningServers.set(accountId, stop);
804
839
  log?.info(`WeChat account ${accountId} started successfully on port ${port}`);
805
840
  log?.info(`Webhook URL: ${webhookUrl}`);
806
841
  return { async stop() {
807
842
  stop();
843
+ runningServers.delete(accountId);
808
844
  setStatus({
809
845
  accountId,
810
846
  port,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "openclaw-wechat-channel",
3
3
  "type": "module",
4
- "version": "0.2.0",
4
+ "version": "0.3.0",
5
5
  "packageManager": "pnpm@10.30.0",
6
6
  "description": "OpenClaw WeChat channel plugin via Proxy API",
7
7
  "license": "MIT",