@abtnode/core 1.8.35 → 1.8.37

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.
package/lib/api/node.js CHANGED
@@ -7,24 +7,14 @@ const isGitpod = require('@abtnode/util/lib/is-gitpod');
7
7
  const getFolderSize = require('@abtnode/util/lib/get-folder-size');
8
8
  const canPackageReadWrite = require('@abtnode/util/lib/can-pkg-rw');
9
9
  const { toDelegateAddress } = require('@arcblock/did-util');
10
- const { STORE_DETAIL_PAGE_PATH_PREFIX } = require('@abtnode/constant');
11
10
 
12
11
  const logger = require('@abtnode/logger')('@abtnode/core:api:node');
13
12
 
14
13
  const IP = require('../util/ip');
15
14
  const { validateNodeInfo, validateUpdateGateway } = require('../validators/node');
16
15
  const { getAll } = require('../blocklet/manager/engine');
17
- const StoreUtil = require('../util/store');
18
16
  const { getDelegateState } = require('../util');
19
17
 
20
- const sanitizeUrl = (url) => {
21
- if (!url) {
22
- throw new Error('Registry URL should not be empty');
23
- }
24
-
25
- return url.trim();
26
- };
27
-
28
18
  class NodeAPI {
29
19
  /**
30
20
  *
@@ -37,69 +27,6 @@ class NodeAPI {
37
27
  this.state = state;
38
28
  }
39
29
 
40
- // eslint-disable-next-line no-unused-vars
41
- async addRegistry({ url }, context) {
42
- logger.info('add registry', { url });
43
-
44
- const urlObj = new URL(url);
45
- let newUrl = urlObj.origin;
46
-
47
- // if the pathname is store blocklet list or blocklet detail
48
- if (urlObj.pathname?.includes(STORE_DETAIL_PAGE_PATH_PREFIX)) {
49
- const lastIndex = urlObj.pathname.lastIndexOf(STORE_DETAIL_PAGE_PATH_PREFIX);
50
- const pathnamePrefix = urlObj.pathname.substring(0, lastIndex);
51
- newUrl = `${newUrl}${pathnamePrefix || ''}`;
52
- }
53
-
54
- const sanitized = sanitizeUrl(newUrl);
55
-
56
- const info = await this.state.read();
57
- const exist = info.blockletRegistryList.find((x) => x.url === sanitized);
58
- if (exist) {
59
- throw new Error(`Blocklet registry already exist: ${sanitized}`);
60
- }
61
-
62
- await StoreUtil.validateRegistryURL(sanitized);
63
-
64
- const newBlockletRegistry = await StoreUtil.getRegistryMeta(sanitized);
65
- const newBlockletRegistryList = info.blockletRegistryList.map((x) => ({ ...x, selected: false }));
66
- newBlockletRegistryList.push({ ...newBlockletRegistry, url: sanitized, selected: true, protected: false });
67
-
68
- return this.state.updateNodeInfo({ blockletRegistryList: newBlockletRegistryList });
69
- }
70
-
71
- // eslint-disable-next-line no-unused-vars
72
- async deleteRegistry({ url }, context) {
73
- logger.info('delete registry', { url });
74
- const sanitized = sanitizeUrl(url);
75
- const info = await this.state.read();
76
- const exist = info.blockletRegistryList.find((x) => x.url === sanitized);
77
- if (!exist) {
78
- throw new Error(`Blocklet registry does not exist: ${sanitized}`);
79
- }
80
-
81
- const blockletRegistryList = info.blockletRegistryList.filter((x) => x.url !== sanitized);
82
- if (!blockletRegistryList.find((x) => x.selected)) {
83
- blockletRegistryList[0].selected = true;
84
- }
85
- return this.state.updateNodeInfo({ blockletRegistryList });
86
- }
87
-
88
- // eslint-disable-next-line no-unused-vars
89
- async selectRegistry({ url }, context) {
90
- logger.info('select registry', { url });
91
- const sanitized = sanitizeUrl(url);
92
- const info = await this.state.read();
93
- const exist = info.blockletRegistryList.find((x) => x.url === sanitized);
94
- if (!exist) {
95
- throw new Error(`Blocklet registry does not exist: ${sanitized}`);
96
- }
97
-
98
- return this.state.updateNodeInfo({
99
- blockletRegistryList: info.blockletRegistryList.map((x) => ({ ...x, selected: x.url === sanitized })),
100
- });
101
- }
102
-
103
30
  async updateNodeInfo(entity = {}, context) {
104
31
  await validateNodeInfo(entity, context);
105
32
 
package/lib/api/team.js CHANGED
@@ -11,6 +11,7 @@ const {
11
11
  PASSPORT_STATUS,
12
12
  WELLKNOWN_SERVICE_PATH_PREFIX,
13
13
  MAX_USER_PAGE_SIZE,
14
+ STORE_DETAIL_PAGE_PATH_PREFIX,
14
15
  } = require('@abtnode/constant');
15
16
  const { isValid: isValidDid } = require('@arcblock/did');
16
17
  const { BlockletEvents } = require('@blocklet/constant');
@@ -30,6 +31,15 @@ const { validateCreateRole, validateUpdateRole } = require('../validators/role')
30
31
  const { validateCreatePermission, validateUpdatePermission } = require('../validators/permission');
31
32
 
32
33
  const { getBlocklet } = require('../util/blocklet');
34
+ const StoreUtil = require('../util/store');
35
+
36
+ const sanitizeUrl = (url) => {
37
+ if (!url) {
38
+ throw new Error('Registry URL should not be empty');
39
+ }
40
+
41
+ return url.trim();
42
+ };
33
43
 
34
44
  const validateReservedRole = (role) => {
35
45
  if (Object.values(ROLES).includes(role)) {
@@ -855,6 +865,55 @@ class TeamAPI extends EventEmitter {
855
865
  );
856
866
  }
857
867
 
868
+ // eslint-disable-next-line no-unused-vars
869
+ async addStore({ teamDid, url }, context) {
870
+ logger.info('add registry', { url });
871
+
872
+ const urlObj = new URL(url);
873
+ let newUrl = urlObj.origin;
874
+
875
+ // if the pathname is store blocklet list or blocklet detail
876
+ if (urlObj.pathname?.includes(STORE_DETAIL_PAGE_PATH_PREFIX)) {
877
+ const lastIndex = urlObj.pathname.lastIndexOf(STORE_DETAIL_PAGE_PATH_PREFIX);
878
+ const pathnamePrefix = urlObj.pathname.substring(0, lastIndex);
879
+ newUrl = `${newUrl}${pathnamePrefix || ''}`;
880
+ }
881
+
882
+ const sanitized = sanitizeUrl(newUrl);
883
+
884
+ const storeList = await this.teamManager.getStoreList(teamDid);
885
+
886
+ const exist = storeList.find((x) => x.url === sanitized);
887
+ if (exist) {
888
+ throw new Error(`Blocklet registry already exist: ${sanitized}`);
889
+ }
890
+
891
+ await StoreUtil.validateRegistryURL(sanitized);
892
+
893
+ const store = await StoreUtil.getRegistryMeta(sanitized);
894
+
895
+ storeList.push({ ...store, url: sanitized, protected: false });
896
+
897
+ return this.teamManager.updateStoreList(teamDid, storeList);
898
+ }
899
+
900
+ // eslint-disable-next-line no-unused-vars
901
+ async deleteStore({ teamDid, url }, context) {
902
+ logger.info('delete registry', { url });
903
+ const sanitized = sanitizeUrl(url);
904
+
905
+ const storeList = await this.teamManager.getStoreList(teamDid);
906
+ const exist = storeList.find((x) => x.url === sanitized);
907
+ if (!exist) {
908
+ throw new Error(`Blocklet registry does not exist: ${sanitized}`);
909
+ }
910
+
911
+ return this.teamManager.updateStoreList(
912
+ teamDid,
913
+ storeList.filter((x) => x.url !== sanitized)
914
+ );
915
+ }
916
+
858
917
  // =======
859
918
  // Private
860
919
  // =======
@@ -3,6 +3,7 @@
3
3
  const fs = require('fs-extra');
4
4
  const { fileURLToPath } = require('url');
5
5
  const path = require('path');
6
+ const flat = require('flat');
6
7
  const urlHttp = require('url-http');
7
8
  const get = require('lodash/get');
8
9
  const pick = require('lodash/pick');
@@ -39,7 +40,6 @@ const {
39
40
  forEachChild,
40
41
  getComponentId,
41
42
  getComponentBundleId,
42
- isExternalBlocklet,
43
43
  } = require('@blocklet/meta/lib/util');
44
44
  const getComponentProcessId = require('@blocklet/meta/lib/get-component-process-id');
45
45
  const validateBlockletEntry = require('@blocklet/meta/lib/entry');
@@ -109,6 +109,7 @@ const {
109
109
  ensureMeta,
110
110
  getBlocklet,
111
111
  ensureEnvDefault,
112
+ getConfigFromPreferences,
112
113
  } = require('../../util/blocklet');
113
114
  const StoreUtil = require('../../util/store');
114
115
  const states = require('../../states');
@@ -269,8 +270,8 @@ class BlockletManager extends BaseBlockletManager {
269
270
  }
270
271
 
271
272
  if (source === BlockletSource.registry) {
272
- const { did, controller, sync, delay } = params;
273
- return this._installFromStore({ did, controller, sync, delay }, context);
273
+ const { did, controller, sync, delay, storeUrl } = params;
274
+ return this._installFromStore({ did, controller, sync, delay, storeUrl }, context);
274
275
  }
275
276
 
276
277
  if (source === BlockletSource.custom) {
@@ -836,6 +837,7 @@ class BlockletManager extends BaseBlockletManager {
836
837
  return result;
837
838
  }
838
839
 
840
+ // Get blocklet by blockletDid or appDid
839
841
  async detail({ did, attachConfig = true, attachRuntimeInfo = true }, context) {
840
842
  if (!did) {
841
843
  throw new Error('did should not be empty');
@@ -860,46 +862,54 @@ class BlockletManager extends BaseBlockletManager {
860
862
  return this.attachRuntimeInfo({ did, nodeInfo, diskInfo: true, context });
861
863
  }
862
864
 
863
- async list({ includeRuntimeInfo = true, useCache = true, filter } = {}, context) {
864
- const blocklets = await states.blocklet.getBlocklets();
865
- let list = blocklets;
865
+ async attachBlockletListRuntimeInfo({ blocklets, useCache }, context) {
866
+ const nodeInfo = await states.node.read();
867
+ const updated = (
868
+ await Promise.all(
869
+ blocklets.map((x) => {
870
+ if (isBeforeInstalled(x.status)) {
871
+ return x;
872
+ }
866
873
 
867
- if (includeRuntimeInfo) {
868
- const nodeInfo = await states.node.read();
869
- const updated = (
870
- await Promise.all(
871
- blocklets.map((x) => {
872
- if (isBeforeInstalled(x.status)) {
873
- return x;
874
- }
874
+ const cachedBlocklet =
875
+ useCache && this.cachedBlocklets ? this.cachedBlocklets.find((y) => y.meta.did === x.meta.did) : null;
875
876
 
876
- const cachedBlocklet =
877
- useCache && this.cachedBlocklets ? this.cachedBlocklets.find((y) => y.meta.did === x.meta.did) : null;
877
+ return this.attachRuntimeInfo({
878
+ did: x.meta.did,
879
+ nodeInfo,
880
+ diskInfo: false,
881
+ context,
882
+ cachedBlocklet,
883
+ });
884
+ })
885
+ )
886
+ ).filter(Boolean);
878
887
 
879
- return this.attachRuntimeInfo({
880
- did: x.meta.did,
881
- nodeInfo,
882
- diskInfo: false,
883
- context,
884
- cachedBlocklet,
885
- });
886
- })
887
- )
888
- ).filter(Boolean);
888
+ this.cachedBlocklets = cloneDeep(updated);
889
+ return updated;
890
+ }
889
891
 
890
- this.cachedBlocklets = cloneDeep(updated);
891
- list = updated;
892
+ async list({ includeRuntimeInfo = true, useCache = true, query, filter } = {}, context) {
893
+ const condition = { ...flat(query || {}) };
894
+ if (filter === 'external-only') {
895
+ condition.controller = {
896
+ $exists: true,
897
+ };
892
898
  }
893
899
 
894
900
  if (filter === 'external-excluded') {
895
- return list.filter((x) => !isExternalBlocklet(x));
901
+ condition.controller = {
902
+ $exists: false,
903
+ };
896
904
  }
897
905
 
898
- if (filter === 'external-only') {
899
- return list.filter(isExternalBlocklet);
906
+ const blocklets = await states.blocklet.getBlocklets(condition);
907
+
908
+ if (includeRuntimeInfo) {
909
+ return this.attachBlockletListRuntimeInfo({ blocklets, useCache }, context);
900
910
  }
901
911
 
902
- return list;
912
+ return blocklets;
903
913
  }
904
914
 
905
915
  // eslint-disable-next-line no-unused-vars
@@ -1122,23 +1132,23 @@ class BlockletManager extends BaseBlockletManager {
1122
1132
  /**
1123
1133
  * upgrade blocklet from registry
1124
1134
  */
1125
- async upgrade({ did, registryUrl, sync }, context) {
1135
+ async upgrade({ did, storeUrl, sync }, context) {
1126
1136
  const blocklet = await states.blocklet.getBlocklet(did);
1127
1137
 
1128
- if (!registryUrl && blocklet.source === BlockletSource.url) {
1138
+ if (!storeUrl && blocklet.source === BlockletSource.url) {
1129
1139
  return this._installFromUrl({ url: blocklet.deployedFrom }, context);
1130
1140
  }
1131
1141
 
1132
- // TODO: 查看了下目前页面中的升级按钮,都是会传 registryUrl 过来的,这个函数里的逻辑感觉需要在以后做一个简化
1133
- if (!registryUrl && blocklet.source !== BlockletSource.registry) {
1134
- throw new Error('Wrong upgrade source, empty registryUrl or not installed from blocklet registry');
1142
+ // TODO: 查看了下目前页面中的升级按钮,都是会传 storeUrl 过来的,这个函数里的逻辑感觉需要在以后做一个简化
1143
+ if (!storeUrl && blocklet.source !== BlockletSource.registry) {
1144
+ throw new Error('Wrong upgrade source, empty storeUrl or not installed from blocklet registry');
1135
1145
  }
1136
1146
 
1137
- const upgradeFromRegistry = registryUrl || blocklet.deployedFrom;
1147
+ const upgradeFromStore = storeUrl || blocklet.deployedFrom;
1138
1148
 
1139
1149
  let newVersionMeta = await StoreUtil.getBlockletMeta({
1140
1150
  did: blocklet.meta.bundleDid,
1141
- registryUrl: upgradeFromRegistry,
1151
+ storeUrl: upgradeFromStore,
1142
1152
  });
1143
1153
  newVersionMeta = ensureMeta(newVersionMeta, { name: blocklet.meta.name, did: blocklet.meta.did });
1144
1154
 
@@ -1189,7 +1199,7 @@ class BlockletManager extends BaseBlockletManager {
1189
1199
  return this._upgrade({
1190
1200
  meta: newVersionMeta,
1191
1201
  source: BlockletSource.registry,
1192
- deployedFrom: upgradeFromRegistry,
1202
+ deployedFrom: upgradeFromStore,
1193
1203
  context,
1194
1204
  sync,
1195
1205
  });
@@ -1374,7 +1384,7 @@ class BlockletManager extends BaseBlockletManager {
1374
1384
 
1375
1385
  const meta = getBlockletMeta(folder);
1376
1386
  if (meta.group !== 'static' && (!meta.scripts || !meta.scripts.dev)) {
1377
- throw new Error('Incorrect blocklet manifest: missing `scripts.dev` field');
1387
+ throw new Error('Incorrect blocklet.yml: missing `scripts.dev` field');
1378
1388
  }
1379
1389
 
1380
1390
  if (rootDid) {
@@ -1967,16 +1977,19 @@ class BlockletManager extends BaseBlockletManager {
1967
1977
  * @memberof BlockletManager
1968
1978
  */
1969
1979
  async _installFromStore(params, context) {
1970
- const { did, registry, sync, delay, controller } = params;
1980
+ const { did, storeUrl, sync, delay, controller } = params;
1971
1981
 
1972
1982
  logger.debug('start install blocklet', { did });
1973
1983
  if (!isValidDid(did)) {
1974
1984
  throw new Error('Blocklet did is invalid');
1975
1985
  }
1976
1986
 
1977
- const registryUrl = registry || (await states.node.getBlockletRegistry());
1978
- const info = await StoreUtil.getRegistryMeta(registryUrl);
1979
- const meta = await StoreUtil.getBlockletMeta({ did, registryUrl });
1987
+ if (!storeUrl) {
1988
+ throw new Error('registry url should not be empty');
1989
+ }
1990
+
1991
+ const info = await StoreUtil.getRegistryMeta(storeUrl);
1992
+ const meta = await StoreUtil.getBlockletMeta({ did, storeUrl });
1980
1993
  if (!meta) {
1981
1994
  throw new Error('Can not install blocklet that not found in registry');
1982
1995
  }
@@ -1989,14 +2002,14 @@ class BlockletManager extends BaseBlockletManager {
1989
2002
  throw new Error('Can not install an already installed blocklet');
1990
2003
  }
1991
2004
 
1992
- if (controller?.vcId) {
1993
- // sometimes nedb will throw error if use states.blocklet.count({ ['controller.vcId']: controller.vcId })
2005
+ if (controller?.nftId) {
2006
+ // sometimes nedb will throw error if use states.blocklet.count({ ['controller.nftId']: controller.nftId })
1994
2007
  const blocklets = await states.blocklet.find({}, { controller: 1 });
1995
- const count = blocklets.filter((x) => x.controller?.vcId === controller.vcId).length;
2008
+ const count = blocklets.filter((x) => x.controller?.nftId === controller.nftId).length;
1996
2009
 
1997
2010
  if (count >= (controller.appMaxCount || 1)) {
1998
2011
  throw new Error(
1999
- `You can only install ${controller.appMaxCount} blocklet with this credential: ${controller.vcId}`
2012
+ `You can only install ${controller.appMaxCount} blocklet with this credential: ${controller.nftId}`
2000
2013
  );
2001
2014
  }
2002
2015
  }
@@ -2005,7 +2018,7 @@ class BlockletManager extends BaseBlockletManager {
2005
2018
  return this._install({
2006
2019
  meta: ensureMeta(meta, { did: blockletDid, name: blockletName }),
2007
2020
  source: BlockletSource.registry,
2008
- deployedFrom: info.cdnUrl || registryUrl,
2021
+ deployedFrom: info.cdnUrl || storeUrl,
2009
2022
  sync,
2010
2023
  delay,
2011
2024
  controller,
@@ -2016,7 +2029,7 @@ class BlockletManager extends BaseBlockletManager {
2016
2029
  /**
2017
2030
  * @type {{
2018
2031
  * id: string;
2019
- * vcId: string;
2032
+ * nftId: string;
2020
2033
  * expireDate: Date;
2021
2034
  * }} Controller
2022
2035
  *
@@ -2048,10 +2061,10 @@ class BlockletManager extends BaseBlockletManager {
2048
2061
  if (inStore) {
2049
2062
  const exist = await states.blocklet.getBlocklet(blockletDid);
2050
2063
  if (exist) {
2051
- return this.upgrade({ did: blockletDid, registryUrl, sync, delay }, context);
2064
+ return this.upgrade({ did: blockletDid, storeUrl: registryUrl, sync, delay }, context);
2052
2065
  }
2053
2066
 
2054
- return this._installFromStore({ did: bundleDid, registry: registryUrl, controller, sync, delay }, context);
2067
+ return this._installFromStore({ did: bundleDid, storeUrl: registryUrl, controller, sync, delay }, context);
2055
2068
  }
2056
2069
 
2057
2070
  const meta = ensureMeta(bundleMeta, { name: blockletName, did: blockletDid });
@@ -3482,11 +3495,11 @@ class BlockletManager extends BaseBlockletManager {
3482
3495
  }
3483
3496
 
3484
3497
  async _setConfigsFromMeta(did, childDid) {
3485
- const blocklet = await states.blocklet.getBlocklet(did);
3498
+ const blocklet = await getBlocklet({ states, dataDirs: this.dataDirs, did, validateEnv: false, ensureDirs: false });
3486
3499
 
3487
3500
  if (!childDid) {
3488
3501
  await forEachBlocklet(blocklet, async (b, { ancestors }) => {
3489
- const environments = get(b.meta, 'environments', []);
3502
+ const environments = [...get(b.meta, 'environments', []), ...getConfigFromPreferences(b)];
3490
3503
 
3491
3504
  // remove default if ancestors has a value
3492
3505
  ensureEnvDefault(environments, ancestors);
@@ -3499,7 +3512,7 @@ class BlockletManager extends BaseBlockletManager {
3499
3512
  await forEachBlocklet(child, async (b, { ancestors }) => {
3500
3513
  await states.blockletExtras.setConfigs(
3501
3514
  [blocklet.meta.did, ...ancestors.map((x) => x.meta.did), b.meta.did],
3502
- get(b.meta, 'environments', [])
3515
+ [...get(b.meta, 'environments', []), ...getConfigFromPreferences(child)]
3503
3516
  );
3504
3517
  });
3505
3518
  }
@@ -3548,13 +3561,13 @@ class BlockletManager extends BaseBlockletManager {
3548
3561
  }
3549
3562
 
3550
3563
  async _getLatestBlockletVersionFromStore({ blocklet, version }) {
3551
- const { deployedFrom: registryUrl } = blocklet;
3564
+ const { deployedFrom: storeUrl } = blocklet;
3552
3565
  const { did, bundleDid } = blocklet.meta;
3553
3566
 
3554
3567
  let versions = this.cachedBlockletVersions.get(did);
3555
3568
 
3556
3569
  if (!versions) {
3557
- const item = await StoreUtil.getBlockletMeta({ did: bundleDid, registryUrl });
3570
+ const item = await StoreUtil.getBlockletMeta({ did: bundleDid, storeUrl });
3558
3571
 
3559
3572
  if (!item) {
3560
3573
  return null;
@@ -3571,23 +3584,7 @@ class BlockletManager extends BaseBlockletManager {
3571
3584
  return null;
3572
3585
  }
3573
3586
 
3574
- // When new version found from the store where the blocklet was installed from, we should use that store first
3575
- if (blocklet.source === BlockletSource.registry && blocklet.deployedFrom) {
3576
- const latestFromSameRegistry = versions.find((x) => x.registryUrl === blocklet.deployedFrom);
3577
- if (latestFromSameRegistry) {
3578
- return latestFromSameRegistry;
3579
- }
3580
- }
3581
-
3582
- // Otherwise try upgrading from other store
3583
- let latestBlockletVersion = versions[0];
3584
- versions.forEach((item) => {
3585
- if (semver.lt(latestBlockletVersion.version, item.version)) {
3586
- latestBlockletVersion = item;
3587
- }
3588
- });
3589
-
3590
- return latestBlockletVersion;
3587
+ return versions[0];
3591
3588
  }
3592
3589
 
3593
3590
  async _getLatestBlockletVersionFromUrl({ blocklet, version }) {
package/lib/event.js CHANGED
@@ -249,6 +249,8 @@ module.exports = ({
249
249
  }
250
250
  };
251
251
 
252
+ const listen = (subject, event, handler) => subject.on(event, (data) => handler(event, data));
253
+
252
254
  [
253
255
  BlockletEvents.added,
254
256
  BlockletEvents.downloadFailed,
@@ -265,12 +267,12 @@ module.exports = ({
265
267
  BlockletEvents.startFailed,
266
268
  BlockletEvents.stopped,
267
269
  ].forEach((eventName) => {
268
- blockletManager.on(eventName, (data) => handleBlockletEvent(eventName, data));
270
+ listen(blockletManager, eventName, handleBlockletEvent);
269
271
  });
270
272
 
271
- notificationState.on(EVENTS.NOTIFICATION_CREATE, (data) => onEvent(EVENTS.NOTIFICATION_CREATE, data));
273
+ listen(notificationState, EVENTS.NOTIFICATION_CREATE, onEvent);
272
274
 
273
- nodeState.on(BlockletEvents.purchaseChange, (data) => onEvent(BlockletEvents.purchaseChange, data));
275
+ listen(nodeState, BlockletEvents.purchaseChange, onEvent);
274
276
  nodeState.on(EVENTS.ROUTING_UPDATED, (nodeInfo) => onEvent(EVENTS.ROUTING_UPDATED, { routing: nodeInfo.routing }));
275
277
  nodeState.once(EVENTS.NODE_ADDED_OWNER, () => downloadAddedBlocklet());
276
278
  nodeState.on(EVENTS.NODE_UPDATED, (nodeInfo, oldInfo) => {
@@ -285,7 +287,8 @@ module.exports = ({
285
287
  });
286
288
  }
287
289
  });
288
- nodeState.on(EVENTS.NODE_UPGRADE_PROGRESS, (session) => onEvent(EVENTS.NODE_UPGRADE_PROGRESS, session));
290
+
291
+ listen(nodeState, EVENTS.NODE_UPGRADE_PROGRESS, onEvent);
289
292
  nodeState.on(EVENTS.RELOAD_GATEWAY, (nodeInfo) => {
290
293
  handleRouting(nodeInfo).catch((err) => {
291
294
  logger.error('Handle routing failed on node.updated', { error: err });
@@ -300,15 +303,16 @@ module.exports = ({
300
303
  });
301
304
  });
302
305
 
303
- teamAPI.on(EVENTS.USER_ADDED, (data) => onEvent(EVENTS.USER_ADDED, data));
304
- teamAPI.on(EVENTS.USER_REMOVED, (data) => onEvent(EVENTS.USER_REMOVED, data));
305
- teamAPI.on(EVENTS.USER_UPDATED, (data) => onEvent(EVENTS.USER_UPDATED, data));
306
- teamAPI.on(BlockletEvents.updated, (data) => onEvent(BlockletEvents.updated, data));
306
+ listen(teamAPI, EVENTS.USER_ADDED, onEvent);
307
+ listen(teamAPI, EVENTS.USER_REMOVED, onEvent);
308
+ listen(teamAPI, EVENTS.USER_UPDATED, onEvent);
309
+ listen(teamAPI, BlockletEvents.updated, onEvent);
310
+ listen(teamManager, BlockletEvents.storeChange, onEvent);
307
311
 
308
- certManager.on('cert.issued', (data) => onEvent(EVENTS.CERT_ISSUED, data));
309
- certManager.on('cert.error', (data) => onEvent(EVENTS.CERT_ERROR, data));
312
+ listen(certManager, EVENTS.CERT_ISSUED, onEvent);
313
+ listen(certManager, EVENTS.CERT_ERROR, onEvent);
310
314
 
311
- routerManager.on(BlockletEvents.updated, (data) => onEvent(BlockletEvents.updated, data));
315
+ listen(routerManager, BlockletEvents.updated, onEvent);
312
316
 
313
317
  events.setEventHandler = (handler) => {
314
318
  if (typeof handler === 'function') {
package/lib/index.js CHANGED
@@ -236,9 +236,6 @@ function ABTNode(options) {
236
236
  getNodeInfo: nodeAPI.getInfo.bind(nodeAPI),
237
237
  getNodeEnv: nodeAPI.getEnv.bind(nodeAPI),
238
238
  updateNodeInfo: nodeAPI.updateNodeInfo.bind(nodeAPI),
239
- addBlockletStore: nodeAPI.addRegistry.bind(nodeAPI),
240
- deleteBlockletStore: nodeAPI.deleteRegistry.bind(nodeAPI),
241
- selectBlockletStore: nodeAPI.selectRegistry.bind(nodeAPI),
242
239
  getDelegationState: nodeAPI.getDelegationState.bind(nodeAPI),
243
240
  cleanupDirtyUpgradeState: states.node.cleanupDirtyUpgradeState.bind(states.node),
244
241
  updateNodeOwner: states.node.updateNodeOwner.bind(states.node),
@@ -307,6 +304,10 @@ function ABTNode(options) {
307
304
  configTrustedPassports: teamAPI.configTrustedPassports.bind(teamAPI),
308
305
  configPassportIssuance: teamAPI.configPassportIssuance.bind(teamAPI),
309
306
 
307
+ // Team Settings
308
+ addBlockletStore: teamAPI.addStore.bind(teamAPI),
309
+ deleteBlockletStore: teamAPI.deleteStore.bind(teamAPI),
310
+
310
311
  // Challenge
311
312
  generateChallenge: states.challenge.generate.bind(states.challenge),
312
313
  verifyChallenge: states.challenge.verify.bind(states.challenge),
@@ -355,6 +356,7 @@ function ABTNode(options) {
355
356
  // Access Key
356
357
  getAccessKeys: states.accessKey.list.bind(states.accessKey),
357
358
  getAccessKey: states.accessKey.detail.bind(states.accessKey),
359
+ getAccessKeyByTag: states.accessKey.getAccessKeyByTag.bind(states.accessKey),
358
360
  createAccessKey: states.accessKey.create.bind(states.accessKey),
359
361
  updateAccessKey: states.accessKey.update.bind(states.accessKey),
360
362
  deleteAccessKey: states.accessKey.remove.bind(states.accessKey),
@@ -31,8 +31,8 @@ class AccessKeyState extends BaseState {
31
31
  });
32
32
  }
33
33
 
34
- async create(input = {}, context) {
35
- const { remark, passport } = input;
34
+ async create(input, context) {
35
+ const { remark, passport, tag } = input || {};
36
36
 
37
37
  validateRemark(remark);
38
38
  validatePassport(passport);
@@ -43,10 +43,15 @@ class AccessKeyState extends BaseState {
43
43
  accessKeyPublic: wallet.publicKey,
44
44
  passport,
45
45
  };
46
+
46
47
  if (remark) {
47
48
  data.remark = remark;
48
49
  }
49
50
 
51
+ if (tag) {
52
+ data.tag = tag;
53
+ }
54
+
50
55
  data.createdBy = getUserName(context);
51
56
  data.updatedBy = getUserName(context);
52
57
 
@@ -57,6 +62,14 @@ class AccessKeyState extends BaseState {
57
62
  };
58
63
  }
59
64
 
65
+ async getAccessKeyByTag({ tag } = {}) {
66
+ if (!tag) {
67
+ throw new Error('tag should not be empty');
68
+ }
69
+
70
+ return this.findOne({ tag });
71
+ }
72
+
60
73
  // eslint-disable-next-line no-unused-vars
61
74
  async list(params, context) {
62
75
  const res = await this.paginate({}, { createdAt: -1 }, { pageSize: 100 });
@@ -410,7 +410,7 @@ class AuditLogState extends BaseState {
410
410
  }
411
411
 
412
412
  try {
413
- const { ip, ua, user } = context;
413
+ const { ip, ua, user = {} } = context;
414
414
  const [info, uaInfo] = await Promise.all([node.states.node.read(), parse(ua)]);
415
415
 
416
416
  fixActor(user);
@@ -302,10 +302,6 @@ class NodeState extends BaseState {
302
302
  }));
303
303
  }
304
304
 
305
- getBlockletRegistry() {
306
- return this.read().then((info) => info.blockletRegistryList.find((item) => item.selected).url);
307
- }
308
-
309
305
  async increaseCustomBlockletNumber() {
310
306
  const { _id, customBlockletNumber = 0 } = await this.read();
311
307
  const num = customBlockletNumber + 1;
@@ -9,6 +9,7 @@ const get = require('lodash/get');
9
9
  const { createRBAC, MemoryStorage, NedbStorage } = require('@abtnode/rbac');
10
10
  const logger = require('@abtnode/logger')('@abtnode/core:team:manager');
11
11
  const { ROLES, RBAC_CONFIG } = require('@abtnode/constant');
12
+ const { BlockletEvents } = require('@blocklet/constant');
12
13
  const Lock = require('@abtnode/util/lib/lock');
13
14
  const UserState = require('../states/user');
14
15
  const SessionState = require('../states/session');
@@ -280,6 +281,26 @@ class TeamManager extends EventEmitter {
280
281
  }
281
282
  }
282
283
 
284
+ async getStoreList(did) {
285
+ if (this.isNodeTeam(did)) {
286
+ const nodeInfo = await this.states.node.read();
287
+ return nodeInfo.blockletRegistryList || [];
288
+ }
289
+
290
+ const settings = await this.states.blockletExtras.getSettings(did);
291
+ return get(settings, 'storeList', []) || [];
292
+ }
293
+
294
+ async updateStoreList(did, list) {
295
+ if (this.isNodeTeam(did)) {
296
+ await this.states.node.updateNodeInfo({ blockletRegistryList: list });
297
+ return;
298
+ }
299
+
300
+ await this.states.blockletExtras.setSettings(did, { storeList: list });
301
+ this.emit(BlockletEvents.storeChange, { meta: { did } });
302
+ }
303
+
283
304
  async getOwner(did) {
284
305
  let owner;
285
306
  if (this.isNodeTeam(did)) {
@@ -16,13 +16,15 @@ const { isValid: isValidDid } = require('@arcblock/did');
16
16
  const logger = require('@abtnode/logger')('@abtnode/core:util:blocklet');
17
17
  const pm2 = require('@abtnode/util/lib/async-pm2');
18
18
  const sleep = require('@abtnode/util/lib/sleep');
19
+ const { formatEnv } = require('@abtnode/util/lib/security');
19
20
  const ensureEndpointHealthy = require('@abtnode/util/lib/ensure-endpoint-healthy');
20
21
  const CustomError = require('@abtnode/util/lib/custom-error');
21
22
  const getFolderSize = require('@abtnode/util/lib/get-folder-size');
22
23
  const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
23
24
  const hashFiles = require('@abtnode/util/lib/hash-files');
24
25
  const isPathPrefixEqual = require('@abtnode/util/lib/is-path-prefix-equal');
25
- const { BLOCKLET_MAX_MEM_LIMIT_IN_MB } = require('@abtnode/constant');
26
+ const { BLOCKLET_MAX_MEM_LIMIT_IN_MB, BLOCKLET_STORE } = require('@abtnode/constant');
27
+ const { BLOCKLET_PREFERENCE_FILE, BLOCKLET_PREFERENCE_PREFIX } = require('@blocklet/constant');
26
28
  const formatBackSlash = require('@abtnode/util/lib/format-back-slash');
27
29
 
28
30
  const SCRIPT_ENGINES_WHITE_LIST = ['npm', 'npx', 'pnpm', 'yarn'];
@@ -148,7 +150,7 @@ const getComponentDirs = (
148
150
  }
149
151
 
150
152
  if (validate && !main && !startFromDevEntry && group !== BlockletGroup.gateway) {
151
- throw new Error('Incorrect blocklet manifest: missing `main` field');
153
+ throw new Error('Incorrect blocklet.yml: missing `main` field');
152
154
  }
153
155
 
154
156
  let appDir = null;
@@ -380,7 +382,7 @@ const getRuntimeEnvironments = (blocklet, nodeEnvironments, ancestors) => {
380
382
  ? getBlockletWallet(blocklet.meta.did, nodeEnvironments.ABT_NODE_SK, undefined, 1)
381
383
  : null;
382
384
 
383
- return {
385
+ const env = {
384
386
  ...blocklet.configObj,
385
387
  ...getSharedConfigObj(blocklet, ancestors),
386
388
  ...blocklet.environmentObj,
@@ -392,6 +394,13 @@ const getRuntimeEnvironments = (blocklet, nodeEnvironments, ancestors) => {
392
394
  ...nodeEnvironments,
393
395
  ...safeNodeEnvironments,
394
396
  };
397
+
398
+ // ensure all envs are literals and do not contain line breaks
399
+ Object.keys(env).forEach((key) => {
400
+ env[key] = formatEnv(env[key]);
401
+ });
402
+
403
+ return env;
395
404
  };
396
405
 
397
406
  const isUsefulError = (err) =>
@@ -1330,6 +1339,15 @@ const getBlocklet = async ({
1330
1339
  blocklet.enablePassportIssuance = get(settings, 'enablePassportIssuance', true);
1331
1340
  blocklet.settings = settings || {};
1332
1341
 
1342
+ blocklet.settings.storeList = blocklet.settings.storeList || [];
1343
+
1344
+ if (!blocklet.settings.storeList.find((x) => x.url === BLOCKLET_STORE.url)) {
1345
+ blocklet.settings.storeList.unshift({
1346
+ ...BLOCKLET_STORE,
1347
+ protected: true,
1348
+ });
1349
+ }
1350
+
1333
1351
  // app site
1334
1352
  blocklet.site = await states.site.findOneByBlocklet(blocklet.meta.did);
1335
1353
 
@@ -1385,6 +1403,39 @@ const ensureEnvDefault = (environments, ancestors) => {
1385
1403
  return environments;
1386
1404
  };
1387
1405
 
1406
+ const fromProperty2Config = (properties = {}, result) => {
1407
+ Object.keys(properties).forEach((key) => {
1408
+ const prop = properties[key];
1409
+ if (prop.properties) {
1410
+ fromProperty2Config(prop.properties, result);
1411
+ } else if (prop['x-decorator'] === 'FormItem') {
1412
+ const secure = prop['x-component'] === 'Password';
1413
+ result.push({
1414
+ default: prop.default || '',
1415
+ description: prop.title || key,
1416
+ name: `${BLOCKLET_PREFERENCE_PREFIX}${key}`,
1417
+ required: prop.required || false,
1418
+ secure,
1419
+ shared: !secure,
1420
+ });
1421
+ }
1422
+ });
1423
+ };
1424
+ const getConfigFromPreferences = (blocklet) => {
1425
+ const result = [];
1426
+ const schemaFile = path.join(blocklet.env.appDir, BLOCKLET_PREFERENCE_FILE);
1427
+ if (fs.existsSync(schemaFile)) {
1428
+ try {
1429
+ const schema = JSON.parse(fs.readFileSync(schemaFile, 'utf8'));
1430
+ fromProperty2Config(schema.schema?.properties, result);
1431
+ } catch {
1432
+ // do nothing
1433
+ }
1434
+ }
1435
+
1436
+ return result;
1437
+ };
1438
+
1388
1439
  module.exports = {
1389
1440
  forEachBlocklet,
1390
1441
  getBlockletMetaFromUrl: (url) => getBlockletMetaFromUrl(url, { logger }),
@@ -1425,4 +1476,5 @@ module.exports = {
1425
1476
  ensureMeta,
1426
1477
  getBlocklet,
1427
1478
  ensureEnvDefault,
1479
+ getConfigFromPreferences,
1428
1480
  };
@@ -1,4 +1,4 @@
1
- const { NODE_REGISTER_URL, BLOCKLET_STORE_URL, BLOCKLET_STORE_URL_DEV } = require('@abtnode/constant');
1
+ const { NODE_REGISTER_URL, BLOCKLET_STORE, BLOCKLET_STORE_DEV } = require('@abtnode/constant');
2
2
  const canPackageReadWrite = require('@abtnode/util/lib/can-pkg-rw');
3
3
 
4
4
  const getDefaultAutoUpgrade = () => {
@@ -16,21 +16,11 @@ const defaultNodeConfigs = {
16
16
  blockletRegistryList: {
17
17
  getDefaultValue: () => [
18
18
  {
19
- name: 'Official Store',
20
- description: 'ArcBlock official blocklet registry',
21
- url: BLOCKLET_STORE_URL,
22
- logoUrl: '/logo.png',
23
- maintainer: 'arcblock',
24
- selected: true,
19
+ ...BLOCKLET_STORE,
25
20
  protected: true,
26
21
  },
27
22
  {
28
- name: 'Dev Store',
29
- description: 'ArcBlock dev registry that contains demo and example blocklets',
30
- url: BLOCKLET_STORE_URL_DEV,
31
- maintainer: 'arcblock',
32
- logoUrl: '/logo.png',
33
- selected: false,
23
+ ...BLOCKLET_STORE_DEV,
34
24
  protected: false,
35
25
  },
36
26
  ],
package/lib/util/store.js CHANGED
@@ -84,7 +84,7 @@ const parseSourceUrl = async (url) => {
84
84
  };
85
85
  };
86
86
 
87
- const resolveTarballURL = async ({ did, tarball = '', registryUrl = '' }) => {
87
+ const resolveTarballURL = async ({ did, tarball = '', storeUrl = '' }) => {
88
88
  if (!tarball) {
89
89
  return '';
90
90
  }
@@ -97,7 +97,7 @@ const resolveTarballURL = async ({ did, tarball = '', registryUrl = '' }) => {
97
97
  return tarball;
98
98
  }
99
99
 
100
- if (!registryUrl) {
100
+ if (!storeUrl) {
101
101
  return '';
102
102
  }
103
103
 
@@ -105,11 +105,11 @@ const resolveTarballURL = async ({ did, tarball = '', registryUrl = '' }) => {
105
105
  return '';
106
106
  }
107
107
 
108
- return joinURL(registryUrl, 'api', 'blocklets', did, tarball);
108
+ return joinURL(storeUrl, 'api', 'blocklets', did, tarball);
109
109
  };
110
110
 
111
- const getBlockletMeta = async ({ did, registryUrl }) => {
112
- const url = joinURL(registryUrl, BLOCKLET_STORE_API_PREFIX, `/blocklets/${did}/blocklet.json?__t__=${Date.now()}`);
111
+ const getBlockletMeta = async ({ did, storeUrl }) => {
112
+ const url = joinURL(storeUrl, BLOCKLET_STORE_API_PREFIX, `/blocklets/${did}/blocklet.json?__t__=${Date.now()}`);
113
113
 
114
114
  const { data } = await request.get(url);
115
115
  try {
@@ -122,7 +122,7 @@ const getBlockletMeta = async ({ did, registryUrl }) => {
122
122
  meta.dist.tarball = await resolveTarballURL({
123
123
  did,
124
124
  tarball: meta.dist.tarball,
125
- registryUrl,
125
+ storeUrl,
126
126
  });
127
127
 
128
128
  return meta;
@@ -5,7 +5,8 @@ const Joi = JOI.extend(didExtension);
5
5
 
6
6
  const blockletController = Joi.object({
7
7
  id: Joi.DID().required(), // userDid
8
- vcId: Joi.DID().required(),
8
+ nftId: Joi.DID().required(),
9
+ nftOwner: Joi.DID().required(),
9
10
  appMaxCount: Joi.number().required().min(1),
10
11
  expireDate: Joi.date(),
11
12
  }).options({ stripUnknown: true });
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.8.35",
6
+ "version": "1.8.37",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,18 +19,18 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "@abtnode/auth": "1.8.35",
23
- "@abtnode/certificate-manager": "1.8.35",
24
- "@abtnode/constant": "1.8.35",
25
- "@abtnode/cron": "1.8.35",
26
- "@abtnode/db": "1.8.35",
27
- "@abtnode/logger": "1.8.35",
28
- "@abtnode/queue": "1.8.35",
29
- "@abtnode/rbac": "1.8.35",
30
- "@abtnode/router-provider": "1.8.35",
31
- "@abtnode/static-server": "1.8.35",
32
- "@abtnode/timemachine": "1.8.35",
33
- "@abtnode/util": "1.8.35",
22
+ "@abtnode/auth": "1.8.37",
23
+ "@abtnode/certificate-manager": "1.8.37",
24
+ "@abtnode/constant": "1.8.37",
25
+ "@abtnode/cron": "1.8.37",
26
+ "@abtnode/db": "1.8.37",
27
+ "@abtnode/logger": "1.8.37",
28
+ "@abtnode/queue": "1.8.37",
29
+ "@abtnode/rbac": "1.8.37",
30
+ "@abtnode/router-provider": "1.8.37",
31
+ "@abtnode/static-server": "1.8.37",
32
+ "@abtnode/timemachine": "1.8.37",
33
+ "@abtnode/util": "1.8.37",
34
34
  "@arcblock/did": "1.18.15",
35
35
  "@arcblock/did-motif": "^1.1.10",
36
36
  "@arcblock/did-util": "1.18.15",
@@ -38,9 +38,9 @@
38
38
  "@arcblock/jwt": "^1.18.15",
39
39
  "@arcblock/pm2-events": "^0.0.5",
40
40
  "@arcblock/vc": "1.18.15",
41
- "@blocklet/constant": "1.8.35",
42
- "@blocklet/meta": "1.8.35",
43
- "@blocklet/sdk": "1.8.35",
41
+ "@blocklet/constant": "1.8.37",
42
+ "@blocklet/meta": "1.8.37",
43
+ "@blocklet/sdk": "1.8.37",
44
44
  "@fidm/x509": "^1.2.1",
45
45
  "@ocap/mcrypto": "1.18.15",
46
46
  "@ocap/util": "1.18.15",
@@ -82,5 +82,5 @@
82
82
  "express": "^4.18.2",
83
83
  "jest": "^27.5.1"
84
84
  },
85
- "gitHead": "dd89e7a61dc8cff64302608ad5ab6545dd903daa"
85
+ "gitHead": "f26f451c6e2b1168b36f78269eafdf3f671236bf"
86
86
  }