@abtnode/core 1.8.61 → 1.8.63-beta-c51e554d
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/team.js +7 -1
- package/lib/blocklet/extras.js +15 -0
- package/lib/blocklet/manager/disk.js +43 -15
- package/lib/blocklet/manager/helper/install-from-backup.js +160 -0
- package/lib/router/helper.js +30 -3
- package/lib/router/manager.js +40 -22
- package/lib/states/blocklet-extras.js +29 -1
- package/lib/util/blocklet.js +111 -68
- package/lib/validators/router.js +2 -2
- package/package.json +17 -17
package/lib/api/team.js
CHANGED
|
@@ -595,7 +595,13 @@ class TeamAPI extends EventEmitter {
|
|
|
595
595
|
async getPassportIssuances({ teamDid, ownerDid }) {
|
|
596
596
|
const state = await this.getSessionState(teamDid);
|
|
597
597
|
|
|
598
|
-
const
|
|
598
|
+
const query = { type: 'passport-issuance' };
|
|
599
|
+
|
|
600
|
+
if (ownerDid) {
|
|
601
|
+
query.ownerDid = ownerDid;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
const list = await state.find(query);
|
|
599
605
|
|
|
600
606
|
return list.map((d) => ({
|
|
601
607
|
// eslint-disable-next-line no-underscore-dangle
|
package/lib/blocklet/extras.js
CHANGED
|
@@ -146,7 +146,22 @@ const parseConfigs = ({ data, did, dek }) => {
|
|
|
146
146
|
return data;
|
|
147
147
|
};
|
|
148
148
|
|
|
149
|
+
const encryptConfigs = ({ data, did, dek }) => {
|
|
150
|
+
const enableSecurity = dek && did;
|
|
151
|
+
|
|
152
|
+
if (enableSecurity && Array.isArray(data)) {
|
|
153
|
+
data.forEach((x) => {
|
|
154
|
+
if (x.secure) {
|
|
155
|
+
x.value = security.encrypt(x.value, did, dek);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return data;
|
|
161
|
+
};
|
|
162
|
+
|
|
149
163
|
module.exports = {
|
|
150
164
|
mergeConfigs,
|
|
151
165
|
parseConfigs,
|
|
166
|
+
encryptConfigs,
|
|
152
167
|
};
|
|
@@ -31,6 +31,7 @@ const {
|
|
|
31
31
|
WHO_CAN_ACCESS,
|
|
32
32
|
SERVER_ROLES,
|
|
33
33
|
WHO_CAN_ACCESS_PREFIX_ROLES,
|
|
34
|
+
BLOCKLET_INSTALL_TYPE,
|
|
34
35
|
} = require('@abtnode/constant');
|
|
35
36
|
|
|
36
37
|
const getBlockletEngine = require('@blocklet/meta/lib/engine');
|
|
@@ -104,7 +105,7 @@ const {
|
|
|
104
105
|
getDiskInfo,
|
|
105
106
|
getUpdateMetaList,
|
|
106
107
|
getRuntimeEnvironments,
|
|
107
|
-
|
|
108
|
+
getTypeFromInstallParams,
|
|
108
109
|
parseChildrenFromMeta,
|
|
109
110
|
checkDuplicateComponents,
|
|
110
111
|
getDiffFiles,
|
|
@@ -118,6 +119,7 @@ const {
|
|
|
118
119
|
consumeServerlessNFT,
|
|
119
120
|
validateAppConfig,
|
|
120
121
|
checkDuplicateAppSk,
|
|
122
|
+
checkDuplicateMountPoint,
|
|
121
123
|
} = require('../../util/blocklet');
|
|
122
124
|
const StoreUtil = require('../../util/store');
|
|
123
125
|
const states = require('../../states');
|
|
@@ -132,6 +134,7 @@ const handleInstanceInStore = require('../../util/public-to-store');
|
|
|
132
134
|
const { getNFTState, getServerDidDomain } = require('../../util');
|
|
133
135
|
const { BlockletRuntimeMonitor } = require('../../monitor/blocklet-runtime-monitor');
|
|
134
136
|
const getHistoryList = require('../../monitor/get-history-list');
|
|
137
|
+
const installFromBackup = require('./helper/install-from-backup');
|
|
135
138
|
|
|
136
139
|
const {
|
|
137
140
|
isInProgress,
|
|
@@ -252,6 +255,7 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
252
255
|
* downloadTokenList: Array<{did: string, token: string}>;
|
|
253
256
|
* startImmediately: boolean;
|
|
254
257
|
* controller: Controller
|
|
258
|
+
* type: BLOCKLET_INSTALL_TYPE
|
|
255
259
|
* }} params
|
|
256
260
|
* @param {{
|
|
257
261
|
* [key: string]: any
|
|
@@ -273,32 +277,37 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
273
277
|
});
|
|
274
278
|
context.downloadTokenList = params.downloadTokenList || [];
|
|
275
279
|
|
|
276
|
-
const
|
|
280
|
+
const type = getTypeFromInstallParams(params);
|
|
277
281
|
if (typeof context.startImmediately === 'undefined') {
|
|
278
282
|
context.startImmediately = !!params.startImmediately;
|
|
279
283
|
}
|
|
280
284
|
|
|
281
|
-
if (
|
|
285
|
+
if (type === BLOCKLET_INSTALL_TYPE.URL) {
|
|
282
286
|
const { url, controller, sync, delay } = params;
|
|
283
287
|
return this._installFromUrl({ url, controller, sync, delay }, context);
|
|
284
288
|
}
|
|
285
289
|
|
|
286
|
-
if (
|
|
290
|
+
if (type === BLOCKLET_INSTALL_TYPE.UPLOAD) {
|
|
287
291
|
const { file, did, diffVersion, deleteSet } = params;
|
|
288
292
|
return this._installFromUpload({ file, did, diffVersion, deleteSet, context });
|
|
289
293
|
}
|
|
290
294
|
|
|
291
|
-
if (
|
|
295
|
+
if (type === BLOCKLET_INSTALL_TYPE.STORE) {
|
|
292
296
|
const { did, controller, sync, delay, storeUrl } = params;
|
|
293
297
|
return this._installFromStore({ did, controller, sync, delay, storeUrl }, context);
|
|
294
298
|
}
|
|
295
299
|
|
|
296
|
-
if (
|
|
300
|
+
if (type === BLOCKLET_INSTALL_TYPE.CREATE) {
|
|
297
301
|
return this._installFromCreate({ title: params.title, description: params.description }, context);
|
|
298
302
|
}
|
|
299
303
|
|
|
304
|
+
if (type === BLOCKLET_INSTALL_TYPE.RESTORE) {
|
|
305
|
+
const { url, blockletSecretKey } = params;
|
|
306
|
+
return this._installFromBackup({ url, blockletSecretKey }, context);
|
|
307
|
+
}
|
|
308
|
+
|
|
300
309
|
// should not be here
|
|
301
|
-
throw new Error('Unknown
|
|
310
|
+
throw new Error('Unknown type');
|
|
302
311
|
}
|
|
303
312
|
|
|
304
313
|
/**
|
|
@@ -1144,20 +1153,26 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1144
1153
|
}
|
|
1145
1154
|
|
|
1146
1155
|
const rootDid = blocklet.meta.did;
|
|
1156
|
+
const isRootComponent = !did;
|
|
1147
1157
|
|
|
1148
|
-
const
|
|
1149
|
-
const component = children.find((x) => x.meta.did === did);
|
|
1150
|
-
|
|
1158
|
+
const component = isRootComponent ? blocklet : blocklet.children.find((x) => x.meta.did === did);
|
|
1151
1159
|
if (!component) {
|
|
1152
1160
|
throw new Error('component does not exist');
|
|
1153
1161
|
}
|
|
1154
1162
|
|
|
1155
|
-
if (!component.dynamic) {
|
|
1163
|
+
if (!isRootComponent && !component.dynamic) {
|
|
1156
1164
|
throw new Error('cannot update mountPoint of non-dynamic component');
|
|
1157
1165
|
}
|
|
1158
1166
|
|
|
1167
|
+
if (isRootComponent && component.group === BlockletGroup.gateway) {
|
|
1168
|
+
throw new Error('cannot update mountPoint of gateway blocklet');
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
checkDuplicateMountPoint(blocklet, mountPoint);
|
|
1172
|
+
|
|
1159
1173
|
component.mountPoint = mountPoint;
|
|
1160
|
-
|
|
1174
|
+
|
|
1175
|
+
await states.blocklet.updateBlocklet(rootDid, { mountPoint: blocklet.mountPoint, children: blocklet.children });
|
|
1161
1176
|
|
|
1162
1177
|
this.emit(BlockletEvents.upgraded, { blocklet, context: { ...context, createAuditLog: false } }); // trigger router refresh
|
|
1163
1178
|
|
|
@@ -1594,6 +1609,19 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1594
1609
|
return blocklet;
|
|
1595
1610
|
}
|
|
1596
1611
|
|
|
1612
|
+
/**
|
|
1613
|
+
* backup 目录结构
|
|
1614
|
+
* /blocklets/<name1>version>
|
|
1615
|
+
* /blocklets/<name2>version>
|
|
1616
|
+
* /blocklets/<name3>version>
|
|
1617
|
+
* /data
|
|
1618
|
+
* /blocklet.json
|
|
1619
|
+
* /blocklet_extras.json
|
|
1620
|
+
*/
|
|
1621
|
+
async _installFromBackup({ url, blockletSecretKey, moveDir } = {}, context = {}) {
|
|
1622
|
+
return installFromBackup({ url, blockletSecretKey, moveDir, context, manager: this, states });
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1597
1625
|
async ensureBlocklet(did, opts = {}) {
|
|
1598
1626
|
return getBlocklet({ ...opts, states, dataDirs: this.dataDirs, did });
|
|
1599
1627
|
}
|
|
@@ -1698,10 +1726,10 @@ class BlockletManager extends BaseBlockletManager {
|
|
|
1698
1726
|
}));
|
|
1699
1727
|
}
|
|
1700
1728
|
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
blocklet.appRuntimeInfo = this.runtimeMonitor.getRuntimeInfo(blocklet.meta.did);
|
|
1729
|
+
// app runtime info, app status
|
|
1730
|
+
blocklet.appRuntimeInfo = this.runtimeMonitor.getRuntimeInfo(blocklet.meta.did);
|
|
1704
1731
|
|
|
1732
|
+
if (!fromCache) {
|
|
1705
1733
|
// app disk info, component runtime info, component status, component engine
|
|
1706
1734
|
await forEachBlocklet(blocklet, async (component, { level }) => {
|
|
1707
1735
|
component.engine = getEngine(getBlockletEngineNameByPlatform(component.meta)).describe();
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const omit = require('lodash/omit');
|
|
4
|
+
|
|
5
|
+
const { forEachBlockletSync } = require('@blocklet/meta/lib/util');
|
|
6
|
+
const getBlockletInfo = require('@blocklet/meta/lib/info');
|
|
7
|
+
|
|
8
|
+
const { BLOCKLET_CONFIGURABLE_KEY } = require('@blocklet/constant');
|
|
9
|
+
|
|
10
|
+
const logger = require('@abtnode/logger')('@abtnode/core:install-from-backup');
|
|
11
|
+
|
|
12
|
+
const { validateBlocklet, checkDuplicateAppSk, getAppDirs } = require('../../../util/blocklet');
|
|
13
|
+
|
|
14
|
+
module.exports = async ({ url, blockletSecretKey, moveDir, context = {}, states, manager } = {}) => {
|
|
15
|
+
// TODO: support more url schema feature (http, did-spaces)
|
|
16
|
+
if (!url.startsWith('file://')) {
|
|
17
|
+
throw new Error('url must starts with file://');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const dir = url.replace('file://', '');
|
|
21
|
+
|
|
22
|
+
if (!dir || !fs.existsSync(dir)) {
|
|
23
|
+
throw new Error(`dir(${dir}) does not exist`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// parse data from source dir
|
|
27
|
+
|
|
28
|
+
const srcBundleDirs = await getAppDirs(path.join(dir, 'blocklets'));
|
|
29
|
+
if (!srcBundleDirs.length) {
|
|
30
|
+
throw new Error(`bundle dirs does not found in ${dir}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const srcDataDir = path.join(dir, 'data');
|
|
34
|
+
|
|
35
|
+
/** @type {import('@abtnode/client').BlockletState} */
|
|
36
|
+
const state = omit(fs.readJSONSync(path.join(dir, 'blocklet.json')), [
|
|
37
|
+
'_id',
|
|
38
|
+
'createdAt',
|
|
39
|
+
'updatedAt',
|
|
40
|
+
'installedAt',
|
|
41
|
+
'startedAt',
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
const extra = omit(fs.readJSONSync(path.join(dir, 'blocklet-extras.json')), ['_id', 'createdAt', 'updatedAt']);
|
|
45
|
+
|
|
46
|
+
if (state.meta.did !== extra.did) {
|
|
47
|
+
throw new Error('did does not match in blocklet.json and blocklet_extra.json');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
forEachBlockletSync(state, (component) => {
|
|
51
|
+
delete component.status;
|
|
52
|
+
delete component.ports;
|
|
53
|
+
delete component.environments;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const { meta } = state;
|
|
57
|
+
|
|
58
|
+
await validateBlocklet({ meta });
|
|
59
|
+
|
|
60
|
+
const { did, name: appName } = meta;
|
|
61
|
+
|
|
62
|
+
// FIXME: meta.did and meta.name should be dynamic created when installing multiple blocklet is supported
|
|
63
|
+
const existState = await states.blocklet.hasBlocklet(did);
|
|
64
|
+
if (existState) {
|
|
65
|
+
logger.error('blocklet is already exist', { did });
|
|
66
|
+
throw new Error('blocklet is already exist');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (blockletSecretKey) {
|
|
70
|
+
extra.configs = extra.configs || [];
|
|
71
|
+
const skConfig = extra.configs.find((x) => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK);
|
|
72
|
+
if (skConfig) {
|
|
73
|
+
skConfig.value = blockletSecretKey;
|
|
74
|
+
} else {
|
|
75
|
+
extra.configs.push({
|
|
76
|
+
key: BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK,
|
|
77
|
+
value: blockletSecretKey,
|
|
78
|
+
secure: true,
|
|
79
|
+
shared: false,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// validate appDid
|
|
85
|
+
const nodeInfo = await states.node.read();
|
|
86
|
+
const { wallet } = getBlockletInfo({ meta: state.meta, configs: extra.configs, environments: [] }, nodeInfo.sk);
|
|
87
|
+
if (state.appDid !== wallet.address) {
|
|
88
|
+
throw new Error('blocklet appDid is different from the previous one');
|
|
89
|
+
}
|
|
90
|
+
await checkDuplicateAppSk({ sk: wallet.secretKey, states });
|
|
91
|
+
|
|
92
|
+
states.blockletExtras.encryptSecurityData({ data: extra, rootDid: extra.did });
|
|
93
|
+
|
|
94
|
+
logger.info('installFromBackup', { srcBundleDirs, srcDataDir });
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
// copy extra
|
|
98
|
+
const existExtra = await states.blockletExtras.find({ did });
|
|
99
|
+
if (existExtra) {
|
|
100
|
+
// 如果数据存在, 当前视为脏数据, 直接删除
|
|
101
|
+
// FIXME 另一个人的数据可能被删除. 修复方式: 动态生成 meta.did 或通过 blocklet sk 生成 meta.did
|
|
102
|
+
// FIXME 简单粗暴的删掉数据可能不是理想的方式,需要考虑旧数据存在时, 如何与新数据 merge
|
|
103
|
+
logger.error('old extra state exists and will be force removed', { existExtra });
|
|
104
|
+
await states.blockletExtras.remove({ did });
|
|
105
|
+
}
|
|
106
|
+
await states.blockletExtras.insert(extra);
|
|
107
|
+
logger.info('blocklet extra is copied successfully');
|
|
108
|
+
|
|
109
|
+
// add blocklet
|
|
110
|
+
await states.blocklet.addBlocklet(state);
|
|
111
|
+
logger.info('blocklet state is added successfully');
|
|
112
|
+
|
|
113
|
+
// copy bundle
|
|
114
|
+
// 假设相同名称的应用,肯定是同一个应用
|
|
115
|
+
// 假设版本号相同时, 应用不会变更
|
|
116
|
+
// FIXME: blocklet bundle name/did 不是唯一的. 修改 blocklet bundle name/did 生成方式 使 name/bundle 唯一
|
|
117
|
+
await Promise.all(
|
|
118
|
+
srcBundleDirs.map(async ({ key: bundleName, dir: srcDir }) => {
|
|
119
|
+
const installDir = path.join(manager.dataDirs.blocklets, bundleName);
|
|
120
|
+
if (fs.existsSync(installDir)) {
|
|
121
|
+
logger.info(`${bundleName} is already exist`);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
fs.mkdirSync(installDir, { recursive: true });
|
|
126
|
+
if (moveDir) {
|
|
127
|
+
await fs.move(srcDir, installDir, { overwrite: true });
|
|
128
|
+
} else {
|
|
129
|
+
await fs.copy(srcDir, installDir);
|
|
130
|
+
}
|
|
131
|
+
logger.info(`bundle is ${moveDir ? 'moved' : 'copied'} successfully`, { installDir });
|
|
132
|
+
})
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// FIXME same as copy extra
|
|
136
|
+
const dataDir = path.join(manager.dataDirs.data, appName);
|
|
137
|
+
if (fs.existsSync(dataDir)) {
|
|
138
|
+
logger.error('old data exists and will be force removed', { dataDir });
|
|
139
|
+
await fs.remove(dataDir);
|
|
140
|
+
}
|
|
141
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
142
|
+
if (fs.existsSync(srcDataDir)) {
|
|
143
|
+
if (moveDir) {
|
|
144
|
+
await fs.move(srcDataDir, dataDir, { overwrite: true });
|
|
145
|
+
} else {
|
|
146
|
+
await fs.copy(srcDataDir, dataDir);
|
|
147
|
+
}
|
|
148
|
+
logger.info(`data is ${moveDir ? 'moved' : 'copied'} successfully`);
|
|
149
|
+
}
|
|
150
|
+
} catch (error) {
|
|
151
|
+
logger.error('installFromBackup failed', { error });
|
|
152
|
+
|
|
153
|
+
await manager._rollback('install', did);
|
|
154
|
+
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
logger.info('start install blocklet', { did });
|
|
159
|
+
return manager._installBlocklet({ did, context });
|
|
160
|
+
};
|
package/lib/router/helper.js
CHANGED
|
@@ -258,13 +258,19 @@ const ensureWellknownRule = async (sites) => {
|
|
|
258
258
|
if (blockletRules.length) {
|
|
259
259
|
// get pathPrefix for blocklet-service
|
|
260
260
|
const rootBlockletRule = blockletRules.find((x) => x.to.did === x.to.componentId);
|
|
261
|
-
|
|
261
|
+
|
|
262
|
+
const servicePathPrefix = joinUrl(
|
|
263
|
+
// rootBlockletRule?.from?.pathPrefix is for backwards compatibility
|
|
264
|
+
// rootBlockletRule?.from?.groupPathPrefix 在旧的场景中可能不为 '/' (blocklet 只能挂载在 relative prefix 下)
|
|
265
|
+
rootBlockletRule?.from?.groupPathPrefix || rootBlockletRule?.from?.pathPrefix || '/',
|
|
266
|
+
WELLKNOWN_SERVICE_PATH_PREFIX
|
|
267
|
+
);
|
|
262
268
|
|
|
263
269
|
// requests for /.well-known/service will stay in blocklet-service and never proxy back to blocklet
|
|
264
270
|
// so any rule is ok to be cloned
|
|
265
|
-
if (!site.rules.some((x) => x.from.pathPrefix ===
|
|
271
|
+
if (!site.rules.some((x) => x.from.pathPrefix === servicePathPrefix)) {
|
|
266
272
|
const rule = cloneDeep(rootBlockletRule || blockletRules[0]);
|
|
267
|
-
rule.from.pathPrefix =
|
|
273
|
+
rule.from.pathPrefix = servicePathPrefix;
|
|
268
274
|
rule.isProtected = true;
|
|
269
275
|
site.rules.push(rule);
|
|
270
276
|
}
|
|
@@ -275,6 +281,25 @@ const ensureWellknownRule = async (sites) => {
|
|
|
275
281
|
return tempSites;
|
|
276
282
|
};
|
|
277
283
|
|
|
284
|
+
const ensureBlockletDid = async (sites) => {
|
|
285
|
+
const info = await states.node.read();
|
|
286
|
+
|
|
287
|
+
return (sites || []).map((site) => {
|
|
288
|
+
if (site.domain === DOMAIN_FOR_INTERNAL_SITE) {
|
|
289
|
+
return site;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if ([DOMAIN_FOR_IP_SITE, DOMAIN_FOR_DEFAULT_SITE, DOMAIN_FOR_IP_SITE_REGEXP].includes(site.domain)) {
|
|
293
|
+
site.blockletDid = info.did;
|
|
294
|
+
return site;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
site.blockletDid = site.domain.replace(BLOCKLET_SITE_GROUP_SUFFIX, '');
|
|
298
|
+
|
|
299
|
+
return site;
|
|
300
|
+
});
|
|
301
|
+
};
|
|
302
|
+
|
|
278
303
|
const ensureCorsForWebWallet = async (sites) => {
|
|
279
304
|
const info = await states.node.read();
|
|
280
305
|
for (const site of sites) {
|
|
@@ -300,8 +325,10 @@ const filterSitesForRemovedBlocklets = async (sites = []) => {
|
|
|
300
325
|
|
|
301
326
|
const ensureLatestInfo = async (sites = [], { withDefaultCors = true } = {}) => {
|
|
302
327
|
let result = await ensureLatestNodeInfo(sites, { withDefaultCors });
|
|
328
|
+
result = await ensureBlockletDid(result);
|
|
303
329
|
result = await ensureWellknownRule(result);
|
|
304
330
|
result = await ensureCorsForWebWallet(result);
|
|
331
|
+
|
|
305
332
|
return ensureLatestInterfaceInfo(result);
|
|
306
333
|
};
|
|
307
334
|
|
package/lib/router/manager.js
CHANGED
|
@@ -11,6 +11,7 @@ const get = require('lodash/get');
|
|
|
11
11
|
const { EventEmitter } = require('events');
|
|
12
12
|
const uuid = require('uuid');
|
|
13
13
|
const isUrl = require('is-url');
|
|
14
|
+
const joinUrl = require('url-join');
|
|
14
15
|
const cloneDeep = require('lodash/cloneDeep');
|
|
15
16
|
const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
|
|
16
17
|
const logger = require('@abtnode/logger')('@abtnode/core:router:manager');
|
|
@@ -570,7 +571,8 @@ class RouterManager extends EventEmitter {
|
|
|
570
571
|
rule.groupId = rule.id;
|
|
571
572
|
rule.from.pathPrefix = normalizePathPrefix(rule.from.pathPrefix);
|
|
572
573
|
if (rule.to.type === ROUTING_RULE_TYPES.BLOCKLET) {
|
|
573
|
-
|
|
574
|
+
// pathPrefix of root blocklet maybe changed to another prefix than '/', so use old groupPathPrefix first
|
|
575
|
+
rule.from.groupPathPrefix = rule.from.groupPathPrefix || rule.from.pathPrefix;
|
|
574
576
|
rule.to.componentId = rule.to.did;
|
|
575
577
|
}
|
|
576
578
|
if (rule.to.url) {
|
|
@@ -580,18 +582,32 @@ class RouterManager extends EventEmitter {
|
|
|
580
582
|
|
|
581
583
|
/**
|
|
582
584
|
* get all rules to be add or update to site from root rule
|
|
583
|
-
* @param {*}
|
|
585
|
+
* @param {*} rootRule
|
|
584
586
|
*/
|
|
585
|
-
async getRulesForMutation(
|
|
586
|
-
if (
|
|
587
|
-
return [
|
|
587
|
+
async getRulesForMutation(rootRule) {
|
|
588
|
+
if (rootRule.to.type !== ROUTING_RULE_TYPES.BLOCKLET) {
|
|
589
|
+
return [rootRule];
|
|
588
590
|
}
|
|
589
591
|
|
|
590
592
|
const rules = [];
|
|
591
|
-
let occupied = false;
|
|
592
593
|
|
|
593
594
|
// get child rules
|
|
594
|
-
const blocklet = await states.blocklet.getBlocklet(
|
|
595
|
+
const blocklet = await states.blocklet.getBlocklet(rootRule.to.did);
|
|
596
|
+
|
|
597
|
+
// blocklet may be mounted in relative prefix (for old usage), so blockletPrefix may not be '/'
|
|
598
|
+
// blocklet prefix is the origin pathPrefix in rootRule
|
|
599
|
+
const blockletPrefix = normalizePathPrefix(rootRule.from.pathPrefix);
|
|
600
|
+
|
|
601
|
+
// root component's mountPoint may not be '/'
|
|
602
|
+
const rootComponentPrefix = joinUrl(blockletPrefix, blocklet.mountPoint || '/');
|
|
603
|
+
rootRule.from.pathPrefix = normalizePathPrefix(rootComponentPrefix);
|
|
604
|
+
|
|
605
|
+
const isOccupiable = blocklet.meta.group === BlockletGroup.gateway;
|
|
606
|
+
|
|
607
|
+
if (!isOccupiable) {
|
|
608
|
+
rules.push(rootRule);
|
|
609
|
+
}
|
|
610
|
+
|
|
595
611
|
forEachChildSync(blocklet, (component, { id, ancestors }) => {
|
|
596
612
|
if (component.meta.group === BlockletGroup.gateway) {
|
|
597
613
|
return;
|
|
@@ -611,38 +627,40 @@ class RouterManager extends EventEmitter {
|
|
|
611
627
|
return;
|
|
612
628
|
}
|
|
613
629
|
|
|
614
|
-
const pathPrefix = path.join(
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
630
|
+
const pathPrefix = path.join(
|
|
631
|
+
blockletPrefix,
|
|
632
|
+
// level 1 component should be independent with root component
|
|
633
|
+
...ancestors.slice(1).map((x) => x.mountPoint || ''),
|
|
634
|
+
mountPoint
|
|
635
|
+
);
|
|
636
|
+
|
|
637
|
+
const occupied = normalizePathPrefix(pathPrefix) === normalizePathPrefix(rootRule.from.pathPrefix);
|
|
638
|
+
|
|
639
|
+
if (occupied && !isOccupiable) {
|
|
640
|
+
return;
|
|
618
641
|
}
|
|
619
642
|
|
|
620
643
|
// if is root path, child rule become root rule
|
|
621
644
|
const childRule = {
|
|
622
|
-
id:
|
|
623
|
-
groupId:
|
|
645
|
+
id: occupied ? rootRule.id : uuid.v4(),
|
|
646
|
+
groupId: rootRule.id,
|
|
624
647
|
from: {
|
|
625
648
|
pathPrefix: normalizePathPrefix(pathPrefix),
|
|
626
|
-
groupPathPrefix:
|
|
649
|
+
groupPathPrefix: blockletPrefix,
|
|
627
650
|
},
|
|
628
651
|
to: {
|
|
629
652
|
type: ROUTING_RULE_TYPES.BLOCKLET,
|
|
630
653
|
port: findInterfacePortByName(component, childWebInterface.name),
|
|
631
|
-
did:
|
|
632
|
-
interfaceName:
|
|
654
|
+
did: rootRule.to.did, // root component did
|
|
655
|
+
interfaceName: rootRule.to.interfaceName, // root component interface
|
|
633
656
|
componentId: id,
|
|
634
657
|
},
|
|
635
|
-
isProtected:
|
|
658
|
+
isProtected: occupied ? rootRule.isProtected : true,
|
|
636
659
|
};
|
|
637
660
|
|
|
638
661
|
rules.push(childRule);
|
|
639
662
|
});
|
|
640
663
|
|
|
641
|
-
// get root rule
|
|
642
|
-
if (!occupied && blocklet.meta.group !== BlockletGroup.gateway) {
|
|
643
|
-
rules.push(rule);
|
|
644
|
-
}
|
|
645
|
-
|
|
646
664
|
return rules;
|
|
647
665
|
}
|
|
648
666
|
}
|
|
@@ -9,7 +9,7 @@ const dayjs = require('dayjs');
|
|
|
9
9
|
|
|
10
10
|
const BaseState = require('./base');
|
|
11
11
|
|
|
12
|
-
const { mergeConfigs, parseConfigs } = require('../blocklet/extras');
|
|
12
|
+
const { mergeConfigs, parseConfigs, encryptConfigs } = require('../blocklet/extras');
|
|
13
13
|
const { validateAddMeta, validateExpiredInfo } = require('../validators/blocklet-extra');
|
|
14
14
|
|
|
15
15
|
const noop = (k) => (v) => v[k];
|
|
@@ -214,6 +214,34 @@ class BlockletExtrasState extends BaseState {
|
|
|
214
214
|
expiredAt: { $exists: true, $lte: now.subtract(EXPIRED_BLOCKLET_DATA_RETENTION_DAYS, 'days').toISOString() },
|
|
215
215
|
});
|
|
216
216
|
}
|
|
217
|
+
|
|
218
|
+
encryptSecurityData({ data, _rootDid } = {}) {
|
|
219
|
+
if (!data) {
|
|
220
|
+
return data;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const { dek } = this.config;
|
|
224
|
+
|
|
225
|
+
if (!dek) {
|
|
226
|
+
return data;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const did = _rootDid || data.did;
|
|
230
|
+
|
|
231
|
+
if (!did) {
|
|
232
|
+
throw new Error('data.did does not exist');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
encryptConfigs({ data: data.configs, did, dek });
|
|
236
|
+
|
|
237
|
+
if (Array.isArray(data.children)) {
|
|
238
|
+
for (const child of data.children) {
|
|
239
|
+
this.encryptSecurityData({ data: child, _rootDid: did });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return data;
|
|
244
|
+
}
|
|
217
245
|
}
|
|
218
246
|
|
|
219
247
|
module.exports = BlockletExtrasState;
|
package/lib/util/blocklet.js
CHANGED
|
@@ -31,8 +31,7 @@ const getFolderSize = require('@abtnode/util/lib/get-folder-size');
|
|
|
31
31
|
const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
|
|
32
32
|
const hashFiles = require('@abtnode/util/lib/hash-files');
|
|
33
33
|
const isPathPrefixEqual = require('@abtnode/util/lib/is-path-prefix-equal');
|
|
34
|
-
const { BLOCKLET_MAX_MEM_LIMIT_IN_MB, BLOCKLET_STORE } = require('@abtnode/constant');
|
|
35
|
-
const { BLOCKLET_PREFERENCE_FILE, BLOCKLET_PREFERENCE_PREFIX } = require('@blocklet/constant');
|
|
34
|
+
const { BLOCKLET_MAX_MEM_LIMIT_IN_MB, BLOCKLET_STORE, BLOCKLET_INSTALL_TYPE } = require('@abtnode/constant');
|
|
36
35
|
const formatBackSlash = require('@abtnode/util/lib/format-back-slash');
|
|
37
36
|
|
|
38
37
|
const SCRIPT_ENGINES_WHITE_LIST = ['npm', 'npx', 'pnpm', 'yarn'];
|
|
@@ -50,6 +49,8 @@ const {
|
|
|
50
49
|
BLOCKLET_CONFIGURABLE_KEY,
|
|
51
50
|
BLOCKLET_DYNAMIC_PATH_PREFIX,
|
|
52
51
|
fromBlockletStatus,
|
|
52
|
+
BLOCKLET_PREFERENCE_FILE,
|
|
53
|
+
BLOCKLET_PREFERENCE_PREFIX,
|
|
53
54
|
} = require('@blocklet/constant');
|
|
54
55
|
const verifyMultiSig = require('@blocklet/meta/lib/verify-multi-sig');
|
|
55
56
|
const validateBlockletEntry = require('@blocklet/meta/lib/entry');
|
|
@@ -926,6 +927,59 @@ const verifyIntegrity = async ({ file, integrity: expected }) => {
|
|
|
926
927
|
return true;
|
|
927
928
|
};
|
|
928
929
|
|
|
930
|
+
/**
|
|
931
|
+
* @param {string} installDir
|
|
932
|
+
* @returns {Array<{ key: <[scope/]name/version>, dir: appDir }>}
|
|
933
|
+
*/
|
|
934
|
+
const getAppDirs = async (installDir) => {
|
|
935
|
+
const appDirs = [];
|
|
936
|
+
|
|
937
|
+
const getNextLevel = (level, name) => {
|
|
938
|
+
if (level === 'root') {
|
|
939
|
+
if (name.startsWith('@')) {
|
|
940
|
+
return 'scope';
|
|
941
|
+
}
|
|
942
|
+
return 'name';
|
|
943
|
+
}
|
|
944
|
+
if (level === 'scope') {
|
|
945
|
+
return 'name';
|
|
946
|
+
}
|
|
947
|
+
if (level === 'name') {
|
|
948
|
+
return 'version';
|
|
949
|
+
}
|
|
950
|
+
throw new Error(`Invalid level ${level}`);
|
|
951
|
+
};
|
|
952
|
+
|
|
953
|
+
const fillAppDirs = async (dir, level = 'root') => {
|
|
954
|
+
if (level === 'version') {
|
|
955
|
+
appDirs.push({
|
|
956
|
+
key: formatBackSlash(path.relative(installDir, dir)),
|
|
957
|
+
dir,
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
const nextDirs = [];
|
|
964
|
+
for (const x of await fs.promises.readdir(dir)) {
|
|
965
|
+
if (!fs.lstatSync(path.join(dir, x)).isDirectory()) {
|
|
966
|
+
logger.error('pruneBlockletBundle: invalid file in bundle storage', { dir, file: x });
|
|
967
|
+
// eslint-disable-next-line no-continue
|
|
968
|
+
continue;
|
|
969
|
+
}
|
|
970
|
+
nextDirs.push(x);
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
for (const x of nextDirs) {
|
|
974
|
+
await fillAppDirs(path.join(dir, x), getNextLevel(level, x));
|
|
975
|
+
}
|
|
976
|
+
};
|
|
977
|
+
|
|
978
|
+
await fillAppDirs(installDir, 'root');
|
|
979
|
+
|
|
980
|
+
return appDirs;
|
|
981
|
+
};
|
|
982
|
+
|
|
929
983
|
const pruneBlockletBundle = async ({ blocklets, installDir, blockletSettings }) => {
|
|
930
984
|
for (const blocklet of blocklets) {
|
|
931
985
|
if (
|
|
@@ -961,53 +1015,10 @@ const pruneBlockletBundle = async ({ blocklets, installDir, blockletSettings })
|
|
|
961
1015
|
}
|
|
962
1016
|
}
|
|
963
1017
|
|
|
964
|
-
// appDirs: [{ key: <[scope/]name/version>, dir: appDir }]
|
|
965
|
-
const appDirs = [];
|
|
966
|
-
|
|
967
1018
|
// fill appDirs
|
|
1019
|
+
let appDirs = [];
|
|
968
1020
|
try {
|
|
969
|
-
|
|
970
|
-
const getNextLevel = (level, name) => {
|
|
971
|
-
if (level === 'root') {
|
|
972
|
-
if (name.startsWith('@')) {
|
|
973
|
-
return 'scope';
|
|
974
|
-
}
|
|
975
|
-
return 'bundle';
|
|
976
|
-
}
|
|
977
|
-
if (level === 'scope') {
|
|
978
|
-
return 'bundle';
|
|
979
|
-
}
|
|
980
|
-
if (level === 'bundle') {
|
|
981
|
-
return 'version';
|
|
982
|
-
}
|
|
983
|
-
throw new Error(`Invalid level ${level}`);
|
|
984
|
-
};
|
|
985
|
-
|
|
986
|
-
const fillAppDirs = async (dir, level = 'root') => {
|
|
987
|
-
if (level === 'version') {
|
|
988
|
-
appDirs.push({
|
|
989
|
-
key: formatBackSlash(path.relative(installDir, dir)),
|
|
990
|
-
dir,
|
|
991
|
-
});
|
|
992
|
-
|
|
993
|
-
return;
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
const nextDirs = [];
|
|
997
|
-
for (const x of await fs.promises.readdir(dir)) {
|
|
998
|
-
if (!fs.lstatSync(path.join(dir, x)).isDirectory()) {
|
|
999
|
-
logger.error('pruneBlockletBundle: invalid file in bundle storage', { dir, file: x });
|
|
1000
|
-
// eslint-disable-next-line no-continue
|
|
1001
|
-
continue;
|
|
1002
|
-
}
|
|
1003
|
-
nextDirs.push(x);
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
for (const x of nextDirs) {
|
|
1007
|
-
await fillAppDirs(path.join(dir, x), getNextLevel(level, x));
|
|
1008
|
-
}
|
|
1009
|
-
};
|
|
1010
|
-
await fillAppDirs(installDir, 'root');
|
|
1021
|
+
appDirs = await getAppDirs(installDir);
|
|
1011
1022
|
} catch (error) {
|
|
1012
1023
|
logger.error('fill app dirs failed', { error });
|
|
1013
1024
|
}
|
|
@@ -1197,24 +1208,34 @@ const getUpdateMetaList = (oldBlocklet = {}, newBlocklet = {}) => {
|
|
|
1197
1208
|
return res;
|
|
1198
1209
|
};
|
|
1199
1210
|
|
|
1200
|
-
|
|
1211
|
+
/**
|
|
1212
|
+
* @returns BLOCKLET_INSTALL_TYPE
|
|
1213
|
+
*/
|
|
1214
|
+
const getTypeFromInstallParams = (params) => {
|
|
1215
|
+
if (params.type) {
|
|
1216
|
+
if (!Object.values(BLOCKLET_INSTALL_TYPE).includes(params.type)) {
|
|
1217
|
+
throw new Error(`Can only install blocklet from ${Object.values(BLOCKLET_INSTALL_TYPE).join('/')}`);
|
|
1218
|
+
}
|
|
1219
|
+
return params.type;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1201
1222
|
if (params.url) {
|
|
1202
|
-
return
|
|
1223
|
+
return BLOCKLET_INSTALL_TYPE.URL;
|
|
1203
1224
|
}
|
|
1204
1225
|
|
|
1205
1226
|
if (params.file) {
|
|
1206
|
-
return
|
|
1227
|
+
return BLOCKLET_INSTALL_TYPE.UPLOAD;
|
|
1207
1228
|
}
|
|
1208
1229
|
|
|
1209
1230
|
if (params.did) {
|
|
1210
|
-
return
|
|
1231
|
+
return BLOCKLET_INSTALL_TYPE.STORE;
|
|
1211
1232
|
}
|
|
1212
1233
|
|
|
1213
1234
|
if (params.title && params.description) {
|
|
1214
|
-
return
|
|
1235
|
+
return BLOCKLET_INSTALL_TYPE.CREATE;
|
|
1215
1236
|
}
|
|
1216
1237
|
|
|
1217
|
-
throw new Error(
|
|
1238
|
+
throw new Error(`Can only install blocklet from ${Object.values(BLOCKLET_INSTALL_TYPE).join('/')}`);
|
|
1218
1239
|
};
|
|
1219
1240
|
|
|
1220
1241
|
const checkDuplicateComponents = (components = []) => {
|
|
@@ -1599,25 +1620,32 @@ const validateAppConfig = async (config, blockletDid, states) => {
|
|
|
1599
1620
|
}
|
|
1600
1621
|
};
|
|
1601
1622
|
|
|
1602
|
-
const checkDuplicateAppSk = async ({ did, states }) => {
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
const configs = await states.blockletExtras.getConfigs([did]);
|
|
1623
|
+
const checkDuplicateAppSk = async ({ sk, did, states }) => {
|
|
1624
|
+
if (!sk && !did) {
|
|
1625
|
+
throw new Error('sk and did is empty');
|
|
1626
|
+
}
|
|
1607
1627
|
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1628
|
+
let appSk = sk;
|
|
1629
|
+
if (!sk) {
|
|
1630
|
+
const nodeInfo = await states.node.read();
|
|
1631
|
+
const blocklet = await states.blocklet.getBlocklet(did);
|
|
1632
|
+
const configs = await states.blockletExtras.getConfigs([did]);
|
|
1633
|
+
const { wallet } = getBlockletInfo(
|
|
1634
|
+
{
|
|
1635
|
+
meta: blocklet.meta,
|
|
1636
|
+
environments: (configs || []).filter((x) => x.value),
|
|
1637
|
+
},
|
|
1638
|
+
nodeInfo.sk
|
|
1639
|
+
);
|
|
1640
|
+
appSk = wallet.secretKey;
|
|
1641
|
+
}
|
|
1615
1642
|
|
|
1616
|
-
const
|
|
1643
|
+
const blocklets = await states.blocklet.getBlocklets({});
|
|
1644
|
+
const others = did ? blocklets.filter((b) => b.meta.did !== did) : blocklets;
|
|
1617
1645
|
|
|
1618
1646
|
const exist = others.find((b) => {
|
|
1619
1647
|
const item = (b.environments || []).find((e) => e.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK);
|
|
1620
|
-
return item?.value === toHex(
|
|
1648
|
+
return item?.value === toHex(appSk);
|
|
1621
1649
|
});
|
|
1622
1650
|
|
|
1623
1651
|
if (exist) {
|
|
@@ -1625,6 +1653,19 @@ const checkDuplicateAppSk = async ({ did, states }) => {
|
|
|
1625
1653
|
}
|
|
1626
1654
|
};
|
|
1627
1655
|
|
|
1656
|
+
const checkDuplicateMountPoint = (blocklet, mountPoint) => {
|
|
1657
|
+
const err = new Error(`cannot add duplicate mount point, ${mountPoint || '/'} already exist`);
|
|
1658
|
+
if (normalizePathPrefix(blocklet.mountPoint) === normalizePathPrefix(mountPoint)) {
|
|
1659
|
+
throw err;
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
for (const component of blocklet.children || []) {
|
|
1663
|
+
if (normalizePathPrefix(component.mountPoint) === normalizePathPrefix(mountPoint)) {
|
|
1664
|
+
throw err;
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
};
|
|
1668
|
+
|
|
1628
1669
|
module.exports = {
|
|
1629
1670
|
consumeServerlessNFT,
|
|
1630
1671
|
forEachBlocklet,
|
|
@@ -1650,13 +1691,14 @@ module.exports = {
|
|
|
1650
1691
|
expandTarball,
|
|
1651
1692
|
verifyIntegrity,
|
|
1652
1693
|
statusMap,
|
|
1694
|
+
getAppDirs,
|
|
1653
1695
|
pruneBlockletBundle,
|
|
1654
1696
|
getDiskInfo,
|
|
1655
1697
|
getRuntimeInfo,
|
|
1656
1698
|
mergeMeta,
|
|
1657
1699
|
fixAndVerifyMetaFromStore,
|
|
1658
1700
|
getUpdateMetaList,
|
|
1659
|
-
|
|
1701
|
+
getTypeFromInstallParams,
|
|
1660
1702
|
findWebInterface,
|
|
1661
1703
|
checkDuplicateComponents,
|
|
1662
1704
|
getDiffFiles,
|
|
@@ -1670,4 +1712,5 @@ module.exports = {
|
|
|
1670
1712
|
createDataArchive,
|
|
1671
1713
|
validateAppConfig,
|
|
1672
1714
|
checkDuplicateAppSk,
|
|
1715
|
+
checkDuplicateMountPoint,
|
|
1673
1716
|
};
|
package/lib/validators/router.js
CHANGED
|
@@ -47,7 +47,7 @@ const ruleSchema = {
|
|
|
47
47
|
port: Joi.number().label('port').port().when('type', { is: ROUTING_RULE_TYPES.BLOCKLET, then: Joi.required() }),
|
|
48
48
|
url: Joi.string().label('url').when('type', { is: ROUTING_RULE_TYPES.REDIRECT, then: Joi.required() }),
|
|
49
49
|
redirectCode: Joi.alternatives()
|
|
50
|
-
.try(301, 302)
|
|
50
|
+
.try(301, 302, 307, 308)
|
|
51
51
|
.label('redirect code')
|
|
52
52
|
.when('type', { is: ROUTING_RULE_TYPES.REDIRECT, then: Joi.required() }),
|
|
53
53
|
interfaceName: Joi.string() // root interface
|
|
@@ -81,7 +81,7 @@ const ruleSchema = {
|
|
|
81
81
|
const corsSchema = Joi.array()
|
|
82
82
|
.items(
|
|
83
83
|
Joi.string().domain({ minDomainSegments: 1, tlds: false }),
|
|
84
|
-
Joi.string().valid(DOMAIN_FOR_DEFAULT_SITE),
|
|
84
|
+
Joi.string().valid(DOMAIN_FOR_DEFAULT_SITE, '__none__'),
|
|
85
85
|
Joi.string().ip()
|
|
86
86
|
)
|
|
87
87
|
.min(1)
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.8.
|
|
6
|
+
"version": "1.8.63-beta-c51e554d",
|
|
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": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@abtnode/auth": "1.8.
|
|
23
|
-
"@abtnode/certificate-manager": "1.8.
|
|
24
|
-
"@abtnode/constant": "1.8.
|
|
25
|
-
"@abtnode/cron": "1.8.
|
|
26
|
-
"@abtnode/db": "1.8.
|
|
27
|
-
"@abtnode/logger": "1.8.
|
|
28
|
-
"@abtnode/queue": "1.8.
|
|
29
|
-
"@abtnode/rbac": "1.8.
|
|
30
|
-
"@abtnode/router-provider": "1.8.
|
|
31
|
-
"@abtnode/static-server": "1.8.
|
|
32
|
-
"@abtnode/timemachine": "1.8.
|
|
33
|
-
"@abtnode/util": "1.8.
|
|
22
|
+
"@abtnode/auth": "1.8.63-beta-c51e554d",
|
|
23
|
+
"@abtnode/certificate-manager": "1.8.63-beta-c51e554d",
|
|
24
|
+
"@abtnode/constant": "1.8.63-beta-c51e554d",
|
|
25
|
+
"@abtnode/cron": "1.8.63-beta-c51e554d",
|
|
26
|
+
"@abtnode/db": "1.8.63-beta-c51e554d",
|
|
27
|
+
"@abtnode/logger": "1.8.63-beta-c51e554d",
|
|
28
|
+
"@abtnode/queue": "1.8.63-beta-c51e554d",
|
|
29
|
+
"@abtnode/rbac": "1.8.63-beta-c51e554d",
|
|
30
|
+
"@abtnode/router-provider": "1.8.63-beta-c51e554d",
|
|
31
|
+
"@abtnode/static-server": "1.8.63-beta-c51e554d",
|
|
32
|
+
"@abtnode/timemachine": "1.8.63-beta-c51e554d",
|
|
33
|
+
"@abtnode/util": "1.8.63-beta-c51e554d",
|
|
34
34
|
"@arcblock/did": "1.18.36",
|
|
35
35
|
"@arcblock/did-motif": "^1.1.10",
|
|
36
36
|
"@arcblock/did-util": "1.18.36",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
"@arcblock/jwt": "^1.18.36",
|
|
39
39
|
"@arcblock/pm2-events": "^0.0.5",
|
|
40
40
|
"@arcblock/vc": "1.18.36",
|
|
41
|
-
"@blocklet/constant": "1.8.
|
|
42
|
-
"@blocklet/meta": "1.8.
|
|
43
|
-
"@blocklet/sdk": "1.8.
|
|
41
|
+
"@blocklet/constant": "1.8.63-beta-c51e554d",
|
|
42
|
+
"@blocklet/meta": "1.8.63-beta-c51e554d",
|
|
43
|
+
"@blocklet/sdk": "1.8.63-beta-c51e554d",
|
|
44
44
|
"@fidm/x509": "^1.2.1",
|
|
45
45
|
"@ocap/mcrypto": "1.18.36",
|
|
46
46
|
"@ocap/util": "1.18.36",
|
|
@@ -85,5 +85,5 @@
|
|
|
85
85
|
"express": "^4.18.2",
|
|
86
86
|
"jest": "^27.5.1"
|
|
87
87
|
},
|
|
88
|
-
"gitHead": "
|
|
88
|
+
"gitHead": "9913ed7968dfab63d6549201a5a98f9819fcfac6"
|
|
89
89
|
}
|