@abtnode/core 1.8.66 → 1.8.67-beta-f8b4c9ec

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.
@@ -15,20 +15,18 @@ const { isNFTExpired, getNftExpirationDate } = require('@abtnode/util/lib/nft');
15
15
  const didDocument = require('@abtnode/util/lib/did-document');
16
16
  const { sign } = require('@arcblock/jwt');
17
17
  const { isValid: isValidDid } = require('@arcblock/did');
18
- const { verifyPresentation } = require('@arcblock/vc');
19
18
  const { toSvg: createDidLogo } =
20
19
  process.env.NODE_ENV !== 'test' ? require('@arcblock/did-motif') : require('@arcblock/did-motif/dist/did-motif.cjs');
21
20
  const getBlockletInfo = require('@blocklet/meta/lib/info');
22
21
  const sleep = require('@abtnode/util/lib/sleep');
23
22
 
24
23
  const logger = require('@abtnode/logger')('@abtnode/core:blocklet:manager');
25
- const { getVcFromPresentation } = require('@abtnode/util/lib/vc');
26
24
  const {
27
- VC_TYPE_BLOCKLET_PURCHASE,
28
25
  WHO_CAN_ACCESS,
29
26
  SERVER_ROLES,
30
27
  WHO_CAN_ACCESS_PREFIX_ROLES,
31
28
  BLOCKLET_INSTALL_TYPE,
29
+ NODE_MODES,
32
30
  } = require('@abtnode/constant');
33
31
 
34
32
  const getBlockletEngine = require('@blocklet/meta/lib/engine');
@@ -49,7 +47,7 @@ const getComponentProcessId = require('@blocklet/meta/lib/get-component-process-
49
47
  const toBlockletDid = require('@blocklet/meta/lib/did');
50
48
  const { validateMeta } = require('@blocklet/meta/lib/validate');
51
49
  const { update: updateMetaFile } = require('@blocklet/meta/lib/file');
52
- const { titleSchema, mountPointSchema, environmentNameSchema } = require('@blocklet/meta/lib/schema');
50
+ const { titleSchema, updateMountPointSchema, environmentNameSchema } = require('@blocklet/meta/lib/schema');
53
51
  const hasReservedKey = require('@blocklet/meta/lib/has-reserved-key');
54
52
  const Lock = require('@abtnode/util/lib/lock');
55
53
 
@@ -111,6 +109,8 @@ const {
111
109
  validateAppConfig,
112
110
  checkDuplicateAppSk,
113
111
  checkDuplicateMountPoint,
112
+ validateStore,
113
+ validateInServerless,
114
114
  } = require('../../util/blocklet');
115
115
  const StoreUtil = require('../../util/store');
116
116
  const states = require('../../states');
@@ -242,6 +242,8 @@ class BlockletManager extends BaseBlockletManager {
242
242
  * did: string;
243
243
  * title: string;
244
244
  * description: string;
245
+ * storeUrl: string;
246
+ * appSk: string;
245
247
  * sync: boolean = false; // download synchronously, not use queue
246
248
  * delay: number; // push download task to queue after a delay
247
249
  * downloadTokenList: Array<{did: string, token: string}>;
@@ -278,28 +280,31 @@ class BlockletManager extends BaseBlockletManager {
278
280
  context.startImmediately = !!params.startImmediately;
279
281
  }
280
282
 
283
+ const { appSk } = params;
284
+
281
285
  if (type === BLOCKLET_INSTALL_TYPE.URL) {
282
286
  const { url, controller, sync, delay } = params;
283
- return this._installFromUrl({ url, controller, sync, delay }, context);
287
+ return this._installFromUrl({ url, controller, sync, delay, appSk }, context);
284
288
  }
285
289
 
286
290
  if (type === BLOCKLET_INSTALL_TYPE.UPLOAD) {
287
291
  const { file, did, diffVersion, deleteSet } = params;
288
- return this._installFromUpload({ file, did, diffVersion, deleteSet, context });
292
+ return this._installFromUpload({ file, did, diffVersion, deleteSet, appSk }, context);
289
293
  }
290
294
 
291
295
  if (type === BLOCKLET_INSTALL_TYPE.STORE) {
292
296
  const { did, controller, sync, delay, storeUrl } = params;
293
- return this._installFromStore({ did, controller, sync, delay, storeUrl }, context);
297
+ return this._installFromStore({ did, controller, sync, delay, storeUrl, appSk }, context);
294
298
  }
295
299
 
296
300
  if (type === BLOCKLET_INSTALL_TYPE.CREATE) {
297
- return this._installFromCreate({ title: params.title, description: params.description }, context);
301
+ const { title, description } = params;
302
+ return this._installFromCreate({ title, description, appSk }, context);
298
303
  }
299
304
 
300
305
  if (type === BLOCKLET_INSTALL_TYPE.RESTORE) {
301
- const { url, blockletSecretKey } = params;
302
- return this._installFromBackup({ url, blockletSecretKey }, context);
306
+ const { url } = params;
307
+ return this._installFromBackup({ url, appSk }, context);
303
308
  }
304
309
 
305
310
  // should not be here
@@ -343,10 +348,16 @@ class BlockletManager extends BaseBlockletManager {
343
348
  },
344
349
  context = {}
345
350
  ) {
346
- const mountPoint = await mountPointSchema.validateAsync(tmpMountPoint);
351
+ const mountPoint = await updateMountPointSchema.validateAsync(tmpMountPoint);
347
352
  logger.debug('start install component', { rootDid, mountPoint, url });
348
353
 
349
354
  if (file) {
355
+ // TODO: 如何触发这种场景?
356
+ const info = await states.node.read();
357
+ if (info.mode === NODE_MODES.SERVERLESS) {
358
+ throw new Error("Can't install component in serverless-mode server via upload");
359
+ }
360
+
350
361
  return this._installComponentFromUpload({
351
362
  rootDid,
352
363
  mountPoint,
@@ -360,6 +371,11 @@ class BlockletManager extends BaseBlockletManager {
360
371
  }
361
372
 
362
373
  if (url) {
374
+ const info = await states.node.read();
375
+ if (info.mode === NODE_MODES.SERVERLESS) {
376
+ validateStore(info, url);
377
+ }
378
+
363
379
  return this._installComponentFromUrl({
364
380
  rootDid,
365
381
  mountPoint,
@@ -431,25 +447,6 @@ class BlockletManager extends BaseBlockletManager {
431
447
  return { isInstalled: !!blocklet, isRunning, blockletDid, isExternal };
432
448
  }
433
449
 
434
- async installBlockletFromVc({ vcPresentation, challenge }, context) {
435
- logger.info('Install from vc');
436
- const vc = getVcFromPresentation(vcPresentation);
437
-
438
- // FIXME: 这里的 trustedIssuers 相当于相信任何 VC,需要想更安全的方法
439
- verifyPresentation({ presentation: vcPresentation, trustedIssuers: [get(vc, 'issuer.id')], challenge });
440
-
441
- if (!vc.type.includes(VC_TYPE_BLOCKLET_PURCHASE)) {
442
- throw new Error(`Expect ${VC_TYPE_BLOCKLET_PURCHASE} VC type`);
443
- }
444
-
445
- const blockletUrl = get(vc, 'credentialSubject.purchased.blocklet.url');
446
- const urlObject = new URL(blockletUrl);
447
- const did = get(vc, 'credentialSubject.purchased.blocklet.id');
448
- const registry = urlObject.origin;
449
-
450
- return this._installFromStore({ did, registry }, context);
451
- }
452
-
453
450
  async start({ did, throwOnError, checkHealthImmediately = false, e2eMode = false }, context) {
454
451
  logger.info('start blocklet', { did });
455
452
  // should check blocklet integrity
@@ -631,7 +628,7 @@ class BlockletManager extends BaseBlockletManager {
631
628
  // FIXME: 需要改成队列执行,本次失败,下次还需要重试,页面刷新后也能知道最新的状态
632
629
  await this._installFromBackup({
633
630
  url: `file://${spacesRestore.blockletRestoreDir}`,
634
- blockletSecretKey: spacesRestore.blockletWallet.secretKey,
631
+ appSk: spacesRestore.blockletWallet.secretKey,
635
632
  moveDir: true,
636
633
  });
637
634
  }
@@ -1004,7 +1001,7 @@ class BlockletManager extends BaseBlockletManager {
1004
1001
  }
1005
1002
 
1006
1003
  // eslint-disable-next-line no-unused-vars
1007
- async config({ did, configs: newConfigs, skipHook }, context) {
1004
+ async config({ did, configs: newConfigs, skipHook, skipDidDocument }, context) {
1008
1005
  if (!Array.isArray(newConfigs)) {
1009
1006
  throw new Error('configs list is not an array');
1010
1007
  }
@@ -1064,7 +1061,7 @@ class BlockletManager extends BaseBlockletManager {
1064
1061
  [BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK, BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_WALLET_TYPE].includes(item.key)
1065
1062
  );
1066
1063
 
1067
- if (isSkOrWalletTypeChanged) {
1064
+ if (isSkOrWalletTypeChanged && !skipDidDocument) {
1068
1065
  await this._updateDidDocument(blocklet);
1069
1066
  }
1070
1067
 
@@ -1198,7 +1195,7 @@ class BlockletManager extends BaseBlockletManager {
1198
1195
  }
1199
1196
 
1200
1197
  async updateComponentMountPoint({ did, rootDid: inputRootDid, mountPoint: tmpMountPoint }, context) {
1201
- const mountPoint = await mountPointSchema.validateAsync(tmpMountPoint);
1198
+ const mountPoint = await updateMountPointSchema.validateAsync(tmpMountPoint);
1202
1199
 
1203
1200
  const blocklet = await states.blocklet.getBlocklet(inputRootDid);
1204
1201
 
@@ -1679,13 +1676,13 @@ class BlockletManager extends BaseBlockletManager {
1679
1676
  * /blocklet.json
1680
1677
  * /blocklet_extras.json
1681
1678
  * @see Blocklet 端到端备份方案的设计与实现(一期) https://team.arcblock.io/comment/discussions/e62084d5-fafa-489e-91d5-defcd6e93223
1682
- * @param {{ url: string, blockletSecretKey: string, moveDir: boolean}} [{ url }={}]
1679
+ * @param {{ url: string, appSk: string, moveDir: boolean}} [{ url }={}]
1683
1680
  * @param {Record<string, string>} [context={}]
1684
1681
  * @return {Promise<any>}
1685
1682
  * @memberof BlockletManager
1686
1683
  */
1687
- async _installFromBackup({ url, blockletSecretKey, moveDir } = {}, context = {}) {
1688
- return installFromBackup({ url, blockletSecretKey, moveDir, context, manager: this, states });
1684
+ async _installFromBackup({ url, appSk, moveDir } = {}, context = {}) {
1685
+ return installFromBackup({ url, appSk, moveDir, context, manager: this, states });
1689
1686
  }
1690
1687
 
1691
1688
  async ensureBlocklet(did, opts = {}) {
@@ -2084,17 +2081,18 @@ class BlockletManager extends BaseBlockletManager {
2084
2081
  *
2085
2082
  * @param {{
2086
2083
  * did: string;
2087
- * registry: string;
2088
2084
  * sync: boolean;
2089
2085
  * delay: number;
2090
2086
  * controller: Controller;
2087
+ * appSk: string;
2088
+ * storeUrl: string;
2091
2089
  * }} params
2092
2090
  * @param {*} context
2093
2091
  * @return {*}
2094
2092
  * @memberof BlockletManager
2095
2093
  */
2096
2094
  async _installFromStore(params, context) {
2097
- const { did, storeUrl, sync, delay, controller } = params;
2095
+ const { did, storeUrl, sync, delay, controller, appSk } = params;
2098
2096
 
2099
2097
  logger.debug('start install blocklet', { did });
2100
2098
  if (!isValidDid(did)) {
@@ -2138,6 +2136,7 @@ class BlockletManager extends BaseBlockletManager {
2138
2136
  sync,
2139
2137
  delay,
2140
2138
  controller,
2139
+ appSk,
2141
2140
  context,
2142
2141
  });
2143
2142
  }
@@ -2154,13 +2153,14 @@ class BlockletManager extends BaseBlockletManager {
2154
2153
  * sync: boolean;
2155
2154
  * delay: number;
2156
2155
  * controller: Controller;
2156
+ * appSk: string;
2157
2157
  * }} params
2158
2158
  * @param {{}} context
2159
2159
  * @return {*}
2160
2160
  * @memberof BlockletManager
2161
2161
  */
2162
2162
  async _installFromUrl(params, context) {
2163
- const { url, sync, delay, controller } = params;
2163
+ const { url, sync, delay, controller, appSk } = params;
2164
2164
 
2165
2165
  logger.debug('start install blocklet', { url });
2166
2166
 
@@ -2174,13 +2174,18 @@ class BlockletManager extends BaseBlockletManager {
2174
2174
 
2175
2175
  // install from store if url is a store url
2176
2176
  const { inStore, registryUrl, blockletDid: bundleDid } = await StoreUtil.parseSourceUrl(url, controller);
2177
+
2178
+ const nodeInfo = await states.node.read();
2179
+
2180
+ await validateStore(nodeInfo, registryUrl);
2181
+
2177
2182
  if (inStore) {
2178
2183
  const exist = await states.blocklet.getBlocklet(blockletDid);
2179
2184
  if (exist) {
2180
2185
  return this.upgrade({ did: blockletDid, storeUrl: registryUrl, sync, delay }, context);
2181
2186
  }
2182
2187
 
2183
- return this._installFromStore({ did: bundleDid, storeUrl: registryUrl, controller, sync, delay }, context);
2188
+ return this._installFromStore({ did: bundleDid, storeUrl: registryUrl, controller, sync, delay, appSk }, context);
2184
2189
  }
2185
2190
 
2186
2191
  const meta = ensureMeta(bundleMeta, { name: blockletName, did: blockletDid });
@@ -2206,6 +2211,7 @@ class BlockletManager extends BaseBlockletManager {
2206
2211
  sync,
2207
2212
  delay,
2208
2213
  controller,
2214
+ appSk,
2209
2215
  context,
2210
2216
  });
2211
2217
  }
@@ -2310,7 +2316,7 @@ class BlockletManager extends BaseBlockletManager {
2310
2316
  );
2311
2317
  }
2312
2318
 
2313
- async _installFromCreate({ title, description }, context = {}) {
2319
+ async _installFromCreate({ title, description, appSk }, context = {}) {
2314
2320
  logger.debug('create blocklet', { title, description });
2315
2321
 
2316
2322
  await joi.string().label('title').max(20).required().validateAsync(title);
@@ -2338,11 +2344,9 @@ class BlockletManager extends BaseBlockletManager {
2338
2344
  };
2339
2345
  const meta = validateMeta(rawMeta);
2340
2346
 
2341
- await states.blocklet.addBlocklet({
2342
- meta,
2343
- source: BlockletSource.custom,
2344
- });
2347
+ await states.blocklet.addBlocklet({ meta, source: BlockletSource.custom });
2345
2348
  await this._setConfigsFromMeta(did);
2349
+ await this._setAppSk(did, appSk);
2346
2350
 
2347
2351
  // check duplicate appSk
2348
2352
  await checkDuplicateAppSk({ did, states });
@@ -2382,7 +2386,7 @@ class BlockletManager extends BaseBlockletManager {
2382
2386
  return { cwd, tarFile };
2383
2387
  }
2384
2388
 
2385
- async _installFromUpload({ file, did, diffVersion, deleteSet, context }) {
2389
+ async _installFromUpload({ file, did, diffVersion, deleteSet, appSk }, context) {
2386
2390
  logger.info('install blocklet', { from: 'upload file' });
2387
2391
  const { tarFile } = await this._downloadFromUpload(file);
2388
2392
 
@@ -2480,6 +2484,7 @@ class BlockletManager extends BaseBlockletManager {
2480
2484
  const oldState = { extraState: oldExtraState };
2481
2485
  try {
2482
2486
  await this._setConfigsFromMeta(meta.did);
2487
+ await this._setAppSk(appSk);
2483
2488
  await validateBlocklet(blocklet);
2484
2489
 
2485
2490
  // check duplicate appSk
@@ -2776,6 +2781,7 @@ class BlockletManager extends BaseBlockletManager {
2776
2781
  * meta: {}; // blocklet meta
2777
2782
  * source: number; // example: BlockletSource.registry,
2778
2783
  * deployedFrom: string;
2784
+ * appSk: string;
2779
2785
  * context: {}
2780
2786
  * sync: boolean = false;
2781
2787
  * delay: number;
@@ -2785,10 +2791,15 @@ class BlockletManager extends BaseBlockletManager {
2785
2791
  * @memberof BlockletManager
2786
2792
  */
2787
2793
  async _install(params) {
2788
- const { meta, source, deployedFrom, context, sync, delay, controller } = params;
2794
+ const { meta, source, deployedFrom, context, sync, delay, controller, appSk } = params;
2789
2795
 
2790
2796
  validateBlockletMeta(meta, { ensureDist: true });
2791
2797
 
2798
+ const info = await states.node.read();
2799
+ if (info.mode === NODE_MODES.SERVERLESS) {
2800
+ validateInServerless({ blockletMeta: meta });
2801
+ }
2802
+
2792
2803
  const { name, did, version } = meta;
2793
2804
 
2794
2805
  const oldExtraState = await states.blockletExtras.findOne({ did: meta.did });
@@ -2808,6 +2819,7 @@ class BlockletManager extends BaseBlockletManager {
2808
2819
  await states.blockletExtras.addMeta({ did, meta: { did, name }, controller });
2809
2820
 
2810
2821
  await this._setConfigsFromMeta(did);
2822
+ await this._setAppSk(did, appSk);
2811
2823
 
2812
2824
  // check duplicate appSk
2813
2825
  await checkDuplicateAppSk({ did, states });
@@ -3405,12 +3417,31 @@ class BlockletManager extends BaseBlockletManager {
3405
3417
  }
3406
3418
  }
3407
3419
 
3420
+ async _setAppSk(did, appSk, context) {
3421
+ if (process.env.NODE_ENV === 'production' && !appSk) {
3422
+ throw new Error(`appSk for blocklet ${did} is required`);
3423
+ }
3424
+
3425
+ if (appSk) {
3426
+ await this.config(
3427
+ {
3428
+ did,
3429
+ configs: [{ key: 'BLOCKLET_APP_SK', value: appSk, secure: true }],
3430
+ skipHook: true,
3431
+ skipDidDocument: true,
3432
+ },
3433
+ context
3434
+ );
3435
+ }
3436
+ }
3437
+
3408
3438
  async _findNextCustomBlockletName(leftTimes = 10) {
3409
3439
  if (leftTimes <= 0) {
3410
3440
  throw new Error('Generate custom blocklet did too many times');
3411
3441
  }
3412
3442
  const number = await states.node.increaseCustomBlockletNumber();
3413
3443
  const name = `custom-${number}`;
3444
+ // MEMO: 空壳 APP可以保留原有的 did 生成逻辑
3414
3445
  const did = toBlockletDid(name);
3415
3446
  const blocklet = await states.blocklet.getBlocklet(did);
3416
3447
  if (blocklet) {
@@ -19,7 +19,7 @@ const { validateBlocklet, checkDuplicateAppSk, getAppDirs } = require('../../../
19
19
  * }} param0
20
20
  * @returns
21
21
  */
22
- module.exports = async ({ url, blockletSecretKey, moveDir, context = {}, states, manager } = {}) => {
22
+ module.exports = async ({ url, appSk, moveDir, context = {}, states, manager } = {}) => {
23
23
  // TODO: support more url schema feature (http, did-spaces)
24
24
  if (!url.startsWith('file://')) {
25
25
  throw new Error('url must starts with file://');
@@ -71,17 +71,17 @@ module.exports = async ({ url, blockletSecretKey, moveDir, context = {}, states,
71
71
  throw new Error('blocklet is already exist');
72
72
  }
73
73
 
74
- if (blockletSecretKey) {
74
+ if (appSk) {
75
75
  extra.configs = extra.configs || [];
76
76
  const skConfig = extra.configs.find((x) => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK);
77
77
  if (skConfig) {
78
- skConfig.value = blockletSecretKey;
78
+ skConfig.value = appSk;
79
79
  skConfig.secure = true;
80
80
  skConfig.shared = false;
81
81
  } else {
82
82
  extra.configs.push({
83
83
  key: BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK,
84
- value: blockletSecretKey,
84
+ value: appSk,
85
85
  secure: true,
86
86
  shared: false,
87
87
  });
@@ -150,10 +150,10 @@ class SpacesBackup {
150
150
  const { errorCount } = await spaceClient.send(
151
151
  new SyncFolderPushCommand({
152
152
  source: join(this.blockletBackupDir, '/'),
153
- target: join('.did-objects', this.blocklet.appDid),
153
+ target: join('.did-objects', this.blocklet.appDid, '/'),
154
154
  debug: true,
155
- concurrency: 64,
156
- retryCount: 100,
155
+ concurrency: 32,
156
+ retryCount: 10,
157
157
  filter: (object) => {
158
158
  return object.name !== '.DS_Store';
159
159
  },
@@ -1,4 +1,4 @@
1
- const { existsSync, remove } = require('fs-extra');
1
+ const { existsSync, remove, ensureDirSync } = require('fs-extra');
2
2
  const { join } = require('path');
3
3
  const fg = require('fast-glob');
4
4
  const { BaseRestore } = require('./base');
@@ -10,8 +10,11 @@ class BlockletsRestore extends BaseRestore {
10
10
  async import() {
11
11
  const blockletsDir = join(this.blockletRestoreDir, this.filename);
12
12
 
13
+ // blockletsDir 可以不存在, 因为还原的 blocklet 可能所有的组件都是来自 store 的
13
14
  if (!existsSync(blockletsDir)) {
14
- throw new Error(`dir not found: ${blockletsDir}`);
15
+ // FIXME: 如果文件夹不存在,需要创建文件夹,因为 installFromBackup 未做容错处理
16
+ ensureDirSync(blockletsDir);
17
+ return;
15
18
  }
16
19
 
17
20
  const paths = await fg('**/*.zip', {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @typedef {{
3
3
  * endpoint: string;
4
- * blockletSecretKey: string;
4
+ * appSk: string;
5
5
  * }} SpaceRestoreInput
6
6
  */
7
7
 
@@ -98,7 +98,7 @@ class SpacesRestore {
98
98
 
99
99
  async getBlockletWallet() {
100
100
  // @FIXME: blocklet 钱包类型如何得知呢?
101
- const wallet = fromSecretKey(this.input.blockletSecretKey, WalletType({ role: types.RoleType.ROLE_APPLICATION }));
101
+ const wallet = fromSecretKey(this.input.appSk, WalletType({ role: types.RoleType.ROLE_APPLICATION }));
102
102
 
103
103
  return wallet;
104
104
  }
@@ -115,10 +115,10 @@ class SpacesRestore {
115
115
  const { errorCount } = await spaceClient.send(
116
116
  new SyncFolderPullCommand({
117
117
  source: join('.did-objects', this.blockletWallet.address, '/'),
118
- target: this.blockletRestoreDir,
118
+ target: join(this.blockletRestoreDir, '/'),
119
119
  debug: true,
120
- concurrency: 64,
121
- retryCount: 100,
120
+ concurrency: 32,
121
+ retryCount: 10,
122
122
  })
123
123
  );
124
124
 
package/lib/event.js CHANGED
@@ -81,7 +81,7 @@ module.exports = ({
81
81
  }
82
82
  };
83
83
 
84
- const handleBlockletAdd = async (name, { blocklet, context }) => {
84
+ const handleBlockletInstall = async (name, { blocklet, context }) => {
85
85
  try {
86
86
  const changed = await ensureBlockletRouting(blocklet, context);
87
87
  if (changed) {
@@ -173,7 +173,7 @@ module.exports = ({
173
173
  const blocklet = payload.blocklet || payload;
174
174
 
175
175
  if ([BlockletEvents.installed].includes(eventName)) {
176
- await handleBlockletAdd(eventName, payload);
176
+ await handleBlockletInstall(eventName, payload);
177
177
 
178
178
  try {
179
179
  await node.createAuditLog({
package/lib/index.js CHANGED
@@ -192,7 +192,6 @@ function ABTNode(options) {
192
192
 
193
193
  // Blocklet manager
194
194
  installBlocklet: blockletManager.install.bind(blockletManager),
195
- installBlockletFromVc: blockletManager.installBlockletFromVc.bind(blockletManager),
196
195
  installComponent: blockletManager.installComponent.bind(blockletManager),
197
196
  startBlocklet: blockletManager.start.bind(blockletManager),
198
197
  stopBlocklet: blockletManager.stop.bind(blockletManager),
@@ -518,7 +518,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
518
518
 
519
519
  const ensureDomainCert = async (domain, url) => {
520
520
  const cert = await certManager.getByDomain(domain);
521
- if (!cert) {
521
+ if (!cert || get(cert, 'meta.validTo') <= Date.now()) {
522
522
  await downloadCert({
523
523
  domain,
524
524
  url,
@@ -183,6 +183,10 @@ Router.formatSites = (sites = []) => {
183
183
  result.forEach((site) => {
184
184
  if (Array.isArray(site.rules) && site.rules.length > 0) {
185
185
  const rules = cloneDeep(site.rules);
186
+
187
+ let hasRootPathBlockletRule = false;
188
+ let tmpBlockletRule;
189
+
186
190
  rules.forEach((rule) => {
187
191
  if ([ROUTING_RULE_TYPES.BLOCKLET].includes(rule.to.type) === false) {
188
192
  return;
@@ -197,6 +201,11 @@ Router.formatSites = (sites = []) => {
197
201
  }
198
202
 
199
203
  if (daemonRule) {
204
+ if (rule.from.pathPrefix === '/') {
205
+ hasRootPathBlockletRule = true;
206
+ }
207
+ tmpBlockletRule = rule;
208
+
200
209
  // Serve meta js: both prefix and suffix do not contain trailing slash
201
210
  // NOTICE: 这里隐含了一个约定
202
211
  // 如果安装的 blockletA 和 blockletB 都需要 __blocklet__.js
@@ -244,6 +253,24 @@ Router.formatSites = (sites = []) => {
244
253
  });
245
254
  }
246
255
  });
256
+
257
+ // ensure /__blocklet__.js should be proxy to daemon
258
+ if (daemonRule && !hasRootPathBlockletRule && tmpBlockletRule) {
259
+ site.rules.push({
260
+ from: {
261
+ pathPrefix: '/',
262
+ groupPathPrefix: '/',
263
+ pathSuffix: '/__blocklet__.js',
264
+ },
265
+ to: {
266
+ type: ROUTING_RULE_TYPES.DAEMON,
267
+ port: daemonRule.to.port,
268
+ did: tmpBlockletRule.to.did,
269
+ componentId: tmpBlockletRule.to.did,
270
+ cacheGroup: site.mode === BLOCKLET_MODES.PRODUCTION ? 'blockletJs' : '',
271
+ },
272
+ });
273
+ }
247
274
  }
248
275
  });
249
276
 
@@ -124,7 +124,7 @@ class NodeState extends BaseState {
124
124
  routing,
125
125
  docker,
126
126
  mode,
127
- enableWelcomePage: true,
127
+ enableWelcomePage: mode !== NODE_MODES.SERVERLESS,
128
128
  runtimeConfig,
129
129
  ownerNft,
130
130
  diskAlertThreshold: DISK_ALERT_THRESHOLD_PERCENT,
@@ -31,7 +31,12 @@ const getFolderSize = require('@abtnode/util/lib/get-folder-size');
31
31
  const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
32
32
  const hashFiles = require('@abtnode/util/lib/hash-files');
33
33
  const isPathPrefixEqual = require('@abtnode/util/lib/is-path-prefix-equal');
34
- const { BLOCKLET_MAX_MEM_LIMIT_IN_MB, BLOCKLET_STORE, BLOCKLET_INSTALL_TYPE } = require('@abtnode/constant');
34
+ const {
35
+ BLOCKLET_MAX_MEM_LIMIT_IN_MB,
36
+ BLOCKLET_STORE,
37
+ BLOCKLET_INSTALL_TYPE,
38
+ BLOCKLET_STORE_DEV,
39
+ } = require('@abtnode/constant');
35
40
  const formatBackSlash = require('@abtnode/util/lib/format-back-slash');
36
41
 
37
42
  const SCRIPT_ENGINES_WHITE_LIST = ['npm', 'npx', 'pnpm', 'yarn'];
@@ -835,7 +840,7 @@ const parseChildrenFromMeta = async (src, context = {}) => {
835
840
  };
836
841
 
837
842
  const validateBlocklet = (blocklet) =>
838
- forEachBlocklet(blocklet, (b) => {
843
+ forEachBlocklet(blocklet, async (b) => {
839
844
  isRequirementsSatisfied(b.meta.requirements);
840
845
  validateEngine(getBlockletEngineNameByPlatform(b.meta));
841
846
  });
@@ -1400,12 +1405,14 @@ const getBlocklet = async ({
1400
1405
 
1401
1406
  blocklet.settings.storeList = blocklet.settings.storeList || [];
1402
1407
 
1403
- if (!blocklet.settings.storeList.find((x) => x.url === BLOCKLET_STORE.url)) {
1404
- blocklet.settings.storeList.unshift({
1405
- ...BLOCKLET_STORE,
1406
- protected: true,
1407
- });
1408
- }
1408
+ [BLOCKLET_STORE_DEV, BLOCKLET_STORE].forEach((store) => {
1409
+ if (!blocklet.settings.storeList.find((x) => x.url === store.url)) {
1410
+ blocklet.settings.storeList.unshift({
1411
+ ...store,
1412
+ protected: true,
1413
+ });
1414
+ }
1415
+ });
1409
1416
 
1410
1417
  // app site
1411
1418
  blocklet.site = await states.site.findOneByBlocklet(blocklet.meta.did);
@@ -1690,6 +1697,32 @@ const checkDuplicateMountPoint = (blocklet, mountPoint) => {
1690
1697
  }
1691
1698
  };
1692
1699
 
1700
+ const validateStore = (nodeInfo, storeUrl) => {
1701
+ if (nodeInfo.mode !== 'serverless') {
1702
+ return;
1703
+ }
1704
+
1705
+ const inStoreList = nodeInfo.blockletRegistryList.find((item) => {
1706
+ const itemURLObj = new URL(item.url);
1707
+ const storeUrlObj = new URL(storeUrl);
1708
+
1709
+ return itemURLObj.host === storeUrlObj.host;
1710
+ });
1711
+
1712
+ if (!inStoreList) {
1713
+ throw new Error('Must be installed from the compliant blocklet store list');
1714
+ }
1715
+ };
1716
+
1717
+ const validateInServerless = ({ blockletMeta }) => {
1718
+ const { interfaces } = blockletMeta;
1719
+ const externalPortInterfaces = (interfaces || []).filter((item) => !!item.port?.external);
1720
+
1721
+ if (externalPortInterfaces.length > 0) {
1722
+ throw new Error('Blocklets with exposed ports cannot be installed');
1723
+ }
1724
+ };
1725
+
1693
1726
  module.exports = {
1694
1727
  consumeServerlessNFT,
1695
1728
  forEachBlocklet,
@@ -1737,4 +1770,6 @@ module.exports = {
1737
1770
  validateAppConfig,
1738
1771
  checkDuplicateAppSk,
1739
1772
  checkDuplicateMountPoint,
1773
+ validateStore,
1774
+ validateInServerless,
1740
1775
  };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.8.66",
6
+ "version": "1.8.67-beta-f8b4c9ec",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,33 +19,33 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "@abtnode/auth": "1.8.66",
23
- "@abtnode/certificate-manager": "1.8.66",
24
- "@abtnode/constant": "1.8.66",
25
- "@abtnode/cron": "1.8.66",
26
- "@abtnode/db": "1.8.66",
27
- "@abtnode/logger": "1.8.66",
28
- "@abtnode/queue": "1.8.66",
29
- "@abtnode/rbac": "1.8.66",
30
- "@abtnode/router-provider": "1.8.66",
31
- "@abtnode/static-server": "1.8.66",
32
- "@abtnode/timemachine": "1.8.66",
33
- "@abtnode/util": "1.8.66",
34
- "@arcblock/did": "1.18.42",
22
+ "@abtnode/auth": "1.8.67-beta-f8b4c9ec",
23
+ "@abtnode/certificate-manager": "1.8.67-beta-f8b4c9ec",
24
+ "@abtnode/constant": "1.8.67-beta-f8b4c9ec",
25
+ "@abtnode/cron": "1.8.67-beta-f8b4c9ec",
26
+ "@abtnode/db": "1.8.67-beta-f8b4c9ec",
27
+ "@abtnode/logger": "1.8.67-beta-f8b4c9ec",
28
+ "@abtnode/queue": "1.8.67-beta-f8b4c9ec",
29
+ "@abtnode/rbac": "1.8.67-beta-f8b4c9ec",
30
+ "@abtnode/router-provider": "1.8.67-beta-f8b4c9ec",
31
+ "@abtnode/static-server": "1.8.67-beta-f8b4c9ec",
32
+ "@abtnode/timemachine": "1.8.67-beta-f8b4c9ec",
33
+ "@abtnode/util": "1.8.67-beta-f8b4c9ec",
34
+ "@arcblock/did": "1.18.54",
35
35
  "@arcblock/did-motif": "^1.1.10",
36
- "@arcblock/did-util": "1.18.42",
37
- "@arcblock/event-hub": "1.18.42",
38
- "@arcblock/jwt": "^1.18.42",
36
+ "@arcblock/did-util": "1.18.54",
37
+ "@arcblock/event-hub": "1.18.54",
38
+ "@arcblock/jwt": "^1.18.54",
39
39
  "@arcblock/pm2-events": "^0.0.5",
40
- "@arcblock/vc": "1.18.42",
41
- "@blocklet/constant": "1.8.66",
42
- "@blocklet/meta": "1.8.66",
43
- "@blocklet/sdk": "1.8.66",
44
- "@did-space/client": "^0.1.66",
40
+ "@arcblock/vc": "1.18.54",
41
+ "@blocklet/constant": "1.8.67-beta-f8b4c9ec",
42
+ "@blocklet/meta": "1.8.67-beta-f8b4c9ec",
43
+ "@blocklet/sdk": "1.8.67-beta-f8b4c9ec",
44
+ "@did-space/client": "^0.1.76",
45
45
  "@fidm/x509": "^1.2.1",
46
- "@ocap/mcrypto": "1.18.42",
47
- "@ocap/util": "1.18.42",
48
- "@ocap/wallet": "1.18.42",
46
+ "@ocap/mcrypto": "1.18.54",
47
+ "@ocap/util": "1.18.54",
48
+ "@ocap/wallet": "1.18.54",
49
49
  "@slack/webhook": "^5.0.4",
50
50
  "archiver": "^5.3.1",
51
51
  "axios": "^0.27.2",
@@ -72,7 +72,6 @@
72
72
  "pm2": "^5.2.0",
73
73
  "semver": "^7.3.8",
74
74
  "shelljs": "^0.8.5",
75
- "slugify": "^1.6.5",
76
75
  "ssri": "^8.0.1",
77
76
  "stream-throttle": "^0.1.3",
78
77
  "stream-to-promise": "^3.0.0",
@@ -90,5 +89,5 @@
90
89
  "express": "^4.18.2",
91
90
  "jest": "^27.5.1"
92
91
  },
93
- "gitHead": "282247fd0ce6702e1d6920e90e2b3be0408cf879"
92
+ "gitHead": "ebf19fcbc6d99fff0d214dc0680c4df81aa94d6d"
94
93
  }