@abtnode/core 1.6.17 → 1.6.21

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/event.js CHANGED
@@ -132,7 +132,7 @@ module.exports = ({
132
132
  onEvent(name, blocklet);
133
133
  };
134
134
 
135
- const handleCLIEvent = (eventName) => {
135
+ const handleServerEvent = (eventName) => {
136
136
  const [, status] = eventName.split('.');
137
137
  onEvent(eventName, {
138
138
  title: `Blocklet Server ${status}`,
@@ -209,7 +209,8 @@ module.exports = ({
209
209
 
210
210
  events.handleBlockletAdd = handleBlockletAdd;
211
211
  events.handleBlockletRemove = handleBlockletRemove;
212
- events.handleCLIEvent = handleCLIEvent;
212
+ events.handleServerEvent = handleServerEvent;
213
+ events.onEvent = onEvent;
213
214
 
214
215
  return events;
215
216
  };
package/lib/index.js CHANGED
@@ -147,7 +147,7 @@ function ABTNode(options) {
147
147
  getCertificates,
148
148
  getSitesFromSnapshot,
149
149
  getRoutingCrons,
150
- ensureDashboardCertificate,
150
+ ensureWildcardCerts,
151
151
  } = getRouterHelpers({ dataDirs, routingSnapshot, routerManager, blockletManager, certManager });
152
152
 
153
153
  const teamManager = new TeamManager({ nodeDid: options.nodeDid, dataDirs, states });
@@ -208,7 +208,6 @@ function ABTNode(options) {
208
208
  upgradeBlocklet: blockletManager.upgrade.bind(blockletManager),
209
209
  configBlocklet: blockletManager.config.bind(blockletManager),
210
210
  devBlocklet: blockletManager.dev.bind(blockletManager),
211
- getBlockletStatus: blockletManager.getStatus.bind(blockletManager),
212
211
  checkChildBlockletsForUpdates: blockletManager.checkChildrenForUpdates.bind(blockletManager),
213
212
  updateChildBlocklets: blockletManager.updateChildren.bind(blockletManager),
214
213
  getLatestBlockletVersion: blockletManager.getLatestBlockletVersion.bind(blockletManager),
@@ -319,7 +318,7 @@ function ABTNode(options) {
319
318
  takeRoutingSnapshot,
320
319
  getSitesFromSnapshot,
321
320
  ensureDashboardRouting,
322
- ensureDashboardCertificate,
321
+ ensureWildcardCerts,
323
322
 
324
323
  addDomainAlias: routerManager.addDomainAlias.bind(routerManager),
325
324
  deleteDomainAlias: routerManager.deleteDomainAlias.bind(routerManager),
@@ -0,0 +1,27 @@
1
+ const yaml = require('js-yaml');
2
+ const fs = require('fs');
3
+ const set = require('lodash/set');
4
+ const omit = require('lodash/omit');
5
+ const { DEFAULT_WILDCARD_CERT_HOST, DEFAULT_DID_DOMAIN, DEFAULT_DID_REGISTRY } = require('@abtnode/constant');
6
+
7
+ module.exports = async ({ states, printInfo, configFile }) => {
8
+ printInfo('Try to rename dashboardDomain to ipWildcardDomain in db...');
9
+
10
+ let info = await states.node.read();
11
+ set(info, 'routing.ipWildcardDomain', info.routing.dashboardDomain);
12
+ set(info, 'routing.wildcardCertHost', DEFAULT_WILDCARD_CERT_HOST);
13
+ set(info, 'didDomain', DEFAULT_DID_DOMAIN);
14
+ set(info, 'didRegistry', DEFAULT_DID_REGISTRY);
15
+ info = omit(info, 'routing.dashboardDomain');
16
+
17
+ await states.node.updateNodeInfo(info);
18
+
19
+ let rawConfig = yaml.safeLoad(fs.readFileSync(configFile).toString());
20
+ set(rawConfig, 'node.routing.ipWildcardDomain', info.routing.ipWildcardDomain);
21
+ set(rawConfig, 'node.routing.wildcardCertHost', DEFAULT_WILDCARD_CERT_HOST);
22
+ set(rawConfig, 'node.didDomain', DEFAULT_DID_DOMAIN);
23
+ set(rawConfig, 'node.didRegistry', DEFAULT_DID_REGISTRY);
24
+ rawConfig = omit(rawConfig, 'node.routing.dashboardDomain');
25
+ fs.writeFileSync(configFile, yaml.dump(rawConfig));
26
+ printInfo(`> Persist new config to file: ${configFile}`);
27
+ };
@@ -419,6 +419,13 @@ const decompressCertificates = async (source, dest) => {
419
419
  return dest;
420
420
  };
421
421
 
422
+ const joinCertDownUrl = (baseUrl, name) => joinUrl(baseUrl, '/certs', name);
423
+
424
+ const getIpEchoCertDownloadUrl = (baseUrl) => joinCertDownUrl(baseUrl, 'ip-abtnet-io.tar.gz');
425
+ const getDidDomainCertDownloadUrl = (baseUrl) => joinCertDownUrl(baseUrl, 'did-abtnet-io.tar.gz');
426
+ const getDownloadCertBaseUrl = (info) =>
427
+ process.env.ABT_NODE_WILDCARD_CERT_HOST || get(info, 'routing.wildcardCertHost', '');
428
+
422
429
  module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerManager, blockletManager, certManager }) {
423
430
  const nodeState = states.node;
424
431
  const blockletState = states.blocklet;
@@ -428,46 +435,13 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
428
435
  // site level duplication detection
429
436
  const hasRuleByPrefix = (site, value) => site.rules.find((x) => x.isProtected && get(x, 'from.pathPrefix') === value);
430
437
 
431
- const updateDashboardCertificate = async ({ checkExpire = true }) => {
432
- const info = await nodeState.read();
433
- const provider = getProviderFromNodeInfo(info);
434
- if (provider === ROUTER_PROVIDER_NONE) {
435
- return;
436
- }
437
-
438
- const https = get(info, 'routing.https', true);
439
- const dashboardDomain = get(info, 'routing.dashboardDomain', '');
440
- const certDownloadAddress =
441
- process.env.ABT_NODE_DASHBOARD_CERT_DOWN_URL || get(info, 'routing.dashboardCertDownloadAddress', '');
442
- if (!https || !dashboardDomain || !certDownloadAddress) {
443
- return;
444
- }
445
-
446
- if (checkExpire) {
447
- try {
448
- const cert = await routerManager.findCertificateByDomain(dashboardDomain);
449
- if (!cert) {
450
- return;
451
- }
452
-
453
- const now = Date.now();
454
- const certInfo = getHttpsCertInfo(cert.certificate);
455
- if (certInfo.validTo - now >= CERTIFICATE_EXPIRES_OFFSET) {
456
- logger.info('skip dashboard certificate update before not expired');
457
- return;
458
- }
459
- } catch (err) {
460
- logger.error('failed to check dashboard certificate expiration', { error: err });
461
- return;
462
- }
463
- }
464
-
438
+ const downloadCert = async ({ domain, url }) => {
465
439
  const destFolder = getTmpDirectory(path.join(`certificate-${Date.now()}`));
466
440
  try {
467
441
  const filename = path.join(destFolder, 'certificate.tar.gz');
468
442
  fs.ensureDirSync(destFolder);
469
443
 
470
- await downloadFile(certDownloadAddress, filename);
444
+ await downloadFile(url, filename);
471
445
  await decompressCertificates(filename, destFolder);
472
446
 
473
447
  const certificateFilePath = path.join(destFolder, 'cert.pem');
@@ -485,7 +459,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
485
459
  const privateKey = fs.readFileSync(privateKeyFilePath).toString();
486
460
 
487
461
  await certManager.upsertByDomain({
488
- domain: dashboardDomain,
462
+ domain,
489
463
  privateKey,
490
464
  certificate,
491
465
  isProtected: true,
@@ -499,23 +473,68 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
499
473
  }
500
474
  };
501
475
 
502
- const ensureDashboardCertificate = async () => {
476
+ const updateCert = async (domain, url) => {
477
+ try {
478
+ const cert = await routerManager.findCertificateByDomain(domain);
479
+ if (!cert) {
480
+ return;
481
+ }
482
+
483
+ const now = Date.now();
484
+ const certInfo = getHttpsCertInfo(cert.certificate);
485
+ if (certInfo.validTo - now >= CERTIFICATE_EXPIRES_OFFSET) {
486
+ logger.info('skip dashboard certificate update before not expired', { domain, url });
487
+ return;
488
+ }
489
+
490
+ await downloadCert({
491
+ domain,
492
+ url,
493
+ });
494
+ } catch (err) {
495
+ logger.error('failed to check dashboard certificate expiration', { error: err, domain, url });
496
+ }
497
+ };
498
+
499
+ const updateDashboardCertificates = async () => {
503
500
  const info = await nodeState.read();
504
- const downloadUrl = get(info, 'routing.dashboardCertDownloadAddress', '');
505
- const dashboardDomain = get(info, 'routing.dashboardDomain', '');
506
- if (!dashboardDomain || !downloadUrl) {
507
- throw new Error('dashboardCertDownloadAddress and dashboardDomain are not found in the routing configs');
501
+ const provider = getProviderFromNodeInfo(info);
502
+ if (provider === ROUTER_PROVIDER_NONE) {
503
+ return;
508
504
  }
509
505
 
510
- const cert = await certManager.getByDomain(dashboardDomain);
511
- if (cert) {
512
- return { status: 'existed' };
506
+ const https = get(info, 'routing.https', true);
507
+ const ipWildcardDomain = get(info, 'routing.ipWildcardDomain', '');
508
+ const didDomain = info.didDomain;
509
+ const certDownloadAddress = getDownloadCertBaseUrl(info);
510
+ if (!https || !certDownloadAddress) {
511
+ return;
513
512
  }
514
513
 
515
- logger.debug('downloading dashboard ip-domain certificate', { url: downloadUrl, dashboardDomain });
516
- await updateDashboardCertificate({ checkExpire: false });
517
- logger.debug('downloaded dashboard ip-domain certificate', { url: downloadUrl, dashboardDomain });
518
- return { status: 'downloaded' };
514
+ await updateCert(ipWildcardDomain, getIpEchoCertDownloadUrl(certDownloadAddress));
515
+ await updateCert(`*.${didDomain}`, getDidDomainCertDownloadUrl(certDownloadAddress));
516
+ };
517
+
518
+ const ensureWildcardCerts = async () => {
519
+ const info = await nodeState.read();
520
+ const didDomain = info.didDomain;
521
+ const ipWildcardDomain = get(info, 'routing.ipWildcardDomain', '');
522
+
523
+ const ensureDomainCert = async (domain, url) => {
524
+ const cert = await certManager.getByDomain(domain);
525
+ if (!cert) {
526
+ await downloadCert({
527
+ domain,
528
+ url,
529
+ });
530
+ }
531
+ };
532
+
533
+ const certBaseUrl = getDownloadCertBaseUrl(info);
534
+ await Promise.all([
535
+ ensureDomainCert(ipWildcardDomain, getIpEchoCertDownloadUrl(certBaseUrl)),
536
+ ensureDomainCert(`*.${didDomain}`, getDidDomainCertDownloadUrl(certBaseUrl)),
537
+ ]);
519
538
  };
520
539
 
521
540
  const upsertSiteRule = async ({ site, rule }, context) => {
@@ -658,9 +677,11 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
658
677
  return domainAlias === item;
659
678
  });
660
679
 
661
- const dashboardDomain = get(info, 'routing.dashboardDomain', '');
680
+ const ipWildcardDomain = get(info, 'routing.ipWildcardDomain', '');
662
681
  const didDomain = `${info.did.toLowerCase()}.${info.didDomain}`;
663
- const dashboardAliasDomains = [dashboardDomain, didDomain]
682
+ let dashboardAliasDomains = [ipWildcardDomain, didDomain];
683
+
684
+ dashboardAliasDomains = dashboardAliasDomains
664
685
  .filter((item) => item && !isExistsInAlias(item))
665
686
  .map((item) => ({ value: item, isProtected: true }));
666
687
 
@@ -746,18 +767,18 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
746
767
 
747
768
  const existSite = await states.site.findOne({ domain: domainGroup });
748
769
  if (!existSite) {
749
- const ipEchoDnsDomain = getIpDnsDomainForBlocklet(blocklet, webInterface, nodeInfo.did);
750
- const appIdEnv = blocklet.environments.find((e) => e.key === 'BLOCKLET_APP_ID');
751
- const domainAliases = [{ value: ipEchoDnsDomain, isProtected: true }];
770
+ const domainAliases = [];
752
771
 
753
772
  const didDomain = getDidDomainForBlocklet({
754
- appId: appIdEnv.value,
773
+ name: blocklet.meta.name,
774
+ daemonDid: nodeInfo.did,
755
775
  didDomain: nodeInfo.didDomain,
756
776
  });
757
777
 
758
- if (blocklet.mode !== 'development') {
759
- domainAliases.push({ value: didDomain, isProtected: true });
760
- }
778
+ const ipEchoDnsDomain = getIpDnsDomainForBlocklet(blocklet, webInterface, nodeInfo.did);
779
+
780
+ // let didDomain in front of ipEchoDnsDomain
781
+ domainAliases.push({ value: didDomain, isProtected: true }, { value: ipEchoDnsDomain, isProtected: true });
761
782
 
762
783
  await routerManager.addRoutingSite(
763
784
  {
@@ -1386,7 +1407,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1386
1407
  getSitesFromSnapshot,
1387
1408
  getCertificates,
1388
1409
  checkDomain,
1389
- ensureDashboardCertificate,
1410
+ ensureWildcardCerts,
1390
1411
  addWellknownSite,
1391
1412
  upsertSiteRule,
1392
1413
 
@@ -1394,7 +1415,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1394
1415
  {
1395
1416
  name: 'update-dashboard-certificate',
1396
1417
  time: '0 1 */6 * * *', // refetch on 0:00, 6:00, etc.
1397
- fn: () => updateDashboardCertificate({ checkExpire: true }),
1418
+ fn: () => updateDashboardCertificates(),
1398
1419
  options: { runOnInit: true },
1399
1420
  },
1400
1421
  {
@@ -60,12 +60,12 @@ const getRoutingTable = ({ sites, nodeInfo }) => {
60
60
  let routingTable = Router.formatSites(sites);
61
61
  routingTable = expandSites(routingTable);
62
62
 
63
- // put dashboardDomain to last, to let blockletDomain match first
63
+ // put ipWildcardDomain to last, to let blockletDomain match first
64
64
  // e.g.
65
- // dashboardDomain: 192-168-3-2.ip.abtnet.io
65
+ // ipWildcardDomain: 192-168-3-2.ip.abtnet.io
66
66
  // blockletDomain: static-demo-xxx-192-168-3-2.ip.abtnet.io
67
- const dashboardDomain = get(nodeInfo, 'routing.dashboardDomain', '');
68
- const index = routingTable.findIndex((x) => x.domain === dashboardDomain);
67
+ const ipWildcardDomain = get(nodeInfo, 'routing.ipWildcardDomain', '');
68
+ const index = routingTable.findIndex((x) => x.domain === ipWildcardDomain);
69
69
  if (index > -1) {
70
70
  routingTable.push(...routingTable.splice(index, 1));
71
71
  }
@@ -219,11 +219,11 @@ Router.formatSites = (sites = []) => {
219
219
 
220
220
  Router.flattenSitesToRules = (sites = [], info = {}) => {
221
221
  const result = [];
222
- const dashboardDomain = get(info, 'routing.dashboardDomain', DEFAULT_DASHBOARD_DOMAIN);
222
+ const ipWildcardDomain = get(info, 'routing.ipWildcardDomain', DEFAULT_DASHBOARD_DOMAIN);
223
223
  sites.forEach((site) => {
224
224
  const aliases = (site.domainAliases || [])
225
225
  .map((x) => (typeof x === 'string' ? x : x.value))
226
- .filter((x) => x !== dashboardDomain)
226
+ .filter((x) => x !== ipWildcardDomain)
227
227
  .filter(Boolean);
228
228
 
229
229
  if (Array.isArray(site.rules) && site.rules.length > 0) {
@@ -221,10 +221,10 @@ class RouterManager extends EventEmitter {
221
221
  }
222
222
  }
223
223
 
224
- const updateResult = await states.site.update(
225
- { _id: id },
226
- { $push: { domainAliases: { value: domainAlias, isProtected: false } } }
227
- );
224
+ // let custom domain in front of protected domain
225
+ const domainAliases = [{ value: domainAlias, isProtected: false }, ...dbSite.domainAliases];
226
+
227
+ const updateResult = await states.site.update({ _id: id }, { $set: { domainAliases } });
228
228
  logger.debug('add domain alias update result', { id, updateResult, domainAlias });
229
229
 
230
230
  const newSite = await states.site.findOne({ _id: id });
@@ -20,7 +20,7 @@ const {
20
20
  const logger = require('@abtnode/logger')('state-blocklet');
21
21
 
22
22
  const BaseState = require('./base');
23
- const { forEachBlocklet } = require('../util/blocklet');
23
+ const { forEachBlocklet, checkDuplicateComponents } = require('../util/blocklet');
24
24
  const { validateBlockletMeta } = require('../util');
25
25
 
26
26
  const lock = new Lock('blocklet-port-assign-lock');
@@ -80,7 +80,11 @@ class BlockletState extends BaseState {
80
80
 
81
81
  getBlocklet(did) {
82
82
  return new Promise((resolve, reject) => {
83
- this.db.findOne({ 'meta.did': did }, (err, doc) => {
83
+ if (!did) {
84
+ resolve(null);
85
+ }
86
+
87
+ this.db.findOne({ $or: [{ 'meta.did': did }, { appDid: did }] }, (err, doc) => {
84
88
  if (err) {
85
89
  return reject(err);
86
90
  }
@@ -160,6 +164,7 @@ class BlockletState extends BaseState {
160
164
  // add to db
161
165
  this.db.insert(
162
166
  {
167
+ appDid: null, // will updated later when updating blocklet environments
163
168
  mode,
164
169
  meta: omit(sanitized, ['htmlAst']),
165
170
  status,
@@ -391,13 +396,20 @@ class BlockletState extends BaseState {
391
396
  return result;
392
397
  }
393
398
 
394
- async setBlockletStatus(did, status) {
399
+ /**
400
+ * @param {String} did blocklet did
401
+ * @param {BlockletStatus} status blocklet status
402
+ *
403
+ * children status only different with parent before blocklet installation
404
+ * @param {Array<{did}>} children
405
+ */
406
+ async setBlockletStatus(did, status, { children } = {}) {
395
407
  if (typeof status === 'undefined') {
396
408
  throw new Error('Unsupported blocklet status');
397
409
  }
398
410
 
399
411
  const doc = await this.getBlocklet(did);
400
- if (doc.status === status) {
412
+ if (doc.status === status && !children) {
401
413
  return formatBlocklet(doc, 'onRead', this.options.dek);
402
414
  }
403
415
 
@@ -412,6 +424,28 @@ class BlockletState extends BaseState {
412
424
  updates.stoppedAt = new Date();
413
425
  }
414
426
 
427
+ // update children status
428
+ updates.children = doc.children.map((child) => {
429
+ if (children === 'all') {
430
+ child.status = status;
431
+ return child;
432
+ }
433
+
434
+ if (!children) {
435
+ if (![BlockletStatus.waiting, BlockletStatus.upgrading, BlockletStatus.installing].includes(status)) {
436
+ child.status = status;
437
+ }
438
+
439
+ return child;
440
+ }
441
+
442
+ const inputChild = children.find((x) => x.did === child.meta.did);
443
+ if (inputChild) {
444
+ child.status = status;
445
+ }
446
+ return child;
447
+ });
448
+
415
449
  await this.update(doc._id, { $set: updates });
416
450
  return formatBlocklet({ ...doc, ...updates }, 'onRead', this.options.dek);
417
451
  }
@@ -463,6 +497,48 @@ class BlockletState extends BaseState {
463
497
 
464
498
  return children;
465
499
  }
500
+
501
+ async addChildren(did, children) {
502
+ const parent = await this.getBlocklet(did);
503
+ if (!parent) {
504
+ throw new Error('Blocklet does not exist');
505
+ }
506
+
507
+ const oldChildren = parent.children || [];
508
+
509
+ const newChildren = [...oldChildren];
510
+ for (const child of children) {
511
+ const { meta, mountPoint, sourceUrl = '', source = '', deployedFrom = '' } = child;
512
+
513
+ if (!mountPoint) {
514
+ throw new Error(`mountPoint is required when adding component ${meta.title || meta.name}`);
515
+ }
516
+
517
+ if (meta.did === parent.meta.did) {
518
+ throw new Error('Cannot add self as a component');
519
+ }
520
+
521
+ checkDuplicateComponents([child], newChildren);
522
+
523
+ newChildren.push({
524
+ mountPoint,
525
+ meta,
526
+ sourceUrl,
527
+ source,
528
+ deployedFrom,
529
+ dynamic: true,
530
+ status: BlockletStatus.added,
531
+ });
532
+ }
533
+
534
+ // use upgradeBlocklet to assign ports to children and write new data to db
535
+ return this.upgradeBlocklet({
536
+ meta: parent.meta,
537
+ source: parent.source,
538
+ deployedFrom: parent.deployedFrom,
539
+ children: newChildren,
540
+ });
541
+ }
466
542
  }
467
543
 
468
544
  BlockletState.BlockletStatus = BlockletStatus;
@@ -92,7 +92,7 @@ class NodeState extends BaseState {
92
92
  mode,
93
93
  runtimeConfig,
94
94
  ownerNft,
95
- launcherInfo,
95
+ launcher,
96
96
  didRegistry,
97
97
  didDomain,
98
98
  enablePassportIssuance = true,
@@ -128,7 +128,7 @@ class NodeState extends BaseState {
128
128
  runtimeConfig,
129
129
  ownerNft,
130
130
  diskAlertThreshold: DISK_ALERT_THRESHOLD_PERCENT,
131
- launcherInfo: launcherInfo || undefined,
131
+ launcher: launcher || undefined,
132
132
  didRegistry,
133
133
  didDomain,
134
134
  enablePassportIssuance,
@@ -162,7 +162,8 @@ class NodeState extends BaseState {
162
162
  // FIXME: 这个接口比较危险,可能会修改一些本不应该修改的字段,后续需要考虑改进
163
163
  async updateNodeInfo(entity = {}) {
164
164
  const record = await this.read();
165
- const updateResult = await this.update(record._id, { $set: omit(entity, ['ownerNft']) });
165
+
166
+ const updateResult = await this.update(record._id, { $set: omit(entity, ['ownerNft', 'sk']) });
166
167
  this.emit('node.updated', updateResult, record);
167
168
  return updateResult;
168
169
  }
@@ -42,7 +42,7 @@ const validateBlockletEntry = require('@blocklet/meta/lib/entry');
42
42
  const getBlockletEngine = require('@blocklet/meta/lib/engine');
43
43
  const getBlockletInfo = require('@blocklet/meta/lib/info');
44
44
  const { validateMeta, fixAndValidateService } = require('@blocklet/meta/lib/validate');
45
- const { forEachBlocklet } = require('@blocklet/meta/lib/util');
45
+ const { forEachBlocklet, isFreeBlocklet } = require('@blocklet/meta/lib/util');
46
46
 
47
47
  const { validate: validateEngine, get: getEngine } = require('../blocklet/manager/engine');
48
48
 
@@ -252,7 +252,7 @@ const getRootSystemEnvironments = (blocklet, nodeInfo) => {
252
252
  const appDescription = description || result.description;
253
253
 
254
254
  // FIXME: we should use https here when possible, eg, when did-gateway is available
255
- const appUrl = `http://${getDidDomainForBlocklet({ appId, didDomain: nodeInfo.didDomain })}`;
255
+ const appUrl = `http://${getDidDomainForBlocklet({ name, daemonDid: nodeInfo.did, didDomain: nodeInfo.didDomain })}`;
256
256
 
257
257
  return {
258
258
  BLOCKLET_DID: did,
@@ -951,7 +951,7 @@ const getRuntimeInfo = async (appId) => {
951
951
 
952
952
  /**
953
953
  * merge services
954
- * from meta.children[].mountPoints[].services
954
+ * from meta.children[].mountPoints[].services, meta.children[].services
955
955
  * to childrenMeta[].interfaces[].services
956
956
  *
957
957
  * @param {array<child>|object{children:array}} source e.g. [<config>] or { children: [<config>] }
@@ -993,6 +993,23 @@ const mergeMeta = (source, childrenMeta = []) => {
993
993
  childInterface.services = services;
994
994
  }
995
995
  });
996
+
997
+ if (config.services) {
998
+ const childInterface = findWebInterface(childMeta);
999
+ if (childInterface) {
1000
+ // merge
1001
+ const services = childInterface.services || [];
1002
+ config.services.forEach((x) => {
1003
+ const index = services.findIndex((y) => y.name === x.name);
1004
+ if (index >= 0) {
1005
+ services.splice(index, 1, x);
1006
+ } else {
1007
+ services.push(x);
1008
+ }
1009
+ });
1010
+ childInterface.services = services;
1011
+ }
1012
+ }
996
1013
  });
997
1014
  };
998
1015
 
@@ -1101,6 +1118,34 @@ const getDiffFiles = async (inputFiles, sourceDir) => {
1101
1118
 
1102
1119
  const getBundleDir = (installDir, bundle) => path.join(installDir, bundle.name, bundle.version);
1103
1120
 
1121
+ const needBlockletDownload = (blocklet, oldBlocklet) => {
1122
+ if ([BlockletSource.upload, BlockletSource.local, BlockletSource.custom].includes(blocklet.source)) {
1123
+ return false;
1124
+ }
1125
+
1126
+ if (!get(oldBlocklet, 'meta.dist.integrity')) {
1127
+ return true;
1128
+ }
1129
+
1130
+ if (get(oldBlocklet, 'meta.dist.integrity') === get(blocklet, 'meta.dist.integrity')) {
1131
+ return false;
1132
+ }
1133
+
1134
+ return true;
1135
+ };
1136
+
1137
+ const verifyPurchase = (meta, opts = {}) => {
1138
+ if (opts.blockletPurchaseVerified) {
1139
+ return true;
1140
+ }
1141
+
1142
+ if (isFreeBlocklet(meta)) {
1143
+ return true;
1144
+ }
1145
+
1146
+ throw new Error('Can not install a non-free blocklet directly');
1147
+ };
1148
+
1104
1149
  module.exports = {
1105
1150
  forEachBlocklet,
1106
1151
  getBlockletMetaFromUrl,
@@ -1135,4 +1180,6 @@ module.exports = {
1135
1180
  checkDuplicateComponents,
1136
1181
  getDiffFiles,
1137
1182
  getBundleDir,
1183
+ needBlockletDownload,
1184
+ verifyPurchase,
1138
1185
  };
@@ -16,8 +16,8 @@ const getIpDnsDomainForBlocklet = (blocklet, blockletInterface) => {
16
16
  }${iName}-${SLOT_FOR_IP_DNS_SITE}.${DEFAULT_IP_DNS_DOMAIN_SUFFIX}`;
17
17
  };
18
18
 
19
- const getDidDomainForBlocklet = ({ appId, didDomain }) => {
20
- return `${appId.toLowerCase()}.${didDomain}`;
19
+ const getDidDomainForBlocklet = ({ name, daemonDid, didDomain }) => {
20
+ return `${formatName(name)}-${daemonDid.toLowerCase()}.${didDomain}`;
21
21
  };
22
22
 
23
23
  module.exports = { getIpDnsDomainForBlocklet, getDidDomainForBlocklet };
package/lib/util/index.js CHANGED
@@ -373,7 +373,7 @@ const getBaseUrls = async (node, ips) => {
373
373
  if (info.routing.provider !== ROUTER_PROVIDER_NONE && info.routing.snapshotHash && info.routing.adminPath) {
374
374
  const sites = await node.getSitesFromSnapshot();
375
375
 
376
- const { dashboardDomain } = info.routing;
376
+ const { ipWildcardDomain } = info.routing;
377
377
  const adminPath = normalizePathPrefix(info.routing.adminPath);
378
378
  const tmpHttpPort = getPort(httpPort, DEFAULT_HTTP_PORT);
379
379
 
@@ -383,12 +383,12 @@ const getBaseUrls = async (node, ips) => {
383
383
  };
384
384
  });
385
385
 
386
- if (dashboardDomain) {
387
- const site = sites.find((c) => (c.domainAliases || []).find((item) => item.value === dashboardDomain));
386
+ if (ipWildcardDomain) {
387
+ const site = sites.find((c) => (c.domainAliases || []).find((item) => item.value === ipWildcardDomain));
388
388
  if (site) {
389
- const httpInfo = await getHttpInfo(dashboardDomain);
389
+ const httpInfo = await getHttpInfo(ipWildcardDomain);
390
390
  const httpsUrls = availableIps.map((ip) => ({
391
- url: `${httpInfo.protocol}://${transformIPToDomain(ip)}.${dashboardDomain.substring(2)}${
391
+ url: `${httpInfo.protocol}://${transformIPToDomain(ip)}.${ipWildcardDomain.substring(2)}${
392
392
  httpInfo.port
393
393
  }${adminPath}`,
394
394
  }));
@@ -27,9 +27,6 @@ const waitUpdaterRpc = async (message) =>
27
27
  const checkNewVersion = async (params, context) => {
28
28
  try {
29
29
  const info = await states.node.read();
30
- if (!info.autoUpgrade) {
31
- return '';
32
- }
33
30
 
34
31
  if (!process.env.ABT_NODE_PACKAGE_NAME) {
35
32
  logger.error('ABT_NODE_PACKAGE_NAME name was not found in environment');
@@ -176,7 +173,14 @@ const getCron = () => ({
176
173
  name: 'check-update',
177
174
  time: '0 0 8 * * *', // check every day
178
175
  // time: '0 */5 * * * *', // check every 5 minutes
179
- fn: checkNewVersion,
176
+ fn: async () => {
177
+ const info = await states.node.read();
178
+ if (!info.autoUpgrade) {
179
+ return;
180
+ }
181
+
182
+ checkNewVersion();
183
+ },
180
184
  options: { runOnInit: false },
181
185
  });
182
186