@abtnode/core 1.17.3-beta-20251120-052956-035abea6 → 1.17.3-beta-20251123-232619-53258789

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.
@@ -10,6 +10,7 @@ const {
10
10
  } = require('@blocklet/meta/lib/util');
11
11
  const { getBlockletEngine, hasStartEngine } = require('@blocklet/meta/lib/engine');
12
12
  const { getComponentsInternalInfo } = require('@blocklet/meta/lib/blocklet');
13
+ const pAll = require('p-all');
13
14
  const {
14
15
  forEachBlocklet,
15
16
  validateBlocklet,
@@ -18,6 +19,7 @@ const {
18
19
  getHealthyCheckTimeout,
19
20
  getHookArgs,
20
21
  shouldSkipComponent,
22
+ getComponentNamesWithVersion,
21
23
  } = require('../../../util/blocklet');
22
24
  const { startBlockletProcess } = require('../../../util/blocklet');
23
25
  const hooks = require('../../hooks');
@@ -39,7 +41,7 @@ const { isDockerOnlySingleInstance } = require('../../../util/docker/is-docker-o
39
41
  * @returns {Promise<Object>} 返回启动后的 blocklet 对象
40
42
  */
41
43
  const blueGreenStartBlocklet = async (
42
- { did, componentDids, operator: _operator, ignoreErrorNotification },
44
+ { did, componentDids, operator: _operator, ignoreErrorNotification, onError },
43
45
  context,
44
46
  manager,
45
47
  states
@@ -169,143 +171,260 @@ const blueGreenStartBlocklet = async (
169
171
 
170
172
  const blueGreenComponentIds = await blueGreenGetComponentIds(blocklet1, entryComponentIds);
171
173
 
172
- // eslint-disable-next-line no-unreachable-loop
174
+ const startedBlockletDids = [];
175
+ const errorBlockletDids = [];
176
+
173
177
  for (const item of blueGreenComponentIds) {
174
178
  if (!item.componentDids.length) {
175
179
  continue;
176
180
  }
177
181
 
178
- try {
179
- const doc1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.starting, {
180
- componentDids: item.componentDids,
181
- operator,
182
- isGreen: item.changeToGreen,
183
- });
182
+ await states.blocklet.setBlockletStatus(did, BlockletStatus.starting, {
183
+ componentDids: item.componentDids,
184
+ operator,
185
+ isGreen: item.changeToGreen,
186
+ });
184
187
 
185
- const nextBlocklet = await ensureAppPortsNotOccupied({
186
- blocklet: blocklet1,
187
- componentDids: item.componentDids,
188
- states,
189
- manager,
190
- isGreen: item.changeToGreen,
191
- });
188
+ await ensureAppPortsNotOccupied({
189
+ blocklet: blocklet1,
190
+ componentDids: item.componentDids,
191
+ states,
192
+ manager,
193
+ isGreen: item.changeToGreen,
194
+ });
195
+ }
192
196
 
193
- manager.emit(BlockletEvents.statusChange, doc1);
197
+ const nextBlocklet = await manager.ensureBlocklet(did, { e2eMode });
194
198
 
195
- const nodeInfo = await states.node.read();
196
- const nodeEnvironments = await states.node.getEnvironments();
199
+ manager.emit(BlockletEvents.statusChange, nextBlocklet);
197
200
 
198
- // 钩子函数设置
199
- const getHookFn =
200
- (hookName) =>
201
- async (b, { env }) => {
202
- const hookArgs = getHookArgs(b);
203
- const needRunDocker = await checkNeedRunDocker(b.meta, env, nodeInfo, isExternalBlocklet(nextBlocklet));
204
- if (!b.meta.scripts?.[hookName]) {
205
- return null;
206
- }
207
- if (needRunDocker) {
208
- return dockerExec({
209
- blocklet: nextBlocklet,
210
- meta: b.meta,
211
- script: b.meta.scripts?.[hookName],
212
- hookName,
213
- nodeInfo,
214
- env,
215
- ...hookArgs,
216
- });
217
- }
218
- return hooks[hookName](b, {
219
- appDir: b.env.appDir,
220
- hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
221
- env,
222
- did, // root blocklet did,
223
- teamManager: manager.teamManager,
224
- ...hookArgs,
201
+ // 收集所有任务
202
+ const tasks = [];
203
+ for (const item of blueGreenComponentIds) {
204
+ if (!item.componentDids.length) {
205
+ continue;
206
+ }
207
+
208
+ for (const subDid of item.componentDids) {
209
+ tasks.push(async () => {
210
+ try {
211
+ const nodeInfo = await states.node.read();
212
+ const nodeEnvironments = await states.node.getEnvironments();
213
+
214
+ // 钩子函数设置
215
+ const getHookFn =
216
+ (hookName) =>
217
+ async (b, { env }) => {
218
+ const hookArgs = getHookArgs(b);
219
+ const needRunDocker = await checkNeedRunDocker(b.meta, env, nodeInfo, isExternalBlocklet(nextBlocklet));
220
+ if (!b.meta.scripts?.[hookName]) {
221
+ return null;
222
+ }
223
+ if (needRunDocker) {
224
+ return dockerExec({
225
+ blocklet: nextBlocklet,
226
+ meta: b.meta,
227
+ script: b.meta.scripts?.[hookName],
228
+ hookName,
229
+ nodeInfo,
230
+ env,
231
+ ...hookArgs,
232
+ });
233
+ }
234
+ return hooks[hookName](b, {
235
+ appDir: b.env.appDir,
236
+ hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
237
+ env,
238
+ did, // root blocklet did,
239
+ teamManager: manager.teamManager,
240
+ ...hookArgs,
241
+ });
242
+ };
243
+
244
+ await startBlockletProcess(nextBlocklet, {
245
+ ...context,
246
+ preFlight: getHookFn('preFlight'),
247
+ preStart: getHookFn('preStart'),
248
+ postStart: getHookFn('postStart'),
249
+ nodeEnvironments,
250
+ nodeInfo,
251
+ e2eMode,
252
+ componentDids: [subDid],
253
+ configSynchronizer: manager.configSynchronizer,
254
+ isGreen: item.changeToGreen,
255
+ });
256
+
257
+ // 健康检查绿色环境
258
+ const { startTimeout, minConsecutiveTime } = getHealthyCheckTimeout(nextBlocklet, {
259
+ checkHealthImmediately,
260
+ componentDids: [subDid],
261
+ });
262
+
263
+ await manager._onCheckIfStarted(
264
+ {
265
+ did,
266
+ context,
267
+ minConsecutiveTime,
268
+ timeout: startTimeout,
269
+ componentDids: [subDid],
270
+ },
271
+ { throwOnError: true, isGreen: item.changeToGreen }
272
+ );
273
+
274
+ // 收集成功的组件(排除已经在 errorBlockletDids 中的组件)
275
+ startedBlockletDids.push({ did: subDid, isGreen: item.changeToGreen });
276
+
277
+ logger.info('Green environment started successfully', {
278
+ did,
279
+ componentDids: [subDid],
225
280
  });
226
- };
227
-
228
- await startBlockletProcess(nextBlocklet, {
229
- ...context,
230
- preFlight: getHookFn('preFlight'),
231
- preStart: getHookFn('preStart'),
232
- postStart: getHookFn('postStart'),
233
- nodeEnvironments,
234
- nodeInfo,
235
- e2eMode,
236
- componentDids: item.componentDids,
237
- configSynchronizer: manager.configSynchronizer,
238
- isGreen: item.changeToGreen,
281
+ } catch (err) {
282
+ const error = Array.isArray(err) ? err[0] : err;
283
+ logger.error('Failed to start green environment', { error, did, title: blocklet1.meta.title });
284
+
285
+ // 收集失败的组件
286
+ errorBlockletDids.push({ did: subDid, error, isGreen: item.changeToGreen });
287
+
288
+ try {
289
+ await manager.deleteProcess({ did, componentDids: [subDid], isGreen: item.changeToGreen });
290
+ } catch (cleanupError) {
291
+ logger.error('Failed to cleanup green environment', { cleanupError });
292
+ }
293
+ }
294
+ });
295
+ }
296
+ }
297
+
298
+ await pAll(tasks, { concurrency: 6 });
299
+
300
+ const lastBlocklet = await manager.ensureBlocklet(did, { e2eMode });
301
+ let errorDescription = '';
302
+
303
+ // 处理启动失败的组件
304
+ if (errorBlockletDids.length) {
305
+ const { error } = errorBlockletDids[0];
306
+ for (const item of errorBlockletDids) {
307
+ logger.error('Failed to start blocklet', {
308
+ error: item.error,
309
+ title: lastBlocklet.meta.title,
310
+ name: getComponentNamesWithVersion(lastBlocklet, [item.did]),
311
+ });
312
+ }
313
+
314
+ errorDescription = `${getComponentNamesWithVersion(
315
+ lastBlocklet,
316
+ errorBlockletDids.map((x) => x.did)
317
+ )} start failed for ${getDisplayName(lastBlocklet)}: ${errorBlockletDids.map((x) => x.error.message).join('. ')}`;
318
+
319
+ if (!ignoreErrorNotification) {
320
+ manager._createNotification(did, {
321
+ title: 'Blue-Green Deployment: Green Start Failed',
322
+ description: errorDescription,
323
+ entityType: 'blocklet',
324
+ entityId: did,
325
+ severity: 'error',
239
326
  });
327
+ }
328
+
329
+ const greenBlockletDids = errorBlockletDids.filter((x) => x.isGreen).map((x) => x.did);
330
+ const blueBlockletDids = errorBlockletDids.filter((x) => !x.isGreen).map((x) => x.did);
240
331
 
241
- // 健康检查绿色环境
242
- const { startTimeout, minConsecutiveTime } = getHealthyCheckTimeout(nextBlocklet, {
243
- checkHealthImmediately,
244
- componentDids: item.componentDids,
332
+ if (greenBlockletDids.length) {
333
+ await manager.deleteProcess({
334
+ did,
335
+ componentDids: greenBlockletDids,
336
+ shouldUpdateBlockletStatus: false,
337
+ isGreen: true,
338
+ });
339
+ await states.blocklet.setBlockletStatus(did, BlockletStatus.error, {
340
+ componentDids: greenBlockletDids,
341
+ operator,
342
+ isGreen: true,
245
343
  });
344
+ }
246
345
 
247
- await manager._onCheckIfStarted(
248
- {
249
- did,
250
- context,
251
- minConsecutiveTime,
252
- timeout: startTimeout,
253
- componentDids: item.componentDids,
254
- },
255
- { throwOnError: true, isGreen: item.changeToGreen, needUpdateBlueStatus: true }
256
- );
257
-
258
- logger.info('Green environment started successfully', {
346
+ if (blueBlockletDids.length) {
347
+ await manager.deleteProcess({
259
348
  did,
260
- componentDids: item.componentDids,
349
+ componentDids: blueBlockletDids,
350
+ shouldUpdateBlockletStatus: false,
351
+ isGreen: false,
261
352
  });
262
- } catch (err) {
263
- const error = Array.isArray(err) ? err[0] : err;
264
- logger.error('Failed to start green environment', { error, did, title: blocklet1.meta.title });
265
-
266
- try {
267
- await manager.deleteProcess({ did, componentDids: item.componentDids, isGreen: item.changeToGreen });
268
- // 如果需要把失败状态设置成 error:
269
- // const doc1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.error, {
270
- // componentDids: item.componentDids,
271
- // operator,
272
- // isGreen: item.changeToGreen,
273
- // });
274
- // manager.emit(BlockletEvents.statusChange, doc1);
275
- manager.emit(BlockletEvents.statusChange, blocklet1);
276
- } catch (cleanupError) {
277
- logger.error('Failed to cleanup green environment', { cleanupError });
278
- }
353
+ await states.blocklet.setBlockletStatus(did, BlockletStatus.error, {
354
+ componentDids: blueBlockletDids,
355
+ operator,
356
+ isGreen: false,
357
+ });
358
+ }
279
359
 
280
- const description = `Green environment start failed for ${getDisplayName(blocklet1)}: ${error.message}`;
281
- if (!ignoreErrorNotification) {
282
- manager._createNotification(did, {
283
- title: 'Blue-Green Deployment: Green Start Failed',
284
- description,
285
- entityType: 'blocklet',
286
- entityId: did,
287
- severity: 'error',
288
- });
289
- }
360
+ const finalBlocklet = await manager.getBlocklet(did);
361
+ manager.emit(BlockletEvents.startFailed, {
362
+ ...finalBlocklet,
363
+ componentDids: errorBlockletDids.map((x) => x.did),
364
+ error: { message: error.message },
365
+ });
366
+ manager.emit(BlockletEvents.statusChange, { ...finalBlocklet, error: { message: error.message } });
367
+ }
290
368
 
291
- if (throwOnError) {
292
- throw new Error(description);
293
- }
294
- throw error;
369
+ // 处理成功启动的组件
370
+ if (startedBlockletDids.length) {
371
+ const startedGreenBlockletDids = startedBlockletDids.filter((x) => x.isGreen).map((x) => x.did);
372
+ const startedBlueBlockletDids = startedBlockletDids.filter((x) => !x.isGreen).map((x) => x.did);
373
+
374
+ if (startedGreenBlockletDids.length) {
375
+ await states.blocklet.setBlockletStatus(did, BlockletStatus.running, {
376
+ componentDids: startedGreenBlockletDids,
377
+ operator,
378
+ isGreen: true,
379
+ });
380
+ await manager.deleteProcess({ did, componentDids: startedGreenBlockletDids, isGreen: false });
381
+ }
382
+
383
+ if (startedBlueBlockletDids.length) {
384
+ await states.blocklet.setBlockletStatus(did, BlockletStatus.running, {
385
+ componentDids: startedBlueBlockletDids,
386
+ operator,
387
+ isGreen: false,
388
+ });
389
+ await manager.deleteProcess({ did, componentDids: startedBlueBlockletDids, isGreen: true });
295
390
  }
296
391
 
297
- const nextBlocklet = await manager.ensureBlocklet(did, { e2eMode });
298
- manager.emit(BlockletEvents.blurOrGreenStarted, { blocklet: nextBlocklet, componentDids, context });
392
+ const finalBlocklet = await manager.getBlocklet(did);
393
+
394
+ await manager.configSynchronizer.throttledSyncAppConfig(finalBlocklet);
395
+ const componentsInfo = getComponentsInternalInfo(finalBlocklet);
396
+ manager.emit(BlockletInternalEvents.componentUpdated, {
397
+ appDid: blocklet1.appDid,
398
+ components: componentsInfo,
399
+ });
400
+ manager.emit(BlockletInternalEvents.componentStarted, {
401
+ appDid: blocklet1.appDid,
402
+ components: startedBlockletDids.map((x) => ({ did: x.did })),
403
+ });
404
+
405
+ manager.emit(BlockletEvents.statusChange, finalBlocklet);
406
+ manager.emit(BlockletEvents.started, {
407
+ ...finalBlocklet,
408
+ componentDids: startedBlockletDids.map((x) => x.did),
409
+ });
299
410
  }
300
411
 
301
- const nextBlocklet = await manager.getBlocklet(did);
302
- const componentsInfo = getComponentsInternalInfo(nextBlocklet);
303
- manager.emit(BlockletInternalEvents.componentStarted, {
304
- appDid: nextBlocklet.appDid,
305
- components: componentsInfo,
306
- });
412
+ // 根据情况更新 route table, 会判断只有包含多 interfaces 的 DID 才会更新 route table
413
+ if (!['true', '1'].includes(process.env.ABT_NODE_DISABLE_BLUE_GREEN)) {
414
+ manager.emit(BlockletEvents.blurOrGreenStarted, {
415
+ blocklet: lastBlocklet,
416
+ componentDids,
417
+ context,
418
+ });
419
+ }
307
420
 
308
- manager.emit(BlockletEvents.statusChange, nextBlocklet);
421
+ if (errorBlockletDids.length && onError) {
422
+ onError(errorBlockletDids);
423
+ }
424
+
425
+ if (throwOnError && errorDescription) {
426
+ throw new Error(errorDescription);
427
+ }
309
428
  };
310
429
 
311
430
  module.exports = {
@@ -28,6 +28,8 @@ const blueGreenUpgradeBlocklet = async (
28
28
  }
29
29
  }
30
30
 
31
+ let errorBlockletDids = [];
32
+
31
33
  try {
32
34
  await states.blocklet.upgradeBlocklet({ meta, source, deployedFrom, children });
33
35
  logger.info('updated blocklet for upgrading', { did, componentDids, source, name });
@@ -81,7 +83,15 @@ const blueGreenUpgradeBlocklet = async (
81
83
  if (runningDids.length) {
82
84
  if (initialized) {
83
85
  await blueGreenStartBlocklet(
84
- { did, componentDids: runningDids, operator: context?.user?.did, ignoreErrorNotification: true },
86
+ {
87
+ did,
88
+ componentDids: runningDids,
89
+ operator: context?.user?.did,
90
+ ignoreErrorNotification: true,
91
+ onError: (dids) => {
92
+ errorBlockletDids = dids;
93
+ },
94
+ },
85
95
  context,
86
96
  manager,
87
97
  states
@@ -158,9 +168,45 @@ const blueGreenUpgradeBlocklet = async (
158
168
  return blocklet;
159
169
  } catch (err) {
160
170
  logger.error('failed to upgrade blocklet', { did, version, name, error: err });
161
- await states.blocklet.upgradeBlocklet({ ...oldBlocklet });
162
- manager.configSynchronizer.throttledSyncAppConfig(oldBlocklet);
171
+ const nextBlocklet = await manager.ensureBlocklet(did);
172
+
173
+ // 提取出错的 blocklet did 列表
174
+ let errorDids = [];
175
+ if (Array.isArray(errorBlockletDids) && errorBlockletDids.length > 0) {
176
+ if (typeof errorBlockletDids[0] === 'string') {
177
+ errorDids = errorBlockletDids;
178
+ } else {
179
+ errorDids = errorBlockletDids.map((x) => x.did);
180
+ }
181
+ }
182
+
183
+ const rollbackBlocklet = { ...oldBlocklet };
184
+ for (const child of nextBlocklet.children) {
185
+ const isErrorBlocklet = errorDids.includes(child.meta.did);
186
+ if (isErrorBlocklet) {
187
+ for (const oldChild of oldBlocklet.children) {
188
+ if (child && oldChild && child.meta.did === oldChild.meta.did) {
189
+ const rollbackChild = rollbackBlocklet.children.find((c) => c.meta.did === child.meta.did);
190
+ if (rollbackChild) {
191
+ rollbackChild.status = oldChild.status;
192
+ rollbackChild.greenStatus = oldChild.greenStatus;
193
+ rollbackChild.ports = oldChild.ports;
194
+ rollbackChild.greenPorts = oldChild.greenPorts;
195
+ }
196
+ }
197
+ }
198
+ } else {
199
+ const rollbackChildIndex = rollbackBlocklet.children.findIndex((c) => c.meta.did === child.meta.did);
200
+ if (rollbackChildIndex !== -1) {
201
+ rollbackBlocklet.children[rollbackChildIndex] = child;
202
+ }
203
+ }
204
+ }
205
+
206
+ await states.blocklet.upgradeBlocklet({ ...rollbackBlocklet });
207
+ manager.configSynchronizer.throttledSyncAppConfig(rollbackBlocklet);
163
208
  await manager._updateDependents(did);
209
+ manager.emit(BlockletEvents.statusChange, { ...rollbackBlocklet, error: { message: err.message } });
164
210
 
165
211
  const actionName = action === INSTALL_ACTIONS.INSTALL_COMPONENT ? 'install' : 'upgrade';
166
212
  const notificationEvent =
@@ -318,6 +318,7 @@ module.exports = ({
318
318
  description: `Blocklet Server is ${status} successfully`,
319
319
  entityType: 'node',
320
320
  status: 'success',
321
+ source: 'system',
321
322
  });
322
323
  };
323
324
 
package/lib/index.js CHANGED
@@ -684,6 +684,7 @@ function ABTNode(options) {
684
684
  if (['deleteBlocklet', 'installBlocklet'].includes(params.action) || teamDid === options.nodeDid) {
685
685
  const result = await states.auditLog.create(params, instance);
686
686
  // 如果是 installBlocklet, 不需要提前返回, 要将 log 记录在 service 中
687
+ // 如果是 deleteBlocklet, 需要提前返回,因为 deleteBlocklet 会触发 blocklet 的删除,不需要再往 service 的auditLog 表中插入记录了
687
688
  if (params.action !== 'installBlocklet') {
688
689
  return result;
689
690
  }
@@ -2,7 +2,6 @@
2
2
  /* eslint-disable no-await-in-loop */
3
3
  /* eslint-disable function-paren-newline */
4
4
  /* eslint-disable no-underscore-dangle */
5
- const pick = require('lodash/pick');
6
5
  const omit = require('lodash/omit');
7
6
  const uniq = require('lodash/uniq');
8
7
  const cloneDeep = require('@abtnode/util/lib/deep-clone');
@@ -15,7 +14,6 @@ const {
15
14
  forEachBlocklet,
16
15
  forEachBlockletSync,
17
16
  forEachComponentV2,
18
- forEachComponentV2Sync,
19
17
  getBlockletServices,
20
18
  hasStartEngine,
21
19
  } = require('@blocklet/meta/lib/util');
@@ -591,14 +589,13 @@ class BlockletState extends BaseState {
591
589
  return res;
592
590
  }
593
591
 
594
- // update children status
595
- forEachComponentV2Sync(doc, (component) => {
592
+ for (const component of doc.children || []) {
596
593
  if (component.meta.group === BlockletGroup.gateway) {
597
- return;
594
+ continue;
598
595
  }
599
596
 
600
597
  if (shouldSkipComponent(component.meta.did, componentDids)) {
601
- return;
598
+ continue;
602
599
  }
603
600
 
604
601
  component[isGreen ? 'greenStatus' : 'status'] = status;
@@ -616,11 +613,16 @@ class BlockletState extends BaseState {
616
613
  }
617
614
  component.operator = operator;
618
615
  component.inProgressStart = Date.now();
619
- });
616
+ }
620
617
 
621
- const isSetStatus = status === BlockletStatus.downloading || status === BlockletStatus.waiting;
622
- const updateData = isSetStatus ? pick(doc, ['status', 'children']) : pick(doc, ['children']);
623
- updateData.operator = operator;
618
+ const shouldSetStatus = status === BlockletStatus.downloading || status === BlockletStatus.waiting;
619
+ const updateData = {
620
+ children: doc.children,
621
+ operator,
622
+ };
623
+ if (shouldSetStatus) {
624
+ updateData.status = status;
625
+ }
624
626
 
625
627
  const res = await this.updateBlocklet(did, updateData);
626
628
  return res;
@@ -223,7 +223,7 @@ class NotificationState extends BaseState {
223
223
  });
224
224
  return result.length > 0 ? result.map((item) => item.did) : [did];
225
225
  } catch (error) {
226
- logger.error('getUserDids error: ', error);
226
+ logger.warn('getUserDids error: ', error);
227
227
  return [did];
228
228
  }
229
229
  }
@@ -798,16 +798,18 @@ class NotificationState extends BaseState {
798
798
  },
799
799
  };
800
800
 
801
- const receiverDids = await this.getUserDids(receiver);
801
+ const includeWhere = {};
802
+ if (receiver) {
803
+ const receiverDids = await this.getUserDids(receiver);
804
+ includeWhere.receiver = { [Op.in]: receiverDids };
805
+ }
802
806
 
803
807
  const include = [
804
808
  {
805
809
  model: this.notificationReceivers.model,
806
810
  as: 'receivers',
807
811
  attributes: [],
808
- where: {
809
- receiver: { [Op.in]: receiverDids },
810
- },
812
+ where: includeWhere,
811
813
  required: false,
812
814
  },
813
815
  ];
@@ -243,9 +243,23 @@ class TeamManager extends EventEmitter {
243
243
  users = users.concat(roleUsers);
244
244
  }
245
245
  if (userDids.length > 0) {
246
- const queryUsers = await Promise.all(
247
- userDids.map((did) => userState.getUser(did, { includePassports: true, enableConnectedAccount: true }))
248
- );
246
+ let queryUsers = [];
247
+ if (userDids.includes('*')) {
248
+ queryUsers = await userState.getUsersByDids({
249
+ dids: userDids,
250
+ query: {
251
+ approved: true,
252
+ selection,
253
+ includeConnectedAccounts,
254
+ includePassports: true,
255
+ },
256
+ });
257
+ } else {
258
+ // 使用 getUser 查询的目的是为了避免传入的 receiver 不在user表中而存在于 connected_account 表中
259
+ queryUsers = await Promise.all(
260
+ userDids.map((did) => userState.getUser(did, { includePassports: true, enableConnectedAccount: true }))
261
+ );
262
+ }
249
263
 
250
264
  const validUsers = queryUsers.filter((user, index) => {
251
265
  if (!user) {