@abtnode/core 1.16.13-beta-55b3e93d → 1.16.13-beta-423a40b1
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 +3 -0
- package/lib/blocklet/hooks.js +1 -1
- package/lib/blocklet/manager/disk.js +29 -4
- package/lib/blocklet/manager/helper/install-application-from-backup.js +3 -0
- package/lib/event.js +2 -0
- package/lib/index.js +20 -1
- package/lib/router/helper.js +59 -2
- package/lib/router/index.js +4 -0
- package/lib/router/manager.js +15 -15
- package/lib/states/audit-log.js +2 -0
- package/lib/states/blocklet.js +47 -26
- package/lib/util/blocklet.js +19 -218
- package/lib/util/launcher.js +1 -1
- package/lib/validators/router.js +27 -12
- package/lib/validators/util.js +12 -0
- package/package.json +19 -18
package/lib/api/team.js
CHANGED
|
@@ -340,6 +340,7 @@ class TeamAPI extends EventEmitter {
|
|
|
340
340
|
logger.info('user approval updated successfully', { teamDid, userDid: user.did, approved: user.approved });
|
|
341
341
|
|
|
342
342
|
this.emit(EVENTS.USER_UPDATED, { teamDid, user: doc2 });
|
|
343
|
+
this.emit(EVENTS.USER_PERMISSION_UPDATED, { teamDid, user: doc2 });
|
|
343
344
|
|
|
344
345
|
return doc2;
|
|
345
346
|
}
|
|
@@ -442,6 +443,7 @@ class TeamAPI extends EventEmitter {
|
|
|
442
443
|
logger.info('user passport revoked successfully', { teamDid, userDid, passportId });
|
|
443
444
|
|
|
444
445
|
this.emit(EVENTS.USER_UPDATED, { teamDid, user: doc });
|
|
446
|
+
this.emit(EVENTS.USER_PERMISSION_UPDATED, { teamDid, user: doc });
|
|
445
447
|
|
|
446
448
|
return doc;
|
|
447
449
|
}
|
|
@@ -458,6 +460,7 @@ class TeamAPI extends EventEmitter {
|
|
|
458
460
|
logger.info('user passport enabled successfully', { teamDid, userDid, passportId });
|
|
459
461
|
|
|
460
462
|
this.emit(EVENTS.USER_UPDATED, { teamDid, user: doc });
|
|
463
|
+
this.emit(EVENTS.USER_PERMISSION_UPDATED, { teamDid, user: doc });
|
|
461
464
|
|
|
462
465
|
return doc;
|
|
463
466
|
}
|
package/lib/blocklet/hooks.js
CHANGED
|
@@ -30,7 +30,7 @@ const runUserHook = async (label, hookName, args) => {
|
|
|
30
30
|
// FIXME @linchen timeout 应该动态设置或不设置
|
|
31
31
|
await runScript(hook, [label, hookName].join(':'), {
|
|
32
32
|
cwd: appDir,
|
|
33
|
-
env: getSafeEnv(env),
|
|
33
|
+
env: { ...getSafeEnv(env), BLOCKLET_HOOK_NAME: hookName },
|
|
34
34
|
silent,
|
|
35
35
|
output: outputFile,
|
|
36
36
|
error: errorFile,
|
|
@@ -9,6 +9,7 @@ const omit = require('lodash/omit');
|
|
|
9
9
|
const merge = require('lodash/merge');
|
|
10
10
|
const pick = require('lodash/pick');
|
|
11
11
|
const isEmpty = require('lodash/isEmpty');
|
|
12
|
+
const cloneDeep = require('lodash/cloneDeep');
|
|
12
13
|
const { isNFTExpired, getNftExpirationDate } = require('@abtnode/util/lib/nft');
|
|
13
14
|
const didDocument = require('@abtnode/util/lib/did-document');
|
|
14
15
|
const { sign } = require('@arcblock/jwt');
|
|
@@ -142,6 +143,7 @@ const RollbackCache = require('./helper/rollback-cache');
|
|
|
142
143
|
const { migrateApplicationToStructV2 } = require('./helper/migrate-application-to-struct-v2');
|
|
143
144
|
const { getBackupFilesUrlFromEndpoint, getBackupEndpoint, getSpaceNameByEndpoint } = require('../../util/spaces');
|
|
144
145
|
const { validateAddSpaceGateway, validateUpdateSpaceGateway } = require('../../validators/space-gateway');
|
|
146
|
+
const { sessionConfigSchema } = require('../../validators/util');
|
|
145
147
|
|
|
146
148
|
const { formatEnvironments, getBlockletMeta, validateOwner } = util;
|
|
147
149
|
|
|
@@ -539,7 +541,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
539
541
|
entity: 'blocklet',
|
|
540
542
|
action: 'check_if_started',
|
|
541
543
|
...params,
|
|
542
|
-
id: did,
|
|
544
|
+
id: `${did}/${(componentDids || []).join(',')}`,
|
|
543
545
|
});
|
|
544
546
|
}
|
|
545
547
|
|
|
@@ -701,7 +703,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
701
703
|
const ticket = this.startQueue.push({
|
|
702
704
|
entity: 'blocklet',
|
|
703
705
|
action: 'restart',
|
|
704
|
-
id: did,
|
|
706
|
+
id: `${did}/${(componentDids || []).join(',')}`,
|
|
705
707
|
did,
|
|
706
708
|
componentDids,
|
|
707
709
|
context,
|
|
@@ -1385,6 +1387,27 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1385
1387
|
return this.getBlocklet(rootDid);
|
|
1386
1388
|
}
|
|
1387
1389
|
|
|
1390
|
+
async updateAppSessionConfig({ did, config }) {
|
|
1391
|
+
const validateConfig = await sessionConfigSchema.validateAsync(config);
|
|
1392
|
+
|
|
1393
|
+
const blocklet = await this.getBlocklet(did);
|
|
1394
|
+
if (!blocklet) {
|
|
1395
|
+
throw new Error('blocklet does not exist');
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
const sessionConfig = cloneDeep(blocklet.settings.session || {});
|
|
1399
|
+
|
|
1400
|
+
sessionConfig.cacheTtl = validateConfig.cacheTtl;
|
|
1401
|
+
sessionConfig.ttl = validateConfig.ttl;
|
|
1402
|
+
|
|
1403
|
+
await states.blockletExtras.setSettings(blocklet.meta.did, { session: sessionConfig });
|
|
1404
|
+
|
|
1405
|
+
const newState = await this.getBlocklet(did);
|
|
1406
|
+
this.emit(BlockletEvents.updated, newState);
|
|
1407
|
+
|
|
1408
|
+
return newState;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1388
1411
|
// eslint-disable-next-line no-unused-vars
|
|
1389
1412
|
async getRuntimeHistory({ did, hours }, context) {
|
|
1390
1413
|
const metaDid = await states.blocklet.getBlockletMetaDid(did);
|
|
@@ -1944,7 +1967,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1944
1967
|
}
|
|
1945
1968
|
|
|
1946
1969
|
async _onCheckIfStarted(jobInfo, { throwOnError } = {}) {
|
|
1947
|
-
const
|
|
1970
|
+
const startedAt = Date.now();
|
|
1971
|
+
const { did, context, minConsecutiveTime = 2000, timeout, componentDids } = jobInfo;
|
|
1948
1972
|
const blocklet = await this.getBlocklet(did);
|
|
1949
1973
|
|
|
1950
1974
|
const { meta } = blocklet;
|
|
@@ -1965,6 +1989,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1965
1989
|
});
|
|
1966
1990
|
|
|
1967
1991
|
this.emit(BlockletEvents.started, res);
|
|
1992
|
+
logger.info('blocklet healthy', { did, name, time: Date.now() - startedAt });
|
|
1968
1993
|
} catch (error) {
|
|
1969
1994
|
const status = await states.blocklet.getBlockletStatus(did);
|
|
1970
1995
|
if ([BlockletStatus.stopping, BlockletStatus.stopped].includes(status)) {
|
|
@@ -1974,7 +1999,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1974
1999
|
|
|
1975
2000
|
logger.error('check blocklet if started failed', { did, name, context, timeout, error });
|
|
1976
2001
|
|
|
1977
|
-
await this.deleteProcess({ did }, context);
|
|
2002
|
+
await this.deleteProcess({ did, componentDids }, context);
|
|
1978
2003
|
await states.blocklet.setBlockletStatus(did, BlockletStatus.error, { componentDids });
|
|
1979
2004
|
|
|
1980
2005
|
this._createNotification(did, {
|
|
@@ -145,6 +145,9 @@ const installApplicationFromBackup = async ({
|
|
|
145
145
|
extra.controller = controller;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
// 在旧版本中安装的 Blocklet 不存在 extra.meta 字段,这里补充一下
|
|
149
|
+
extra.meta = extra.meta || { did, name: appName };
|
|
150
|
+
|
|
148
151
|
await states.blockletExtras.insert(extra);
|
|
149
152
|
logger.info('blocklet extra is copied successfully');
|
|
150
153
|
|
package/lib/event.js
CHANGED
|
@@ -105,6 +105,7 @@ module.exports = ({
|
|
|
105
105
|
|
|
106
106
|
// Emit events to node listener
|
|
107
107
|
// Call eventHandler
|
|
108
|
+
// NOT emit events to event hub
|
|
108
109
|
const onInternalEvent = (name, data) => {
|
|
109
110
|
events.emit(name, data);
|
|
110
111
|
if (typeof eventHandler === 'function') {
|
|
@@ -421,6 +422,7 @@ module.exports = ({
|
|
|
421
422
|
listen(teamAPI, EVENTS.USER_ADDED, onEvent);
|
|
422
423
|
listen(teamAPI, EVENTS.USER_REMOVED, onEvent);
|
|
423
424
|
listen(teamAPI, EVENTS.USER_UPDATED, onEvent);
|
|
425
|
+
listen(teamAPI, EVENTS.USER_PERMISSION_UPDATED, onEvent);
|
|
424
426
|
listen(teamAPI, BlockletEvents.updated, onEvent);
|
|
425
427
|
listen(teamManager, BlockletEvents.storeChange, onEvent);
|
|
426
428
|
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const uniq = require('lodash/uniq');
|
|
3
4
|
const md5 = require('@abtnode/util/lib/md5');
|
|
4
5
|
const formatContext = require('@abtnode/util/lib/format-context');
|
|
5
6
|
const Cron = require('@abtnode/cron');
|
|
@@ -259,6 +260,7 @@ function ABTNode(options) {
|
|
|
259
260
|
configOAuth: blockletManager.configOAuth.bind(blockletManager),
|
|
260
261
|
configNotification: blockletManager.configNotification.bind(blockletManager),
|
|
261
262
|
updateWhoCanAccess: blockletManager.updateWhoCanAccess.bind(blockletManager),
|
|
263
|
+
updateAppSessionConfig: blockletManager.updateAppSessionConfig.bind(blockletManager),
|
|
262
264
|
updateComponentTitle: blockletManager.updateComponentTitle.bind(blockletManager),
|
|
263
265
|
updateComponentMountPoint: blockletManager.updateComponentMountPoint.bind(blockletManager),
|
|
264
266
|
backupBlocklet: blockletManager.backup.bind(blockletManager),
|
|
@@ -390,7 +392,24 @@ function ABTNode(options) {
|
|
|
390
392
|
|
|
391
393
|
// AuditLog
|
|
392
394
|
createAuditLog: (params) => states.auditLog.create(params, instance),
|
|
393
|
-
getAuditLogs:
|
|
395
|
+
getAuditLogs: async (params) => {
|
|
396
|
+
if (params.scope) {
|
|
397
|
+
const blocklet = await states.blocklet.getBlocklet(params.scope);
|
|
398
|
+
if (blocklet) {
|
|
399
|
+
params.scope = uniq(
|
|
400
|
+
[
|
|
401
|
+
params.scope,
|
|
402
|
+
blocklet.appDid,
|
|
403
|
+
blocklet.appPid,
|
|
404
|
+
blocklet.structV1Did,
|
|
405
|
+
...blocklet.migratedFrom.map((x) => x.appDid),
|
|
406
|
+
].filter(Boolean)
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return states.auditLog.findPaginated.call(states.auditLog, params);
|
|
412
|
+
},
|
|
394
413
|
|
|
395
414
|
// Routing
|
|
396
415
|
routerManager,
|
package/lib/router/helper.js
CHANGED
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const tar = require('tar');
|
|
6
|
+
const UUID = require('uuid');
|
|
6
7
|
const isUrl = require('is-url');
|
|
7
8
|
const get = require('lodash/get');
|
|
8
9
|
const cloneDeep = require('lodash/cloneDeep');
|
|
9
10
|
const groupBy = require('lodash/groupBy');
|
|
10
11
|
const isEqual = require('lodash/isEqual');
|
|
11
12
|
const joinUrl = require('url-join');
|
|
12
|
-
const { replaceSlotToIp, findComponentById, findWebInterface } = require('@blocklet/meta/lib/util');
|
|
13
|
+
const { replaceSlotToIp, findComponentById, findWebInterface, getComponentId } = require('@blocklet/meta/lib/util');
|
|
13
14
|
const { getProvider } = require('@abtnode/router-provider');
|
|
14
15
|
const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
|
|
15
16
|
const getTmpDir = require('@abtnode/util/lib/get-tmp-directory');
|
|
@@ -488,6 +489,60 @@ const ensureBlockletWellknownRules = (sites, blocklets) => {
|
|
|
488
489
|
.filter(Boolean);
|
|
489
490
|
};
|
|
490
491
|
|
|
492
|
+
// Expand component rules to blocklet rules
|
|
493
|
+
const isComponentRule = (x) => x.to.type === ROUTING_RULE_TYPES.COMPONENT;
|
|
494
|
+
const expandComponentRules = (sites = [], blocklets) => {
|
|
495
|
+
return sites
|
|
496
|
+
.map((site) => {
|
|
497
|
+
if (!site.domain.endsWith(BLOCKLET_SITE_GROUP_SUFFIX)) {
|
|
498
|
+
return site;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
if (site.componentExpanded) {
|
|
502
|
+
return site;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const blocklet = blocklets.find((x) => x.meta.did === site.blockletDid);
|
|
506
|
+
const components = blocklet.children.filter((x) => x.mountPoint !== '/' && x.mode === BLOCKLET_MODES.PRODUCTION);
|
|
507
|
+
const expandedRules = [];
|
|
508
|
+
|
|
509
|
+
site.rules.filter(isComponentRule).forEach((baseRule) => {
|
|
510
|
+
components.forEach((x) => {
|
|
511
|
+
const newRule = {
|
|
512
|
+
id: UUID.v4(),
|
|
513
|
+
groupId: baseRule.groupId,
|
|
514
|
+
from: {
|
|
515
|
+
groupPathPrefix: '/',
|
|
516
|
+
},
|
|
517
|
+
to: {
|
|
518
|
+
type: ROUTING_RULE_TYPES.BLOCKLET,
|
|
519
|
+
componentId: getComponentId(x, [blocklet]),
|
|
520
|
+
interfaceName: BLOCKLET_INTERFACE_PUBLIC,
|
|
521
|
+
port: findInterfacePortByName(x, BLOCKLET_INTERFACE_PUBLIC),
|
|
522
|
+
did: blocklet.meta.did,
|
|
523
|
+
target: '/',
|
|
524
|
+
},
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
if (x.meta.did === baseRule.to.componentId) {
|
|
528
|
+
newRule.from.pathPrefix = baseRule.from.pathPrefix;
|
|
529
|
+
newRule.to.pageGroup = baseRule.to.pageGroup;
|
|
530
|
+
} else {
|
|
531
|
+
newRule.from.pathPrefix = joinUrl(baseRule.from.pathPrefix, x.mountPoint);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
expandedRules.push(newRule);
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
site.rules = site.rules.filter((x) => !isComponentRule(x)).concat(expandedRules);
|
|
539
|
+
site.componentExpanded = true;
|
|
540
|
+
|
|
541
|
+
return site;
|
|
542
|
+
})
|
|
543
|
+
.filter(Boolean);
|
|
544
|
+
};
|
|
545
|
+
|
|
491
546
|
const ensureBlockletCache = (sites = [], blocklets) => {
|
|
492
547
|
return sites
|
|
493
548
|
.map((site) => {
|
|
@@ -545,12 +600,13 @@ const ensureLatestInfo = async (sites = [], { withDefaultCors = true } = {}) =>
|
|
|
545
600
|
let result = await ensureLatestNodeInfo(sites, { withDefaultCors });
|
|
546
601
|
result = await ensureBlockletDid(result);
|
|
547
602
|
result = await filterSitesForRemovedBlocklets(sites, blocklets);
|
|
548
|
-
result = await ensureBlockletWellknownRules(result, blocklets);
|
|
549
603
|
result = await ensureBlockletCache(result, blocklets);
|
|
550
604
|
result = await ensureWellknownRule(result);
|
|
551
605
|
result = await ensureCorsForWebWallet(result);
|
|
552
606
|
result = await ensureCorsForDidSpace(result, blocklets);
|
|
553
607
|
result = await ensureLatestInterfaceInfo(result);
|
|
608
|
+
result = await ensureBlockletWellknownRules(result, blocklets);
|
|
609
|
+
result = await expandComponentRules(result, blocklets);
|
|
554
610
|
|
|
555
611
|
return result;
|
|
556
612
|
};
|
|
@@ -1457,3 +1513,4 @@ module.exports.ensureLatestInterfaceInfo = ensureLatestInterfaceInfo;
|
|
|
1457
1513
|
module.exports.ensureLatestInfo = ensureLatestInfo;
|
|
1458
1514
|
module.exports.ensureWellknownRule = ensureWellknownRule;
|
|
1459
1515
|
module.exports.ensureBlockletWellknownRules = ensureBlockletWellknownRules;
|
|
1516
|
+
module.exports.expandComponentRules = expandComponentRules;
|
package/lib/router/index.js
CHANGED
|
@@ -223,6 +223,7 @@ Router.formatSites = (sites = []) => {
|
|
|
223
223
|
did: rule.to.did,
|
|
224
224
|
componentId: rule.to.componentId,
|
|
225
225
|
cacheGroup: site.mode === BLOCKLET_MODES.PRODUCTION ? 'blockletJs' : '',
|
|
226
|
+
pageGroup: rule.to.pageGroup,
|
|
226
227
|
},
|
|
227
228
|
});
|
|
228
229
|
site.rules.push({
|
|
@@ -238,6 +239,7 @@ Router.formatSites = (sites = []) => {
|
|
|
238
239
|
did: rule.to.did,
|
|
239
240
|
componentId: rule.to.componentId,
|
|
240
241
|
cacheGroup: site.mode === BLOCKLET_MODES.PRODUCTION ? 'blockletJs' : '',
|
|
242
|
+
pageGroup: rule.to.pageGroup,
|
|
241
243
|
},
|
|
242
244
|
});
|
|
243
245
|
});
|
|
@@ -271,6 +273,7 @@ Router.formatSites = (sites = []) => {
|
|
|
271
273
|
type: ROUTING_RULE_TYPES.DAEMON,
|
|
272
274
|
port: daemonRule.to.port,
|
|
273
275
|
cacheGroup: site.mode === BLOCKLET_MODES.PRODUCTION ? 'blockletJs' : '',
|
|
276
|
+
pageGroup: rule.to.pageGroup,
|
|
274
277
|
did: rule.to.did,
|
|
275
278
|
},
|
|
276
279
|
});
|
|
@@ -287,6 +290,7 @@ Router.formatSites = (sites = []) => {
|
|
|
287
290
|
type: ROUTING_RULE_TYPES.DAEMON,
|
|
288
291
|
target: BLOCKLET_PROXY_PATH_PREFIX,
|
|
289
292
|
cacheGroup: !isServiceFeDevelopment && site.mode === BLOCKLET_MODES.PRODUCTION ? 'blockletProxy' : '',
|
|
293
|
+
pageGroup: rule.to.pageGroup,
|
|
290
294
|
did: rule.to.did,
|
|
291
295
|
},
|
|
292
296
|
});
|
package/lib/router/manager.js
CHANGED
|
@@ -598,30 +598,30 @@ class RouterManager extends EventEmitter {
|
|
|
598
598
|
|
|
599
599
|
/**
|
|
600
600
|
* get all rules to be add or update to site from root rule
|
|
601
|
-
* @param {*}
|
|
601
|
+
* @param {*} rawRule
|
|
602
602
|
*/
|
|
603
|
-
async getRulesForMutation(
|
|
604
|
-
if (
|
|
605
|
-
return [
|
|
603
|
+
async getRulesForMutation(rawRule) {
|
|
604
|
+
if (rawRule.to.type !== ROUTING_RULE_TYPES.BLOCKLET) {
|
|
605
|
+
return [rawRule];
|
|
606
606
|
}
|
|
607
607
|
|
|
608
608
|
const rules = [];
|
|
609
609
|
|
|
610
610
|
// get child rules
|
|
611
|
-
const blocklet = await states.blocklet.getBlocklet(
|
|
611
|
+
const blocklet = await states.blocklet.getBlocklet(rawRule.to.did);
|
|
612
612
|
|
|
613
613
|
// blocklet may be mounted in relative prefix (for old usage), so blockletPrefix may not be '/'
|
|
614
|
-
// blocklet prefix is the origin pathPrefix in
|
|
615
|
-
const blockletPrefix = normalizePathPrefix(
|
|
614
|
+
// blocklet prefix is the origin pathPrefix in rawRule
|
|
615
|
+
const blockletPrefix = normalizePathPrefix(rawRule.from.pathPrefix);
|
|
616
616
|
|
|
617
617
|
// root component's mountPoint may not be '/'
|
|
618
618
|
const rootComponentPrefix = joinUrl(blockletPrefix, blocklet.mountPoint || '/');
|
|
619
|
-
|
|
619
|
+
rawRule.from.pathPrefix = normalizePathPrefix(rootComponentPrefix);
|
|
620
620
|
|
|
621
621
|
const isOccupiable = blocklet.meta.group === BlockletGroup.gateway;
|
|
622
622
|
|
|
623
623
|
if (!isOccupiable) {
|
|
624
|
-
rules.push(
|
|
624
|
+
rules.push(rawRule);
|
|
625
625
|
}
|
|
626
626
|
|
|
627
627
|
forEachChildSync(blocklet, (component, { id, ancestors }) => {
|
|
@@ -650,7 +650,7 @@ class RouterManager extends EventEmitter {
|
|
|
650
650
|
mountPoint
|
|
651
651
|
);
|
|
652
652
|
|
|
653
|
-
const occupied = normalizePathPrefix(pathPrefix) === normalizePathPrefix(
|
|
653
|
+
const occupied = normalizePathPrefix(pathPrefix) === normalizePathPrefix(rawRule.from.pathPrefix);
|
|
654
654
|
|
|
655
655
|
if (occupied && !isOccupiable) {
|
|
656
656
|
return;
|
|
@@ -658,8 +658,8 @@ class RouterManager extends EventEmitter {
|
|
|
658
658
|
|
|
659
659
|
// if is root path, child rule become root rule
|
|
660
660
|
const childRule = {
|
|
661
|
-
id: occupied ?
|
|
662
|
-
groupId:
|
|
661
|
+
id: occupied ? rawRule.id : uuid.v4(),
|
|
662
|
+
groupId: rawRule.id,
|
|
663
663
|
from: {
|
|
664
664
|
pathPrefix: normalizePathPrefix(pathPrefix),
|
|
665
665
|
groupPathPrefix: blockletPrefix,
|
|
@@ -667,11 +667,11 @@ class RouterManager extends EventEmitter {
|
|
|
667
667
|
to: {
|
|
668
668
|
type: ROUTING_RULE_TYPES.BLOCKLET,
|
|
669
669
|
port: findInterfacePortByName(component, childWebInterface.name),
|
|
670
|
-
did:
|
|
671
|
-
interfaceName:
|
|
670
|
+
did: rawRule.to.did, // root component did
|
|
671
|
+
interfaceName: rawRule.to.interfaceName, // root component interface
|
|
672
672
|
componentId: id,
|
|
673
673
|
},
|
|
674
|
-
isProtected: occupied ?
|
|
674
|
+
isProtected: occupied ? rawRule.isProtected : true,
|
|
675
675
|
};
|
|
676
676
|
|
|
677
677
|
rules.push(childRule);
|
package/lib/states/audit-log.js
CHANGED
|
@@ -167,6 +167,8 @@ const getLogContent = async (action, args, context, result, info, node) => {
|
|
|
167
167
|
return `removed blocklet store ${args.url}`;
|
|
168
168
|
case 'selectBlockletStore':
|
|
169
169
|
return `selected blocklet store ${args.url}`;
|
|
170
|
+
case 'updateAppSessionConfig':
|
|
171
|
+
return `updated session config: ${JSON.stringify(args.config)}`;
|
|
170
172
|
|
|
171
173
|
// teams: members/passports
|
|
172
174
|
case 'addUser':
|
package/lib/states/blocklet.js
CHANGED
|
@@ -153,6 +153,7 @@ class BlockletState extends BaseState {
|
|
|
153
153
|
this.defaultPort = config.blockletPort || 5555;
|
|
154
154
|
// @didMap: { [did: string]: metaDid: string }
|
|
155
155
|
this.didMap = new Map();
|
|
156
|
+
this.statusLocks = new Map();
|
|
156
157
|
}
|
|
157
158
|
|
|
158
159
|
async getBlocklet(did, { decryptSk = true } = {}) {
|
|
@@ -207,6 +208,8 @@ class BlockletState extends BaseState {
|
|
|
207
208
|
|
|
208
209
|
this.didMap.delete(doc.meta?.did);
|
|
209
210
|
this.didMap.delete(doc.appDid);
|
|
211
|
+
this.statusLocks.delete(doc.meta?.did);
|
|
212
|
+
this.statusLocks.delete(doc.appDid);
|
|
210
213
|
|
|
211
214
|
this.emit('remove', doc);
|
|
212
215
|
return formatBlocklet(doc, 'onRead', this.config.dek);
|
|
@@ -505,39 +508,49 @@ class BlockletState extends BaseState {
|
|
|
505
508
|
throw new Error('Unsupported blocklet status');
|
|
506
509
|
}
|
|
507
510
|
|
|
508
|
-
const
|
|
509
|
-
|
|
510
|
-
if (doc.meta?.group === BlockletGroup.gateway && !doc.children?.length) {
|
|
511
|
-
return this.updateBlocklet(did, { status });
|
|
512
|
-
}
|
|
511
|
+
const statusLock = this._getStatusLock(did);
|
|
513
512
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
}
|
|
513
|
+
try {
|
|
514
|
+
await statusLock.acquire();
|
|
515
|
+
const doc = await this.getBlocklet(did);
|
|
518
516
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
if (component.meta.group === BlockletGroup.gateway) {
|
|
522
|
-
return;
|
|
517
|
+
if (doc.meta?.group === BlockletGroup.gateway && !doc.children?.length) {
|
|
518
|
+
return this.updateBlocklet(did, { status });
|
|
523
519
|
}
|
|
524
520
|
|
|
525
|
-
|
|
526
|
-
|
|
521
|
+
// for backward compatibility
|
|
522
|
+
if (!doc.structVersion && !doc.children?.length) {
|
|
523
|
+
return this.updateBlocklet(did, { status });
|
|
527
524
|
}
|
|
528
525
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
component.
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
if (status === BlockletStatus.stopped) {
|
|
535
|
-
component.startedAt = null;
|
|
536
|
-
component.stoppedAt = new Date();
|
|
537
|
-
}
|
|
538
|
-
});
|
|
526
|
+
// update children status
|
|
527
|
+
forEachComponentV2Sync(doc, (component) => {
|
|
528
|
+
if (component.meta.group === BlockletGroup.gateway) {
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
539
531
|
|
|
540
|
-
|
|
532
|
+
if (shouldSkipComponent(component.meta.did, componentDids)) {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
component.status = status;
|
|
537
|
+
if (status === BlockletStatus.running) {
|
|
538
|
+
component.startedAt = new Date();
|
|
539
|
+
component.stoppedAt = null;
|
|
540
|
+
}
|
|
541
|
+
if (status === BlockletStatus.stopped) {
|
|
542
|
+
component.startedAt = null;
|
|
543
|
+
component.stoppedAt = new Date();
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
const res = await this.updateBlocklet(did, pick(doc, ['status', 'children']));
|
|
548
|
+
statusLock.release();
|
|
549
|
+
return res;
|
|
550
|
+
} catch (error) {
|
|
551
|
+
statusLock.release();
|
|
552
|
+
throw error;
|
|
553
|
+
}
|
|
541
554
|
}
|
|
542
555
|
|
|
543
556
|
setInstalledAt(did) {
|
|
@@ -641,6 +654,14 @@ class BlockletState extends BaseState {
|
|
|
641
654
|
updateStructV1Did(did, v1Did) {
|
|
642
655
|
return this.updateBlocklet(did, { structV1Did: v1Did });
|
|
643
656
|
}
|
|
657
|
+
|
|
658
|
+
_getStatusLock(did) {
|
|
659
|
+
if (!this.statusLocks.has(did)) {
|
|
660
|
+
this.statusLocks[did] = new Lock();
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
return this.statusLocks[did];
|
|
664
|
+
}
|
|
644
665
|
}
|
|
645
666
|
|
|
646
667
|
BlockletState.BlockletStatus = BlockletStatus;
|
package/lib/util/blocklet.js
CHANGED
|
@@ -41,6 +41,13 @@ const {
|
|
|
41
41
|
APP_STRUCT_VERSION,
|
|
42
42
|
EXPIRED_BLOCKLET_DATA_RETENTION_DAYS,
|
|
43
43
|
} = require('@abtnode/constant');
|
|
44
|
+
const {
|
|
45
|
+
parseComponents,
|
|
46
|
+
ensureMeta,
|
|
47
|
+
filterDuplicateComponents,
|
|
48
|
+
validateBlockletMeta,
|
|
49
|
+
getComponentConfig,
|
|
50
|
+
} = require('@blocklet/resolver');
|
|
44
51
|
const formatBackSlash = require('@abtnode/util/lib/format-back-slash');
|
|
45
52
|
const { toSvg: createDidLogo } =
|
|
46
53
|
process.env.NODE_ENV !== 'test' ? require('@arcblock/did-motif') : require('@arcblock/did-motif/dist/did-motif.cjs');
|
|
@@ -67,7 +74,6 @@ const validateBlockletEntry = require('@blocklet/meta/lib/entry');
|
|
|
67
74
|
const getBlockletEngine = require('@blocklet/meta/lib/engine');
|
|
68
75
|
const getBlockletInfo = require('@blocklet/meta/lib/info');
|
|
69
76
|
const getBlockletWallet = require('@blocklet/meta/lib/wallet');
|
|
70
|
-
const { validateMeta, fixAndValidateService } = require('@blocklet/meta/lib/validate');
|
|
71
77
|
const {
|
|
72
78
|
forEachBlocklet,
|
|
73
79
|
getDisplayName,
|
|
@@ -75,7 +81,6 @@ const {
|
|
|
75
81
|
forEachBlockletSync,
|
|
76
82
|
forEachChildSync,
|
|
77
83
|
forEachComponentV2Sync,
|
|
78
|
-
isComponentBlocklet,
|
|
79
84
|
getSharedConfigObj,
|
|
80
85
|
getComponentName,
|
|
81
86
|
isEnvShareable,
|
|
@@ -85,13 +90,8 @@ const {
|
|
|
85
90
|
isInProgress,
|
|
86
91
|
isRunning,
|
|
87
92
|
} = require('@blocklet/meta/lib/util');
|
|
88
|
-
const toBlockletDid = require('@blocklet/meta/lib/did');
|
|
89
93
|
const { titleSchema, descriptionSchema, logoSchema } = require('@blocklet/meta/lib/schema');
|
|
90
|
-
const {
|
|
91
|
-
getSourceUrlsFromConfig,
|
|
92
|
-
getBlockletMetaFromUrls,
|
|
93
|
-
getBlockletMetaFromUrl,
|
|
94
|
-
} = require('@blocklet/meta/lib/util-meta');
|
|
94
|
+
const { getBlockletMetaFromUrl } = require('@blocklet/meta/lib/util-meta');
|
|
95
95
|
const getComponentProcessId = require('@blocklet/meta/lib/get-component-process-id');
|
|
96
96
|
|
|
97
97
|
const { validate: validateEngine, get: getEngine } = require('../blocklet/manager/engine');
|
|
@@ -103,12 +103,6 @@ const externalIpUtil = require('./get-accessible-external-node-ip');
|
|
|
103
103
|
const { getIpDnsDomainForBlocklet } = require('./get-domain-for-blocklet');
|
|
104
104
|
const { replaceDomainSlot } = require('./index');
|
|
105
105
|
|
|
106
|
-
const getComponentConfig = (meta) => {
|
|
107
|
-
const components = meta.components || meta.children || [];
|
|
108
|
-
const staticComponents = (meta.staticComponents || []).map((x) => ({ ...x, static: true }));
|
|
109
|
-
return [...components, ...staticComponents];
|
|
110
|
-
};
|
|
111
|
-
|
|
112
106
|
/**
|
|
113
107
|
* get blocklet engine info, default is node
|
|
114
108
|
* @param {object} blockletMeta blocklet meta
|
|
@@ -469,11 +463,11 @@ const isUsefulError = (err) =>
|
|
|
469
463
|
!/^Process \d+ not found$/.test(err.message);
|
|
470
464
|
|
|
471
465
|
const getHealthyCheckTimeout = (blocklet, { checkHealthImmediately } = {}) => {
|
|
472
|
-
let minConsecutiveTime =
|
|
466
|
+
let minConsecutiveTime = 2000;
|
|
473
467
|
if (process.env.NODE_ENV === 'test' && process.env.ABT_NODE_TEST_MIN_CONSECUTIVE_TIME !== undefined) {
|
|
474
468
|
minConsecutiveTime = process.env.ABT_NODE_TEST_MIN_CONSECUTIVE_TIME;
|
|
475
469
|
} else if (checkHealthImmediately) {
|
|
476
|
-
minConsecutiveTime =
|
|
470
|
+
minConsecutiveTime = 1000;
|
|
477
471
|
}
|
|
478
472
|
|
|
479
473
|
if (process.env.BLOCKLET_START_TIMEOUT) {
|
|
@@ -540,6 +534,7 @@ const startBlockletProcess = async (
|
|
|
540
534
|
|
|
541
535
|
// get env
|
|
542
536
|
const env = getRuntimeEnvironments(b, nodeEnvironments, ancestors);
|
|
537
|
+
const startedAt = Date.now();
|
|
543
538
|
|
|
544
539
|
// run hook
|
|
545
540
|
await preStart(b, { env });
|
|
@@ -564,7 +559,7 @@ const startBlockletProcess = async (
|
|
|
564
559
|
output: path.join(logsDir, 'output.log'),
|
|
565
560
|
error: path.join(logsDir, 'error.log'),
|
|
566
561
|
wait_ready: process.env.NODE_ENV !== 'test',
|
|
567
|
-
listen_timeout:
|
|
562
|
+
listen_timeout: 3000,
|
|
568
563
|
max_memory_restart: `${maxMemoryRestart}M`,
|
|
569
564
|
max_restarts: b.mode === BLOCKLET_MODES.DEVELOPMENT ? 0 : 3,
|
|
570
565
|
env: {
|
|
@@ -618,9 +613,9 @@ const startBlockletProcess = async (
|
|
|
618
613
|
|
|
619
614
|
const status = await getProcessState(processId);
|
|
620
615
|
if (status === BlockletStatus.error) {
|
|
621
|
-
throw new Error(`${processId} is not running within
|
|
616
|
+
throw new Error(`${processId} is not running within 3 seconds`);
|
|
622
617
|
}
|
|
623
|
-
logger.info('blocklet started', { processId, status });
|
|
618
|
+
logger.info('blocklet started', { processId, status, time: Date.now() - startedAt });
|
|
624
619
|
|
|
625
620
|
// run hook
|
|
626
621
|
postStart(b, { env }).catch((err) => {
|
|
@@ -736,128 +731,6 @@ const reloadProcess = (processId) =>
|
|
|
736
731
|
});
|
|
737
732
|
});
|
|
738
733
|
|
|
739
|
-
/**
|
|
740
|
-
* this function has side effect to component (will set component.children: Array<staticComponent> )
|
|
741
|
-
* this function has side effect to dynamicComponents (will push dynamicComponent in dynamicComponents)
|
|
742
|
-
*
|
|
743
|
-
* @param {Component} component
|
|
744
|
-
* @param {{
|
|
745
|
-
* ancestors: Array<{meta}>
|
|
746
|
-
* dynamicComponents: Array<{Component}>
|
|
747
|
-
* }} context
|
|
748
|
-
* @returns {{
|
|
749
|
-
* dynamicComponents: Array<Component>,
|
|
750
|
-
* staticComponents: Array<Component>,
|
|
751
|
-
* }}
|
|
752
|
-
*/
|
|
753
|
-
const parseComponents = async (component, context = {}) => {
|
|
754
|
-
const { ancestors = [], dynamicComponents = [] } = context;
|
|
755
|
-
if (ancestors.length > 40) {
|
|
756
|
-
throw new Error('The depth of component should not exceed 40');
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
const configs = getComponentConfig(component.meta) || [];
|
|
760
|
-
|
|
761
|
-
if (!configs || !configs.length) {
|
|
762
|
-
return {
|
|
763
|
-
staticComponents: [],
|
|
764
|
-
dynamicComponents,
|
|
765
|
-
};
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
const staticComponents = [];
|
|
769
|
-
|
|
770
|
-
// FIXME @linchen 改成并行获取
|
|
771
|
-
for (const config of configs) {
|
|
772
|
-
const isStatic = !!config.static;
|
|
773
|
-
|
|
774
|
-
if (isStatic) {
|
|
775
|
-
if (!config.name) {
|
|
776
|
-
throw new Error(`Name does not found in child ${config.name}`);
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
if (!config.mountPoint) {
|
|
780
|
-
throw new Error(`MountPoint does not found in child ${config.name}`);
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
const urls = getSourceUrlsFromConfig(config);
|
|
785
|
-
|
|
786
|
-
let rawMeta;
|
|
787
|
-
try {
|
|
788
|
-
rawMeta = await getBlockletMetaFromUrls(urls, { logger });
|
|
789
|
-
} catch (error) {
|
|
790
|
-
throw new Error(`Failed get component meta. Component: ${urls.join(', ')}, reason: ${error.message}`);
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
if (rawMeta.group === BlockletGroup.gateway) {
|
|
794
|
-
throw new Error(`Cannot add gateway component ${rawMeta.title || rawMeta.did}`);
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
validateBlockletMeta(rawMeta, { ensureDist: true });
|
|
798
|
-
|
|
799
|
-
if (!isComponentBlocklet(rawMeta)) {
|
|
800
|
-
throw new Error(
|
|
801
|
-
`The blocklet cannot be a component: ${rawMeta.title}. The reason may be that the developer set capabilities.component to false in blocklet.yml`
|
|
802
|
-
);
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
const webInterface = findWebInterface(rawMeta);
|
|
806
|
-
if (!webInterface) {
|
|
807
|
-
throw new Error(`Web interface does not found in component ${rawMeta.title || rawMeta.name}`);
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
const meta = ensureMeta(rawMeta, { name: isStatic ? config.name : null });
|
|
811
|
-
|
|
812
|
-
// check circular dependencies
|
|
813
|
-
if (ancestors.map((x) => x.meta?.bundleDid).indexOf(meta.bundleDid) > -1) {
|
|
814
|
-
throw new Error('Blocklet components have circular dependencies');
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
if (config.title) {
|
|
818
|
-
meta.title = config.title;
|
|
819
|
-
meta.title = await titleSchema.validateAsync(config.title);
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
if (config.description) {
|
|
823
|
-
meta.description = await descriptionSchema.validateAsync(config.description);
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
const mountPoint = isStatic ? config.mountPoint : config.mountPoint || `/${meta.did}`;
|
|
827
|
-
|
|
828
|
-
const child = {
|
|
829
|
-
mountPoint,
|
|
830
|
-
meta,
|
|
831
|
-
bundleSource: config.source,
|
|
832
|
-
dependencies: [],
|
|
833
|
-
};
|
|
834
|
-
|
|
835
|
-
if (isStatic) {
|
|
836
|
-
staticComponents.push(child);
|
|
837
|
-
} else {
|
|
838
|
-
dynamicComponents.push(child);
|
|
839
|
-
component.dependencies = component.dependencies || [];
|
|
840
|
-
component.dependencies.push({
|
|
841
|
-
did: child.meta.bundleDid,
|
|
842
|
-
required: !!config.required,
|
|
843
|
-
version: config.source.version || 'latest',
|
|
844
|
-
});
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
await parseComponents(child, {
|
|
848
|
-
ancestors: [...ancestors, { meta }],
|
|
849
|
-
dynamicComponents,
|
|
850
|
-
});
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
component.children = staticComponents;
|
|
854
|
-
|
|
855
|
-
return {
|
|
856
|
-
staticComponents,
|
|
857
|
-
dynamicComponents,
|
|
858
|
-
};
|
|
859
|
-
};
|
|
860
|
-
|
|
861
734
|
const validateBlocklet = (blocklet) =>
|
|
862
735
|
forEachBlocklet(blocklet, (b) => {
|
|
863
736
|
isRequirementsSatisfied(b.meta.requirements);
|
|
@@ -894,7 +767,9 @@ const checkBlockletProcessHealthy = async (blocklet, { minConsecutiveTime, timeo
|
|
|
894
767
|
|
|
895
768
|
const logToTerminal = [blocklet.mode, b.mode].includes(BLOCKLET_MODES.DEVELOPMENT);
|
|
896
769
|
|
|
770
|
+
const startedAt = Date.now();
|
|
897
771
|
await _checkProcessHealthy(b, { minConsecutiveTime, timeout, logToTerminal });
|
|
772
|
+
logger.info('component healthy', { did: b.meta.did, time: Date.now() - startedAt });
|
|
898
773
|
},
|
|
899
774
|
{ parallel: true }
|
|
900
775
|
);
|
|
@@ -923,10 +798,9 @@ const _checkProcessHealthy = async (blocklet, { minConsecutiveTime, timeout, log
|
|
|
923
798
|
}
|
|
924
799
|
};
|
|
925
800
|
|
|
926
|
-
await sleep(400);
|
|
927
801
|
let status = await getStatus();
|
|
928
|
-
for (let i = 0; i <
|
|
929
|
-
const t = process.env.NODE_ENV !== 'test' ?
|
|
802
|
+
for (let i = 0; i < 20 && status !== 'online'; i++) {
|
|
803
|
+
const t = process.env.NODE_ENV !== 'test' ? 500 : 30;
|
|
930
804
|
await sleep(t);
|
|
931
805
|
status = await getStatus();
|
|
932
806
|
}
|
|
@@ -945,11 +819,7 @@ const _checkProcessHealthy = async (blocklet, { minConsecutiveTime, timeout, log
|
|
|
945
819
|
);
|
|
946
820
|
}
|
|
947
821
|
try {
|
|
948
|
-
await ensureEndpointHealthy({
|
|
949
|
-
port,
|
|
950
|
-
minConsecutiveTime,
|
|
951
|
-
timeout,
|
|
952
|
-
});
|
|
822
|
+
await ensureEndpointHealthy({ port, minConsecutiveTime, timeout });
|
|
953
823
|
} catch (error) {
|
|
954
824
|
logger.error('ensure endpoint healthy failed', { port, minConsecutiveTime, timeout });
|
|
955
825
|
throw error;
|
|
@@ -1327,45 +1197,6 @@ const needBlockletDownload = (blocklet, oldBlocklet) => {
|
|
|
1327
1197
|
return get(oldBlocklet, 'meta.dist.integrity') !== get(blocklet, 'meta.dist.integrity');
|
|
1328
1198
|
};
|
|
1329
1199
|
|
|
1330
|
-
const isDidMatchName = (did, name) => {
|
|
1331
|
-
if (isValidDid(did) && name === did) {
|
|
1332
|
-
return true;
|
|
1333
|
-
}
|
|
1334
|
-
|
|
1335
|
-
return toBlockletDid(name) === did;
|
|
1336
|
-
};
|
|
1337
|
-
|
|
1338
|
-
/**
|
|
1339
|
-
* set bundleDid and bundleMeta in meta
|
|
1340
|
-
* update name and did to server index
|
|
1341
|
-
* in app structure 2.0, application's bundleDid, bundleName, meta, did will be same
|
|
1342
|
-
*/
|
|
1343
|
-
const ensureMeta = (meta, { name, did } = {}) => {
|
|
1344
|
-
if (name && did && !isDidMatchName(did, name)) {
|
|
1345
|
-
throw new Error(`name does not match with did: ${name}, ${did}`);
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
|
-
const newMeta = {
|
|
1349
|
-
...meta,
|
|
1350
|
-
};
|
|
1351
|
-
|
|
1352
|
-
if (!newMeta.did || !newMeta.name || !isDidMatchName(newMeta.did, newMeta.name)) {
|
|
1353
|
-
throw new Error(`name does not match with did in meta: ${newMeta.name}, ${newMeta.did}`);
|
|
1354
|
-
}
|
|
1355
|
-
|
|
1356
|
-
if (!meta.bundleDid) {
|
|
1357
|
-
newMeta.bundleDid = meta.did;
|
|
1358
|
-
newMeta.bundleName = meta.name;
|
|
1359
|
-
}
|
|
1360
|
-
|
|
1361
|
-
if (name) {
|
|
1362
|
-
newMeta.name = name;
|
|
1363
|
-
newMeta.did = did || toBlockletDid(name);
|
|
1364
|
-
}
|
|
1365
|
-
|
|
1366
|
-
return newMeta;
|
|
1367
|
-
};
|
|
1368
|
-
|
|
1369
1200
|
const getBlocklet = async ({
|
|
1370
1201
|
did,
|
|
1371
1202
|
dataDirs,
|
|
@@ -1784,36 +1615,6 @@ const checkVersionCompatibility = (components) => {
|
|
|
1784
1615
|
}
|
|
1785
1616
|
};
|
|
1786
1617
|
|
|
1787
|
-
const filterDuplicateComponents = (components = [], currents = []) => {
|
|
1788
|
-
const arr = [];
|
|
1789
|
-
|
|
1790
|
-
components.forEach((component) => {
|
|
1791
|
-
if (currents.some((x) => x.meta.did === component.meta.did)) {
|
|
1792
|
-
return;
|
|
1793
|
-
}
|
|
1794
|
-
|
|
1795
|
-
const index = arr.findIndex((x) => x.meta.did === component.meta.did);
|
|
1796
|
-
if (index > -1) {
|
|
1797
|
-
const exist = arr[index];
|
|
1798
|
-
|
|
1799
|
-
// 选择最小版本:
|
|
1800
|
-
// 如果 com1 和 com2 都依赖某个 component, com1 声明依赖版本 1.0.0, 实际获取版本 1.0.0; com2 声明依赖版本 latest(不限), 实际获取版本 2.0.0 -> 则应该取 1.0.0
|
|
1801
|
-
if (semver.lt(component.meta.version, exist.meta.version)) {
|
|
1802
|
-
arr.splice(index, 1, component);
|
|
1803
|
-
}
|
|
1804
|
-
} else {
|
|
1805
|
-
arr.push(component);
|
|
1806
|
-
}
|
|
1807
|
-
});
|
|
1808
|
-
|
|
1809
|
-
return arr;
|
|
1810
|
-
};
|
|
1811
|
-
|
|
1812
|
-
const validateBlockletMeta = (meta, opts = {}) => {
|
|
1813
|
-
fixAndValidateService(meta);
|
|
1814
|
-
return validateMeta(meta, { ensureName: true, skipValidateDidName: true, schemaOptions: { ...opts } });
|
|
1815
|
-
};
|
|
1816
|
-
|
|
1817
1618
|
const getBlockletKnownAs = (blocklet) => {
|
|
1818
1619
|
const alsoKnownAs = [blocklet.appDid];
|
|
1819
1620
|
if (Array.isArray(blocklet.migratedFrom)) {
|
package/lib/util/launcher.js
CHANGED
package/lib/validators/router.js
CHANGED
|
@@ -17,19 +17,21 @@ const domainMessages = {
|
|
|
17
17
|
},
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
const getPrefixSchema = (field) =>
|
|
21
|
+
Joi.string()
|
|
22
|
+
.trim()
|
|
23
|
+
.max(150)
|
|
24
|
+
.messages({
|
|
25
|
+
zh: { 'string.empty': `${field} 不能为空`, 'string.max': `${field} 的最大长度是 150` },
|
|
26
|
+
en: { 'string.empty': `${field} cannot be empty`, 'string.max': `The maximum length of ${field} is 150` },
|
|
27
|
+
})
|
|
28
|
+
.custom((value) => urlPathFriendly(value));
|
|
29
|
+
|
|
20
30
|
const ruleSchema = {
|
|
21
31
|
isProtected: Joi.boolean(),
|
|
22
32
|
|
|
23
33
|
from: Joi.object({
|
|
24
|
-
pathPrefix:
|
|
25
|
-
.required()
|
|
26
|
-
.trim()
|
|
27
|
-
.max(150)
|
|
28
|
-
.messages({
|
|
29
|
-
zh: { 'string.empty': 'URL 前缀不能为空', 'string.max': 'URL 前缀的最大长度是 150' },
|
|
30
|
-
en: { 'string.empty': 'URL prefix cannot be empty', 'string.max': 'The maximum length of URL prefix is 150' },
|
|
31
|
-
})
|
|
32
|
-
.custom((value) => urlPathFriendly(value)),
|
|
34
|
+
pathPrefix: getPrefixSchema('from.pathPrefix').required(),
|
|
33
35
|
groupPathPrefix: Joi.string().trim().min(1).max(150), // path prefix of interface of root blocklet
|
|
34
36
|
header: Joi.any(), // TODO: header does not take effect
|
|
35
37
|
}),
|
|
@@ -44,12 +46,24 @@ const ruleSchema = {
|
|
|
44
46
|
ROUTING_RULE_TYPES.REDIRECT,
|
|
45
47
|
ROUTING_RULE_TYPES.GENERAL_PROXY,
|
|
46
48
|
ROUTING_RULE_TYPES.DIRECT_RESPONSE,
|
|
49
|
+
ROUTING_RULE_TYPES.GENERAL_REWRITE,
|
|
50
|
+
ROUTING_RULE_TYPES.COMPONENT,
|
|
47
51
|
ROUTING_RULE_TYPES.NONE
|
|
48
52
|
)
|
|
49
53
|
.required(),
|
|
50
|
-
did: Joi.string()
|
|
54
|
+
did: Joi.string()
|
|
55
|
+
.label('did')
|
|
56
|
+
.when('type', {
|
|
57
|
+
is: Joi.string().valid(ROUTING_RULE_TYPES.BLOCKLET, ROUTING_RULE_TYPES.COMPONENT),
|
|
58
|
+
then: Joi.required(),
|
|
59
|
+
}), // root blocklet did
|
|
51
60
|
port: Joi.number().label('port').port().when('type', { is: ROUTING_RULE_TYPES.BLOCKLET, then: Joi.required() }),
|
|
52
|
-
url: Joi.string()
|
|
61
|
+
url: Joi.string()
|
|
62
|
+
.label('url')
|
|
63
|
+
.when('type', {
|
|
64
|
+
is: Joi.string().valid(ROUTING_RULE_TYPES.REDIRECT, ROUTING_RULE_TYPES.GENERAL_REWRITE),
|
|
65
|
+
then: Joi.required(),
|
|
66
|
+
}),
|
|
53
67
|
redirectCode: Joi.alternatives()
|
|
54
68
|
.try(301, 302, 307, 308)
|
|
55
69
|
.label('redirect code')
|
|
@@ -70,7 +84,8 @@ const ruleSchema = {
|
|
|
70
84
|
.valid(...Object.keys(ROUTER_CACHE_GROUPS))
|
|
71
85
|
.allow('')
|
|
72
86
|
.default(''),
|
|
73
|
-
targetPrefix:
|
|
87
|
+
targetPrefix: getPrefixSchema('to.targetPrefix'), // path prefix of interface of target blocklet
|
|
88
|
+
pageGroup: Joi.string().allow('').default(''),
|
|
74
89
|
},
|
|
75
90
|
|
|
76
91
|
// List of services that manipulate the request before the upstream blocklet
|
package/lib/validators/util.js
CHANGED
|
@@ -22,8 +22,20 @@ const blockletController = Joi.object({
|
|
|
22
22
|
|
|
23
23
|
const createValidator = (schema) => (entity) => schema.validateAsync(entity);
|
|
24
24
|
|
|
25
|
+
const sessionConfigSchema = Joi.object({
|
|
26
|
+
cacheTtl: Joi.number()
|
|
27
|
+
.min(5 * 60) // 5min
|
|
28
|
+
.max(86400) // 1d
|
|
29
|
+
.default(10 * 60), // 10min
|
|
30
|
+
ttl: Joi.number()
|
|
31
|
+
.min(86400) // 1d
|
|
32
|
+
.max(86400 * 30) // 30d
|
|
33
|
+
.default(86400 * 7), // 7d
|
|
34
|
+
});
|
|
35
|
+
|
|
25
36
|
module.exports = {
|
|
26
37
|
createValidator,
|
|
27
38
|
getMultipleLangParams,
|
|
28
39
|
blockletController,
|
|
40
|
+
sessionConfigSchema,
|
|
29
41
|
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.16.13-beta-
|
|
6
|
+
"version": "1.16.13-beta-423a40b1",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -19,31 +19,32 @@
|
|
|
19
19
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
20
20
|
"license": "Apache-2.0",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@abtnode/auth": "1.16.13-beta-
|
|
23
|
-
"@abtnode/certificate-manager": "1.16.13-beta-
|
|
24
|
-
"@abtnode/constant": "1.16.13-beta-
|
|
25
|
-
"@abtnode/cron": "1.16.13-beta-
|
|
26
|
-
"@abtnode/logger": "1.16.13-beta-
|
|
27
|
-
"@abtnode/models": "1.16.13-beta-
|
|
28
|
-
"@abtnode/queue": "1.16.13-beta-
|
|
29
|
-
"@abtnode/rbac": "1.16.13-beta-
|
|
30
|
-
"@abtnode/router-provider": "1.16.13-beta-
|
|
31
|
-
"@abtnode/static-server": "1.16.13-beta-
|
|
32
|
-
"@abtnode/timemachine": "1.16.13-beta-
|
|
33
|
-
"@abtnode/util": "1.16.13-beta-
|
|
22
|
+
"@abtnode/auth": "1.16.13-beta-423a40b1",
|
|
23
|
+
"@abtnode/certificate-manager": "1.16.13-beta-423a40b1",
|
|
24
|
+
"@abtnode/constant": "1.16.13-beta-423a40b1",
|
|
25
|
+
"@abtnode/cron": "1.16.13-beta-423a40b1",
|
|
26
|
+
"@abtnode/logger": "1.16.13-beta-423a40b1",
|
|
27
|
+
"@abtnode/models": "1.16.13-beta-423a40b1",
|
|
28
|
+
"@abtnode/queue": "1.16.13-beta-423a40b1",
|
|
29
|
+
"@abtnode/rbac": "1.16.13-beta-423a40b1",
|
|
30
|
+
"@abtnode/router-provider": "1.16.13-beta-423a40b1",
|
|
31
|
+
"@abtnode/static-server": "1.16.13-beta-423a40b1",
|
|
32
|
+
"@abtnode/timemachine": "1.16.13-beta-423a40b1",
|
|
33
|
+
"@abtnode/util": "1.16.13-beta-423a40b1",
|
|
34
34
|
"@arcblock/did": "1.18.84",
|
|
35
35
|
"@arcblock/did-auth": "1.18.84",
|
|
36
36
|
"@arcblock/did-ext": "^1.18.84",
|
|
37
|
-
"@arcblock/did-motif": "^1.1.
|
|
37
|
+
"@arcblock/did-motif": "^1.1.11",
|
|
38
38
|
"@arcblock/did-util": "1.18.84",
|
|
39
39
|
"@arcblock/event-hub": "1.18.84",
|
|
40
40
|
"@arcblock/jwt": "^1.18.84",
|
|
41
41
|
"@arcblock/pm2-events": "^0.0.5",
|
|
42
42
|
"@arcblock/validator": "^1.18.84",
|
|
43
43
|
"@arcblock/vc": "1.18.84",
|
|
44
|
-
"@blocklet/constant": "1.16.13-beta-
|
|
45
|
-
"@blocklet/meta": "1.16.13-beta-
|
|
46
|
-
"@blocklet/
|
|
44
|
+
"@blocklet/constant": "1.16.13-beta-423a40b1",
|
|
45
|
+
"@blocklet/meta": "1.16.13-beta-423a40b1",
|
|
46
|
+
"@blocklet/resolver": "1.16.13-beta-423a40b1",
|
|
47
|
+
"@blocklet/sdk": "1.16.13-beta-423a40b1",
|
|
47
48
|
"@did-space/client": "^0.2.117",
|
|
48
49
|
"@fidm/x509": "^1.2.1",
|
|
49
50
|
"@ocap/mcrypto": "1.18.84",
|
|
@@ -96,5 +97,5 @@
|
|
|
96
97
|
"express": "^4.18.2",
|
|
97
98
|
"jest": "^27.5.1"
|
|
98
99
|
},
|
|
99
|
-
"gitHead": "
|
|
100
|
+
"gitHead": "1aee04f45042bd4784ca72f9f8b93918980be4d4"
|
|
100
101
|
}
|