@abtnode/core 1.16.14-beta-0c29907f → 1.16.14-beta-1936d3d0

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.
@@ -77,7 +77,7 @@ const {
77
77
  SUSPENDED_REASON,
78
78
  } = require('@blocklet/constant');
79
79
  const isUndefined = require('lodash/isUndefined');
80
- const { WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
80
+ const { WELLKNOWN_SERVICE_PATH_PREFIX, WELLKNOWN_BLOCKLET_ADMIN_PATH } = require('@abtnode/constant');
81
81
  const { signV2 } = require('@arcblock/jwt');
82
82
  const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
83
83
  const pLimit = require('p-limit');
@@ -477,18 +477,6 @@ class DiskBlockletManager extends BaseBlockletManager {
477
477
  blocklet1.status = BlockletStatus.starting;
478
478
  this.emit(BlockletEvents.statusChange, doc1);
479
479
 
480
- if (blocklet1.mode === BLOCKLET_MODES.DEVELOPMENT) {
481
- const { logsDir } = blocklet1.env;
482
-
483
- try {
484
- fs.removeSync(logsDir);
485
- fs.mkdirSync(logsDir, { recursive: true });
486
- } catch {
487
- // Windows && Node.js 18.x 下会发生删除错误(ENOTEMPTY)
488
- // 但是这个错误并不影响后续逻辑,所以这里对这个错误做了 catch
489
- }
490
- }
491
-
492
480
  const blocklet = await ensureAppPortsNotOccupied({ blocklet: blocklet1, componentDids, states, manager: this });
493
481
 
494
482
  const getHookFn =
@@ -622,6 +610,16 @@ class DiskBlockletManager extends BaseBlockletManager {
622
610
  components: getComponentsInternalInfo(res),
623
611
  });
624
612
 
613
+ this._createNotification(did, {
614
+ title: '',
615
+ description: `${
616
+ componentDids?.length ? getComponentNamesWithVersion(blocklet, componentDids) : 'All components'
617
+ } is successfully stopped for ${blocklet.meta.title}.`,
618
+ entityType: 'blocklet',
619
+ entityId: did,
620
+ severity: 'success',
621
+ });
622
+
625
623
  return res;
626
624
  }
627
625
 
@@ -1311,7 +1309,7 @@ class DiskBlockletManager extends BaseBlockletManager {
1311
1309
  const enabled = newConfig?.email?.enabled;
1312
1310
  if (enabled) {
1313
1311
  const { error } = emailConfigSchema.validate(
1314
- pick(newConfig?.email || {}, ['from', 'host', 'port', 'user', 'password'])
1312
+ pick(newConfig?.email || {}, ['from', 'host', 'port', 'user', 'password', 'secure'])
1315
1313
  );
1316
1314
  if (error) {
1317
1315
  logger.error('configNotification validate error', { error });
@@ -1510,7 +1508,7 @@ class DiskBlockletManager extends BaseBlockletManager {
1510
1508
  addToUpdates(component.meta.did, status);
1511
1509
  logger.info('will sync status from pm2', { did, status, oldStatus, componentDid: component.meta.did });
1512
1510
  }
1513
- } catch {
1511
+ } catch (error) {
1514
1512
  if (
1515
1513
  ![
1516
1514
  BlockletStatus.added,
@@ -1519,11 +1517,21 @@ class DiskBlockletManager extends BaseBlockletManager {
1519
1517
  BlockletStatus.installing,
1520
1518
  BlockletStatus.installed,
1521
1519
  BlockletStatus.upgrading,
1522
- ].includes(component.status)
1520
+ ].includes(component.status) &&
1521
+ (error.code !== 'BLOCKLET_PROCESS_404' ||
1522
+ ![BlockletStatus.stopped, BlockletStatus.error].includes(component.status))
1523
1523
  ) {
1524
+ const oldStatus = component.status;
1524
1525
  const status = BlockletStatus.stopped;
1525
1526
  component.status = status;
1526
1527
  addToUpdates(component.meta.did, status);
1528
+ logger.info('will sync status from pm2', {
1529
+ did,
1530
+ status,
1531
+ oldStatus,
1532
+ componentDid: component.meta.did,
1533
+ error: error.message,
1534
+ });
1527
1535
  }
1528
1536
  }
1529
1537
  },
@@ -2013,6 +2021,16 @@ class DiskBlockletManager extends BaseBlockletManager {
2013
2021
 
2014
2022
  this.emit(BlockletEvents.statusChange, res);
2015
2023
  this.emit(BlockletEvents.started, { ...res, componentDids });
2024
+ this._createNotification(did, {
2025
+ title: '',
2026
+ description: `${getComponentNamesWithVersion(blocklet, componentDids)} is successfully started for ${
2027
+ blocklet.meta.title
2028
+ }.`,
2029
+ entityType: 'blocklet',
2030
+ entityId: did,
2031
+ severity: 'success',
2032
+ });
2033
+
2016
2034
  logger.info('blocklet healthy', { did, name, time: Date.now() - startedAt });
2017
2035
  } catch (error) {
2018
2036
  const status = await states.blocklet.getBlockletStatus(did);
@@ -2543,7 +2561,7 @@ class DiskBlockletManager extends BaseBlockletManager {
2543
2561
  try {
2544
2562
  // delete old process
2545
2563
  try {
2546
- await this.deleteProcess({ did }, context);
2564
+ await this.deleteProcess({ did, componentDids }, context);
2547
2565
  logger.info('delete blocklet process for upgrading', { did, name });
2548
2566
  } catch (err) {
2549
2567
  logger.error('delete blocklet process for upgrading', { did, name, error: err });
@@ -2965,7 +2983,9 @@ class DiskBlockletManager extends BaseBlockletManager {
2965
2983
  if (blocklet) {
2966
2984
  const urls = blocklet.site?.domainAliases || [];
2967
2985
  const customUrl = urls.find((x) => !x.isProtected)?.value;
2968
- blockletUrl = `http://${customUrl || getDidDomainForBlocklet({ appPid: blocklet.appPid })}`;
2986
+ blockletUrl = `http://${
2987
+ customUrl || getDidDomainForBlocklet({ appPid: blocklet.appPid })
2988
+ }${WELLKNOWN_BLOCKLET_ADMIN_PATH}`;
2969
2989
  }
2970
2990
  } catch (error) {
2971
2991
  logger.error('[_createNotification] get blocklet url failed', { error });
@@ -128,7 +128,7 @@ const getLogContent = async (action, args, context, result, info, node) => {
128
128
  case 'deleteComponent':
129
129
  return `removed ${result.deletedComponent.meta.title}@${result.deletedComponent.meta.version} ${ args.keepData !== false ? 'but kept its data and config' : 'and its data and config' }`; // prettier-ignore
130
130
  case 'configBlocklet':
131
- return `updated following config for ${args.did?.length > 1 ? componentOrApplicationInfo(result, [args.did[1]]) : 'application'}: ${args.configs.map(x => `* ${x.key}`).join(', ')}`; // prettier-ignore
131
+ return `updated following config for ${args.did?.length > 1 ? componentOrApplicationInfo(result, [args.did[1]]) : 'application'}: ${args.configs.map(x => `*${x.key}*`).join(', ')}`; // prettier-ignore
132
132
  case 'backupToSpaces':
133
133
  if (args?.success) {
134
134
  return `Backup application to ${args.url} successfully:\n- Backup files have been stored [here](${args.backupUrl})`;
@@ -157,10 +157,9 @@ const getComponentDirs = (
157
157
  // FIXME 这个函数做了太多的事
158
158
  // get data dirs
159
159
 
160
- const { name: appName } = ancestors.concat(component)[0].meta;
161
160
  const componentName = getComponentName(component, ancestors);
162
161
 
163
- const logsDir = path.join(dataDirs.logs, appName);
162
+ const logsDir = path.join(dataDirs.logs, componentName);
164
163
  const dataDir = path.join(dataDirs.data, componentName);
165
164
  const cacheDir = path.join(dataDirs.cache, componentName);
166
165
 
@@ -0,0 +1,403 @@
1
+ /* eslint-disable no-underscore-dangle */
2
+ const path = require('path');
3
+ const createArchive = require('archiver');
4
+ const fs = require('fs-extra');
5
+ const glob = require('fast-glob');
6
+ const isEqual = require('lodash/isEqual');
7
+ const { Tail } = require('tail');
8
+ const readLastLines = require('read-last-lines');
9
+ const { BLOCKLET_MODES } = require('@blocklet/constant');
10
+ const { findComponentByIdV2 } = require('@blocklet/meta/lib/util');
11
+ const dayjs = require('@abtnode/util/lib/dayjs');
12
+ const logger = require('@abtnode/logger')(require('../../package.json').name);
13
+
14
+ class StreamLog {
15
+ constructor() {
16
+ this._files = null; // Object { <level>: <filePath> }
17
+ this._tails = null; // Object { <level>: <Tail> }
18
+ }
19
+
20
+ /**
21
+ * @param {Object} files Object { <level>: <filePath> }
22
+ * @return {Boolean} if files change
23
+ */
24
+ setFiles(files) {
25
+ if (!isEqual(this._files, files)) {
26
+ this.clearTails();
27
+ this._files = files;
28
+ return true;
29
+ }
30
+ return false;
31
+ }
32
+
33
+ getRecent(lineNum, callback) {
34
+ if (!this._files) {
35
+ callback(new Error('files is empty'));
36
+ }
37
+ Object.entries(this._files).forEach(([level, file]) => {
38
+ if (!file || !fs.existsSync(file)) {
39
+ return;
40
+ }
41
+ readLastLines
42
+ .read(file, lineNum || 0)
43
+ .then((data) => {
44
+ callback(null, level, data);
45
+ })
46
+ .catch((error) => {
47
+ callback(error, level);
48
+ });
49
+ });
50
+ }
51
+
52
+ ensureTails() {
53
+ if (this._tails) {
54
+ return this._tails;
55
+ }
56
+ if (!this._files) {
57
+ return {};
58
+ }
59
+ try {
60
+ this._tails = {};
61
+ Object.entries(this._files).forEach(([level, file]) => {
62
+ if (!file || !fs.existsSync(file)) {
63
+ return;
64
+ }
65
+
66
+ // 测试发现 Windows 下 fs.watch 没有效果,但是 fs.watch 的性能更好,所以只在 windows 下使用 fs.watchFile
67
+ this._tails[level] = new Tail(file, {
68
+ useWatchFile: process.platform === 'win32',
69
+ fsWatchOptions: { interval: 1500 },
70
+ });
71
+ });
72
+ return this._tails;
73
+ } catch (error) {
74
+ this._tails = null;
75
+ throw error;
76
+ }
77
+ }
78
+
79
+ clearTails() {
80
+ if (this._tails) {
81
+ Object.values(this._tails).forEach((tail) => {
82
+ tail.unwatch();
83
+ });
84
+ this._tails = null;
85
+ }
86
+ }
87
+ }
88
+
89
+ const createFile = (files) => {
90
+ Object.values(files).forEach((file) => {
91
+ if (!fs.existsSync(file)) {
92
+ try {
93
+ const dir = path.dirname(file);
94
+ fs.mkdirSync(dir, { recursive: true });
95
+ } catch (err) {
96
+ // Do nothing
97
+ }
98
+ fs.writeFileSync(file, '', 'utf8');
99
+ }
100
+ });
101
+ };
102
+
103
+ const getLogFiles = async ({ name, node }) => {
104
+ const dt = new Date();
105
+ const { yyyy, mm, dd } = {
106
+ yyyy: dt.getFullYear(),
107
+ mm: `${dt.getMonth() + 1}`.padStart(2, 0),
108
+ dd: `${dt.getDate()}`.padStart(2, 0),
109
+ };
110
+ const date = `${yyyy}-${mm}-${dd}`;
111
+
112
+ if (name === 'abtnode') {
113
+ const logDir = path.join(node.dataDirs.logs, '_abtnode');
114
+
115
+ const info = path.join(logDir, `daemon-${date}.log`);
116
+ const error = path.join(logDir, `daemon-error-${date}.log`);
117
+ const access = path.join(logDir, 'access.log');
118
+ const stdout = path.join(logDir, 'daemon.stdout.log');
119
+ const stderr = path.join(logDir, 'daemon.stderr.log');
120
+
121
+ createFile({
122
+ info,
123
+ error,
124
+ access,
125
+ stdout,
126
+ stderr,
127
+ });
128
+
129
+ return {
130
+ info,
131
+ error,
132
+ access,
133
+ stdout,
134
+ stderr,
135
+ };
136
+ }
137
+
138
+ if (name === 'blocklet-services') {
139
+ const logDir = path.join(node.dataDirs.logs, '_abtnode');
140
+ const info = path.join(logDir, 'service.log');
141
+ const error = path.join(logDir, 'service.error.log');
142
+ createFile({ info, error });
143
+ return { info, error };
144
+ }
145
+
146
+ if (name.indexOf('blocklet-') === 0) {
147
+ const did = name.substring('blocklet-'.length);
148
+ const [appId, componentId] = did.split('/');
149
+ const blocklet = await node.getBlocklet({ did: appId, useCache: true });
150
+ let { name: blockletName } = blocklet.meta;
151
+
152
+ if (componentId) {
153
+ const component = findComponentByIdV2(blocklet, componentId);
154
+ if (component) {
155
+ blockletName = path.join(blockletName, component.meta.name);
156
+ }
157
+ }
158
+
159
+ const dir = path.join(node.dataDirs.logs, blockletName);
160
+ const info = path.join(dir, `info-${date}.log`);
161
+ const error = path.join(dir, `info-error-${date}.log`);
162
+ const access = path.join(dir, 'access.log');
163
+ const stdout = path.join(dir, 'output.log');
164
+ const stderr = path.join(dir, 'error.log');
165
+
166
+ createFile({
167
+ info,
168
+ error,
169
+ access,
170
+ stdout,
171
+ stderr,
172
+ });
173
+
174
+ return {
175
+ info,
176
+ error,
177
+ access,
178
+ stdout,
179
+ stderr,
180
+ recent: blocklet.mode === BLOCKLET_MODES.DEVELOPMENT ? 0 : 100,
181
+ };
182
+ }
183
+
184
+ if (name.startsWith('service-gateway-')) {
185
+ const providerName = name.substring('service-gateway-'.length);
186
+ const provider = node.getRouterProvider(providerName);
187
+ if (!provider) {
188
+ logger.error('router engine is empty', { name, providerName });
189
+ return {};
190
+ }
191
+
192
+ return provider.getLogFilesForToday();
193
+ }
194
+
195
+ return {};
196
+ };
197
+
198
+ const getDownloadLogFilesFromServer = async ({ dates, nodeInfo, node } = {}) => {
199
+ const logDir = path.join(node.dataDirs.logs, '_abtnode');
200
+
201
+ const pm2Log = path.join(logDir, 'pm2.log');
202
+ const pm2LogSrc = path.join(process.env.PM2_HOME, 'pm2.log');
203
+ if (fs.existsSync(pm2LogSrc)) {
204
+ await fs.copy(pm2LogSrc, pm2Log);
205
+ }
206
+
207
+ const provider = node.getRouterProvider(nodeInfo.routing.provider);
208
+ if (!provider) {
209
+ logger.error('router engine is empty');
210
+ }
211
+
212
+ const list = [];
213
+
214
+ dates.forEach((d) => {
215
+ // log file created by @abtnode/log
216
+ // log file created by abt-node-log-rotate
217
+ list.push(path.join(logDir, `*-${d}*`));
218
+
219
+ // log file create by router
220
+ const routerLogDir = provider.getLogDir();
221
+ if (routerLogDir) {
222
+ list.push(path.join(routerLogDir, `*-${d}*`));
223
+ }
224
+ });
225
+
226
+ // abt-node-daemon console & gateway
227
+ list.push(path.join(logDir, 'daemon.stdout.log*'));
228
+ list.push(path.join(logDir, 'daemon.stderr.log*'));
229
+ list.push(path.join(logDir, 'access.log*'));
230
+
231
+ // abt-node-service console & gateway
232
+ list.push(path.join(logDir, 'service.output.log*'));
233
+ list.push(path.join(logDir, 'service.error.log*'));
234
+ list.push(path.join(logDir, 'service.log*'));
235
+
236
+ // abt-node-db-hub console & backup
237
+ list.push(path.join(logDir, 'db.output.log*'));
238
+ list.push(path.join(logDir, 'db.error.log*'));
239
+
240
+ // abt-node-event-hub console
241
+ list.push(path.join(logDir, 'event.output.log*'));
242
+ list.push(path.join(logDir, 'event.error.log*'));
243
+
244
+ // abt-node-log-rotate console
245
+ list.push(path.join(logDir, 'pm2-logrotate.stdout.log*'));
246
+ list.push(path.join(logDir, 'pm2-logrotate.stderr.log*'));
247
+
248
+ // abt-node-updater console
249
+ list.push(path.join(logDir, 'updater.error.log*'));
250
+ list.push(path.join(logDir, 'updater.output.log*'));
251
+
252
+ // fallback log
253
+ list.push(path.join(logDir, 'stderr.log*'));
254
+ list.push(path.join(logDir, 'stdout.log*'));
255
+
256
+ // router
257
+ list.push(...Object.values(provider.getLogFilesForToday() || {}));
258
+
259
+ // pm2 log
260
+ list.push(pm2Log);
261
+
262
+ return glob(list);
263
+ };
264
+
265
+ const getDownloadLogFilesFromBlocklet = ({ dates, blocklet } = {}) => {
266
+ const appLogDir = path.join(blocklet.env.logsDir);
267
+ const componentLogDirs = blocklet.children.map((c) => path.join(c.env.logsDir));
268
+
269
+ const list = [];
270
+
271
+ [appLogDir, ...componentLogDirs].forEach((logDir) => {
272
+ dates.forEach((d) => {
273
+ // log file created by @abtnode/log
274
+ // log file created by abt-node-log-rotate
275
+ list.push(path.join(logDir, `*-${d}*`));
276
+ });
277
+
278
+ list.push(path.join(logDir, 'output.log*'));
279
+ list.push(path.join(logDir, 'error.log*'));
280
+ list.push(path.join(logDir, 'access.log*'));
281
+ });
282
+
283
+ return glob(list);
284
+ };
285
+
286
+ const getDownloadLogFiles = async ({ did, node, days = 1, now } = {}) => {
287
+ const dates = [dayjs(now).format('YYYY-MM-DD')];
288
+
289
+ for (let i = 1; i <= days; i++) {
290
+ dates.unshift(dayjs(now).subtract(i, 'day').format('YYYY-MM-DD'));
291
+ }
292
+
293
+ const nodeInfo = await node.getNodeInfo({ useCache: true });
294
+
295
+ if (nodeInfo.did === did) {
296
+ return getDownloadLogFilesFromServer({ dates, node, nodeInfo });
297
+ }
298
+
299
+ const blocklet = await node.getBlocklet({ did });
300
+ if (!blocklet) {
301
+ throw new Error('blocklet not found');
302
+ }
303
+
304
+ return getDownloadLogFilesFromBlocklet({ dates, blocklet });
305
+ };
306
+
307
+ const createStreamLogManager = ({ onLog, onGetLogFiles }) => {
308
+ const store = {}; // Object<name: streamLog>
309
+
310
+ const ensure = (name) => {
311
+ if (!store[name]) {
312
+ store[name] = new StreamLog();
313
+ }
314
+ return store[name];
315
+ };
316
+
317
+ const destroy = (name) => {
318
+ logger.info('log stream: destroy', { name });
319
+ if (!store[name]) {
320
+ return;
321
+ }
322
+ const log = store[name];
323
+ try {
324
+ log.clearTails();
325
+ delete store[name];
326
+ } catch (error) {
327
+ logger.error('log stream: remove ref error ', error);
328
+ delete store[name];
329
+ }
330
+ };
331
+
332
+ const add = async (name, topic, firstLogCb) => {
333
+ logger.info('log stream: add', { name });
334
+ const log = ensure(name);
335
+ try {
336
+ // update files
337
+ // push recent 100 log
338
+ const { recent = 100, ...logFiles } = await onGetLogFiles(name);
339
+ const changed = await log.setFiles(logFiles);
340
+ logger.info('log stream: added', { name, logFiles });
341
+ log.getRecent(recent, (error, level, data) => {
342
+ if (error) {
343
+ logger.error('log stream error ', error);
344
+ }
345
+ if (firstLogCb) {
346
+ firstLogCb(level, data, logFiles);
347
+ }
348
+ });
349
+ // stream
350
+ if (changed) {
351
+ const tails = log.ensureTails();
352
+ Object.entries(tails).forEach(([level, tail]) => {
353
+ tail.on('line', (data) => {
354
+ onLog({ topic, level, logFiles, data });
355
+ });
356
+ tail.on('error', (error) => {
357
+ logger.error('log tail error ', { error });
358
+ destroy(name);
359
+ });
360
+ });
361
+ }
362
+ } catch (error) {
363
+ logger.error('log stream error ', error);
364
+ }
365
+ };
366
+
367
+ return {
368
+ add,
369
+ destroy,
370
+ };
371
+ };
372
+
373
+ const createDownloadLogStream = async ({ node, did, days, now }) => {
374
+ const files = await getDownloadLogFiles({ node, did, days, now });
375
+
376
+ if (!files.length) {
377
+ throw new Error('Log file does not found');
378
+ }
379
+
380
+ const cwd = path.dirname(node.dataDirs.logs);
381
+
382
+ const archive = createArchive('zip', { zlib: { level: 9 } });
383
+ files.forEach((x) => {
384
+ archive.file(x, {
385
+ name: x.replace(`${cwd}/logs`, '/logs').replace(`${cwd}`, '/logs').replace('/_abtnode', '/blocklet-server'),
386
+ });
387
+ });
388
+
389
+ archive.rawPipe = archive.pipe.bind(archive);
390
+ archive.pipe = (s) => {
391
+ archive.rawPipe(s);
392
+ archive.finalize();
393
+ };
394
+
395
+ return archive;
396
+ };
397
+
398
+ module.exports = {
399
+ createStreamLogManager,
400
+ getLogFiles,
401
+ getDownloadLogFiles,
402
+ createDownloadLogStream,
403
+ };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.16.14-beta-0c29907f",
6
+ "version": "1.16.14-beta-1936d3d0",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,19 +19,19 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "Apache-2.0",
21
21
  "dependencies": {
22
- "@abtnode/analytics": "1.16.14-beta-0c29907f",
23
- "@abtnode/auth": "1.16.14-beta-0c29907f",
24
- "@abtnode/certificate-manager": "1.16.14-beta-0c29907f",
25
- "@abtnode/constant": "1.16.14-beta-0c29907f",
26
- "@abtnode/cron": "1.16.14-beta-0c29907f",
27
- "@abtnode/logger": "1.16.14-beta-0c29907f",
28
- "@abtnode/models": "1.16.14-beta-0c29907f",
29
- "@abtnode/queue": "1.16.14-beta-0c29907f",
30
- "@abtnode/rbac": "1.16.14-beta-0c29907f",
31
- "@abtnode/router-provider": "1.16.14-beta-0c29907f",
32
- "@abtnode/static-server": "1.16.14-beta-0c29907f",
33
- "@abtnode/timemachine": "1.16.14-beta-0c29907f",
34
- "@abtnode/util": "1.16.14-beta-0c29907f",
22
+ "@abtnode/analytics": "1.16.14-beta-1936d3d0",
23
+ "@abtnode/auth": "1.16.14-beta-1936d3d0",
24
+ "@abtnode/certificate-manager": "1.16.14-beta-1936d3d0",
25
+ "@abtnode/constant": "1.16.14-beta-1936d3d0",
26
+ "@abtnode/cron": "1.16.14-beta-1936d3d0",
27
+ "@abtnode/logger": "1.16.14-beta-1936d3d0",
28
+ "@abtnode/models": "1.16.14-beta-1936d3d0",
29
+ "@abtnode/queue": "1.16.14-beta-1936d3d0",
30
+ "@abtnode/rbac": "1.16.14-beta-1936d3d0",
31
+ "@abtnode/router-provider": "1.16.14-beta-1936d3d0",
32
+ "@abtnode/static-server": "1.16.14-beta-1936d3d0",
33
+ "@abtnode/timemachine": "1.16.14-beta-1936d3d0",
34
+ "@abtnode/util": "1.16.14-beta-1936d3d0",
35
35
  "@arcblock/did": "1.18.87",
36
36
  "@arcblock/did-auth": "1.18.87",
37
37
  "@arcblock/did-ext": "^1.18.87",
@@ -42,10 +42,10 @@
42
42
  "@arcblock/pm2-events": "^0.0.5",
43
43
  "@arcblock/validator": "^1.18.87",
44
44
  "@arcblock/vc": "1.18.87",
45
- "@blocklet/constant": "1.16.14-beta-0c29907f",
46
- "@blocklet/meta": "1.16.14-beta-0c29907f",
47
- "@blocklet/resolver": "1.16.14-beta-0c29907f",
48
- "@blocklet/sdk": "1.16.14-beta-0c29907f",
45
+ "@blocklet/constant": "1.16.14-beta-1936d3d0",
46
+ "@blocklet/meta": "1.16.14-beta-1936d3d0",
47
+ "@blocklet/resolver": "1.16.14-beta-1936d3d0",
48
+ "@blocklet/sdk": "1.16.14-beta-1936d3d0",
49
49
  "@did-space/client": "^0.2.129",
50
50
  "@fidm/x509": "^1.2.1",
51
51
  "@ocap/mcrypto": "1.18.87",
@@ -76,6 +76,7 @@
76
76
  "node-stream-zip": "^1.15.0",
77
77
  "p-limit": "^3.1.0",
78
78
  "p-retry": "4.6.1",
79
+ "read-last-lines": "^1.8.0",
79
80
  "semver": "^7.3.8",
80
81
  "sequelize": "^6.31.0",
81
82
  "shelljs": "^0.8.5",
@@ -83,6 +84,7 @@
83
84
  "stream-throttle": "^0.1.3",
84
85
  "stream-to-promise": "^3.0.0",
85
86
  "systeminformation": "^5.17.12",
87
+ "tail": "^2.2.4",
86
88
  "tar": "^6.1.11",
87
89
  "transliteration": "^2.3.5",
88
90
  "ua-parser-js": "^1.0.2",
@@ -94,7 +96,8 @@
94
96
  "compression": "^1.7.4",
95
97
  "expand-tilde": "^2.0.2",
96
98
  "express": "^4.18.2",
97
- "jest": "^27.5.1"
99
+ "jest": "^27.5.1",
100
+ "unzipper": "^0.10.11"
98
101
  },
99
- "gitHead": "1f02851a71861dbf09bfedfa9df6d9fc6d2355a3"
102
+ "gitHead": "32bcf5b55889ebd7302887eedd306d331e9cd3b8"
100
103
  }