@abtnode/core 1.16.49-beta-20250823-082650-626c1473 → 1.16.49-beta-20250827-025603-2bb1a7ee

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/lib/api/team.js CHANGED
@@ -188,9 +188,8 @@ const getUserSessionWhere = ({ status, blocklet }) => {
188
188
 
189
189
  // 关注取消关注相关接口
190
190
  const USER_RELATION_ACTIONS = {
191
- follow: (state, followerDid, userDid) => state.followUser(followerDid, userDid),
192
- unfollow: (state, followerDid, userDid) => state.unfollowUser(followerDid, userDid),
193
- isFollowing: (state, followerDid, userDid) => state.isFollowing(followerDid, userDid),
191
+ follow: (state, followerDid, userDid, options) => state.followUser(followerDid, userDid, options),
192
+ unfollow: (state, followerDid, userDid, options) => state.unfollowUser(followerDid, userDid, options),
194
193
  };
195
194
 
196
195
  // 获取用户相关接口
@@ -400,7 +399,7 @@ class TeamAPI extends EventEmitter {
400
399
  return doc;
401
400
  }
402
401
 
403
- async getUsers({ teamDid, query, paging: inputPaging, sort, dids }) {
402
+ async getUsers({ teamDid, query, paging: inputPaging, sort, dids }, context = {}) {
404
403
  const state = await this.getUserState(teamDid);
405
404
  const nodeInfo = await this.node.read();
406
405
 
@@ -423,7 +422,7 @@ class TeamAPI extends EventEmitter {
423
422
  let paging;
424
423
 
425
424
  if (dids) {
426
- list = await state.getUsersByDids({ query, dids });
425
+ list = await state.getUsersByDids({ query, dids }, context);
427
426
  paging = {
428
427
  total: list.length,
429
428
  pageSize: dids.length,
@@ -431,7 +430,7 @@ class TeamAPI extends EventEmitter {
431
430
  page: 1,
432
431
  };
433
432
  } else {
434
- const doc = await state.getUsers({ query, sort, paging: { pageSize: 20, ...inputPaging } });
433
+ const doc = await state.getUsers({ query, sort, paging: { pageSize: 20, ...inputPaging } }, context);
435
434
  list = doc.list;
436
435
  paging = doc.paging;
437
436
  }
@@ -484,6 +483,7 @@ class TeamAPI extends EventEmitter {
484
483
  'connectedAccounts',
485
484
 
486
485
  'metadata',
486
+ 'isFollowing',
487
487
  ]);
488
488
 
489
489
  return {
@@ -590,8 +590,8 @@ class TeamAPI extends EventEmitter {
590
590
  return full || owner;
591
591
  }
592
592
 
593
- async userFollowAction({ teamDid, userDid, action = 'follow' }, context = {}) {
594
- const { userDid: followerDid } = context;
593
+ async userFollowAction({ teamDid, userDid, followerDid, action = 'follow', options = {} }, context = {}) {
594
+ const targetDid = followerDid || context.userDid;
595
595
 
596
596
  if (!USER_RELATION_ACTIONS[action]) {
597
597
  throw new CustomError(
@@ -599,12 +599,49 @@ class TeamAPI extends EventEmitter {
599
599
  `Invalid action: ${action}. Supported: ${Object.keys(USER_RELATION_ACTIONS).join(', ')}`
600
600
  );
601
601
  }
602
+ let result;
603
+ try {
604
+ const state = await this.getUserState(teamDid);
605
+ result = await USER_RELATION_ACTIONS[action](state, targetDid, userDid, options);
606
+ } catch (error) {
607
+ logger.error(`Failed to ${action} user`, {
608
+ followerDid: targetDid,
609
+ userDid,
610
+ error,
611
+ });
612
+ throw error;
613
+ }
602
614
 
603
- const state = await this.getUserState(teamDid);
604
- return USER_RELATION_ACTIONS[action](state, followerDid, userDid);
615
+ try {
616
+ if (action === 'follow' && !options.skipNotification) {
617
+ const currentUser = await this.getUser({ teamDid, user: { did: targetDid } });
618
+ await this.createNotification({
619
+ teamDid,
620
+ receiver: userDid,
621
+ title: 'Followed',
622
+ description: `<${currentUser.fullName}(did:abt:${currentUser.did})> followed you`,
623
+ activity: {
624
+ type: 'follow',
625
+ actor: followerDid,
626
+ target: {
627
+ type: 'user',
628
+ id: followerDid,
629
+ },
630
+ },
631
+ entityId: teamDid,
632
+ source: 'system',
633
+ severity: 'success',
634
+ });
635
+ }
636
+ } catch (error) {
637
+ // 消息创建失败,不影响 follow 操作
638
+ logger.error('Failed to create notification', { error });
639
+ }
640
+
641
+ return result;
605
642
  }
606
643
 
607
- async getUserFollows({ teamDid, userDid, type = 'following', paging, sort }, context = {}) {
644
+ async getUserFollows({ teamDid, userDid, type = 'following', paging, sort, options = {} }, context = {}) {
608
645
  const state = await this.getUserState(teamDid);
609
646
 
610
647
  const blocklet = await getBlocklet({ did: teamDid, states: this.states, dataDirs: this.dataDirs });
@@ -624,13 +661,14 @@ class TeamAPI extends EventEmitter {
624
661
  {
625
662
  paging,
626
663
  sort,
664
+ ...options,
627
665
  },
628
666
  context
629
667
  );
630
668
 
631
669
  list.forEach((item) => {
632
670
  const { user } = item;
633
- if (user?.avatar && user?.avatar?.startsWith(USER_AVATAR_URL_PREFIX)) {
671
+ if (user && user?.avatar && user?.avatar?.startsWith(USER_AVATAR_URL_PREFIX)) {
634
672
  user.avatar = `${getFederatedUserAvatarUrl(user.avatar, blocklet)}?imageFilter=resize&w=48&h=48`;
635
673
  }
636
674
  });
@@ -645,14 +683,17 @@ class TeamAPI extends EventEmitter {
645
683
  }
646
684
  }
647
685
 
648
- async getUserFollowStats({ teamDid, userDid }) {
686
+ async getUserFollowStats({ teamDid, userDids }) {
649
687
  const state = await this.getUserState(teamDid);
650
- try {
651
- return state.getFollowStats(userDid);
652
- } catch (error) {
653
- logger.error('Failed to get follow stats', { error });
654
- throw error;
688
+ return state.getFollowStats(userDids);
689
+ }
690
+
691
+ async checkFollowing({ teamDid, userDids = [], followerDid }) {
692
+ if (!followerDid) {
693
+ throw new CustomError(400, 'Follower DID is required');
655
694
  }
695
+ const state = await this.getUserState(teamDid);
696
+ return state.isFollowing(followerDid, userDids);
656
697
  }
657
698
 
658
699
  async updateUser({ teamDid, user }) {
@@ -439,9 +439,6 @@ class DiskBlockletManager extends BaseBlockletManager {
439
439
  restart: async (params) => {
440
440
  await this.restart(params);
441
441
  },
442
- stop: async (params) => {
443
- await this.stop(params);
444
- },
445
442
  createAuditLog: (params) => this.createAuditLog(params),
446
443
  notification: (did, title, description, severity) => {
447
444
  try {
@@ -793,7 +790,15 @@ class DiskBlockletManager extends BaseBlockletManager {
793
790
  }
794
791
 
795
792
  async start(
796
- { did, throwOnError, checkHealthImmediately = false, e2eMode = false, componentDids: inputComponentDids, atomic },
793
+ {
794
+ did,
795
+ throwOnError,
796
+ checkHealthImmediately = false,
797
+ e2eMode = false,
798
+ componentDids: inputComponentDids,
799
+ atomic,
800
+ operator,
801
+ },
797
802
  context
798
803
  ) {
799
804
  const blocklet = await this.ensureBlocklet(did, { e2eMode });
@@ -823,29 +828,50 @@ class DiskBlockletManager extends BaseBlockletManager {
823
828
  });
824
829
 
825
830
  if (atomic || !blocklet.structVersion) {
826
- return this._start({ blocklet, throwOnError, checkHealthImmediately, e2eMode, componentDids }, context);
831
+ return this._start({ blocklet, throwOnError, checkHealthImmediately, e2eMode, componentDids, operator }, context);
827
832
  }
828
833
 
829
834
  const tasks = componentDids.map(
830
835
  (componentDid) => () =>
831
- this._start({ blocklet, throwOnError, checkHealthImmediately, e2eMode, componentDids: [componentDid] }, context)
836
+ this._start(
837
+ {
838
+ blocklet,
839
+ throwOnError,
840
+ checkHealthImmediately,
841
+ e2eMode,
842
+ componentDids: [componentDid],
843
+ operator,
844
+ },
845
+ context
846
+ )
832
847
  );
833
848
 
834
- const rest = await pAll(tasks, { concurrency: 4 });
849
+ const rest = await pAll(tasks, { concurrency: 6 });
835
850
 
836
851
  return rest[0];
837
852
  }
838
853
 
839
854
  async _start(
840
- { blocklet: inputBlocklet, did, throwOnError, checkHealthImmediately = false, e2eMode = false, componentDids },
855
+ {
856
+ blocklet: inputBlocklet,
857
+ did,
858
+ throwOnError,
859
+ checkHealthImmediately = false,
860
+ e2eMode = false,
861
+ componentDids,
862
+ operator: _operator,
863
+ },
841
864
  context
842
865
  ) {
866
+ const operator = _operator || context?.user?.did;
867
+
843
868
  logger.info('start blocklet', {
844
869
  did: did || inputBlocklet.meta.did,
845
870
  componentDids,
846
871
  throwOnError,
847
872
  checkHealthImmediately,
848
873
  e2eMode,
874
+ operator,
849
875
  });
850
876
  // should check blocklet integrity
851
877
  const blocklet1 = inputBlocklet || (await this.ensureBlocklet(did, { e2eMode }));
@@ -875,11 +901,9 @@ class DiskBlockletManager extends BaseBlockletManager {
875
901
  }
876
902
  }
877
903
 
878
- // blocklet may be manually stopped durning starting
879
- // so error message would not be sent if blocklet is stopped
880
- // so we need update status first
881
904
  const doc1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.starting, {
882
905
  componentDids,
906
+ operator,
883
907
  });
884
908
  blocklet1.status = BlockletStatus.starting;
885
909
  this.emit(BlockletEvents.statusChange, doc1);
@@ -990,7 +1014,7 @@ class DiskBlockletManager extends BaseBlockletManager {
990
1014
  });
991
1015
 
992
1016
  await this.deleteProcess({ did, componentDids });
993
- const res = await states.blocklet.setBlockletStatus(did, BlockletStatus.error, { componentDids });
1017
+ const res = await states.blocklet.setBlockletStatus(did, BlockletStatus.error, { componentDids, operator });
994
1018
  this.emit(BlockletEvents.startFailed, { ...res, componentDids, error: { message: error.message } });
995
1019
  this.emit(BlockletEvents.statusChange, { ...res, error: { message: error.message } });
996
1020
 
@@ -1002,14 +1026,15 @@ class DiskBlockletManager extends BaseBlockletManager {
1002
1026
  }
1003
1027
  }
1004
1028
 
1005
- async stop({ did, updateStatus = true, silent = false, componentDids, reason }, context) {
1006
- logger.info('stop blocklet', { did, componentDids, updateStatus, silent });
1029
+ async stop({ did, updateStatus = true, silent = false, componentDids, reason, operator: _operator }, context) {
1030
+ const operator = _operator || context?.user?.did;
1031
+ logger.info('stop blocklet', { did, componentDids, updateStatus, silent, operator });
1007
1032
 
1008
1033
  const blocklet = await this.getBlocklet(did);
1009
1034
  const { processId } = blocklet.env;
1010
1035
 
1011
1036
  if (updateStatus) {
1012
- const doc = await states.blocklet.setBlockletStatus(did, BlockletStatus.stopping, { componentDids });
1037
+ const doc = await states.blocklet.setBlockletStatus(did, BlockletStatus.stopping, { componentDids, operator });
1013
1038
  blocklet.status = BlockletStatus.stopping;
1014
1039
  this.emit(BlockletEvents.statusChange, doc);
1015
1040
  }
@@ -1055,7 +1080,7 @@ class DiskBlockletManager extends BaseBlockletManager {
1055
1080
  } catch (error) {
1056
1081
  logger.error('Failed to stop blocklet', { error, did });
1057
1082
  if (updateStatus) {
1058
- const res = await states.blocklet.setBlockletStatus(did, BlockletStatus.error, { componentDids });
1083
+ const res = await states.blocklet.setBlockletStatus(did, BlockletStatus.error, { componentDids, operator });
1059
1084
  this.emit(BlockletEvents.statusChange, res);
1060
1085
  }
1061
1086
  throw error;
@@ -1066,7 +1091,7 @@ class DiskBlockletManager extends BaseBlockletManager {
1066
1091
  launcher.notifyBlockletUpdated(blocklet);
1067
1092
 
1068
1093
  if (updateStatus) {
1069
- const res = await states.blocklet.setBlockletStatus(did, BlockletStatus.stopped, { componentDids });
1094
+ const res = await states.blocklet.setBlockletStatus(did, BlockletStatus.stopped, { componentDids, operator });
1070
1095
  // send notification to websocket channel
1071
1096
  this.emit(BlockletEvents.statusChange, res);
1072
1097
 
@@ -1173,11 +1198,15 @@ class DiskBlockletManager extends BaseBlockletManager {
1173
1198
  * @param {Record<string, any>} context
1174
1199
  * @returns {import('@blocklet/server-js').BlockletState}
1175
1200
  */
1176
- async restart({ did, componentDids }, context) {
1177
- logger.info('restart blocklet', { did });
1201
+ async restart({ did, componentDids, operator: _operator }, context) {
1202
+ const operator = _operator || context?.user?.did;
1203
+ logger.info('restart blocklet', { did, operator });
1178
1204
  const blocklet = await this.getBlocklet(did);
1179
1205
  await this.checkControllerStatus(blocklet, 'restart');
1180
- await states.blocklet.setBlockletStatus(did, BlockletStatus.stopping, { componentDids });
1206
+ await states.blocklet.setBlockletStatus(did, BlockletStatus.stopping, {
1207
+ componentDids,
1208
+ operator,
1209
+ });
1181
1210
  const result = await states.blocklet.getBlocklet(did);
1182
1211
  this.emit(BlockletEvents.statusChange, result);
1183
1212
 
@@ -1187,12 +1216,13 @@ class DiskBlockletManager extends BaseBlockletManager {
1187
1216
  id: `${did}/${(componentDids || []).join(',')}`,
1188
1217
  did,
1189
1218
  componentDids,
1219
+ operator,
1190
1220
  context,
1191
1221
  });
1192
1222
  ticket.on('failed', async (err) => {
1193
1223
  logger.error('failed to restart blocklet', { did, error: err });
1194
1224
 
1195
- const state = await states.blocklet.setBlockletStatus(did, BlockletStatus.stopped, { componentDids });
1225
+ const state = await states.blocklet.setBlockletStatus(did, BlockletStatus.stopped, { componentDids, operator });
1196
1226
  this.emit(BlockletEvents.statusChange, state);
1197
1227
 
1198
1228
  const description = `${getComponentNamesWithVersion(result, componentDids)} restart failed for ${getDisplayName(
@@ -3276,9 +3306,9 @@ class DiskBlockletManager extends BaseBlockletManager {
3276
3306
  }
3277
3307
  }
3278
3308
 
3279
- async _onRestart({ did, componentDids, context }) {
3280
- await this.stop({ did, componentDids, updateStatus: false }, context);
3281
- await this.start({ did, componentDids }, context);
3309
+ async _onRestart({ did, componentDids, context, operator }) {
3310
+ await this.stop({ did, componentDids, updateStatus: false, operator }, context);
3311
+ await this.start({ did, componentDids, operator }, context);
3282
3312
  }
3283
3313
 
3284
3314
  async _onCheckIfStarted(jobInfo, { throwOnError } = {}) {
@@ -3,6 +3,7 @@ const pAll = require('p-all');
3
3
  const { BlockletStatus } = require('@blocklet/constant');
4
4
  const sleep = require('@abtnode/util/lib/sleep');
5
5
  const { getDisplayName } = require('@blocklet/meta/lib/util');
6
+ const { isValid } = require('@arcblock/did');
6
7
 
7
8
  const states = require('../../states');
8
9
  const { isBlockletPortHealthy, shouldCheckHealthy } = require('../../util/blocklet');
@@ -31,6 +32,9 @@ class EnsureBlockletRunning {
31
32
 
32
33
  highLoadDisk = +process.env.ABT_NODE_ENSURE_RUNNING_HIGH_LOAD_DISK || 0.95;
33
34
 
35
+ // 进行中状态超时时间(毫秒)
36
+ inProgressTimeout = +process.env.ABT_NODE_ENSURE_RUNNING_IN_PROGRESS_TIMEOUT || 5 * 60 * 1000;
37
+
34
38
  runningBlocklets = {};
35
39
 
36
40
  runningRootBlocklets = {};
@@ -211,6 +215,43 @@ class EnsureBlockletRunning {
211
215
  return;
212
216
  }
213
217
 
218
+ // Skip health check if blocklet is in progress status
219
+ if (inProgressStatuses.includes(blocklet.status)) {
220
+ // Check if it's user-initiated operation
221
+ // 如果 operator 是 z 开头的字符串,表示是 did, 跳过健康检查
222
+ if (blocklet.operator && isValid(blocklet.operator)) {
223
+ logger.info('Skip ensure running check for user-initiated operation', {
224
+ did,
225
+ componentDid: blocklet.meta.did,
226
+ status: blocklet.status,
227
+ operator: blocklet.operator,
228
+ });
229
+ return;
230
+ }
231
+
232
+ // Check timeout for daemon-initiated or no operator recorded operations
233
+ if (blocklet.inProgressStart) {
234
+ const elapsedTime = Date.now() - new Date(blocklet.inProgressStart).getTime();
235
+ if (elapsedTime < this.inProgressTimeout) {
236
+ logger.info('Skip ensure running check due to timeout not reached', {
237
+ did,
238
+ componentDid: blocklet.meta.did,
239
+ status: blocklet.status,
240
+ elapsedTime,
241
+ timeout: this.inProgressTimeout,
242
+ });
243
+ return;
244
+ }
245
+ logger.warn('InProgress timeout reached, proceeding with health check', {
246
+ did,
247
+ componentDid: blocklet.meta.did,
248
+ status: blocklet.status,
249
+ elapsedTime,
250
+ timeout: this.inProgressTimeout,
251
+ });
252
+ }
253
+ }
254
+
214
255
  const health = await this.isBlockletPortHealthyWithRetries(
215
256
  blocklet,
216
257
  inProgressStatuses.includes(blocklet.status)
@@ -266,7 +307,13 @@ class EnsureBlockletRunning {
266
307
 
267
308
  try {
268
309
  logger.info('restart blocklet:', did, componentDids);
269
- await this.restart({ did, componentDids, checkHealthImmediately: true });
310
+ await this.restart({
311
+ did,
312
+ componentDids,
313
+ checkHealthImmediately: true,
314
+ atomic: true,
315
+ operator: 'ensure-blocklet-running',
316
+ });
270
317
  if (this.whenCycleCheck) {
271
318
  this.createAuditLog({
272
319
  action: 'ensureBlockletRunning',
@@ -38923,7 +38923,7 @@ module.exports = require("zlib");
38923
38923
  /***/ ((module) => {
38924
38924
 
38925
38925
  "use strict";
38926
- module.exports = /*#__PURE__*/JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.48","description":"","main":"lib/index.js","files":["lib"],"scripts":{"lint":"eslint tests lib --ignore-pattern \'tests/assets/*\'","lint:fix":"eslint --fix tests lib","test":"node tools/jest.js","coverage":"npm run test -- --coverage"},"keywords":[],"author":"wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)","license":"Apache-2.0","dependencies":{"@abtnode/analytics":"1.16.48","@abtnode/auth":"1.16.48","@abtnode/certificate-manager":"1.16.48","@abtnode/constant":"1.16.48","@abtnode/cron":"1.16.48","@abtnode/db-cache":"1.16.48","@abtnode/docker-utils":"1.16.48","@abtnode/logger":"1.16.48","@abtnode/models":"1.16.48","@abtnode/queue":"1.16.48","@abtnode/rbac":"1.16.48","@abtnode/router-provider":"1.16.48","@abtnode/static-server":"1.16.48","@abtnode/timemachine":"1.16.48","@abtnode/util":"1.16.48","@aigne/aigne-hub":"^0.6.8","@arcblock/did":"1.22.2","@arcblock/did-connect-js":"1.22.2","@arcblock/did-ext":"1.22.2","@arcblock/did-motif":"^1.1.14","@arcblock/did-util":"1.22.2","@arcblock/event-hub":"1.22.2","@arcblock/jwt":"1.22.2","@arcblock/pm2-events":"^0.0.5","@arcblock/validator":"1.22.2","@arcblock/vc":"1.22.2","@blocklet/constant":"1.16.48","@blocklet/did-space-js":"^1.1.18","@blocklet/env":"1.16.48","@blocklet/error":"^0.2.5","@blocklet/meta":"1.16.48","@blocklet/resolver":"1.16.48","@blocklet/sdk":"1.16.48","@blocklet/server-js":"1.16.48","@blocklet/store":"1.16.48","@blocklet/theme":"^3.1.27","@fidm/x509":"^1.2.1","@ocap/mcrypto":"1.22.2","@ocap/util":"1.22.2","@ocap/wallet":"1.22.2","@slack/webhook":"^5.0.4","archiver":"^7.0.1","axios":"^1.7.9","axon":"^2.0.3","chalk":"^4.1.2","cross-spawn":"^7.0.3","dayjs":"^1.11.13","deep-diff":"^1.0.2","detect-port":"^1.5.1","envfile":"^7.1.0","escape-string-regexp":"^4.0.0","fast-glob":"^3.3.2","filesize":"^10.1.1","flat":"^5.0.2","fs-extra":"^11.2.0","get-port":"^5.1.1","hasha":"^5.2.2","is-base64":"^1.1.0","is-cidr":"4","is-ip":"3","is-url":"^1.2.4","joi":"17.12.2","joi-extension-semver":"^5.0.0","js-yaml":"^4.1.0","kill-port":"^2.0.1","lodash":"^4.17.21","node-stream-zip":"^1.15.0","p-all":"^3.0.0","p-limit":"^3.1.0","p-map":"^4.0.0","p-retry":"^4.6.2","p-wait-for":"^3.2.0","private-ip":"^2.3.4","rate-limiter-flexible":"^5.0.5","read-last-lines":"^1.8.0","semver":"^7.6.3","sequelize":"^6.35.0","shelljs":"^0.8.5","slugify":"^1.6.6","ssri":"^8.0.1","stream-throttle":"^0.1.3","stream-to-promise":"^3.0.0","systeminformation":"^5.23.3","tail":"^2.2.4","tar":"^6.1.11","transliteration":"^2.3.5","ua-parser-js":"^1.0.2","ufo":"^1.5.3","uuid":"^11.1.0","valid-url":"^1.0.9","which":"^2.0.2","xbytes":"^1.8.0"},"devDependencies":{"expand-tilde":"^2.0.2","express":"^4.18.2","jest":"^29.7.0","unzipper":"^0.10.11"},"gitHead":"e5764f753181ed6a7c615cd4fc6682aacf0cb7cd"}');
38926
+ module.exports = /*#__PURE__*/JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.48","description":"","main":"lib/index.js","files":["lib"],"scripts":{"lint":"eslint tests lib --ignore-pattern \'tests/assets/*\'","lint:fix":"eslint --fix tests lib","test":"node tools/jest.js","coverage":"npm run test -- --coverage"},"keywords":[],"author":"wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)","license":"Apache-2.0","dependencies":{"@abtnode/analytics":"1.16.48","@abtnode/auth":"1.16.48","@abtnode/certificate-manager":"1.16.48","@abtnode/constant":"1.16.48","@abtnode/cron":"1.16.48","@abtnode/db-cache":"1.16.48","@abtnode/docker-utils":"1.16.48","@abtnode/logger":"1.16.48","@abtnode/models":"1.16.48","@abtnode/queue":"1.16.48","@abtnode/rbac":"1.16.48","@abtnode/router-provider":"1.16.48","@abtnode/static-server":"1.16.48","@abtnode/timemachine":"1.16.48","@abtnode/util":"1.16.48","@aigne/aigne-hub":"^0.6.9","@arcblock/did":"1.22.2","@arcblock/did-connect-js":"1.22.2","@arcblock/did-ext":"1.22.2","@arcblock/did-motif":"^1.1.14","@arcblock/did-util":"1.22.2","@arcblock/event-hub":"1.22.2","@arcblock/jwt":"1.22.2","@arcblock/pm2-events":"^0.0.5","@arcblock/validator":"1.22.2","@arcblock/vc":"1.22.2","@blocklet/constant":"1.16.48","@blocklet/did-space-js":"^1.1.18","@blocklet/env":"1.16.48","@blocklet/error":"^0.2.5","@blocklet/meta":"1.16.48","@blocklet/resolver":"1.16.48","@blocklet/sdk":"1.16.48","@blocklet/server-js":"1.16.48","@blocklet/store":"1.16.48","@blocklet/theme":"^3.1.30","@fidm/x509":"^1.2.1","@ocap/mcrypto":"1.22.2","@ocap/util":"1.22.2","@ocap/wallet":"1.22.2","@slack/webhook":"^5.0.4","archiver":"^7.0.1","axios":"^1.7.9","axon":"^2.0.3","chalk":"^4.1.2","cross-spawn":"^7.0.3","dayjs":"^1.11.13","deep-diff":"^1.0.2","detect-port":"^1.5.1","envfile":"^7.1.0","escape-string-regexp":"^4.0.0","fast-glob":"^3.3.2","filesize":"^10.1.1","flat":"^5.0.2","fs-extra":"^11.2.0","get-port":"^5.1.1","hasha":"^5.2.2","is-base64":"^1.1.0","is-cidr":"4","is-ip":"3","is-url":"^1.2.4","joi":"17.12.2","joi-extension-semver":"^5.0.0","js-yaml":"^4.1.0","kill-port":"^2.0.1","lodash":"^4.17.21","node-stream-zip":"^1.15.0","p-all":"^3.0.0","p-limit":"^3.1.0","p-map":"^4.0.0","p-retry":"^4.6.2","p-wait-for":"^3.2.0","private-ip":"^2.3.4","rate-limiter-flexible":"^5.0.5","read-last-lines":"^1.8.0","semver":"^7.6.3","sequelize":"^6.35.0","shelljs":"^0.8.5","slugify":"^1.6.6","ssri":"^8.0.1","stream-throttle":"^0.1.3","stream-to-promise":"^3.0.0","systeminformation":"^5.23.3","tail":"^2.2.4","tar":"^6.1.11","transliteration":"^2.3.5","ua-parser-js":"^1.0.2","ufo":"^1.5.3","uuid":"^11.1.0","valid-url":"^1.0.9","which":"^2.0.2","xbytes":"^1.8.0"},"devDependencies":{"expand-tilde":"^2.0.2","express":"^4.18.2","jest":"^29.7.0","unzipper":"^0.10.11"},"gitHead":"e5764f753181ed6a7c615cd4fc6682aacf0cb7cd"}');
38927
38927
 
38928
38928
  /***/ }),
38929
38929
 
package/lib/index.js CHANGED
@@ -536,11 +536,11 @@ function ABTNode(options) {
536
536
  // user follow
537
537
  followUser: (params, context) => teamAPI.userFollowAction({ ...params, action: 'follow' }, context),
538
538
  unfollowUser: (params, context) => teamAPI.userFollowAction({ ...params, action: 'unfollow' }, context),
539
- isFollowing: (params, context) => teamAPI.userFollowAction({ ...params, action: 'isFollowing' }, context),
540
539
 
541
540
  getUserFollowers: (params, context) => teamAPI.getUserFollows({ ...params, type: 'followers' }, context),
542
541
  getUserFollowing: (params, context) => teamAPI.getUserFollows({ ...params, type: 'following' }, context),
543
542
  getUserFollowStats: teamAPI.getUserFollowStats.bind(teamAPI),
543
+ checkFollowing: teamAPI.checkFollowing.bind(teamAPI),
544
544
 
545
545
  // Tagging
546
546
  createTag: teamAPI.createTag.bind(teamAPI),
@@ -311,7 +311,7 @@ Router.formatSites = (sites = []) => {
311
311
  const rules = Array.isArray(site.rules) ? cloneDeep(site.rules) : [];
312
312
  const grouped = {};
313
313
 
314
- // 0. serve robots.txt/sitemap.xml from root and proxy to daemon
314
+ // 0. serve robots.txt/sitemap.xml and favicon.ico from root and proxy to daemon
315
315
  if (isBlockletSite(site.domain) && !site.rules.find((x) => x.from.pathPrefix === '/robots.txt')) {
316
316
  site.rules.push({
317
317
  dynamic: true,
@@ -329,6 +329,14 @@ Router.formatSites = (sites = []) => {
329
329
  });
330
330
  }
331
331
 
332
+ if (isBlockletSite(site.domain) && !site.rules.find((x) => x.from.pathPrefix === '/favicon.ico')) {
333
+ site.rules.push({
334
+ dynamic: true,
335
+ from: { root: true, pathPrefix: '/', groupPathPrefix: '/', pathSuffix: '/favicon.ico' },
336
+ to: { type: ROUTING_RULE_TYPES.SERVICE, port: process.env.ABT_NODE_SERVICE_PORT, did: site.blockletDid },
337
+ });
338
+ }
339
+
332
340
  // 1. serve blocklet.js for each component: both prefix and suffix do not contain trailing slash
333
341
  rules.forEach((rule) => {
334
342
  if ([ROUTING_RULE_TYPES.BLOCKLET].includes(rule.to.type) === false) {
@@ -555,8 +555,8 @@ class BlockletState extends BaseState {
555
555
  * componentDids?: Array<Did>
556
556
  * }}
557
557
  */
558
- async setBlockletStatus(did, status, { componentDids } = {}) {
559
- logger.info('setBlockletStatus', { did, status, componentDids });
558
+ async setBlockletStatus(did, status, { componentDids, operator = 'daemon' } = {}) {
559
+ logger.info('setBlockletStatus', { did, status, componentDids, operator });
560
560
  if (typeof status === 'undefined') {
561
561
  throw new Error('Unsupported blocklet status');
562
562
  }
@@ -568,14 +568,16 @@ class BlockletState extends BaseState {
568
568
  const doc = await this.getBlocklet(did);
569
569
 
570
570
  if (doc.meta?.group === BlockletGroup.gateway && !doc.children?.length) {
571
- const res = await this.updateBlocklet(did, { status });
571
+ const updateData = { status, operator };
572
+ const res = await this.updateBlocklet(did, updateData);
572
573
  statusLock.release();
573
574
  return res;
574
575
  }
575
576
 
576
577
  // for backward compatibility
577
578
  if (!doc.structVersion && !doc.children?.length) {
578
- const res = await this.updateBlocklet(did, { status });
579
+ const updateData = { status, operator };
580
+ const res = await this.updateBlocklet(did, updateData);
579
581
  statusLock.release();
580
582
  return res;
581
583
  }
@@ -599,9 +601,14 @@ class BlockletState extends BaseState {
599
601
  component.startedAt = null;
600
602
  component.stoppedAt = new Date();
601
603
  }
604
+ component.operator = operator;
605
+ component.inProgressStart = Date.now();
602
606
  });
603
607
 
604
- const res = await this.updateBlocklet(did, pick(doc, ['status', 'children']));
608
+ const updateData = pick(doc, ['status', 'children']);
609
+ updateData.operator = operator;
610
+
611
+ const res = await this.updateBlocklet(did, updateData);
605
612
  statusLock.release();
606
613
  return res;
607
614
  } catch (error) {
@@ -253,7 +253,7 @@ class User extends ExtendBase {
253
253
  /**
254
254
  * Get blocklet service user list
255
255
  */
256
- async getUsers({ query, sort, paging } = {}) {
256
+ async getUsers({ query, sort, paging } = {}, context = {}) {
257
257
  const where = {};
258
258
  const replacements = {};
259
259
 
@@ -268,7 +268,11 @@ class User extends ExtendBase {
268
268
  includeTags = false,
269
269
  includePassports = false,
270
270
  includeConnectedAccounts = false,
271
+ includeFollowStatus = false,
271
272
  } = query || {};
273
+
274
+ const { user } = context || {};
275
+
272
276
  const shouldIncludeTag = (tags && tags.length) || includeTags;
273
277
 
274
278
  if (isNullOrUndefined(approved) === false) {
@@ -417,18 +421,27 @@ SELECT did,inviter,generation FROM UserTree`.trim();
417
421
  }
418
422
 
419
423
  const result = await this.paginate({ where, include, replacements }, sorting, paging);
424
+
425
+ if (includeFollowStatus && user?.did) {
426
+ result.list = await this._enrichWithFollowStatus(result.list, user.did);
427
+ }
428
+
420
429
  return { list: result.list, paging: { ...result.paging, total: total || result.paging.total } };
421
430
  }
422
431
 
423
432
  // eslint-disable-next-line require-await
424
- async getUsersByDids({ dids, query }) {
433
+ async getUsersByDids({ dids, query }, context = {}) {
425
434
  const {
426
435
  approved,
427
436
  includeTags = false,
428
437
  includePassports = false,
429
438
  includeConnectedAccounts = false,
439
+ includeFollowStatus = false,
430
440
  selection = {},
431
441
  } = query || {};
442
+
443
+ const { user } = context || {};
444
+
432
445
  // 如果 dids 包含 *,则查询全部
433
446
  const condition = dids.includes('*') ? {} : { did: dids };
434
447
  if (isNullOrUndefined(approved) === false) {
@@ -448,7 +461,12 @@ SELECT did,inviter,generation FROM UserTree`.trim();
448
461
  include.push(this.getConnectedInclude());
449
462
  }
450
463
 
451
- const result = await this.find({ where: condition, include }, selection);
464
+ let result = await this.find({ where: condition, include }, selection);
465
+
466
+ if (includeFollowStatus && user?.did) {
467
+ result = await this._enrichWithFollowStatus(result, user.did, dids);
468
+ }
469
+
452
470
  return result;
453
471
  }
454
472
 
@@ -837,18 +855,40 @@ SELECT did,inviter,generation FROM UserTree`.trim();
837
855
  dids.forEach((did) => {
838
856
  const { error } = Joi.DID().validate(did);
839
857
  if (error) {
840
- throw new CustomError(400, `Invalid did: ${did}`);
858
+ throw new CustomError(400, JSON.stringify({ code: 'INVALID_USER', message: `Invalid did: ${did}` }));
841
859
  }
842
860
  });
843
861
 
844
862
  const users = await Promise.all(dids.map((did) => this.getUserByDid(did)));
845
863
  dids.forEach((did, index) => {
846
864
  if (!users[index]) {
847
- throw new CustomError(404, `User does not exist: ${did}`);
865
+ throw new CustomError(400, JSON.stringify({ code: 'USER_NOT_FOUND', message: `User does not exist: ${did}` }));
848
866
  }
849
867
  });
850
868
  }
851
869
 
870
+ /**
871
+ * 为用户列表添加关注状态
872
+ * @private
873
+ * @param {Array} users - 用户列表
874
+ * @param {string} currentUserDid - 当前用户的 DID
875
+ * @param {Array} userDids - 用户DID列表,如果未提供则从 users 中提取
876
+ * @returns {Promise<Array>} - 添加了 isFollowing 字段的用户列表
877
+ */
878
+ async _enrichWithFollowStatus(users, currentUserDid, userDids = null) {
879
+ if (!currentUserDid || !users || users.length === 0) {
880
+ return users;
881
+ }
882
+
883
+ const targetDids = userDids || users.map((item) => item.did);
884
+ const followerMap = await this.isFollowing(currentUserDid, targetDids);
885
+
886
+ return users.map((item) => ({
887
+ ...item,
888
+ isFollowing: followerMap[item.did],
889
+ }));
890
+ }
891
+
852
892
  /**
853
893
  * 关注用户
854
894
  * @param {string} followerDid - 关注者的 DID
@@ -858,7 +898,7 @@ SELECT did,inviter,generation FROM UserTree`.trim();
858
898
  checkUserFollowers(this.userFollowers);
859
899
 
860
900
  if (followerDid === userDid) {
861
- throw new CustomError(400, 'Cannot follow yourself');
901
+ throw new CustomError(400, JSON.stringify({ code: 'SELF_FOLLOW', message: 'Cannot follow yourself' }));
862
902
  }
863
903
 
864
904
  // 检查两个用户是否存在 + 检查是否已经关注(并行执行)
@@ -868,7 +908,7 @@ SELECT did,inviter,generation FROM UserTree`.trim();
868
908
  ]);
869
909
 
870
910
  if (existingFollow) {
871
- throw new CustomError(400, 'Already following this user');
911
+ throw new CustomError(400, JSON.stringify({ code: 'ALREADY_FOLLOWING', message: 'Already following this user' }));
872
912
  }
873
913
 
874
914
  // 创建关注关系
@@ -895,9 +935,22 @@ SELECT did,inviter,generation FROM UserTree`.trim();
895
935
 
896
936
  /**
897
937
  * 通用的关注关系查询函数
938
+ * @param {string} targetDid - 目标用户DID
939
+ * @param {string} type - 查询类型 'followers' 或 'following'
940
+ * @param {object} options - 选项
941
+ * @param {object} options.paging - 分页参数
942
+ * @param {object} options.sort - 排序参数
943
+ * @param {boolean} options.includeUserInfo - 是否包含用户详细信息,默认true
944
+ * @param {boolean} options.includeFollowStatus - 是否包含当前用户的关注状态,默认 true
945
+ * @param {object} context - 上下文,包含当前用户信息
898
946
  * @private
899
947
  */
900
- async _getFollowRelations(targetDid, type, { paging, sort, includeUserInfo = true } = {}, context = {}) {
948
+ async _getFollowRelations(
949
+ targetDid,
950
+ type,
951
+ { paging, sort, includeUserInfo = true, includeFollowStatus = true } = {},
952
+ context = {}
953
+ ) {
901
954
  checkUserFollowers(this.userFollowers);
902
955
 
903
956
  const { user: contextUser } = context;
@@ -911,44 +964,63 @@ SELECT did,inviter,generation FROM UserTree`.trim();
911
964
  const sorting = [['createdAt', sort?.createdAt ? order : 'DESC']];
912
965
  const result = await this.userFollowers.paginate({ where }, sorting, paging);
913
966
 
914
- // 如果需要包含用户信息,手动查询用户数据
967
+ // 准备用户信息映射
968
+ let userMap = new Map();
915
969
  if (includeUserInfo && this.models.User) {
916
970
  const userDids = [...new Set(result.list.map((follow) => (isFollowers ? follow.followerDid : follow.userDid)))];
917
971
  const users = await this.find({
918
972
  where: { did: { [Op.in]: userDids } },
919
973
  attributes: ['did', 'fullName', 'avatar', 'email'],
920
974
  });
921
- const userMap = new Map(users.map((user) => [user.did, user]));
922
-
923
- const enrichedList = await Promise.all(
924
- result.list.map(async (follow) => {
925
- const userDid = isFollowers ? follow.followerDid : follow.userDid;
926
- const user = userMap.get(userDid);
927
- const enrichedFollow = {
928
- ...follow,
929
- user: user ? { ...user } : null,
930
- };
975
+ userMap = new Map(users.map((user) => [user.did, user]));
976
+ }
931
977
 
932
- if (contextUser?.did && contextUser.did !== targetDid) {
933
- // 如果查看的是别人的关注列表,需要添加是否已关注的信息
934
- const isFollowing = await this.isFollowing(contextUser.did, user.did);
935
- enrichedFollow.isFollowing = isFollowing;
936
- } else if (isFollowers) {
937
- // 如果是查询粉丝,需要添加是否已关注的信息
938
- const isFollowing = await this.isFollowing(targetDid, follow.followerDid);
939
- enrichedFollow.isFollowing = isFollowing;
940
- } else {
941
- enrichedFollow.isFollowing = true;
942
- }
978
+ // 准备关注状态映射
979
+ let followingStatusMap = {};
980
+ if (includeFollowStatus && contextUser?.did) {
981
+ if (contextUser.did !== targetDid) {
982
+ // 查询当前用户对列表中所有用户的关注状态
983
+ const targetUserDids = result.list.map((follow) => (isFollowers ? follow.followerDid : follow.userDid));
984
+ followingStatusMap = await this.isFollowing(contextUser.did, targetUserDids);
985
+ } else if (isFollowers && targetDid) {
986
+ // 查询目标用户对所有粉丝的关注状态
987
+ const followerDids = result.list.map((follow) => follow.followerDid);
988
+ followingStatusMap = await this.isFollowing(targetDid, followerDids);
989
+ }
990
+ }
943
991
 
944
- return enrichedFollow;
945
- })
946
- );
992
+ // 构建增强的列表
993
+ const enrichedList = result.list.map((follow) => {
994
+ const userDid = isFollowers ? follow.followerDid : follow.userDid;
995
+ const enrichedFollow = { ...follow };
947
996
 
948
- result.list = enrichedList;
949
- }
997
+ // 添加用户信息
998
+ if (includeUserInfo && userMap.size > 0) {
999
+ const user = userMap.get(userDid);
1000
+ enrichedFollow.user = user ? { ...user } : null;
1001
+ }
950
1002
 
951
- if (!includeUserInfo) {
1003
+ // 添加关注状态
1004
+ if (includeFollowStatus && contextUser?.did) {
1005
+ if (contextUser.did !== targetDid) {
1006
+ // 如果查看的是别人的关注列表,需要添加是否已关注的信息
1007
+ enrichedFollow.isFollowing = followingStatusMap[userDid] || false;
1008
+ } else if (isFollowers) {
1009
+ // 如果是查询粉丝,需要添加是否已关注的信息
1010
+ enrichedFollow.isFollowing = followingStatusMap[follow.followerDid] || false;
1011
+ } else {
1012
+ // 查看自己的关注列表,默认都是已关注状态
1013
+ enrichedFollow.isFollowing = true;
1014
+ }
1015
+ }
1016
+
1017
+ return enrichedFollow;
1018
+ });
1019
+
1020
+ result.list = enrichedList;
1021
+
1022
+ // 如果不需要用户信息且不需要关注状态,只返回用户DID
1023
+ if (!includeUserInfo && !includeFollowStatus) {
952
1024
  result.list = result.list.map((follow) => (isFollowers ? follow.followerDid : follow.userDid));
953
1025
  }
954
1026
 
@@ -970,53 +1042,102 @@ SELECT did,inviter,generation FROM UserTree`.trim();
970
1042
  }
971
1043
 
972
1044
  /**
973
- * 检查用户A是否关注了用户B
1045
+ * 批量检查用户A是否关注了多个用户
974
1046
  * @param {string} followerDid - 关注者的 DID
975
- * @param {string} userDid - 被关注用户的 DID
1047
+ * @param {string[]} userDids - 被关注用户的 DID 数组
1048
+ * @returns {Promise<{[userDid: string]: boolean}>} - 返回一个对象,键为用户DID,值为是否关注的布尔值
976
1049
  */
977
- async isFollowing(followerDid, userDid) {
978
- if (!this.userFollowers) {
979
- return false;
1050
+ async isFollowing(followerDid, userDids) {
1051
+ if (!this.userFollowers || !followerDid || !Array.isArray(userDids) || userDids.length === 0) {
1052
+ return userDids.reduce((acc, userDid) => ({ ...acc, [userDid]: false }), {});
980
1053
  }
981
1054
 
982
1055
  try {
983
- const follow = await this.userFollowers.findOne({
984
- userDid,
1056
+ // 一次性查询所有关注关系
1057
+ const follows = await this.userFollowers.find({
985
1058
  followerDid,
1059
+ userDid: { [Op.in]: userDids },
1060
+ });
1061
+ // 构建已关注用户的 Set,提高查找效率
1062
+ const followingSet = new Set(follows.map((follow) => follow.userDid));
1063
+
1064
+ // 构建结果对象
1065
+ const result = {};
1066
+ userDids.forEach((userDid) => {
1067
+ result[userDid] = followingSet.has(userDid);
986
1068
  });
987
1069
 
988
- return !!follow;
1070
+ return result;
989
1071
  } catch (error) {
990
- logger.error('Failed to check following status:', error);
991
- return false;
1072
+ logger.error('Failed to check multiple following status:', error);
1073
+ // 出错时返回全部为 false 的结果
1074
+ return userDids.reduce((acc, userDid) => ({ ...acc, [userDid]: false }), {});
992
1075
  }
993
1076
  }
994
1077
 
995
1078
  /**
996
- * 获取用户的关注统计信息
997
- * @param {string} userDid - 用户的 DID
1079
+ * 批量获取多个用户的关注统计信息
1080
+ * @param {string[]} userDids - 用户的 DID 数组
1081
+ * @returns {Promise<{[userDid: string]: {followers: number, following: number}}>} - 返回对象,键为用户DID,值为统计信息
998
1082
  */
999
- async getFollowStats(userDid) {
1000
- if (!this.userFollowers) {
1001
- return {
1002
- followers: 0,
1003
- following: 0,
1004
- };
1083
+ async getFollowStats(userDids = []) {
1084
+ if (!this.userFollowers || !Array.isArray(userDids) || userDids.length === 0) {
1085
+ return userDids.reduce(
1086
+ (acc, userDid) => ({
1087
+ ...acc,
1088
+ [userDid]: { followers: 0, following: 0 },
1089
+ }),
1090
+ {}
1091
+ );
1005
1092
  }
1006
1093
 
1007
1094
  try {
1008
- const [followers, following] = await Promise.all([
1009
- this.userFollowers.count({ userDid }), // 粉丝数
1010
- this.userFollowers.count({ followerDid: userDid }), // 关注数
1095
+ // 使用原生 SQL 查询进行批量统计,提高性能
1096
+ const followersQuery = `
1097
+ SELECT "userDid", COUNT(*) as count
1098
+ FROM user_followers
1099
+ WHERE "userDid" IN (:userDids)
1100
+ GROUP BY "userDid"
1101
+ `;
1102
+
1103
+ const followingQuery = `
1104
+ SELECT "followerDid", COUNT(*) as count
1105
+ FROM user_followers
1106
+ WHERE "followerDid" IN (:userDids)
1107
+ GROUP BY "followerDid"
1108
+ `;
1109
+
1110
+ const [followersResults, followingResults] = await Promise.all([
1111
+ this.model.sequelize.query(followersQuery, { replacements: { userDids }, type: Sequelize.QueryTypes.SELECT }),
1112
+ this.model.sequelize.query(followingQuery, { replacements: { userDids }, type: Sequelize.QueryTypes.SELECT }),
1011
1113
  ]);
1012
1114
 
1013
- return {
1014
- followers,
1015
- following,
1016
- };
1115
+ // 使用 Map 构造函数和数组映射优化数据结构构建
1116
+ const followersMap = new Map(followersResults.map((row) => [row.userDid, Number(row.count)]));
1117
+ const followingMap = new Map(followingResults.map((row) => [row.followerDid, Number(row.count)]));
1118
+
1119
+ // 使用 Object.fromEntries 优化结果对象构建
1120
+ const result = Object.fromEntries(
1121
+ userDids.map((userDid) => [
1122
+ userDid,
1123
+ {
1124
+ followers: followersMap.get(userDid) || 0,
1125
+ following: followingMap.get(userDid) || 0,
1126
+ },
1127
+ ])
1128
+ );
1129
+
1130
+ return result;
1017
1131
  } catch (error) {
1018
- logger.error('Failed to get follow stats:', error);
1019
- return { followers: 0, following: 0 };
1132
+ logger.error('Failed to get multiple follow stats:', error);
1133
+ // 出错时返回全部为 0 的结果
1134
+ return userDids.reduce(
1135
+ (acc, userDid) => ({
1136
+ ...acc,
1137
+ [userDid]: { followers: 0, following: 0 },
1138
+ }),
1139
+ {}
1140
+ );
1020
1141
  }
1021
1142
  }
1022
1143
  }
@@ -925,8 +925,8 @@ const getProcessState = async (processId) => {
925
925
  return statusMap[info.pm2_env.status];
926
926
  };
927
927
 
928
- const getProcessInfo = (processId, { throwOnNotExist = true } = {}) =>
929
- getPm2ProcessInfo(processId, { printError: logger.error.bind(logger), throwOnNotExist });
928
+ const getProcessInfo = (processId, { throwOnNotExist = true, timeout = 10_000 } = {}) =>
929
+ getPm2ProcessInfo(processId, { printError: logger.error.bind(logger), throwOnNotExist, timeout });
930
930
 
931
931
  const deleteProcess = (processId) => {
932
932
  return new Promise((resolve, reject) => {
@@ -1027,7 +1027,7 @@ const _checkProcessHealthy = async (blocklet, { minConsecutiveTime, timeout, log
1027
1027
  // ensure pm2 status is 'online'
1028
1028
  const getStatus = async () => {
1029
1029
  try {
1030
- const info = await getProcessInfo(processId);
1030
+ const info = await getProcessInfo(processId, { timeout: 3_000 });
1031
1031
  return info.pm2_env.status;
1032
1032
  } catch (err) {
1033
1033
  logger.error('blocklet checkStart error', { error: err, processId, name });
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.16.49-beta-20250823-082650-626c1473",
6
+ "version": "1.16.49-beta-20250827-025603-2bb1a7ee",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,22 +19,22 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "Apache-2.0",
21
21
  "dependencies": {
22
- "@abtnode/analytics": "1.16.49-beta-20250823-082650-626c1473",
23
- "@abtnode/auth": "1.16.49-beta-20250823-082650-626c1473",
24
- "@abtnode/certificate-manager": "1.16.49-beta-20250823-082650-626c1473",
25
- "@abtnode/constant": "1.16.49-beta-20250823-082650-626c1473",
26
- "@abtnode/cron": "1.16.49-beta-20250823-082650-626c1473",
27
- "@abtnode/db-cache": "1.16.49-beta-20250823-082650-626c1473",
28
- "@abtnode/docker-utils": "1.16.49-beta-20250823-082650-626c1473",
29
- "@abtnode/logger": "1.16.49-beta-20250823-082650-626c1473",
30
- "@abtnode/models": "1.16.49-beta-20250823-082650-626c1473",
31
- "@abtnode/queue": "1.16.49-beta-20250823-082650-626c1473",
32
- "@abtnode/rbac": "1.16.49-beta-20250823-082650-626c1473",
33
- "@abtnode/router-provider": "1.16.49-beta-20250823-082650-626c1473",
34
- "@abtnode/static-server": "1.16.49-beta-20250823-082650-626c1473",
35
- "@abtnode/timemachine": "1.16.49-beta-20250823-082650-626c1473",
36
- "@abtnode/util": "1.16.49-beta-20250823-082650-626c1473",
37
- "@aigne/aigne-hub": "^0.6.8",
22
+ "@abtnode/analytics": "1.16.49-beta-20250827-025603-2bb1a7ee",
23
+ "@abtnode/auth": "1.16.49-beta-20250827-025603-2bb1a7ee",
24
+ "@abtnode/certificate-manager": "1.16.49-beta-20250827-025603-2bb1a7ee",
25
+ "@abtnode/constant": "1.16.49-beta-20250827-025603-2bb1a7ee",
26
+ "@abtnode/cron": "1.16.49-beta-20250827-025603-2bb1a7ee",
27
+ "@abtnode/db-cache": "1.16.49-beta-20250827-025603-2bb1a7ee",
28
+ "@abtnode/docker-utils": "1.16.49-beta-20250827-025603-2bb1a7ee",
29
+ "@abtnode/logger": "1.16.49-beta-20250827-025603-2bb1a7ee",
30
+ "@abtnode/models": "1.16.49-beta-20250827-025603-2bb1a7ee",
31
+ "@abtnode/queue": "1.16.49-beta-20250827-025603-2bb1a7ee",
32
+ "@abtnode/rbac": "1.16.49-beta-20250827-025603-2bb1a7ee",
33
+ "@abtnode/router-provider": "1.16.49-beta-20250827-025603-2bb1a7ee",
34
+ "@abtnode/static-server": "1.16.49-beta-20250827-025603-2bb1a7ee",
35
+ "@abtnode/timemachine": "1.16.49-beta-20250827-025603-2bb1a7ee",
36
+ "@abtnode/util": "1.16.49-beta-20250827-025603-2bb1a7ee",
37
+ "@aigne/aigne-hub": "^0.6.9",
38
38
  "@arcblock/did": "1.22.2",
39
39
  "@arcblock/did-connect-js": "1.22.2",
40
40
  "@arcblock/did-ext": "1.22.2",
@@ -45,16 +45,16 @@
45
45
  "@arcblock/pm2-events": "^0.0.5",
46
46
  "@arcblock/validator": "1.22.2",
47
47
  "@arcblock/vc": "1.22.2",
48
- "@blocklet/constant": "1.16.49-beta-20250823-082650-626c1473",
48
+ "@blocklet/constant": "1.16.49-beta-20250827-025603-2bb1a7ee",
49
49
  "@blocklet/did-space-js": "^1.1.18",
50
- "@blocklet/env": "1.16.49-beta-20250823-082650-626c1473",
50
+ "@blocklet/env": "1.16.49-beta-20250827-025603-2bb1a7ee",
51
51
  "@blocklet/error": "^0.2.5",
52
- "@blocklet/meta": "1.16.49-beta-20250823-082650-626c1473",
53
- "@blocklet/resolver": "1.16.49-beta-20250823-082650-626c1473",
54
- "@blocklet/sdk": "1.16.49-beta-20250823-082650-626c1473",
55
- "@blocklet/server-js": "1.16.49-beta-20250823-082650-626c1473",
56
- "@blocklet/store": "1.16.49-beta-20250823-082650-626c1473",
57
- "@blocklet/theme": "^3.1.27",
52
+ "@blocklet/meta": "1.16.49-beta-20250827-025603-2bb1a7ee",
53
+ "@blocklet/resolver": "1.16.49-beta-20250827-025603-2bb1a7ee",
54
+ "@blocklet/sdk": "1.16.49-beta-20250827-025603-2bb1a7ee",
55
+ "@blocklet/server-js": "1.16.49-beta-20250827-025603-2bb1a7ee",
56
+ "@blocklet/store": "1.16.49-beta-20250827-025603-2bb1a7ee",
57
+ "@blocklet/theme": "^3.1.30",
58
58
  "@fidm/x509": "^1.2.1",
59
59
  "@ocap/mcrypto": "1.22.2",
60
60
  "@ocap/util": "1.22.2",
@@ -118,5 +118,5 @@
118
118
  "jest": "^29.7.0",
119
119
  "unzipper": "^0.10.11"
120
120
  },
121
- "gitHead": "54d2281fc6f72dadd12ed86b38d5a4e150bcaba8"
121
+ "gitHead": "2b70eea34e8bc8546abb09d38935e8906d9586fd"
122
122
  }