@abtnode/core 1.16.11-beta-0ae58a71 → 1.16.11-beta-f74663ac

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.
Files changed (53) hide show
  1. package/lib/api/node.js +1 -1
  2. package/lib/api/team.js +5 -5
  3. package/lib/blocklet/downloader/blocklet-downloader.js +34 -19
  4. package/lib/blocklet/downloader/bundle-downloader.js +2 -2
  5. package/lib/blocklet/hooks.js +1 -1
  6. package/lib/blocklet/manager/base.js +9 -9
  7. package/lib/blocklet/manager/disk.js +286 -172
  8. package/lib/blocklet/manager/helper/install-application-from-backup.js +1 -1
  9. package/lib/blocklet/manager/helper/install-application-from-general.js +18 -3
  10. package/lib/blocklet/manager/helper/install-component-from-dev.js +0 -1
  11. package/lib/blocklet/manager/helper/install-component-from-upload.js +8 -4
  12. package/lib/blocklet/manager/helper/install-component-from-url.js +4 -2
  13. package/lib/blocklet/manager/helper/upgrade-components.js +7 -7
  14. package/lib/blocklet/manager/pm2-events.js +3 -3
  15. package/lib/blocklet/migration.js +2 -2
  16. package/lib/blocklet/storage/backup/base.js +1 -0
  17. package/lib/blocklet/storage/backup/blocklet-extras.js +1 -1
  18. package/lib/blocklet/storage/backup/blocklet.js +1 -1
  19. package/lib/blocklet/storage/backup/disk.js +1 -0
  20. package/lib/blocklet/storage/restore/blocklet-extras.js +1 -1
  21. package/lib/blocklet/storage/restore/blocklet.js +1 -1
  22. package/lib/blocklet/storage/restore/disk.js +1 -1
  23. package/lib/blocklet/storage/restore/spaces.js +1 -1
  24. package/lib/cert.js +5 -5
  25. package/lib/crons/rotate-pm2-logs/index.js +1 -1
  26. package/lib/event.js +11 -1
  27. package/lib/index.js +8 -2
  28. package/lib/migrations/1.16.11-component-status.js +22 -0
  29. package/lib/migrations/index.js +3 -3
  30. package/lib/monitor/blocklet-runtime-monitor.js +7 -2
  31. package/lib/processes/updater.js +1 -1
  32. package/lib/router/helper.js +5 -5
  33. package/lib/states/audit-log.js +1 -1
  34. package/lib/states/backup.js +5 -4
  35. package/lib/states/blocklet-extras.js +11 -1
  36. package/lib/states/blocklet.js +46 -39
  37. package/lib/states/cache.js +1 -1
  38. package/lib/states/node.js +6 -2
  39. package/lib/states/notification.js +1 -1
  40. package/lib/states/routing-snapshot.js +1 -1
  41. package/lib/states/site.js +1 -1
  42. package/lib/states/user.js +12 -6
  43. package/lib/team/manager.js +6 -6
  44. package/lib/util/blocklet.js +130 -118
  45. package/lib/util/launcher.js +238 -0
  46. package/lib/util/reset-node.js +19 -16
  47. package/lib/util/rpc.js +1 -1
  48. package/lib/util/store.js +1 -1
  49. package/lib/validators/space-gateway.js +3 -0
  50. package/lib/validators/util.js +3 -0
  51. package/lib/webhook/sender/api/index.js +1 -1
  52. package/lib/webhook/sender/slack/index.js +1 -1
  53. package/package.json +17 -17
@@ -203,7 +203,7 @@ const installApplicationFromBackup = async ({
203
203
  // 从 store 下载 blocklet
204
204
  await manager.blockletDownloader.download(blockletState, {
205
205
  skipCheckIntegrity: true,
206
- onProgress: async (data) => {
206
+ onProgress: (data) => {
207
207
  manager.emit(BlockletEvents.downloadBundleProgress, { appDid: wallet.address, meta: { did }, ...data });
208
208
  },
209
209
  });
@@ -54,9 +54,7 @@ const installApplicationFromGeneral = async ({
54
54
 
55
55
  // check install count
56
56
  if (controller?.nftId) {
57
- // sometimes nedb will throw error if use states.blocklet.count({ ['controller.nftId']: controller.nftId })
58
57
  const installedCount = await states.blockletExtras.count({ 'controller.nftId': controller.nftId });
59
-
60
58
  if (installedCount >= (controller.appMaxCount || 1)) {
61
59
  throw new Error(
62
60
  `You can only install ${controller.appMaxCount} blocklet with this credential: ${controller.nftId}`
@@ -120,7 +118,24 @@ const installApplicationFromGeneral = async ({
120
118
  },
121
119
  ]);
122
120
  } catch (err) {
123
- await manager._rollback('install', did, {});
121
+ const componentDid = component?.meta?.did;
122
+ logger.error('failed to create blocklet extras', { did, componentDid, error: err });
123
+
124
+ try {
125
+ await manager._rollback('install', did, {});
126
+ } catch (e) {
127
+ logger.error('failed to remove blocklet on create extras error', { did, componentDid, error: e });
128
+ }
129
+
130
+ manager._createNotification(did, {
131
+ title: 'Blocklet Install Failed',
132
+ description: `Blocklet ${title || component?.meta?.title} install failed with error: ${err.message}`,
133
+ entityType: 'blocklet',
134
+ entityId: did,
135
+ severity: 'error',
136
+ });
137
+
138
+ throw err;
124
139
  }
125
140
 
126
141
  if (!blocklet.children.length) {
@@ -56,7 +56,6 @@ const installComponentFromDev = async ({ folder, meta, rootDid, mountPoint, mana
56
56
  const newBlocklet = await states.blocklet.getBlocklet(rootDid);
57
57
  await validateBlocklet(newBlocklet);
58
58
  await manager._downloadBlocklet(newBlocklet);
59
- await states.blocklet.setBlockletStatus(rootDid, BlockletStatus.stopped);
60
59
 
61
60
  // Add Config
62
61
  await manager._setConfigsFromMeta(rootDid);
@@ -13,6 +13,7 @@ const {
13
13
  ensureMeta,
14
14
  checkStructVersion,
15
15
  checkVersionCompatibility,
16
+ getBlockletStatus,
16
17
  } = require('../../../util/blocklet');
17
18
  const { resolveDownload, resolveDiffDownload, downloadFromUpload } = require('../../downloader/resolve-download');
18
19
 
@@ -39,9 +40,10 @@ const installComponentFromUpload = async ({
39
40
  // download
40
41
  const { tarFile } = await downloadFromUpload(file, { downloadDir: path.join(manager.dataDirs.tmp, 'download') });
41
42
 
42
- if (isInProgress(oldBlocklet.status)) {
43
- logger.error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
44
- throw new Error(`Can not deploy blocklet when it is ${fromBlockletStatus(oldBlocklet.status)}`);
43
+ const appStatus = getBlockletStatus(oldBlocklet);
44
+ if (isInProgress(appStatus)) {
45
+ logger.error(`Can not deploy blocklet when it is ${fromBlockletStatus(appStatus)}`);
46
+ throw new Error(`Can not deploy blocklet when it is ${fromBlockletStatus(appStatus)}`);
45
47
  }
46
48
 
47
49
  let meta;
@@ -105,6 +107,8 @@ const installComponentFromUpload = async ({
105
107
  const action = 'upgrade';
106
108
  await manager._rollbackCache.backup({ did: newBlocklet.meta.did, action, oldBlocklet });
107
109
 
110
+ const componentDids = [newChild.meta.did, ...newChildren.map((x) => x.meta.did)];
111
+
108
112
  await manager._downloadAndInstall({
109
113
  blocklet: newBlocklet,
110
114
  oldBlocklet,
@@ -112,7 +116,7 @@ const installComponentFromUpload = async ({
112
116
  throwOnError: true,
113
117
  postAction: action,
114
118
  skipCheckStatusBeforeDownload: true,
115
- selectedComponentDids: newChildren.map((x) => x.meta.did),
119
+ componentDids,
116
120
  });
117
121
  return manager.getBlocklet(newBlocklet.meta.did);
118
122
  };
@@ -127,8 +127,10 @@ const installComponentFromUrl = async ({
127
127
  throw err;
128
128
  }
129
129
 
130
+ const componentDids = [newChild.meta.did, ...newChildren.map((x) => x.meta.did)];
131
+
130
132
  // new blocklet
131
- const newBlocklet = await states.blocklet.setBlockletStatus(rootDid, BlockletStatus.waiting);
133
+ const newBlocklet = await states.blocklet.setBlockletStatus(rootDid, BlockletStatus.waiting, { componentDids });
132
134
 
133
135
  newBlocklet.children = blocklet.children;
134
136
  await validateBlocklet(newBlocklet);
@@ -138,7 +140,7 @@ const installComponentFromUrl = async ({
138
140
  const downloadParams = {
139
141
  oldBlocklet: { ...oldBlocklet },
140
142
  blocklet: { ...newBlocklet },
141
- selectedComponentDids: [newChild.meta.did, ...newChildren.map((x) => x.meta.did)],
143
+ componentDids,
142
144
  context,
143
145
  postAction: action,
144
146
  };
@@ -73,8 +73,8 @@ const check = async ({ did, states }) => {
73
73
  };
74
74
  };
75
75
 
76
- const upgrade = async ({ updateId, selectedComponentDids, context, states, manager }) => {
77
- if (!selectedComponentDids?.length) {
76
+ const upgrade = async ({ updateId, componentDids, context, states, manager }) => {
77
+ if (!componentDids?.length) {
78
78
  throw new Error('At least one component needs to be selected');
79
79
  }
80
80
 
@@ -87,7 +87,7 @@ const upgrade = async ({ updateId, selectedComponentDids, context, states, manag
87
87
  let dynamicComponents = [];
88
88
  const children = cloneDeep(oldBlocklet.children).map((oldComponent) => {
89
89
  const newComponent = sessionData.children.find((x) => x.meta.did === oldComponent.meta.did);
90
- if (newComponent && selectedComponentDids.includes(newComponent.meta.did)) {
90
+ if (newComponent && componentDids.includes(newComponent.meta.did)) {
91
91
  dynamicComponents.push(...(newComponent._dynamicComponents || []));
92
92
  delete newComponent._dynamicComponents;
93
93
  return newComponent;
@@ -97,8 +97,8 @@ const upgrade = async ({ updateId, selectedComponentDids, context, states, manag
97
97
  dynamicComponents = filterDuplicateComponents(dynamicComponents, children);
98
98
  children.push(...dynamicComponents);
99
99
 
100
- // selectedComponentDids
101
- selectedComponentDids.push(...dynamicComponents.map((x) => x.meta.did));
100
+ // componentDids
101
+ componentDids.push(...dynamicComponents.map((x) => x.meta.did));
102
102
 
103
103
  checkVersionCompatibility(children);
104
104
 
@@ -108,7 +108,7 @@ const upgrade = async ({ updateId, selectedComponentDids, context, states, manag
108
108
  });
109
109
 
110
110
  // new blocklet
111
- const newBlocklet = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
111
+ const newBlocklet = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting, { componentDids });
112
112
 
113
113
  newBlocklet.children = children;
114
114
  await validateBlocklet(newBlocklet);
@@ -128,7 +128,7 @@ const upgrade = async ({ updateId, selectedComponentDids, context, states, manag
128
128
  id: did,
129
129
  oldBlocklet: { ...oldBlocklet },
130
130
  blocklet: { ...newBlocklet },
131
- selectedComponentDids: selectedComponentDids || [],
131
+ componentDids: componentDids || [],
132
132
  context,
133
133
  postAction: action,
134
134
  },
@@ -27,10 +27,10 @@ class BlockletPm2Events extends EventEmitter {
27
27
  if (actualPm2Home !== expectedPm2Home) {
28
28
  return;
29
29
  }
30
- const { BLOCKLET_DID: blockletDid } = details.process || {};
31
- logger.debug('listen pm2 event', { name, blockletDid });
30
+ const { BLOCKLET_DID: blockletDid, BLOCKLET_COMPONENT_DID: componentDid } = details.process || {};
31
+ logger.debug('listen pm2 event', { name, blockletDid, componentDid });
32
32
  if (blockletDid) {
33
- this.emit(name, { blockletDid });
33
+ this.emit(name, { blockletDid, componentDid });
34
34
  }
35
35
  })
36
36
  .error((error) => {
@@ -78,14 +78,14 @@ async function runScripts({
78
78
  return true;
79
79
  }
80
80
 
81
- async function doBackup({ dbDir, backupDir, printInfo, printSuccess }) {
81
+ function doBackup({ dbDir, backupDir, printInfo, printSuccess }) {
82
82
  printInfo('Backing up before migration...');
83
83
  fs.emptyDirSync(backupDir);
84
84
  fs.copySync(dbDir, backupDir);
85
85
  printSuccess('Backup success');
86
86
  }
87
87
 
88
- async function doRestore({ dbDir, backupDir, printInfo, printSuccess }) {
88
+ function doRestore({ dbDir, backupDir, printInfo, printSuccess }) {
89
89
  printInfo('Restoring when migration failed...');
90
90
  fs.emptyDirSync(dbDir);
91
91
  fs.copySync(backupDir, dbDir);
@@ -68,6 +68,7 @@ class BaseBackup {
68
68
  this.securityContext = backup.securityContext;
69
69
  }
70
70
 
71
+ // eslint-disable-next-line require-await
71
72
  async export() {
72
73
  throw new Error('not implemented');
73
74
  }
@@ -42,7 +42,7 @@ class BlockletExtrasBackup extends BaseBackup {
42
42
  * @return {Promise<any>}
43
43
  * @memberof BlockletExtrasBackup
44
44
  */
45
- async cleanData(raw) {
45
+ cleanData(raw) {
46
46
  const blockletExtra = cloneDeep(raw);
47
47
 
48
48
  const queue = [blockletExtra];
@@ -28,7 +28,7 @@ class BlockletBackup extends BaseBackup {
28
28
  * @return {Promise<import('@abtnode/client').BlockletState>}
29
29
  * @memberof BlockletBackup
30
30
  */
31
- async cleanData() {
31
+ cleanData() {
32
32
  const clone = cloneDeep(this.blocklet);
33
33
 
34
34
  /** @type {import('@abtnode/client').ComponentState[]} */
@@ -111,6 +111,7 @@ class DiskBackup extends BaseBackup {
111
111
  this.securityContext = await this._getSecurityContext(states);
112
112
  }
113
113
 
114
+ // eslint-disable-next-line require-await
114
115
  async export() {
115
116
  return this._exportData(this.dataBackup, this.storages);
116
117
  }
@@ -8,7 +8,7 @@ const { BaseRestore } = require('./base');
8
8
  class BlockletExtrasRestore extends BaseRestore {
9
9
  filename = 'blocklet-extras.json';
10
10
 
11
- async import(params) {
11
+ import(params) {
12
12
  const extras = this.cleanExtras(this.getExtras(), params);
13
13
  removeSync(join(this.restoreDir, this.filename));
14
14
  outputJsonSync(join(this.restoreDir, this.filename), extras);
@@ -8,7 +8,7 @@ const { BaseRestore } = require('./base');
8
8
  class BlockletRestore extends BaseRestore {
9
9
  filename = 'blocklet.json';
10
10
 
11
- async import(params) {
11
+ import(params) {
12
12
  const blocklet = this.decrypt(this.getBlocklet(), params);
13
13
  removeSync(join(this.restoreDir, this.filename));
14
14
  outputJsonSync(join(this.restoreDir, this.filename), blocklet);
@@ -61,7 +61,7 @@ class DiskRestore extends BaseRestore {
61
61
  }
62
62
  }
63
63
 
64
- async initialize() {
64
+ initialize() {
65
65
  this.serverDir = process.env.ABT_NODE_DATA_DIR;
66
66
  this.restoreDir = getBackupDirs(this.serverDir, this.input.appDid).restoreDir;
67
67
  if (existsSync(this.restoreDir)) {
@@ -82,7 +82,7 @@ class SpacesRestore extends BaseRestore {
82
82
  }
83
83
  }
84
84
 
85
- async initialize() {
85
+ initialize() {
86
86
  this.serverDir = process.env.ABT_NODE_DATA_DIR;
87
87
  this.restoreDir = join(this.serverDir, 'tmp/restore', this.input.appDid);
88
88
  if (existsSync(this.restoreDir)) {
package/lib/cert.js CHANGED
@@ -4,7 +4,7 @@ const logger = require('@abtnode/logger')('@abtnode/core:cert');
4
4
  const { EVENTS } = require('@abtnode/constant');
5
5
  const { BlockletEvents } = require('@blocklet/constant');
6
6
 
7
- const onCertExpired = async (cert, states) => {
7
+ const onCertExpired = (cert, states) => {
8
8
  logger.info('send certificate expire notification', { domain: cert.domain });
9
9
  states.notification.create({
10
10
  title: 'SSL Certificate Expired',
@@ -120,7 +120,7 @@ class Cert extends EventEmitter {
120
120
  * did?:string // blocklet.meta.did
121
121
  * }}
122
122
  */
123
- async issue({ domain, did }) {
123
+ issue({ domain, did }) {
124
124
  logger.info(`generate certificate for ${domain}`);
125
125
 
126
126
  if (did) {
@@ -137,7 +137,7 @@ class Cert extends EventEmitter {
137
137
  return result;
138
138
  }
139
139
 
140
- async update(data) {
140
+ update(data) {
141
141
  return this.manager.update(data.id, { name: data.name, public: data.public });
142
142
  }
143
143
 
@@ -149,11 +149,11 @@ class Cert extends EventEmitter {
149
149
  return {};
150
150
  }
151
151
 
152
- async addWithoutValidations(data) {
152
+ addWithoutValidations(data) {
153
153
  return this.manager.addWithoutValidations(data);
154
154
  }
155
155
 
156
- async updateWithoutValidations(id, data) {
156
+ updateWithoutValidations(id, data) {
157
157
  return this.manager.updateWithoutValidations(id, data);
158
158
  }
159
159
 
@@ -7,7 +7,7 @@ const getCron = () => ({
7
7
  name: 'rotate-pm2-logs',
8
8
  time: '0 0 * * *', // default : every day at midnight
9
9
  options: { runOnInit: false },
10
- fn: async () => {
10
+ fn: () => {
11
11
  console.info(`Log rotator started on ${new Date().toISOString()}`);
12
12
  const child = spawn('node', [path.join(__dirname, './script.js')], {
13
13
  detached: true,
package/lib/event.js CHANGED
@@ -3,7 +3,13 @@ const cloneDeep = require('lodash/cloneDeep');
3
3
  const { EventEmitter } = require('events');
4
4
  const { wipeSensitiveData } = require('@blocklet/meta/lib/util');
5
5
  const logger = require('@abtnode/logger')('@abtnode/core:event');
6
- const { BLOCKLET_MODES, BlockletStatus, BlockletSource, BlockletEvents } = require('@blocklet/constant');
6
+ const {
7
+ BLOCKLET_MODES,
8
+ BlockletStatus,
9
+ BlockletSource,
10
+ BlockletEvents,
11
+ BlockletInternalEvents,
12
+ } = require('@blocklet/constant');
7
13
  const { EVENTS } = require('@abtnode/constant');
8
14
  const { NodeMonitSender } = require('./monitor/node-monit-sender');
9
15
  const handleInstanceInStore = require('./util/public-to-store');
@@ -375,6 +381,10 @@ module.exports = ({
375
381
  listen(blockletManager, eventName, handleBlockletEvent);
376
382
  });
377
383
 
384
+ [BlockletInternalEvents.componentsUpdated, BlockletInternalEvents.appConfigChanged].forEach((eventName) => {
385
+ listen(blockletManager, eventName, onEvent);
386
+ });
387
+
378
388
  listen(notificationState, EVENTS.NOTIFICATION_CREATE, onEvent);
379
389
 
380
390
  listen(nodeState, BlockletEvents.purchaseChange, onEvent);
package/lib/index.js CHANGED
@@ -16,6 +16,7 @@ const getRouterHelpers = require('./router/helper');
16
16
  const TeamManager = require('./team/manager');
17
17
  const NodeAPI = require('./api/node');
18
18
  const TeamAPI = require('./api/team');
19
+ const { getLauncherSession, isLauncherSessionConsumed, setupAppOwner } = require('./util/launcher');
19
20
  const WebHook = require('./webhook');
20
21
  const states = require('./states');
21
22
  const Cert = require('./cert');
@@ -250,7 +251,6 @@ function ABTNode(options) {
250
251
  devBlocklet: blockletManager.dev.bind(blockletManager),
251
252
  checkComponentsForUpdates: blockletManager.checkComponentsForUpdates.bind(blockletManager),
252
253
  upgradeComponents: blockletManager.upgradeComponents.bind(blockletManager),
253
- getBlockletMetaFromUrl: getMetaFromUrl.bind(blockletManager),
254
254
  getBlockletForLauncher: blockletManager.getBlockletForLauncher.bind(blockletManager),
255
255
  resetBlocklet: blockletManager.reset.bind(blockletManager),
256
256
  deleteBlockletProcess: blockletManager.deleteProcess.bind(blockletManager),
@@ -268,7 +268,6 @@ function ABTNode(options) {
268
268
  // For diagnose purpose
269
269
  syncBlockletStatus: blockletManager.status.bind(blockletManager),
270
270
  ensureBlockletIntegrity: blockletManager.ensureBlocklet.bind(blockletManager),
271
- updateBlockletStatus: states.blocklet.setBlockletStatus.bind(states.blocklet),
272
271
 
273
272
  getBlocklets: blockletManager.list.bind(blockletManager),
274
273
  getBlockletsFromBackup: blockletManager.listBackups.bind(blockletManager),
@@ -277,6 +276,7 @@ function ABTNode(options) {
277
276
  hasBlocklet: blockletManager.hasBlocklet.bind(blockletManager),
278
277
  updateAllBlockletEnvironment: blockletManager.updateAllBlockletEnvironment.bind(blockletManager),
279
278
  setBlockletInitialized: blockletManager.setInitialized.bind(blockletManager),
279
+ setBlockletOwner: blockletManager.updateOwner.bind(blockletManager),
280
280
  updateBlockletOwner: blockletManager.updateOwner.bind(blockletManager),
281
281
  getBlockletRuntimeHistory: blockletManager.getRuntimeHistory.bind(blockletManager),
282
282
 
@@ -462,6 +462,12 @@ function ABTNode(options) {
462
462
 
463
463
  // for exporting blocklet data dir
464
464
  createBlockletDataArchive: createDataArchive,
465
+
466
+ // public utils used in launch workflow
467
+ getBlockletMetaFromUrl: getMetaFromUrl,
468
+ getLauncherSession,
469
+ isLauncherSessionConsumed,
470
+ setupAppOwner,
465
471
  };
466
472
 
467
473
  const events = createEvents({
@@ -0,0 +1,22 @@
1
+ /* eslint-disable no-await-in-loop */
2
+ /* eslint-disable no-continue */
3
+
4
+ module.exports = async ({ states, printInfo }) => {
5
+ printInfo('Try to update component status...');
6
+
7
+ const apps = await states.blocklet.find({});
8
+
9
+ for (const app of apps || []) {
10
+ const appStatus = app.status;
11
+ let shouldUpdate = false;
12
+ for (const component of app.children || []) {
13
+ shouldUpdate = true;
14
+ component.status = appStatus;
15
+ }
16
+
17
+ if (shouldUpdate) {
18
+ await states.blocklet.update({ id: app.id }, { $set: { children: app.children } });
19
+ printInfo(`Blocklet in blocklet.db updated: ${app.meta?.title}. status: ${appStatus}`);
20
+ }
21
+ }
22
+ };
@@ -78,7 +78,7 @@ const getMigrationScripts = (scriptsDir) => {
78
78
  return sorted;
79
79
  };
80
80
 
81
- const doBackup = async ({ dataDir, configFile, printInfo, printSuccess }) => {
81
+ const doBackup = ({ dataDir, configFile, printInfo, printSuccess }) => {
82
82
  printInfo('Backing up state db and config before migration...');
83
83
 
84
84
  const backupDir = path.join(dataDir, 'migration', Date.now().toString());
@@ -96,7 +96,7 @@ const doBackup = async ({ dataDir, configFile, printInfo, printSuccess }) => {
96
96
  return backupDir;
97
97
  };
98
98
 
99
- const doRestore = async ({ dataDir, configFile, backupPath, printInfo, printSuccess }) => {
99
+ const doRestore = ({ dataDir, configFile, backupPath, printInfo, printSuccess }) => {
100
100
  printInfo('Restoring when migration failed...');
101
101
 
102
102
  const dbBackup = path.join(backupPath, BACKUP_FILE_DB);
@@ -309,7 +309,7 @@ const runDataMigrations = async ({
309
309
  }
310
310
  };
311
311
 
312
- const closeDatabaseConnections = async ({
312
+ const closeDatabaseConnections = ({
313
313
  dataDir,
314
314
  blocklets = [],
315
315
  printInfo = console.info, // eslint-disable-line
@@ -116,7 +116,7 @@ class BlockletRuntimeMonitor extends EventEmitter {
116
116
  await forEachBlocklet(
117
117
  blocklet,
118
118
  async (component, { id: componentId, ancestors }) => {
119
- if (component.meta.group !== BlockletGroup.gateway) {
119
+ if (component.meta.group !== BlockletGroup.gateway && component.status === BlockletStatus.running) {
120
120
  const processId = getComponentProcessId(component, ancestors);
121
121
  try {
122
122
  const runtimeInfo = await getRuntimeInfo(processId);
@@ -130,8 +130,13 @@ class BlockletRuntimeMonitor extends EventEmitter {
130
130
  appCpu += runtimeInfo.cpuUsage || 0;
131
131
  appMem += runtimeInfo.memoryUsage || 0;
132
132
  } catch (err) {
133
- this.logger.error('failed to get blocklet runtime info', { processId, error: err });
133
+ // component status in db may not sync with pm2 when server has just started
134
+ if (err.code !== 'BLOCKLET_PROCESS_404') {
135
+ this.logger.error('failed to get blocklet runtime info', { processId, error: err });
136
+ }
134
137
  }
138
+ } else {
139
+ delete this.data[blockletDid][componentId];
135
140
  }
136
141
  },
137
142
  { parallel: true }
@@ -109,7 +109,7 @@ const verifyBlockletServer = async (version) => {
109
109
  };
110
110
 
111
111
  // Restart Blocklet Server
112
- const restartBlockletServer = async (dataDir) => {
112
+ const restartBlockletServer = (dataDir) => {
113
113
  // We put this in the event loop because it will terminate the current node process
114
114
  // But we need to wait for the session state to transition from restarting to cleanup
115
115
  process.nextTick(async () => {
@@ -168,7 +168,7 @@ const ensureServiceRule = async (sites) => {
168
168
  return site;
169
169
  });
170
170
  };
171
- const ensureRootRule = async (sites) => {
171
+ const ensureRootRule = (sites) => {
172
172
  return sites.map((site) => {
173
173
  if (!isBasicSite(site.domain) && !site.rules.some((x) => x.from.pathPrefix === '/')) {
174
174
  site.rules.push({
@@ -388,7 +388,7 @@ const ensureCorsForWebWallet = async (sites) => {
388
388
  * @param {Array<import('@abtnode/client').BlockletState>} blocklets
389
389
  * @return {Promise<any>}
390
390
  */
391
- const ensureCorsForDidSpace = async (sites = [], blocklets) => {
391
+ const ensureCorsForDidSpace = (sites = [], blocklets) => {
392
392
  return sites.map((site) => {
393
393
  const blocklet = blocklets.find((x) => x.meta.did === site.blockletDid);
394
394
  if (blocklet) {
@@ -404,7 +404,7 @@ const ensureCorsForDidSpace = async (sites = [], blocklets) => {
404
404
  });
405
405
  };
406
406
 
407
- const filterSitesForRemovedBlocklets = async (sites = [], blocklets) => {
407
+ const filterSitesForRemovedBlocklets = (sites = [], blocklets) => {
408
408
  return sites.filter((site) => {
409
409
  if (!site.domain.endsWith(BLOCKLET_SITE_GROUP_SUFFIX)) {
410
410
  return true;
@@ -420,7 +420,7 @@ const filterSitesForRemovedBlocklets = async (sites = [], blocklets) => {
420
420
  *
421
421
  * @returns {boolean} if routing changed
422
422
  */
423
- const ensureBlockletWellknownRules = async (sites, blocklets) => {
423
+ const ensureBlockletWellknownRules = (sites, blocklets) => {
424
424
  /**
425
425
  * 1. component blocklet 不允许有相同多的 wellknown
426
426
  * 1. wellknown 可以访问的路由:
@@ -488,7 +488,7 @@ const ensureBlockletWellknownRules = async (sites, blocklets) => {
488
488
  .filter(Boolean);
489
489
  };
490
490
 
491
- const ensureBlockletCache = async (sites = [], blocklets) => {
491
+ const ensureBlockletCache = (sites = [], blocklets) => {
492
492
  return sites
493
493
  .map((site) => {
494
494
  if (!site.domain.endsWith(BLOCKLET_SITE_GROUP_SUFFIX)) {
@@ -493,7 +493,7 @@ class AuditLogState extends BaseState {
493
493
  });
494
494
  }
495
495
 
496
- async findPaginated({ scope, category, paging } = {}) {
496
+ findPaginated({ scope, category, paging } = {}) {
497
497
  const conditions = {};
498
498
  if (scope) {
499
499
  conditions.scope = scope;
@@ -35,7 +35,7 @@ class BackupState extends BaseState {
35
35
  /**
36
36
  * @param {Pick<import('@abtnode/models').BackupState, 'appPid' | 'userDid' | 'strategy' | 'sourceUrl' | 'target'>} backup
37
37
  */
38
- async start(backup) {
38
+ start(backup) {
39
39
  const { error, value } = validateBackupStart.validate(backup, {
40
40
  stripUnknown: true,
41
41
  allowUnknown: true,
@@ -52,7 +52,7 @@ class BackupState extends BaseState {
52
52
  * @param {string} id
53
53
  * @param {Pick<import('@abtnode/models').BackupState, 'targetUrl'>} successBackupInfo
54
54
  */
55
- async success(id, successBackupInfo) {
55
+ success(id, successBackupInfo) {
56
56
  const { error, value } = validateBackupSuccess.validate(successBackupInfo, {
57
57
  stripUnknown: true,
58
58
  allowUnknown: true,
@@ -78,7 +78,7 @@ class BackupState extends BaseState {
78
78
  * @param {string} id
79
79
  * @param {Pick<import('@abtnode/models').BackupState, 'message'>} errorBackupInfo
80
80
  */
81
- async fail(id, errorBackupInfo) {
81
+ fail(id, errorBackupInfo) {
82
82
  const { error, value } = validateBackupFail.validate(errorBackupInfo, {
83
83
  stripUnknown: true,
84
84
  allowUnknown: true,
@@ -104,6 +104,7 @@ class BackupState extends BaseState {
104
104
  * @param {import('@abtnode/models').BackupState} backup
105
105
  * @return {Promise<import('@abtnode/models').BackupState>}
106
106
  */
107
+ // eslint-disable-next-line require-await
107
108
  async create(backup) {
108
109
  const { error, value } = validateBackup.validate(backup, {
109
110
  allowUnknown: true,
@@ -121,7 +122,7 @@ class BackupState extends BaseState {
121
122
  * @param {{ did: string }} { did }
122
123
  * @return {Promise<Array<import('@abtnode/models').BackupState>>}
123
124
  */
124
- async getBlockletBackups({ did }) {
125
+ getBlockletBackups({ did }) {
125
126
  return this.find({ appPid: did }, {}, { updatedAt: -1 });
126
127
  }
127
128
  }
@@ -207,10 +207,20 @@ class BlockletExtrasState extends BaseState {
207
207
  return super.upsert({ did }, { $set: entity });
208
208
  }
209
209
 
210
- async getMeta(did) {
210
+ getMeta(did) {
211
211
  return super.findOne({ did }, { did: 1, controller: 1, meta: 1 });
212
212
  }
213
213
 
214
+ async isLauncherSessionConsumed(sessionId) {
215
+ const count = await super.count({ 'controller.sessionId': sessionId });
216
+ return count > 0;
217
+ }
218
+
219
+ async isLauncherNftConsumed(nftId) {
220
+ const count = await super.count({ 'controller.nftId': nftId });
221
+ return count > 0;
222
+ }
223
+
214
224
  encryptSecurityData({ data, _rootDid } = {}) {
215
225
  if (!data) {
216
226
  return data;