@abtnode/core 1.16.0-beta-1d6c582e → 1.16.0-beta-99e016c7

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.
@@ -1,6 +1,23 @@
1
+ /**
2
+ * @typedef {{
3
+ * appDid: string
4
+ * event: import('events').EventEmitter,
5
+ * }} BaseBackupInput
6
+ *
7
+ * @typedef {{
8
+ * encrypt: (v: string) => string,
9
+ * decrypt: (v: string) => string,
10
+ * }} BaseSecurityContext
11
+ */
12
+
13
+ const { Hasher } = require('@ocap/mcrypto');
14
+ const { toBuffer } = require('@ocap/util');
15
+ const getBlockletInfo = require('@blocklet/meta/lib/info');
16
+ const security = require('@abtnode/util/lib/security');
17
+
1
18
  class BaseBackup {
2
19
  /**
3
- * @type {import('./spaces').SpaceBackupInput}
20
+ * @type {BaseBackupInput}
4
21
  * @memberof BaseBackup
5
22
  */
6
23
  input;
@@ -21,8 +38,8 @@ class BaseBackup {
21
38
 
22
39
  /**
23
40
  *
24
- * @description spaces 的 endpoint
25
- * @type {import('./spaces').SecurityContext}
41
+ * @description 安全相关的上下文
42
+ * @type {BaseSecurityContext}
26
43
  * @memberof BaseBackup
27
44
  */
28
45
  securityContext;
@@ -41,20 +58,57 @@ class BaseBackup {
41
58
 
42
59
  /**
43
60
  *
44
- *
45
- * @param {import('./spaces').SpacesBackup} spacesBackup
61
+ * @param {BaseBackup} backup
46
62
  * @memberof BaseBackup
47
63
  */
48
- ensureParams(spacesBackup) {
49
- this.blocklet = spacesBackup.blocklet;
50
- this.serverDir = spacesBackup.serverDir;
51
- this.backupDir = spacesBackup.backupDir;
52
- this.securityContext = spacesBackup.securityContext;
64
+ ensureParams(backup) {
65
+ this.blocklet = backup.blocklet;
66
+ this.serverDir = backup.serverDir;
67
+ this.backupDir = backup.backupDir;
68
+ this.securityContext = backup.securityContext;
53
69
  }
54
70
 
55
71
  async export() {
56
72
  throw new Error('not implemented');
57
73
  }
74
+
75
+ async _getSecurityContext(states) {
76
+ const blocklet = await states.blocklet.getBlocklet(this.input.appDid);
77
+ const nodeInfo = await states.node.read();
78
+
79
+ const { wallet } = getBlockletInfo(blocklet, nodeInfo.sk);
80
+
81
+ const { secretKey, address } = wallet; // we encrypt using latest wallet, not the permanent wallet
82
+ const password = toBuffer(Hasher.SHA3.hash256(Buffer.concat([secretKey, address].map(toBuffer))));
83
+ const encrypt = (v) => security.encrypt(v, address, password);
84
+ const decrypt = (v) => security.decrypt(v, address, password);
85
+
86
+ return {
87
+ signer: wallet,
88
+ delegation: '',
89
+ encrypt,
90
+ decrypt,
91
+ };
92
+ }
93
+
94
+ /**
95
+ *
96
+ * @param {BaseBackup} dataBackup
97
+ * @param {Array<BaseBackup>} storages
98
+ * @memberof BaseBackup
99
+ */
100
+ async _exportData(dataBackup, storages) {
101
+ // @note: dataBackup 需要先于 blockletBackup 执行,并且 blockletBackup 与其他 backup的执行可以是无序的
102
+ dataBackup.ensureParams(this);
103
+ await dataBackup.export();
104
+
105
+ await Promise.all(
106
+ storages.map((storage) => {
107
+ storage.ensureParams(this);
108
+ return storage.export();
109
+ })
110
+ );
111
+ }
58
112
  }
59
113
 
60
114
  module.exports = {
@@ -66,7 +66,7 @@ class BlockletBackup extends BaseBackup {
66
66
  * @memberof BlockletExtrasBackup
67
67
  */
68
68
  encrypt(info) {
69
- if (Array.isArray(info.migratedFrom)) {
69
+ if (Array.isArray(info?.migratedFrom)) {
70
70
  info.migratedFrom = info.migratedFrom.map((x) => {
71
71
  x.appSk = this.securityContext.encrypt(x.appSk);
72
72
  return x;
@@ -0,0 +1,132 @@
1
+ const fs = require('fs-extra');
2
+ const { isValid } = require('@arcblock/did');
3
+ const { ensureDirSync } = require('fs-extra');
4
+ const { isEmpty } = require('lodash');
5
+ const { join } = require('path');
6
+ const { getAppName } = require('@blocklet/meta/lib/util');
7
+
8
+ const states = require('../../../states');
9
+ const { getBackupDirs } = require('../utils/disk');
10
+ const { BaseBackup } = require('./base');
11
+ const { AuditLogBackup } = require('./audit-log');
12
+ const { BlockletBackup } = require('./blocklet');
13
+ const { BlockletExtrasBackup } = require('./blocklet-extras');
14
+ const { BlockletsBackup } = require('./blocklets');
15
+ const { DataBackup } = require('./data');
16
+ const { RoutingRuleBackup } = require('./routing-rule');
17
+
18
+ class DiskBackup extends BaseBackup {
19
+ /**
20
+ *
21
+ * @type {import('./base').BaseBackupInput}
22
+ * @memberof DiskBackup
23
+ */
24
+ input;
25
+
26
+ /**
27
+ * @description blocklet state 对象
28
+ * @type {import('@abtnode/client').BlockletState}
29
+ * @memberof DiskBackup
30
+ */
31
+ blocklet;
32
+
33
+ /**
34
+ * @type {string}
35
+ * @memberof DiskBackup
36
+ */
37
+ backupDir;
38
+
39
+ /**
40
+ *
41
+ * @description server 的数据目录
42
+ * @type {string}
43
+ * @memberof DiskBackup
44
+ */
45
+ serverDir;
46
+
47
+ /**
48
+ *
49
+ * @type {import('./base').BaseSecurityContext}
50
+ * @memberof DiskBackup
51
+ */
52
+ securityContext;
53
+
54
+ storages;
55
+
56
+ dataBackup;
57
+
58
+ /**
59
+ *
60
+ * @param {import('./base').BaseBackupInput} input
61
+ * @memberof DiskBackup
62
+ */
63
+ constructor(input) {
64
+ super(input);
65
+ this.verify(input);
66
+ this.input = input;
67
+ this.storages = [
68
+ new AuditLogBackup(this.input),
69
+ new BlockletBackup(this.input),
70
+ new BlockletsBackup(this.input),
71
+ new BlockletExtrasBackup(this.input),
72
+ new RoutingRuleBackup(this.input),
73
+ ];
74
+ this.dataBackup = new DataBackup(this.input);
75
+ }
76
+
77
+ /**
78
+ * @param {import('./base').BaseBackupInput} input
79
+ * @returns {void}
80
+ * @memberof DiskBackup
81
+ */
82
+ verify(input) {
83
+ if (isEmpty(input?.appDid) || !isValid(input?.appDid)) {
84
+ throw new Error(`input.appDid(${input?.appDid}) is not a valid did`);
85
+ }
86
+ }
87
+
88
+ /**
89
+ *
90
+ * @returns {Promise<void>}
91
+ * @memberof DiskBackup
92
+ */
93
+ async backup() {
94
+ await this.initialize();
95
+ await this.addMeta();
96
+ await this.export();
97
+ }
98
+
99
+ async initialize() {
100
+ this.blocklet = await states.blocklet.getBlocklet(this.input.appDid);
101
+ if (isEmpty(this.blocklet)) {
102
+ throw new Error('blocklet cannot be empty');
103
+ }
104
+
105
+ this.serverDir = process.env.ABT_NODE_DATA_DIR;
106
+ const { baseBackupDir, backupDir } = getBackupDirs(this.serverDir, this.blocklet.appDid);
107
+ this.baseBackupDir = baseBackupDir;
108
+ this.backupDir = backupDir;
109
+ ensureDirSync(this.backupDir);
110
+
111
+ this.securityContext = await this._getSecurityContext(states);
112
+ }
113
+
114
+ async export() {
115
+ return this._exportData(this.dataBackup, this.storages);
116
+ }
117
+
118
+ async addMeta() {
119
+ const meta = {
120
+ appDid: this.blocklet.appDid,
121
+ appPid: this.blocklet.appPid,
122
+ name: getAppName(this.blocklet),
123
+ createdAt: Date.now(),
124
+ };
125
+
126
+ await fs.writeJSON(join(this.baseBackupDir, 'meta.json'), meta);
127
+ }
128
+ }
129
+
130
+ module.exports = {
131
+ DiskBackup,
132
+ };
@@ -20,15 +20,12 @@ const { SpaceClient, BackupBlockletCommand } = require('@did-space/client');
20
20
  const { ensureDirSync } = require('fs-extra');
21
21
  const { isEmpty } = require('lodash');
22
22
  const { join, basename } = require('path');
23
- const { Hasher } = require('@ocap/mcrypto');
24
- const { toBuffer } = require('@ocap/util');
25
23
  const { getAppName, getAppDescription } = require('@blocklet/meta/lib/util');
26
- const getBlockletInfo = require('@blocklet/meta/lib/info');
27
- const security = require('@abtnode/util/lib/security');
28
24
 
29
25
  const logger = require('@abtnode/logger')('@abtnode/core:storage:backup');
30
26
 
31
27
  const states = require('../../../states');
28
+ const { BaseBackup } = require('./base');
32
29
  const { AuditLogBackup } = require('./audit-log');
33
30
  const { BlockletBackup } = require('./blocklet');
34
31
  const { BlockletExtrasBackup } = require('./blocklet-extras');
@@ -36,7 +33,7 @@ const { BlockletsBackup } = require('./blocklets');
36
33
  const { DataBackup } = require('./data');
37
34
  const { RoutingRuleBackup } = require('./routing-rule');
38
35
 
39
- class SpacesBackup {
36
+ class SpacesBackup extends BaseBackup {
40
37
  /**
41
38
  *
42
39
  * @type {SpaceBackupInput}
@@ -84,12 +81,15 @@ class SpacesBackup {
84
81
 
85
82
  storages;
86
83
 
84
+ dataBackup;
85
+
87
86
  /**
88
87
  *
89
88
  * @param {SpaceBackupInput} input
90
89
  * @memberof SpacesBackup
91
90
  */
92
91
  constructor(input) {
92
+ super(input);
93
93
  this.verify(input);
94
94
  this.input = input;
95
95
  this.storages = [
@@ -99,6 +99,7 @@ class SpacesBackup {
99
99
  new BlockletExtrasBackup(this.input),
100
100
  new RoutingRuleBackup(this.input),
101
101
  ];
102
+ this.dataBackup = new DataBackup(this.input);
102
103
  }
103
104
 
104
105
  /**
@@ -140,7 +141,7 @@ class SpacesBackup {
140
141
  throw new Error('spaceEndpoint cannot be empty');
141
142
  }
142
143
 
143
- this.securityContext = await this.getSecurityContext();
144
+ this.securityContext = await this._getSecurityContext(states);
144
145
  }
145
146
 
146
147
  async export() {
@@ -151,17 +152,7 @@ class SpacesBackup {
151
152
  completed: false,
152
153
  });
153
154
 
154
- // @note: dataBackup 需要先于 blockletBackup 执行,并且 blockletBackup 与其他 backup的执行可以是无序的
155
- const dataBackup = new DataBackup(this.input);
156
- dataBackup.ensureParams(this);
157
- await dataBackup.export();
158
-
159
- await Promise.all(
160
- this.storages.map((storage) => {
161
- storage.ensureParams(this);
162
- return storage.export();
163
- })
164
- );
155
+ await this._exportData(this.dataBackup, this.storages);
165
156
 
166
157
  this.input.event.emit(BlockletEvents.backupProgress, {
167
158
  appDid: this.input.appDid,
@@ -220,25 +211,6 @@ class SpacesBackup {
220
211
  throw new Error(`Sync to spaces encountered error: ${message}`);
221
212
  }
222
213
  }
223
-
224
- async getSecurityContext() {
225
- const blocklet = await states.blocklet.getBlocklet(this.input.appDid);
226
- const nodeInfo = await states.node.read();
227
-
228
- const { wallet } = getBlockletInfo(blocklet, nodeInfo.sk);
229
-
230
- const { secretKey, address } = wallet; // we encrypt using latest wallet, not the permanent wallet
231
- const password = toBuffer(Hasher.SHA3.hash256(Buffer.concat([secretKey, address].map(toBuffer))));
232
- const encrypt = (v) => security.encrypt(v, address, password);
233
- const decrypt = (v) => security.decrypt(v, address, password);
234
-
235
- return {
236
- signer: wallet,
237
- delegation: '',
238
- encrypt,
239
- decrypt,
240
- };
241
- }
242
214
  }
243
215
 
244
216
  module.exports = {
@@ -1,13 +1,20 @@
1
+ /**
2
+ * @typedef {{
3
+ * appDid: string; // --> appDid
4
+ * password: Buffer; // derived from (appSk, appDid)
5
+ * event: import('events').EventEmitter,
6
+ * }} BaseRestoreInput
7
+ */
8
+
1
9
  class BaseRestore {
2
10
  /**
3
11
  *
4
- * @type {import('./spaces').SpaceRestoreInput}
12
+ * @type {BaseRestoreInput}
5
13
  * @memberof BaseRestore
6
14
  */
7
15
  input;
8
16
 
9
17
  /**
10
- * @description 当前 blocklet 的数据目录
11
18
  * @type {string}
12
19
  * @memberof BaseRestore
13
20
  */
@@ -28,12 +35,12 @@ class BaseRestore {
28
35
  /**
29
36
  *
30
37
  *
31
- * @param {import('./spaces').SpacesRestore} spaces
38
+ * @param {BaseRestore} restore
32
39
  * @memberof BaseRestore
33
40
  */
34
- ensureParams(spaces) {
35
- this.restoreDir = spaces.restoreDir;
36
- this.serverDir = spaces.serverDir;
41
+ ensureParams(restore) {
42
+ this.restoreDir = restore.restoreDir;
43
+ this.serverDir = restore.serverDir;
37
44
  }
38
45
 
39
46
  // eslint-disable-next-line
@@ -9,8 +9,7 @@ class BlockletExtrasRestore extends BaseRestore {
9
9
  filename = 'blocklet-extras.json';
10
10
 
11
11
  async import(params) {
12
- const extras = this.getExtras();
13
- this.cleanExtras(extras, params);
12
+ const extras = this.cleanExtras(this.getExtras(), params);
14
13
  removeSync(join(this.restoreDir, this.filename));
15
14
  outputJsonSync(join(this.restoreDir, this.filename), extras);
16
15
  }
@@ -32,9 +31,10 @@ class BlockletExtrasRestore extends BaseRestore {
32
31
  *
33
32
  * @description 清理数据并加密
34
33
  * @param {import('@abtnode/client').BlockletState} raw
34
+ * @returns {import('@abtnode/client').BlockletState}
35
35
  * @memberof BlockletExtrasRestore
36
36
  */
37
- async cleanExtras(raw, params) {
37
+ cleanExtras(raw, params) {
38
38
  const blockletExtra = cloneDeep(raw);
39
39
 
40
40
  const queue = [blockletExtra];
@@ -48,6 +48,8 @@ class BlockletExtrasRestore extends BaseRestore {
48
48
  queue.push(...current.children);
49
49
  }
50
50
  }
51
+
52
+ return blockletExtra;
51
53
  }
52
54
 
53
55
  /**
@@ -33,7 +33,7 @@ class BlockletRestore extends BaseRestore {
33
33
  */
34
34
  decrypt(blocklet, params) {
35
35
  const { password } = this.input;
36
- if (Array.isArray(blocklet.migratedFrom)) {
36
+ if (Array.isArray(blocklet?.migratedFrom)) {
37
37
  blocklet.migratedFrom = blocklet.migratedFrom.map((x) => {
38
38
  x.appSk = security.decrypt(x.appSk, params.salt, password);
39
39
  return x;
@@ -0,0 +1,104 @@
1
+ const { isValid } = require('@arcblock/did');
2
+ const { isEmpty } = require('lodash');
3
+ const merge = require('lodash/merge');
4
+ const { ensureDirSync, existsSync, rmSync, copy } = require('fs-extra');
5
+
6
+ const { getBackupDirs } = require('../utils/disk');
7
+ const { BaseRestore } = require('./base');
8
+ const { BlockletExtrasRestore } = require('./blocklet-extras');
9
+ const { BlockletRestore } = require('./blocklet');
10
+ const { BlockletsRestore } = require('./blocklets');
11
+
12
+ class DiskRestore extends BaseRestore {
13
+ /**
14
+ *
15
+ * @type {import('./base').BaseRestoreInput}
16
+ * @memberof DiskRestore
17
+ */
18
+ input;
19
+
20
+ /**
21
+ * @type {string}
22
+ * @memberof DiskRestore
23
+ */
24
+ restoreDir;
25
+
26
+ /**
27
+ *
28
+ * @description server 的数据目录
29
+ * @type {string}
30
+ * @memberof DiskRestore
31
+ */
32
+ serverDir;
33
+
34
+ storages;
35
+
36
+ /**
37
+ *
38
+ * @param {import('./base').BaseRestoreInput} input
39
+ * @memberof DiskRestore
40
+ */
41
+ constructor(input) {
42
+ super(input);
43
+ this.verify(input);
44
+ this.input = input;
45
+ this.storages = [
46
+ new BlockletExtrasRestore(this.input),
47
+ new BlockletRestore(this.input),
48
+ new BlockletsRestore(this.input),
49
+ ];
50
+ }
51
+
52
+ /**
53
+ *
54
+ * @param {import('./base').BaseRestoreInput} input
55
+ * @returns {void}
56
+ * @memberof DiskRestore
57
+ */
58
+ verify(input) {
59
+ if (isEmpty(input?.appDid) || !isValid(input?.appDid)) {
60
+ throw new Error(`input.appDid(${input?.appDid}) is not a valid did`);
61
+ }
62
+ }
63
+
64
+ async initialize() {
65
+ this.serverDir = process.env.ABT_NODE_DATA_DIR;
66
+ this.restoreDir = getBackupDirs(this.serverDir, this.input.appDid).restoreDir;
67
+ if (existsSync(this.restoreDir)) {
68
+ rmSync(this.restoreDir, { recursive: true });
69
+ }
70
+ ensureDirSync(this.restoreDir);
71
+
72
+ this.storages.map((x) => x.ensureParams(this));
73
+ }
74
+
75
+ async restore() {
76
+ await this.initialize();
77
+ await this.syncFromBackupDir();
78
+
79
+ const params = await Promise.all(this.storages.map((x) => x.getImportParams()));
80
+ await this.import(merge(...params));
81
+
82
+ return this.storages.map((x) => x.getInstallParams());
83
+ }
84
+
85
+ async syncFromBackupDir() {
86
+ const { appDid } = this.input;
87
+
88
+ const { backupDir } = getBackupDirs(this.serverDir, appDid);
89
+
90
+ await copy(backupDir, this.restoreDir);
91
+ }
92
+
93
+ async import(params) {
94
+ await Promise.all(
95
+ this.storages.map((storage) => {
96
+ return storage.import(params);
97
+ })
98
+ );
99
+ }
100
+ }
101
+
102
+ module.exports = {
103
+ DiskRestore,
104
+ };
@@ -13,18 +13,19 @@
13
13
 
14
14
  const validUrl = require('valid-url');
15
15
  const merge = require('lodash/merge');
16
- const { BlockletEvents } = require('@blocklet/constant');
16
+ const { BlockletEvents, RESTORE_PROGRESS_STATUS } = require('@blocklet/constant');
17
17
  const { SpaceClient, RestoreBlockletCommand } = require('@did-space/client');
18
18
  const { ensureDirSync, existsSync, rmSync } = require('fs-extra');
19
- const { join, basename } = require('path');
19
+ const { join } = require('path');
20
20
 
21
21
  const logger = require('@abtnode/logger')('@abtnode/core:storage:restore');
22
22
 
23
+ const { BaseRestore } = require('./base');
23
24
  const { BlockletExtrasRestore } = require('./blocklet-extras');
24
25
  const { BlockletRestore } = require('./blocklet');
25
26
  const { BlockletsRestore } = require('./blocklets');
26
27
 
27
- class SpacesRestore {
28
+ class SpacesRestore extends BaseRestore {
28
29
  /**
29
30
  *
30
31
  * @type {SpaceRestoreInput}
@@ -55,6 +56,7 @@ class SpacesRestore {
55
56
  * @memberof SpacesRestore
56
57
  */
57
58
  constructor(input) {
59
+ super(input);
58
60
  this.verify(input);
59
61
  this.input = input;
60
62
  this.storages = [
@@ -120,7 +122,8 @@ class SpacesRestore {
120
122
  logger.info('restore progress', { appDid: this.input.appDid, data });
121
123
  this.input.event.emit(BlockletEvents.restoreProgress, {
122
124
  appDid: this.input.appDid,
123
- message: `Downloading file ${basename(data.key)} (${data.completed}/${data.total})`,
125
+ status: RESTORE_PROGRESS_STATUS.downloading,
126
+ data,
124
127
  });
125
128
  },
126
129
 
@@ -137,8 +140,9 @@ class SpacesRestore {
137
140
  async import(params) {
138
141
  this.input.event.emit(BlockletEvents.restoreProgress, {
139
142
  appDid: this.input.appDid,
140
- message: 'Preparing to import data...',
143
+ status: RESTORE_PROGRESS_STATUS.importData,
141
144
  });
145
+
142
146
  await Promise.all(
143
147
  this.storages.map((storage) => {
144
148
  return storage.import(params);
@@ -146,7 +150,7 @@ class SpacesRestore {
146
150
  );
147
151
  this.input.event.emit(BlockletEvents.restoreProgress, {
148
152
  appDid: this.input.appDid,
149
- message: 'Importing data successfully...',
153
+ status: RESTORE_PROGRESS_STATUS.importDataSuccess,
150
154
  });
151
155
  }
152
156
  }
@@ -0,0 +1,61 @@
1
+ const path = require('path');
2
+ const fs = require('fs-extra');
3
+
4
+ const logger = require('@abtnode/logger')('@abtnode/core:storage:utils:disk');
5
+
6
+ const backupDirName = '_abtnode/backup';
7
+ const restoreDirName = 'tmp/restore-disk';
8
+
9
+ const getBackupList = (dataDir) => {
10
+ const baseBackupDir = path.join(dataDir, backupDirName);
11
+ const backupList = [];
12
+ const appDidList = fs.readdirSync(baseBackupDir);
13
+
14
+ appDidList.forEach((appDid) => {
15
+ const metaFile = path.join(baseBackupDir, appDid, 'meta.json');
16
+ if (fs.existsSync(metaFile)) {
17
+ try {
18
+ const meta = fs.readJsonSync(metaFile);
19
+ if (meta.appDid === appDid) {
20
+ backupList.push(meta);
21
+ }
22
+ } catch (error) {
23
+ logger.error('read meta.json error', error);
24
+ }
25
+ }
26
+ });
27
+
28
+ return backupList;
29
+ };
30
+
31
+ const removeBackup = async (dataDir, appDid) => {
32
+ try {
33
+ const baseBackupDir = path.join(dataDir, backupDirName);
34
+ const backupDir = path.join(baseBackupDir, appDid);
35
+ if (fs.existsSync(backupDir)) {
36
+ await fs.remove(backupDir);
37
+ return true;
38
+ }
39
+ return false;
40
+ } catch (error) {
41
+ logger.error('remove backup error', error);
42
+ return false;
43
+ }
44
+ };
45
+
46
+ const getBackupDirs = (serverDir, appDid) => {
47
+ const baseBackupDir = path.join(serverDir, 'data', backupDirName, appDid);
48
+ const backupDir = path.join(baseBackupDir, appDid);
49
+ const restoreDir = path.join(serverDir, restoreDirName, appDid);
50
+ return {
51
+ baseBackupDir,
52
+ backupDir,
53
+ restoreDir,
54
+ };
55
+ };
56
+
57
+ module.exports = {
58
+ getBackupList,
59
+ removeBackup,
60
+ getBackupDirs,
61
+ };
package/lib/event.js CHANGED
@@ -257,7 +257,13 @@ module.exports = ({
257
257
  }
258
258
 
259
259
  if (
260
- ![BlockletEvents.removed, BlockletEvents.dataCleaned].includes(eventName) &&
260
+ [
261
+ BlockletEvents.started,
262
+ BlockletEvents.startFailed,
263
+ BlockletEvents.stopped,
264
+ BlockletEvents.reloaded,
265
+ BlockletEvents.statusChange,
266
+ ].includes(eventName) &&
261
267
  blocklet.status &&
262
268
  !isBeforeInstalled(blocklet.status)
263
269
  ) {
package/lib/index.js CHANGED
@@ -230,11 +230,12 @@ function ABTNode(options) {
230
230
  deleteBlockletProcess: blockletManager.deleteProcess.bind(blockletManager),
231
231
  configPublicToStore: blockletManager.configPublicToStore.bind(blockletManager),
232
232
  configNavigations: blockletManager.configNavigations.bind(blockletManager),
233
+ configOAuth: blockletManager.configOAuth.bind(blockletManager),
233
234
  updateWhoCanAccess: blockletManager.updateWhoCanAccess.bind(blockletManager),
234
235
  updateComponentTitle: blockletManager.updateComponentTitle.bind(blockletManager),
235
236
  updateComponentMountPoint: blockletManager.updateComponentMountPoint.bind(blockletManager),
236
- backupToSpaces: blockletManager.backupToSpaces.bind(blockletManager),
237
- restoreFromSpaces: blockletManager.restoreFromSpaces.bind(blockletManager),
237
+ backupBlocklet: blockletManager.backup.bind(blockletManager),
238
+ restoreBlocklet: blockletManager.restore.bind(blockletManager),
238
239
  migrateApplicationToStructV2: blockletManager.migrateApplicationToStructV2.bind(blockletManager),
239
240
 
240
241
  // For diagnose purpose
@@ -243,6 +244,7 @@ function ABTNode(options) {
243
244
  updateBlockletStatus: states.blocklet.setBlockletStatus.bind(states.blocklet),
244
245
 
245
246
  getBlocklets: blockletManager.list.bind(blockletManager),
247
+ getBlockletsFromBackup: blockletManager.listBackups.bind(blockletManager),
246
248
  getBlocklet: blockletManager.detail.bind(blockletManager),
247
249
  getBlockletDiff: blockletManager.diff.bind(blockletManager),
248
250
  hasBlocklet: blockletManager.hasBlocklet.bind(blockletManager),