@abtnode/core 1.8.65-beta-f7af64a4 → 1.8.65-beta-bfcc12ce

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,7 +1,8 @@
1
- const { removeSync, existsSync, ensureDirSync, createWriteStream } = require('fs-extra');
2
- const { join, dirname } = require('path');
3
- const archiver = require('archiver');
1
+ const { join } = require('path');
2
+ const validUrl = require('valid-url');
4
3
  const { BaseBackup } = require('./base');
4
+ const { dirToZip } = require('../utils/zip');
5
+ const { compareAndMove } = require('../utils/hash');
5
6
 
6
7
  class BlockletsBackup extends BaseBackup {
7
8
  /**
@@ -13,21 +14,25 @@ class BlockletsBackup extends BaseBackup {
13
14
  const blockletMetas = this.getBlockletMetas(this.blocklet);
14
15
  const serverBlockletsDir = join(this.serverDataDir, 'blocklets');
15
16
 
17
+ const blockletMetasFromLocal = blockletMetas.filter(
18
+ (b) => !validUrl.isHttpUri(b.tarball) && !validUrl.isHttpsUri(b.tarball)
19
+ );
20
+
16
21
  const dirs = [];
17
- for (const blockletMeta of blockletMetas) {
22
+ for (const blockletMeta of blockletMetasFromLocal) {
18
23
  const sourceDir = join(serverBlockletsDir, blockletMeta.name, blockletMeta.version);
19
- const destDir = join(blockletMeta.name, blockletMeta.version);
20
- dirs.push({ sourceDir, destDir });
24
+ const zipPath = join(this.blockletBackupDir, 'blocklets', blockletMeta.name, `${blockletMeta.version}.zip`);
25
+ dirs.push({ sourceDir, zipPath });
21
26
  }
22
27
 
23
- await this.dirsToZip(dirs, join(this.blockletBackupDir, 'blocklets.zip'));
28
+ await this.dirsToZip(dirs);
24
29
  }
25
30
 
26
31
  /**
27
32
  *
28
33
  *
29
34
  * @param {import('@abtnode/client').BlockletState} blocklet
30
- * @returns {Array<{name: string, version: string}>}
35
+ * @returns {Array<{name: string, version: string, tarball: string}>}
31
36
  * @memberof BlockletsBackup
32
37
  */
33
38
  getBlockletMetas(blocklet) {
@@ -39,6 +44,7 @@ class BlockletsBackup extends BaseBackup {
39
44
  metas.push({
40
45
  name: blocklet.meta.bundleName,
41
46
  version: blocklet.meta.version,
47
+ tarball: blocklet?.meta?.dist?.tarball,
42
48
  });
43
49
 
44
50
  for (const child of blocklet.children) {
@@ -49,31 +55,19 @@ class BlockletsBackup extends BaseBackup {
49
55
  }
50
56
 
51
57
  /**
52
- * @param {Array<{sourceDir: string, destDir: string}>} dirs: /some/folder/to/compress
58
+ * @param {Array<{sourceDir: string, zipPath: string}>} dirs: /some/folder/to/compress
53
59
  * @param {String} zipPath: /path/to/created.zip
54
60
  * @returns {Promise}
55
61
  * @memberof BlockletsBackup
56
62
  */
57
- async dirsToZip(dirs, zipPath) {
58
- ensureDirSync(dirname(zipPath));
59
- if (existsSync(zipPath)) {
60
- removeSync(zipPath);
61
- }
62
-
63
- const archive = archiver('zip', { zlib: { level: 9 } });
64
- const stream = createWriteStream(zipPath);
65
-
66
- return new Promise((resolve, reject) => {
67
- archive.on('error', (err) => reject(err));
68
- stream.on('close', () => resolve());
69
-
70
- for (const dir of dirs) {
71
- archive.directory(dir.sourceDir, dir.destDir);
72
- }
73
-
74
- archive.pipe(stream);
75
- archive.finalize();
76
- });
63
+ async dirsToZip(dirs) {
64
+ await Promise.all(
65
+ dirs.map(async (dir) => {
66
+ const tempZipPath = `${dir.zipPath}.bak`;
67
+ await dirToZip(dir.sourceDir, tempZipPath);
68
+ await compareAndMove(dir.zipPath, tempZipPath);
69
+ })
70
+ );
77
71
  }
78
72
  }
79
73
 
@@ -1,4 +1,4 @@
1
- const { copySync } = require('fs-extra');
1
+ const { copy } = require('fs-extra');
2
2
  const { join } = require('path');
3
3
  const { BaseBackup } = require('./base');
4
4
 
@@ -12,7 +12,7 @@ class DataBackup extends BaseBackup {
12
12
  const blockletDataDir = join(this.serverDataDir, 'data', this.blocklet.meta.name);
13
13
  const blockletBackupDataDir = join(this.blockletBackupDir, 'data');
14
14
 
15
- copySync(blockletDataDir, blockletBackupDataDir, { overwrite: true });
15
+ await copy(blockletDataDir, blockletBackupDataDir, { overwrite: true });
16
16
  }
17
17
  }
18
18
 
@@ -1,7 +1,8 @@
1
- const { ensureDirSync, copySync, statSync } = require('fs-extra');
1
+ const { ensureDirSync, copy, statSync } = require('fs-extra');
2
2
  const { join } = require('path');
3
3
  const { BaseBackup } = require('./base');
4
4
 
5
+ // note: 可以不需要备份
5
6
  class LogsBackup extends BaseBackup {
6
7
  async export() {
7
8
  const sourceLogsDir = join(this.serverDataDir, 'logs', this.blocklet.meta.name);
@@ -9,7 +10,7 @@ class LogsBackup extends BaseBackup {
9
10
 
10
11
  const targetLogsDir = join(this.blockletBackupDir, 'logs');
11
12
 
12
- copySync(sourceLogsDir, targetLogsDir, {
13
+ await copy(sourceLogsDir, targetLogsDir, {
13
14
  overwrite: true,
14
15
  filter: (src) => {
15
16
  return !statSync(src).isSymbolicLink();
@@ -8,7 +8,7 @@ const { isValid } = require('@arcblock/did');
8
8
  const { BLOCKLET_CONFIGURABLE_KEY } = require('@blocklet/constant');
9
9
  const { getBlockletInfo } = require('@blocklet/meta');
10
10
  const { SpaceClient, SyncFolderPushCommand } = require('@did-space/client');
11
- const { ensureDirSync, existsSync, rmdirSync, removeSync } = require('fs-extra');
11
+ const { ensureDirSync } = require('fs-extra');
12
12
  const { isEmpty } = require('lodash');
13
13
  const { join } = require('path');
14
14
  const states = require('../../../states');
@@ -17,7 +17,6 @@ const { BlockletBackup } = require('./blocklet');
17
17
  const { BlockletExtrasBackup } = require('./blocklet-extras');
18
18
  const { BlockletsBackup } = require('./blocklets');
19
19
  const { DataBackup } = require('./data');
20
- const { LogsBackup } = require('./logs');
21
20
  const { RoutingRuleBackup } = require('./routing-rule');
22
21
 
23
22
  class SpacesBackup {
@@ -78,7 +77,6 @@ class SpacesBackup {
78
77
  this.input = input;
79
78
  this.storages = [
80
79
  new AuditLogBackup(this.input),
81
- new LogsBackup(this.input),
82
80
  new BlockletBackup(this.input),
83
81
  new BlockletsBackup(this.input),
84
82
  new BlockletExtrasBackup(this.input),
@@ -107,7 +105,6 @@ class SpacesBackup {
107
105
  await this.initialize();
108
106
  await this.export();
109
107
  await this.syncToSpaces();
110
- await this.destroy();
111
108
  }
112
109
 
113
110
  async initialize() {
@@ -121,9 +118,6 @@ class SpacesBackup {
121
118
  this.serverDataDir = process.env.ABT_NODE_DATA_DIR;
122
119
 
123
120
  this.blockletBackupDir = join(process.env.ABT_NODE_DATA_DIR, 'tmp/backup', this.blocklet.meta.did);
124
- if (existsSync(this.blockletBackupDir)) {
125
- rmdirSync(this.blockletBackupDir, { recursive: true });
126
- }
127
121
  ensureDirSync(this.blockletBackupDir);
128
122
 
129
123
  this.spacesEndpoint = this.blocklet.environments.find(
@@ -158,7 +152,8 @@ class SpacesBackup {
158
152
  source: join(this.blockletBackupDir, '/'),
159
153
  target: join('.did-objects', this.blocklet.appDid),
160
154
  debug: true,
161
- retryCount: 3,
155
+ concurrency: 64,
156
+ retryCount: 100,
162
157
  filter: (object) => {
163
158
  return object.name !== '.DS_Store';
164
159
  },
@@ -176,12 +171,6 @@ class SpacesBackup {
176
171
  const { wallet } = getBlockletInfo(blockletInfo, nodeInfo.sk);
177
172
  return wallet;
178
173
  }
179
-
180
- async destroy() {
181
- if (existsSync(this.blockletBackupDir)) {
182
- removeSync(this.blockletBackupDir);
183
- }
184
- }
185
174
  }
186
175
 
187
176
  module.exports = {
@@ -1,5 +1,5 @@
1
1
  const { removeSync, outputJsonSync, readJSONSync } = require('fs-extra');
2
- const { cloneDeep } = require('lodash');
2
+ const { cloneDeep, isArray } = require('lodash');
3
3
  const { join } = require('path');
4
4
  const security = require('@abtnode/util/lib/security');
5
5
  const { BaseRestore } = require('./base');
@@ -61,6 +61,13 @@ class BlockletExtrasRestore extends BaseRestore {
61
61
  * @memberof BlockletExtrasRestore
62
62
  */
63
63
  useBlockletDecryptConfigs(configs) {
64
+ // eslint-disable-next-line no-console
65
+ console.log('debug', configs, !configs || !isArray(configs));
66
+
67
+ if (!configs || !isArray(configs)) {
68
+ return;
69
+ }
70
+
64
71
  for (const config of configs) {
65
72
  // secure 为 true 的配置才需要被加密保存上次到 did spaces
66
73
  if (config.secure) {
@@ -76,8 +83,6 @@ class BlockletExtrasRestore extends BaseRestore {
76
83
  config.value = decryptByBlocklet;
77
84
  }
78
85
  }
79
-
80
- return configs;
81
86
  }
82
87
  }
83
88
 
@@ -1,23 +1,41 @@
1
- const { existsSync, removeSync } = require('fs-extra');
1
+ const { existsSync, remove } = require('fs-extra');
2
2
  const { join } = require('path');
3
- const StreamZip = require('node-stream-zip');
3
+ const fg = require('fast-glob');
4
4
  const { BaseRestore } = require('./base');
5
+ const { zipToDir } = require('../utils/zip');
5
6
 
6
7
  class BlockletsRestore extends BaseRestore {
7
- filename = 'blocklets.zip';
8
+ filename = 'blocklets';
8
9
 
9
10
  async import() {
10
- const blockletZipPath = join(this.blockletRestoreDir, this.filename);
11
+ const blockletsDir = join(this.blockletRestoreDir, this.filename);
11
12
 
12
- if (!existsSync(blockletZipPath)) {
13
- throw new Error(`file not found: ${blockletZipPath}`);
13
+ if (!existsSync(blockletsDir)) {
14
+ throw new Error(`dir not found: ${blockletsDir}`);
14
15
  }
15
16
 
16
- // eslint-disable-next-line new-cap
17
- const zip = new StreamZip.async({ file: blockletZipPath });
18
- await zip.extract(null, join(this.blockletRestoreDir, 'blocklets'));
19
- await zip.close();
20
- removeSync(blockletZipPath);
17
+ const paths = await fg('**/*.zip', {
18
+ cwd: blockletsDir,
19
+ onlyFiles: true,
20
+ absolute: true,
21
+ });
22
+
23
+ /**
24
+ * @type {{source: string, target: string}}
25
+ */
26
+ const zipConfigs = paths.map((path) => {
27
+ return {
28
+ source: path,
29
+ target: path.replace(/.zip$/, ''),
30
+ };
31
+ });
32
+
33
+ await Promise.all(
34
+ zipConfigs.map(async (zipConfig) => {
35
+ await zipToDir(zipConfig.source, zipConfig.target);
36
+ await remove(zipConfig.source);
37
+ })
38
+ );
21
39
  }
22
40
  }
23
41
 
@@ -0,0 +1,21 @@
1
+ const { removeSync, existsSync } = require('fs-extra');
2
+ const { join } = require('path');
3
+ const { BaseRestore } = require('./base');
4
+ const { zipToDir } = require('../utils/zip');
5
+
6
+ class LogsRestore extends BaseRestore {
7
+ filename = 'logs.zip';
8
+
9
+ async import() {
10
+ const blockletZipPath = join(this.blockletRestoreDir, this.filename);
11
+
12
+ if (!existsSync(blockletZipPath)) {
13
+ throw new Error(`file not found: ${blockletZipPath}`);
14
+ }
15
+
16
+ await zipToDir(blockletZipPath, join(this.blockletRestoreDir, 'logs'));
17
+ removeSync(blockletZipPath);
18
+ }
19
+ }
20
+
21
+ module.exports = { LogsRestore };
@@ -74,6 +74,10 @@ class SpacesRestore {
74
74
  this.serverDataDir = process.env.ABT_NODE_DATA_DIR;
75
75
  this.blockletWallet = await this.getBlockletWallet();
76
76
 
77
+ if (!this.input.endpoint.includes(this.blockletWallet.address)) {
78
+ throw new Error(`endpoint and blocklet.appDid(${this.blockletWallet.address}) do not match`);
79
+ }
80
+
77
81
  this.blockletRestoreDir = join(process.env.ABT_NODE_DATA_DIR, 'tmp/restore', this.blockletWallet.address);
78
82
  if (existsSync(this.blockletRestoreDir)) {
79
83
  rmdirSync(this.blockletRestoreDir, { recursive: true });
@@ -113,7 +117,8 @@ class SpacesRestore {
113
117
  source: join('.did-objects', this.blockletWallet.address, '/'),
114
118
  target: this.blockletRestoreDir,
115
119
  debug: true,
116
- retryCount: 3,
120
+ concurrency: 64,
121
+ retryCount: 100,
117
122
  })
118
123
  );
119
124
 
@@ -0,0 +1,51 @@
1
+ const { removeSync, existsSync, move, createReadStream } = require('fs-extra');
2
+ const hasha = require('hasha');
3
+
4
+ /**
5
+ *
6
+ *
7
+ * @param {NodeJS.ReadableStream} stream1
8
+ * @param {NodeJS.ReadableStream} stream2
9
+ * @return {Promise<boolean>}
10
+ */
11
+ async function compareHash(stream1, stream2) {
12
+ const hash1 = await hasha.fromStream(stream1, {
13
+ algorithm: 'md5',
14
+ });
15
+ const hash2 = await hasha.fromStream(stream2, {
16
+ algorithm: 'md5',
17
+ });
18
+
19
+ return hash1 === hash2;
20
+ }
21
+
22
+ /**
23
+ *
24
+ * @description 比对新文件和旧文件的hash,旧文件不存在或者hash不同时,使用新文件替换,hash相同,删除新文件
25
+ * @param {string} oldFilePath
26
+ * @param {string} newFilePath
27
+ * @returns {Promise<boolean>}
28
+ */
29
+ async function compareAndMove(oldFilePath, newFilePath) {
30
+ if (!existsSync(oldFilePath)) {
31
+ await move(newFilePath, oldFilePath, { overwrite: true });
32
+ return;
33
+ }
34
+
35
+ if (!existsSync(newFilePath)) {
36
+ throw new Error(`newFilePath(${newFilePath}) not found`);
37
+ }
38
+
39
+ const isSame = await compareHash(createReadStream(oldFilePath), createReadStream(newFilePath));
40
+ if (isSame) {
41
+ removeSync(newFilePath);
42
+ return;
43
+ }
44
+
45
+ await move(newFilePath, oldFilePath, { overwrite: true });
46
+ }
47
+
48
+ module.exports = {
49
+ compareHash,
50
+ compareAndMove,
51
+ };
@@ -0,0 +1,43 @@
1
+ const archiver = require('archiver');
2
+ const { ensureDirSync, existsSync, removeSync, createWriteStream } = require('fs-extra');
3
+ const { dirname } = require('path');
4
+ const StreamZip = require('node-stream-zip');
5
+
6
+ /**
7
+ *
8
+ *
9
+ * @param {string} source ~/abc/ 通常是一个文件夹
10
+ * @param {string} target abc.zip 压缩包的名称
11
+ * @return {*}
12
+ */
13
+ function dirToZip(source, target) {
14
+ return new Promise((resolve, reject) => {
15
+ ensureDirSync(dirname(target));
16
+
17
+ if (existsSync(target)) {
18
+ removeSync(target);
19
+ }
20
+
21
+ const output = createWriteStream(target);
22
+ const archive = archiver('zip', { level: 9 });
23
+ archive.on('error', (err) => reject(err));
24
+ output.on('close', () => resolve());
25
+
26
+ archive.directory(source, false);
27
+
28
+ archive.pipe(output);
29
+ archive.finalize();
30
+ });
31
+ }
32
+
33
+ async function zipToDir(source, target) {
34
+ // eslint-disable-next-line new-cap
35
+ const zip = new StreamZip.async({ file: source });
36
+ await zip.extract(null, target);
37
+ await zip.close();
38
+ }
39
+
40
+ module.exports = {
41
+ dirToZip,
42
+ zipToDir,
43
+ };
@@ -7,7 +7,7 @@ const get = require('lodash/get');
7
7
  const cloneDeep = require('lodash/cloneDeep');
8
8
  const isEqual = require('lodash/isEqual');
9
9
  const joinUrl = require('url-join');
10
- const { replaceSlotToIp } = require('@blocklet/meta/lib/util');
10
+ const { replaceSlotToIp, findComponentById, findWebInterface } = require('@blocklet/meta/lib/util');
11
11
  const { getProvider } = require('@abtnode/router-provider');
12
12
  const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
13
13
  const getTmpDir = require('@abtnode/util/lib/get-tmp-directory');
@@ -41,9 +41,11 @@ const {
41
41
  const {
42
42
  BLOCKLET_DYNAMIC_PATH_PREFIX,
43
43
  BLOCKLET_INTERFACE_TYPE_WEB,
44
+ BLOCKLET_INTERFACE_PUBLIC,
44
45
  BLOCKLET_INTERFACE_WELLKNOWN,
45
46
  BLOCKLET_INTERFACE_TYPE_WELLKNOWN,
46
47
  BlockletEvents,
48
+ BLOCKLET_MODES,
47
49
  } = require('@blocklet/constant');
48
50
 
49
51
  // eslint-disable-next-line global-require
@@ -206,6 +208,9 @@ const ensureLatestInterfaceInfo = async (sites = []) => {
206
208
  }
207
209
 
208
210
  site.rules = site.rules.map((rule) => {
211
+ if (rule.dynamic) {
212
+ return rule;
213
+ }
209
214
  // If a rule already has a target and target is WELLKNOWN_SERVICE_PATH_PREFIX, just return
210
215
  // Indicates that the rule id generated by the system for auth service
211
216
  if (rule.isProtected && rule.to.target === WELLKNOWN_SERVICE_PATH_PREFIX) {
@@ -279,6 +284,7 @@ const ensureWellknownRule = async (sites) => {
279
284
  rule.from.pathPrefix = servicePathPrefix;
280
285
  rule.to.target = servicePathPrefix;
281
286
  rule.isProtected = true;
287
+ rule.dynamic = true; // mark as dynamic to avoid redundant generated rules
282
288
  site.rules.push(rule);
283
289
  }
284
290
 
@@ -290,6 +296,7 @@ const ensureWellknownRule = async (sites) => {
290
296
  rule.to.cacheGroup = 'blockletProxy';
291
297
  rule.to.target = avatarPathPrefix;
292
298
  rule.isProtected = true;
299
+ rule.dynamic = true; // mark as dynamic to avoid redundant generated rules
293
300
  site.rules.push(rule);
294
301
  }
295
302
  }
@@ -312,7 +319,7 @@ const ensureBlockletDid = async (sites) => {
312
319
  return site;
313
320
  }
314
321
 
315
- site.blockletDid = site.domain.replace(BLOCKLET_SITE_GROUP_SUFFIX, '');
322
+ site.blockletDid = getDidFromDomainGroupName(site.domain);
316
323
 
317
324
  return site;
318
325
  });
@@ -329,30 +336,76 @@ const ensureCorsForWebWallet = async (sites) => {
329
336
  return sites;
330
337
  };
331
338
 
332
- const filterSitesForRemovedBlocklets = async (sites = []) => {
333
- const blocklets = await states.blocklet.getBlocklets();
339
+ const filterSitesForRemovedBlocklets = async (sites = [], blocklets) => {
334
340
  return sites.filter((site) => {
335
341
  if (!site.domain.endsWith(BLOCKLET_SITE_GROUP_SUFFIX)) {
336
342
  return true;
337
343
  }
338
344
 
339
- const did = getDidFromDomainGroupName(site.domain);
340
- const blocklet = blocklets.find((x) => x.meta.did === did);
341
- if (blocklet) {
342
- site.mode = blocklet.mode;
343
- }
344
-
345
+ const blocklet = blocklets.find((x) => x.meta.did === site.blockletDid);
345
346
  return !!blocklet;
346
347
  });
347
348
  };
348
349
 
350
+ const ensureBlockletCache = async (sites = [], blocklets) => {
351
+ return sites
352
+ .map((site) => {
353
+ if (!site.domain.endsWith(BLOCKLET_SITE_GROUP_SUFFIX)) {
354
+ return site;
355
+ }
356
+
357
+ if (site.cacheableGenerated) {
358
+ return site;
359
+ }
360
+
361
+ // For each rule, get component, check cacheable, clone and push new rule
362
+ const blocklet = blocklets.find((x) => x.meta.did === site.blockletDid);
363
+ const cacheRules = [];
364
+ site.rules
365
+ .filter(
366
+ (x) =>
367
+ x.to.type === ROUTING_RULE_TYPES.BLOCKLET &&
368
+ x.to.interfaceName === BLOCKLET_INTERFACE_PUBLIC &&
369
+ x.from.pathPrefix.startsWith(WELLKNOWN_SERVICE_PATH_PREFIX) === false
370
+ )
371
+ .forEach((rule) => {
372
+ const component = findComponentById(blocklet, rule.to.componentId);
373
+ if (component.mode !== BLOCKLET_MODES.PRODUCTION) {
374
+ return;
375
+ }
376
+ const cacheable = get(findWebInterface(component), 'cacheable', []);
377
+ cacheable.forEach((cachePrefix) => {
378
+ const clone = cloneDeep(rule);
379
+ clone.from.pathPrefix = joinUrl(rule.from.pathPrefix, cachePrefix);
380
+ clone.to.cacheGroup = 'blockletProxy';
381
+ clone.to.target = cachePrefix;
382
+ clone.dynamic = true; // mark as dynamic to avoid redundant generated rules
383
+ cacheRules.push(clone);
384
+ });
385
+ });
386
+
387
+ site.rules = site.rules.concat(cacheRules);
388
+ site.mode = blocklet.mode;
389
+ site.cacheableGenerated = true;
390
+
391
+ return site;
392
+ })
393
+ .filter(Boolean);
394
+ };
395
+
349
396
  const ensureLatestInfo = async (sites = [], { withDefaultCors = true } = {}) => {
397
+ const blocklets = await states.blocklet.getBlocklets();
398
+
399
+ // CAUTION: following steps are very important, please do not change the order
350
400
  let result = await ensureLatestNodeInfo(sites, { withDefaultCors });
351
401
  result = await ensureBlockletDid(result);
402
+ result = await filterSitesForRemovedBlocklets(sites, blocklets);
403
+ result = await ensureBlockletCache(result, blocklets);
352
404
  result = await ensureWellknownRule(result);
353
405
  result = await ensureCorsForWebWallet(result);
406
+ result = await ensureLatestInterfaceInfo(result);
354
407
 
355
- return ensureLatestInterfaceInfo(result);
408
+ return result;
356
409
  };
357
410
 
358
411
  const decompressCertificates = async (source, dest) => {
@@ -1064,7 +1117,6 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1064
1117
  try {
1065
1118
  const info = await nodeState.read();
1066
1119
  let { sites } = await readRoutingSites();
1067
- sites = await filterSitesForRemovedBlocklets(sites);
1068
1120
  sites = await ensureLatestInfo(sites);
1069
1121
  sites = await ensureServiceRule(sites);
1070
1122
  sites = await ensureRootRule(sites);
@@ -192,6 +192,10 @@ Router.formatSites = (sites = []) => {
192
192
  return;
193
193
  }
194
194
 
195
+ if (rule.dynamic) {
196
+ return;
197
+ }
198
+
195
199
  if (daemonRule) {
196
200
  // Serve meta js: both prefix and suffix do not contain trailing slash
197
201
  // NOTICE: 这里隐含了一个约定
@@ -92,7 +92,7 @@ class BlockletState extends BaseState {
92
92
  this.defaultPort = config.blockletPort || 5555;
93
93
  }
94
94
 
95
- getBlocklet(did) {
95
+ getBlocklet(did, { decryptSk = true } = {}) {
96
96
  return new Promise((resolve, reject) => {
97
97
  if (!did) {
98
98
  resolve(null);
@@ -103,7 +103,7 @@ class BlockletState extends BaseState {
103
103
  return reject(err);
104
104
  }
105
105
 
106
- return resolve(doc ? formatBlocklet(doc, 'onRead', this.config.dek) : null);
106
+ return resolve(doc ? formatBlocklet(doc, 'onRead', decryptSk ? this.config.dek : null) : null);
107
107
  });
108
108
  });
109
109
  }
@@ -931,7 +931,7 @@ const verifyIntegrity = async ({ file, integrity: expected }) => {
931
931
 
932
932
  /**
933
933
  * @param {string} installDir
934
- * @returns {Array<{ key: <[scope/]name/version>, dir: appDir }>}
934
+ * @returns {Promise<Array<{ key: string, dir: string }>>} key is <[scope/]name/version>, dir is appDir
935
935
  */
936
936
  const getAppDirs = async (installDir) => {
937
937
  const appDirs = [];