@abtnode/core 1.7.10 → 1.7.13

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.
@@ -10,6 +10,7 @@ const MigrationState = require('./migration');
10
10
  const SessionState = require('./session');
11
11
  const ExtrasState = require('./blocklet-extras');
12
12
  const CacheState = require('./cache');
13
+ const AuditLogState = require('./audit-log');
13
14
 
14
15
  const init = (dataDirs, options) => {
15
16
  const notificationState = new NotificationState(dataDirs.core, options);
@@ -23,6 +24,7 @@ const init = (dataDirs, options) => {
23
24
  const sessionState = new SessionState(dataDirs.core, options);
24
25
  const extrasState = new ExtrasState(dataDirs.core, options);
25
26
  const cacheState = new CacheState(dataDirs.core, options);
27
+ const auditLogState = new AuditLogState(dataDirs.core, options);
26
28
 
27
29
  return {
28
30
  node: nodeState,
@@ -36,6 +38,7 @@ const init = (dataDirs, options) => {
36
38
  session: sessionState,
37
39
  blockletExtras: extrasState,
38
40
  cache: cacheState,
41
+ auditLog: auditLogState,
39
42
  };
40
43
  };
41
44
 
@@ -278,6 +278,14 @@ class NodeState extends BaseState {
278
278
  await this.update(_id, { $set: { customBlockletNumber: num } });
279
279
  return num;
280
280
  }
281
+
282
+ async updateGateway(gateway) {
283
+ const [, nodeInfo] = await this.update({}, { $set: { 'routing.requestLimit': gateway.requestLimit } });
284
+
285
+ this.emit(EVENTS.RELOAD_GATEWAY, nodeInfo);
286
+
287
+ return nodeInfo.routing;
288
+ }
281
289
  }
282
290
 
283
291
  module.exports = NodeState;
@@ -6,7 +6,6 @@ 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');
10
9
  const streamToPromise = require('stream-to-promise');
11
10
  const { Throttle } = require('stream-throttle');
12
11
  const ssri = require('ssri');
@@ -43,6 +42,7 @@ const getBlockletEngine = require('@blocklet/meta/lib/engine');
43
42
  const getBlockletInfo = require('@blocklet/meta/lib/info');
44
43
  const { validateMeta, fixAndValidateService } = require('@blocklet/meta/lib/validate');
45
44
  const { forEachBlocklet, isFreeBlocklet, getDisplayName, findWebInterface } = require('@blocklet/meta/lib/util');
45
+ const toBlockletDid = require('@blocklet/meta/lib/did');
46
46
 
47
47
  const { validate: validateEngine, get: getEngine } = require('../blocklet/manager/engine');
48
48
 
@@ -103,7 +103,10 @@ const PRIVATE_NODE_ENVS = [
103
103
  * appMain: app entry file or script (run appMain to start blocklet process)
104
104
  * appCwd: cwd of appMain
105
105
  */
106
- const getBlockletDirs = (blocklet, { rootBlocklet, dataDirs, ensure = false, e2eMode = false } = {}) => {
106
+ const getBlockletDirs = (
107
+ blocklet,
108
+ { rootBlocklet, dataDirs, ensure = false, e2eMode = false, validate = true } = {}
109
+ ) => {
107
110
  if (!rootBlocklet) {
108
111
  // eslint-disable-next-line no-param-reassign
109
112
  rootBlocklet = blocklet;
@@ -133,7 +136,7 @@ const getBlockletDirs = (blocklet, { rootBlocklet, dataDirs, ensure = false, e2e
133
136
  }
134
137
  }
135
138
 
136
- if (!main && !startFromDevEntry && group !== BlockletGroup.gateway) {
139
+ if (validate && !main && !startFromDevEntry && group !== BlockletGroup.gateway) {
137
140
  throw new Error('Incorrect blocklet manifest: missing `main` field');
138
141
  }
139
142
 
@@ -163,7 +166,7 @@ const getBlockletDirs = (blocklet, { rootBlocklet, dataDirs, ensure = false, e2e
163
166
 
164
167
  mainDir = appDir;
165
168
 
166
- if (!startFromDevEntry && !isBeforeInstalled(rootBlocklet.status)) {
169
+ if (validate && !startFromDevEntry && !isBeforeInstalled(rootBlocklet.status)) {
167
170
  try {
168
171
  validateBlockletEntry(appDir, blocklet.meta);
169
172
  } catch (err) {
@@ -171,7 +174,7 @@ const getBlockletDirs = (blocklet, { rootBlocklet, dataDirs, ensure = false, e2e
171
174
  }
172
175
  }
173
176
 
174
- if (!BLOCKLET_GROUPS.includes(group)) {
177
+ if (validate && !BLOCKLET_GROUPS.includes(group)) {
175
178
  throw new CustomError('BLOCKLET_CORRUPTED', `Unsupported blocklet type ${group}`);
176
179
  }
177
180
 
@@ -633,25 +636,30 @@ const reloadProcess = (appId) =>
633
636
  });
634
637
  });
635
638
 
639
+ const parseChildren = (children, parentMeta = {}, { dynamic } = {}) => {
640
+ const configs = Array.isArray(parentMeta) ? parentMeta : parentMeta.children || [];
641
+
642
+ children.forEach((x) => {
643
+ if (dynamic !== undefined) {
644
+ x.dynamic = !!dynamic;
645
+ }
646
+ });
647
+
648
+ mergeMeta(configs, children);
649
+ return children;
650
+ };
651
+
636
652
  /**
637
653
  * this function has side effect on children
638
654
  */
639
- const parseChildren = async (src, { children, dynamic } = {}) => {
655
+ const parseChildrenFromMeta = async (src, { dynamic } = {}) => {
640
656
  const configs = Array.isArray(src) ? src : src.children || [];
641
657
 
642
- if (children) {
643
- children.forEach((x) => {
644
- x.dynamic = !!dynamic;
645
- });
646
- mergeMeta(configs, children);
647
- return children;
648
- }
649
-
650
658
  if (!configs || !configs.length) {
651
659
  return [];
652
660
  }
653
661
 
654
- const results = [];
662
+ const children = [];
655
663
 
656
664
  for (const config of configs) {
657
665
  const mountPoint = config.mountPoint || config.mountPoints[0].root.prefix;
@@ -660,15 +668,6 @@ const parseChildren = async (src, { children, dynamic } = {}) => {
660
668
  }
661
669
 
662
670
  const m = await getBlockletMetaFromUrl(config.resolved);
663
- if (m.name !== config.name) {
664
- logger.error('Resolved child blocklet name does not match in the configuration', {
665
- expected: config.name,
666
- resolved: m.name,
667
- });
668
- throw new Error(
669
- `Child blocklet name does not match in the configuration. expected: ${config.name}, resolved: ${m.name}`
670
- );
671
- }
672
671
  validateBlockletMeta(m, { ensureDist: true });
673
672
 
674
673
  const webInterface = findWebInterface(m);
@@ -681,17 +680,26 @@ const parseChildren = async (src, { children, dynamic } = {}) => {
681
680
  throw new Error(`Prefix does not match in child ${config.name}. expected: ${rule}, resolved: ${mountPoint}`);
682
681
  }
683
682
 
684
- results.push({
683
+ const meta = ensureMeta(m, { name: config.name });
684
+ if (config.title) {
685
+ meta.title = config.title;
686
+ }
687
+ if (config.description) {
688
+ meta.description = config.description;
689
+ }
690
+
691
+ const child = {
685
692
  mountPoint,
686
- meta: m,
687
- dynamic: !!dynamic,
693
+ meta,
688
694
  sourceUrl: config.resolved,
689
- });
695
+ };
696
+
697
+ children.push(child);
690
698
  }
691
699
 
692
- mergeMeta(configs, results);
700
+ parseChildren(children, configs, { dynamic });
693
701
 
694
- return results;
702
+ return children;
695
703
  };
696
704
 
697
705
  const validateBlocklet = (blocklet) =>
@@ -800,7 +808,7 @@ const pruneBlockletBundle = async ({ blocklets, installDir, blockletSettings })
800
808
  ].includes(blocklet.status)
801
809
  ) {
802
810
  logger.info('There are blocklet activities in progress, abort pruning', {
803
- name: blocklet.meta.name,
811
+ bundleName: blocklet.meta.bundleName,
804
812
  status: fromBlockletStatus(blocklet.status),
805
813
  });
806
814
  return;
@@ -810,14 +818,16 @@ const pruneBlockletBundle = async ({ blocklets, installDir, blockletSettings })
810
818
  // blockletMap: { <[scope/]name/version>: true }
811
819
  const blockletMap = {};
812
820
  for (const blocklet of blocklets) {
813
- blockletMap[`${blocklet.meta.name}/${blocklet.meta.version}`] = true;
821
+ blockletMap[`${blocklet.meta.bundleName}/${blocklet.meta.version}`] = true;
814
822
  for (const child of blocklet.children || []) {
815
- blockletMap[`${child.meta.name}/${child.meta.version}`] = true;
823
+ blockletMap[`${child.meta.bundleName}/${child.meta.version}`] = true;
816
824
  }
817
825
  }
818
826
  for (const setting of blockletSettings) {
819
827
  for (const child of setting.children || []) {
820
- blockletMap[`${child.meta.name}/${child.meta.version}`] = true;
828
+ if (child.status !== BlockletStatus.deleted) {
829
+ blockletMap[`${child.meta.bundleName}/${child.meta.version}`] = true;
830
+ }
821
831
  }
822
832
  }
823
833
 
@@ -1006,11 +1016,7 @@ const mergeMeta = (source, childrenMeta = []) => {
1006
1016
  });
1007
1017
  };
1008
1018
 
1009
- const fixAndVerifyBlockletMeta = (meta, did) => {
1010
- if (meta.did !== did) {
1011
- throw new Error('Invalid blocklet meta: did does not match');
1012
- }
1013
-
1019
+ const fixAndVerifyMetaFromStore = (meta) => {
1014
1020
  const sanitized = validateMeta(meta, { ensureDist: false, schemaOptions: { noDefaults: true, stripUnknown: true } });
1015
1021
 
1016
1022
  try {
@@ -1057,8 +1063,10 @@ const getSourceFromInstallParams = (params) => {
1057
1063
  throw new Error('Can only install blocklet from store/url/upload/custom');
1058
1064
  };
1059
1065
 
1060
- const checkDuplicateComponents = (dynamicComponents, staticComponents) => {
1061
- const duplicates = intersectionBy(dynamicComponents, staticComponents, 'meta.did');
1066
+ const checkDuplicateComponents = (components = []) => {
1067
+ const duplicates = components.filter(
1068
+ (item, index) => components.findIndex((x) => x.meta.did === item.meta.did) !== index
1069
+ );
1062
1070
  if (duplicates.length) {
1063
1071
  throw new Error(
1064
1072
  `Cannot add duplicate component${duplicates.length > 1 ? 's' : ''}: ${duplicates
@@ -1066,6 +1074,13 @@ const checkDuplicateComponents = (dynamicComponents, staticComponents) => {
1066
1074
  .join(', ')}`
1067
1075
  );
1068
1076
  }
1077
+
1078
+ const duplicateMountPoints = components.filter(
1079
+ (item, index) => components.findIndex((x) => x.mountPoint === item.mountPoint) !== index
1080
+ );
1081
+ if (duplicateMountPoints.length) {
1082
+ throw new Error(`mountpoint must be unique: ${duplicateMountPoints.map((x) => x.mountPoint).join(', ')}`);
1083
+ }
1069
1084
  };
1070
1085
 
1071
1086
  const getDiffFiles = async (inputFiles, sourceDir) => {
@@ -1109,7 +1124,7 @@ const getDiffFiles = async (inputFiles, sourceDir) => {
1109
1124
  };
1110
1125
  };
1111
1126
 
1112
- const getBundleDir = (installDir, bundle) => path.join(installDir, bundle.name, bundle.version);
1127
+ const getBundleDir = (installDir, meta) => path.join(installDir, meta.bundleName || meta.name, meta.version);
1113
1128
 
1114
1129
  const needBlockletDownload = (blocklet, oldBlocklet) => {
1115
1130
  if ([BlockletSource.upload, BlockletSource.local, BlockletSource.custom].includes(blocklet.source)) {
@@ -1139,9 +1154,51 @@ const verifyPurchase = (meta, opts = {}) => {
1139
1154
  throw new Error('Can not install a non-free blocklet directly');
1140
1155
  };
1141
1156
 
1157
+ const findAvailableDid = (meta, siblings) => {
1158
+ const reg = /-(\d+)$/;
1159
+ const match = reg.exec(meta.name);
1160
+
1161
+ const newName = match ? meta.name.replace(reg, `-${Number(match[1]) + 1}`) : `${meta.name}-1`;
1162
+ const newDid = toBlockletDid(newName);
1163
+ const newMeta = { name: newName, did: newDid };
1164
+
1165
+ if (!(siblings || []).some((x) => x.did === newMeta.did)) {
1166
+ return newMeta;
1167
+ }
1168
+
1169
+ return findAvailableDid(newMeta, siblings);
1170
+ };
1171
+
1172
+ const ensureMeta = (meta, { name, did } = {}) => {
1173
+ if (name && did && toBlockletDid(name) !== did) {
1174
+ throw new Error('name does not match with did');
1175
+ }
1176
+
1177
+ const newMeta = {
1178
+ ...meta,
1179
+ };
1180
+
1181
+ if (!newMeta.did || !newMeta.name || toBlockletDid(newMeta.name) !== newMeta.did) {
1182
+ throw new Error('name does not match with did in meta');
1183
+ }
1184
+
1185
+ if (!meta.bundleDid) {
1186
+ newMeta.bundleDid = meta.did;
1187
+ newMeta.bundleName = meta.name;
1188
+ }
1189
+
1190
+ if (name) {
1191
+ newMeta.name = name;
1192
+ newMeta.did = did || toBlockletDid(name);
1193
+ }
1194
+
1195
+ return newMeta;
1196
+ };
1197
+
1142
1198
  module.exports = {
1143
1199
  forEachBlocklet,
1144
1200
  getBlockletMetaFromUrl,
1201
+ parseChildrenFromMeta,
1145
1202
  parseChildren,
1146
1203
  getBlockletDirs,
1147
1204
  getRootSystemEnvironments,
@@ -1166,7 +1223,7 @@ module.exports = {
1166
1223
  getDiskInfo,
1167
1224
  getRuntimeInfo,
1168
1225
  mergeMeta,
1169
- fixAndVerifyBlockletMeta,
1226
+ fixAndVerifyMetaFromStore,
1170
1227
  getUpdateMetaList,
1171
1228
  getSourceFromInstallParams,
1172
1229
  findWebInterface,
@@ -1175,4 +1232,6 @@ module.exports = {
1175
1232
  getBundleDir,
1176
1233
  needBlockletDownload,
1177
1234
  verifyPurchase,
1235
+ findAvailableDid,
1236
+ ensureMeta,
1178
1237
  };
package/lib/util/index.js CHANGED
@@ -474,6 +474,39 @@ const getSafeEnv = (inputEnv, processEnv = process.env) => {
474
474
  return mergedEnv;
475
475
  };
476
476
 
477
+ // For performance sake, we only support 1 param here, and the cache is flushed every minute
478
+ const memoizeAsync = (fn, flushInterval = 60000) => {
479
+ const cache = new Map();
480
+ setInterval(() => cache.clear(), flushInterval);
481
+
482
+ return (arg) => {
483
+ if (cache.has(arg)) {
484
+ return cache.get(arg);
485
+ }
486
+
487
+ // eslint-disable-next-line prefer-spread
488
+ const result = fn.apply(null, [arg]);
489
+ cache.set(arg, result);
490
+
491
+ return result;
492
+ };
493
+ };
494
+
495
+ const getStateCrons = (states) => [
496
+ {
497
+ name: 'cleanup-audit-logs',
498
+ time: '0 0 6 * * *', // cleanup old logs every day at 6am
499
+ // time: '0 */5 * * * *', // cleanup every 5 minutes
500
+ options: { runOnInit: false },
501
+ fn: async () => {
502
+ const removed = await states.auditLog.remove({
503
+ createdAt: { $lt: new Date(Date.now() - 1000 * 60 * 60 * 24 * 90) },
504
+ });
505
+ logger.info(`Removed ${removed} audit logs`);
506
+ },
507
+ },
508
+ ];
509
+
477
510
  const lib = {
478
511
  validateOwner,
479
512
  getProviderFromNodeInfo,
@@ -510,6 +543,8 @@ const lib = {
510
543
  transformIPToDomain,
511
544
  getQueueConcurrencyByMem,
512
545
  getSafeEnv,
546
+ memoizeAsync,
547
+ getStateCrons,
513
548
  };
514
549
 
515
550
  module.exports = lib;
package/lib/util/ip.js CHANGED
@@ -1,6 +1,9 @@
1
1
  const getIp = require('@abtnode/util/lib/get-ip');
2
2
  const logger = require('@abtnode/logger')('@abtnode/core:ip');
3
3
 
4
+ const doRpc = require('./rpc');
5
+ const { memoizeAsync } = require('./index');
6
+
4
7
  let cache = null;
5
8
  const fetch = async () => {
6
9
  try {
@@ -22,6 +25,9 @@ const cron = {
22
25
  fn: fetch,
23
26
  };
24
27
 
28
+ const lookup = memoizeAsync((ip) => doRpc({ command: 'lookup', ip }));
29
+
25
30
  module.exports.fetch = fetch;
26
31
  module.exports.get = get;
27
32
  module.exports.cron = cron;
33
+ module.exports.lookup = lookup;
@@ -0,0 +1,16 @@
1
+ const axon = require('axon');
2
+ const logger = require('@abtnode/logger')('@abtnode/core:rpc');
3
+
4
+ const sock = axon.socket('req');
5
+ sock.connect(Number(process.env.ABT_NODE_UPDATER_PORT || 40405), '127.0.0.1');
6
+
7
+ const doRpc = async (message) =>
8
+ new Promise((resolve) => {
9
+ logger.info('send rpc request', message);
10
+ sock.send(JSON.stringify(message), (result) => {
11
+ logger.info('receive rpc response', result);
12
+ resolve(result);
13
+ });
14
+ });
15
+
16
+ module.exports = doRpc;
package/lib/util/ua.js ADDED
@@ -0,0 +1,54 @@
1
+ const semver = require('semver');
2
+ const parser = require('ua-parser-js');
3
+ const packageJson = require('../../package.json');
4
+
5
+ const { memoizeAsync } = require('./index');
6
+
7
+ const parseWalletUA = (userAgent) => {
8
+ const ua = (userAgent || '').toString().toLowerCase();
9
+ let os = '';
10
+ let version = '';
11
+ if (ua.indexOf('android') > -1) {
12
+ os = 'android';
13
+ } else if (ua.indexOf('darwin') > -1) {
14
+ os = 'ios';
15
+ } else if (ua.indexOf('arcwallet') === 0) {
16
+ os = 'web';
17
+ }
18
+
19
+ const match = ua.split(/\s+/).find((x) => x.startsWith('arcwallet'));
20
+ if (match) {
21
+ const tmp = match.split('/');
22
+ if (tmp.length > 1 && semver.coerce(tmp[1])) {
23
+ version = semver.coerce(tmp[1]).version;
24
+ }
25
+ }
26
+
27
+ return { os, version };
28
+ };
29
+
30
+ const parse = memoizeAsync((ua) => {
31
+ let result = parser(ua);
32
+ if (result.browser.name) {
33
+ return result;
34
+ }
35
+
36
+ result = parseWalletUA(ua);
37
+ if (result.version) {
38
+ return {
39
+ browser: {
40
+ name: `DID Wallet ${result.os.toUpperCase()}`,
41
+ version: result.version,
42
+ },
43
+ };
44
+ }
45
+
46
+ return {
47
+ browser: {
48
+ name: 'CLI',
49
+ version: packageJson.version,
50
+ },
51
+ };
52
+ });
53
+
54
+ module.exports = { parse };
@@ -1,5 +1,4 @@
1
1
  /* eslint-disable no-param-reassign */
2
- const axon = require('axon');
3
2
  const semver = require('semver');
4
3
  const sleep = require('@abtnode/util/lib/sleep');
5
4
  const { NODE_MODES, NODE_UPGRADE_PROGRESS, EVENTS } = require('@abtnode/constant');
@@ -8,21 +7,10 @@ const Lock = require('@abtnode/util/lib/lock');
8
7
  const logger = require('@abtnode/logger')('@abtnode/core:upgrade');
9
8
 
10
9
  const states = require('../states');
10
+ const doRpc = require('./rpc');
11
11
 
12
12
  const lock = new Lock('node-upgrade-lock');
13
13
 
14
- // Connect to updater and send RPC call
15
- const sock = axon.socket('req');
16
- sock.connect(Number(process.env.ABT_NODE_UPDATER_PORT), '127.0.0.1');
17
- const waitUpdaterRpc = async (message) =>
18
- new Promise((resolve) => {
19
- logger.info('send command to updater process', message);
20
- sock.send(JSON.stringify(message), (result) => {
21
- logger.info('receive response from updater process', result);
22
- resolve(result);
23
- });
24
- });
25
-
26
14
  // eslint-disable-next-line no-unused-vars
27
15
  const checkNewVersion = async (params, context) => {
28
16
  try {
@@ -120,7 +108,7 @@ const doUpgrade = async (session) => {
120
108
 
121
109
  // 2. install specified version
122
110
  if (session.stage === NODE_UPGRADE_PROGRESS.INSTALLING) {
123
- await waitUpdaterRpc({ command: 'install', version: to });
111
+ await doRpc({ command: 'install', version: to });
124
112
  logger.info('new version installed for upgrading', { from, to, sessionId });
125
113
  await goNextState(NODE_UPGRADE_PROGRESS.RESTARTING);
126
114
  }
@@ -131,7 +119,7 @@ const doUpgrade = async (session) => {
131
119
  await sleep(3000);
132
120
  await goNextState(NODE_UPGRADE_PROGRESS.CLEANUP);
133
121
  await sleep(3000);
134
- await waitUpdaterRpc({ command: 'restart', dataDir: process.env.ABT_NODE_DATA_DIR });
122
+ await doRpc({ command: 'restart', dataDir: process.env.ABT_NODE_DATA_DIR });
135
123
  await lock.release();
136
124
  return; // we should abort here and resume after restart
137
125
  }
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable newline-per-chained-call */
2
+ const { GATEWAY_REQ_LIMIT } = require('@abtnode/constant');
2
3
  const Joi = require('joi');
3
4
  const { getMultipleLangParams } = require('./util');
4
5
 
@@ -42,6 +43,18 @@ const nodeInfoSchema = Joi.object({
42
43
  }),
43
44
  }).options({ stripUnknown: true });
44
45
 
46
+ const updateGatewaySchema = Joi.object({
47
+ requestLimit: Joi.object({
48
+ enabled: Joi.bool().required(),
49
+ rate: Joi.number()
50
+ .min(GATEWAY_REQ_LIMIT.min)
51
+ .max(GATEWAY_REQ_LIMIT.max)
52
+ .when('requestLimit.enabled', { is: true, then: Joi.required() }),
53
+ ipHeader: Joi.string().allow('').trim(),
54
+ }),
55
+ });
56
+
45
57
  module.exports = {
46
58
  validateNodeInfo: (entity, context) => nodeInfoSchema.validateAsync(entity, getMultipleLangParams(context)),
59
+ validateUpdateGateway: (entity, context) => updateGatewaySchema.validateAsync(entity, getMultipleLangParams(context)),
47
60
  };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.7.10",
6
+ "version": "1.7.13",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,29 +19,29 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "@abtnode/certificate-manager": "1.7.10",
23
- "@abtnode/constant": "1.7.10",
24
- "@abtnode/cron": "1.7.10",
25
- "@abtnode/db": "1.7.10",
26
- "@abtnode/logger": "1.7.10",
27
- "@abtnode/queue": "1.7.10",
28
- "@abtnode/rbac": "1.7.10",
29
- "@abtnode/router-provider": "1.7.10",
30
- "@abtnode/static-server": "1.7.10",
31
- "@abtnode/timemachine": "1.7.10",
32
- "@abtnode/util": "1.7.10",
33
- "@arcblock/did": "^1.16.5",
22
+ "@abtnode/certificate-manager": "1.7.13",
23
+ "@abtnode/constant": "1.7.13",
24
+ "@abtnode/cron": "1.7.13",
25
+ "@abtnode/db": "1.7.13",
26
+ "@abtnode/logger": "1.7.13",
27
+ "@abtnode/queue": "1.7.13",
28
+ "@abtnode/rbac": "1.7.13",
29
+ "@abtnode/router-provider": "1.7.13",
30
+ "@abtnode/static-server": "1.7.13",
31
+ "@abtnode/timemachine": "1.7.13",
32
+ "@abtnode/util": "1.7.13",
33
+ "@arcblock/did": "^1.16.6",
34
34
  "@arcblock/did-motif": "^1.1.5",
35
- "@arcblock/event-hub": "1.16.5",
35
+ "@arcblock/event-hub": "1.16.6",
36
36
  "@arcblock/pm2-events": "^0.0.5",
37
- "@arcblock/vc": "^1.16.5",
38
- "@blocklet/meta": "1.7.10",
37
+ "@arcblock/vc": "^1.16.6",
38
+ "@blocklet/meta": "1.7.13",
39
39
  "@fidm/x509": "^1.2.1",
40
40
  "@nedb/core": "^1.2.2",
41
41
  "@nedb/multi": "^1.2.2",
42
- "@ocap/mcrypto": "^1.16.5",
43
- "@ocap/util": "^1.16.5",
44
- "@ocap/wallet": "^1.16.5",
42
+ "@ocap/mcrypto": "^1.16.6",
43
+ "@ocap/util": "^1.16.6",
44
+ "@ocap/wallet": "^1.16.6",
45
45
  "@slack/webhook": "^5.0.3",
46
46
  "axios": "^0.26.1",
47
47
  "axon": "^2.0.3",
@@ -67,6 +67,7 @@
67
67
  "stream-to-promise": "^3.0.0",
68
68
  "systeminformation": "^5.11.5",
69
69
  "tar": "^6.1.0",
70
+ "ua-parser-js": "^1.0.2",
70
71
  "unzipper": "^0.10.11",
71
72
  "url-join": "^4.0.1",
72
73
  "uuid": "7.0.3"
@@ -77,5 +78,5 @@
77
78
  "express": "^4.17.1",
78
79
  "jest": "^27.4.5"
79
80
  },
80
- "gitHead": "8eab10fd39b6183a2fa4d2706f52e8b2ecaa059a"
81
+ "gitHead": "c35c485417df0e023c06c09557644b46a6c8c655"
81
82
  }