@abtnode/core 1.6.4 → 1.6.5
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/blocklet/manager/disk.js +125 -130
- package/lib/migrations/1.6.4-security.js +18 -2
- package/lib/migrations/1.6.5-security.js +60 -0
- package/lib/states/base.js +8 -0
- package/lib/states/blocklet.js +58 -17
- package/lib/util/blocklet.js +1 -1
- package/package.json +12 -12
|
@@ -114,8 +114,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
114
114
|
|
|
115
115
|
this.dataDirs = dataDirs;
|
|
116
116
|
this.installDir = dataDirs.blocklets;
|
|
117
|
-
this.state = states.blocklet;
|
|
118
|
-
this.node = states.node;
|
|
119
117
|
this.startQueue = startQueue;
|
|
120
118
|
this.installQueue = installQueue;
|
|
121
119
|
/**
|
|
@@ -127,10 +125,6 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
127
125
|
*/
|
|
128
126
|
this.downloadLocks = {};
|
|
129
127
|
this.registry = registry;
|
|
130
|
-
this.notification = states.notification;
|
|
131
|
-
this.session = states.session;
|
|
132
|
-
this.extras = states.blockletExtras;
|
|
133
|
-
this.cache = states.cache;
|
|
134
128
|
|
|
135
129
|
// cached installed blocklets for performance
|
|
136
130
|
this.cachedBlocklets = null;
|
|
@@ -232,7 +226,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
232
226
|
}
|
|
233
227
|
|
|
234
228
|
// update status
|
|
235
|
-
await
|
|
229
|
+
await states.blocklet.setBlockletStatus(did, BlockletStatus.starting);
|
|
236
230
|
blocklet.status = BlockletStatus.starting;
|
|
237
231
|
this.emit(BlockletEvents.statusChange, blocklet);
|
|
238
232
|
|
|
@@ -243,7 +237,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
243
237
|
}
|
|
244
238
|
|
|
245
239
|
// start process
|
|
246
|
-
const nodeEnvironments = await
|
|
240
|
+
const nodeEnvironments = await states.node.getEnvironments();
|
|
247
241
|
await startBlockletProcess(blocklet, {
|
|
248
242
|
preStart: (b) =>
|
|
249
243
|
hooks.preStart(b, {
|
|
@@ -254,13 +248,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
254
248
|
progress: blocklet.mode === BLOCKLET_MODES.DEVELOPMENT,
|
|
255
249
|
}),
|
|
256
250
|
nodeEnvironments,
|
|
257
|
-
nodeInfo: await
|
|
251
|
+
nodeInfo: await states.node.read(),
|
|
258
252
|
});
|
|
259
253
|
|
|
260
254
|
// check blocklet healthy
|
|
261
255
|
const { startTimeout, minConsecutiveTime } = getHealthyCheckTimeout(blocklet, { checkHealthImmediately });
|
|
262
256
|
const params = {
|
|
263
|
-
|
|
257
|
+
did,
|
|
264
258
|
context,
|
|
265
259
|
minConsecutiveTime,
|
|
266
260
|
timeout: startTimeout,
|
|
@@ -282,7 +276,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
282
276
|
const error = Array.isArray(err) ? err[0] : err;
|
|
283
277
|
logger.error('Failed to start blocklet', { error, did, name: blocklet.meta.name });
|
|
284
278
|
const description = `Start blocklet ${blocklet.meta.name} failed with error: ${error.message}`;
|
|
285
|
-
|
|
279
|
+
states.notification.create({
|
|
286
280
|
title: 'Start Blocklet Failed',
|
|
287
281
|
description,
|
|
288
282
|
entityType: 'blocklet',
|
|
@@ -291,7 +285,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
291
285
|
});
|
|
292
286
|
|
|
293
287
|
await this.deleteProcess({ did });
|
|
294
|
-
const res = await
|
|
288
|
+
const res = await states.blocklet.setBlockletStatus(did, BlockletStatus.error);
|
|
295
289
|
this.emit(BlockletEvents.startFailed, res);
|
|
296
290
|
|
|
297
291
|
if (throwOnError) {
|
|
@@ -309,12 +303,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
309
303
|
const { appId } = blocklet.env;
|
|
310
304
|
|
|
311
305
|
if (updateStatus) {
|
|
312
|
-
await
|
|
306
|
+
await states.blocklet.setBlockletStatus(did, BlockletStatus.stopping);
|
|
313
307
|
blocklet.status = BlockletStatus.stopping;
|
|
314
308
|
this.emit(BlockletEvents.statusChange, blocklet);
|
|
315
309
|
}
|
|
316
310
|
|
|
317
|
-
const nodeEnvironments = await
|
|
311
|
+
const nodeEnvironments = await states.node.getEnvironments();
|
|
318
312
|
|
|
319
313
|
await stopBlockletProcess(blocklet, {
|
|
320
314
|
preStop: (b) =>
|
|
@@ -323,7 +317,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
323
317
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
324
318
|
env: getRuntimeEnvironments(b, nodeEnvironments),
|
|
325
319
|
did, // root blocklet did
|
|
326
|
-
notification:
|
|
320
|
+
notification: states.notification,
|
|
327
321
|
context,
|
|
328
322
|
exitOnError: false,
|
|
329
323
|
progress: blocklet.mode === BLOCKLET_MODES.DEVELOPMENT,
|
|
@@ -344,18 +338,18 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
344
338
|
async restart({ did }, context) {
|
|
345
339
|
logger.info('restart blocklet', { did });
|
|
346
340
|
|
|
347
|
-
await
|
|
348
|
-
const result = await
|
|
341
|
+
await states.blocklet.setBlockletStatus(did, BlockletStatus.stopping);
|
|
342
|
+
const result = await states.blocklet.getBlocklet(did);
|
|
349
343
|
this.emit(BlockletEvents.statusChange, result);
|
|
350
344
|
|
|
351
345
|
const ticket = this.startQueue.push({ entity: 'blocklet', action: 'restart', id: did, did, context });
|
|
352
346
|
ticket.on('failed', async (err) => {
|
|
353
347
|
logger.error('failed to restart blocklet', { did, error: err });
|
|
354
348
|
|
|
355
|
-
const state = await
|
|
349
|
+
const state = await states.blocklet.setBlockletStatus(did, BlockletStatus.stopped);
|
|
356
350
|
this.emit(BlockletEvents.statusChange, state);
|
|
357
351
|
|
|
358
|
-
|
|
352
|
+
states.notification.create({
|
|
359
353
|
title: 'Blocklet Restart Failed',
|
|
360
354
|
description: `Blocklet ${did} restart failed with error: ${err.message || 'queue exception'}`,
|
|
361
355
|
entityType: 'blocklet',
|
|
@@ -371,9 +365,9 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
371
365
|
async reload({ did }, context) {
|
|
372
366
|
const blocklet = await this.ensureBlocklet(did);
|
|
373
367
|
|
|
374
|
-
await
|
|
368
|
+
await states.blocklet.setBlockletStatus(did, BlockletStatus.stopping);
|
|
375
369
|
await reloadBlockletProcess(blocklet);
|
|
376
|
-
await
|
|
370
|
+
await states.blocklet.setBlockletStatus(did, BlockletStatus.running);
|
|
377
371
|
logger.info('blocklet reload successfully', { did });
|
|
378
372
|
|
|
379
373
|
const res = await this.status(did);
|
|
@@ -387,7 +381,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
387
381
|
try {
|
|
388
382
|
const blocklet = await this.ensureBlocklet(did);
|
|
389
383
|
|
|
390
|
-
const nodeEnvironments = await
|
|
384
|
+
const nodeEnvironments = await states.node.getEnvironments();
|
|
391
385
|
|
|
392
386
|
await deleteBlockletProcess(blocklet, {
|
|
393
387
|
preDelete: (b) =>
|
|
@@ -396,7 +390,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
396
390
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
397
391
|
env: getRuntimeEnvironments(b, nodeEnvironments),
|
|
398
392
|
did, // root blocklet did
|
|
399
|
-
notification:
|
|
393
|
+
notification: states.notification,
|
|
400
394
|
context,
|
|
401
395
|
exitOnError: false,
|
|
402
396
|
}),
|
|
@@ -417,7 +411,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
417
411
|
async cancelDownload({ did }, context) {
|
|
418
412
|
await preDownloadLock.acquire();
|
|
419
413
|
try {
|
|
420
|
-
const blocklet = await
|
|
414
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
421
415
|
if (!blocklet) {
|
|
422
416
|
throw new Error('Can not cancel download for non-exist blocklet in database.', { did });
|
|
423
417
|
}
|
|
@@ -446,7 +440,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
446
440
|
|
|
447
441
|
await deleteBlockletProcess(blocklet);
|
|
448
442
|
|
|
449
|
-
const result = await
|
|
443
|
+
const result = await states.blocklet.setBlockletStatus(did, BlockletStatus.stopped);
|
|
450
444
|
logger.info('blocklet process deleted successfully', { did });
|
|
451
445
|
return result;
|
|
452
446
|
}
|
|
@@ -456,22 +450,27 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
456
450
|
throw new Error('did should not be empty');
|
|
457
451
|
}
|
|
458
452
|
|
|
459
|
-
const nodeInfo = await
|
|
453
|
+
const nodeInfo = await states.node.read();
|
|
460
454
|
|
|
461
455
|
if (!attachRuntimeInfo) {
|
|
462
|
-
|
|
456
|
+
try {
|
|
457
|
+
const blocklet = await this.ensureBlocklet(did);
|
|
458
|
+
return blocklet;
|
|
459
|
+
} catch {
|
|
460
|
+
return null;
|
|
461
|
+
}
|
|
463
462
|
}
|
|
464
463
|
|
|
465
464
|
return this.attachRuntimeInfo({ did, nodeInfo, diskInfo: true, context });
|
|
466
465
|
}
|
|
467
466
|
|
|
468
467
|
async list({ includeRuntimeInfo = true, useCache = true } = {}, context) {
|
|
469
|
-
const blocklets = await
|
|
468
|
+
const blocklets = await states.blocklet.getBlocklets();
|
|
470
469
|
if (!includeRuntimeInfo) {
|
|
471
470
|
return blocklets;
|
|
472
471
|
}
|
|
473
472
|
|
|
474
|
-
const nodeInfo = await
|
|
473
|
+
const nodeInfo = await states.node.read();
|
|
475
474
|
const updated = (
|
|
476
475
|
await Promise.all(
|
|
477
476
|
blocklets.map((x) => {
|
|
@@ -513,7 +512,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
513
512
|
}
|
|
514
513
|
|
|
515
514
|
// run hook
|
|
516
|
-
const nodeEnvironments = await
|
|
515
|
+
const nodeEnvironments = await states.node.getEnvironments();
|
|
517
516
|
newConfigs.forEach((x) => {
|
|
518
517
|
if (x.key === 'BLOCKLET_APP_SK') {
|
|
519
518
|
try {
|
|
@@ -540,7 +539,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
540
539
|
hooks: Object.assign(blocklet.meta.hooks || {}, blocklet.meta.scripts || {}),
|
|
541
540
|
exitOnError: true,
|
|
542
541
|
env: { ...getRuntimeEnvironments(blocklet, nodeEnvironments), ...blocklet.configObj },
|
|
543
|
-
notification:
|
|
542
|
+
notification: states.notification,
|
|
544
543
|
did,
|
|
545
544
|
context,
|
|
546
545
|
progress: blocklet.mode === BLOCKLET_MODES.DEVELOPMENT,
|
|
@@ -548,8 +547,8 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
548
547
|
|
|
549
548
|
// update db
|
|
550
549
|
const configs = childDid
|
|
551
|
-
? await
|
|
552
|
-
: await
|
|
550
|
+
? await states.blockletExtras.setChildConfigs(did, childDid, newConfigs)
|
|
551
|
+
: await states.blockletExtras.setConfigs(did, newConfigs);
|
|
553
552
|
|
|
554
553
|
const newState = await this.updateBlockletEnvironment(did);
|
|
555
554
|
|
|
@@ -569,7 +568,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
569
568
|
* upgrade blocklet from registry
|
|
570
569
|
*/
|
|
571
570
|
async upgrade({ did, registryUrl }, context) {
|
|
572
|
-
const blocklet = await
|
|
571
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
573
572
|
|
|
574
573
|
// TODO: 查看了下目前页面中的升级按钮,都是会传 registryUrl 过来的,这个函数里的逻辑感觉需要在以后做一个简化
|
|
575
574
|
if (!registryUrl && blocklet.source !== BlockletSource.registry) {
|
|
@@ -649,7 +648,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
649
648
|
|
|
650
649
|
logger.info('Get blocklet diff', { did, clientFilesNumber: clientFiles.length });
|
|
651
650
|
|
|
652
|
-
const state = await
|
|
651
|
+
const state = await states.blocklet.getBlocklet(did);
|
|
653
652
|
if (!state) {
|
|
654
653
|
return {
|
|
655
654
|
hasBlocklet: false,
|
|
@@ -707,7 +706,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
707
706
|
}
|
|
708
707
|
|
|
709
708
|
async checkChildrenForUpdates({ did }) {
|
|
710
|
-
const blocklet = await
|
|
709
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
711
710
|
const childrenMeta = await getChildrenMeta(blocklet.meta);
|
|
712
711
|
const updateList = getUpdateMetaList(
|
|
713
712
|
blocklet.children.map((x) => x.meta),
|
|
@@ -719,7 +718,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
719
718
|
}
|
|
720
719
|
|
|
721
720
|
// start session
|
|
722
|
-
const { id: updateId } = await
|
|
721
|
+
const { id: updateId } = await states.session.start({
|
|
723
722
|
did,
|
|
724
723
|
childrenMeta,
|
|
725
724
|
});
|
|
@@ -731,10 +730,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
731
730
|
}
|
|
732
731
|
|
|
733
732
|
async updateChildren({ updateId }, context) {
|
|
734
|
-
const { did, childrenMeta } = await
|
|
733
|
+
const { did, childrenMeta } = await states.session.end(updateId);
|
|
735
734
|
|
|
736
735
|
// get old blocklet
|
|
737
|
-
const oldBlocklet = await
|
|
736
|
+
const oldBlocklet = await states.blocklet.getBlocklet(did);
|
|
738
737
|
const { meta } = oldBlocklet;
|
|
739
738
|
const { name, version } = meta;
|
|
740
739
|
|
|
@@ -748,10 +747,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
748
747
|
});
|
|
749
748
|
|
|
750
749
|
// new blocklet
|
|
751
|
-
const newBlocklet = await
|
|
750
|
+
const newBlocklet = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
|
|
752
751
|
mergeMeta(meta, childrenMeta);
|
|
753
752
|
newBlocklet.meta = meta;
|
|
754
|
-
newBlocklet.children = await
|
|
753
|
+
newBlocklet.children = await states.blocklet.getChildrenFromMetas(childrenMeta);
|
|
755
754
|
await validateBlocklet(newBlocklet);
|
|
756
755
|
|
|
757
756
|
this.emit(BlockletEvents.statusChange, newBlocklet);
|
|
@@ -775,7 +774,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
775
774
|
logger.error('queue failed', { entity: 'blocklet', action, did, version, name, error: err });
|
|
776
775
|
await this._rollback(action, did, oldBlocklet);
|
|
777
776
|
this.emit(`blocklet.${action}.failed`, { did, version, err });
|
|
778
|
-
|
|
777
|
+
states.notification.create({
|
|
779
778
|
title: `Blocklet ${capitalize(action)} Failed`,
|
|
780
779
|
description: `Blocklet ${name}@${version} ${action} failed with error: ${err.message || 'queue exception'}`,
|
|
781
780
|
entityType: 'blocklet',
|
|
@@ -800,7 +799,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
800
799
|
const { did, version } = meta;
|
|
801
800
|
meta.title = `[DEV] ${meta.title || meta.name}`;
|
|
802
801
|
|
|
803
|
-
const exist = await
|
|
802
|
+
const exist = await states.blocklet.getBlocklet(did);
|
|
804
803
|
if (exist) {
|
|
805
804
|
if (exist.mode === BLOCKLET_MODES.PRODUCTION) {
|
|
806
805
|
throw new Error('The blocklet of production mode already exists, please remove it before developing');
|
|
@@ -826,7 +825,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
826
825
|
|
|
827
826
|
const childrenMeta = await getChildrenMeta(meta);
|
|
828
827
|
mergeMeta(meta, childrenMeta);
|
|
829
|
-
const blocklet = await
|
|
828
|
+
const blocklet = await states.blocklet.addBlocklet({
|
|
830
829
|
did,
|
|
831
830
|
meta,
|
|
832
831
|
source: BlockletSource.local,
|
|
@@ -837,7 +836,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
837
836
|
logger.info('add blocklet for dev', { did, version, meta });
|
|
838
837
|
|
|
839
838
|
await this._downloadBlocklet(blocklet);
|
|
840
|
-
await
|
|
839
|
+
await states.blocklet.setBlockletStatus(did, BlockletStatus.installed);
|
|
841
840
|
|
|
842
841
|
// Add environments
|
|
843
842
|
await this._setConfigs(did);
|
|
@@ -852,7 +851,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
852
851
|
throw new Error(`Blocklet did is invalid: ${did}`);
|
|
853
852
|
}
|
|
854
853
|
|
|
855
|
-
const blocklet = await
|
|
854
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
856
855
|
if (!blocklet) {
|
|
857
856
|
throw new Error(`Can not find blocklet in database by did ${did}`);
|
|
858
857
|
}
|
|
@@ -868,11 +867,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
868
867
|
}),
|
|
869
868
|
};
|
|
870
869
|
|
|
871
|
-
const configs = await
|
|
870
|
+
const configs = await states.blockletExtras.getConfigs(did);
|
|
872
871
|
fillBlockletConfigs(blocklet, configs);
|
|
873
872
|
|
|
874
873
|
// merge settings to blocklet
|
|
875
|
-
const settings = await
|
|
874
|
+
const settings = await states.blockletExtras.getSettings(did);
|
|
876
875
|
blocklet.trustedPassports = get(settings, 'trustedPassports') || [];
|
|
877
876
|
blocklet.enablePassportIssuance = get(settings, 'enablePassportIssuance', true);
|
|
878
877
|
|
|
@@ -897,7 +896,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
897
896
|
}),
|
|
898
897
|
};
|
|
899
898
|
|
|
900
|
-
const childConfigs = await
|
|
899
|
+
const childConfigs = await states.blockletExtras.getChildConfigs(did, childDid);
|
|
901
900
|
fillBlockletConfigs(child, childConfigs);
|
|
902
901
|
}
|
|
903
902
|
|
|
@@ -913,7 +912,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
913
912
|
return blocklet;
|
|
914
913
|
}
|
|
915
914
|
|
|
916
|
-
return
|
|
915
|
+
return states.blocklet.setBlockletStatus(did, BlockletStatus.stopped);
|
|
917
916
|
};
|
|
918
917
|
|
|
919
918
|
const blocklet = await this.ensureBlocklet(did);
|
|
@@ -931,9 +930,9 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
931
930
|
const status = await getBlockletStatusFromProcess(blocklet);
|
|
932
931
|
if (shouldUpdateStatus) {
|
|
933
932
|
if (status === BlockletStatus.stopped) {
|
|
934
|
-
await
|
|
933
|
+
await states.blocklet.stopBlocklet(did);
|
|
935
934
|
}
|
|
936
|
-
return
|
|
935
|
+
return states.blocklet.setBlockletStatus(did, status);
|
|
937
936
|
}
|
|
938
937
|
} catch (err) {
|
|
939
938
|
if (shouldUpdateStatus) {
|
|
@@ -990,7 +989,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
990
989
|
}
|
|
991
990
|
|
|
992
991
|
if (blocklet.status === BlockletStatus.running) {
|
|
993
|
-
await
|
|
992
|
+
await states.blocklet.setBlockletStatus(did, BlockletStatus.stopped);
|
|
994
993
|
blocklet.status = BlockletStatus.stopped;
|
|
995
994
|
}
|
|
996
995
|
}
|
|
@@ -1017,7 +1016,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1017
1016
|
|
|
1018
1017
|
return blocklet;
|
|
1019
1018
|
} catch (err) {
|
|
1020
|
-
const simpleState = await
|
|
1019
|
+
const simpleState = await states.blocklet.getBlocklet(did);
|
|
1021
1020
|
logger.error('failed to get blocklet info', {
|
|
1022
1021
|
did,
|
|
1023
1022
|
name: get(simpleState, 'meta.name'),
|
|
@@ -1056,7 +1055,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1056
1055
|
try {
|
|
1057
1056
|
await preDownloadLock.acquire();
|
|
1058
1057
|
|
|
1059
|
-
const b0 = await
|
|
1058
|
+
const b0 = await states.blocklet.getBlocklet(did);
|
|
1060
1059
|
if (!b0 || ![BlockletStatus.waiting, BlockletStatus.downloading].includes(b0.status)) {
|
|
1061
1060
|
if (!b0) {
|
|
1062
1061
|
logger.error('blocklet does not exist before downloading', { name, did });
|
|
@@ -1072,7 +1071,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1072
1071
|
return;
|
|
1073
1072
|
}
|
|
1074
1073
|
|
|
1075
|
-
const blocklet1 = await
|
|
1074
|
+
const blocklet1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.downloading);
|
|
1076
1075
|
this.emit(BlockletEvents.statusChange, blocklet1);
|
|
1077
1076
|
|
|
1078
1077
|
preDownloadLock.release();
|
|
@@ -1090,7 +1089,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1090
1089
|
preDownloadLock.release();
|
|
1091
1090
|
|
|
1092
1091
|
this.emit(BlockletEvents.downloadFailed, { meta: did });
|
|
1093
|
-
|
|
1092
|
+
states.notification.create({
|
|
1094
1093
|
title: 'Blocklet Download Failed',
|
|
1095
1094
|
description: `Blocklet ${name}@${version} download failed with error: ${err.message}`,
|
|
1096
1095
|
entityType: 'blocklet',
|
|
@@ -1134,7 +1133,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1134
1133
|
const { did, version } = meta;
|
|
1135
1134
|
logger.info('do install blocklet', { did, version });
|
|
1136
1135
|
|
|
1137
|
-
const state = await
|
|
1136
|
+
const state = await states.blocklet.setBlockletStatus(did, BlockletStatus.installing);
|
|
1138
1137
|
this.emit(BlockletEvents.statusChange, state);
|
|
1139
1138
|
|
|
1140
1139
|
try {
|
|
@@ -1160,7 +1159,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1160
1159
|
const { version, did } = newBlocklet.meta;
|
|
1161
1160
|
logger.info(`do ${action} blocklet`, { did, version });
|
|
1162
1161
|
|
|
1163
|
-
const state = await
|
|
1162
|
+
const state = await states.blocklet.setBlockletStatus(did, BlockletStatus.upgrading);
|
|
1164
1163
|
this.emit(BlockletEvents.statusChange, state);
|
|
1165
1164
|
|
|
1166
1165
|
try {
|
|
@@ -1180,9 +1179,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1180
1179
|
}
|
|
1181
1180
|
|
|
1182
1181
|
async onCheckIfStarted(jobInfo, { throwOnError } = {}) {
|
|
1183
|
-
const {
|
|
1182
|
+
const { did, context, minConsecutiveTime = 5000, timeout } = jobInfo;
|
|
1183
|
+
const blocklet = await this.ensureBlocklet(did);
|
|
1184
|
+
|
|
1184
1185
|
const { meta } = blocklet;
|
|
1185
|
-
const {
|
|
1186
|
+
const { name } = meta;
|
|
1186
1187
|
|
|
1187
1188
|
try {
|
|
1188
1189
|
// healthy check
|
|
@@ -1195,9 +1196,9 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1195
1196
|
logger.error('check blocklet if started failed', { did, name, context, timeout, error });
|
|
1196
1197
|
|
|
1197
1198
|
await this.deleteProcess({ did }, context);
|
|
1198
|
-
await
|
|
1199
|
+
await states.blocklet.setBlockletStatus(did, BlockletStatus.error);
|
|
1199
1200
|
|
|
1200
|
-
|
|
1201
|
+
states.notification.create({
|
|
1201
1202
|
title: 'Blocklet Start Failed',
|
|
1202
1203
|
description: `Blocklet ${name} start failed: ${error.message}`,
|
|
1203
1204
|
entityType: 'blocklet',
|
|
@@ -1215,16 +1216,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1215
1216
|
|
|
1216
1217
|
async updateBlockletEnvironment(did) {
|
|
1217
1218
|
const blockletWithEnv = await this.ensureBlocklet(did);
|
|
1218
|
-
const blocklet = await
|
|
1219
|
-
const nodeInfo = await
|
|
1219
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
1220
|
+
const nodeInfo = await states.node.read();
|
|
1220
1221
|
|
|
1221
1222
|
const rootSystemEnvironments = getRootSystemEnvironments(blockletWithEnv, nodeInfo);
|
|
1222
|
-
const rootConfig = blockletWithEnv.configObj;
|
|
1223
1223
|
const overwrittenEnvironments = getOverwrittenEnvironments(blockletWithEnv, nodeInfo);
|
|
1224
1224
|
|
|
1225
1225
|
// fill environments to blocklet and blocklet.children
|
|
1226
1226
|
blocklet.environments = formatEnvironments({
|
|
1227
|
-
...rootConfig,
|
|
1228
1227
|
...getSystemEnvironments(blockletWithEnv),
|
|
1229
1228
|
...rootSystemEnvironments,
|
|
1230
1229
|
...overwrittenEnvironments,
|
|
@@ -1233,10 +1232,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1233
1232
|
for (const child of blocklet.children) {
|
|
1234
1233
|
const childWithEnv = blockletWithEnv.children.find((x) => x.meta.did === child.meta.did);
|
|
1235
1234
|
if (childWithEnv) {
|
|
1236
|
-
const childConfig = childWithEnv.configObj;
|
|
1237
1235
|
child.environments = formatEnvironments({
|
|
1238
|
-
...childConfig, // custom env of child blocklet
|
|
1239
|
-
...rootConfig, // // custom env of root blocklet FIXME: use options or hooks to make merge logic flexible
|
|
1240
1236
|
...getSystemEnvironments(childWithEnv), // system env of child blocklet
|
|
1241
1237
|
...rootSystemEnvironments, // system env of root blocklet
|
|
1242
1238
|
...overwrittenEnvironments,
|
|
@@ -1245,11 +1241,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1245
1241
|
}
|
|
1246
1242
|
|
|
1247
1243
|
// update state to db
|
|
1248
|
-
return
|
|
1244
|
+
return states.blocklet.updateBlocklet(did, blocklet);
|
|
1249
1245
|
}
|
|
1250
1246
|
|
|
1251
1247
|
async updateAllBlockletEnvironment() {
|
|
1252
|
-
const blocklets = await
|
|
1248
|
+
const blocklets = await states.blocklet.getBlocklets();
|
|
1253
1249
|
for (let i = 0; i < blocklets.length; i++) {
|
|
1254
1250
|
const blocklet = blocklets[i];
|
|
1255
1251
|
await this.updateBlockletEnvironment(blocklet.meta.did);
|
|
@@ -1269,7 +1265,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1269
1265
|
throw new Error('Can not install blocklet that not found in registry');
|
|
1270
1266
|
}
|
|
1271
1267
|
|
|
1272
|
-
const state = await
|
|
1268
|
+
const state = await states.blocklet.getBlocklet(blocklet.did);
|
|
1273
1269
|
if (state) {
|
|
1274
1270
|
throw new Error('Can not install an already installed blocklet');
|
|
1275
1271
|
}
|
|
@@ -1297,7 +1293,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1297
1293
|
}
|
|
1298
1294
|
|
|
1299
1295
|
// upgrade
|
|
1300
|
-
const exist = await
|
|
1296
|
+
const exist = await states.blocklet.getBlocklet(meta.did);
|
|
1301
1297
|
if (exist) {
|
|
1302
1298
|
return this._upgrade({
|
|
1303
1299
|
meta,
|
|
@@ -1346,7 +1342,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1346
1342
|
|
|
1347
1343
|
// diff deploy
|
|
1348
1344
|
if (did && diffVersion) {
|
|
1349
|
-
const oldBlocklet = await
|
|
1345
|
+
const oldBlocklet = await states.blocklet.getBlocklet(did);
|
|
1350
1346
|
if (!oldBlocklet) {
|
|
1351
1347
|
throw new Error(`Blocklet ${did} not found when diff deploying`);
|
|
1352
1348
|
}
|
|
@@ -1367,11 +1363,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1367
1363
|
const { meta } = await this._resolveDiffDownload(cwd, tarFile, deleteSet, oldBlocklet);
|
|
1368
1364
|
const childrenMeta = await getChildrenMeta(meta);
|
|
1369
1365
|
mergeMeta(meta, childrenMeta);
|
|
1370
|
-
const newBlocklet = await
|
|
1366
|
+
const newBlocklet = await states.blocklet.getBlocklet(did);
|
|
1371
1367
|
newBlocklet.meta = meta;
|
|
1372
1368
|
newBlocklet.source = BlockletSource.upload;
|
|
1373
1369
|
newBlocklet.deployedFrom = `Upload by ${context.user.did}`;
|
|
1374
|
-
newBlocklet.children = await
|
|
1370
|
+
newBlocklet.children = await states.blocklet.getChildrenFromMetas(childrenMeta);
|
|
1375
1371
|
await validateBlocklet(newBlocklet);
|
|
1376
1372
|
await this._downloadBlocklet(newBlocklet, oldBlocklet);
|
|
1377
1373
|
|
|
@@ -1384,7 +1380,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1384
1380
|
|
|
1385
1381
|
// full deploy
|
|
1386
1382
|
const { meta } = await this._resolveDownload(cwd, tarFile);
|
|
1387
|
-
const oldBlocklet = await
|
|
1383
|
+
const oldBlocklet = await states.blocklet.getBlocklet(meta.did);
|
|
1388
1384
|
|
|
1389
1385
|
if (oldBlocklet) {
|
|
1390
1386
|
if (isInProgress(oldBlocklet.status)) {
|
|
@@ -1394,11 +1390,11 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1394
1390
|
|
|
1395
1391
|
const childrenMeta = await getChildrenMeta(meta);
|
|
1396
1392
|
mergeMeta(meta, childrenMeta);
|
|
1397
|
-
const newBlocklet = await
|
|
1393
|
+
const newBlocklet = await states.blocklet.getBlocklet(meta.did);
|
|
1398
1394
|
newBlocklet.meta = meta;
|
|
1399
1395
|
newBlocklet.source = BlockletSource.upload;
|
|
1400
1396
|
newBlocklet.deployedFrom = `Upload by ${context.user.did}`;
|
|
1401
|
-
newBlocklet.children = await
|
|
1397
|
+
newBlocklet.children = await states.blocklet.getChildrenFromMetas(childrenMeta);
|
|
1402
1398
|
|
|
1403
1399
|
await validateBlocklet(newBlocklet);
|
|
1404
1400
|
await this._downloadBlocklet(newBlocklet, oldBlocklet);
|
|
@@ -1412,7 +1408,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1412
1408
|
|
|
1413
1409
|
const childrenMeta = await getChildrenMeta(meta);
|
|
1414
1410
|
mergeMeta(meta, childrenMeta);
|
|
1415
|
-
const blocklet = await
|
|
1411
|
+
const blocklet = await states.blocklet.addBlocklet({
|
|
1416
1412
|
did: meta.did,
|
|
1417
1413
|
meta,
|
|
1418
1414
|
source: BlockletSource.upload,
|
|
@@ -1438,7 +1434,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1438
1434
|
* @param {object} blocklet object
|
|
1439
1435
|
*/
|
|
1440
1436
|
async download(did, blocklet) {
|
|
1441
|
-
await
|
|
1437
|
+
await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
|
|
1442
1438
|
this.installQueue.push(
|
|
1443
1439
|
{
|
|
1444
1440
|
entity: 'blocklet',
|
|
@@ -1456,7 +1452,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1456
1452
|
throw new Error('did is required');
|
|
1457
1453
|
}
|
|
1458
1454
|
|
|
1459
|
-
const blocklet = await
|
|
1455
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
1460
1456
|
if (!blocklet) {
|
|
1461
1457
|
return null;
|
|
1462
1458
|
}
|
|
@@ -1465,12 +1461,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1465
1461
|
}
|
|
1466
1462
|
|
|
1467
1463
|
async prune() {
|
|
1468
|
-
const blocklets = await
|
|
1464
|
+
const blocklets = await states.blocklet.getBlocklets();
|
|
1469
1465
|
await pruneBlockletBundle(blocklets, this.dataDirs.blocklets);
|
|
1470
1466
|
}
|
|
1471
1467
|
|
|
1472
1468
|
async getLatestBlockletVersion({ did, version }) {
|
|
1473
|
-
const blocklet = await
|
|
1469
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
1474
1470
|
if (!blocklet) {
|
|
1475
1471
|
throw new Error('the blocklet is not installed');
|
|
1476
1472
|
}
|
|
@@ -1478,7 +1474,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1478
1474
|
let versions = this.cachedBlockletVersions.get(did);
|
|
1479
1475
|
|
|
1480
1476
|
if (!versions) {
|
|
1481
|
-
const { blockletRegistryList } = await
|
|
1477
|
+
const { blockletRegistryList } = await states.node.read();
|
|
1482
1478
|
const tasks = blockletRegistryList.map((registry) =>
|
|
1483
1479
|
this.registry
|
|
1484
1480
|
.getBlockletMeta({ did, registryUrl: registry.url })
|
|
@@ -1526,7 +1522,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1526
1522
|
name: 'refresh-accessible-ip',
|
|
1527
1523
|
time: '0 */10 * * * *', // 10min
|
|
1528
1524
|
fn: async () => {
|
|
1529
|
-
const nodeInfo = await
|
|
1525
|
+
const nodeInfo = await states.node.read();
|
|
1530
1526
|
await refreshAccessibleExternalNodeIp(nodeInfo);
|
|
1531
1527
|
},
|
|
1532
1528
|
},
|
|
@@ -1541,7 +1537,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1541
1537
|
logger.error('sync blocklet status failed', { error: err });
|
|
1542
1538
|
}
|
|
1543
1539
|
};
|
|
1544
|
-
const blocklets = await
|
|
1540
|
+
const blocklets = await states.blocklet.getBlocklets();
|
|
1545
1541
|
blocklets.forEach(run);
|
|
1546
1542
|
}
|
|
1547
1543
|
|
|
@@ -1553,7 +1549,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1553
1549
|
const childrenMeta = await getChildrenMeta(meta);
|
|
1554
1550
|
mergeMeta(meta, childrenMeta);
|
|
1555
1551
|
try {
|
|
1556
|
-
const blocklet = await
|
|
1552
|
+
const blocklet = await states.blocklet.addBlocklet({
|
|
1557
1553
|
did: meta.did,
|
|
1558
1554
|
meta,
|
|
1559
1555
|
source,
|
|
@@ -1567,7 +1563,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1567
1563
|
|
|
1568
1564
|
logger.info('blocklet added to database', { meta });
|
|
1569
1565
|
|
|
1570
|
-
const blocklet1 = await
|
|
1566
|
+
const blocklet1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
|
|
1571
1567
|
this.emit(BlockletEvents.added, blocklet1);
|
|
1572
1568
|
|
|
1573
1569
|
// download
|
|
@@ -1579,7 +1575,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1579
1575
|
|
|
1580
1576
|
if (sync) {
|
|
1581
1577
|
await this.onDownload({ ...downloadParams, throwOnError: true });
|
|
1582
|
-
return
|
|
1578
|
+
return states.blocklet.getBlocklet(did);
|
|
1583
1579
|
}
|
|
1584
1580
|
|
|
1585
1581
|
const ticket = this.installQueue.push(
|
|
@@ -1595,12 +1591,12 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1595
1591
|
logger.error('failed to install blocklet', { name, did, version, error: err });
|
|
1596
1592
|
try {
|
|
1597
1593
|
await this._delExtras(did);
|
|
1598
|
-
await
|
|
1594
|
+
await states.blocklet.deleteBlocklet(did);
|
|
1599
1595
|
} catch (e) {
|
|
1600
1596
|
logger.error('failed to remove blocklet on install error', { did: meta.did, error: e });
|
|
1601
1597
|
}
|
|
1602
1598
|
|
|
1603
|
-
|
|
1599
|
+
states.notification.create({
|
|
1604
1600
|
title: 'Blocklet Install Failed',
|
|
1605
1601
|
description: `Blocklet ${name}@${version} install failed with error: ${err.message || 'queue exception'}`,
|
|
1606
1602
|
entityType: 'blocklet',
|
|
@@ -1612,7 +1608,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1612
1608
|
return blocklet1;
|
|
1613
1609
|
} catch (err) {
|
|
1614
1610
|
logger.error('failed to install blocklet', { name, did, version, error: err });
|
|
1615
|
-
|
|
1611
|
+
states.notification.create({
|
|
1616
1612
|
title: 'Blocklet Install Failed',
|
|
1617
1613
|
description: `Blocklet ${name}@${version} install failed with error: ${err.message || 'queue exception'}`,
|
|
1618
1614
|
entityType: 'blocklet',
|
|
@@ -1635,19 +1631,19 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1635
1631
|
|
|
1636
1632
|
const { name, version, did } = meta;
|
|
1637
1633
|
|
|
1638
|
-
const oldBlocklet = await
|
|
1634
|
+
const oldBlocklet = await states.blocklet.getBlocklet(did);
|
|
1639
1635
|
|
|
1640
1636
|
// NOTE: 目前的版本移除了降级通道,所以不需要考虑降级通道的情况
|
|
1641
1637
|
const action = semver.gt(oldBlocklet.meta.version, version) ? 'downgrade' : 'upgrade';
|
|
1642
1638
|
logger.info(`${action} blocklet`, { did, version });
|
|
1643
1639
|
|
|
1644
|
-
const newBlocklet = await
|
|
1640
|
+
const newBlocklet = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting);
|
|
1645
1641
|
const childrenMeta = await getChildrenMeta(meta);
|
|
1646
1642
|
mergeMeta(meta, childrenMeta);
|
|
1647
1643
|
newBlocklet.meta = meta;
|
|
1648
1644
|
newBlocklet.source = source;
|
|
1649
1645
|
newBlocklet.deployedFrom = deployedFrom;
|
|
1650
|
-
newBlocklet.children = await
|
|
1646
|
+
newBlocklet.children = await states.blocklet.getChildrenFromMetas(childrenMeta);
|
|
1651
1647
|
|
|
1652
1648
|
await validateBlocklet(newBlocklet);
|
|
1653
1649
|
|
|
@@ -1664,7 +1660,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1664
1660
|
|
|
1665
1661
|
if (sync) {
|
|
1666
1662
|
await this.onDownload({ ...downloadParams, throwOnError: true });
|
|
1667
|
-
return
|
|
1663
|
+
return states.blocklet.getBlocklet(did);
|
|
1668
1664
|
}
|
|
1669
1665
|
|
|
1670
1666
|
const ticket = this.installQueue.push(
|
|
@@ -1681,7 +1677,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1681
1677
|
logger.error('queue failed', { entity: 'blocklet', action, did, version, name, error: err });
|
|
1682
1678
|
await this._rollback(action, did, oldBlocklet);
|
|
1683
1679
|
this.emit(`blocklet.${action}.failed`, { did, version, err });
|
|
1684
|
-
|
|
1680
|
+
states.notification.create({
|
|
1685
1681
|
title: `Blocklet ${capitalize(action)} Failed`,
|
|
1686
1682
|
description: `Blocklet ${name}@${version} ${action} failed with error: ${err.message || 'queue exception'}`,
|
|
1687
1683
|
entityType: 'blocklet',
|
|
@@ -1839,14 +1835,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1839
1835
|
}
|
|
1840
1836
|
|
|
1841
1837
|
// pre install
|
|
1842
|
-
const nodeEnvironments = await
|
|
1838
|
+
const nodeEnvironments = await states.node.getEnvironments();
|
|
1843
1839
|
const preInstall = (b) =>
|
|
1844
1840
|
hooks.preInstall({
|
|
1845
1841
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1846
1842
|
env: { ...nodeEnvironments },
|
|
1847
1843
|
appDir: blocklet.env.appDir,
|
|
1848
1844
|
did, // root blocklet did
|
|
1849
|
-
notification:
|
|
1845
|
+
notification: states.notification,
|
|
1850
1846
|
context,
|
|
1851
1847
|
});
|
|
1852
1848
|
await forEachBlocklet(blocklet, preInstall, { parallel: true });
|
|
@@ -1862,17 +1858,17 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1862
1858
|
env: getRuntimeEnvironments(b, nodeEnvironments),
|
|
1863
1859
|
appDir: blocklet.env.appDir,
|
|
1864
1860
|
did, // root blocklet did
|
|
1865
|
-
notification:
|
|
1861
|
+
notification: states.notification,
|
|
1866
1862
|
context,
|
|
1867
1863
|
});
|
|
1868
1864
|
await forEachBlocklet(blocklet, postInstall, { parallel: true });
|
|
1869
1865
|
|
|
1870
|
-
await
|
|
1866
|
+
await states.blocklet.setBlockletStatus(did, BlockletStatus.installed);
|
|
1871
1867
|
blocklet = await this.ensureBlocklet(did);
|
|
1872
1868
|
logger.info('blocklet installed', { source, meta });
|
|
1873
1869
|
this.emit(BlockletEvents.installed, { blocklet, context });
|
|
1874
1870
|
|
|
1875
|
-
|
|
1871
|
+
states.notification.create({
|
|
1876
1872
|
title: 'Blocklet Installed',
|
|
1877
1873
|
description: `Blocklet ${meta.name}@${meta.version} is installed successfully. (Source: ${
|
|
1878
1874
|
deployedFrom || fromBlockletSource(source)
|
|
@@ -1884,13 +1880,13 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1884
1880
|
});
|
|
1885
1881
|
return blocklet;
|
|
1886
1882
|
} catch (err) {
|
|
1887
|
-
const { meta } = await
|
|
1883
|
+
const { meta } = await states.blocklet.getBlocklet(did);
|
|
1888
1884
|
const { name, version } = meta;
|
|
1889
1885
|
logger.error('failed to install blocklet', { name, did, version, error: err });
|
|
1890
1886
|
try {
|
|
1891
1887
|
await this._rollback('install', did);
|
|
1892
1888
|
this.emit(BlockletEvents.installFailed, { meta: { did } });
|
|
1893
|
-
|
|
1889
|
+
states.notification.create({
|
|
1894
1890
|
title: 'Blocklet Install Failed',
|
|
1895
1891
|
description: `Blocklet ${meta.name}@${meta.version} install failed with error: ${err.message}`,
|
|
1896
1892
|
entityType: 'blocklet',
|
|
@@ -1921,20 +1917,20 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1921
1917
|
}
|
|
1922
1918
|
|
|
1923
1919
|
// update state
|
|
1924
|
-
await
|
|
1920
|
+
await states.blocklet.upgradeBlocklet({ meta, source, deployedFrom, children });
|
|
1925
1921
|
await this._setConfigs(did);
|
|
1926
1922
|
|
|
1927
1923
|
let blocklet = await this.ensureBlocklet(did);
|
|
1928
1924
|
|
|
1929
1925
|
// pre install
|
|
1930
|
-
const nodeEnvironments = await
|
|
1926
|
+
const nodeEnvironments = await states.node.getEnvironments();
|
|
1931
1927
|
const preInstall = (b) =>
|
|
1932
1928
|
hooks.preInstall({
|
|
1933
1929
|
hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
|
|
1934
1930
|
env: { ...nodeEnvironments },
|
|
1935
1931
|
appDir: blocklet.env.appDir,
|
|
1936
1932
|
did, // root blocklet did
|
|
1937
|
-
notification:
|
|
1933
|
+
notification: states.notification,
|
|
1938
1934
|
context,
|
|
1939
1935
|
});
|
|
1940
1936
|
await forEachBlocklet(blocklet, preInstall, { parallel: true });
|
|
@@ -1950,7 +1946,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1950
1946
|
env: getRuntimeEnvironments(b, nodeEnvironments),
|
|
1951
1947
|
appDir: b.env.appDir,
|
|
1952
1948
|
did, // root blocklet did
|
|
1953
|
-
notification:
|
|
1949
|
+
notification: states.notification,
|
|
1954
1950
|
context,
|
|
1955
1951
|
});
|
|
1956
1952
|
await forEachBlocklet(blocklet, postInstall, { parallel: true });
|
|
@@ -1966,7 +1962,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1966
1962
|
env: getRuntimeEnvironments(b, nodeEnvironments),
|
|
1967
1963
|
appDir: b.env.appDir,
|
|
1968
1964
|
did: b.meta.did,
|
|
1969
|
-
notification:
|
|
1965
|
+
notification: states.notification,
|
|
1970
1966
|
context,
|
|
1971
1967
|
});
|
|
1972
1968
|
}
|
|
@@ -1991,7 +1987,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1991
1987
|
} else {
|
|
1992
1988
|
const status =
|
|
1993
1989
|
oldBlocklet.status === BlockletStatus.installed ? BlockletStatus.installed : BlockletStatus.stopped;
|
|
1994
|
-
await
|
|
1990
|
+
await states.blocklet.setBlockletStatus(did, status);
|
|
1995
1991
|
}
|
|
1996
1992
|
|
|
1997
1993
|
blocklet = await this.ensureBlocklet(did, context);
|
|
@@ -2003,7 +1999,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2003
1999
|
downgrade: BlockletEvents.downgraded,
|
|
2004
2000
|
};
|
|
2005
2001
|
this.emit(eventNames[action], { blocklet, context });
|
|
2006
|
-
|
|
2002
|
+
states.notification.create({
|
|
2007
2003
|
title: `Blocklet ${capitalize(action)} Success`,
|
|
2008
2004
|
description: `Blocklet ${name}@${version} ${action} successfully. (Source: ${
|
|
2009
2005
|
deployedFrom || fromBlockletSource(source)
|
|
@@ -2022,7 +2018,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2022
2018
|
const b = await this._rollback(action, did, oldBlocklet);
|
|
2023
2019
|
logger.error(`failed to ${action} blocklet`, { did, version, name, error: err });
|
|
2024
2020
|
this.emit(BlockletEvents.updated, { blocklet: b });
|
|
2025
|
-
|
|
2021
|
+
states.notification.create({
|
|
2026
2022
|
title: `Blocklet ${capitalize(action)} Failed`,
|
|
2027
2023
|
description: `Blocklet ${name}@${version} ${action} failed with error: ${err.message}`,
|
|
2028
2024
|
entityType: 'blocklet',
|
|
@@ -2101,14 +2097,14 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2101
2097
|
await fs.move(tarballPath, cachePath, { overwrite: true });
|
|
2102
2098
|
|
|
2103
2099
|
const key = 'blocklet:manager:downloadCache';
|
|
2104
|
-
const cacheList = (await
|
|
2100
|
+
const cacheList = (await states.cache.get(key)) || [];
|
|
2105
2101
|
const exist = cacheList.find((x) => x.integrity === integrity);
|
|
2106
2102
|
|
|
2107
2103
|
// update
|
|
2108
2104
|
if (exist) {
|
|
2109
2105
|
logger.info('update cache tarFile', { base58: integrity });
|
|
2110
2106
|
exist.accessAt = Date.now();
|
|
2111
|
-
await
|
|
2107
|
+
await states.cache.set(key, cacheList);
|
|
2112
2108
|
return;
|
|
2113
2109
|
}
|
|
2114
2110
|
|
|
@@ -2132,7 +2128,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2132
2128
|
logger.info('add cache tarFile', { base58: integrity });
|
|
2133
2129
|
|
|
2134
2130
|
// update
|
|
2135
|
-
await
|
|
2131
|
+
await states.cache.set(key, cacheList);
|
|
2136
2132
|
}
|
|
2137
2133
|
|
|
2138
2134
|
async _getCachedTarFile(integrity) {
|
|
@@ -2253,9 +2249,9 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2253
2249
|
|
|
2254
2250
|
async _syncPm2Status(pm2Status, did) {
|
|
2255
2251
|
try {
|
|
2256
|
-
const state = await
|
|
2252
|
+
const state = await states.blocklet.getBlocklet(did);
|
|
2257
2253
|
if (state && util.shouldUpdateBlockletStatus(state.status)) {
|
|
2258
|
-
const result = await
|
|
2254
|
+
const result = await states.blocklet.setBlockletStatus(did, pm2StatusMap[pm2Status]);
|
|
2259
2255
|
logger.info('sync pm2 status to blocklet', { result });
|
|
2260
2256
|
}
|
|
2261
2257
|
} catch (error) {
|
|
@@ -2300,8 +2296,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2300
2296
|
|
|
2301
2297
|
if (['upgrade', 'downgrade'].includes(action)) {
|
|
2302
2298
|
// rollback blocklet
|
|
2303
|
-
const
|
|
2304
|
-
const result = await this.state.updateById(_id, { $set: oldBlocklet });
|
|
2299
|
+
const result = await states.blocklet.updateBlocklet(did, oldBlocklet);
|
|
2305
2300
|
await this._setConfigs(did);
|
|
2306
2301
|
logger.info('blocklet rollback successfully', { did });
|
|
2307
2302
|
this.emit(BlockletEvents.updated, { blocklet: result });
|
|
@@ -2313,7 +2308,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2313
2308
|
}
|
|
2314
2309
|
|
|
2315
2310
|
async _deleteBlocklet({ did, keepData, keepLogsDir, keepConfigs }, context) {
|
|
2316
|
-
const blocklet = await
|
|
2311
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
2317
2312
|
const { name } = blocklet.meta;
|
|
2318
2313
|
const dataDir = path.join(this.dataDirs.data, name);
|
|
2319
2314
|
const logsDir = path.join(this.dataDirs.logs, name);
|
|
@@ -2335,7 +2330,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2335
2330
|
}
|
|
2336
2331
|
}
|
|
2337
2332
|
|
|
2338
|
-
const result = await
|
|
2333
|
+
const result = await states.blocklet.deleteBlocklet(did);
|
|
2339
2334
|
logger.info('blocklet removed successfully', { did });
|
|
2340
2335
|
|
|
2341
2336
|
this.emit(BlockletEvents.removed, { blocklet: result, context });
|
|
@@ -2343,20 +2338,20 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
2343
2338
|
}
|
|
2344
2339
|
|
|
2345
2340
|
async _setConfigs(did) {
|
|
2346
|
-
const blocklet = await
|
|
2341
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
2347
2342
|
const { meta } = blocklet;
|
|
2348
|
-
await
|
|
2343
|
+
await states.blockletExtras.setConfigs(did, get(meta, 'environments', []));
|
|
2349
2344
|
for (const child of blocklet.children) {
|
|
2350
|
-
await
|
|
2345
|
+
await states.blockletExtras.setChildConfigs(did, child.meta.did, get(child.meta, 'environments'));
|
|
2351
2346
|
}
|
|
2352
2347
|
}
|
|
2353
2348
|
|
|
2354
2349
|
async _delExtras(did) {
|
|
2355
|
-
const blocklet = await
|
|
2356
|
-
await
|
|
2357
|
-
await
|
|
2350
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
2351
|
+
await states.blockletExtras.delConfigs(did);
|
|
2352
|
+
await states.blockletExtras.delSettings(did);
|
|
2358
2353
|
for (const child of blocklet.children) {
|
|
2359
|
-
await
|
|
2354
|
+
await states.blockletExtras.delChildConfigs(did, child.meta.did);
|
|
2360
2355
|
}
|
|
2361
2356
|
}
|
|
2362
2357
|
}
|
|
@@ -7,7 +7,7 @@ const cloneDeep = require('lodash/cloneDeep');
|
|
|
7
7
|
const security = require('@abtnode/util/lib/security');
|
|
8
8
|
|
|
9
9
|
module.exports = async ({ states, configFile, dataDir }) => {
|
|
10
|
-
if (process.env.CI) {
|
|
10
|
+
if (process.env.CI || process.env.NODE_ENV === 'test') {
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -34,8 +34,24 @@ module.exports = async ({ states, configFile, dataDir }) => {
|
|
|
34
34
|
return c;
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
const newChildren = cloneDeep(item.children || []).map((x) => {
|
|
38
|
+
return {
|
|
39
|
+
...x,
|
|
40
|
+
configs: cloneDeep(x.configs || []).map((c) => {
|
|
41
|
+
if (c.secure) {
|
|
42
|
+
c.value = security.encrypt(c.value, item.did, fs.readFileSync(file));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return c;
|
|
46
|
+
}),
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await states.blockletExtras.update({ did: item.did }, { $set: { configs: newConfigs, children: newChildren } });
|
|
38
51
|
}
|
|
52
|
+
|
|
53
|
+
states.node.compactDatafile();
|
|
54
|
+
states.blockletExtras.compactDatafile();
|
|
39
55
|
} catch (err) {
|
|
40
56
|
console.error(err);
|
|
41
57
|
throw err;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/* eslint-disable no-await-in-loop */
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const uniq = require('lodash/uniq');
|
|
5
|
+
const cloneDeep = require('lodash/cloneDeep');
|
|
6
|
+
const security = require('@abtnode/util/lib/security');
|
|
7
|
+
const { forEachBlocklet } = require('@blocklet/meta/lib/util');
|
|
8
|
+
|
|
9
|
+
module.exports = async ({ states, dataDir }) => {
|
|
10
|
+
if (process.env.CI || process.env.NODE_ENV === 'test') {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const file = path.join(dataDir, '.sock');
|
|
15
|
+
if (fs.existsSync(file) === false) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const extras = await states.blockletExtras.find();
|
|
21
|
+
const blocklets = await states.blocklet.find();
|
|
22
|
+
for (const blocklet of blocklets) {
|
|
23
|
+
forEachBlocklet(
|
|
24
|
+
blocklet,
|
|
25
|
+
(b) => {
|
|
26
|
+
let configKeys;
|
|
27
|
+
const extra = extras.find((x) => x.did === blocklet.meta.did);
|
|
28
|
+
const rootKeys = (extra.configs || []).map((x) => x.key);
|
|
29
|
+
if (b.meta.did === blocklet.meta.did) {
|
|
30
|
+
configKeys = rootKeys;
|
|
31
|
+
} else {
|
|
32
|
+
const childExtra = (extra.children || []).find((x) => x.did === b.meta.did);
|
|
33
|
+
const childKeys = childExtra ? childExtra.configs.map((x) => x.key) : [];
|
|
34
|
+
configKeys = uniq([...rootKeys, ...childKeys]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
b.environments = cloneDeep(b.environments || [])
|
|
38
|
+
.filter((x) => configKeys.includes(x.key) === false)
|
|
39
|
+
.map((c) => {
|
|
40
|
+
if (c.key === 'BLOCKLET_APP_SK') {
|
|
41
|
+
c.value = security.encrypt(c.value, b.meta.did, fs.readFileSync(file));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return c;
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
{ sync: true }
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
await states.blocklet.updateById(blocklet._id, {
|
|
51
|
+
$set: { environments: blocklet.environments, children: blocklet.children, migratedFrom: '1.6.5' },
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
states.blocklet.compactDatafile();
|
|
56
|
+
} catch (err) {
|
|
57
|
+
console.error(err);
|
|
58
|
+
throw err;
|
|
59
|
+
}
|
|
60
|
+
};
|
package/lib/states/base.js
CHANGED
|
@@ -191,6 +191,14 @@ class BaseState extends EventEmitter {
|
|
|
191
191
|
insert(...args) {
|
|
192
192
|
return this.asyncDB.insert(...args);
|
|
193
193
|
}
|
|
194
|
+
|
|
195
|
+
compactDatafile() {
|
|
196
|
+
this.db.persistence.compactDatafile((err) => {
|
|
197
|
+
if (err) {
|
|
198
|
+
console.error(`failed to compact datafile: ${this.filename}`, err);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
194
202
|
}
|
|
195
203
|
|
|
196
204
|
/**
|
package/lib/states/blocklet.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable no-async-promise-executor */
|
|
1
2
|
/* eslint-disable no-await-in-loop */
|
|
2
3
|
/* eslint-disable function-paren-newline */
|
|
3
4
|
/* eslint-disable no-underscore-dangle */
|
|
@@ -5,6 +6,7 @@ const omit = require('lodash/omit');
|
|
|
5
6
|
const uniq = require('lodash/uniq');
|
|
6
7
|
const detectPort = require('detect-port');
|
|
7
8
|
const Lock = require('@abtnode/util/lib/lock');
|
|
9
|
+
const security = require('@abtnode/util/lib/security');
|
|
8
10
|
const { fixPerson, fixInterfaces } = require('@blocklet/meta/lib/fix');
|
|
9
11
|
const {
|
|
10
12
|
BlockletStatus,
|
|
@@ -27,6 +29,40 @@ const getMaxPort = (ports = {}) => Math.max(Object.values(ports).map(Number));
|
|
|
27
29
|
const getExternalPortsFromMeta = (meta) =>
|
|
28
30
|
(meta.interfaces || []).map((x) => x.port && x.port.external).filter(Boolean);
|
|
29
31
|
|
|
32
|
+
const formatBlocklet = (blocklet, phase, dek) => {
|
|
33
|
+
forEachBlocklet(
|
|
34
|
+
blocklet,
|
|
35
|
+
(b) => {
|
|
36
|
+
if (b.meta) {
|
|
37
|
+
fixPerson(b.meta);
|
|
38
|
+
fixInterfaces(b.meta);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
b.children = b.children || [];
|
|
42
|
+
|
|
43
|
+
if (!b.environments || !b.meta || !dek) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
['BLOCKLET_APP_SK'].forEach((key) => {
|
|
48
|
+
const env = b.environments.find((x) => x.key === key);
|
|
49
|
+
if (!env) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (phase === 'onUpdate' && env.value.indexOf('0x') === 0) {
|
|
53
|
+
env.value = security.encrypt(env.value, b.meta.did, dek);
|
|
54
|
+
}
|
|
55
|
+
if (phase === 'onRead' && env.value.indexOf('0x') === -1) {
|
|
56
|
+
env.value = security.decrypt(env.value, b.meta.did, dek);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
{ sync: true }
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return blocklet;
|
|
64
|
+
};
|
|
65
|
+
|
|
30
66
|
class BlockletState extends BaseState {
|
|
31
67
|
/**
|
|
32
68
|
* Creates an instance of BlockletState
|
|
@@ -48,14 +84,7 @@ class BlockletState extends BaseState {
|
|
|
48
84
|
return reject(err);
|
|
49
85
|
}
|
|
50
86
|
|
|
51
|
-
|
|
52
|
-
// TODO: this only exists for backward compatible
|
|
53
|
-
fixPerson(doc.meta);
|
|
54
|
-
fixInterfaces(doc.meta);
|
|
55
|
-
doc.children = doc.children || [];
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return resolve(doc);
|
|
87
|
+
return resolve(doc ? formatBlocklet(doc, 'onRead', this.options.dek) : null);
|
|
59
88
|
});
|
|
60
89
|
});
|
|
61
90
|
}
|
|
@@ -70,14 +99,7 @@ class BlockletState extends BaseState {
|
|
|
70
99
|
return reject(err);
|
|
71
100
|
}
|
|
72
101
|
|
|
73
|
-
return resolve(
|
|
74
|
-
docs.filter(Boolean).map((doc) => {
|
|
75
|
-
// TODO: this only exists for backward compatible
|
|
76
|
-
fixPerson(doc.meta);
|
|
77
|
-
fixInterfaces(doc.meta);
|
|
78
|
-
return doc;
|
|
79
|
-
})
|
|
80
|
-
);
|
|
102
|
+
return resolve(docs.filter(Boolean).map((doc) => formatBlocklet(doc, 'onRead', this.options.dek)));
|
|
81
103
|
});
|
|
82
104
|
});
|
|
83
105
|
}
|
|
@@ -114,7 +136,6 @@ class BlockletState extends BaseState {
|
|
|
114
136
|
} = {}) {
|
|
115
137
|
return this.getBlocklet(did).then(
|
|
116
138
|
(doc) =>
|
|
117
|
-
// eslint-disable-next-line no-async-promise-executor
|
|
118
139
|
new Promise(async (resolve, reject) => {
|
|
119
140
|
if (doc) {
|
|
120
141
|
reject(new Error('Blocklet already added'));
|
|
@@ -165,6 +186,26 @@ class BlockletState extends BaseState {
|
|
|
165
186
|
);
|
|
166
187
|
}
|
|
167
188
|
|
|
189
|
+
updateBlocklet(did, updates) {
|
|
190
|
+
return this.getBlocklet(did).then(
|
|
191
|
+
(doc) =>
|
|
192
|
+
new Promise(async (resolve, reject) => {
|
|
193
|
+
if (!doc) {
|
|
194
|
+
reject(new Error('Blocklet does not exist'));
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
const formatted = formatBlocklet(updates, 'onUpdate', this.options.dek);
|
|
200
|
+
const newDoc = await this.updateById(doc._id, { $set: formatted });
|
|
201
|
+
resolve(newDoc);
|
|
202
|
+
} catch (err) {
|
|
203
|
+
reject(err);
|
|
204
|
+
}
|
|
205
|
+
})
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
168
209
|
upgradeBlocklet({ meta, source, deployedFrom, children } = {}) {
|
|
169
210
|
return this.getBlocklet(meta.did).then(
|
|
170
211
|
(doc) =>
|
package/lib/util/blocklet.js
CHANGED
|
@@ -192,7 +192,6 @@ const fillBlockletConfigs = (blocklet, configs) => {
|
|
|
192
192
|
acc[x.key] = x.value;
|
|
193
193
|
return acc;
|
|
194
194
|
}, {});
|
|
195
|
-
blocklet.userEnvironments = blocklet.configObj; // deprecated
|
|
196
195
|
blocklet.environmentObj = (blocklet.environments || []).reduce((acc, x) => {
|
|
197
196
|
acc[x.key] = x.value;
|
|
198
197
|
return acc;
|
|
@@ -308,6 +307,7 @@ const getRuntimeEnvironments = (blocklet, nodeEnvironments) => {
|
|
|
308
307
|
|
|
309
308
|
return {
|
|
310
309
|
...blocklet.environmentObj,
|
|
310
|
+
...blocklet.configObj,
|
|
311
311
|
...nodeEnvironments,
|
|
312
312
|
...safeNodeEnvironments,
|
|
313
313
|
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.6.
|
|
6
|
+
"version": "1.6.5",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -19,20 +19,20 @@
|
|
|
19
19
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@abtnode/constant": "1.6.
|
|
23
|
-
"@abtnode/cron": "1.6.
|
|
24
|
-
"@abtnode/logger": "1.6.
|
|
25
|
-
"@abtnode/queue": "1.6.
|
|
26
|
-
"@abtnode/rbac": "1.6.
|
|
27
|
-
"@abtnode/router-provider": "1.6.
|
|
28
|
-
"@abtnode/static-server": "1.6.
|
|
29
|
-
"@abtnode/timemachine": "1.6.
|
|
30
|
-
"@abtnode/util": "1.6.
|
|
22
|
+
"@abtnode/constant": "1.6.5",
|
|
23
|
+
"@abtnode/cron": "1.6.5",
|
|
24
|
+
"@abtnode/logger": "1.6.5",
|
|
25
|
+
"@abtnode/queue": "1.6.5",
|
|
26
|
+
"@abtnode/rbac": "1.6.5",
|
|
27
|
+
"@abtnode/router-provider": "1.6.5",
|
|
28
|
+
"@abtnode/static-server": "1.6.5",
|
|
29
|
+
"@abtnode/timemachine": "1.6.5",
|
|
30
|
+
"@abtnode/util": "1.6.5",
|
|
31
31
|
"@arcblock/did": "^1.13.77",
|
|
32
32
|
"@arcblock/event-hub": "1.13.77",
|
|
33
33
|
"@arcblock/pm2-events": "^0.0.5",
|
|
34
34
|
"@arcblock/vc": "^1.13.77",
|
|
35
|
-
"@blocklet/meta": "1.6.
|
|
35
|
+
"@blocklet/meta": "1.6.5",
|
|
36
36
|
"@fidm/x509": "^1.2.1",
|
|
37
37
|
"@nedb/core": "^1.2.2",
|
|
38
38
|
"@nedb/multi": "^1.2.2",
|
|
@@ -73,5 +73,5 @@
|
|
|
73
73
|
"express": "^4.17.1",
|
|
74
74
|
"jest": "^27.3.1"
|
|
75
75
|
},
|
|
76
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "59da906682f8122797a932640aebbad5a30dfcc3"
|
|
77
77
|
}
|