@abtnode/core 1.7.19 → 1.7.20

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.
@@ -5,7 +5,6 @@ const path = require('path');
5
5
  const os = require('os');
6
6
  const tar = require('tar');
7
7
  const get = require('lodash/get');
8
- const intersection = require('lodash/intersection');
9
8
  const streamToPromise = require('stream-to-promise');
10
9
  const { Throttle } = require('stream-throttle');
11
10
  const ssri = require('ssri');
@@ -43,8 +42,19 @@ const validateBlockletEntry = require('@blocklet/meta/lib/entry');
43
42
  const getBlockletEngine = require('@blocklet/meta/lib/engine');
44
43
  const getBlockletInfo = require('@blocklet/meta/lib/info');
45
44
  const { validateMeta, fixAndValidateService } = require('@blocklet/meta/lib/validate');
46
- const { forEachBlocklet, isFreeBlocklet, getDisplayName, findWebInterface } = require('@blocklet/meta/lib/util');
45
+ const {
46
+ forEachBlocklet,
47
+ isFreeBlocklet,
48
+ getDisplayName,
49
+ findWebInterface,
50
+ forEachBlockletSync,
51
+ forEachChildSync,
52
+ isComponentBlocklet,
53
+ getSharedConfigObj,
54
+ getComponentName,
55
+ } = require('@blocklet/meta/lib/util');
47
56
  const toBlockletDid = require('@blocklet/meta/lib/did');
57
+ const { titleSchema, descriptionSchema } = require('@blocklet/meta/lib/schema');
48
58
 
49
59
  const { validate: validateEngine, get: getEngine } = require('../blocklet/manager/engine');
50
60
 
@@ -97,44 +107,36 @@ const PRIVATE_NODE_ENVS = [
97
107
 
98
108
  /**
99
109
  * @returns { dataDir, logsDir, cacheDir, appMain, appDir, mainDir, appCwd }
100
- * dataDir: dataDirs.data/name (root blocklet) or dataDirs.data/name/childName (child blocklet)
110
+ * dataDir: dataDirs.data/name (root component) or dataDirs.data/name/childName (child component)
101
111
  * logsDir: dataDirs.log/name
102
- * cacheDir: dataDirs.cache/name (root blocklet) or dataDirs.cache/name/childName (child blocklet)
103
- * appDir: blocklet bundle dir
104
- * mainDir: appDir (dapp) or appDir/main (static). Used for for static blocklet
105
- * appMain: app entry file or script (run appMain to start blocklet process)
112
+ * cacheDir: dataDirs.cache/name (root component) or dataDirs.cache/name/childName (child component)
113
+ * appDir: component bundle dir
114
+ * mainDir: appDir (dapp) or appDir/main (static). Used for for static component
115
+ * appMain: app entry file or script (run appMain to start component process)
106
116
  * appCwd: cwd of appMain
107
117
  */
108
- const getBlockletDirs = (
109
- blocklet,
110
- { rootBlocklet, dataDirs, ensure = false, e2eMode = false, validate = true } = {}
118
+ const getComponentDirs = (
119
+ component,
120
+ { dataDirs, ensure = false, e2eMode = false, validate = true, ancestors = [] } = {}
111
121
  ) => {
112
- if (!rootBlocklet) {
113
- // eslint-disable-next-line no-param-reassign
114
- rootBlocklet = blocklet;
115
- }
116
122
  // get data dirs
117
123
 
118
- const { name } = blocklet.meta;
124
+ const { name: appName } = ancestors.concat(component)[0].meta;
125
+ const componentName = getComponentName(component, ancestors);
119
126
 
120
- let logsDir = path.join(dataDirs.logs, name);
121
- let dataDir = path.join(dataDirs.data, name);
122
- let cacheDir = path.join(dataDirs.cache, name);
123
- if (rootBlocklet !== blocklet) {
124
- dataDir = path.join(dataDirs.data, rootBlocklet.meta.name, name);
125
- cacheDir = path.join(dataDirs.cache, rootBlocklet.meta.name, name);
126
- logsDir = path.join(dataDirs.logs, rootBlocklet.meta.name);
127
- }
127
+ const logsDir = path.join(dataDirs.logs, appName);
128
+ const dataDir = path.join(dataDirs.data, componentName);
129
+ const cacheDir = path.join(dataDirs.cache, componentName);
128
130
 
129
131
  // get app dirs
130
132
 
131
- const { main, group } = blocklet.meta;
133
+ const { main, group } = component.meta;
132
134
 
133
135
  let startFromDevEntry = '';
134
- if (blocklet.mode === BLOCKLET_MODES.DEVELOPMENT && blocklet.meta.scripts) {
135
- startFromDevEntry = blocklet.meta.scripts.dev;
136
- if (e2eMode && blocklet.meta.scripts.e2eDev) {
137
- startFromDevEntry = blocklet.meta.scripts.e2eDev;
136
+ if (component.mode === BLOCKLET_MODES.DEVELOPMENT && component.meta.scripts) {
137
+ startFromDevEntry = component.meta.scripts.dev;
138
+ if (e2eMode && component.meta.scripts.e2eDev) {
139
+ startFromDevEntry = component.meta.scripts.e2eDev;
138
140
  }
139
141
  }
140
142
 
@@ -145,10 +147,10 @@ const getBlockletDirs = (
145
147
  let appDir = null;
146
148
  let mainDir = null;
147
149
 
148
- if (blocklet.source === BlockletSource.local) {
149
- appDir = blocklet.deployedFrom;
150
+ if (component.source === BlockletSource.local) {
151
+ appDir = component.deployedFrom;
150
152
  } else {
151
- appDir = getBundleDir(dataDirs.blocklets, blocklet.meta);
153
+ appDir = getBundleDir(dataDirs.blocklets, component.meta);
152
154
  }
153
155
 
154
156
  if (!appDir) {
@@ -168,9 +170,9 @@ const getBlockletDirs = (
168
170
 
169
171
  mainDir = appDir;
170
172
 
171
- if (validate && !startFromDevEntry && !isBeforeInstalled(rootBlocklet.status)) {
173
+ if (validate && !startFromDevEntry && !isBeforeInstalled(component.status)) {
172
174
  try {
173
- validateBlockletEntry(appDir, blocklet.meta);
175
+ validateBlockletEntry(appDir, component.meta);
174
176
  } catch (err) {
175
177
  throw new CustomError('BLOCKLET_CORRUPTED', err.message);
176
178
  }
@@ -186,7 +188,7 @@ const getBlockletDirs = (
186
188
  appMain = startFromDevEntry;
187
189
  appCwd = appDir;
188
190
  } else if (group === 'dapp') {
189
- appMain = getBlockletEngine(blocklet.meta).script || BLOCKLET_ENTRY_FILE;
191
+ appMain = getBlockletEngine(component.meta).script || BLOCKLET_ENTRY_FILE;
190
192
  appCwd = appDir;
191
193
  } else if (group === 'static') {
192
194
  mainDir = path.join(appDir, main);
@@ -200,11 +202,11 @@ const getBlockletDirs = (
200
202
  };
201
203
 
202
204
  /**
203
- * set 'configs', configObj', 'environmentObj' to blocklet
205
+ * set 'configs', configObj', 'environmentObj' to blocklet TODO
204
206
  * @param {*} blocklet
205
207
  * @param {*} configs
206
208
  */
207
- const fillBlockletConfigs = (blocklet, configs, parent) => {
209
+ const fillBlockletConfigs = (blocklet, configs) => {
208
210
  blocklet.configs = configs || [];
209
211
  blocklet.configObj = blocklet.configs.reduce((acc, x) => {
210
212
  acc[x.key] = x.value;
@@ -214,13 +216,6 @@ const fillBlockletConfigs = (blocklet, configs, parent) => {
214
216
  acc[x.key] = x.value;
215
217
  return acc;
216
218
  }, {});
217
-
218
- const sharedConfigs = getSharedConfigs(blocklet, parent);
219
- Object.keys(sharedConfigs).forEach((key) => {
220
- blocklet.configObj[key] = sharedConfigs[key];
221
- const item = blocklet.configs.find((x) => x.key === key);
222
- item.value = sharedConfigs[key];
223
- });
224
219
  };
225
220
 
226
221
  const ensureBlockletExpanded = async (meta, appDir) => {
@@ -243,7 +238,7 @@ const ensureBlockletExpanded = async (meta, appDir) => {
243
238
  }
244
239
  };
245
240
 
246
- const getRootSystemEnvironments = (blocklet, nodeInfo) => {
241
+ const getAppSystemEnvironments = (blocklet, nodeInfo) => {
247
242
  const { did, name, title, description } = blocklet.meta;
248
243
  const keys = Object.keys(BLOCKLET_CONFIGURABLE_KEY);
249
244
  const result = getBlockletInfo(
@@ -273,7 +268,7 @@ const getRootSystemEnvironments = (blocklet, nodeInfo) => {
273
268
  };
274
269
  };
275
270
 
276
- const getOverwrittenEnvironments = (blocklet, nodeInfo) => {
271
+ const getAppOverwrittenEnvironments = (blocklet, nodeInfo) => {
277
272
  const result = {};
278
273
  if (!blocklet || !blocklet.configObj) {
279
274
  return result;
@@ -306,7 +301,7 @@ const getOverwrittenEnvironments = (blocklet, nodeInfo) => {
306
301
  return result;
307
302
  };
308
303
 
309
- const getSystemEnvironments = (blocklet) => {
304
+ const getComponentSystemEnvironments = (blocklet) => {
310
305
  const { port, ports } = blocklet;
311
306
  const portEnvironments = {};
312
307
  if (port) {
@@ -316,17 +311,17 @@ const getSystemEnvironments = (blocklet) => {
316
311
  Object.assign(portEnvironments, ports);
317
312
  }
318
313
  return {
314
+ BLOCKLET_REAL_DID: blocklet.env.id,
319
315
  BLOCKLET_DATA_DIR: blocklet.env.dataDir,
320
316
  BLOCKLET_LOG_DIR: blocklet.env.logsDir,
321
317
  BLOCKLET_CACHE_DIR: blocklet.env.cacheDir,
322
- BLOCKLET_REAL_DID: blocklet.meta.did,
323
318
  BLOCKLET_APP_DIR: blocklet.env.appDir,
324
319
  BLOCKLET_MAIN_DIR: blocklet.env.mainDir,
325
320
  ...portEnvironments,
326
321
  };
327
322
  };
328
323
 
329
- const getRuntimeEnvironments = (blocklet, nodeEnvironments, parent) => {
324
+ const getRuntimeEnvironments = (blocklet, nodeEnvironments, ancestors) => {
330
325
  // pm2 will force inject env variables of daemon process to blocklet process
331
326
  // we can only rewrite these private env variables to empty
332
327
  const safeNodeEnvironments = PRIVATE_NODE_ENVS.reduce((o, x) => {
@@ -335,30 +330,14 @@ const getRuntimeEnvironments = (blocklet, nodeEnvironments, parent) => {
335
330
  }, {});
336
331
 
337
332
  return {
338
- ...blocklet.environmentObj,
339
333
  ...blocklet.configObj,
340
- ...getSharedConfigs(blocklet, parent),
334
+ ...getSharedConfigObj(blocklet, ancestors),
335
+ ...blocklet.environmentObj,
341
336
  ...nodeEnvironments,
342
337
  ...safeNodeEnvironments,
343
338
  };
344
339
  };
345
340
 
346
- // we support share insecure same configs between parent and child blocklets
347
- const getSharedConfigs = (child, parent) => {
348
- const sharedConfigs = {};
349
- if (parent && Array.isArray(parent.configs) && child.meta.did !== parent.meta.did) {
350
- const parentKeys = parent.configs.filter((x) => x.secure === false && x.shared !== false).map((x) => x.key);
351
- const childKeys = child.configs.map((x) => x.key);
352
- const sharedKeys = intersection(parentKeys, childKeys);
353
- sharedKeys.forEach((key) => {
354
- if (!child.configObj[key]) {
355
- sharedConfigs[key] = parent.configObj[key];
356
- }
357
- });
358
- }
359
- return sharedConfigs;
360
- };
361
-
362
341
  const isUsefulError = (err) => err && err.message !== 'process or namespace not found';
363
342
 
364
343
  const getHealthyCheckTimeout = (blocklet, { checkHealthImmediately } = {}) => {
@@ -435,32 +414,40 @@ const getBlockletMetaFromUrls = async (urls) => {
435
414
  * Start all precesses of a blocklet
436
415
  * @param {*} blocklet should contain env props
437
416
  */
438
- const startBlockletProcess = async (blocklet, { preStart = noop, nodeEnvironments, nodeInfo, e2eMode } = {}) => {
417
+ const startBlockletProcess = async (
418
+ blocklet,
419
+ { preStart = noop, nodeEnvironments, nodeInfo, e2eMode, skippedProcessIds = [] } = {}
420
+ ) => {
439
421
  if (!blocklet) {
440
422
  throw new Error('blocklet should not be empty');
441
423
  }
442
424
 
443
425
  await forEachBlocklet(
444
426
  blocklet,
445
- async (b) => {
427
+ async (b, { ancestors }) => {
446
428
  if (b.meta.group === BlockletGroup.gateway) {
447
429
  return;
448
430
  }
449
431
 
450
- const { appMain, appId, appCwd, logsDir } = b.env;
432
+ const { appMain, processId, appCwd, logsDir } = b.env;
433
+
434
+ if (skippedProcessIds.includes(processId)) {
435
+ logger.info(`skip start process ${processId}`);
436
+ return;
437
+ }
451
438
 
452
439
  // get env
453
- const env = getRuntimeEnvironments(b, nodeEnvironments);
440
+ const env = getRuntimeEnvironments(b, nodeEnvironments, ancestors);
454
441
 
455
442
  // run hook
456
- await preStart(b);
443
+ await preStart(b, { env });
457
444
 
458
445
  // start process
459
446
  const maxMemoryRestart = get(nodeInfo, 'runtimeConfig.blockletMaxMemoryLimit', BLOCKLET_MAX_MEM_LIMIT_IN_MB);
460
447
 
461
448
  const options = {
462
449
  namespace: 'blocklets',
463
- name: appId,
450
+ name: processId,
464
451
  cwd: appCwd,
465
452
  time: true,
466
453
  output: path.join(logsDir, 'output.log'),
@@ -500,12 +487,12 @@ const startBlockletProcess = async (blocklet, { preStart = noop, nodeEnvironment
500
487
 
501
488
  await pm2.startAsync(options);
502
489
 
503
- const status = await getProcessState(appId);
490
+ const status = await getProcessState(processId);
504
491
  if (status === BlockletStatus.error) {
505
- throw new Error(`${appId} is not running within 5 seconds`);
492
+ throw new Error(`${processId} is not running within 5 seconds`);
506
493
  }
507
494
 
508
- logger.info('blocklet started', { appId, status });
495
+ logger.info('blocklet started', { processId, status });
509
496
  },
510
497
  { parallel: true }
511
498
  );
@@ -515,12 +502,17 @@ const startBlockletProcess = async (blocklet, { preStart = noop, nodeEnvironment
515
502
  * Stop all precesses of a blocklet
516
503
  * @param {*} blocklet should contain env props
517
504
  */
518
- const stopBlockletProcess = async (blocklet, { preStop = noop } = {}) => {
505
+ const stopBlockletProcess = async (blocklet, { preStop = noop, skippedProcessIds = [] } = {}) => {
519
506
  await forEachBlocklet(
520
507
  blocklet,
521
- async (b) => {
522
- await preStop(b);
523
- await deleteProcess(b.env.appId);
508
+ async (b, { ancestors }) => {
509
+ if (skippedProcessIds.includes(b.env.processId)) {
510
+ logger.info(`skip stop process ${b.env.processId}`);
511
+ return;
512
+ }
513
+
514
+ await preStop(b, { ancestors });
515
+ await deleteProcess(b.env.processId);
524
516
  },
525
517
  { parallel: true }
526
518
  );
@@ -530,12 +522,17 @@ const stopBlockletProcess = async (blocklet, { preStop = noop } = {}) => {
530
522
  * Delete all precesses of a blocklet
531
523
  * @param {*} blocklet should contain env props
532
524
  */
533
- const deleteBlockletProcess = async (blocklet, { preDelete = noop } = {}) => {
525
+ const deleteBlockletProcess = async (blocklet, { preDelete = noop, skippedProcessIds = [] } = {}) => {
534
526
  await forEachBlocklet(
535
527
  blocklet,
536
- async (b) => {
537
- await preDelete(b);
538
- await deleteProcess(b.env.appId);
528
+ async (b, { ancestors }) => {
529
+ if (skippedProcessIds.includes(b.env.processId)) {
530
+ logger.info(`skip delete process ${b.env.processId}`);
531
+ return;
532
+ }
533
+
534
+ await preDelete(b, { ancestors });
535
+ await deleteProcess(b.env.processId);
539
536
  },
540
537
  { parallel: true }
541
538
  );
@@ -552,8 +549,8 @@ const reloadBlockletProcess = async (blocklet) =>
552
549
  if (b.meta.group === BlockletGroup.gateway) {
553
550
  return;
554
551
  }
555
- logger.info('reload process', { appId: b.env.appId });
556
- await reloadProcess(b.env.appId);
552
+ logger.info('reload process', { processId: b.env.processId });
553
+ await reloadProcess(b.env.processId);
557
554
  },
558
555
  { parallel: false }
559
556
  );
@@ -562,7 +559,7 @@ const getBlockletStatusFromProcess = async (blocklet) => {
562
559
  const tasks = [];
563
560
  await forEachBlocklet(blocklet, (b) => {
564
561
  if (b.meta.group !== BlockletGroup.gateway) {
565
- tasks.push(getProcessState(b.env.appId));
562
+ tasks.push(getProcessState(b.env.processId));
566
563
  }
567
564
  });
568
565
 
@@ -592,11 +589,11 @@ const getRootBlockletStatus = (statusList = []) => {
592
589
  };
593
590
 
594
591
  /**
595
- * @param {*} appId
592
+ * @param {*} processId
596
593
  * @returns {BlockletStatus}
597
594
  */
598
- const getProcessState = async (appId) => {
599
- const info = await getProcessInfo(appId);
595
+ const getProcessState = async (processId) => {
596
+ const info = await getProcessInfo(processId);
600
597
  if (!statusMap[info.pm2_env.status]) {
601
598
  logger.error('Cannot find the blocklet status for pm2 status mapping', {
602
599
  pm2Status: info.pm2_env.status,
@@ -608,9 +605,9 @@ const getProcessState = async (appId) => {
608
605
  return statusMap[info.pm2_env.status];
609
606
  };
610
607
 
611
- const getProcessInfo = (appId) =>
608
+ const getProcessInfo = (processId) =>
612
609
  new Promise((resolve, reject) => {
613
- pm2.describe(appId, async (err, [info]) => {
610
+ pm2.describe(processId, async (err, [info]) => {
614
611
  if (err) {
615
612
  logger.error('Failed to get blocklet status from pm2', { error: err });
616
613
  return reject(err);
@@ -624,10 +621,10 @@ const getProcessInfo = (appId) =>
624
621
  });
625
622
  });
626
623
 
627
- const deleteProcess = (appId) =>
624
+ const deleteProcess = (processId) =>
628
625
  new Promise((resolve, reject) => {
629
626
  pm2.connect(() => {
630
- pm2.delete(appId, async (err) => {
627
+ pm2.delete(processId, async (err) => {
631
628
  if (isUsefulError(err)) {
632
629
  logger.error('blocklet process delete failed', { error: err });
633
630
  return reject(err);
@@ -637,9 +634,9 @@ const deleteProcess = (appId) =>
637
634
  });
638
635
  });
639
636
 
640
- const reloadProcess = (appId) =>
637
+ const reloadProcess = (processId) =>
641
638
  new Promise((resolve, reject) => {
642
- pm2.reload(appId, async (err) => {
639
+ pm2.reload(processId, async (err) => {
643
640
  if (err) {
644
641
  if (isUsefulError(err)) {
645
642
  logger.error('blocklet reload failed', { error: err });
@@ -696,7 +693,12 @@ const getSourceUrlsFromConfig = (config) => {
696
693
  /**
697
694
  * this function has side effect on children
698
695
  */
699
- const parseChildrenFromMeta = async (src, { dynamic } = {}) => {
696
+ const parseChildrenFromMeta = async (src, context = {}) => {
697
+ const { dynamic, ancestors = [] } = context;
698
+ if (ancestors.length > 40) {
699
+ throw new Error('The depth of component should not exceed 40');
700
+ }
701
+
700
702
  const configs = Array.isArray(src) ? src : src.children || [];
701
703
 
702
704
  if (!configs || !configs.length) {
@@ -722,22 +724,42 @@ const parseChildrenFromMeta = async (src, { dynamic } = {}) => {
722
724
 
723
725
  validateBlockletMeta(m, { ensureDist: true });
724
726
 
727
+ verifyPurchase(m, context);
728
+
729
+ if (!isComponentBlocklet(m)) {
730
+ throw new Error(`The blocklet cannot be a component: ${m.title}`);
731
+ }
732
+
725
733
  const webInterface = findWebInterface(m);
726
734
  if (!webInterface) {
727
735
  throw new Error(`Web interface does not found in child ${config.name}`);
728
736
  }
729
737
 
738
+ // validate mountPoint
730
739
  const rule = webInterface.prefix;
731
- if (rule !== BLOCKLET_DYNAMIC_PATH_PREFIX && normalizePathPrefix(rule) !== normalizePathPrefix(mountPoint)) {
732
- throw new Error(`Prefix does not match in child ${config.name}. expected: ${rule}, resolved: ${mountPoint}`);
740
+ if (rule !== BLOCKLET_DYNAMIC_PATH_PREFIX) {
741
+ const fullMountPoint = path.join(
742
+ ancestors.map((x) => x.mountPoint || ''),
743
+ mountPoint
744
+ );
745
+ if (normalizePathPrefix(rule) !== normalizePathPrefix(fullMountPoint)) {
746
+ throw new Error(`Prefix does not match in child ${config.name}. expected: ${rule}, resolved: ${mountPoint}`);
747
+ }
733
748
  }
734
749
 
735
750
  const meta = ensureMeta(m, { name: config.name });
751
+
752
+ // check circular dependencies
753
+ if (ancestors.map((x) => x.meta?.bundleDid).indexOf(meta.bundleDid) > -1) {
754
+ throw new Error('Blocklet components have circular dependencies');
755
+ }
756
+
736
757
  if (config.title) {
737
758
  meta.title = config.title;
759
+ meta.title = await titleSchema.validateAsync(config.title);
738
760
  }
739
761
  if (config.description) {
740
- meta.description = config.description;
762
+ meta.description = await descriptionSchema.validateAsync(config.description);
741
763
  }
742
764
 
743
765
  const child = {
@@ -746,6 +768,12 @@ const parseChildrenFromMeta = async (src, { dynamic } = {}) => {
746
768
  bundleSource: config.source || { url: config.resolved },
747
769
  };
748
770
 
771
+ child.children = await parseChildrenFromMeta(meta, {
772
+ ...context,
773
+ ancestors: [...ancestors, { meta, mountPoint }],
774
+ dynamic: false,
775
+ });
776
+
749
777
  children.push(child);
750
778
  }
751
779
 
@@ -775,7 +803,7 @@ const checkBlockletProcessHealthy = async (blocklet, { minConsecutiveTime, timeo
775
803
  const _checkProcessHealthy = async (blocklet, { minConsecutiveTime, timeout }) => {
776
804
  const { meta, ports, env } = blocklet;
777
805
  const { name } = meta;
778
- const { appId } = env;
806
+ const { processId } = env;
779
807
 
780
808
  const webInterface = (meta.interfaces || []).find((x) => x.type === BLOCKLET_INTERFACE_TYPE_WEB);
781
809
  if (!webInterface) {
@@ -787,10 +815,10 @@ const _checkProcessHealthy = async (blocklet, { minConsecutiveTime, timeout }) =
787
815
  // ensure pm2 status is 'online'
788
816
  const getStatus = async () => {
789
817
  try {
790
- const info = await getProcessInfo(appId);
818
+ const info = await getProcessInfo(processId);
791
819
  return info.pm2_env.status;
792
820
  } catch (err) {
793
- logger.error('blocklet checkStart error', { error: err, appId, name });
821
+ logger.error('blocklet checkStart error', { error: err, processId, name });
794
822
  return '';
795
823
  }
796
824
  };
@@ -819,7 +847,7 @@ const _checkProcessHealthy = async (blocklet, { minConsecutiveTime, timeout }) =
819
847
  throw error;
820
848
  }
821
849
  } catch (error) {
822
- logger.error('start blocklet failed', { appId, name });
850
+ logger.error('start blocklet failed', { processId, name });
823
851
  throw error;
824
852
  }
825
853
  };
@@ -870,15 +898,16 @@ const pruneBlockletBundle = async ({ blocklets, installDir, blockletSettings })
870
898
  // blockletMap: { <[scope/]name/version>: true }
871
899
  const blockletMap = {};
872
900
  for (const blocklet of blocklets) {
873
- blockletMap[`${blocklet.meta.bundleName}/${blocklet.meta.version}`] = true;
874
- for (const child of blocklet.children || []) {
875
- blockletMap[`${child.meta.bundleName}/${child.meta.version}`] = true;
876
- }
901
+ forEachBlockletSync(blocklet, (component) => {
902
+ blockletMap[`${component.meta.bundleName}/${component.meta.version}`] = true;
903
+ });
877
904
  }
878
905
  for (const setting of blockletSettings) {
879
906
  for (const child of setting.children || []) {
880
907
  if (child.status !== BlockletStatus.deleted) {
881
- blockletMap[`${child.meta.bundleName}/${child.meta.version}`] = true;
908
+ forEachBlockletSync(child, (component) => {
909
+ blockletMap[`${component.meta.bundleName}/${component.meta.version}`] = true;
910
+ });
882
911
  }
883
912
  }
884
913
  }
@@ -993,8 +1022,8 @@ const getDiskInfo = async (blocklet, { useFakeDiskInfo } = {}) => {
993
1022
  }
994
1023
  };
995
1024
 
996
- const getRuntimeInfo = async (appId) => {
997
- const proc = await getProcessInfo(appId);
1025
+ const getRuntimeInfo = async (processId) => {
1026
+ const proc = await getProcessInfo(processId);
998
1027
  return {
999
1028
  pid: proc.pid,
1000
1029
  uptime: proc.pm2_env ? +new Date() - Number(proc.pm2_env.pm_uptime) : 0,
@@ -1084,15 +1113,23 @@ const fixAndVerifyMetaFromStore = (meta) => {
1084
1113
  return fixAndValidateService(meta);
1085
1114
  };
1086
1115
 
1087
- const getUpdateMetaList = (oldMetas = [], newMetas = []) => {
1088
- const oldMap = oldMetas.reduce((obj, x) => {
1089
- if (x.did) {
1090
- obj[x.did] = x.version;
1116
+ const getUpdateMetaList = (oldBlocklet = {}, newBlocklet = {}) => {
1117
+ const oldMap = {};
1118
+ forEachChildSync(oldBlocklet, (b, { id }) => {
1119
+ if (b.bundleSource) {
1120
+ oldMap[id] = b.meta.version;
1091
1121
  }
1092
- return obj;
1093
- }, {});
1122
+ });
1123
+
1124
+ const res = [];
1094
1125
 
1095
- return newMetas.filter(({ version, did }) => did && version !== oldMap[did]);
1126
+ forEachChildSync(newBlocklet, (b, { id }) => {
1127
+ if (b.bundleSource && b.meta.version !== oldMap[id]) {
1128
+ res.push({ id, meta: b.meta });
1129
+ }
1130
+ });
1131
+
1132
+ return res;
1096
1133
  };
1097
1134
 
1098
1135
  const getSourceFromInstallParams = (params) => {
@@ -1131,7 +1168,7 @@ const checkDuplicateComponents = (components = []) => {
1131
1168
  (item, index) => components.findIndex((x) => x.mountPoint === item.mountPoint) !== index
1132
1169
  );
1133
1170
  if (duplicateMountPoints.length) {
1134
- throw new Error(`mountpoint must be unique: ${duplicateMountPoints.map((x) => x.mountPoint).join(', ')}`);
1171
+ throw new Error(`mount point must be unique: ${duplicateMountPoints.map((x) => x.mountPoint).join(', ')}`);
1135
1172
  }
1136
1173
  };
1137
1174
 
@@ -1187,11 +1224,7 @@ const needBlockletDownload = (blocklet, oldBlocklet) => {
1187
1224
  return true;
1188
1225
  }
1189
1226
 
1190
- if (get(oldBlocklet, 'meta.dist.integrity') === get(blocklet, 'meta.dist.integrity')) {
1191
- return false;
1192
- }
1193
-
1194
- return true;
1227
+ return !(get(oldBlocklet, 'meta.dist.integrity') === get(blocklet, 'meta.dist.integrity'));
1195
1228
  };
1196
1229
 
1197
1230
  const verifyPurchase = (meta, opts = {}) => {
@@ -1252,10 +1285,10 @@ module.exports = {
1252
1285
  getBlockletMetaFromUrl,
1253
1286
  parseChildrenFromMeta,
1254
1287
  parseChildren,
1255
- getBlockletDirs,
1256
- getRootSystemEnvironments,
1257
- getSystemEnvironments,
1258
- getOverwrittenEnvironments,
1288
+ getComponentDirs,
1289
+ getAppSystemEnvironments,
1290
+ getAppOverwrittenEnvironments,
1291
+ getComponentSystemEnvironments,
1259
1292
  getRuntimeEnvironments,
1260
1293
  validateBlocklet,
1261
1294
  fillBlockletConfigs,
@@ -44,7 +44,6 @@ const ruleSchema = {
44
44
  )
45
45
  .required(),
46
46
  did: Joi.string().label('did').when('type', { is: ROUTING_RULE_TYPES.BLOCKLET, then: Joi.required() }), // root blocklet did
47
- realDid: Joi.string().label('real did'), // child blocklet did
48
47
  port: Joi.number().label('port').port().when('type', { is: ROUTING_RULE_TYPES.BLOCKLET, then: Joi.required() }),
49
48
  url: Joi.string().label('url').when('type', { is: ROUTING_RULE_TYPES.REDIRECT, then: Joi.required() }),
50
49
  redirectCode: Joi.alternatives()
@@ -54,13 +53,13 @@ const ruleSchema = {
54
53
  interfaceName: Joi.string() // root interface
55
54
  .label('interface name')
56
55
  .when('type', { is: ROUTING_RULE_TYPES.BLOCKLET, then: Joi.required() }),
57
- realInterfaceName: Joi.string().label('real interface name'), // child blocklet interface
58
56
  response: Joi.object({ status: Joi.number().required(), contentType: Joi.string(), body: Joi.string().required() })
59
57
  .label('response')
60
58
  .when('type', {
61
59
  is: ROUTING_RULE_TYPES.DIRECT_RESPONSE,
62
60
  then: Joi.required(),
63
61
  }),
62
+ componentId: Joi.string().label('component id'), // component global id
64
63
  },
65
64
 
66
65
  // List of services that manipulate the request before the upstream blocklet
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.7.19",
6
+ "version": "1.7.20",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,23 +19,23 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "@abtnode/certificate-manager": "1.7.19",
23
- "@abtnode/constant": "1.7.19",
24
- "@abtnode/cron": "1.7.19",
25
- "@abtnode/db": "1.7.19",
26
- "@abtnode/logger": "1.7.19",
27
- "@abtnode/queue": "1.7.19",
28
- "@abtnode/rbac": "1.7.19",
29
- "@abtnode/router-provider": "1.7.19",
30
- "@abtnode/static-server": "1.7.19",
31
- "@abtnode/timemachine": "1.7.19",
32
- "@abtnode/util": "1.7.19",
22
+ "@abtnode/certificate-manager": "1.7.20",
23
+ "@abtnode/constant": "1.7.20",
24
+ "@abtnode/cron": "1.7.20",
25
+ "@abtnode/db": "1.7.20",
26
+ "@abtnode/logger": "1.7.20",
27
+ "@abtnode/queue": "1.7.20",
28
+ "@abtnode/rbac": "1.7.20",
29
+ "@abtnode/router-provider": "1.7.20",
30
+ "@abtnode/static-server": "1.7.20",
31
+ "@abtnode/timemachine": "1.7.20",
32
+ "@abtnode/util": "1.7.20",
33
33
  "@arcblock/did": "^1.16.15",
34
- "@arcblock/did-motif": "^1.1.8",
34
+ "@arcblock/did-motif": "^1.1.9",
35
35
  "@arcblock/event-hub": "1.16.15",
36
36
  "@arcblock/pm2-events": "^0.0.5",
37
37
  "@arcblock/vc": "^1.16.15",
38
- "@blocklet/meta": "1.7.19",
38
+ "@blocklet/meta": "1.7.20",
39
39
  "@fidm/x509": "^1.2.1",
40
40
  "@nedb/core": "^1.2.2",
41
41
  "@nedb/multi": "^1.2.2",
@@ -79,5 +79,5 @@
79
79
  "express": "^4.17.1",
80
80
  "jest": "^27.4.5"
81
81
  },
82
- "gitHead": "73c02fe34d02270e59c5edfeedd7e2a878b772c4"
82
+ "gitHead": "7e579415aa56cc422f3e26d902cf029fbc92e47a"
83
83
  }