@xmanrui/dsh-im 3.0.3 → 3.0.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xmanrui/dsh-im",
3
- "version": "3.0.3",
3
+ "version": "3.0.4",
4
4
  "description": "把九种 IM 机器人和公网 AI Office 接入本机 DeepSeek Harness。 Connect nine IM channels and a public AI Office to a local DeepSeek Harness.",
5
5
  "keywords": [
6
6
  "deepseek-harness",
@@ -97,11 +97,6 @@ function normalizeBot(value) {
97
97
  typeof entry === 'string' && /^[1-9]\d{4,14}$/.test(entry)
98
98
  )))]
99
99
  : [],
100
- groupAllowedNumbers: Array.isArray(value.accessPolicy?.groupAllowedNumbers)
101
- ? [...new Set(value.accessPolicy.groupAllowedNumbers.filter((entry) => (
102
- typeof entry === 'string' && /^[1-9]\d{4,14}$/.test(entry)
103
- )))]
104
- : [],
105
100
  },
106
101
  bot: {
107
102
  name: text(value.bot?.name, 'WhatsApp机器人', 100),
@@ -37,8 +37,6 @@ function accessPolicyFor(account) {
37
37
  accessMode,
38
38
  allowedNumbers: Array.isArray(account?.accessPolicy?.allowedNumbers)
39
39
  ? account.accessPolicy.allowedNumbers : [],
40
- groupAllowedNumbers: Array.isArray(account?.accessPolicy?.groupAllowedNumbers)
41
- ? account.accessPolicy.groupAllowedNumbers : [],
42
40
  };
43
41
  }
44
42
 
@@ -54,39 +52,30 @@ function allowedNumbersFromText(value) {
54
52
  export function WhatsappAccessSettings({ account, busy = false, onSave }) {
55
53
  const policy = accessPolicyFor(account);
56
54
  const sourceNumbers = policy.allowedNumbers.join('\n');
57
- const sourceGroupNumbers = policy.groupAllowedNumbers.join('\n');
58
55
  const helpId = React.useId();
59
56
  const [accessMode, setAccessMode] = React.useState(policy.accessMode);
60
57
  const [allowedNumbers, setAllowedNumbers] = React.useState(sourceNumbers);
61
- const [groupAllowedNumbers, setGroupAllowedNumbers] = React.useState(sourceGroupNumbers);
62
58
  const [error, setError] = React.useState(null);
63
59
 
64
60
  React.useEffect(() => {
65
61
  setAccessMode(policy.accessMode);
66
62
  setAllowedNumbers(sourceNumbers);
67
- setGroupAllowedNumbers(sourceGroupNumbers);
68
63
  setError(null);
69
- }, [policy.accessMode, sourceNumbers, sourceGroupNumbers]);
64
+ }, [policy.accessMode, sourceNumbers]);
70
65
 
71
66
  const save = async (event) => {
72
67
  event.preventDefault();
73
68
  setError(null);
74
69
  try {
75
70
  const normalized = allowedNumbersFromText(allowedNumbers);
76
- const normalizedGroup = allowedNumbersFromText(groupAllowedNumbers);
77
71
  if (typeof onSave !== 'function') throw new Error('WhatsApp 访问设置暂不可用。');
78
- await onSave({
79
- accessMode,
80
- allowedNumbers: normalized,
81
- groupAllowedNumbers: normalizedGroup,
82
- });
72
+ await onSave({ accessMode, allowedNumbers: normalized });
83
73
  } catch (caught) {
84
74
  setError(caught?.message ?? 'WhatsApp 访问设置保存失败。');
85
75
  }
86
76
  };
87
77
 
88
78
  const allowlistEnabled = accessMode === 'private-allowlist';
89
- const groupAllowlistEnabled = accessMode === 'open';
90
79
  const labels = {
91
80
  'self-only': '仅自己模式',
92
81
  'private-allowlist': '指定联系人模式',
@@ -114,7 +103,7 @@ export function WhatsappAccessSettings({ account, busy = false, onSave }) {
114
103
  h('span', null, '响应自聊和白名单联系人的私聊,忽略群聊。')),
115
104
  h('span', { className: 'dwa-accessTooltipItem' },
116
105
  h('strong', null, '开放响应模式'),
117
- h('span', null, '响应所有私聊、已绑定账号自己发出的群聊消息,以及允许成员的提及或回复;群聊号码列表留空时允许所有群成员。')))))),
106
+ h('span', null, '响应所有私聊、已绑定账号自己发出的群聊消息,以及其他群成员的提及或回复。')))))),
118
107
  h('label', { className: 'dwa-accessField' },
119
108
  h('span', null, '模式'),
120
109
  h('select', {
@@ -126,28 +115,18 @@ export function WhatsappAccessSettings({ account, busy = false, onSave }) {
126
115
  h('option', { value: 'self-only' }, '仅自己模式(默认)'),
127
116
  h('option', { value: 'private-allowlist' }, '指定联系人模式'),
128
117
  h('option', { value: 'open' }, '开放响应模式'))),
129
- (allowlistEnabled || groupAllowlistEnabled)
118
+ allowlistEnabled
130
119
  ? h('label', { className: 'dwa-accessField' },
131
- h('span', null, allowlistEnabled
132
- ? '允许私聊的 WhatsApp 电话号码'
133
- : '允许在群聊中呼叫机器人的 WhatsApp 电话号码'),
120
+ h('span', null, '允许私聊的 WhatsApp 电话号码'),
134
121
  h('textarea', {
135
- value: allowlistEnabled ? allowedNumbers : groupAllowedNumbers,
122
+ value: allowedNumbers,
136
123
  disabled: busy,
137
124
  rows: 3,
138
125
  placeholder: '每行一个含国家或地区代码的号码',
139
- 'aria-label': allowlistEnabled
140
- ? '允许私聊的 WhatsApp 电话号码'
141
- : '允许在群聊中呼叫机器人的 WhatsApp 电话号码',
142
- onChange: (event) => {
143
- if (allowlistEnabled) setAllowedNumbers(event.target.value);
144
- else setGroupAllowedNumbers(event.target.value);
145
- setError(null);
146
- },
126
+ 'aria-label': '允许私聊的 WhatsApp 电话号码',
127
+ onChange: (event) => { setAllowedNumbers(event.target.value); setError(null); },
147
128
  }),
148
- h('small', null, allowlistEnabled
149
- ? '可以包含开头的 +,保存时会自动移除。'
150
- : '留空表示所有群成员都可以通过提及或回复呼叫机器人。'))
129
+ h('small', null, '可以包含开头的 +,保存时会自动移除。'))
151
130
  : null,
152
131
  allowlistEnabled && allowedNumbers.trim() === ''
153
132
  ? h('p', { className: 'dwa-accessWarning', role: 'status' },
@@ -380,12 +380,9 @@ const EN = Object.freeze({
380
380
  '只响应已绑定 WhatsApp 账号的自聊消息。': 'Only respond to self-chat messages from the linked WhatsApp account.',
381
381
  '响应自聊和白名单联系人的私聊,忽略群聊。': 'Respond to self-chat and allowlisted direct messages; ignore group messages.',
382
382
  '响应所有私聊、已绑定账号自己发出的群聊消息,以及其他群成员的提及或回复。': 'Respond to all direct messages, group messages sent by the linked account, and mentions or replies from other group members.',
383
- '响应所有私聊、已绑定账号自己发出的群聊消息,以及允许成员的提及或回复;群聊号码列表留空时允许所有群成员。': 'Respond to all direct messages, group messages sent by the linked account, and mentions or replies from allowed members; leaving the group number list empty allows every group member.',
384
383
  '允许私聊的 WhatsApp 电话号码': 'WhatsApp phone numbers allowed to send direct messages',
385
- '允许在群聊中呼叫机器人的 WhatsApp 电话号码': 'WhatsApp phone numbers allowed to call the bot in group chats',
386
384
  '每行一个含国家或地区代码的号码': 'One number with country or region code per line',
387
385
  '可以包含开头的 +,保存时会自动移除。': 'A leading + is allowed and removed when saved.',
388
- '留空表示所有群成员都可以通过提及或回复呼叫机器人。': 'Leave empty to let every group member call the bot by mentioning it or replying to it.',
389
386
  '仅指定联系人模式使用白名单,切换模式时会保留。': 'Only Selected contacts uses the allowlist; it is retained when modes change.',
390
387
  '白名单为空;保存后将只接受自聊消息。': 'The allowlist is empty; only self-chat messages will be accepted after saving.',
391
388
  '电话号码必须包含国家或地区代码,每行一个。': 'Each phone number must include a country or region code on its own line.',
@@ -53,8 +53,8 @@ function payloadFailure(endpoint, payload) {
53
53
  && payload.confirm === true ? null : 'bot.delete requires a botId and confirm=true.';
54
54
  }
55
55
  if (endpoint === WHATSAPP_ENDPOINTS.setAccessPolicy) {
56
- if (!exactKeys(payload, ['botId', 'accessMode', 'allowedNumbers', 'groupAllowedNumbers'])
57
- || Object.keys(payload).length !== 4
56
+ if (!exactKeys(payload, ['botId', 'accessMode', 'allowedNumbers'])
57
+ || Object.keys(payload).length !== 3
58
58
  || !validId(payload.botId)) return '请输入有效的 WhatsApp 访问模式和电话号码。';
59
59
  try {
60
60
  normalizeWhatsappAccessPolicy(payload);
@@ -63,7 +63,6 @@ export function normalizeWhatsappAccessPolicy(value = {}) {
63
63
  return Object.freeze({
64
64
  accessMode,
65
65
  allowedNumbers: normalizeWhatsappAllowedNumbers(value.allowedNumbers),
66
- groupAllowedNumbers: normalizeWhatsappAllowedNumbers(value.groupAllowedNumbers),
67
66
  });
68
67
  }
69
68
 
@@ -334,7 +334,6 @@ export class WhatsappController {
334
334
  connectedAt: new Date().toISOString(),
335
335
  accessMode: previous?.accessMode,
336
336
  allowedNumbers: previous?.allowedNumbers,
337
- groupAllowedNumbers: previous?.groupAllowedNumbers,
338
337
  };
339
338
  try {
340
339
  if (record.controller.signal.aborted || this.#closed) throw Object.assign(new Error(), { name: 'AbortError' });
@@ -3,7 +3,6 @@ import { createHash, randomBytes } from 'node:crypto';
3
3
  import {
4
4
  areJidsSameUser,
5
5
  downloadMediaMessage,
6
- jidNormalizedUser,
7
6
  normalizeMessageContent,
8
7
  } from '@whiskeysockets/baileys';
9
8
 
@@ -14,7 +13,6 @@ import { trackOutboundArtifactProviderPromise } from '../shared/semantic/artifac
14
13
  import { createWhatsappBridgeStatus, WhatsappHarnessBridge } from './whatsapp-bridge.mjs';
15
14
  import {
16
15
  WHATSAPP_ACCESS_MODES,
17
- normalizeWhatsappAccountJid,
18
16
  normalizeWhatsappAccessPolicy,
19
17
  } from './config-store.mjs';
20
18
  import { createWhatsappWebSession } from './whatsapp-web-session.mjs';
@@ -206,21 +204,8 @@ export function createWhatsappMediaDownloader({
206
204
  });
207
205
  }
208
206
 
209
- function whatsappAccountMatcher(accountJid, aliases) {
210
- const accountJids = new Set(
211
- [accountJid, ...(Array.isArray(aliases) ? aliases : [])]
212
- .map((jid) => normalizeWhatsappAccountJid(jidNormalizedUser(jid)))
213
- .filter(Boolean),
214
- );
215
- return (jid) => {
216
- const normalized = normalizeWhatsappAccountJid(jidNormalizedUser(jid));
217
- return normalized !== null && accountJids.has(normalized);
218
- };
219
- }
220
-
221
207
  export function normalizeWhatsappMessage(message, accountJid, {
222
208
  download = downloadMediaMessage,
223
- accountAliases = [],
224
209
  } = {}) {
225
210
  const remoteJid = typeof message?.key?.remoteJid === 'string' ? message.key.remoteJid : '';
226
211
  const alternateRemoteJid = typeof message?.key?.remoteJidAlt === 'string'
@@ -230,9 +215,8 @@ export function normalizeWhatsappMessage(message, accountJid, {
230
215
  || remoteJid.endsWith('@newsletter')) return null;
231
216
  const group = remoteJid.endsWith('@g.us');
232
217
  const fromMe = message.key.fromMe === true;
233
- const matchesAccount = whatsappAccountMatcher(accountJid, accountAliases);
234
218
  const selfChat = fromMe && !group
235
- && [remoteJid, alternateRemoteJid].some(matchesAccount);
219
+ && [remoteJid, alternateRemoteJid].some((jid) => jid && areJidsSameUser(jid, accountJid));
236
220
  if (fromMe && !selfChat && !group) return null;
237
221
  const senderJid = fromMe ? accountJid : group ? message.key.participant : remoteJid;
238
222
  const senderAlternateJid = group && !fromMe ? message.key.participantAlt : alternateRemoteJid;
@@ -241,9 +225,9 @@ export function normalizeWhatsappMessage(message, accountJid, {
241
225
  const content = normalizeMessageContent(message.message);
242
226
  const context = messageContext(content);
243
227
  const mentioned = Array.isArray(context?.mentionedJid)
244
- && context.mentionedJid.some(matchesAccount);
228
+ && context.mentionedJid.some((jid) => areJidsSameUser(jid, accountJid));
245
229
  const replyToSelf = typeof context?.participant === 'string'
246
- && matchesAccount(context.participant);
230
+ && areJidsSameUser(context.participant, accountJid);
247
231
  const image = whatsappImageSource(message, content, download, { viewOnce });
248
232
  const file = whatsappFileSource(message, content, download);
249
233
  return {
@@ -251,7 +235,6 @@ export function normalizeWhatsappMessage(message, accountJid, {
251
235
  providerMessageId: messageId,
252
236
  senderId: senderJid,
253
237
  senderAlternateId: typeof senderAlternateJid === 'string' ? senderAlternateJid : '',
254
- senderIsSelf: fromMe,
255
238
  senderIsBot: false,
256
239
  kind: group ? 'group' : 'direct',
257
240
  conversationId: remoteJid,
@@ -270,22 +253,12 @@ export function normalizeWhatsappMessage(message, accountJid, {
270
253
  export function whatsappInboundAllowed(message, {
271
254
  accessMode = WHATSAPP_ACCESS_MODES.selfOnly,
272
255
  allowedNumbers = new Set(),
273
- groupAllowedNumbers = new Set(),
274
256
  } = {}) {
275
- if (accessMode === WHATSAPP_ACCESS_MODES.open) {
276
- if (message?.kind !== 'group' || message.senderIsSelf === true) return true;
277
- if (!(groupAllowedNumbers instanceof Set)) return false;
278
- if (groupAllowedNumbers.size === 0) return true;
279
- const senderJids = [message.senderId, message.senderAlternateId]
280
- .filter((jid) => typeof jid === 'string' && jid.endsWith('@s.whatsapp.net'));
281
- return [...groupAllowedNumbers].some((number) => senderJids.some((jid) => (
282
- areJidsSameUser(jid, `${number}@s.whatsapp.net`)
283
- )));
284
- }
257
+ if (accessMode === WHATSAPP_ACCESS_MODES.open) return true;
285
258
  if (message?.kind !== 'direct') return false;
286
259
  if (message.selfChat === true) return true;
287
- if (accessMode !== WHATSAPP_ACCESS_MODES.privateAllowlist) return false;
288
- if (!(allowedNumbers instanceof Set)) return false;
260
+ if (accessMode !== WHATSAPP_ACCESS_MODES.privateAllowlist
261
+ || !(allowedNumbers instanceof Set)) return false;
289
262
  const senderJids = [message.senderId, message.senderAlternateId]
290
263
  .filter((jid) => typeof jid === 'string' && jid.endsWith('@s.whatsapp.net'));
291
264
  return [...allowedNumbers].some((number) => senderJids.some((jid) => (
@@ -569,7 +542,6 @@ export class WhatsappRuntime {
569
542
  #mediaUploadTimeoutMs;
570
543
  #accessMode;
571
544
  #allowedPrivateNumbers;
572
- #allowedGroupNumbers;
573
545
  #createSession;
574
546
  #status = createWhatsappRuntimeStatus();
575
547
  #abortController = null;
@@ -618,7 +590,6 @@ export class WhatsappRuntime {
618
590
  const policy = normalizeWhatsappAccessPolicy(value);
619
591
  this.#accessMode = policy.accessMode;
620
592
  this.#allowedPrivateNumbers = new Set(policy.allowedNumbers);
621
- this.#allowedGroupNumbers = new Set(policy.groupAllowedNumbers);
622
593
  this.#config = { ...this.#config, ...policy };
623
594
  return policy;
624
595
  }
@@ -653,13 +624,7 @@ export class WhatsappRuntime {
653
624
  { code: 'relink-required' },
654
625
  )),
655
626
  onMessage: async (raw, context) => {
656
- const linkedAccount = context?.socket?.user;
657
627
  const message = normalizeWhatsappMessage(raw, this.#config.accountJid, {
658
- accountAliases: [
659
- linkedAccount?.id,
660
- linkedAccount?.lid,
661
- linkedAccount?.phoneNumber,
662
- ],
663
628
  download: createWhatsappMediaDownloader({
664
629
  socket: context?.socket,
665
630
  logger: this.#logger,
@@ -670,7 +635,6 @@ export class WhatsappRuntime {
670
635
  if (!whatsappInboundAllowed(message, {
671
636
  accessMode: this.#accessMode,
672
637
  allowedNumbers: this.#allowedPrivateNumbers,
673
- groupAllowedNumbers: this.#allowedGroupNumbers,
674
638
  })) {
675
639
  this.#status.messagesRejected += 1;
676
640
  this.#status.lastRejectedAt = new Date().toISOString();