@abtnode/core 1.6.15 → 1.6.19

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.
@@ -49,7 +49,10 @@ class NodeState extends BaseState {
49
49
  }
50
50
 
51
51
  isInitialized(doc) {
52
- return !!doc.nodeOwner;
52
+ const isOwnerConnected = !!doc.nodeOwner;
53
+ const isControlledBy3rdParty =
54
+ !doc.enablePassportIssuance && Array.isArray(doc.trustedPassports) && doc.trustedPassports.length > 0;
55
+ return isOwnerConnected || isControlledBy3rdParty;
53
56
  }
54
57
 
55
58
  /**
@@ -92,13 +95,15 @@ class NodeState extends BaseState {
92
95
  launcherInfo,
93
96
  didRegistry,
94
97
  didDomain,
98
+ enablePassportIssuance = true,
99
+ trustedPassports = [],
95
100
  } = this.options;
96
101
 
97
102
  if (nodeOwner && !validateOwner(nodeOwner)) {
98
103
  return reject(new Error('Node owner is invalid'));
99
104
  }
100
105
 
101
- const initialized = this.isInitialized({ nodeOwner });
106
+ const initialized = this.isInitialized({ nodeOwner, enablePassportIssuance, trustedPassports });
102
107
 
103
108
  return getDefaultConfigs()
104
109
  .then((defaultConfigs) =>
@@ -126,6 +131,9 @@ class NodeState extends BaseState {
126
131
  launcherInfo: launcherInfo || undefined,
127
132
  didRegistry,
128
133
  didDomain,
134
+ enablePassportIssuance,
135
+ trustedPassports,
136
+ customBlockletNumber: 0,
129
137
  },
130
138
  async (e, data) => {
131
139
  if (e) {
@@ -262,6 +270,13 @@ class NodeState extends BaseState {
262
270
  getBlockletRegistry() {
263
271
  return this.read().then((info) => info.blockletRegistryList.find((item) => item.selected).url);
264
272
  }
273
+
274
+ async increaseCustomBlockletNumber() {
275
+ const { _id, customBlockletNumber = 0 } = await this.read();
276
+ const num = customBlockletNumber + 1;
277
+ await this.update(_id, { $set: { customBlockletNumber: num } });
278
+ return num;
279
+ }
265
280
  }
266
281
 
267
282
  module.exports = NodeState;
@@ -6,9 +6,11 @@ const os = require('os');
6
6
  const tar = require('tar');
7
7
  const get = require('lodash/get');
8
8
  const intersection = require('lodash/intersection');
9
+ const intersectionBy = require('lodash/intersectionBy');
9
10
  const streamToPromise = require('stream-to-promise');
10
11
  const { Throttle } = require('stream-throttle');
11
12
  const ssri = require('ssri');
13
+ const diff = require('deep-diff');
12
14
 
13
15
  const { toHex } = require('@ocap/util');
14
16
  const logger = require('@abtnode/logger')('@abtnode/core:util:blocklet');
@@ -17,7 +19,10 @@ const sleep = require('@abtnode/util/lib/sleep');
17
19
  const ensureEndpointHealthy = require('@abtnode/util/lib/ensure-endpoint-healthy');
18
20
  const CustomError = require('@abtnode/util/lib/custom-error');
19
21
  const getFolderSize = require('@abtnode/util/lib/get-folder-size');
22
+ const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
23
+ const hashFiles = require('@abtnode/util/lib/hash-files');
20
24
  const { BLOCKLET_MAX_MEM_LIMIT_IN_MB } = require('@abtnode/constant');
25
+
21
26
  const {
22
27
  BlockletStatus,
23
28
  BlockletSource,
@@ -29,6 +34,7 @@ const {
29
34
  BLOCKLET_DEFAULT_PORT_NAME,
30
35
  BLOCKLET_INTERFACE_TYPE_WEB,
31
36
  BLOCKLET_CONFIGURABLE_KEY,
37
+ BLOCKLET_DYNAMIC_PATH_PREFIX,
32
38
  fromBlockletStatus,
33
39
  } = require('@blocklet/meta/lib/constants');
34
40
  const verifyMultiSig = require('@blocklet/meta/lib/verify-multi-sig');
@@ -41,6 +47,7 @@ const { forEachBlocklet } = require('@blocklet/meta/lib/util');
41
47
  const { validate: validateEngine, get: getEngine } = require('../blocklet/manager/engine');
42
48
 
43
49
  const isRequirementsSatisfied = require('./requirement');
50
+ const { getDidDomainForBlocklet } = require('./get-domain-for-blocklet');
44
51
  const { getServices } = require('./service');
45
52
  const {
46
53
  isBeforeInstalled,
@@ -60,8 +67,6 @@ const getBlockletEngineNameByPlatform = (blockletMeta) => getBlockletEngine(bloc
60
67
 
61
68
  const noop = () => {};
62
69
 
63
- const asyncFs = fs.promises;
64
-
65
70
  const statusMap = {
66
71
  online: BlockletStatus.running,
67
72
  launching: BlockletStatus.starting,
@@ -79,8 +84,6 @@ const PRIVATE_NODE_ENVS = [
79
84
  'ABT_NODE_TOKEN_SECRET',
80
85
  'ABT_NODE_SK',
81
86
  'ABT_NODE_SESSION_SECRET',
82
- 'ABT_NODE_NAME',
83
- 'ABT_NODE_DESCRIPTION',
84
87
  'ABT_NODE_BASE_URL',
85
88
  'ABT_NODE_LOG_LEVEL',
86
89
  'ABT_NODE_LOG_DIR',
@@ -119,19 +122,9 @@ const getBlockletDirs = (blocklet, { rootBlocklet, dataDirs, ensure = false } =
119
122
  logsDir = path.join(dataDirs.logs, rootBlocklet.meta.name);
120
123
  }
121
124
 
122
- if (ensure) {
123
- try {
124
- fs.mkdirSync(dataDir, { recursive: true });
125
- fs.mkdirSync(logsDir, { recursive: true });
126
- fs.mkdirSync(cacheDir, { recursive: true });
127
- } catch (err) {
128
- logger.error('make blocklet dir failed', { error: err });
129
- }
130
- }
131
-
132
125
  // get app dirs
133
126
 
134
- const { version, main, group } = blocklet.meta;
127
+ const { main, group } = blocklet.meta;
135
128
 
136
129
  const startFromDevEntry =
137
130
  blocklet.mode === BLOCKLET_MODES.DEVELOPMENT && blocklet.meta.scripts && blocklet.meta.scripts.dev;
@@ -146,13 +139,24 @@ const getBlockletDirs = (blocklet, { rootBlocklet, dataDirs, ensure = false } =
146
139
  if (blocklet.source === BlockletSource.local) {
147
140
  appDir = blocklet.deployedFrom;
148
141
  } else {
149
- appDir = path.join(dataDirs.blocklets, name, version);
142
+ appDir = getBundleDir(dataDirs.blocklets, blocklet.meta);
150
143
  }
151
144
 
152
145
  if (!appDir) {
153
146
  throw new Error('Can not determine blocklet directory, maybe invalid deployment from local blocklets');
154
147
  }
155
148
 
149
+ if (ensure) {
150
+ try {
151
+ fs.mkdirSync(dataDir, { recursive: true });
152
+ fs.mkdirSync(logsDir, { recursive: true });
153
+ fs.mkdirSync(cacheDir, { recursive: true });
154
+ fs.mkdirSync(appDir, { recursive: true }); // prevent getDiskInfo failed from custom blocklet
155
+ } catch (err) {
156
+ logger.error('make blocklet dir failed', { error: err });
157
+ }
158
+ }
159
+
156
160
  mainDir = appDir;
157
161
 
158
162
  if (!startFromDevEntry && !isBeforeInstalled(rootBlocklet.status)) {
@@ -247,12 +251,16 @@ const getRootSystemEnvironments = (blocklet, nodeInfo) => {
247
251
  const appName = title || name || result.name;
248
252
  const appDescription = description || result.description;
249
253
 
254
+ // FIXME: we should use https here when possible, eg, when did-gateway is available
255
+ const appUrl = `http://${getDidDomainForBlocklet({ name, daemonDid: nodeInfo.did, didDomain: nodeInfo.didDomain })}`;
256
+
250
257
  return {
251
258
  BLOCKLET_DID: did,
252
259
  BLOCKLET_APP_SK: appSk,
253
260
  BLOCKLET_APP_ID: appId,
254
261
  BLOCKLET_APP_NAME: appName,
255
262
  BLOCKLET_APP_DESCRIPTION: appDescription,
263
+ BLOCKLET_APP_URL: appUrl,
256
264
  };
257
265
  };
258
266
 
@@ -432,11 +440,13 @@ const startBlockletProcess = async (blocklet, { preStart = noop, nodeEnvironment
432
440
  const options = {
433
441
  namespace: 'blocklets',
434
442
  name: appId,
435
- max_memory_restart: `${maxMemoryRestart}M`,
443
+ cwd: appCwd,
436
444
  time: true,
437
445
  output: path.join(logsDir, 'output.log'),
438
446
  error: path.join(logsDir, 'error.log'),
439
- cwd: appCwd,
447
+ wait_ready: process.env.NODE_ENV !== 'test',
448
+ listen_timeout: 5000,
449
+ max_memory_restart: `${maxMemoryRestart}M`,
440
450
  max_restarts: b.mode === BLOCKLET_MODES.DEVELOPMENT ? 0 : 3,
441
451
  env: {
442
452
  ...env,
@@ -464,17 +474,17 @@ const startBlockletProcess = async (blocklet, { preStart = noop, nodeEnvironment
464
474
  const engine = getEngine(blockletEngineInfo.interpreter);
465
475
  options.interpreter = engine.interpreter === 'node' ? '' : engine.interpreter;
466
476
  options.interpreterArgs = engine.args || '';
467
-
468
477
  options.script = blockletEngineInfo.script || appMain;
469
-
470
- logger.debug('start.blocklet.engine.info', { blockletEngineInfo });
471
- logger.debug('start.blocklet.max_memory_restart', { maxMemoryRestart });
472
478
  }
473
479
 
474
480
  await pm2.startAsync(options);
475
- logger.info('blocklet started', {
476
- appId,
477
- });
481
+
482
+ const status = await getProcessState(appId);
483
+ if (status === BlockletStatus.error) {
484
+ throw new Error(`${appId} is not running within 5 seconds`);
485
+ }
486
+
487
+ logger.info('blocklet started', { appId, status });
478
488
  },
479
489
  { parallel: true }
480
490
  );
@@ -537,6 +547,10 @@ const getBlockletStatusFromProcess = async (blocklet) => {
537
547
 
538
548
  const list = await Promise.all(tasks);
539
549
 
550
+ if (!list.length) {
551
+ return blocklet.status;
552
+ }
553
+
540
554
  return getRootBlockletStatus(list);
541
555
  };
542
556
 
@@ -615,26 +629,76 @@ const reloadProcess = (appId) =>
615
629
  });
616
630
  });
617
631
 
618
- const getChildrenMeta = async (meta) => {
619
- const children = [];
620
- if (meta.children && meta.children.length) {
621
- for (const child of meta.children) {
622
- const m = await getBlockletMetaFromUrl(child.resolved);
623
- if (m.name !== child.name) {
624
- logger.error('Resolved child blocklet name does not match in the configuration', {
625
- expected: child.name,
626
- resolved: m.name,
627
- });
628
- throw new Error(
629
- `Child blocklet name does not match in the configuration. expected: ${child.name}, resolved: ${m.name}`
630
- );
631
- }
632
- validateBlockletMeta(m, { ensureDist: true });
633
- children.push(m);
632
+ const findWebInterface = (blocklet) => {
633
+ const meta = blocklet.meta || blocklet || {};
634
+ const { interfaces = [] } = meta;
635
+
636
+ if (!Array.isArray(interfaces)) {
637
+ return null;
638
+ }
639
+
640
+ return interfaces.find((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
641
+ };
642
+
643
+ /**
644
+ * this function has side effect on children
645
+ */
646
+ const parseChildren = async (src, { children, dynamic } = {}) => {
647
+ const configs = Array.isArray(src) ? src : src.children || [];
648
+
649
+ if (children) {
650
+ children.forEach((x) => {
651
+ x.dynamic = !!dynamic;
652
+ });
653
+ mergeMeta(configs, children);
654
+ return children;
655
+ }
656
+
657
+ if (!configs || !configs.length) {
658
+ return [];
659
+ }
660
+
661
+ const results = [];
662
+
663
+ for (const config of configs) {
664
+ const mountPoint = config.mountPoint || config.mountPoints[0].root.prefix;
665
+ if (!mountPoint) {
666
+ throw new Error(`MountPoint does not found in child ${config.name}`);
667
+ }
668
+
669
+ const m = await getBlockletMetaFromUrl(config.resolved);
670
+ if (m.name !== config.name) {
671
+ logger.error('Resolved child blocklet name does not match in the configuration', {
672
+ expected: config.name,
673
+ resolved: m.name,
674
+ });
675
+ throw new Error(
676
+ `Child blocklet name does not match in the configuration. expected: ${config.name}, resolved: ${m.name}`
677
+ );
678
+ }
679
+ validateBlockletMeta(m, { ensureDist: true });
680
+
681
+ const webInterface = findWebInterface(m);
682
+ if (!webInterface) {
683
+ throw new Error(`Web interface does not found in child ${config.name}`);
684
+ }
685
+
686
+ const rule = webInterface.prefix;
687
+ if (rule !== BLOCKLET_DYNAMIC_PATH_PREFIX && normalizePathPrefix(rule) !== normalizePathPrefix(mountPoint)) {
688
+ throw new Error(`Prefix does not match in child ${config.name}. expected: ${rule}, resolved: ${mountPoint}`);
634
689
  }
690
+
691
+ results.push({
692
+ mountPoint,
693
+ meta: m,
694
+ dynamic: !!dynamic,
695
+ sourceUrl: config.resolved,
696
+ });
635
697
  }
636
698
 
637
- return children;
699
+ mergeMeta(configs, results);
700
+
701
+ return results;
638
702
  };
639
703
 
640
704
  const validateBlocklet = (blocklet) =>
@@ -732,7 +796,7 @@ const verifyIntegrity = async ({ file, integrity: expected }) => {
732
796
  return true;
733
797
  };
734
798
 
735
- const pruneBlockletBundle = async (blocklets, installDir) => {
799
+ const pruneBlockletBundle = async ({ blocklets, installDir, blockletSettings }) => {
736
800
  for (const blocklet of blocklets) {
737
801
  if (
738
802
  [
@@ -750,53 +814,104 @@ const pruneBlockletBundle = async (blocklets, installDir) => {
750
814
  }
751
815
  }
752
816
 
753
- // blockletMap: { <name/version>: true }
754
- const blockletMap = blocklets.reduce((map, b) => {
755
- map[`${b.meta.name}/${b.meta.version}`] = true;
756
- for (const child of b.children || []) {
757
- map[`${child.meta.name}/${child.meta.version}`] = true;
817
+ // blockletMap: { <[scope/]name/version>: true }
818
+ const blockletMap = {};
819
+ for (const blocklet of blocklets) {
820
+ blockletMap[`${blocklet.meta.name}/${blocklet.meta.version}`] = true;
821
+ for (const child of blocklet.children || []) {
822
+ blockletMap[`${child.meta.name}/${child.meta.version}`] = true;
758
823
  }
759
- return map;
760
- }, {});
824
+ }
825
+ for (const setting of blockletSettings) {
826
+ for (const child of setting.children || []) {
827
+ blockletMap[`${child.meta.name}/${child.meta.version}`] = true;
828
+ }
829
+ }
761
830
 
762
- // appDirs: [{ key: <name/version>, dir: appDir }]
831
+ // appDirs: [{ key: <[scope/]name/version>, dir: appDir }]
763
832
  const appDirs = [];
764
833
 
765
834
  // fill appDirs
766
835
  try {
767
- const fillAppDirs = async (dir) => {
768
- if (fs.existsSync(path.join(dir, 'blocklet.yml'))) {
836
+ // @return root/scope/bundle/version
837
+ const getNextLevel = (level, name) => {
838
+ if (level === 'root') {
839
+ if (name.startsWith('@')) {
840
+ return 'scope';
841
+ }
842
+ return 'bundle';
843
+ }
844
+ if (level === 'scope') {
845
+ return 'bundle';
846
+ }
847
+ if (level === 'bundle') {
848
+ return 'version';
849
+ }
850
+ throw new Error(`Invalid level ${level}`);
851
+ };
852
+
853
+ const fillAppDirs = async (dir, level = 'root') => {
854
+ if (level === 'version') {
855
+ if (!fs.existsSync(path.join(dir, 'blocklet.yml'))) {
856
+ logger.error('blocklet.yml does not exist in blocklet bundle dir', { dir });
857
+ return;
858
+ }
859
+
769
860
  appDirs.push({
770
861
  key: path.relative(installDir, dir),
771
862
  dir,
772
863
  });
864
+
773
865
  return;
774
866
  }
867
+
775
868
  const nextDirs = [];
776
- for (const x of await asyncFs.readdir(dir)) {
777
- const nextDir = path.join(dir, x);
778
- // if blocklet.yml does not exist in dir but non-folder file exists in dir, stop finding
779
- if (!fs.lstatSync(nextDir).isDirectory()) {
780
- logger.error('blocklet.yml does not exist in blocklet bundle dir', { dir });
781
- return;
869
+ for (const x of await fs.promises.readdir(dir)) {
870
+ if (!fs.lstatSync(path.join(dir, x)).isDirectory()) {
871
+ logger.error('pruneBlockletBundle: invalid file in bundle storage', { dir, file: x });
872
+ // eslint-disable-next-line no-continue
873
+ continue;
782
874
  }
783
- nextDirs.push(nextDir);
875
+ nextDirs.push(x);
784
876
  }
785
877
 
786
878
  for (const x of nextDirs) {
787
- await fillAppDirs(x);
879
+ await fillAppDirs(path.join(dir, x), getNextLevel(level, x));
788
880
  }
789
881
  };
790
- await fillAppDirs(installDir);
882
+ await fillAppDirs(installDir, 'root');
791
883
  } catch (error) {
792
884
  logger.error('fill app dirs failed', { error });
793
885
  }
794
886
 
887
+ const ensureBundleDirRemoved = async (dir) => {
888
+ const relativeDir = path.relative(installDir, dir);
889
+ const arr = relativeDir.split('/').filter(Boolean);
890
+ const { length } = arr;
891
+ const bundleName = arr[length - 2];
892
+ const scopeName = length > 2 ? arr[length - 3] : '';
893
+ const bundleDir = path.join(installDir, scopeName, bundleName);
894
+ const isEmpty = (await fs.promises.readdir(bundleDir)).length === 0;
895
+ if (isEmpty) {
896
+ logger.info('Remove bundle folder', { bundleDir });
897
+ await fs.remove(bundleDir);
898
+ }
899
+ if (scopeName) {
900
+ const scopeDir = path.join(installDir, scopeName);
901
+ const isScopeEmpty = (await fs.promises.readdir(scopeDir)).length === 0;
902
+ if (isScopeEmpty) {
903
+ logger.info('Remove scope folder', { scopeDir });
904
+ await fs.remove(scopeDir);
905
+ }
906
+ }
907
+ };
908
+
795
909
  // remove trash
796
910
  for (const app of appDirs) {
797
911
  if (!blockletMap[app.key]) {
798
- logger.info('Remove blocklet bundle', { dir: app.dir });
912
+ logger.info('Remove app folder', { dir: app.dir });
799
913
  await fs.remove(app.dir);
914
+ await ensureBundleDirRemoved(app.dir);
800
915
  }
801
916
  }
802
917
 
@@ -834,15 +949,25 @@ const getRuntimeInfo = async (appId) => {
834
949
  };
835
950
  };
836
951
 
837
- const mergeMeta = (meta, childrenMeta = []) => {
952
+ /**
953
+ * merge services
954
+ * from meta.children[].mountPoints[].services
955
+ * to childrenMeta[].interfaces[].services
956
+ *
957
+ * @param {array<child>|object{children:array}} source e.g. [<config>] or { children: [<config>] }
958
+ * @param {array<meta|{meta}>} childrenMeta e.g. [<meta>] or [{ meta: <meta> }]
959
+ */
960
+
961
+ const mergeMeta = (source, childrenMeta = []) => {
838
962
  // configMap
839
963
  const configMap = {};
840
- (meta.children || []).forEach((x) => {
964
+ (Array.isArray(source) ? source : source.children || []).forEach((x) => {
841
965
  configMap[x.name] = x;
842
966
  });
843
967
 
844
968
  // merge service from config to child meta
845
- childrenMeta.forEach((childMeta) => {
969
+ childrenMeta.forEach((child) => {
970
+ const childMeta = child.meta || child;
846
971
  const config = configMap[childMeta.name];
847
972
  if (!config) {
848
973
  return;
@@ -902,10 +1027,100 @@ const getUpdateMetaList = (oldMetas = [], newMetas = []) => {
902
1027
  return newMetas.filter(({ version, did }) => did && version !== oldMap[did]);
903
1028
  };
904
1029
 
1030
+ const getSourceFromInstallParams = (params) => {
1031
+ if (params.url) {
1032
+ return BlockletSource.url;
1033
+ }
1034
+
1035
+ if (params.file) {
1036
+ return BlockletSource.upload;
1037
+ }
1038
+
1039
+ if (params.did) {
1040
+ return BlockletSource.registry;
1041
+ }
1042
+
1043
+ if (params.title && params.description) {
1044
+ return BlockletSource.custom;
1045
+ }
1046
+
1047
+ throw new Error('Can only install blocklet from store/url/upload/custom');
1048
+ };
1049
+
1050
+ const checkDuplicateComponents = (dynamicComponents, staticComponents) => {
1051
+ const duplicates = intersectionBy(dynamicComponents, staticComponents, 'meta.did');
1052
+ if (duplicates.length) {
1053
+ throw new Error(
1054
+ `Cannot add duplicate component${duplicates.length > 1 ? 's' : ''}: ${duplicates
1055
+ .map((x) => x.meta.title || x.meta.name)
1056
+ .join(', ')}`
1057
+ );
1058
+ }
1059
+ };
1060
+
1061
+ const getDiffFiles = async (inputFiles, sourceDir) => {
1062
+ if (!fs.existsSync(sourceDir)) {
1063
+ throw new Error(`${sourceDir} does not exist`);
1064
+ }
1065
+
1066
+ const files = inputFiles.reduce((obj, item) => {
1067
+ obj[item.file] = item.hash;
1068
+ return obj;
1069
+ }, {});
1070
+
1071
+ const { files: sourceFiles } = await hashFiles(sourceDir, {
1072
+ filter: (x) => x.indexOf('node_modules') === -1,
1073
+ concurrentHash: 1,
1074
+ });
1075
+
1076
+ const addSet = [];
1077
+ const changeSet = [];
1078
+ const deleteSet = [];
1079
+
1080
+ const diffFiles = diff(sourceFiles, files);
1081
+ if (diffFiles) {
1082
+ diffFiles.forEach((item) => {
1083
+ if (item.kind === 'D') {
1084
+ deleteSet.push(item.path[0]);
1085
+ }
1086
+ if (item.kind === 'E') {
1087
+ changeSet.push(item.path[0]);
1088
+ }
1089
+ if (item.kind === 'N') {
1090
+ addSet.push(item.path[0]);
1091
+ }
1092
+ });
1093
+ }
1094
+
1095
+ return {
1096
+ addSet,
1097
+ changeSet,
1098
+ deleteSet,
1099
+ };
1100
+ };
1101
+
1102
+ const getBundleDir = (installDir, bundle) => path.join(installDir, bundle.name, bundle.version);
1103
+
1104
+ const needBlockletDownload = (blocklet, oldBlocklet) => {
1105
+ if ([BlockletSource.upload, BlockletSource.local, BlockletSource.custom].includes(blocklet.source)) {
1106
+ return false;
1107
+ }
1108
+
1109
+ if (!get(oldBlocklet, 'meta.dist.integrity')) {
1110
+ return true;
1111
+ }
1112
+
1113
+ if (get(oldBlocklet, 'meta.dist.integrity') === get(blocklet, 'meta.dist.integrity')) {
1114
+ return false;
1115
+ }
1116
+
1117
+ return true;
1118
+ };
1119
+
905
1120
  module.exports = {
906
1121
  forEachBlocklet,
907
1122
  getBlockletMetaFromUrl,
908
- getChildrenMeta,
1123
+ parseChildren,
909
1124
  getBlockletDirs,
910
1125
  getRootSystemEnvironments,
911
1126
  getSystemEnvironments,
@@ -931,4 +1146,10 @@ module.exports = {
931
1146
  mergeMeta,
932
1147
  fixAndVerifyBlockletMeta,
933
1148
  getUpdateMetaList,
1149
+ getSourceFromInstallParams,
1150
+ findWebInterface,
1151
+ checkDuplicateComponents,
1152
+ getDiffFiles,
1153
+ getBundleDir,
1154
+ needBlockletDownload,
934
1155
  };
@@ -35,7 +35,7 @@ const defaultNodeConfigs = {
35
35
  },
36
36
  ],
37
37
  },
38
- registerUrl: { getDefaultValue: () => NODE_REGISTER_URL }, // removed in 1.5.1
38
+ registerUrl: { getDefaultValue: () => NODE_REGISTER_URL },
39
39
  webWalletUrl: { getDefaultValue: () => WEB_WALLET_URL },
40
40
  };
41
41
 
@@ -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 };
@@ -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
 
@@ -9,14 +9,23 @@ const nodeInfoSchema = Joi.object({
9
9
  description: Joi.string()
10
10
  .required()
11
11
  .messages({ zh: { 'string.empty': '描述不能为空' }, en: { 'string.empty': 'Description cannot be empty' } }),
12
+ registerUrl: Joi.string()
13
+ .uri({ scheme: [/https?/] })
14
+ .label('register url')
15
+ .allow('')
16
+ .optional()
17
+ .messages({
18
+ zh: { 'string.uriCustomScheme': '应用启动器必须是合法的 URL' },
19
+ en: { 'string.uriCustomScheme': 'Blocklet Launcher must be a valid URL' },
20
+ }),
12
21
  webWalletUrl: Joi.string()
13
22
  .uri({ scheme: [/https?/] })
14
23
  .label('web wallet url')
15
24
  .allow('')
16
25
  .optional()
17
26
  .messages({
18
- zh: { 'string.uriCustomScheme': 'Web DID Wallet 必须是合法的 URL' },
19
- en: { 'string.uriCustomScheme': 'Web DID Wallet must be a valid URL' },
27
+ zh: { 'string.uriCustomScheme': 'Web Wallet 必须是合法的 URL' },
28
+ en: { 'string.uriCustomScheme': 'Web Wallet must be a valid URL' },
20
29
  }),
21
30
  autoUpgrade: Joi.boolean(),
22
31
  enableWelcomePage: Joi.boolean(),
@@ -31,16 +40,6 @@ const nodeInfoSchema = Joi.object({
31
40
  'number.max': 'Disk usage alert threshold cannot be higher than 99%',
32
41
  },
33
42
  }),
34
- // removed in 1.5.1
35
- registerUrl: Joi.string()
36
- .uri({ scheme: [/https?/] })
37
- .label('register url')
38
- .allow('')
39
- .optional()
40
- .messages({
41
- zh: { 'string.uriCustomScheme': '注册地址必须是合法的 URL' },
42
- en: { 'string.uriCustomScheme': 'Registry URL must be a valid URL' },
43
- }),
44
43
  }).options({ stripUnknown: true });
45
44
 
46
45
  module.exports = {