@abtnode/core 1.16.28-beta-bfbab430 → 1.16.28-beta-641c9f13

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/team.js CHANGED
@@ -2,7 +2,7 @@ const { EventEmitter } = require('events');
2
2
  const pick = require('lodash/pick');
3
3
  const defaults = require('lodash/defaults');
4
4
  const cloneDeep = require('lodash/cloneDeep');
5
- const joinUrl = require('url-join');
5
+ const { joinURL } = require('ufo');
6
6
 
7
7
  const logger = require('@abtnode/logger')('@abtnode/core:api:team');
8
8
  const {
@@ -511,7 +511,7 @@ class TeamAPI extends EventEmitter {
511
511
  role,
512
512
  }),
513
513
  endpoint: getPassportStatusEndpoint({
514
- baseUrl: joinUrl(appUrl, WELLKNOWN_SERVICE_PATH_PREFIX),
514
+ baseUrl: joinURL(appUrl, WELLKNOWN_SERVICE_PATH_PREFIX),
515
515
  userDid,
516
516
  teamDid,
517
517
  }),
@@ -966,7 +966,7 @@ class TeamAPI extends EventEmitter {
966
966
  role,
967
967
  }),
968
968
  endpoint: getPassportStatusEndpoint({
969
- baseUrl: joinUrl(appUrl, WELLKNOWN_SERVICE_PATH_PREFIX),
969
+ baseUrl: joinURL(appUrl, WELLKNOWN_SERVICE_PATH_PREFIX),
970
970
  userDid,
971
971
  teamDid,
972
972
  }),
@@ -1,11 +1,13 @@
1
1
  const get = require('lodash/get');
2
2
  const camelCase = require('lodash/camelCase');
3
3
  const runScript = require('@abtnode/util/lib/run-script');
4
+ const { getSecurityNodeOptions } = require('@abtnode/util/lib/security');
4
5
 
5
6
  // eslint-disable-next-line global-require
6
7
  const logger = require('@abtnode/logger')(`${require('../../package.json').name}:blocklet:hooks`);
7
8
 
8
9
  const { getSafeEnv } = require('../util');
10
+ const states = require('../states');
9
11
 
10
12
  const runUserHook = async (label, hookName, args) => {
11
13
  const {
@@ -27,10 +29,16 @@ const runUserHook = async (label, hookName, args) => {
27
29
  }
28
30
 
29
31
  logger.info(`run hook:${hookName}:`, { label, hook });
32
+
33
+ const nodeInfo = await states.node.read();
30
34
  // FIXME @linchen timeout 应该动态设置或不设置
31
35
  await runScript(hook, [label, hookName].join(':'), {
32
36
  cwd: appDir,
33
- env: { ...getSafeEnv(env), BLOCKLET_HOOK_NAME: hookName },
37
+ env: {
38
+ ...getSafeEnv(env),
39
+ BLOCKLET_HOOK_NAME: hookName,
40
+ NODE_OPTIONS: getSecurityNodeOptions({ environmentObj: env, ...args }, nodeInfo.enableFileSystemIsolation),
41
+ },
34
42
  silent,
35
43
  output: outputFile,
36
44
  error: errorFile,
@@ -5,6 +5,7 @@ const path = require('path');
5
5
  const flat = require('flat');
6
6
  const LRU = require('lru-cache');
7
7
  const get = require('lodash/get');
8
+ const uniq = require('lodash/uniq');
8
9
  const omit = require('lodash/omit');
9
10
  const merge = require('lodash/merge');
10
11
  const pick = require('lodash/pick');
@@ -15,7 +16,7 @@ const { sign } = require('@arcblock/jwt');
15
16
  const { isInServerlessMode } = require('@abtnode/util/lib/serverless');
16
17
  const sleep = require('@abtnode/util/lib/sleep');
17
18
  const getBlockletInfo = require('@blocklet/meta/lib/info');
18
- const joinUrl = require('url-join');
19
+ const { joinURL } = require('ufo');
19
20
  const { sendToUser } = require('@blocklet/sdk/lib/util/send-notification');
20
21
 
21
22
  const logger = require('@abtnode/logger')('@abtnode/core:blocklet:manager');
@@ -614,7 +615,6 @@ class DiskBlockletManager extends BaseBlockletManager {
614
615
  if (!blocklet.children) {
615
616
  return componentDids;
616
617
  }
617
-
618
618
  const targetDid = !inputComponentDids?.length ? componentDids[0] : inputComponentDids[0];
619
619
 
620
620
  const canStartStatus = {
@@ -629,26 +629,37 @@ class DiskBlockletManager extends BaseBlockletManager {
629
629
  filter: (child) => atomic || canStartStatus[child.status],
630
630
  });
631
631
 
632
- // 让当前的组件的状态提前变成 starting, 不然用户会很奇怪, 明明点了启动, 但是当前组件没变化.
633
- const targetChild = blocklet.children.find((x) => x.meta.did === targetDid);
634
- const doc = await states.blocklet.setBlockletStatus(blocklet.meta?.did, BlockletStatus.starting, {
635
- componentDids: [targetDid],
632
+ logger.info('start required components', {
633
+ did: blocklet.meta.did,
634
+ targetDid,
635
+ componentDids,
636
+ inputComponentDids,
637
+ checkHealthImmediately,
638
+ requiredDidsLayers,
636
639
  });
637
- targetChild.status = BlockletStatus.starting;
638
- this.emit(BlockletEvents.statusChange, doc);
639
640
 
640
- // start by dependency
641
- for (const dids of requiredDidsLayers) {
642
- if (atomic) {
643
- await this._start({ blocklet, throwOnError, checkHealthImmediately, e2eMode, componentDids: dids }, context);
644
- } else {
645
- const tasks = dids.map(
646
- (x) => () =>
647
- this._start({ blocklet, throwOnError, checkHealthImmediately, e2eMode, componentDids: [x] }, context)
648
- );
649
- await pAll(tasks, { concurrency: 4 }).catch((err) => {
650
- throw new Error(err.errors.join(', '));
651
- });
641
+ // 让当前的组件的状态提前变成 starting, 不然用户会很奇怪, 明明点了启动, 但是当前组件没变化.
642
+ if (requiredDidsLayers.length) {
643
+ const targetChild = blocklet.children.find((x) => x.meta.did === targetDid);
644
+ const doc = await states.blocklet.setBlockletStatus(blocklet.meta?.did, BlockletStatus.starting, {
645
+ componentDids: [targetDid],
646
+ });
647
+ targetChild.status = BlockletStatus.starting;
648
+ this.emit(BlockletEvents.statusChange, doc);
649
+
650
+ // start by dependency
651
+ for (const dids of requiredDidsLayers) {
652
+ if (atomic) {
653
+ await this._start({ blocklet, throwOnError, checkHealthImmediately, e2eMode, componentDids: dids }, context);
654
+ } else {
655
+ const tasks = dids.map(
656
+ (x) => () =>
657
+ this._start({ blocklet, throwOnError, checkHealthImmediately, e2eMode, componentDids: [x] }, context)
658
+ );
659
+ await pAll(tasks, { concurrency: 4 }).catch((err) => {
660
+ throw new Error(err.errors.join(', '));
661
+ });
662
+ }
652
663
  }
653
664
  }
654
665
 
@@ -658,12 +669,13 @@ class DiskBlockletManager extends BaseBlockletManager {
658
669
  }
659
670
 
660
671
  async start(
661
- { did, throwOnError, checkHealthImmediately = false, e2eMode = false, componentDids: _inputComponentDids, atomic },
672
+ { did, throwOnError, checkHealthImmediately = false, e2eMode = false, componentDids: inputComponentDids, atomic },
662
673
  context
663
674
  ) {
664
675
  const blocklet = await this.ensureBlocklet(did, { e2eMode });
665
- const inputComponentDids = Array.from(new Set(_inputComponentDids || []));
666
- let componentDids = inputComponentDids?.length ? inputComponentDids : blocklet.children.map((x) => x.meta.did);
676
+ let componentDids = uniq(
677
+ inputComponentDids?.length ? inputComponentDids : blocklet.children.map((x) => x.meta.did)
678
+ );
667
679
 
668
680
  // sync component config before at first to ensure resource component config is ready
669
681
  const serverSk = (await states.node.read()).sk;
@@ -2787,7 +2799,7 @@ class DiskBlockletManager extends BaseBlockletManager {
2787
2799
  * @type {import('@abtnode/client').NodeState}
2788
2800
  */
2789
2801
  const node = await states.node.read();
2790
- referrer = joinUrl(
2802
+ referrer = joinURL(
2791
2803
  `https://${encode(node.did)}.${DEFAULT_DID_DOMAIN}`,
2792
2804
  node.routing.adminPath,
2793
2805
  `/blocklets/${did}/storage`
@@ -3637,11 +3649,17 @@ class DiskBlockletManager extends BaseBlockletManager {
3637
3649
  }
3638
3650
  }
3639
3651
  if (runningDids.length) {
3640
- try {
3641
- await this.start({ did, componentDids: runningDids }, context);
3642
- logger.info('started blocklet for upgrading', { did, version, runningDids });
3643
- } catch (error) {
3644
- logger.error('failed to start blocklet for upgrading', { did, version, runningDids, error });
3652
+ const initialized = !!blocklet.settings?.initialized;
3653
+ if (initialized) {
3654
+ try {
3655
+ await this.start({ did, componentDids: runningDids }, context);
3656
+ logger.info('started blocklet for upgrading', { did, version, runningDids });
3657
+ } catch (error) {
3658
+ logger.error('failed to start blocklet for upgrading', { did, version, runningDids, error });
3659
+ }
3660
+ } else {
3661
+ await states.blocklet.setBlockletStatus(did, BlockletStatus.stopped, { componentDids: runningDids });
3662
+ logger.info('set blocklet as stopped since not initialized', { did, version, runningDids });
3645
3663
  }
3646
3664
  }
3647
3665
  if (stoppedDids.length) {
@@ -4468,7 +4486,7 @@ class FederatedBlockletManager extends DiskBlockletManager {
4468
4486
  async joinFederatedLogin({ appUrl, did }, context) {
4469
4487
  const url = new URL(appUrl);
4470
4488
  // master service api 的地址
4471
- url.pathname = joinUrl(WELLKNOWN_SERVICE_PATH_PREFIX, '/api/federated/join');
4489
+ url.pathname = joinURL(WELLKNOWN_SERVICE_PATH_PREFIX, '/api/federated/join');
4472
4490
 
4473
4491
  const blocklet = await this.getBlocklet(did);
4474
4492
  const nodeInfo = await states.node.read();
@@ -4485,7 +4503,7 @@ class FederatedBlockletManager extends DiskBlockletManager {
4485
4503
  aliasDomain: domainAliases.map((x) => x.value),
4486
4504
  appLogo:
4487
4505
  blocklet.environmentObj.BLOCKLET_APP_LOGO ||
4488
- normalizePathPrefix(joinUrl(WELLKNOWN_SERVICE_PATH_PREFIX, '/blocklet/logo')) ||
4506
+ normalizePathPrefix(joinURL(WELLKNOWN_SERVICE_PATH_PREFIX, '/blocklet/logo')) ||
4489
4507
  '/',
4490
4508
  appLogoRect: blocklet.environmentObj.BLOCKLET_APP_LOGO_RECT,
4491
4509
  did: permanentWallet.address,
@@ -1,6 +1,7 @@
1
1
  const path = require('path');
2
2
 
3
3
  const logger = require('@abtnode/logger')('@abtnode/core:install-component-upload');
4
+ const uniq = require('lodash/uniq');
4
5
  const getComponentProcessId = require('@blocklet/meta/lib/get-component-process-id');
5
6
  const { isInProgress, hasStartEngine } = require('@blocklet/meta/lib/util');
6
7
 
@@ -119,7 +120,7 @@ const installComponentFromUpload = async ({
119
120
  // backup rollback data
120
121
  await manager._rollbackCache.backup({ did: newBlocklet.meta.did, action, oldBlocklet });
121
122
 
122
- const componentDids = [newChild.meta.did, ...newChildren.map((x) => x.meta.did)];
123
+ const componentDids = uniq([newChild.meta.did, ...newChildren.map((x) => x.meta.did)]);
123
124
 
124
125
  await manager._downloadAndInstall({
125
126
  blocklet: newBlocklet,
@@ -1,7 +1,7 @@
1
1
  const { sign } = require('@arcblock/jwt');
2
2
 
3
3
  const logger = require('@abtnode/logger')('@abtnode/core:install-component-url');
4
-
4
+ const uniq = require('lodash/uniq');
5
5
  const { isFreeBlocklet, hasStartEngine } = require('@blocklet/meta/lib/util');
6
6
  const { titleSchema, updateMountPointSchema } = require('@blocklet/meta/lib/schema');
7
7
  const hasReservedKey = require('@blocklet/meta/lib/has-reserved-key');
@@ -141,7 +141,7 @@ const installComponentFromUrl = async ({
141
141
  throw err;
142
142
  }
143
143
 
144
- const componentDids = [newChild.meta.did, ...newChildren.map((x) => x.meta.did)];
144
+ const componentDids = uniq([newChild.meta.did, ...newChildren.map((x) => x.meta.did)]);
145
145
 
146
146
  // new blocklet
147
147
  const newBlocklet = await states.blocklet.setBlockletStatus(rootDid, BlockletStatus.waiting, { componentDids });
@@ -1,4 +1,4 @@
1
- const EventEmitter = require('events');
1
+ const { EventEmitter } = require('events');
2
2
 
3
3
  const cloneDeep = require('lodash/cloneDeep');
4
4
  const pLimit = require('p-limit');
@@ -1,4 +1,4 @@
1
- const EventEmitter = require('events');
1
+ const { EventEmitter } = require('events');
2
2
  const dayjs = require('@abtnode/util/lib/dayjs');
3
3
  const pick = require('lodash/pick');
4
4
  const cloneDeep = require('lodash/cloneDeep');
@@ -10,7 +10,7 @@ const get = require('lodash/get');
10
10
  const cloneDeep = require('lodash/cloneDeep');
11
11
  const groupBy = require('lodash/groupBy');
12
12
  const isEqual = require('lodash/isEqual');
13
- const joinUrl = require('url-join');
13
+ const { joinURL } = require('ufo');
14
14
  const {
15
15
  replaceSlotToIp,
16
16
  findComponentById,
@@ -288,7 +288,7 @@ const ensureLatestInterfaceInfo = async (sites = []) => {
288
288
  if (rule.isProtected && rule.to.target === WELLKNOWN_SERVICE_PATH_PREFIX) {
289
289
  return rule;
290
290
  }
291
- if (rule.isProtected && rule.to.target === joinUrl(WELLKNOWN_SERVICE_PATH_PREFIX, USER_AVATAR_PATH_PREFIX)) {
291
+ if (rule.isProtected && rule.to.target === joinURL(WELLKNOWN_SERVICE_PATH_PREFIX, USER_AVATAR_PATH_PREFIX)) {
292
292
  return rule;
293
293
  }
294
294
 
@@ -359,7 +359,7 @@ const ensureWellknownRule = async (sites = []) => {
359
359
  const rule = grouped[groupPathPrefix][0];
360
360
 
361
361
  // Serve blocklet service always
362
- const servicePathPrefix = joinUrl(groupPathPrefix, WELLKNOWN_SERVICE_PATH_PREFIX);
362
+ const servicePathPrefix = joinURL(groupPathPrefix, WELLKNOWN_SERVICE_PATH_PREFIX);
363
363
  if (!site.rules.some((x) => x.from.pathPrefix === servicePathPrefix)) {
364
364
  site.rules.push({
365
365
  id: rule.id,
@@ -380,7 +380,7 @@ const ensureWellknownRule = async (sites = []) => {
380
380
  }
381
381
 
382
382
  // Cache user avatar from gateway
383
- const avatarPathPrefix = joinUrl(servicePathPrefix, USER_AVATAR_PATH_PREFIX);
383
+ const avatarPathPrefix = joinURL(servicePathPrefix, USER_AVATAR_PATH_PREFIX);
384
384
  if (!site.rules.some((x) => x.from.pathPrefix === avatarPathPrefix)) {
385
385
  site.rules.push({
386
386
  id: rule.id,
@@ -492,7 +492,7 @@ const ensureBlockletWellknownRules = (sites, blocklets) => {
492
492
 
493
493
  const tmpMountPoint = mountPoint || blocklet.mountPoint;
494
494
  if (tmpMountPoint) {
495
- pathPrefix = joinUrl(tmpMountPoint, pathPrefix);
495
+ pathPrefix = joinURL(tmpMountPoint, pathPrefix);
496
496
  }
497
497
 
498
498
  const port = findInterfacePortByName(blocklet, tmpInterface.name);
@@ -585,7 +585,7 @@ const expandComponentRules = (sites = [], blocklets) => {
585
585
  newRule.from.pathPrefix = baseRule.from.pathPrefix;
586
586
  newRule.to.pageGroup = baseRule.to.pageGroup;
587
587
  } else {
588
- newRule.from.pathPrefix = joinUrl(baseRule.from.pathPrefix, x.mountPoint);
588
+ newRule.from.pathPrefix = joinURL(baseRule.from.pathPrefix, x.mountPoint);
589
589
  }
590
590
 
591
591
  expandedRules.push(newRule);
@@ -633,7 +633,7 @@ const ensureBlockletCache = (sites = [], blocklets) => {
633
633
  const cacheable = get(findWebInterface(component), 'cacheable', []);
634
634
  cacheable.forEach((cachePrefix) => {
635
635
  const clone = cloneDeep(rule);
636
- clone.from.pathPrefix = joinUrl(rule.from.pathPrefix, cachePrefix);
636
+ clone.from.pathPrefix = joinURL(rule.from.pathPrefix, cachePrefix);
637
637
  clone.to.cacheGroup = isServiceFeDevelopment ? '' : 'blockletProxy';
638
638
  clone.to.targetPrefix = cachePrefix;
639
639
  clone.dynamic = true; // mark as dynamic to avoid redundant generated rules
@@ -674,7 +674,7 @@ const decompressCertificates = async (source, dest) => {
674
674
  return dest;
675
675
  };
676
676
 
677
- const joinCertDownUrl = (baseUrl, name) => joinUrl(baseUrl, '/certs', name);
677
+ const joinCertDownUrl = (baseUrl, name) => joinURL(baseUrl, '/certs', name);
678
678
 
679
679
  const getIpEchoCertDownloadUrl = (baseUrl) => joinCertDownUrl(baseUrl, 'ip-abtnet-io.tar.gz');
680
680
  const getDidDomainCertDownloadUrl = (baseUrl) => joinCertDownUrl(baseUrl, 'did-abtnet-io.tar.gz');
@@ -13,7 +13,7 @@ const toLower = require('lodash/toLower');
13
13
  const { EventEmitter } = require('events');
14
14
  const uuid = require('uuid');
15
15
  const isUrl = require('is-url');
16
- const joinUrl = require('url-join');
16
+ const { joinURL } = require('ufo');
17
17
  const cloneDeep = require('lodash/cloneDeep');
18
18
  const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
19
19
  const logger = require('@abtnode/logger')('@abtnode/core:router:manager');
@@ -704,7 +704,7 @@ class RouterManager extends EventEmitter {
704
704
  const blockletPrefix = normalizePathPrefix(rawRule.from.pathPrefix);
705
705
 
706
706
  // root component's mountPoint may not be '/'
707
- const rootComponentPrefix = joinUrl(blockletPrefix, blocklet.mountPoint || '/');
707
+ const rootComponentPrefix = joinURL(blockletPrefix, blocklet.mountPoint || '/');
708
708
  rawRule.from.pathPrefix = normalizePathPrefix(rootComponentPrefix);
709
709
 
710
710
  const isOccupiable = isGatewayBlocklet(blocklet.meta);
@@ -3,7 +3,7 @@
3
3
  const pick = require('lodash/pick');
4
4
  const get = require('lodash/get');
5
5
  const uniq = require('lodash/uniq');
6
- const joinUrl = require('url-join');
6
+ const { joinURL } = require('ufo');
7
7
  const { getDisplayName } = require('@blocklet/meta/lib/util');
8
8
  const { BLOCKLET_SITE_GROUP_SUFFIX, NODE_SERVICES } = require('@abtnode/constant');
9
9
  const logger = require('@abtnode/logger')('@abtnode/core:states:audit-log');
@@ -12,7 +12,7 @@ const BaseState = require('./base');
12
12
 
13
13
  const { parse } = require('../util/ua');
14
14
 
15
- const getServerInfo = (info) => `[${info.name}](${joinUrl(info.routing.adminPath, '/settings/about')})`;
15
+ const getServerInfo = (info) => `[${info.name}](${joinURL(info.routing.adminPath, '/settings/about')})`;
16
16
  /**
17
17
  * @description
18
18
  * @param {import('@abtnode/client').BlockletState} blocklet
@@ -21,7 +21,7 @@ const getServerInfo = (info) => `[${info.name}](${joinUrl(info.routing.adminPath
21
21
  * }} info
22
22
  * @returns {string}
23
23
  */
24
- const getBlockletInfo = (blocklet, info) => `[${getDisplayName(blocklet)}](${joinUrl(info.routing.adminPath, '/blocklets/', blocklet.meta.did, '/overview')})`; // prettier-ignore
24
+ const getBlockletInfo = (blocklet, info) => `[${getDisplayName(blocklet)}](${joinURL(info.routing.adminPath, '/blocklets/', blocklet.meta.did, '/overview')})`; // prettier-ignore
25
25
  const componentOrApplication = (componentDids) => (componentDids?.length ? 'component' : 'application');
26
26
  const getComponentNames = (blocklet, componentDids, withVersion) =>
27
27
  uniq(componentDids || [])
@@ -82,10 +82,10 @@ const expandUser = async (teamDid, userDid, passportId, info, node) => {
82
82
  const passport = user.passports.find((x) => x.id === passportId);
83
83
 
84
84
  if (teamDid === info.did) {
85
- return [`[${user.fullName}](${joinUrl(info.routing.adminPath, '/team/members')})`, passport ? passport.name : ''];
85
+ return [`[${user.fullName}](${joinURL(info.routing.adminPath, '/team/members')})`, passport ? passport.name : ''];
86
86
  }
87
87
 
88
- return [`[${user.fullName}](${joinUrl(info.routing.adminPath, '/blocklets/', teamDid, '/members')})`, passport ? passport.name : '']; // prettier-ignore
88
+ return [`[${user.fullName}](${joinURL(info.routing.adminPath, '/blocklets/', teamDid, '/members')})`, passport ? passport.name : '']; // prettier-ignore
89
89
  };
90
90
 
91
91
  /**
@@ -393,6 +393,7 @@ class User extends ExtendBase {
393
393
  'email',
394
394
  'avatar',
395
395
  'role',
396
+
396
397
  'locale',
397
398
  'extra',
398
399
  'lastLoginIp',
@@ -413,6 +414,8 @@ class User extends ExtendBase {
413
414
  if (updates.sourceAppPid) {
414
415
  delete updates.sourceAppPid;
415
416
  }
417
+ // 登录不再更新 locale
418
+ delete updates.locale;
416
419
  // update user, connectedAccount, passport
417
420
  updates.connectedAccounts = updateConnectedAccount(exist.connectedAccounts, user.connectedAccount);
418
421
  updated = await this.updateUser(exist.did, updates);
@@ -1,3 +1,4 @@
1
+ /* eslint-disable camelcase */
1
2
  /* eslint-disable no-await-in-loop */
2
3
 
3
4
  const fs = require('fs-extra');
@@ -27,7 +28,7 @@ const logger = require('@abtnode/logger')('@abtnode/core:util:blocklet');
27
28
  const pm2 = require('@abtnode/util/lib/async-pm2');
28
29
  const sleep = require('@abtnode/util/lib/sleep');
29
30
  const getPm2ProcessInfo = require('@abtnode/util/lib/get-pm2-process-info');
30
- const { formatEnv } = require('@abtnode/util/lib/security');
31
+ const { formatEnv, getSecurityNodeOptions } = require('@abtnode/util/lib/security');
31
32
  const ensureEndpointHealthy = require('@abtnode/util/lib/ensure-endpoint-healthy');
32
33
  const getFolderSize = require('@abtnode/util/lib/get-folder-size');
33
34
  const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
@@ -180,7 +181,9 @@ const getComponentDirs = (component, { dataDirs, ensure = false, ancestors = []
180
181
  };
181
182
 
182
183
  /**
183
- * @returns { cwd, script, args, environmentObj, interpreter, interpreterArgs }
184
+ * @param component {import('@abtnode/client').ComponentState & { environmentObj: {[key: string]: string } } }
185
+ * @returns {{cwd, script, args, environmentObj, interpreter, interpreterArgs}: { args: []}}
186
+ * @return {*}
184
187
  */
185
188
  const getComponentStartEngine = (component, { e2eMode = false } = {}) => {
186
189
  if (!hasStartEngine(component.meta)) {
@@ -208,14 +211,14 @@ const getComponentStartEngine = (component, { e2eMode = false } = {}) => {
208
211
  }
209
212
 
210
213
  let script = null;
211
- let interpreter = '';
212
- let interpreterArgs = '';
214
+ let interpreter;
215
+ let interpreterArgs = [];
213
216
  const environmentObj = {};
214
217
  let args = [];
215
218
 
216
219
  if (startFromDevEntry) {
217
220
  script = startFromDevEntry;
218
- } else if (group === 'dapp' || group === 'engine') {
221
+ } else if (group === 'dapp') {
219
222
  script = blockletEngineInfo.source || BLOCKLET_ENTRY_FILE;
220
223
  args = blockletEngineInfo.args || [];
221
224
  } else if (group === 'static') {
@@ -226,11 +229,18 @@ const getComponentStartEngine = (component, { e2eMode = false } = {}) => {
226
229
 
227
230
  if (component.mode !== BLOCKLET_MODES.DEVELOPMENT) {
228
231
  const engine = getEngine(blockletEngineInfo.interpreter);
229
- interpreter = engine.interpreter === 'node' ? '' : engine.interpreter;
230
- interpreterArgs = engine.args || '';
232
+ interpreter = engine.interpreter === 'node' ? undefined : engine.interpreter;
233
+ interpreterArgs = interpreterArgs.concat(engine.args ? [engine.args] : []);
231
234
  }
232
235
 
233
- return { cwd, script, args, environmentObj, interpreter, interpreterArgs };
236
+ return {
237
+ cwd,
238
+ script,
239
+ args,
240
+ environmentObj,
241
+ interpreter,
242
+ interpreterArgs: interpreterArgs.join(' ').trim(),
243
+ };
234
244
  };
235
245
 
236
246
  const getBlockletConfigObj = (blocklet, { excludeSecure } = {}) => {
@@ -248,7 +258,6 @@ const getBlockletConfigObj = (blocklet, { excludeSecure } = {}) => {
248
258
 
249
259
  return obj;
250
260
  };
251
-
252
261
  /**
253
262
  * set 'configs', configObj', 'environmentObj' to blocklet TODO
254
263
  * @param {*} blocklet
@@ -531,6 +540,12 @@ const startBlockletProcess = async (
531
540
 
532
541
  await forEachBlocklet(
533
542
  blocklet,
543
+ /**
544
+ *
545
+ * @param {import('@abtnode/client').BlockletState} b
546
+ * @param {*} param1
547
+ * @returns
548
+ */
534
549
  async (b, { ancestors }) => {
535
550
  if (b.meta.group === BlockletGroup.gateway) {
536
551
  return;
@@ -572,10 +587,10 @@ const startBlockletProcess = async (
572
587
  await installExternalDependencies({ appDir: env?.BLOCKLET_APP_DIR });
573
588
 
574
589
  // run hook
575
- await preFlight(b, { env });
590
+ await preFlight(b, { env: { ...env } });
576
591
 
577
592
  // run hook
578
- await preStart(b, { env });
593
+ await preStart(b, { env: { ...env } });
579
594
 
580
595
  // kill process if port is occupied
581
596
  try {
@@ -588,6 +603,9 @@ const startBlockletProcess = async (
588
603
  // start process
589
604
  const maxMemoryRestart = get(nodeInfo, 'runtimeConfig.blockletMaxMemoryLimit', BLOCKLET_MAX_MEM_LIMIT_IN_MB);
590
605
 
606
+ /**
607
+ * @type {pm2.StartOptions}
608
+ */
591
609
  const options = {
592
610
  namespace: 'blocklets',
593
611
  name: processId,
@@ -606,6 +624,7 @@ const startBlockletProcess = async (
606
624
  ...env,
607
625
  NODE_ENV: 'production',
608
626
  BLOCKLET_START_AT: now,
627
+ NODE_OPTIONS: getSecurityNodeOptions(b, nodeInfo.enableFileSystemIsolation),
609
628
  },
610
629
  script,
611
630
  args,
@@ -1,4 +1,4 @@
1
- const joinUrl = require('url-join');
1
+ const { joinURL } = require('ufo');
2
2
  const axios = require('@abtnode/util/lib/axios');
3
3
  const { DEFAULT_IP_DOMAIN, WELLKNOWN_SERVER_ADMIN_PATH } = require('@abtnode/constant');
4
4
  const logger = require('@abtnode/logger')('@abtnode/core:util:get-accessible-external-node-ip');
@@ -15,7 +15,7 @@ const timeout = process.env.NODE_ENV === 'test' ? 500 : 5000;
15
15
  const checkConnected = async ({ ip, info }) => {
16
16
  const { adminPath = WELLKNOWN_SERVER_ADMIN_PATH } = info.routing || {};
17
17
  const origin = `https://${getNodeDomain(ip)}`;
18
- const endpoint = joinUrl(origin, adminPath);
18
+ const endpoint = joinURL(origin, adminPath);
19
19
  await axios.get(endpoint, { timeout });
20
20
  };
21
21
 
package/lib/util/index.js CHANGED
@@ -8,7 +8,7 @@ const camelCase = require('lodash/camelCase');
8
8
  const get = require('lodash/get');
9
9
  const pickBy = require('lodash/pickBy');
10
10
  const { isFromPublicKey } = require('@arcblock/did');
11
- const joinUrl = require('url-join');
11
+ const { joinURL } = require('ufo');
12
12
  const { Certificate } = require('@fidm/x509');
13
13
  const getPortLib = require('get-port');
14
14
  const v8 = require('v8');
@@ -362,7 +362,7 @@ const getStateCrons = (states) => [
362
362
 
363
363
  const getDelegateState = async (chainHost, address) => {
364
364
  const result = await axios.post(
365
- joinUrl(chainHost, '/gql/'),
365
+ joinURL(chainHost, '/gql/'),
366
366
  JSON.stringify({
367
367
  query: `{
368
368
  getDelegateState(address: "${address}") {
@@ -388,7 +388,7 @@ const getDelegateState = async (chainHost, address) => {
388
388
  };
389
389
 
390
390
  const getNFTState = async (chainHost, nftId) => {
391
- const url = joinUrl(new URL(chainHost).origin, '/api/gql/');
391
+ const url = joinURL(new URL(chainHost).origin, '/api/gql/');
392
392
 
393
393
  const result = await axios.post(
394
394
  url,
@@ -1,6 +1,6 @@
1
1
  const path = require('path');
2
2
  const fs = require('fs-extra');
3
- const joinUrl = require('url-join');
3
+ const { joinURL } = require('ufo');
4
4
  const dayjs = require('@abtnode/util/lib/dayjs');
5
5
  const pick = require('lodash/pick');
6
6
  const uniq = require('lodash/uniq');
@@ -206,7 +206,7 @@ const setupAppOwner = async (node, sessionId) => {
206
206
  throw new Error(`Owner user not found from launcher: ${launcherUrl}`);
207
207
  }
208
208
  appOwnerProfile = pick(user, ['fullName', 'email', 'avatar']);
209
- const avatarBase64 = await getAvatarByUrl(joinUrl(launcherUrl, user.avatar));
209
+ const avatarBase64 = await getAvatarByUrl(joinURL(launcherUrl, user.avatar));
210
210
  appOwnerProfile.avatar = await extractUserAvatar(avatarBase64, { dataDir });
211
211
  logger.info('Create owner from launcher for blocklet', { appDid, ownerDid, ownerPk, sessionId, appOwnerProfile });
212
212
  } else {
@@ -242,7 +242,7 @@ const setupAppOwner = async (node, sessionId) => {
242
242
  endpoint: appUrl,
243
243
  }),
244
244
  endpoint: getPassportStatusEndpoint({
245
- baseUrl: joinUrl(appUrl, WELLKNOWN_SERVICE_PATH_PREFIX),
245
+ baseUrl: joinURL(appUrl, WELLKNOWN_SERVICE_PATH_PREFIX),
246
246
  userDid: ownerDid,
247
247
  teamDid: appDid,
248
248
  }),
@@ -3,7 +3,7 @@ const { default: axios } = require('axios');
3
3
  const isUrl = require('is-url');
4
4
  const isArray = require('lodash/isArray');
5
5
  const isEmpty = require('lodash/isEmpty');
6
- const joinUrl = require('url-join');
6
+ const { joinURL, withQuery } = require('ufo');
7
7
 
8
8
  /**
9
9
  * @description
@@ -35,7 +35,9 @@ function getBackupFilesUrlFromEndpoint(endpoint) {
35
35
  const spaceDid = strArray.at(-4);
36
36
  const appDid = strArray.at(-2);
37
37
 
38
- return joinUrl(prefix, 'space', spaceDid, 'apps', appDid, 'explorer', `?key=/apps/${appDid}/.did-objects/${appDid}/`);
38
+ return withQuery(joinURL(prefix, 'space', spaceDid, 'apps', appDid, 'explorer'), {
39
+ key: `/apps/${appDid}/.did-objects/${appDid}/`,
40
+ });
39
41
  }
40
42
 
41
43
  function getDIDSpacesUrlFromEndpoint(endpoint) {
package/lib/util/store.js CHANGED
@@ -1,4 +1,4 @@
1
- const joinUrl = require('url-join');
1
+ const { joinURL, withQuery } = require('ufo');
2
2
  const pick = require('lodash/pick');
3
3
  const isBase64 = require('is-base64');
4
4
 
@@ -48,7 +48,9 @@ const fixAndVerifyMetaFromStore = (meta) => {
48
48
 
49
49
  const getStoreMeta = async (registry) => {
50
50
  try {
51
- const url = joinUrl(registry, BLOCKLET_STORE_META_PATH, `?__t__=${Date.now()}`);
51
+ const url = withQuery(joinURL(registry, BLOCKLET_STORE_META_PATH), {
52
+ __t__: Date.now(),
53
+ });
52
54
  const { data } = await request.get(url);
53
55
 
54
56
  if (!data) {
@@ -69,7 +71,7 @@ const getStoreMeta = async (registry) => {
69
71
  } else if (isBase64(logoUrl, { allowMime: true })) {
70
72
  result.logoUrl = logoUrl;
71
73
  } else {
72
- result.logoUrl = joinUrl(registry, logoUrl);
74
+ result.logoUrl = joinURL(registry, logoUrl);
73
75
  }
74
76
  }
75
77
 
@@ -124,14 +126,14 @@ const resolveTarballURL = ({ did, tarball = '', storeUrl = '' }) => {
124
126
  return '';
125
127
  }
126
128
 
127
- return joinUrl(storeUrl, 'api', 'blocklets', did, tarball);
129
+ return joinURL(storeUrl, 'api', 'blocklets', did, tarball);
128
130
  };
129
131
 
130
132
  const getBlockletMetaUrl = ({ did, storeUrl }) =>
131
- joinUrl(storeUrl, BLOCKLET_STORE_API_PREFIX, `/blocklets/${did}/blocklet.json`);
133
+ joinURL(storeUrl, BLOCKLET_STORE_API_PREFIX, `/blocklets/${did}/blocklet.json`);
132
134
 
133
135
  const getBlockletMeta = async ({ did, storeUrl }) => {
134
- const url = joinUrl(storeUrl, BLOCKLET_STORE_API_PREFIX, `/blocklets/${did}/blocklet.json?__t__=${Date.now()}`);
136
+ const url = joinURL(storeUrl, BLOCKLET_STORE_API_PREFIX, `/blocklets/${did}/blocklet.json?__t__=${Date.now()}`);
135
137
 
136
138
  const { data } = await request.get(url);
137
139
  try {
@@ -39,6 +39,7 @@ const nodeInfoSchema = Joi.object({
39
39
  }),
40
40
  autoUpgrade: Joi.boolean(),
41
41
  enableWelcomePage: Joi.boolean(),
42
+ enableFileSystemIsolation: Joi.boolean(),
42
43
  diskAlertThreshold: Joi.number()
43
44
  .label('disk alarm threshold')
44
45
  .max(99)
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.16.28-beta-bfbab430",
6
+ "version": "1.16.28-beta-641c9f13",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,19 +19,19 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "Apache-2.0",
21
21
  "dependencies": {
22
- "@abtnode/analytics": "1.16.28-beta-bfbab430",
23
- "@abtnode/auth": "1.16.28-beta-bfbab430",
24
- "@abtnode/certificate-manager": "1.16.28-beta-bfbab430",
25
- "@abtnode/constant": "1.16.28-beta-bfbab430",
26
- "@abtnode/cron": "1.16.28-beta-bfbab430",
27
- "@abtnode/logger": "1.16.28-beta-bfbab430",
28
- "@abtnode/models": "1.16.28-beta-bfbab430",
29
- "@abtnode/queue": "1.16.28-beta-bfbab430",
30
- "@abtnode/rbac": "1.16.28-beta-bfbab430",
31
- "@abtnode/router-provider": "1.16.28-beta-bfbab430",
32
- "@abtnode/static-server": "1.16.28-beta-bfbab430",
33
- "@abtnode/timemachine": "1.16.28-beta-bfbab430",
34
- "@abtnode/util": "1.16.28-beta-bfbab430",
22
+ "@abtnode/analytics": "1.16.28-beta-641c9f13",
23
+ "@abtnode/auth": "1.16.28-beta-641c9f13",
24
+ "@abtnode/certificate-manager": "1.16.28-beta-641c9f13",
25
+ "@abtnode/constant": "1.16.28-beta-641c9f13",
26
+ "@abtnode/cron": "1.16.28-beta-641c9f13",
27
+ "@abtnode/logger": "1.16.28-beta-641c9f13",
28
+ "@abtnode/models": "1.16.28-beta-641c9f13",
29
+ "@abtnode/queue": "1.16.28-beta-641c9f13",
30
+ "@abtnode/rbac": "1.16.28-beta-641c9f13",
31
+ "@abtnode/router-provider": "1.16.28-beta-641c9f13",
32
+ "@abtnode/static-server": "1.16.28-beta-641c9f13",
33
+ "@abtnode/timemachine": "1.16.28-beta-641c9f13",
34
+ "@abtnode/util": "1.16.28-beta-641c9f13",
35
35
  "@arcblock/did": "1.18.123",
36
36
  "@arcblock/did-auth": "1.18.123",
37
37
  "@arcblock/did-ext": "^1.18.123",
@@ -42,20 +42,20 @@
42
42
  "@arcblock/pm2-events": "^0.0.5",
43
43
  "@arcblock/validator": "^1.18.123",
44
44
  "@arcblock/vc": "1.18.123",
45
- "@blocklet/constant": "1.16.28-beta-bfbab430",
46
- "@blocklet/env": "1.16.28-beta-bfbab430",
47
- "@blocklet/meta": "1.16.28-beta-bfbab430",
48
- "@blocklet/resolver": "1.16.28-beta-bfbab430",
49
- "@blocklet/sdk": "1.16.28-beta-bfbab430",
50
- "@blocklet/store": "1.16.28-beta-bfbab430",
51
- "@did-space/client": "^0.4.20",
45
+ "@blocklet/constant": "1.16.28-beta-641c9f13",
46
+ "@blocklet/env": "1.16.28-beta-641c9f13",
47
+ "@blocklet/meta": "1.16.28-beta-641c9f13",
48
+ "@blocklet/resolver": "1.16.28-beta-641c9f13",
49
+ "@blocklet/sdk": "1.16.28-beta-641c9f13",
50
+ "@blocklet/store": "1.16.28-beta-641c9f13",
51
+ "@did-space/client": "^0.5.1",
52
52
  "@fidm/x509": "^1.2.1",
53
53
  "@ocap/mcrypto": "1.18.123",
54
54
  "@ocap/util": "1.18.123",
55
55
  "@ocap/wallet": "1.18.123",
56
56
  "@slack/webhook": "^5.0.4",
57
57
  "archiver": "^7.0.1",
58
- "axios": "^0.27.2",
58
+ "axios": "^1.7.2",
59
59
  "axon": "^2.0.3",
60
60
  "chalk": "^4.1.2",
61
61
  "cross-spawn": "^7.0.3",
@@ -92,7 +92,7 @@
92
92
  "tar": "^6.1.11",
93
93
  "transliteration": "^2.3.5",
94
94
  "ua-parser-js": "^1.0.2",
95
- "url-join": "^4.0.1",
95
+ "ufo": "^1.5.3",
96
96
  "uuid": "^9.0.1",
97
97
  "valid-url": "^1.0.9",
98
98
  "xbytes": "^1.8.0"
@@ -103,5 +103,5 @@
103
103
  "jest": "^29.7.0",
104
104
  "unzipper": "^0.10.11"
105
105
  },
106
- "gitHead": "f1fbf0752de46be00d1faa0d54eb7d28016e0bb9"
106
+ "gitHead": "eb1fa63e4ed26fe5ba230845a318faa29408138b"
107
107
  }