@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.
Files changed (66) hide show
  1. package/lib/api/team/access-key-manager.js +104 -0
  2. package/lib/api/team/invitation-manager.js +461 -0
  3. package/lib/api/team/notification-manager.js +189 -0
  4. package/lib/api/team/oauth-manager.js +60 -0
  5. package/lib/api/team/org-crud-manager.js +202 -0
  6. package/lib/api/team/org-manager.js +56 -0
  7. package/lib/api/team/org-member-manager.js +403 -0
  8. package/lib/api/team/org-query-manager.js +126 -0
  9. package/lib/api/team/org-resource-manager.js +186 -0
  10. package/lib/api/team/passport-manager.js +670 -0
  11. package/lib/api/team/rbac-manager.js +335 -0
  12. package/lib/api/team/session-manager.js +540 -0
  13. package/lib/api/team/store-manager.js +198 -0
  14. package/lib/api/team/tag-manager.js +230 -0
  15. package/lib/api/team/user-auth-manager.js +132 -0
  16. package/lib/api/team/user-manager.js +78 -0
  17. package/lib/api/team/user-query-manager.js +299 -0
  18. package/lib/api/team/user-social-manager.js +354 -0
  19. package/lib/api/team/user-update-manager.js +224 -0
  20. package/lib/api/team/verify-code-manager.js +161 -0
  21. package/lib/api/team.js +439 -3287
  22. package/lib/blocklet/manager/disk/auth-manager.js +68 -0
  23. package/lib/blocklet/manager/disk/backup-manager.js +288 -0
  24. package/lib/blocklet/manager/disk/cleanup-manager.js +157 -0
  25. package/lib/blocklet/manager/disk/component-manager.js +83 -0
  26. package/lib/blocklet/manager/disk/config-manager.js +191 -0
  27. package/lib/blocklet/manager/disk/controller-manager.js +64 -0
  28. package/lib/blocklet/manager/disk/delete-reset-manager.js +328 -0
  29. package/lib/blocklet/manager/disk/download-manager.js +96 -0
  30. package/lib/blocklet/manager/disk/env-config-manager.js +311 -0
  31. package/lib/blocklet/manager/disk/federated-manager.js +651 -0
  32. package/lib/blocklet/manager/disk/hook-manager.js +124 -0
  33. package/lib/blocklet/manager/disk/install-component-manager.js +95 -0
  34. package/lib/blocklet/manager/disk/install-core-manager.js +448 -0
  35. package/lib/blocklet/manager/disk/install-download-manager.js +313 -0
  36. package/lib/blocklet/manager/disk/install-manager.js +36 -0
  37. package/lib/blocklet/manager/disk/install-upgrade-manager.js +340 -0
  38. package/lib/blocklet/manager/disk/job-manager.js +467 -0
  39. package/lib/blocklet/manager/disk/lifecycle-manager.js +26 -0
  40. package/lib/blocklet/manager/disk/notification-manager.js +343 -0
  41. package/lib/blocklet/manager/disk/query-manager.js +562 -0
  42. package/lib/blocklet/manager/disk/settings-manager.js +507 -0
  43. package/lib/blocklet/manager/disk/start-manager.js +611 -0
  44. package/lib/blocklet/manager/disk/stop-restart-manager.js +292 -0
  45. package/lib/blocklet/manager/disk/update-manager.js +153 -0
  46. package/lib/blocklet/manager/disk.js +669 -5796
  47. package/lib/blocklet/manager/helper/blue-green-start-blocklet.js +5 -0
  48. package/lib/blocklet/manager/lock.js +18 -0
  49. package/lib/event/index.js +28 -24
  50. package/lib/router/helper.js +5 -1
  51. package/lib/util/blocklet/app-utils.js +192 -0
  52. package/lib/util/blocklet/blocklet-loader.js +258 -0
  53. package/lib/util/blocklet/config-manager.js +232 -0
  54. package/lib/util/blocklet/did-document.js +240 -0
  55. package/lib/util/blocklet/environment.js +555 -0
  56. package/lib/util/blocklet/health-check.js +449 -0
  57. package/lib/util/blocklet/install-utils.js +365 -0
  58. package/lib/util/blocklet/logo.js +57 -0
  59. package/lib/util/blocklet/meta-utils.js +269 -0
  60. package/lib/util/blocklet/port-manager.js +141 -0
  61. package/lib/util/blocklet/process-manager.js +504 -0
  62. package/lib/util/blocklet/runtime-info.js +105 -0
  63. package/lib/util/blocklet/validation.js +418 -0
  64. package/lib/util/blocklet.js +98 -3066
  65. package/lib/util/wallet-app-notification.js +40 -0
  66. package/package.json +22 -22
@@ -0,0 +1,292 @@
1
+ /* eslint-disable no-await-in-loop */
2
+ const logger = require('@abtnode/logger')('@abtnode/core:blocklet:manager:stop-restart');
3
+ const {
4
+ BlockletEvents,
5
+ BlockletInternalEvents,
6
+ SUSPENDED_REASON,
7
+ BLOCKLET_CONTROLLER_STATUS,
8
+ BlockletStatus,
9
+ } = require('@blocklet/constant');
10
+ const { getDisplayName, isExternalBlocklet } = require('@blocklet/meta/lib/util');
11
+
12
+ const states = require('../../../states');
13
+ const launcher = require('../../../util/launcher');
14
+ const hooks = require('../../hooks');
15
+ const {
16
+ stopBlockletProcess,
17
+ reloadBlockletProcess,
18
+ getRuntimeEnvironments,
19
+ shouldSkipComponent,
20
+ getComponentNamesWithVersion,
21
+ getHookArgs,
22
+ } = require('../../../util/blocklet');
23
+ const checkNeedRunDocker = require('../../../util/docker/check-need-run-docker');
24
+ const { dockerExec } = require('../../../util/docker/docker-exec');
25
+
26
+ /**
27
+ * Stop blocklet
28
+ */
29
+ async function stop(
30
+ manager,
31
+ { did, updateStatus = true, silent = false, componentDids, reason, operator: _operator },
32
+ context
33
+ ) {
34
+ const operator = _operator || context?.user?.did;
35
+ logger.info('stop blocklet', { did, componentDids, updateStatus, silent, operator });
36
+
37
+ const blocklet = await manager.getBlocklet(did);
38
+ const { processId } = blocklet.env;
39
+
40
+ if (updateStatus) {
41
+ const doc = await states.blocklet.setBlockletStatus(did, BlockletStatus.stopping, {
42
+ componentDids,
43
+ operator,
44
+ isGreenAndBlue: true,
45
+ });
46
+ blocklet.status = BlockletStatus.stopping;
47
+ manager.emit(BlockletEvents.statusChange, doc);
48
+ }
49
+
50
+ try {
51
+ const nodeInfo = await states.node.read();
52
+ const nodeEnvironments = await states.node.getEnvironments(nodeInfo);
53
+ await stopBlockletProcess(blocklet, {
54
+ preStop: async (b, { ancestors }) => {
55
+ const nextEnv = getRuntimeEnvironments(b, nodeEnvironments, ancestors);
56
+ const needRunDocker = await checkNeedRunDocker(b.meta, nextEnv, nodeInfo, isExternalBlocklet(blocklet));
57
+ const hookArgs = getHookArgs(b);
58
+ if (needRunDocker) {
59
+ const script = b.meta.scripts?.preStop;
60
+ if (script) {
61
+ return dockerExec({
62
+ blocklet,
63
+ meta: b.meta,
64
+ script,
65
+ env: nextEnv,
66
+ hookName: 'preStop',
67
+ nodeInfo,
68
+ ...hookArgs,
69
+ });
70
+ }
71
+ return null;
72
+ }
73
+ return hooks.preStop(b.meta.title, {
74
+ appDir: b.env.appDir,
75
+ hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
76
+ env: nextEnv,
77
+ did, // root blocklet did
78
+ notification: states.notification,
79
+ context,
80
+ exitOnError: false,
81
+ silent,
82
+ teamManager: manager.teamManager,
83
+ ...hookArgs,
84
+ });
85
+ },
86
+ componentDids,
87
+ isStopGreenAndBlue: true,
88
+ });
89
+ } catch (error) {
90
+ logger.error('Failed to stop blocklet', { error, did });
91
+ if (updateStatus) {
92
+ const res = await states.blocklet.setBlockletStatus(did, BlockletStatus.error, {
93
+ componentDids,
94
+ operator,
95
+ isGreenAndBlue: true,
96
+ });
97
+ manager.emit(BlockletEvents.statusChange, res);
98
+ }
99
+ throw error;
100
+ }
101
+
102
+ logger.info('blocklet stopped successfully', { processId, did });
103
+
104
+ launcher.notifyBlockletStopped(blocklet);
105
+
106
+ if (updateStatus) {
107
+ const res = await states.blocklet.setBlockletStatus(did, BlockletStatus.stopped, {
108
+ componentDids,
109
+ operator,
110
+ isGreenAndBlue: true,
111
+ });
112
+ // send notification to websocket channel
113
+ manager.emit(BlockletEvents.statusChange, res);
114
+
115
+ // send notification to wallet
116
+ manager.emit(BlockletEvents.stopped, { ...res, componentDids });
117
+
118
+ manager.emit(BlockletInternalEvents.componentStopped, {
119
+ appDid: blocklet.appDid,
120
+ components: componentDids?.length
121
+ ? componentDids.map((x) => ({ did: x }))
122
+ : blocklet.children.map((x) => ({ did: x.meta.did })),
123
+ });
124
+ manager.configSynchronizer.throttledSyncAppConfig(blocklet.meta.did);
125
+
126
+ let description = `${
127
+ componentDids?.length ? getComponentNamesWithVersion(blocklet, componentDids) : 'All components'
128
+ } is successfully stopped for ${getDisplayName(blocklet)}.`;
129
+
130
+ if (reason === SUSPENDED_REASON.expired) {
131
+ description = `${description} Reason: The subscription has expired.`;
132
+ }
133
+ const stopLength = componentDids?.length || 0;
134
+ manager._createNotification(did, {
135
+ title: `${stopLength > 1 ? `${stopLength} components` : 'Component'} stopped successfully for ${getDisplayName(blocklet)}`,
136
+ description,
137
+ entityType: 'blocklet',
138
+ entityId: did,
139
+ severity: 'success',
140
+ });
141
+
142
+ return res;
143
+ }
144
+
145
+ return blocklet;
146
+ }
147
+
148
+ /**
149
+ * Restart blocklet
150
+ */
151
+ async function restart(manager, { did, componentDids, operator: _operator }, context) {
152
+ const operator = _operator || context?.user?.did;
153
+ logger.info('restart blocklet', { did, operator });
154
+ const blocklet = await manager.getBlocklet(did);
155
+ await manager.checkControllerStatus(blocklet, 'restart');
156
+
157
+ const result = await states.blocklet.getBlocklet(did);
158
+ const dids = componentDids?.length
159
+ ? componentDids
160
+ : result.children
161
+ .filter((x) => x.status === BlockletStatus.running || x.greenStatus === BlockletStatus.running)
162
+ .map((x) => x.meta.did);
163
+ manager.emit(BlockletEvents.statusChange, result);
164
+
165
+ const ticket = manager.startQueue.push({
166
+ entity: 'blocklet',
167
+ action: 'restart',
168
+ id: `${did}/${(dids || []).join(',')}`,
169
+ did,
170
+ componentDids: dids,
171
+ operator,
172
+ context,
173
+ });
174
+ ticket.on('failed', (err) => {
175
+ logger.error('failed to restart blocklet', { did, error: err });
176
+
177
+ const description = `${getComponentNamesWithVersion(result, componentDids)} restart failed for ${getDisplayName(
178
+ result
179
+ )}: ${err.message || 'queue exception'}`;
180
+ const upgradeLength = dids.length;
181
+ manager._createNotification(did, {
182
+ title: `${upgradeLength > 1 ? `${upgradeLength} components` : 'Component'} failed to restart for ${getDisplayName(result)}`,
183
+ description,
184
+ entityType: 'blocklet',
185
+ entityId: did,
186
+ severity: 'error',
187
+ });
188
+ });
189
+
190
+ return result;
191
+ }
192
+
193
+ /**
194
+ * Reload blocklet
195
+ */
196
+ async function reload(manager, { did, componentDids: list }) {
197
+ const blocklet = await manager.getBlocklet(did);
198
+ await manager.checkControllerStatus(blocklet, 'reload');
199
+
200
+ const componentDids = (blocklet.children || [])
201
+ .filter((x) => x.status === BlockletStatus.running)
202
+ .filter((x) => !shouldSkipComponent(x.meta.did, list))
203
+ .map((x) => x.meta.did);
204
+
205
+ if (!componentDids.length) {
206
+ throw new Error('No running component found');
207
+ }
208
+
209
+ try {
210
+ await reloadBlockletProcess(blocklet, { componentDids });
211
+ const res = await states.blocklet.setBlockletStatus(did, BlockletStatus.running, { componentDids });
212
+ logger.info('blocklet reload successfully', { did, componentDids });
213
+ manager.emit(BlockletEvents.statusChange, res);
214
+ return res;
215
+ } catch (error) {
216
+ logger.error('Failed to reload blocklet', { error, did, componentDids });
217
+ throw error;
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Stop expired blocklets
223
+ */
224
+ async function stopExpiredBlocklets(manager) {
225
+ try {
226
+ logger.info('start checking expired blocklet');
227
+ const blockletExtras = await states.blockletExtras.find(
228
+ {
229
+ controller: {
230
+ $exists: true,
231
+ },
232
+ },
233
+ { did: 1, meta: 1, controller: 1 }
234
+ );
235
+
236
+ if (blockletExtras.length === 0) {
237
+ logger.info('no serverless blocklet');
238
+ return;
239
+ }
240
+
241
+ logger.info('serverless blocklet count', { count: blockletExtras.length });
242
+
243
+ for (const data of blockletExtras) {
244
+ try {
245
+ const { did } = data;
246
+ const isExpired = await launcher.isBlockletExpired(did, data.controller);
247
+
248
+ if (isExpired) {
249
+ logger.info('the blocklet already expired and will be stopped', {
250
+ blockletDid: did,
251
+ nftId: data.controller.nftId,
252
+ });
253
+
254
+ // 如果 Blocklet 没停止, 先停止
255
+ const blocklet = await states.blocklet.getBlocklet(did);
256
+ if (blocklet.status !== BlockletStatus.stopped) {
257
+ await stop(manager, { did, reason: SUSPENDED_REASON.expired });
258
+ logger.info('the expired blocklet is stopped', { did, blockletDid: did });
259
+ }
260
+
261
+ await states.blockletExtras.updateByDid(did, {
262
+ controller: {
263
+ ...data.controller,
264
+ status: {
265
+ value: BLOCKLET_CONTROLLER_STATUS.suspended,
266
+ reason: SUSPENDED_REASON.expired,
267
+ },
268
+ },
269
+ });
270
+ logger.info('the expired blocklet is stopped', { did });
271
+ }
272
+ } catch (error) {
273
+ logger.error('stop expired blocklet failed', {
274
+ blockletDid: data.did,
275
+ nftId: data.controller?.nftId,
276
+ error,
277
+ });
278
+ }
279
+ }
280
+
281
+ logger.info('check expired external blocklet end');
282
+ } catch (error) {
283
+ logger.error('check expired external blocklet failed', { error });
284
+ }
285
+ }
286
+
287
+ module.exports = {
288
+ stop,
289
+ restart,
290
+ reload,
291
+ stopExpiredBlocklets,
292
+ };
@@ -0,0 +1,153 @@
1
+ const logger = require('@abtnode/logger')('@abtnode/core:blocklet:manager:update');
2
+ const md5 = require('@abtnode/util/lib/md5');
3
+ const { WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
4
+ const { BlockletStatus } = require('@blocklet/constant');
5
+ const { getBlockletInfo } = require('@blocklet/meta/lib/info');
6
+ const { getDisplayName } = require('@blocklet/meta/lib/util');
7
+
8
+ const states = require('../../../states');
9
+ const launcher = require('../../../util/launcher');
10
+ const { shouldJobBackoff } = require('../../../util');
11
+ const UpgradeComponents = require('../helper/upgrade-components');
12
+
13
+ /**
14
+ * Check for component updates
15
+ * @param {Object} manager - BlockletManager instance
16
+ * @param {Object} params
17
+ * @param {string} params.did - Blocklet DID
18
+ * @returns {Promise<void>}
19
+ */
20
+ async function _onCheckForComponentUpdate(manager, { did }) {
21
+ if (shouldJobBackoff()) {
22
+ logger.warn('Check for component update is not available when blocklet server is starting.');
23
+ return;
24
+ }
25
+
26
+ const blocklet = await manager.getBlocklet(did);
27
+ if (blocklet.status === BlockletStatus.stopped) {
28
+ logger.warn('Check for component update is not available when blocklet is stopped.');
29
+ return;
30
+ }
31
+
32
+ const list = await UpgradeComponents.check({ did, states });
33
+ if (!list || !list.updateList?.length) {
34
+ return;
35
+ }
36
+ const componentDids = list.updateList.map((item) => item.meta.did);
37
+ const updateList = list.updateList.map((item) => {
38
+ return { title: item.meta.title, description: item.meta.description, version: item.meta.version };
39
+ });
40
+
41
+ const checkUpdateMd5 = md5(JSON.stringify(updateList));
42
+ const oldMd5 = await states.blockletExtras.getSettings(did, 'checkUpdateMd5', '');
43
+ // notification has been sent, no more
44
+ if (checkUpdateMd5 === oldMd5) {
45
+ return;
46
+ }
47
+
48
+ const firstComponent = updateList[0];
49
+ const blockletTitle = getDisplayName(blocklet);
50
+
51
+ const description = {
52
+ en: `${blockletTitle} has components with a new version: ${firstComponent.title} ${firstComponent.version} ${
53
+ updateList.length > 1 ? 'and more...' : '.'
54
+ }`,
55
+ zh: `${blockletTitle} 的组件有新版本: ${firstComponent.title} ${updateList.length > 1 ? '等等...' : '.'}`,
56
+ };
57
+ const title = {
58
+ en: `${blockletTitle} has components with a new version`,
59
+ zh: `${blockletTitle} 的组件有新版本`,
60
+ };
61
+ const body = {
62
+ en: `${blockletTitle} has new versions of the following components:`,
63
+ zh: `${blockletTitle} 以下组件有新版:`,
64
+ };
65
+ const button = {
66
+ en: 'Upgrade to new version',
67
+ zh: '升级到新版本',
68
+ };
69
+
70
+ const action = `/blocklets/${did}/components?checkUpdate=1`;
71
+ const blockletDashboardAction = `${WELLKNOWN_SERVICE_PATH_PREFIX}/admin/components?checkUpdate=1`;
72
+ const users = await manager.teamManager.getOwnerAndAdminUsers(did, true);
73
+ const nodeInfo = await states.node.read();
74
+ const { wallet } = getBlockletInfo(blocklet, nodeInfo.sk);
75
+
76
+ const attachments = [
77
+ {
78
+ type: 'section',
79
+ fields: updateList
80
+ .slice(0, 3)
81
+ .map((item) => {
82
+ return [
83
+ {
84
+ type: 'text',
85
+ data: { type: 'plain', color: '#9397A1', text: item.title },
86
+ },
87
+ {
88
+ type: 'text',
89
+ data: { type: 'plain', text: item.version },
90
+ },
91
+ ];
92
+ })
93
+ .flat(),
94
+ },
95
+ ];
96
+
97
+ try {
98
+ await manager._sendAllMessageToUser({
99
+ did,
100
+ blocklet,
101
+ title,
102
+ body,
103
+ button,
104
+ attachments,
105
+ description,
106
+ action,
107
+ blockletDashboardAction,
108
+ sender: {
109
+ appDid: wallet.address,
110
+ appSk: wallet.secretKey,
111
+ },
112
+ users,
113
+ componentDids,
114
+ });
115
+ await states.blockletExtras.setSettings(did, { checkUpdateMd5 });
116
+ } catch (err) {
117
+ logger.error('send checked update email failed', { error: err });
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Report component usage
123
+ * @param {Object} manager - BlockletManager instance
124
+ * @param {Object} params
125
+ * @param {string} params.did - Blocklet DID
126
+ * @param {Array<string>} params.componentDids - Component DIDs
127
+ * @param {string} params.eventType - Event type
128
+ * @param {string} params.time - Time
129
+ * @returns {Promise<void>}
130
+ */
131
+ async function _reportComponentUsage(manager, { did, componentDids, eventType, time }) {
132
+ try {
133
+ logger.info('start report component usage', { did, componentDids, eventType });
134
+
135
+ const blocklet = await manager.getBlocklet(did);
136
+ await launcher.reportComponentsEvent({
137
+ blocklet,
138
+ dids: componentDids,
139
+ type: eventType,
140
+ time: time || new Date().toISOString(),
141
+ });
142
+
143
+ logger.info('report component usage success', { did, componentDids, eventType });
144
+ } catch (error) {
145
+ logger.error('report component usage failed', { did, componentDids, eventType, error });
146
+ throw error; // 一定要 throw 出去,否则会导致队列任务不会重试
147
+ }
148
+ }
149
+
150
+ module.exports = {
151
+ _onCheckForComponentUpdate,
152
+ _reportComponentUsage,
153
+ };