@abtnode/core 1.16.11-next-069c3537 → 1.16.11-next-a232f5fb

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/api/node.js CHANGED
@@ -83,7 +83,7 @@ class NodeAPI {
83
83
  }
84
84
 
85
85
  deleteCache() {
86
- this.cache.del('del');
86
+ this.cache.del('info');
87
87
  }
88
88
 
89
89
  async getDiskInfo() {
@@ -66,6 +66,7 @@ const {
66
66
  RESTORE_PROGRESS_STATUS,
67
67
  CHAIN_PROP_MAP_REVERSE,
68
68
  } = require('@blocklet/constant');
69
+ const { consumeServerlessNFT, consumeLauncherSession } = require('../../util/launcher');
69
70
  const util = require('../../util');
70
71
  const {
71
72
  refresh: refreshAccessibleExternalNodeIp,
@@ -94,7 +95,6 @@ const {
94
95
  getBlocklet,
95
96
  ensureEnvDefault,
96
97
  getConfigFromPreferences,
97
- consumeServerlessNFT,
98
98
  validateAppConfig,
99
99
  checkDuplicateMountPoint,
100
100
  validateStore,
@@ -2308,14 +2308,22 @@ class BlockletManager extends BaseBlockletManager {
2308
2308
  });
2309
2309
  }
2310
2310
 
2311
- if (blocklet?.controller?.nftId && process.env.NODE_ENV !== 'test') {
2312
- const nodeInfo = await states.node.read();
2313
- await consumeServerlessNFT({ nftId: blocklet.controller.nftId, nodeInfo, blocklet });
2314
- await states.blockletExtras.updateByDid(did, {
2315
- controller: { ...blocklet.controller, consumedAt: new Date().toISOString() },
2316
- });
2311
+ if (blocklet.controller && process.env.NODE_ENV !== 'test') {
2312
+ let isNFTConsumed = false;
2313
+ if (blocklet.controller.launcherSessionId && blocklet.controller.launcherUrl) {
2314
+ await consumeLauncherSession({ params: blocklet.controller, blocklet });
2315
+ isNFTConsumed = true;
2316
+ } else if (blocklet.controller.nftId) {
2317
+ await consumeServerlessNFT({ nftId: blocklet.controller.nftId, blocklet });
2318
+ isNFTConsumed = true;
2319
+ }
2317
2320
 
2318
- this.emit(BlockletEvents.nftConsumed, { blocklet, context });
2321
+ if (isNFTConsumed) {
2322
+ await states.blockletExtras.updateByDid(did, {
2323
+ controller: { ...blocklet.controller, consumedAt: new Date().toISOString() },
2324
+ });
2325
+ this.emit(BlockletEvents.nftConsumed, { blocklet, context });
2326
+ }
2319
2327
  }
2320
2328
 
2321
2329
  if (createNotification) {
@@ -54,9 +54,7 @@ const installApplicationFromGeneral = async ({
54
54
 
55
55
  // check install count
56
56
  if (controller?.nftId) {
57
- // sometimes nedb will throw error if use states.blocklet.count({ ['controller.nftId']: controller.nftId })
58
57
  const installedCount = await states.blockletExtras.count({ 'controller.nftId': controller.nftId });
59
-
60
58
  if (installedCount >= (controller.appMaxCount || 1)) {
61
59
  throw new Error(
62
60
  `You can only install ${controller.appMaxCount} blocklet with this credential: ${controller.nftId}`
@@ -120,7 +118,24 @@ const installApplicationFromGeneral = async ({
120
118
  },
121
119
  ]);
122
120
  } catch (err) {
123
- await manager._rollback('install', did, {});
121
+ const componentDid = component?.meta?.did;
122
+ logger.error('failed to create blocklet extras', { did, componentDid, error: err });
123
+
124
+ try {
125
+ await manager._rollback('install', did, {});
126
+ } catch (e) {
127
+ logger.error('failed to remove blocklet on create extras error', { did, componentDid, error: e });
128
+ }
129
+
130
+ manager._createNotification(did, {
131
+ title: 'Blocklet Install Failed',
132
+ description: `Blocklet ${title || component?.meta?.title} install failed with error: ${err.message}`,
133
+ entityType: 'blocklet',
134
+ entityId: did,
135
+ severity: 'error',
136
+ });
137
+
138
+ throw err;
124
139
  }
125
140
 
126
141
  if (!blocklet.children.length) {
package/lib/index.js CHANGED
@@ -16,6 +16,7 @@ const getRouterHelpers = require('./router/helper');
16
16
  const TeamManager = require('./team/manager');
17
17
  const NodeAPI = require('./api/node');
18
18
  const TeamAPI = require('./api/team');
19
+ const { getLauncherSession, isLauncherSessionConsumed, setupAppOwner } = require('./util/launcher');
19
20
  const WebHook = require('./webhook');
20
21
  const states = require('./states');
21
22
  const Cert = require('./cert');
@@ -250,7 +251,6 @@ function ABTNode(options) {
250
251
  devBlocklet: blockletManager.dev.bind(blockletManager),
251
252
  checkComponentsForUpdates: blockletManager.checkComponentsForUpdates.bind(blockletManager),
252
253
  upgradeComponents: blockletManager.upgradeComponents.bind(blockletManager),
253
- getBlockletMetaFromUrl: getMetaFromUrl.bind(blockletManager),
254
254
  getBlockletForLauncher: blockletManager.getBlockletForLauncher.bind(blockletManager),
255
255
  resetBlocklet: blockletManager.reset.bind(blockletManager),
256
256
  deleteBlockletProcess: blockletManager.deleteProcess.bind(blockletManager),
@@ -462,6 +462,12 @@ function ABTNode(options) {
462
462
 
463
463
  // for exporting blocklet data dir
464
464
  createBlockletDataArchive: createDataArchive,
465
+
466
+ // public utils used in launch workflow
467
+ getBlockletMetaFromUrl: getMetaFromUrl,
468
+ getLauncherSession,
469
+ isLauncherSessionConsumed,
470
+ setupAppOwner,
465
471
  };
466
472
 
467
473
  const events = createEvents({
@@ -226,6 +226,16 @@ class BlockletExtrasState extends BaseState {
226
226
  return docs.filter((x) => x.controller?.nftId).filter((x) => x.expiredAt <= deadline);
227
227
  }
228
228
 
229
+ async isLauncherSessionConsumed(sessionId) {
230
+ const count = await super.count({ 'controller.sessionId': sessionId });
231
+ return count > 0;
232
+ }
233
+
234
+ async isLauncherNftConsumed(nftId) {
235
+ const count = await super.count({ 'controller.nftId': nftId });
236
+ return count > 0;
237
+ }
238
+
229
239
  encryptSecurityData({ data, _rootDid } = {}) {
230
240
  if (!data) {
231
241
  return data;
@@ -3,10 +3,8 @@
3
3
  const fs = require('fs-extra');
4
4
  const path = require('path');
5
5
  const dayjs = require('dayjs');
6
- const joinURL = require('url-join');
7
6
  const shelljs = require('shelljs');
8
7
  const os = require('os');
9
- const pRetry = require('p-retry');
10
8
  const tar = require('tar');
11
9
  const get = require('lodash/get');
12
10
  const uniq = require('lodash/uniq');
@@ -19,19 +17,16 @@ const diff = require('deep-diff');
19
17
  const createArchive = require('archiver');
20
18
  const isUrl = require('is-url');
21
19
  const semver = require('semver');
22
- const axios = require('@abtnode/util/lib/axios');
23
- const { stableStringify } = require('@arcblock/vc');
24
20
  const { chainInfo: chainInfoSchema } = require('@arcblock/did-auth/lib/schema');
25
21
 
26
22
  const { fromSecretKey } = require('@ocap/wallet');
27
- const { toHex, toBase58, isHex, toDid, toAddress } = require('@ocap/util');
23
+ const { toHex, isHex, toDid, toAddress } = require('@ocap/util');
28
24
  const { isValid: isValidDid, isEthereumDid } = require('@arcblock/did');
29
25
  const logger = require('@abtnode/logger')('@abtnode/core:util:blocklet');
30
26
  const pm2 = require('@abtnode/util/lib/async-pm2');
31
27
  const sleep = require('@abtnode/util/lib/sleep');
32
28
  const getPm2ProcessInfo = require('@abtnode/util/lib/get-pm2-process-info');
33
29
  const killProcessOccupiedPorts = require('@abtnode/util/lib/kill-process-occupied-ports');
34
- const getNodeWallet = require('@abtnode/util/lib/get-app-wallet');
35
30
  const { formatEnv } = require('@abtnode/util/lib/security');
36
31
  const ensureEndpointHealthy = require('@abtnode/util/lib/ensure-endpoint-healthy');
37
32
  const CustomError = require('@abtnode/util/lib/custom-error');
@@ -100,7 +95,7 @@ const { validate: validateEngine, get: getEngine } = require('../blocklet/manage
100
95
 
101
96
  const isRequirementsSatisfied = require('./requirement');
102
97
  const { getDidDomainForBlocklet } = require('./get-domain-for-blocklet');
103
- const { expandBundle, findInterfacePortByName, prettyURL, getNFTState, templateReplace } = require('./index');
98
+ const { expandBundle, findInterfacePortByName, prettyURL, templateReplace } = require('./index');
104
99
  const externalIpUtil = require('./get-accessible-external-node-ip');
105
100
  const { getIpDnsDomainForBlocklet } = require('./get-domain-for-blocklet');
106
101
  const { replaceDomainSlot } = require('./index');
@@ -1538,51 +1533,6 @@ const getBlockletURLForLauncher = async ({ blocklet, nodeInfo }) => {
1538
1533
  const didDomain = getDidDomainForBlocklet({ appPid: blocklet.appPid, didDomain: nodeInfo.didDomain });
1539
1534
  return `https://${didDomain}`;
1540
1535
  };
1541
-
1542
- const consumeServerlessNFT = async ({ nftId, nodeInfo, blocklet }) => {
1543
- try {
1544
- const state = await getNFTState(blocklet.controller.chainHost, nftId);
1545
- if (!state) {
1546
- throw new Error(`get nft state failed, chainHost: ${blocklet.controller.chainHost}, nftId: ${nftId}`);
1547
- }
1548
-
1549
- const appURL = await getBlockletURLForLauncher({ blocklet, nodeInfo });
1550
-
1551
- logger.info('app url when consuming nft', { appURL, nftId });
1552
-
1553
- const body = { nftId, appURL };
1554
-
1555
- const { launcherUrl } = state.data.value;
1556
-
1557
- const wallet = getNodeWallet(nodeInfo.sk);
1558
- const func = async () => {
1559
- const { data } = await axios.post(joinURL(launcherUrl, '/api/serverless/consume'), body, {
1560
- headers: {
1561
- 'x-sig': toBase58(wallet.sign(stableStringify(body))),
1562
- },
1563
- });
1564
-
1565
- return data;
1566
- };
1567
-
1568
- const delay = 10 * 1000;
1569
- const result = await pRetry(func, {
1570
- retries: 3,
1571
- minTimeout: delay,
1572
- maxTimeout: delay,
1573
- onFailedAttempt: (error) => {
1574
- logger.error(`attempt consume nft ${nftId} failed`, { error });
1575
- },
1576
- });
1577
-
1578
- logger.info('consume serverless nft success', { nftId, hash: result.hash });
1579
- } catch (error) {
1580
- logger.error('consume serverless nft failed', { nftId, error });
1581
-
1582
- throw new Error(`consume nft ${nftId} failed`);
1583
- }
1584
- };
1585
-
1586
1536
  const createDataArchive = (dataDir, fileName) => {
1587
1537
  const zipPath = path.join(os.tmpdir(), fileName);
1588
1538
  if (fs.existsSync(zipPath)) {
@@ -1958,7 +1908,6 @@ const shouldCleanExpiredBlocklet = (expirationDate) => {
1958
1908
 
1959
1909
  module.exports = {
1960
1910
  updateBlockletFallbackLogo,
1961
- consumeServerlessNFT,
1962
1911
  forEachBlocklet,
1963
1912
  getBlockletMetaFromUrl: (url) => getBlockletMetaFromUrl(url, { logger }),
1964
1913
  parseComponents,
@@ -0,0 +1,237 @@
1
+ const path = require('path');
2
+ const fs = require('fs-extra');
3
+ const joinUrl = require('url-join');
4
+ const pick = require('lodash/pick');
5
+ const joinURL = require('url-join');
6
+ const { parseUserAvatar, extractUserAvatar, getAvatarFile, getAvatarByUrl } = require('@abtnode/util/lib/user');
7
+ const { Hasher } = require('@ocap/mcrypto');
8
+ const { getDisplayName } = require('@blocklet/meta/lib/util');
9
+ const getBlockletInfo = require('@blocklet/meta/lib/info');
10
+
11
+ const { getLauncherUser, getLauncherSession: getLauncherSessionRaw, doRequest } = require('@abtnode/auth/lib/launcher');
12
+ const { createAuthToken, getPassportStatusEndpoint } = require('@abtnode/auth/lib/auth');
13
+ const { createPassportVC, createPassport, createUserPassport } = require('@abtnode/auth/lib/passport');
14
+
15
+ const { BlockletStatus } = require('@blocklet/constant');
16
+ const {
17
+ WELLKNOWN_SERVICE_PATH_PREFIX,
18
+ NODE_DATA_DIR_NAME,
19
+ USER_AVATAR_URL_PREFIX,
20
+ ROLES,
21
+ } = require('@abtnode/constant');
22
+
23
+ const logger = require('@abtnode/logger')('@abtnode/core:util:launcher');
24
+
25
+ const { getNFTState } = require('./index');
26
+ const { getBlockletURLForLauncher } = require('./blocklet');
27
+ const states = require('../states');
28
+
29
+ const consumeServerlessNFT = async ({ nftId, blocklet }) => {
30
+ try {
31
+ const state = await getNFTState(blocklet.controller.chainHost, nftId);
32
+ if (!state) {
33
+ throw new Error(`Get nft state failed, chainHost: ${blocklet.controller.chainHost}, nftId: ${nftId}`);
34
+ }
35
+
36
+ const nodeInfo = await states.node.read();
37
+ const appURL = await getBlockletURLForLauncher({ blocklet, nodeInfo });
38
+ logger.info('Consuming serverless nft params', { appURL, nftId });
39
+
40
+ const { launcherUrl } = state.data.value;
41
+ const result = await doRequest(nodeInfo.sk, {
42
+ launcherUrl,
43
+ pathname: '/api/serverless/consume',
44
+ payload: { nftId, appURL },
45
+ method: 'post',
46
+ });
47
+
48
+ logger.info('Consume serverless nft success', { nftId, hash: result.hash });
49
+ } catch (error) {
50
+ logger.error('Consume serverless nft failed', { nftId, error });
51
+ throw new Error(`consume nft ${nftId} failed`);
52
+ }
53
+ };
54
+
55
+ const consumeLauncherSession = async ({ params, blocklet }) => {
56
+ try {
57
+ const info = await states.node.read();
58
+ const { appUrl, name } = getBlockletInfo(blocklet, info.sk);
59
+ const result = await doRequest(info.sk, {
60
+ launcherUrl: params.launcherUrl,
61
+ pathname: `/api/launches/${params.launcherSessionId}/installed`,
62
+ payload: { appDid: blocklet.appPid, appUrl, appName: name, ownerDid: params.ownerDid },
63
+ method: 'post',
64
+ });
65
+
66
+ logger.info('Consume launcher session success', { params, result });
67
+ } catch (error) {
68
+ logger.error('Consume launcher session failed', { params, error });
69
+ throw new Error(`Consume launcher session ${params.launcherSessionId} failed`);
70
+ }
71
+ };
72
+
73
+ const setupAppOwner = async (node, sessionId) => {
74
+ const session = await node.getSession({ id: sessionId });
75
+ if (!session) {
76
+ throw new Error(`Blocklet setup session not found in server: ${sessionId}`);
77
+ }
78
+
79
+ const { appDid, userDid, ownerDid, ownerPk, lastLoginIp, context, locale, launcherUrl, launcherSessionId } = session;
80
+ const [info, blocklet] = await Promise.all([states.node.read(), states.blocklet.getBlocklet(appDid)]);
81
+ if (!blocklet) {
82
+ throw new Error(`Blocklet not found in server: ${appDid}`);
83
+ }
84
+ if (blocklet.status !== BlockletStatus.installed) {
85
+ throw new Error(`Blocklet status not expected: ${appDid}`);
86
+ }
87
+
88
+ const { wallet } = getBlockletInfo(blocklet, info.sk);
89
+ const appUrl = blocklet.environments.find((x) => x.key === 'BLOCKLET_APP_URL').value;
90
+ const dataDir = blocklet.environments.find((x) => x.key === 'BLOCKLET_DATA_DIR').value;
91
+ const serverDataDir = path.join(node.dataDirs.data, NODE_DATA_DIR_NAME);
92
+
93
+ let user;
94
+ let appOwnerProfile;
95
+ // get user from launcher or server
96
+ if (launcherUrl && launcherSessionId) {
97
+ user = await getLauncherUser(info.sk, { launcherUrl, launcherSessionId });
98
+ if (!user) {
99
+ throw new Error(`Owner user not found from launcher: ${launcherUrl}`);
100
+ }
101
+ appOwnerProfile = pick(user, ['fullName', 'email', 'avatar']);
102
+ const avatarBase64 = await getAvatarByUrl(joinURL(launcherUrl, user.avatar));
103
+ appOwnerProfile.avatar = await extractUserAvatar(avatarBase64, { dataDir });
104
+ logger.info('Create owner from launcher for blocklet', { appDid, ownerDid, ownerPk, sessionId, appOwnerProfile });
105
+ } else {
106
+ user = await node.getUser({ teamDid: info.did, user: { did: userDid } });
107
+ if (!user) {
108
+ throw new Error(`Owner user not found in server: ${userDid}`);
109
+ }
110
+ appOwnerProfile = pick(user, ['fullName', 'email', 'avatar']);
111
+ if (user.avatar && user.avatar.startsWith(USER_AVATAR_URL_PREFIX)) {
112
+ const filename = user.avatar.split('/').pop();
113
+ const srcFile = getAvatarFile(serverDataDir, filename);
114
+ const destFile = getAvatarFile(dataDir, filename);
115
+ fs.mkdirpSync(path.dirname(destFile));
116
+ fs.copyFileSync(srcFile, destFile);
117
+ } else {
118
+ appOwnerProfile.avatar = extractUserAvatar(user.avatar, { dataDir });
119
+ }
120
+ logger.info('Create owner from session for blocklet', { appDid, ownerDid, ownerPk, sessionId, appOwnerProfile });
121
+ }
122
+
123
+ // create and send owner passport
124
+ const role = ROLES.OWNER;
125
+ const vc = createPassportVC({
126
+ issuerName: getDisplayName(blocklet),
127
+ issuerWallet: wallet,
128
+ ownerDid,
129
+ passport: await createPassport({
130
+ name: role,
131
+ node,
132
+ teamDid: appDid,
133
+ locale,
134
+ endpoint: appUrl,
135
+ }),
136
+ endpoint: getPassportStatusEndpoint({
137
+ baseUrl: joinUrl(appUrl, WELLKNOWN_SERVICE_PATH_PREFIX),
138
+ userDid: ownerDid,
139
+ teamDid: appDid,
140
+ }),
141
+ ownerProfile: { ...appOwnerProfile, avatar: parseUserAvatar(user.avatar, { dataDir: serverDataDir }) },
142
+ preferredColor: 'default',
143
+ expirationDate: undefined,
144
+ });
145
+
146
+ // create app owner passport
147
+ const passport = createUserPassport(vc, { role });
148
+
149
+ // add app owner to database
150
+ const doc = await node.loginUser({
151
+ teamDid: appDid,
152
+ user: {
153
+ ...appOwnerProfile,
154
+ did: ownerDid,
155
+ pk: ownerPk,
156
+ passport,
157
+ locale,
158
+ lastLoginIp,
159
+ connectedAccount: {
160
+ provider: 'wallet',
161
+ did: ownerDid,
162
+ pk: ownerPk,
163
+ },
164
+ },
165
+ });
166
+ await node.createAuditLog(
167
+ {
168
+ action: 'addUser',
169
+ args: { teamDid: appDid, userDid: ownerDid, reason: 'launch blocklet' },
170
+ context: { ...context, user: doc },
171
+ result: doc,
172
+ },
173
+ node
174
+ );
175
+ logger.info('Create owner for blocklet', { appDid, ownerDid, sessionId });
176
+
177
+ // create owner login token that can be used to login on blocklet site
178
+ const appSecret = Hasher.SHA3.hash256(Buffer.concat([wallet.secretKey, wallet.address].map(Buffer.from)));
179
+ const setupToken = createAuthToken({
180
+ did: ownerDid,
181
+ passport,
182
+ role,
183
+ secret: appSecret,
184
+ expiresIn: '7d',
185
+ });
186
+
187
+ await node.endSession({ id: sessionId });
188
+ logger.info('Complete install for blocklet', { appDid, ownerDid, sessionId });
189
+
190
+ return {
191
+ session,
192
+ blocklet,
193
+ setupToken,
194
+ passport: vc,
195
+ };
196
+ };
197
+
198
+ const getLauncherSession = async ({ launcherUrl, launcherSessionId, external = true }) => {
199
+ const info = await states.node.read();
200
+ const result = await getLauncherSessionRaw(info.sk, { launcherUrl, launcherSessionId });
201
+
202
+ // strip sensitive data if call from external
203
+ if (external && result.launcherSession) {
204
+ result.launcherSession = pick(result.launcherSession, ['_id', 'status']);
205
+ }
206
+
207
+ return result;
208
+ };
209
+
210
+ // Check local first, then remote, FIXME: @wangshijun should we check on chain nft?
211
+ const isLauncherSessionConsumed = async (params) => {
212
+ let consumed = await states.blockletExtras.isLauncherSessionConsumed(params.launcherSessionId);
213
+ logger.info('Launcher session consumed at local?', { params, consumed });
214
+ if (consumed) {
215
+ return true;
216
+ }
217
+
218
+ const { error, launcherSession } = await getLauncherSession(params);
219
+ if (error) {
220
+ throw new Error(error);
221
+ }
222
+ if (!launcherSession) {
223
+ throw new Error('Launcher session not found');
224
+ }
225
+
226
+ consumed = launcherSession.status > 40;
227
+ logger.info('Launcher session consumed at remote?', { params, consumed });
228
+ return consumed;
229
+ };
230
+
231
+ module.exports = {
232
+ consumeServerlessNFT,
233
+ consumeLauncherSession,
234
+ setupAppOwner,
235
+ getLauncherSession,
236
+ isLauncherSessionConsumed,
237
+ };
@@ -15,6 +15,9 @@ const blockletController = Joi.object({
15
15
  nftOwner: Joi.DID().required(),
16
16
  chainHost: Joi.string().uri().required(),
17
17
  appMaxCount: Joi.number().required().min(1),
18
+ launcherUrl: Joi.string().uri().optional(),
19
+ launcherSessionId: Joi.string().optional(),
20
+ ownerDid: Joi.DID().optional(),
18
21
  }).options({ stripUnknown: true });
19
22
 
20
23
  const createValidator = (schema) => (entity) => schema.validateAsync(entity);
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.16.11-next-069c3537",
6
+ "version": "1.16.11-next-a232f5fb",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,18 +19,18 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "Apache-2.0",
21
21
  "dependencies": {
22
- "@abtnode/auth": "1.16.11-next-069c3537",
23
- "@abtnode/certificate-manager": "1.16.11-next-069c3537",
24
- "@abtnode/constant": "1.16.11-next-069c3537",
25
- "@abtnode/cron": "1.16.11-next-069c3537",
26
- "@abtnode/logger": "1.16.11-next-069c3537",
27
- "@abtnode/models": "1.16.11-next-069c3537",
28
- "@abtnode/queue": "1.16.11-next-069c3537",
29
- "@abtnode/rbac": "1.16.11-next-069c3537",
30
- "@abtnode/router-provider": "1.16.11-next-069c3537",
31
- "@abtnode/static-server": "1.16.11-next-069c3537",
32
- "@abtnode/timemachine": "1.16.11-next-069c3537",
33
- "@abtnode/util": "1.16.11-next-069c3537",
22
+ "@abtnode/auth": "1.16.11-next-a232f5fb",
23
+ "@abtnode/certificate-manager": "1.16.11-next-a232f5fb",
24
+ "@abtnode/constant": "1.16.11-next-a232f5fb",
25
+ "@abtnode/cron": "1.16.11-next-a232f5fb",
26
+ "@abtnode/logger": "1.16.11-next-a232f5fb",
27
+ "@abtnode/models": "1.16.11-next-a232f5fb",
28
+ "@abtnode/queue": "1.16.11-next-a232f5fb",
29
+ "@abtnode/rbac": "1.16.11-next-a232f5fb",
30
+ "@abtnode/router-provider": "1.16.11-next-a232f5fb",
31
+ "@abtnode/static-server": "1.16.11-next-a232f5fb",
32
+ "@abtnode/timemachine": "1.16.11-next-a232f5fb",
33
+ "@abtnode/util": "1.16.11-next-a232f5fb",
34
34
  "@arcblock/did": "1.18.80",
35
35
  "@arcblock/did-auth": "1.18.80",
36
36
  "@arcblock/did-ext": "^1.18.80",
@@ -41,10 +41,10 @@
41
41
  "@arcblock/pm2-events": "^0.0.5",
42
42
  "@arcblock/validator": "^1.18.80",
43
43
  "@arcblock/vc": "1.18.80",
44
- "@blocklet/constant": "1.16.11-next-069c3537",
45
- "@blocklet/meta": "1.16.11-next-069c3537",
46
- "@blocklet/sdk": "1.16.11-next-069c3537",
47
- "@did-space/client": "^0.2.99",
44
+ "@blocklet/constant": "1.16.11-next-a232f5fb",
45
+ "@blocklet/meta": "1.16.11-next-a232f5fb",
46
+ "@blocklet/sdk": "1.16.11-next-a232f5fb",
47
+ "@did-space/client": "^0.2.112",
48
48
  "@fidm/x509": "^1.2.1",
49
49
  "@ocap/mcrypto": "1.18.80",
50
50
  "@ocap/util": "1.18.80",
@@ -96,5 +96,5 @@
96
96
  "express": "^4.18.2",
97
97
  "jest": "^27.5.1"
98
98
  },
99
- "gitHead": "680dafcd7c2d446013abf25a370b8cfb70bfa7eb"
99
+ "gitHead": "1af264e9b6648aa191fbf23c67717262ac717697"
100
100
  }