@abtnode/core 1.16.29-next-680cf137 → 1.16.30-beta-00e8bdd1

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.
@@ -18,6 +18,7 @@ const runUserHook = async (label, hookName, args) => {
18
18
  silent = false,
19
19
  notification,
20
20
  did,
21
+ timeout,
21
22
  output: outputFile,
22
23
  error: errorFile,
23
24
  } = args;
@@ -40,6 +41,7 @@ const runUserHook = async (label, hookName, args) => {
40
41
  NODE_OPTIONS: getSecurityNodeOptions({ environmentObj: env, ...args }, nodeInfo.enableFileSystemIsolation),
41
42
  },
42
43
  silent,
44
+ timeout,
43
45
  output: outputFile,
44
46
  error: errorFile,
45
47
  });
@@ -212,9 +212,10 @@ const { formatEnvironments, getBlockletMeta, validateOwner, isCLI } = util;
212
212
 
213
213
  const statusLock = new Lock('blocklet-status-lock');
214
214
 
215
- const getHooksOutputFiles = (blocklet) => ({
215
+ const getHookArgs = (blocklet) => ({
216
216
  output: blocklet.mode === BLOCKLET_MODES.DEVELOPMENT ? '' : path.join(blocklet.env.logsDir, 'output.log'),
217
217
  error: blocklet.mode === BLOCKLET_MODES.DEVELOPMENT ? '' : path.join(blocklet.env.logsDir, 'error.log'),
218
+ timeout: (get(blocklet, 'meta.timeout.script') || 120) * 1000,
218
219
  });
219
220
 
220
221
  const pm2StatusMap = {
@@ -766,7 +767,7 @@ class DiskBlockletManager extends BaseBlockletManager {
766
767
  hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
767
768
  env,
768
769
  did, // root blocklet did,
769
- ...getHooksOutputFiles(b),
770
+ ...getHookArgs(b),
770
771
  });
771
772
 
772
773
  // start process
@@ -867,7 +868,7 @@ class DiskBlockletManager extends BaseBlockletManager {
867
868
  context,
868
869
  exitOnError: false,
869
870
  silent,
870
- ...getHooksOutputFiles(b),
871
+ ...getHookArgs(b),
871
872
  }),
872
873
  componentDids,
873
874
  });
@@ -898,11 +899,6 @@ class DiskBlockletManager extends BaseBlockletManager {
898
899
  ? componentDids.map((x) => ({ did: x }))
899
900
  : blocklet.children.map((x) => ({ did: x.meta.did })),
900
901
  });
901
- // for backward compatibility
902
- this.emit(BlockletInternalEvents.componentsUpdated, {
903
- appDid: blocklet.appDid,
904
- components: getComponentsInternalInfo(res),
905
- });
906
902
  this.configSynchronizer.throttledSyncAppConfig(blocklet.meta.did);
907
903
 
908
904
  let description = `${
@@ -1068,7 +1064,7 @@ class DiskBlockletManager extends BaseBlockletManager {
1068
1064
  notification: states.notification,
1069
1065
  context,
1070
1066
  exitOnError: false,
1071
- ...getHooksOutputFiles(b),
1067
+ ...getHookArgs(b),
1072
1068
  }),
1073
1069
  });
1074
1070
 
@@ -1265,11 +1261,6 @@ class DiskBlockletManager extends BaseBlockletManager {
1265
1261
  appDid: app.appDid,
1266
1262
  components: [{ did: child.meta.did }],
1267
1263
  });
1268
- // for backward compatibility
1269
- this.emit(BlockletInternalEvents.componentsUpdated, {
1270
- appDid: app.appDid,
1271
- components: getComponentsInternalInfo(newBlocklet),
1272
- });
1273
1264
  this.configSynchronizer.throttledSyncAppConfig(app.meta.did);
1274
1265
 
1275
1266
  return { ...newBlocklet, deletedComponent: child };
@@ -1349,21 +1340,38 @@ class DiskBlockletManager extends BaseBlockletManager {
1349
1340
  }
1350
1341
  }
1351
1342
 
1352
- // eslint-disable-next-line no-unused-vars
1353
- async deleteProcess({ did, componentDids }, context) {
1343
+ /**
1344
+ *
1345
+ * @param {object} param - params
1346
+ * @param {string} param.did - blocklet did
1347
+ * @param {string[]} param.componentDids - component dids
1348
+ * @param {boolean} param.shouldUpdateBlockletStatus - should update blocklet status
1349
+ * @param {*} context
1350
+ * @returns
1351
+ */
1352
+ async deleteProcess({ did, componentDids, shouldUpdateBlockletStatus = true }, context) {
1354
1353
  const blocklet = await this.getBlocklet(did);
1355
1354
 
1356
1355
  logger.info('delete blocklet process', { did, componentDids });
1357
1356
 
1358
1357
  await deleteBlockletProcess(blocklet, { ...context, componentDids });
1359
-
1360
- const result = await states.blocklet.setBlockletStatus(did, BlockletStatus.stopped, { componentDids });
1361
1358
  logger.info('blocklet process deleted successfully', { did, componentDids });
1362
- return result;
1359
+
1360
+ // 有些情况不需要更新 blocklet 状态, 比如下载完成,安装之前清理 process 时, 不需要更新 blocklet 状态
1361
+ if (shouldUpdateBlockletStatus) {
1362
+ const result = await states.blocklet.setBlockletStatus(did, BlockletStatus.stopped, { componentDids });
1363
+ logger.info('blocklet status updated to stopped after deleted processes', { did, componentDids });
1364
+ return result;
1365
+ }
1366
+
1367
+ return blocklet;
1363
1368
  }
1364
1369
 
1365
1370
  // Get blocklet by blockletDid or appDid
1366
- async detail({ did, attachConfig = true, attachRuntimeInfo, useCache, getOptionalComponents }, context) {
1371
+ async detail(
1372
+ { did, attachConfig = true, attachRuntimeInfo, attachDiskInfo = false, useCache, getOptionalComponents },
1373
+ context
1374
+ ) {
1367
1375
  if (!did) {
1368
1376
  throw new Error('did should not be empty');
1369
1377
  }
@@ -1373,7 +1381,7 @@ class DiskBlockletManager extends BaseBlockletManager {
1373
1381
  }
1374
1382
 
1375
1383
  if (attachRuntimeInfo) {
1376
- return this._attachRuntimeInfo({ did, diskInfo: true, context, getOptionalComponents });
1384
+ return this._attachRuntimeInfo({ did, diskInfo: !!attachDiskInfo, context, getOptionalComponents });
1377
1385
  }
1378
1386
 
1379
1387
  if (useCache && this.cachedBlocklets.has(did)) {
@@ -1490,7 +1498,7 @@ class DiskBlockletManager extends BaseBlockletManager {
1490
1498
  env: { ...getRuntimeEnvironments(blocklet, nodeEnvironments, ancestors), ...configObj },
1491
1499
  did,
1492
1500
  context,
1493
- ...getHooksOutputFiles(blocklet),
1501
+ ...getHookArgs(blocklet),
1494
1502
  });
1495
1503
  }
1496
1504
 
@@ -1566,7 +1574,6 @@ class DiskBlockletManager extends BaseBlockletManager {
1566
1574
  this.configSynchronizer.throttledSyncAppConfig(blocklet.meta.did);
1567
1575
  }
1568
1576
 
1569
- this.emit(BlockletEvents.updated, { ...newState, context });
1570
1577
  const serverSk = (await states.node.read()).sk;
1571
1578
  if (childDid) {
1572
1579
  const configs = JSON.stringify(finalConfigs.map((x) => ({ key: x.key, value: x.value })));
@@ -1579,6 +1586,8 @@ class DiskBlockletManager extends BaseBlockletManager {
1579
1586
  this.configSynchronizer.syncComponentConfig(childDid, rootDid, { serverSk });
1580
1587
  }
1581
1588
 
1589
+ this.emit(BlockletEvents.updated, { ...newState, context });
1590
+
1582
1591
  try {
1583
1592
  const observableConfigs = [
1584
1593
  BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_URL,
@@ -1853,11 +1862,6 @@ class DiskBlockletManager extends BaseBlockletManager {
1853
1862
  appDid: blocklet.appDid,
1854
1863
  components: getComponentsInternalInfo(blocklet).filter((x) => x.did === component.meta.did),
1855
1864
  });
1856
- // for backward compatibility
1857
- this.emit(BlockletInternalEvents.componentsUpdated, {
1858
- appDid: blocklet.appDid,
1859
- components: getComponentsInternalInfo(blocklet),
1860
- });
1861
1865
  this.configSynchronizer.throttledSyncAppConfig(blocklet.meta.did);
1862
1866
 
1863
1867
  return this.getBlocklet(rootDid);
@@ -2709,11 +2713,6 @@ class DiskBlockletManager extends BaseBlockletManager {
2709
2713
  appDid: blocklet.appDid,
2710
2714
  components: (componentDids || []).map((x) => ({ did: x })),
2711
2715
  });
2712
- // for backward compatibility
2713
- this.emit(BlockletInternalEvents.componentsUpdated, {
2714
- appDid: blocklet.appDid,
2715
- components: getComponentsInternalInfo(res),
2716
- });
2717
2716
  this.configSynchronizer.throttledSyncAppConfig(res);
2718
2717
 
2719
2718
  this.emit(BlockletEvents.statusChange, res);
@@ -3247,7 +3246,7 @@ class DiskBlockletManager extends BaseBlockletManager {
3247
3246
  return [];
3248
3247
  }
3249
3248
 
3250
- async _attachRuntimeInfo({ did, diskInfo = true, context, getOptionalComponents }) {
3249
+ async _attachRuntimeInfo({ did, diskInfo = false, context, getOptionalComponents }) {
3251
3250
  if (!did) {
3252
3251
  throw new Error('did should not be empty');
3253
3252
  }
@@ -3259,7 +3258,9 @@ class DiskBlockletManager extends BaseBlockletManager {
3259
3258
  return null;
3260
3259
  }
3261
3260
 
3262
- blocklet.site.domainAliases = await this.getDomainAliases(blocklet, context);
3261
+ if (blocklet.site) {
3262
+ blocklet.site.domainAliases = await this.getDomainAliases(blocklet, context);
3263
+ }
3263
3264
 
3264
3265
  // app runtime info, app status
3265
3266
  blocklet.appRuntimeInfo = this.runtimeMonitor.getRuntimeInfo(blocklet.meta.did);
@@ -3449,7 +3450,7 @@ class DiskBlockletManager extends BaseBlockletManager {
3449
3450
 
3450
3451
  // ensure delete process
3451
3452
  try {
3452
- await this.deleteProcess({ did }, context);
3453
+ await this.deleteProcess({ did, shouldUpdateBlockletStatus: false }, context);
3453
3454
  logger.info('ensure delete blocklet process for installing', { did, name: meta.name });
3454
3455
  } catch (err) {
3455
3456
  logger.error('ensure delete blocklet process failed for installing', { did, name: meta.name, error: err });
@@ -3642,7 +3643,7 @@ class DiskBlockletManager extends BaseBlockletManager {
3642
3643
  env: getRuntimeEnvironments(b, nodeEnvironments, [blocklet]),
3643
3644
  oldVersion: oldVersions[b.meta.did],
3644
3645
  newVersion: b.meta.version,
3645
- ...getHooksOutputFiles(b),
3646
+ ...getHookArgs(b),
3646
3647
  });
3647
3648
  } catch (error) {
3648
3649
  logger.error('Failed to run migration scripts', { appDid: did, title: b.meta.title, error });
@@ -3693,7 +3694,8 @@ class DiskBlockletManager extends BaseBlockletManager {
3693
3694
  }
3694
3695
  }
3695
3696
  if (stoppedDids.length) {
3696
- await states.blocklet.setBlockletStatus(did, BlockletStatus.stopped, { componentDids: stoppedDids });
3697
+ const status = action === INSTALL_ACTIONS.INSTALL_COMPONENT ? BlockletStatus.installed : BlockletStatus.stopped;
3698
+ await states.blocklet.setBlockletStatus(did, status, { componentDids: stoppedDids });
3697
3699
  }
3698
3700
 
3699
3701
  blocklet = await this.getBlocklet(did, context);
@@ -3747,11 +3749,6 @@ class DiskBlockletManager extends BaseBlockletManager {
3747
3749
  }
3748
3750
  );
3749
3751
  }
3750
- // for backward compatibility
3751
- this.emit(BlockletInternalEvents.componentsUpdated, {
3752
- appDid: blocklet.appDid,
3753
- components: getComponentsInternalInfo(blocklet),
3754
- });
3755
3752
  this.configSynchronizer.throttledSyncAppConfig(blocklet);
3756
3753
 
3757
3754
  return blocklet;
@@ -4040,7 +4037,7 @@ class DiskBlockletManager extends BaseBlockletManager {
4040
4037
  did: blocklet.meta.did, // root blocklet did
4041
4038
  notification: states.notification,
4042
4039
  context,
4043
- ...getHooksOutputFiles(b),
4040
+ ...getHookArgs(b),
4044
4041
  });
4045
4042
 
4046
4043
  await forEachBlocklet(blocklet, hookFn, { parallel: true, concurrencyLimit: 4 });
@@ -4210,14 +4207,15 @@ class DiskBlockletManager extends BaseBlockletManager {
4210
4207
  for (const data of blockletExtras) {
4211
4208
  try {
4212
4209
  const { did } = data;
4213
- const launcherSession = await launcher.getLauncherSession({
4210
+ const { launcherSession } = await launcher.getLauncherSession({
4214
4211
  launcherUrl: data.controller.launcherUrl,
4215
4212
  launcherSessionId: data.controller.launcherSessionId,
4216
4213
  });
4214
+
4217
4215
  const isTerminated = launcher.isLaunchSessionTerminated(launcherSession);
4218
4216
 
4219
4217
  if (!isTerminated) {
4220
- logger.info('skip cleaning the non-exceed redemption blocklet', {
4218
+ logger.info('skip cleaning the non-terminated blocklet', {
4221
4219
  blockletDid: did,
4222
4220
  controller: data.controller,
4223
4221
  launcherSession,
@@ -13,7 +13,10 @@ const { formatName } = require('../../../util/get-domain-for-blocklet');
13
13
 
14
14
  const needParseDependents = (meta, app) => {
15
15
  const dependents = (meta.components || []).map((x) => x.source.name);
16
- return !dependents.every((name) => app.children.some((x) => x.meta.name === name));
16
+ if (meta.engine?.interpreter === 'blocklet') {
17
+ dependents.push(meta.engine.source.name);
18
+ }
19
+ return !dependents.filter(Boolean).every((name) => app.children.some((x) => x.meta.name === name));
17
20
  };
18
21
 
19
22
  const installComponentFromDev = async ({ folder, meta, rootDid, mountPoint, manager, states, skipParseDependents }) => {
@@ -30,18 +30,24 @@ const check = async ({ did, states }) => {
30
30
  const bundleSource = getFixedBundleSource(child);
31
31
 
32
32
  if (bundleSource) {
33
- const { dynamicComponents } = await parseComponents({
34
- meta: {
35
- components: [
36
- {
37
- source: bundleSource,
38
- name: child.meta.name,
39
- mountPoint: child.mountPoint,
40
- },
41
- ],
33
+ const { dynamicComponents } = await parseComponents(
34
+ {
35
+ meta: {
36
+ components: [
37
+ {
38
+ source: bundleSource,
39
+ name: child.meta.name,
40
+ mountPoint: child.mountPoint,
41
+ },
42
+ ],
43
+ },
42
44
  },
43
- });
45
+ { continueOnError: true }
46
+ );
44
47
  const newChild = dynamicComponents.find((x) => x.meta.name === child.meta.name);
48
+ if (!newChild) {
49
+ continue;
50
+ }
45
51
  newChild._dynamicComponents = dynamicComponents.filter((x) => x.meta.name !== child.meta.name);
46
52
  newChildren.push(newChild);
47
53
  } else {
@@ -22,6 +22,7 @@ async function runScripts({
22
22
  printError,
23
23
  output,
24
24
  error,
25
+ timeout,
25
26
  }) {
26
27
  // 获取所有待执行的脚本
27
28
  let scripts = [];
@@ -61,6 +62,7 @@ async function runScripts({
61
62
  silent: false,
62
63
  output,
63
64
  error,
65
+ timeout,
64
66
  });
65
67
  printInfo(`Migration script executed: ${scriptPath}`);
66
68
  } catch (migrationErr) {
@@ -107,6 +109,7 @@ module.exports = async ({
107
109
  printError = logger.error,
108
110
  output,
109
111
  error,
112
+ timeout,
110
113
  }) => {
111
114
  if (!oldVersion) {
112
115
  return;
@@ -136,6 +139,7 @@ module.exports = async ({
136
139
  printSuccess,
137
140
  output,
138
141
  error,
142
+ timeout,
139
143
  });
140
144
 
141
145
  fs.removeSync(backupDir);
@@ -2,6 +2,7 @@ const path = require('path');
2
2
  const { PROJECT } = require('@blocklet/constant');
3
3
  const { upload } = require('@blocklet/store');
4
4
  const { getDisplayName } = require('@blocklet/meta/lib/util');
5
+ const fs = require('fs/promises');
5
6
 
6
7
  function ensureArray(value) {
7
8
  if (!value) {
@@ -18,6 +19,37 @@ function getReleaseDir(blocklet, projectId, releaseId) {
18
19
  return path.join(projectDir, PROJECT.RELEASE_DIR, `${releaseId}`);
19
20
  }
20
21
 
22
+ const MAX_RETRIES = 5;
23
+ const RETRY_DELAY = 100;
24
+
25
+ // 利用乐观锁, 去更新字段, 如果连续5次都失败, 就算更新失败
26
+ async function updateReleaseWithRetry(releaseState, releaseId, projectId, storeId) {
27
+ // eslint-disable-next-line no-unused-vars
28
+ for (const _ of Array(MAX_RETRIES).fill(0)) {
29
+ // eslint-disable-next-line no-await-in-loop
30
+ const release = await releaseState.findOne({ projectId, id: releaseId });
31
+ release.publishedStoreIds = ensureArray(release.publishedStoreIds);
32
+ release.publishedStoreIds.push(storeId);
33
+
34
+ try {
35
+ // eslint-disable-next-line no-await-in-loop
36
+ const result = await releaseState.update(
37
+ { id: releaseId, updatedAt: release.updatedAt },
38
+ { $set: { publishedStoreIds: Array.from(new Set(release.publishedStoreIds)) } }
39
+ );
40
+ if (result?.[0] > 0) {
41
+ return true;
42
+ }
43
+ // eslint-disable-next-line no-await-in-loop
44
+ await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY));
45
+ } catch (error) {
46
+ throw new Error(`Failed to update release: ${error.message}`);
47
+ }
48
+ }
49
+
50
+ throw new Error('Failed to update release after maximum retries');
51
+ }
52
+
21
53
  const publishToStore = async ({ did, projectId, releaseId, type, storeId, manager }) => {
22
54
  if (
23
55
  !did ||
@@ -42,6 +74,7 @@ const publishToStore = async ({ did, projectId, releaseId, type, storeId, manage
42
74
  if (!store) {
43
75
  throw new Error('no find connected store');
44
76
  }
77
+
45
78
  const { storeUrl } = store;
46
79
  const { accessToken, developerDid } = store;
47
80
 
@@ -50,7 +83,12 @@ const publishToStore = async ({ did, projectId, releaseId, type, storeId, manage
50
83
  throw new Error('blocklet not found');
51
84
  }
52
85
 
53
- const releaseDir = getReleaseDir(blocklet, projectId, releaseId);
86
+ const project = await projectState.findOne({ id: projectId });
87
+ let releaseDir = getReleaseDir(blocklet, projectId, releaseId);
88
+ if (project.possibleSameStore) {
89
+ await fs.cp(releaseDir, `${releaseDir}-${storeId}`, { recursive: true });
90
+ releaseDir = `${releaseDir}-${storeId}`;
91
+ }
54
92
  const metaFile = path.join(releaseDir, '.blocklet', 'release', 'blocklet.json');
55
93
 
56
94
  const response = await upload({
@@ -58,16 +96,11 @@ const publishToStore = async ({ did, projectId, releaseId, type, storeId, manage
58
96
  storeUrl,
59
97
  accessToken,
60
98
  developerDid,
99
+ possibleSameStore: project.possibleSameStore,
61
100
  source: `Blocklet Studio (${getDisplayName(blocklet)})`,
62
101
  });
63
102
 
64
- release.publishedStoreIds = ensureArray(release.publishedStoreIds);
65
- release.publishedStoreIds.push(storeId);
66
-
67
- await releaseState.update(
68
- { id: releaseId },
69
- { $set: { publishedStoreIds: Array.from(new Set(release.publishedStoreIds)) } }
70
- );
103
+ await updateReleaseWithRetry(releaseState, releaseId, projectId, storeId);
71
104
 
72
105
  return response?.status;
73
106
  };
@@ -11,14 +11,14 @@ const check = async (threshold) => {
11
11
  for (const disk of disks) {
12
12
  const usageRatio = (disk.used / disk.total) * 100;
13
13
  if (Number.isNaN(usageRatio)) {
14
- return;
14
+ continue;
15
15
  }
16
16
 
17
17
  const usageRatioPercent = `${usageRatio.toFixed(2)}%`;
18
18
  logger.info('check disk usage', { usage: usageRatioPercent, threshold });
19
19
 
20
20
  if (usageRatio < threshold) {
21
- return;
21
+ continue;
22
22
  }
23
23
 
24
24
  // eslint-disable-next-line no-await-in-loop
@@ -357,11 +357,7 @@ module.exports = ({
357
357
  }
358
358
  }
359
359
 
360
- if (
361
- [BlockletEvents.started, BlockletEvents.startFailed, BlockletEvents.stopped, BlockletEvents.reloaded].includes(
362
- eventName
363
- )
364
- ) {
360
+ if ([BlockletEvents.started, BlockletEvents.startFailed, BlockletEvents.stopped].includes(eventName)) {
365
361
  try {
366
362
  await blockletManager.runtimeMonitor.monit(blocklet.meta.did);
367
363
  } catch (error) {
@@ -79,6 +79,8 @@ class Project extends BaseState {
79
79
  'lastReleaseId',
80
80
  'lastReleaseFiles',
81
81
  'connectedStores',
82
+ 'autoUpload',
83
+ 'possibleSameStore',
82
84
  ]),
83
85
  (x) => !isUndefinedOrNull(x)
84
86
  );
@@ -639,7 +639,13 @@ const startBlockletProcess = async (
639
639
  const clusterSize = Number(blocklet.configObj.BLOCKLET_CLUSTER_SIZE) || +process.env.ABT_NODE_MAX_CLUSTER_SIZE;
640
640
  options.execMode = 'cluster';
641
641
  options.mergeLogs = true;
642
- options.instances = Math.min(os.cpus().length, clusterSize);
642
+ options.instances = Math.max(Math.min(os.cpus().length, clusterSize), 1);
643
+ options.env.BLOCKLET_CLUSTER_SIZE = options.instances;
644
+ if (options.instances !== clusterSize) {
645
+ logger.warn(`Fallback cluster size to ${options.instances} for ${processId}, ignore custom ${clusterSize}`);
646
+ }
647
+ } else {
648
+ delete options.env.BLOCKLET_CLUSTER_SIZE;
643
649
  }
644
650
 
645
651
  if (b.mode === BLOCKLET_MODES.DEVELOPMENT) {
@@ -1069,11 +1075,8 @@ const pruneBlockletBundle = async ({ blocklets, installDir, blockletSettings })
1069
1075
  logger.info('Blocklet source folder has been pruned');
1070
1076
  };
1071
1077
 
1072
- const getDiskInfo = async (blocklet, { useFakeDiskInfo } = {}) => {
1073
- if (useFakeDiskInfo) {
1074
- return { app: 0, cache: 0, log: 0, data: 0 };
1075
- }
1076
-
1078
+ const _diskInfoTasks = {};
1079
+ const _getDiskInfo = async (blocklet) => {
1077
1080
  try {
1078
1081
  const { env } = blocklet;
1079
1082
  const [app, cache, log, data] = await Promise.all([
@@ -1084,9 +1087,30 @@ const getDiskInfo = async (blocklet, { useFakeDiskInfo } = {}) => {
1084
1087
  ]);
1085
1088
  return { app, cache, log, data };
1086
1089
  } catch (error) {
1087
- logger.error('Get disk info failed', { name: blocklet.meta.name, error });
1090
+ logger.error('Get disk info failed', { name: getDisplayName(blocklet), error });
1091
+ return { app: 0, cache: 0, log: 0, data: 0 };
1092
+ }
1093
+ };
1094
+
1095
+ const getDiskInfo = (blocklet, { useFakeDiskInfo } = {}) => {
1096
+ if (useFakeDiskInfo) {
1088
1097
  return { app: 0, cache: 0, log: 0, data: 0 };
1089
1098
  }
1099
+
1100
+ const { appDid } = blocklet;
1101
+
1102
+ // Cache disk info results for 1 minute
1103
+ _diskInfoTasks[appDid] ??= _getDiskInfo(blocklet).finally(() => {
1104
+ setTimeout(() => {
1105
+ delete _diskInfoTasks[appDid];
1106
+ }, 120 * 1000);
1107
+ });
1108
+
1109
+ return new Promise((resolve) => {
1110
+ _diskInfoTasks[appDid].then(resolve).catch(() => {
1111
+ resolve({ app: 0, cache: 0, log: 0, data: 0 });
1112
+ });
1113
+ });
1090
1114
  };
1091
1115
 
1092
1116
  const getRuntimeInfo = async (processId) => {
@@ -1579,6 +1603,20 @@ const validateAppConfig = async (config, states) => {
1579
1603
  throw new Error(`${x.key}(${x.value}) is not a valid URL`);
1580
1604
  }
1581
1605
  }
1606
+
1607
+ if (x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_CLUSTER_SIZE) {
1608
+ if (isEmpty(x.value)) {
1609
+ x.value = '';
1610
+ }
1611
+
1612
+ const v = Number(x.value);
1613
+ if (Number.isNaN(v)) {
1614
+ throw new Error(`${x.key} must be number`);
1615
+ }
1616
+ if (!Number.isInteger(v)) {
1617
+ throw new Error(`${x.key} must be integer`);
1618
+ }
1619
+ }
1582
1620
  };
1583
1621
 
1584
1622
  const checkDuplicateAppSk = async ({ sk, did, states }) => {
package/lib/util/index.js CHANGED
@@ -7,6 +7,7 @@ const shell = require('shelljs');
7
7
  const camelCase = require('lodash/camelCase');
8
8
  const get = require('lodash/get');
9
9
  const pickBy = require('lodash/pickBy');
10
+ const uniq = require('lodash/uniq');
10
11
  const { isFromPublicKey } = require('@arcblock/did');
11
12
  const { joinURL } = require('ufo');
12
13
  const { Certificate } = require('@fidm/x509');
@@ -195,7 +196,7 @@ const getBaseUrls = async (node, ips) => {
195
196
  const info = await node.getNodeInfo();
196
197
  const { https, httpPort, httpsPort } = info.routing;
197
198
  const getPort = (port, defaultPort) => (port && port !== defaultPort ? `:${port}` : '');
198
- const availableIps = ips.filter(Boolean);
199
+ const availableIps = uniq(ips.filter(Boolean));
199
200
 
200
201
  const getHttpInfo = async (domain) => {
201
202
  const certificate = https ? await node.certManager.getNormalByDomain(domain) : null;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.16.29-next-680cf137",
6
+ "version": "1.16.30-beta-00e8bdd1",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,40 +19,40 @@
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.29-next-680cf137",
23
- "@abtnode/auth": "1.16.29-next-680cf137",
24
- "@abtnode/certificate-manager": "1.16.29-next-680cf137",
25
- "@abtnode/constant": "1.16.29-next-680cf137",
26
- "@abtnode/cron": "1.16.29-next-680cf137",
27
- "@abtnode/logger": "1.16.29-next-680cf137",
28
- "@abtnode/models": "1.16.29-next-680cf137",
29
- "@abtnode/queue": "1.16.29-next-680cf137",
30
- "@abtnode/rbac": "1.16.29-next-680cf137",
31
- "@abtnode/router-provider": "1.16.29-next-680cf137",
32
- "@abtnode/static-server": "1.16.29-next-680cf137",
33
- "@abtnode/timemachine": "1.16.29-next-680cf137",
34
- "@abtnode/util": "1.16.29-next-680cf137",
35
- "@arcblock/did": "1.18.126",
36
- "@arcblock/did-auth": "1.18.126",
37
- "@arcblock/did-ext": "^1.18.126",
22
+ "@abtnode/analytics": "1.16.30-beta-00e8bdd1",
23
+ "@abtnode/auth": "1.16.30-beta-00e8bdd1",
24
+ "@abtnode/certificate-manager": "1.16.30-beta-00e8bdd1",
25
+ "@abtnode/constant": "1.16.30-beta-00e8bdd1",
26
+ "@abtnode/cron": "1.16.30-beta-00e8bdd1",
27
+ "@abtnode/logger": "1.16.30-beta-00e8bdd1",
28
+ "@abtnode/models": "1.16.30-beta-00e8bdd1",
29
+ "@abtnode/queue": "1.16.30-beta-00e8bdd1",
30
+ "@abtnode/rbac": "1.16.30-beta-00e8bdd1",
31
+ "@abtnode/router-provider": "1.16.30-beta-00e8bdd1",
32
+ "@abtnode/static-server": "1.16.30-beta-00e8bdd1",
33
+ "@abtnode/timemachine": "1.16.30-beta-00e8bdd1",
34
+ "@abtnode/util": "1.16.30-beta-00e8bdd1",
35
+ "@arcblock/did": "1.18.128",
36
+ "@arcblock/did-auth": "1.18.128",
37
+ "@arcblock/did-ext": "^1.18.128",
38
38
  "@arcblock/did-motif": "^1.1.13",
39
- "@arcblock/did-util": "1.18.126",
40
- "@arcblock/event-hub": "1.18.126",
41
- "@arcblock/jwt": "^1.18.126",
39
+ "@arcblock/did-util": "1.18.128",
40
+ "@arcblock/event-hub": "1.18.128",
41
+ "@arcblock/jwt": "^1.18.128",
42
42
  "@arcblock/pm2-events": "^0.0.5",
43
- "@arcblock/validator": "^1.18.126",
44
- "@arcblock/vc": "1.18.126",
45
- "@blocklet/constant": "1.16.29-next-680cf137",
46
- "@blocklet/env": "1.16.29-next-680cf137",
47
- "@blocklet/meta": "1.16.29-next-680cf137",
48
- "@blocklet/resolver": "1.16.29-next-680cf137",
49
- "@blocklet/sdk": "1.16.29-next-680cf137",
50
- "@blocklet/store": "1.16.29-next-680cf137",
51
- "@did-space/client": "^0.5.7",
43
+ "@arcblock/validator": "^1.18.128",
44
+ "@arcblock/vc": "1.18.128",
45
+ "@blocklet/constant": "1.16.30-beta-00e8bdd1",
46
+ "@blocklet/env": "1.16.30-beta-00e8bdd1",
47
+ "@blocklet/meta": "1.16.30-beta-00e8bdd1",
48
+ "@blocklet/resolver": "1.16.30-beta-00e8bdd1",
49
+ "@blocklet/sdk": "1.16.30-beta-00e8bdd1",
50
+ "@blocklet/store": "1.16.30-beta-00e8bdd1",
51
+ "@did-space/client": "^0.5.17",
52
52
  "@fidm/x509": "^1.2.1",
53
- "@ocap/mcrypto": "1.18.126",
54
- "@ocap/util": "1.18.126",
55
- "@ocap/wallet": "1.18.126",
53
+ "@ocap/mcrypto": "1.18.128",
54
+ "@ocap/util": "1.18.128",
55
+ "@ocap/wallet": "1.18.128",
56
56
  "@slack/webhook": "^5.0.4",
57
57
  "archiver": "^7.0.1",
58
58
  "axios": "^1.7.2",
@@ -87,7 +87,7 @@
87
87
  "ssri": "^8.0.1",
88
88
  "stream-throttle": "^0.1.3",
89
89
  "stream-to-promise": "^3.0.0",
90
- "systeminformation": "^5.17.12",
90
+ "systeminformation": "^5.23.3",
91
91
  "tail": "^2.2.4",
92
92
  "tar": "^6.1.11",
93
93
  "transliteration": "^2.3.5",
@@ -103,5 +103,5 @@
103
103
  "jest": "^29.7.0",
104
104
  "unzipper": "^0.10.11"
105
105
  },
106
- "gitHead": "17b7e7c5e43c497980d4fe6b5bb20609328041bd"
106
+ "gitHead": "e165c7e64a2900b4c390b7435c0bb71abbf9b625"
107
107
  }