@abtnode/core 1.17.8-beta-20260108-224855-28496abb → 1.17.8-beta-20260111-112953-aed5ff39
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/access-key-manager.js +104 -0
- package/lib/api/team/invitation-manager.js +461 -0
- package/lib/api/team/notification-manager.js +189 -0
- package/lib/api/team/oauth-manager.js +60 -0
- package/lib/api/team/org-crud-manager.js +202 -0
- package/lib/api/team/org-manager.js +56 -0
- package/lib/api/team/org-member-manager.js +403 -0
- package/lib/api/team/org-query-manager.js +126 -0
- package/lib/api/team/org-resource-manager.js +186 -0
- package/lib/api/team/passport-manager.js +670 -0
- package/lib/api/team/rbac-manager.js +335 -0
- package/lib/api/team/session-manager.js +540 -0
- package/lib/api/team/store-manager.js +198 -0
- package/lib/api/team/tag-manager.js +230 -0
- package/lib/api/team/user-auth-manager.js +132 -0
- package/lib/api/team/user-manager.js +78 -0
- package/lib/api/team/user-query-manager.js +299 -0
- package/lib/api/team/user-social-manager.js +354 -0
- package/lib/api/team/user-update-manager.js +224 -0
- package/lib/api/team/verify-code-manager.js +161 -0
- package/lib/api/team.js +439 -3287
- package/lib/blocklet/manager/disk/auth-manager.js +68 -0
- package/lib/blocklet/manager/disk/backup-manager.js +288 -0
- package/lib/blocklet/manager/disk/cleanup-manager.js +157 -0
- package/lib/blocklet/manager/disk/component-manager.js +83 -0
- package/lib/blocklet/manager/disk/config-manager.js +191 -0
- package/lib/blocklet/manager/disk/controller-manager.js +64 -0
- package/lib/blocklet/manager/disk/delete-reset-manager.js +328 -0
- package/lib/blocklet/manager/disk/download-manager.js +96 -0
- package/lib/blocklet/manager/disk/env-config-manager.js +311 -0
- package/lib/blocklet/manager/disk/federated-manager.js +651 -0
- package/lib/blocklet/manager/disk/hook-manager.js +124 -0
- package/lib/blocklet/manager/disk/install-component-manager.js +95 -0
- package/lib/blocklet/manager/disk/install-core-manager.js +448 -0
- package/lib/blocklet/manager/disk/install-download-manager.js +313 -0
- package/lib/blocklet/manager/disk/install-manager.js +36 -0
- package/lib/blocklet/manager/disk/install-upgrade-manager.js +340 -0
- package/lib/blocklet/manager/disk/job-manager.js +467 -0
- package/lib/blocklet/manager/disk/lifecycle-manager.js +26 -0
- package/lib/blocklet/manager/disk/notification-manager.js +343 -0
- package/lib/blocklet/manager/disk/query-manager.js +562 -0
- package/lib/blocklet/manager/disk/settings-manager.js +507 -0
- package/lib/blocklet/manager/disk/start-manager.js +611 -0
- package/lib/blocklet/manager/disk/stop-restart-manager.js +292 -0
- package/lib/blocklet/manager/disk/update-manager.js +153 -0
- package/lib/blocklet/manager/disk.js +669 -5796
- package/lib/blocklet/manager/helper/blue-green-start-blocklet.js +5 -0
- package/lib/blocklet/manager/lock.js +18 -0
- package/lib/event/index.js +28 -24
- package/lib/router/helper.js +5 -1
- package/lib/util/blocklet/app-utils.js +192 -0
- package/lib/util/blocklet/blocklet-loader.js +258 -0
- package/lib/util/blocklet/config-manager.js +232 -0
- package/lib/util/blocklet/did-document.js +240 -0
- package/lib/util/blocklet/environment.js +555 -0
- package/lib/util/blocklet/health-check.js +449 -0
- package/lib/util/blocklet/install-utils.js +365 -0
- package/lib/util/blocklet/logo.js +57 -0
- package/lib/util/blocklet/meta-utils.js +269 -0
- package/lib/util/blocklet/port-manager.js +141 -0
- package/lib/util/blocklet/process-manager.js +504 -0
- package/lib/util/blocklet/runtime-info.js +105 -0
- package/lib/util/blocklet/validation.js +418 -0
- package/lib/util/blocklet.js +98 -3066
- package/lib/util/wallet-app-notification.js +40 -0
- package/package.json +22 -22
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
/* eslint-disable no-await-in-loop */
|
|
2
|
+
const omit = require('lodash/omit');
|
|
3
|
+
const logger = require('@abtnode/logger')('@abtnode/core:blocklet:manager:env-config');
|
|
4
|
+
const { sanitizeTag } = require('@abtnode/util/lib/sanitize');
|
|
5
|
+
const { getBlockletInfo } = require('@blocklet/meta/lib/info');
|
|
6
|
+
const { sendToUser } = require('@blocklet/sdk/lib/util/send-notification');
|
|
7
|
+
const { encrypt } = require('@blocklet/sdk/lib/security');
|
|
8
|
+
const { getComponentApiKey } = require('@abtnode/util/lib/blocklet');
|
|
9
|
+
const { environmentNameSchema } = require('@blocklet/meta/lib/schema');
|
|
10
|
+
const {
|
|
11
|
+
BlockletEvents,
|
|
12
|
+
BlockletInternalEvents,
|
|
13
|
+
BLOCKLET_CONFIGURABLE_KEY,
|
|
14
|
+
BLOCKLET_PREFERENCE_PREFIX,
|
|
15
|
+
} = require('@blocklet/constant');
|
|
16
|
+
const { isPreferenceKey } = require('@blocklet/meta/lib/util');
|
|
17
|
+
const { shouldSyncFederated } = require('@abtnode/auth/lib/util/federated');
|
|
18
|
+
|
|
19
|
+
const states = require('../../../states');
|
|
20
|
+
const {
|
|
21
|
+
getRuntimeEnvironments,
|
|
22
|
+
isExternalBlocklet,
|
|
23
|
+
validateAppConfig,
|
|
24
|
+
isRotatingAppSk,
|
|
25
|
+
getConfigsFromInput,
|
|
26
|
+
getHookArgs,
|
|
27
|
+
} = require('../../../util/blocklet');
|
|
28
|
+
const hooks = require('../../hooks');
|
|
29
|
+
const launcher = require('../../../util/launcher');
|
|
30
|
+
const checkNeedRunDocker = require('../../../util/docker/check-need-run-docker');
|
|
31
|
+
const { dockerExec } = require('../../../util/docker/docker-exec');
|
|
32
|
+
const { getWalletAppNotification } = require('../../../util/wallet-app-notification');
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Config blocklet environment
|
|
36
|
+
* @param {Object} manager - BlockletManager instance
|
|
37
|
+
* @param {Object} params
|
|
38
|
+
* @param {Object} context
|
|
39
|
+
* @returns {Promise<Object>}
|
|
40
|
+
*/
|
|
41
|
+
async function config(manager, { did, configs: newConfigs, skipHook, skipDidDocument, skipEmitEvents }, context) {
|
|
42
|
+
// todo: skipDidDocument will be deleted
|
|
43
|
+
if (!Array.isArray(newConfigs)) {
|
|
44
|
+
throw new Error('configs list is not an array');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 对用户输入的配置进行 XSS 清理
|
|
48
|
+
const sanitizedConfigs = newConfigs
|
|
49
|
+
.map((c) => ({
|
|
50
|
+
...c,
|
|
51
|
+
value: sanitizeTag(c.value),
|
|
52
|
+
}))
|
|
53
|
+
.filter((x) => (x.key.startsWith(BLOCKLET_PREFERENCE_PREFIX) ? omit(x, 'shared') : x));
|
|
54
|
+
|
|
55
|
+
const tmpDids = Array.isArray(did) ? did : [did];
|
|
56
|
+
const [rootDid, childDid] = tmpDids;
|
|
57
|
+
const rootMetaDid = await states.blocklet.getBlockletMetaDid(rootDid);
|
|
58
|
+
|
|
59
|
+
logger.info('config blocklet', { rootDid, rootMetaDid, childDid });
|
|
60
|
+
|
|
61
|
+
const ancestors = [];
|
|
62
|
+
let blocklet = await manager.getBlocklet(rootDid);
|
|
63
|
+
if (childDid) {
|
|
64
|
+
ancestors.push(blocklet);
|
|
65
|
+
blocklet = blocklet.children.find((x) => x.meta.did === childDid);
|
|
66
|
+
if (!blocklet) {
|
|
67
|
+
throw new Error('Child blocklet does not exist', { rootDid, childDid });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const configObj = {};
|
|
72
|
+
const ignoredKeys = [];
|
|
73
|
+
for (const x of sanitizedConfigs) {
|
|
74
|
+
if (['CHAIN_TYPE', 'BLOCKLET_APP_CHAIN_TYPE'].includes(x.key)) {
|
|
75
|
+
throw new Error(`${x.key} should not be changed`);
|
|
76
|
+
} else if (x.custom === true) {
|
|
77
|
+
// custom key
|
|
78
|
+
await environmentNameSchema.validateAsync(x.key);
|
|
79
|
+
} else if (BLOCKLET_CONFIGURABLE_KEY[x.key] && x.key.startsWith('BLOCKLET_')) {
|
|
80
|
+
// app key
|
|
81
|
+
if (childDid) {
|
|
82
|
+
logger.error(`Cannot set ${x.key} to child blocklet`, { rootDid, childDid });
|
|
83
|
+
throw new Error(`Cannot set ${x.key} to child blocklet`);
|
|
84
|
+
}
|
|
85
|
+
await validateAppConfig(x, states);
|
|
86
|
+
} else if (!BLOCKLET_CONFIGURABLE_KEY[x.key] && !isPreferenceKey(x)) {
|
|
87
|
+
const hasEnvInMeta = (b) => (b.meta.environments || []).some((y) => y.name === x.key);
|
|
88
|
+
if (!hasEnvInMeta(blocklet)) {
|
|
89
|
+
// forbid unknown environment items
|
|
90
|
+
if (
|
|
91
|
+
// config should in component.meta.environments
|
|
92
|
+
childDid ||
|
|
93
|
+
// config should in app.meta.environments and or in one of component.meta.environments
|
|
94
|
+
!(blocklet.children || []).some(hasEnvInMeta)
|
|
95
|
+
) {
|
|
96
|
+
logger.warn(`unknown environment item: ${x.key}`, { rootDid, childDid, config: x });
|
|
97
|
+
ignoredKeys.push(x.key);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
configObj[x.key] = x.value;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const finalConfigs = sanitizedConfigs.filter((x) => !ignoredKeys.includes(x.key));
|
|
107
|
+
const willAppSkChange = isRotatingAppSk(finalConfigs, blocklet.configs, blocklet.externalSk);
|
|
108
|
+
|
|
109
|
+
// NOTICE: cannot use appDid as did param because appDid will become old appDid in alsoKnownAs and cannot get blocklet by the old appDid
|
|
110
|
+
if (willAppSkChange && rootDid !== rootMetaDid) {
|
|
111
|
+
throw new Error(`Please use app meta did (${rootMetaDid}) as did param when config appSk`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// run hook
|
|
115
|
+
if (!skipHook) {
|
|
116
|
+
// FIXME: we should also call preConfig for child blocklets
|
|
117
|
+
const nodeInfo = await states.node.read();
|
|
118
|
+
const nodeEnvironments = await states.node.getEnvironments(nodeInfo);
|
|
119
|
+
const nextEnv = { ...getRuntimeEnvironments(blocklet, nodeEnvironments, ancestors), ...configObj };
|
|
120
|
+
const needRunDocker = await checkNeedRunDocker(blocklet.meta, nextEnv, nodeInfo, isExternalBlocklet(blocklet));
|
|
121
|
+
const hookArgs = getHookArgs(blocklet);
|
|
122
|
+
if (needRunDocker) {
|
|
123
|
+
if (blocklet.meta.scripts?.preConfig) {
|
|
124
|
+
await dockerExec({
|
|
125
|
+
blocklet: {
|
|
126
|
+
status: blocklet.status,
|
|
127
|
+
meta: {
|
|
128
|
+
did: rootDid,
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
meta: blocklet.meta,
|
|
132
|
+
nodeInfo,
|
|
133
|
+
env: nextEnv,
|
|
134
|
+
script: blocklet.meta.scripts.preConfig,
|
|
135
|
+
retry: 0,
|
|
136
|
+
hookName: 'preConfig',
|
|
137
|
+
...hookArgs,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
await hooks.preConfig(blocklet.meta.title, {
|
|
142
|
+
appDir: blocklet.env.appDir,
|
|
143
|
+
hooks: Object.assign(blocklet.meta.hooks || {}, blocklet.meta.scripts || {}),
|
|
144
|
+
exitOnError: true,
|
|
145
|
+
env: nextEnv,
|
|
146
|
+
did,
|
|
147
|
+
context,
|
|
148
|
+
teamManager: manager.teamManager,
|
|
149
|
+
...hookArgs,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
Object.assign(blocklet.configObj, configObj);
|
|
155
|
+
|
|
156
|
+
// update db
|
|
157
|
+
if (childDid) {
|
|
158
|
+
const { sharedConfigs, selfConfigs } = getConfigsFromInput(finalConfigs, blocklet.configs);
|
|
159
|
+
|
|
160
|
+
if (sharedConfigs.length) {
|
|
161
|
+
await states.blockletExtras.setConfigs([rootMetaDid], sharedConfigs);
|
|
162
|
+
}
|
|
163
|
+
if (selfConfigs.length) {
|
|
164
|
+
await states.blockletExtras.setConfigs([rootMetaDid, childDid], selfConfigs);
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
await states.blockletExtras.setConfigs([rootMetaDid], finalConfigs);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (willAppSkChange) {
|
|
171
|
+
const info = await states.node.read();
|
|
172
|
+
const { wallet } = getBlockletInfo(blocklet, info.sk);
|
|
173
|
+
const migratedFrom = Array.isArray(blocklet.migratedFrom) ? blocklet.migratedFrom : [];
|
|
174
|
+
await states.blocklet.updateBlocklet(rootDid, {
|
|
175
|
+
migratedFrom: [
|
|
176
|
+
...migratedFrom,
|
|
177
|
+
{ appSk: wallet.secretKey, appDid: wallet.address, at: new Date().toISOString() },
|
|
178
|
+
],
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Reload nginx to make sure did-space can embed content from this app
|
|
183
|
+
if (finalConfigs.find((x) => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_BACKUP_ENDPOINT)?.value) {
|
|
184
|
+
manager.emit(BlockletEvents.spaceConnected, blocklet);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// update blocklet meta
|
|
188
|
+
if (blocklet.structVersion && !childDid) {
|
|
189
|
+
const changedTitle = finalConfigs.find((x) => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_NAME)?.value;
|
|
190
|
+
const changedDescription = finalConfigs.find(
|
|
191
|
+
(x) => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_DESCRIPTION
|
|
192
|
+
)?.value;
|
|
193
|
+
|
|
194
|
+
if (changedTitle || changedDescription) {
|
|
195
|
+
await states.blocklet.updateBlocklet(rootDid, {
|
|
196
|
+
meta: {
|
|
197
|
+
...blocklet.meta,
|
|
198
|
+
title: changedTitle || blocklet.meta.title,
|
|
199
|
+
description: changedDescription || blocklet.meta.description,
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// chain config
|
|
206
|
+
await manager._ensureAppChainConfig(rootMetaDid, finalConfigs);
|
|
207
|
+
|
|
208
|
+
await manager._updateBlockletEnvironment(rootDid);
|
|
209
|
+
|
|
210
|
+
// response
|
|
211
|
+
const newState = await manager.getBlocklet(rootDid);
|
|
212
|
+
|
|
213
|
+
if (willAppSkChange && !skipDidDocument) {
|
|
214
|
+
await manager._updateDidDocument(newState);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (!skipEmitEvents) {
|
|
218
|
+
if (!childDid && !finalConfigs.some((x) => x.key === BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_SK)) {
|
|
219
|
+
await manager.configSynchronizer.throttledSyncAppConfig(blocklet.meta.did);
|
|
220
|
+
manager.emit(BlockletInternalEvents.appConfigChanged, {
|
|
221
|
+
appDid: rootDid,
|
|
222
|
+
configs: finalConfigs.map((x) => ({ key: x.key, value: x.value })),
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const serverSk = (await states.node.read()).sk;
|
|
227
|
+
if (childDid) {
|
|
228
|
+
const configs = JSON.stringify(finalConfigs.map((x) => ({ key: x.key, value: x.value })));
|
|
229
|
+
await manager.configSynchronizer.syncComponentConfig(childDid, rootDid, { serverSk });
|
|
230
|
+
|
|
231
|
+
manager.emit(BlockletInternalEvents.componentConfigChanged, {
|
|
232
|
+
appDid: rootDid,
|
|
233
|
+
componentDid: childDid,
|
|
234
|
+
configs: encrypt(configs, getComponentApiKey({ serverSk, app: ancestors[0], component: blocklet }), childDid),
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// broadcast shared configs to all components through app channel
|
|
238
|
+
const sharedConfigs = finalConfigs.filter((x) => x.shared);
|
|
239
|
+
if (sharedConfigs.length) {
|
|
240
|
+
manager.emit(BlockletInternalEvents.appConfigChanged, {
|
|
241
|
+
appDid: rootDid,
|
|
242
|
+
configs: sharedConfigs.map((x) => ({ key: x.key, value: x.value })),
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
manager.emit(BlockletEvents.updated, { ...newState, context });
|
|
248
|
+
|
|
249
|
+
try {
|
|
250
|
+
const observableConfigs = [
|
|
251
|
+
BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_URL,
|
|
252
|
+
BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_NAME,
|
|
253
|
+
BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_DESCRIPTION,
|
|
254
|
+
BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO,
|
|
255
|
+
BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO_SQUARE,
|
|
256
|
+
BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO_SQUARE_DARK,
|
|
257
|
+
BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO_RECT,
|
|
258
|
+
BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO_RECT_DARK,
|
|
259
|
+
BLOCKLET_CONFIGURABLE_KEY.BLOCKLET_APP_LOGO_FAVICON,
|
|
260
|
+
];
|
|
261
|
+
|
|
262
|
+
const shouldSendWalletNotification = observableConfigs.some((x) => finalConfigs.some((y) => y.key === x));
|
|
263
|
+
|
|
264
|
+
if (shouldSendWalletNotification) {
|
|
265
|
+
// notify launcher config changed
|
|
266
|
+
launcher.notifyBlockletUpdated(blocklet);
|
|
267
|
+
if (shouldSyncFederated(blocklet)) {
|
|
268
|
+
try {
|
|
269
|
+
// 通知站点群更新信息
|
|
270
|
+
manager.syncFederatedConfig({ did });
|
|
271
|
+
} catch (err) {
|
|
272
|
+
logger.error('Failed to sync federated config after updated config', { did, error: err });
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const receiverUsers = await manager.teamManager.getOwnerAndAdminUsers(newState.appPid, true);
|
|
278
|
+
const receivers = receiverUsers.map((x) => x.did);
|
|
279
|
+
|
|
280
|
+
if (shouldSendWalletNotification && receivers.length) {
|
|
281
|
+
const nodeInfo = await states.node.read();
|
|
282
|
+
const blockletInfo = getBlockletInfo(newState, nodeInfo.sk);
|
|
283
|
+
const { actions, attachments } = await getWalletAppNotification(newState, blockletInfo);
|
|
284
|
+
|
|
285
|
+
const sender = {
|
|
286
|
+
appDid: blockletInfo.wallet.address,
|
|
287
|
+
appSk: blockletInfo.wallet.secretKey,
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
await sendToUser(
|
|
291
|
+
receivers,
|
|
292
|
+
{
|
|
293
|
+
title: 'Blocklet Config Changed',
|
|
294
|
+
body: `Blocklet ${blockletInfo.name} config changed`,
|
|
295
|
+
attachments,
|
|
296
|
+
actions,
|
|
297
|
+
},
|
|
298
|
+
sender
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
} catch (error) {
|
|
302
|
+
logger.error('Failed to send wallet notification after updated config', { did, error });
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return newState;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
module.exports = {
|
|
310
|
+
config,
|
|
311
|
+
};
|