@abtnode/core 1.8.36 → 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
  // =======
@@ -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');
@@ -1130,23 +1132,23 @@ class BlockletManager extends BaseBlockletManager {
1130
1132
  /**
1131
1133
  * upgrade blocklet from registry
1132
1134
  */
1133
- async upgrade({ did, registryUrl, sync }, context) {
1135
+ async upgrade({ did, storeUrl, sync }, context) {
1134
1136
  const blocklet = await states.blocklet.getBlocklet(did);
1135
1137
 
1136
- if (!registryUrl && blocklet.source === BlockletSource.url) {
1138
+ if (!storeUrl && blocklet.source === BlockletSource.url) {
1137
1139
  return this._installFromUrl({ url: blocklet.deployedFrom }, context);
1138
1140
  }
1139
1141
 
1140
- // TODO: 查看了下目前页面中的升级按钮,都是会传 registryUrl 过来的,这个函数里的逻辑感觉需要在以后做一个简化
1141
- if (!registryUrl && blocklet.source !== BlockletSource.registry) {
1142
- 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');
1143
1145
  }
1144
1146
 
1145
- const upgradeFromRegistry = registryUrl || blocklet.deployedFrom;
1147
+ const upgradeFromStore = storeUrl || blocklet.deployedFrom;
1146
1148
 
1147
1149
  let newVersionMeta = await StoreUtil.getBlockletMeta({
1148
1150
  did: blocklet.meta.bundleDid,
1149
- registryUrl: upgradeFromRegistry,
1151
+ storeUrl: upgradeFromStore,
1150
1152
  });
1151
1153
  newVersionMeta = ensureMeta(newVersionMeta, { name: blocklet.meta.name, did: blocklet.meta.did });
1152
1154
 
@@ -1197,7 +1199,7 @@ class BlockletManager extends BaseBlockletManager {
1197
1199
  return this._upgrade({
1198
1200
  meta: newVersionMeta,
1199
1201
  source: BlockletSource.registry,
1200
- deployedFrom: upgradeFromRegistry,
1202
+ deployedFrom: upgradeFromStore,
1201
1203
  context,
1202
1204
  sync,
1203
1205
  });
@@ -1382,7 +1384,7 @@ class BlockletManager extends BaseBlockletManager {
1382
1384
 
1383
1385
  const meta = getBlockletMeta(folder);
1384
1386
  if (meta.group !== 'static' && (!meta.scripts || !meta.scripts.dev)) {
1385
- throw new Error('Incorrect blocklet manifest: missing `scripts.dev` field');
1387
+ throw new Error('Incorrect blocklet.yml: missing `scripts.dev` field');
1386
1388
  }
1387
1389
 
1388
1390
  if (rootDid) {
@@ -1975,16 +1977,19 @@ class BlockletManager extends BaseBlockletManager {
1975
1977
  * @memberof BlockletManager
1976
1978
  */
1977
1979
  async _installFromStore(params, context) {
1978
- const { did, registry, sync, delay, controller } = params;
1980
+ const { did, storeUrl, sync, delay, controller } = params;
1979
1981
 
1980
1982
  logger.debug('start install blocklet', { did });
1981
1983
  if (!isValidDid(did)) {
1982
1984
  throw new Error('Blocklet did is invalid');
1983
1985
  }
1984
1986
 
1985
- const registryUrl = registry || (await states.node.getBlockletRegistry());
1986
- const info = await StoreUtil.getRegistryMeta(registryUrl);
1987
- 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 });
1988
1993
  if (!meta) {
1989
1994
  throw new Error('Can not install blocklet that not found in registry');
1990
1995
  }
@@ -2013,7 +2018,7 @@ class BlockletManager extends BaseBlockletManager {
2013
2018
  return this._install({
2014
2019
  meta: ensureMeta(meta, { did: blockletDid, name: blockletName }),
2015
2020
  source: BlockletSource.registry,
2016
- deployedFrom: info.cdnUrl || registryUrl,
2021
+ deployedFrom: info.cdnUrl || storeUrl,
2017
2022
  sync,
2018
2023
  delay,
2019
2024
  controller,
@@ -2056,10 +2061,10 @@ class BlockletManager extends BaseBlockletManager {
2056
2061
  if (inStore) {
2057
2062
  const exist = await states.blocklet.getBlocklet(blockletDid);
2058
2063
  if (exist) {
2059
- return this.upgrade({ did: blockletDid, registryUrl, sync, delay }, context);
2064
+ return this.upgrade({ did: blockletDid, storeUrl: registryUrl, sync, delay }, context);
2060
2065
  }
2061
2066
 
2062
- return this._installFromStore({ did: bundleDid, registry: registryUrl, controller, sync, delay }, context);
2067
+ return this._installFromStore({ did: bundleDid, storeUrl: registryUrl, controller, sync, delay }, context);
2063
2068
  }
2064
2069
 
2065
2070
  const meta = ensureMeta(bundleMeta, { name: blockletName, did: blockletDid });
@@ -3490,11 +3495,11 @@ class BlockletManager extends BaseBlockletManager {
3490
3495
  }
3491
3496
 
3492
3497
  async _setConfigsFromMeta(did, childDid) {
3493
- const blocklet = await states.blocklet.getBlocklet(did);
3498
+ const blocklet = await getBlocklet({ states, dataDirs: this.dataDirs, did, validateEnv: false, ensureDirs: false });
3494
3499
 
3495
3500
  if (!childDid) {
3496
3501
  await forEachBlocklet(blocklet, async (b, { ancestors }) => {
3497
- const environments = get(b.meta, 'environments', []);
3502
+ const environments = [...get(b.meta, 'environments', []), ...getConfigFromPreferences(b)];
3498
3503
 
3499
3504
  // remove default if ancestors has a value
3500
3505
  ensureEnvDefault(environments, ancestors);
@@ -3507,7 +3512,7 @@ class BlockletManager extends BaseBlockletManager {
3507
3512
  await forEachBlocklet(child, async (b, { ancestors }) => {
3508
3513
  await states.blockletExtras.setConfigs(
3509
3514
  [blocklet.meta.did, ...ancestors.map((x) => x.meta.did), b.meta.did],
3510
- get(b.meta, 'environments', [])
3515
+ [...get(b.meta, 'environments', []), ...getConfigFromPreferences(child)]
3511
3516
  );
3512
3517
  });
3513
3518
  }
@@ -3556,13 +3561,13 @@ class BlockletManager extends BaseBlockletManager {
3556
3561
  }
3557
3562
 
3558
3563
  async _getLatestBlockletVersionFromStore({ blocklet, version }) {
3559
- const { deployedFrom: registryUrl } = blocklet;
3564
+ const { deployedFrom: storeUrl } = blocklet;
3560
3565
  const { did, bundleDid } = blocklet.meta;
3561
3566
 
3562
3567
  let versions = this.cachedBlockletVersions.get(did);
3563
3568
 
3564
3569
  if (!versions) {
3565
- const item = await StoreUtil.getBlockletMeta({ did: bundleDid, registryUrl });
3570
+ const item = await StoreUtil.getBlockletMeta({ did: bundleDid, storeUrl });
3566
3571
 
3567
3572
  if (!item) {
3568
3573
  return null;
@@ -3579,23 +3584,7 @@ class BlockletManager extends BaseBlockletManager {
3579
3584
  return null;
3580
3585
  }
3581
3586
 
3582
- // When new version found from the store where the blocklet was installed from, we should use that store first
3583
- if (blocklet.source === BlockletSource.registry && blocklet.deployedFrom) {
3584
- const latestFromSameRegistry = versions.find((x) => x.registryUrl === blocklet.deployedFrom);
3585
- if (latestFromSameRegistry) {
3586
- return latestFromSameRegistry;
3587
- }
3588
- }
3589
-
3590
- // Otherwise try upgrading from other store
3591
- let latestBlockletVersion = versions[0];
3592
- versions.forEach((item) => {
3593
- if (semver.lt(latestBlockletVersion.version, item.version)) {
3594
- latestBlockletVersion = item;
3595
- }
3596
- });
3597
-
3598
- return latestBlockletVersion;
3587
+ return versions[0];
3599
3588
  }
3600
3589
 
3601
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),
@@ -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;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.8.36",
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.36",
23
- "@abtnode/certificate-manager": "1.8.36",
24
- "@abtnode/constant": "1.8.36",
25
- "@abtnode/cron": "1.8.36",
26
- "@abtnode/db": "1.8.36",
27
- "@abtnode/logger": "1.8.36",
28
- "@abtnode/queue": "1.8.36",
29
- "@abtnode/rbac": "1.8.36",
30
- "@abtnode/router-provider": "1.8.36",
31
- "@abtnode/static-server": "1.8.36",
32
- "@abtnode/timemachine": "1.8.36",
33
- "@abtnode/util": "1.8.36",
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.36",
42
- "@blocklet/meta": "1.8.36",
43
- "@blocklet/sdk": "1.8.36",
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": "507e974ce88bad1aa002c593130b32982207f803"
85
+ "gitHead": "f26f451c6e2b1168b36f78269eafdf3f671236bf"
86
86
  }