@abtnode/core 1.16.52-beta-20251003-083412-fdfc4e36 → 1.16.52-beta-20251008-091027-c46c73e3

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.
@@ -0,0 +1,301 @@
1
+ /* eslint-disable no-await-in-loop */
2
+ const logger = require('@abtnode/logger')('@abtnode/core:blocklet-manager:blue-green');
3
+ const { BlockletStatus, BlockletGroup, BlockletEvents, BlockletInternalEvents } = require('@blocklet/constant');
4
+ const {
5
+ hasRunnableComponent,
6
+ getDisplayName,
7
+ isExternalBlocklet,
8
+ forEachBlockletSync,
9
+ getComponentMissingConfigs,
10
+ } = require('@blocklet/meta/lib/util');
11
+ const { getBlockletEngine, hasStartEngine } = require('@blocklet/meta/lib/engine');
12
+ const { getComponentsInternalInfo } = require('@blocklet/meta/lib/blocklet');
13
+ const {
14
+ forEachBlocklet,
15
+ validateBlocklet,
16
+ validateBlockletChainInfo,
17
+ ensureAppPortsNotOccupied,
18
+ getHealthyCheckTimeout,
19
+ getHookArgs,
20
+ shouldSkipComponent,
21
+ } = require('../../../util/blocklet');
22
+ const { startBlockletProcess } = require('../../../util/blocklet');
23
+ const hooks = require('../../hooks');
24
+ const checkNeedRunDocker = require('../../../util/docker/check-need-run-docker');
25
+ const { blueGreenGetComponentIds } = require('./blue-green-get-componentids');
26
+ const { dockerExec } = require('../../../util/docker/docker-exec');
27
+ const { isDockerOnlySingleInstance } = require('../../../util/docker/is-docker-only-single-instances');
28
+
29
+ /**
30
+ * 绿(Green)环境:指一个并行的、与蓝环境几乎一模一样的环境,用来部署新的版本。新代码、新配置都会先部署到绿环境中。
31
+ *
32
+ * @param {Object} params - 启动参数
33
+ * @param {string} params.did - blocklet DID
34
+ * @param {Array<string>} params.componentDids - 组件 DID 列表
35
+ * @param {string} params.operator - 操作者
36
+ * @param {Object} context - 上下文信息
37
+ * @param {Object} manager - blocklet 管理器实例
38
+ * @param {Object} states - 状态管理器
39
+ * @returns {Promise<Object>} 返回启动后的 blocklet 对象
40
+ */
41
+ const blueGreenStartBlocklet = async (
42
+ { did, componentDids, operator: _operator, ignoreErrorNotification },
43
+ context,
44
+ manager,
45
+ states
46
+ ) => {
47
+ const operator = _operator || context?.user?.did;
48
+ const throwOnError = true;
49
+ const checkHealthImmediately = true;
50
+ const e2eMode = false;
51
+
52
+ logger.info('start green blocklet (blue-green deployment)', {
53
+ did,
54
+ componentDids,
55
+ throwOnError,
56
+ checkHealthImmediately,
57
+ e2eMode,
58
+ operator,
59
+ });
60
+
61
+ // 获取并验证 blocklet
62
+ const blocklet1 = await manager.ensureBlocklet(did, { e2eMode });
63
+ did = blocklet1.meta.did; // eslint-disable-line no-param-reassign
64
+
65
+ // 验证组件需求和引擎
66
+ await validateBlocklet(blocklet1);
67
+ await validateBlockletChainInfo(blocklet1);
68
+
69
+ if (!hasRunnableComponent(blocklet1)) {
70
+ throw new Error('No runnable component found');
71
+ }
72
+
73
+ const customerDockerUseVolumeComponentIds = [];
74
+ const otherComponentIds = [];
75
+ await forEachBlockletSync(blocklet1, (b) => {
76
+ if (!componentDids.includes(b.meta.did)) {
77
+ return;
78
+ }
79
+ if (isDockerOnlySingleInstance(b.meta)) {
80
+ customerDockerUseVolumeComponentIds.push(b.meta.did);
81
+ } else {
82
+ otherComponentIds.push(b.meta.did);
83
+ }
84
+ });
85
+
86
+ if (customerDockerUseVolumeComponentIds.length) {
87
+ await manager.stop(
88
+ { did, componentDids: customerDockerUseVolumeComponentIds, updateStatus: false, operator },
89
+ context
90
+ );
91
+ await manager.start({ did, componentDids: customerDockerUseVolumeComponentIds, operator }, context);
92
+ }
93
+
94
+ // 分类组件 ID
95
+ const entryComponentIds = [];
96
+ const nonEntryComponentIds = [];
97
+ const componentDidsSet = new Set(otherComponentIds);
98
+
99
+ await forEachBlocklet(
100
+ blocklet1,
101
+ (b) => {
102
+ if (!componentDidsSet.has(b.meta.did)) {
103
+ return;
104
+ }
105
+
106
+ if (b.meta.group === BlockletGroup.gateway) {
107
+ nonEntryComponentIds.push(b.meta.did);
108
+ return;
109
+ }
110
+ const engine = getBlockletEngine(b.meta);
111
+ if (engine.interpreter === 'blocklet') {
112
+ nonEntryComponentIds.push(b.meta.did);
113
+ return;
114
+ }
115
+ if (!hasStartEngine(b.meta)) {
116
+ nonEntryComponentIds.push(b.meta.did);
117
+ return;
118
+ }
119
+ entryComponentIds.push(b.meta.did);
120
+ },
121
+ { parallel: true, concurrencyLimit: 4 }
122
+ );
123
+
124
+ if (nonEntryComponentIds.length) {
125
+ await states.blocklet.setBlockletStatus(did, BlockletStatus.running, {
126
+ componentDids: nonEntryComponentIds,
127
+ operator,
128
+ isGreen: true,
129
+ });
130
+ }
131
+
132
+ if (!entryComponentIds.length) {
133
+ await manager.emit(BlockletEvents.started, {
134
+ ...blocklet1,
135
+ componentDids: nonEntryComponentIds,
136
+ });
137
+ return;
138
+ }
139
+
140
+ // check required config
141
+ try {
142
+ for (const component of blocklet1.children) {
143
+ if (!entryComponentIds.includes(component.meta.did)) {
144
+ continue;
145
+ }
146
+ if (!shouldSkipComponent(component.meta.did, entryComponentIds)) {
147
+ const missingProps = getComponentMissingConfigs(component, blocklet1);
148
+ if (missingProps.length) {
149
+ throw new Error(
150
+ `Missing required configuration to start ${component.meta.title}: ${missingProps.map((x) => x.key).join(',')}`
151
+ );
152
+ }
153
+ }
154
+ }
155
+ } catch (error) {
156
+ const description = `Green environment start failed for ${getDisplayName(blocklet1)}: ${error.message}`;
157
+ if (!ignoreErrorNotification) {
158
+ manager._createNotification(did, {
159
+ title: 'Blue-Green Deployment: Green Start Failed',
160
+ description,
161
+ entityType: 'blocklet',
162
+ entityId: did,
163
+ severity: 'error',
164
+ });
165
+ }
166
+ return;
167
+ }
168
+
169
+ const blueGreenComponentIds = await blueGreenGetComponentIds(blocklet1, entryComponentIds);
170
+
171
+ // eslint-disable-next-line no-unreachable-loop
172
+ for (const item of blueGreenComponentIds) {
173
+ if (!item.componentDids.length) {
174
+ continue;
175
+ }
176
+ const nextBlocklet = await ensureAppPortsNotOccupied({
177
+ blocklet: blocklet1,
178
+ componentDids: item.componentDids,
179
+ states,
180
+ manager,
181
+ isGreen: item.changeToGreen,
182
+ });
183
+
184
+ try {
185
+ const doc1 = await states.blocklet.setBlockletStatus(did, BlockletStatus.starting, {
186
+ componentDids: item.componentDids,
187
+ operator,
188
+ isGreen: item.changeToGreen,
189
+ });
190
+ nextBlocklet.greenStatus = BlockletStatus.starting;
191
+ manager.emit(BlockletEvents.statusChange, doc1);
192
+
193
+ const nodeInfo = await states.node.read();
194
+ const nodeEnvironments = await states.node.getEnvironments();
195
+
196
+ // 钩子函数设置
197
+ const getHookFn =
198
+ (hookName) =>
199
+ async (b, { env }) => {
200
+ const hookArgs = getHookArgs(b);
201
+ const needRunDocker = await checkNeedRunDocker(b.meta, env, nodeInfo, isExternalBlocklet(nextBlocklet));
202
+ if (!b.meta.scripts?.[hookName]) {
203
+ return null;
204
+ }
205
+ if (needRunDocker) {
206
+ return dockerExec({
207
+ blocklet: nextBlocklet,
208
+ meta: b.meta,
209
+ script: b.meta.scripts?.[hookName],
210
+ hookName,
211
+ nodeInfo,
212
+ env,
213
+ ...hookArgs,
214
+ });
215
+ }
216
+ return hooks[hookName](b, {
217
+ appDir: b.env.appDir,
218
+ hooks: Object.assign(b.meta.hooks || {}, b.meta.scripts || {}),
219
+ env,
220
+ did, // root blocklet did,
221
+ teamManager: manager.teamManager,
222
+ ...hookArgs,
223
+ });
224
+ };
225
+
226
+ await startBlockletProcess(nextBlocklet, {
227
+ ...context,
228
+ preFlight: getHookFn('preFlight'),
229
+ preStart: getHookFn('preStart'),
230
+ postStart: getHookFn('postStart'),
231
+ nodeEnvironments,
232
+ nodeInfo,
233
+ e2eMode,
234
+ componentDids: item.componentDids,
235
+ configSynchronizer: manager.configSynchronizer,
236
+ isGreen: item.changeToGreen,
237
+ });
238
+
239
+ // 健康检查绿色环境
240
+ const { startTimeout, minConsecutiveTime } = getHealthyCheckTimeout(nextBlocklet, {
241
+ checkHealthImmediately,
242
+ componentDids: item.componentDids,
243
+ });
244
+
245
+ await manager._onCheckIfStarted(
246
+ {
247
+ did,
248
+ context,
249
+ minConsecutiveTime,
250
+ timeout: startTimeout,
251
+ componentDids: item.componentDids,
252
+ },
253
+ { throwOnError: true, isGreen: item.changeToGreen, needUpdateBlueStatus: true }
254
+ );
255
+
256
+ logger.info('Green environment started successfully', {
257
+ did,
258
+ componentDids: item.componentDids,
259
+ });
260
+ } catch (err) {
261
+ const error = Array.isArray(err) ? err[0] : err;
262
+ logger.error('Failed to start green environment', { error, did, title: blocklet1.meta.title });
263
+
264
+ try {
265
+ await manager.deleteProcess({ did, componentDids: item.componentDids, isGreen: item.changeToGreen });
266
+ manager.emit(BlockletEvents.statusChange, blocklet1);
267
+ } catch (cleanupError) {
268
+ logger.error('Failed to cleanup green environment', { cleanupError });
269
+ }
270
+
271
+ const description = `Green environment start failed for ${getDisplayName(blocklet1)}: ${error.message}`;
272
+ if (!ignoreErrorNotification) {
273
+ manager._createNotification(did, {
274
+ title: 'Blue-Green Deployment: Green Start Failed',
275
+ description,
276
+ entityType: 'blocklet',
277
+ entityId: did,
278
+ severity: 'error',
279
+ });
280
+ }
281
+
282
+ if (throwOnError) {
283
+ throw new Error(description);
284
+ }
285
+ throw error;
286
+ }
287
+ }
288
+
289
+ const nextBlocklet = await manager.getBlocklet(did);
290
+ const componentsInfo = getComponentsInternalInfo(nextBlocklet);
291
+ manager.emit(BlockletInternalEvents.componentStarted, {
292
+ appDid: nextBlocklet.appDid,
293
+ components: componentsInfo,
294
+ });
295
+
296
+ manager.emit(BlockletEvents.statusChange, nextBlocklet);
297
+ };
298
+
299
+ module.exports = {
300
+ blueGreenStartBlocklet,
301
+ };
@@ -0,0 +1,18 @@
1
+ const blueGreenUpdateBlockletStatus = async ({ states, did, status, blueGreenComponentIds }) => {
2
+ const outputBlocklet = {};
3
+ await Promise.all(
4
+ blueGreenComponentIds.map(async (item) => {
5
+ if (!item.componentDids.length) {
6
+ return;
7
+ }
8
+ const res = await states.blocklet.setBlockletStatus(did, status, {
9
+ componentDids: item.componentDids,
10
+ isGreen: item.changeToGreen,
11
+ });
12
+ Object.assign(outputBlocklet, res);
13
+ })
14
+ );
15
+ return outputBlocklet;
16
+ };
17
+
18
+ module.exports = { blueGreenUpdateBlockletStatus };
@@ -0,0 +1,191 @@
1
+ /* eslint-disable no-await-in-loop */
2
+ const logger = require('@abtnode/logger')('@abtnode/core:blocklet-manager:upgrade-blue-green');
3
+ const { BlockletStatus, BlockletEvents, BlockletInternalEvents } = require('@blocklet/constant');
4
+ const { INSTALL_ACTIONS, WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
5
+ const { getDisplayName, hasStartEngine } = require('@blocklet/meta/lib/util');
6
+ const { getComponentsInternalInfo } = require('@blocklet/meta/lib/blocklet');
7
+ const { getComponentNamesWithVersion, updateBlockletFallbackLogo } = require('../../../util/blocklet');
8
+ const { blueGreenStartBlocklet } = require('./blue-green-start-blocklet');
9
+
10
+ const blueGreenUpgradeBlocklet = async (
11
+ { newBlocklet, oldBlocklet, componentDids, action, shouldCleanUploadFile, url },
12
+ context,
13
+ manager,
14
+ states
15
+ ) => {
16
+ const { meta, source, deployedFrom, children } = newBlocklet;
17
+ const { did, version, name } = meta;
18
+ const title = getDisplayName(newBlocklet);
19
+
20
+ for (const child of newBlocklet.children) {
21
+ for (const child2 of oldBlocklet.children) {
22
+ if (child && child2 && child.meta.did === child2.meta.did) {
23
+ child.status = child2.status;
24
+ child.greenStatus = child2.greenStatus;
25
+ child.ports = child2.ports;
26
+ child.greenPorts = child2.greenPorts;
27
+ }
28
+ }
29
+ }
30
+
31
+ try {
32
+ await states.blocklet.upgradeBlocklet({ meta, source, deployedFrom, children });
33
+ logger.info('updated blocklet for upgrading', { did, componentDids, source, name });
34
+
35
+ await manager._setConfigsFromMeta(did);
36
+
37
+ let blocklet = await manager.ensureBlocklet(did);
38
+
39
+ await manager._updateBlockletEnvironment(did);
40
+ blocklet = await manager.getBlocklet(did);
41
+
42
+ await manager._runUserHook('preInstall', blocklet, context);
43
+ await manager._runUserHook('postInstall', blocklet, context);
44
+ await manager._runUserHook('preFlight', blocklet, context);
45
+ await manager._runMigration({
46
+ parallel: false,
47
+ did,
48
+ blocklet,
49
+ oldBlocklet,
50
+ componentDids,
51
+ });
52
+
53
+ const runningDids = [];
54
+ const stoppedDids = [];
55
+
56
+ if (action === INSTALL_ACTIONS.INSTALL_COMPONENT) {
57
+ for (const componentDid of componentDids) {
58
+ const component = blocklet.children.find((x) => x.meta.did === componentDid);
59
+ if (!component) {
60
+ continue;
61
+ }
62
+ if (hasStartEngine(component.meta)) {
63
+ stoppedDids.push(componentDid);
64
+ } else {
65
+ runningDids.push(componentDid);
66
+ }
67
+ }
68
+ } else {
69
+ for (const componentDid of componentDids) {
70
+ const oldComponent = oldBlocklet.children.find((x) => x.meta.did === componentDid);
71
+ if (oldComponent?.status === BlockletStatus.running || oldComponent?.greenStatus === BlockletStatus.running) {
72
+ runningDids.push(componentDid);
73
+ } else {
74
+ stoppedDids.push(componentDid);
75
+ }
76
+ }
77
+ }
78
+
79
+ const initialized = !!blocklet.settings?.initialized;
80
+
81
+ if (runningDids.length) {
82
+ if (initialized) {
83
+ await blueGreenStartBlocklet(
84
+ { did, componentDids: runningDids, operator: context?.user?.did, ignoreErrorNotification: true },
85
+ context,
86
+ manager,
87
+ states
88
+ );
89
+ await states.blocklet.setInstalledAt(did);
90
+ } else {
91
+ await states.blocklet.setBlockletStatus(did, BlockletStatus.stopped, {
92
+ componentDids: runningDids,
93
+ isGreenAndBlue: true,
94
+ });
95
+ }
96
+ }
97
+
98
+ if (stoppedDids.length) {
99
+ const status = action === INSTALL_ACTIONS.INSTALL_COMPONENT ? BlockletStatus.installed : BlockletStatus.stopped;
100
+ await states.blocklet.setBlockletStatus(did, status, {
101
+ componentDids: stoppedDids,
102
+ isGreenAndBlue: true,
103
+ });
104
+ }
105
+
106
+ blocklet = await manager.getBlocklet(did, context);
107
+
108
+ await updateBlockletFallbackLogo(blocklet);
109
+
110
+ await manager._updateDependents(did);
111
+
112
+ manager.refreshListCache();
113
+
114
+ manager.configSynchronizer.throttledSyncAppConfig(blocklet);
115
+
116
+ try {
117
+ manager.emit(BlockletEvents.upgraded, { blocklet, context });
118
+
119
+ const isInstallAction = action === INSTALL_ACTIONS.INSTALL_COMPONENT;
120
+ const notificationEvent = isInstallAction ? BlockletEvents.componentInstalled : BlockletEvents.componentUpgraded;
121
+ const actionName = isInstallAction ? 'installed' : 'upgraded';
122
+
123
+ manager.emit(notificationEvent, { ...blocklet, componentDids, oldBlocklet, context });
124
+
125
+ manager._createNotification(did, {
126
+ title: `Component ${actionName} succeed`,
127
+ description: `${getComponentNamesWithVersion(
128
+ newBlocklet,
129
+ componentDids
130
+ )} is ${actionName} successfully for ${title}`,
131
+ action: `/blocklets/${did}/overview`,
132
+ blockletDashboardAction: `${WELLKNOWN_SERVICE_PATH_PREFIX}/admin/blocklets`,
133
+ entityType: 'blocklet',
134
+ entityId: did,
135
+ severity: 'success',
136
+ });
137
+
138
+ if (shouldCleanUploadFile && url) {
139
+ manager._cleanUploadFile(url);
140
+ }
141
+ } catch (error) {
142
+ logger.error('emit upgrade notification failed', { name, version, error });
143
+ }
144
+
145
+ await manager._ensureDeletedChildrenInSettings(blocklet);
146
+
147
+ if (oldBlocklet.status === BlockletStatus.running || oldBlocklet.greenStatus === BlockletStatus.running) {
148
+ manager.emit(
149
+ action === INSTALL_ACTIONS.INSTALL_COMPONENT
150
+ ? BlockletInternalEvents.componentInstalled
151
+ : BlockletInternalEvents.componentUpgraded,
152
+ {
153
+ appDid: blocklet.appDid,
154
+ components: getComponentsInternalInfo(blocklet).filter((c) => componentDids.includes(c.did)),
155
+ }
156
+ );
157
+ }
158
+
159
+ return blocklet;
160
+ } catch (err) {
161
+ logger.error('failed to upgrade blocklet', { did, version, name, error: err });
162
+ manager.configSynchronizer.throttledSyncAppConfig(oldBlocklet);
163
+ await manager._updateDependents(did);
164
+
165
+ const actionName = action === INSTALL_ACTIONS.INSTALL_COMPONENT ? 'install' : 'upgrade';
166
+ const notificationEvent =
167
+ action === INSTALL_ACTIONS.INSTALL_COMPONENT
168
+ ? BlockletEvents.componentInstallFailed
169
+ : BlockletEvents.componentUpgradeFailed;
170
+
171
+ manager.emit(notificationEvent, {
172
+ blocklet: { ...newBlocklet, componentDids, error: { message: err.message } },
173
+ context,
174
+ });
175
+
176
+ manager._createNotification(did, {
177
+ title: `Component ${actionName} failed`,
178
+ description: `${getComponentNamesWithVersion(newBlocklet, componentDids)} ${actionName} failed for ${title}: ${
179
+ err.message
180
+ }.`,
181
+ entityType: 'blocklet',
182
+ entityId: did,
183
+ severity: 'error',
184
+ });
185
+ throw err;
186
+ }
187
+ };
188
+
189
+ module.exports = {
190
+ blueGreenUpgradeBlocklet,
191
+ };
@@ -3,7 +3,7 @@ const cloneDeep = require('@abtnode/util/lib/deep-clone');
3
3
 
4
4
  const logger = require('@abtnode/logger')('@abtnode/core:upgrade-component');
5
5
 
6
- const { BlockletStatus, BlockletEvents } = require('@blocklet/constant');
6
+ const { BlockletEvents } = require('@blocklet/constant');
7
7
  const { INSTALL_ACTIONS } = require('@abtnode/constant');
8
8
  const { parseOptionalComponents } = require('@blocklet/resolver');
9
9
  const {
@@ -127,17 +127,11 @@ const upgrade = async ({ updateId, componentDids, context, states, manager }) =>
127
127
  children: children.map((x) => ({ name: x.meta.name, version: x.meta.version })),
128
128
  });
129
129
 
130
- // new blocklet
131
- const newBlocklet = await states.blocklet.setBlockletStatus(did, BlockletStatus.waiting, { componentDids });
132
-
133
- newBlocklet.children = children;
130
+ const newBlocklet = { ...oldBlocklet, children };
134
131
  await validateBlocklet(newBlocklet);
135
132
 
136
- manager.emit(BlockletEvents.statusChange, newBlocklet);
137
-
138
133
  const action = INSTALL_ACTIONS.UPGRADE_COMPONENT;
139
134
 
140
- // backup rollback data
141
135
  await manager._rollbackCache.backup({ did, action, oldBlocklet });
142
136
 
143
137
  // add to queue
@@ -158,7 +152,6 @@ const upgrade = async ({ updateId, componentDids, context, states, manager }) =>
158
152
  ticket.on('failed', async (err) => {
159
153
  logger.error('queue failed', { entity: 'blocklet', action, did, error: err });
160
154
  await manager._rollback(action, did, oldBlocklet);
161
-
162
155
  manager.emit(BlockletEvents.componentUpgradeFailed, {
163
156
  blocklet: { ...oldBlocklet, componentDids, error: { message: err.message } },
164
157
  context: { ...context, createAuditLog: false },
@@ -730,6 +730,8 @@ module.exports = Object.freeze({
730
730
  'deleteBlockletResponseHeaderPolicy',
731
731
  'deleteBlockletAccessPolicy',
732
732
  'configVault',
733
+ 'removeOrgMember',
734
+ 'deleteOrg',
733
735
  ],
734
736
 
735
737
  // 如果是 multiple tenant 的情况下, 这些白名单不会验证 RBAC
@@ -860,6 +862,7 @@ module.exports = Object.freeze({
860
862
  'https://*.didspaces.com',
861
863
  'https://*.blocklet.dev',
862
864
  'https://domain.didlabs.org',
865
+ 'https://cdn.blocklet.io',
863
866
  ],
864
867
  CSP_SYSTEM_SOURCES: [
865
868
  'https://*.did.abtnet.io',
@@ -38946,7 +38949,7 @@ module.exports = require("zlib");
38946
38949
  /***/ ((module) => {
38947
38950
 
38948
38951
  "use strict";
38949
- module.exports = /*#__PURE__*/JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.51","description":"","main":"lib/index.js","files":["lib"],"scripts":{"lint":"eslint tests lib --ignore-pattern \'tests/assets/*\'","lint:fix":"eslint --fix tests lib","test":"node tools/jest.js","test:disk":"node tools/jest.js tests/blocklet/manager/disk.spec.js","coverage":"npm run test -- --coverage"},"keywords":[],"author":"wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)","license":"Apache-2.0","dependencies":{"@abtnode/analytics":"1.16.51","@abtnode/auth":"1.16.51","@abtnode/certificate-manager":"1.16.51","@abtnode/constant":"1.16.51","@abtnode/cron":"1.16.51","@abtnode/db-cache":"1.16.51","@abtnode/docker-utils":"1.16.51","@abtnode/logger":"1.16.51","@abtnode/models":"1.16.51","@abtnode/queue":"1.16.51","@abtnode/rbac":"1.16.51","@abtnode/router-provider":"1.16.51","@abtnode/static-server":"1.16.51","@abtnode/timemachine":"1.16.51","@abtnode/util":"1.16.51","@aigne/aigne-hub":"^0.10.0","@arcblock/did":"1.25.6","@arcblock/did-connect-js":"1.25.6","@arcblock/did-ext":"1.25.6","@arcblock/did-motif":"^1.1.14","@arcblock/did-util":"1.25.6","@arcblock/event-hub":"1.25.6","@arcblock/jwt":"1.25.6","@arcblock/pm2-events":"^0.0.5","@arcblock/validator":"1.25.6","@arcblock/vc":"1.25.6","@blocklet/constant":"1.16.51","@blocklet/did-space-js":"^1.1.29","@blocklet/env":"1.16.51","@blocklet/error":"^0.2.5","@blocklet/meta":"1.16.51","@blocklet/resolver":"1.16.51","@blocklet/sdk":"1.16.51","@blocklet/server-js":"1.16.51","@blocklet/store":"1.16.51","@blocklet/theme":"^3.1.44","@fidm/x509":"^1.2.1","@ocap/mcrypto":"1.25.6","@ocap/util":"1.25.6","@ocap/wallet":"1.25.6","@slack/webhook":"^5.0.4","archiver":"^7.0.1","axios":"^1.7.9","axon":"^2.0.3","chalk":"^4.1.2","cross-spawn":"^7.0.3","dayjs":"^1.11.13","deep-diff":"^1.0.2","detect-port":"^1.5.1","envfile":"^7.1.0","escape-string-regexp":"^4.0.0","fast-glob":"^3.3.2","filesize":"^10.1.1","flat":"^5.0.2","fs-extra":"^11.2.0","get-port":"^5.1.1","hasha":"^5.2.2","is-base64":"^1.1.0","is-cidr":"4","is-ip":"3","is-url":"^1.2.4","joi":"17.12.2","joi-extension-semver":"^5.0.0","js-yaml":"^4.1.0","kill-port":"^2.0.1","lodash":"^4.17.21","node-stream-zip":"^1.15.0","p-all":"^3.0.0","p-limit":"^3.1.0","p-map":"^4.0.0","p-retry":"^4.6.2","p-wait-for":"^3.2.0","private-ip":"^2.3.4","rate-limiter-flexible":"^5.0.5","read-last-lines":"^1.8.0","semver":"^7.6.3","sequelize":"^6.35.0","shelljs":"^0.8.5","slugify":"^1.6.6","ssri":"^8.0.1","stream-throttle":"^0.1.3","stream-to-promise":"^3.0.0","systeminformation":"^5.23.3","tail":"^2.2.4","tar":"^6.1.11","transliteration":"^2.3.5","ua-parser-js":"^1.0.2","ufo":"^1.5.3","uuid":"^11.1.0","valid-url":"^1.0.9","which":"^2.0.2","xbytes":"^1.8.0"},"devDependencies":{"expand-tilde":"^2.0.2","express":"^4.18.2","jest":"^29.7.0","unzipper":"^0.10.11"},"gitHead":"e5764f753181ed6a7c615cd4fc6682aacf0cb7cd"}');
38952
+ module.exports = /*#__PURE__*/JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.51","description":"","main":"lib/index.js","files":["lib"],"scripts":{"lint":"eslint tests lib --ignore-pattern \'tests/assets/*\'","lint:fix":"eslint --fix tests lib","test":"node tools/jest.js","test:disk":"CI=true npm run test tests/blocklet/manager/disk.spec.js","test:blue":"CI=true npm run test tests/blocklet/manager/disk-blue-green.spec.js","coverage":"npm run test -- --coverage"},"keywords":[],"author":"wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)","license":"Apache-2.0","dependencies":{"@abtnode/analytics":"1.16.51","@abtnode/auth":"1.16.51","@abtnode/certificate-manager":"1.16.51","@abtnode/constant":"1.16.51","@abtnode/cron":"1.16.51","@abtnode/db-cache":"1.16.51","@abtnode/docker-utils":"1.16.51","@abtnode/logger":"1.16.51","@abtnode/models":"1.16.51","@abtnode/queue":"1.16.51","@abtnode/rbac":"1.16.51","@abtnode/router-provider":"1.16.51","@abtnode/static-server":"1.16.51","@abtnode/timemachine":"1.16.51","@abtnode/util":"1.16.51","@aigne/aigne-hub":"^0.10.0","@arcblock/did":"1.25.6","@arcblock/did-connect-js":"1.25.6","@arcblock/did-ext":"1.25.6","@arcblock/did-motif":"^1.1.14","@arcblock/did-util":"1.25.6","@arcblock/event-hub":"1.25.6","@arcblock/jwt":"1.25.6","@arcblock/pm2-events":"^0.0.5","@arcblock/validator":"1.25.6","@arcblock/vc":"1.25.6","@blocklet/constant":"1.16.51","@blocklet/did-space-js":"^1.1.29","@blocklet/env":"1.16.51","@blocklet/error":"^0.2.5","@blocklet/meta":"1.16.51","@blocklet/resolver":"1.16.51","@blocklet/sdk":"1.16.51","@blocklet/server-js":"1.16.51","@blocklet/store":"1.16.51","@blocklet/theme":"^3.1.45","@fidm/x509":"^1.2.1","@ocap/mcrypto":"1.25.6","@ocap/util":"1.25.6","@ocap/wallet":"1.25.6","@slack/webhook":"^5.0.4","archiver":"^7.0.1","axios":"^1.7.9","axon":"^2.0.3","chalk":"^4.1.2","cross-spawn":"^7.0.3","dayjs":"^1.11.13","deep-diff":"^1.0.2","detect-port":"^1.5.1","envfile":"^7.1.0","escape-string-regexp":"^4.0.0","fast-glob":"^3.3.2","filesize":"^10.1.1","flat":"^5.0.2","fs-extra":"^11.2.0","get-port":"^5.1.1","hasha":"^5.2.2","is-base64":"^1.1.0","is-cidr":"4","is-ip":"3","is-url":"^1.2.4","joi":"17.12.2","joi-extension-semver":"^5.0.0","js-yaml":"^4.1.0","kill-port":"^2.0.1","lodash":"^4.17.21","node-stream-zip":"^1.15.0","p-all":"^3.0.0","p-limit":"^3.1.0","p-map":"^4.0.0","p-retry":"^4.6.2","p-wait-for":"^3.2.0","private-ip":"^2.3.4","rate-limiter-flexible":"^5.0.5","read-last-lines":"^1.8.0","semver":"^7.6.3","sequelize":"^6.35.0","shelljs":"^0.8.5","slugify":"^1.6.6","ssri":"^8.0.1","stream-throttle":"^0.1.3","stream-to-promise":"^3.0.0","systeminformation":"^5.23.3","tail":"^2.2.4","tar":"^6.1.11","transliteration":"^2.3.5","ua-parser-js":"^1.0.2","ufo":"^1.5.3","uuid":"^11.1.0","valid-url":"^1.0.9","which":"^2.0.2","xbytes":"^1.8.0"},"devDependencies":{"expand-tilde":"^2.0.2","express":"^4.18.2","jest":"^29.7.0","unzipper":"^0.10.11"},"gitHead":"e5764f753181ed6a7c615cd4fc6682aacf0cb7cd"}');
38950
38953
 
38951
38954
  /***/ }),
38952
38955
 
@@ -1,5 +1,6 @@
1
1
  const { EventEmitter } = require('events');
2
2
  const getRequestIP = require('@abtnode/util/lib/get-request-ip');
3
+ const { Op } = require('sequelize');
3
4
  const logger = require('@abtnode/logger')('@abtnode/core:blocklet-passport');
4
5
 
5
6
  const Cron = require('@abtnode/cron');
@@ -72,8 +73,13 @@ class PassportAPI extends EventEmitter {
72
73
  const { page, pageSize } = validatePaging(paging);
73
74
 
74
75
  const where = query;
75
- if (query.role === '$all') {
76
- delete where.role;
76
+ if (query.role === '$all' || !query.role) {
77
+ // 只展示非 Org passport
78
+ const roles = await this.teamManager.getRoles(teamDid);
79
+ const queryRoles = roles.filter((x) => !x.orgId).map((x) => x.name);
80
+ where.role = {
81
+ [Op.in]: queryRoles,
82
+ };
77
83
  }
78
84
 
79
85
  const result = await passportState.passports(where, { issuanceDate: -1 }, { pageSize, page });
package/lib/index.js CHANGED
@@ -555,6 +555,24 @@ function ABTNode(options) {
555
555
 
556
556
  createTagging: teamAPI.createTagging.bind(teamAPI),
557
557
  deleteTagging: teamAPI.deleteTagging.bind(teamAPI),
558
+ // Org
559
+ createOrg: teamAPI.createOrg.bind(teamAPI),
560
+ updateOrg: teamAPI.updateOrg.bind(teamAPI),
561
+ deleteOrg: teamAPI.deleteOrg.bind(teamAPI),
562
+ getOrgs: teamAPI.getOrgs.bind(teamAPI),
563
+ getOrg: teamAPI.getOrg.bind(teamAPI),
564
+ // Org Member
565
+ getOrgMembers: teamAPI.getOrgMembers.bind(teamAPI),
566
+ addOrgMember: teamAPI.addOrgMember.bind(teamAPI), // 加入的方式是通过邀请,因此不能批量添加
567
+ updateOrgMember: teamAPI.updateOrgMember.bind(teamAPI), // 加入的方式是通过邀请,因此不能批量添加
568
+ removeOrgMember: teamAPI.removeOrgMember.bind(teamAPI),
569
+ getOrgInvitableUsers: teamAPI.getOrgInvitableUsers.bind(teamAPI),
570
+ inviteMembersToOrg: teamAPI.inviteMembersToOrg.bind(teamAPI), // TODO: 批量邀请用户到组织 与 addOrgMember 可能重复
571
+
572
+ // org resource
573
+ getOrgResource: teamAPI.getOrgResource.bind(teamAPI),
574
+ addOrgResource: teamAPI.addOrgResource.bind(teamAPI),
575
+ migrateOrgResource: teamAPI.migrateOrgResource.bind(teamAPI),
558
576
 
559
577
  // Access Control
560
578
  getRBAC: (did = options.nodeDid) => teamManager.getRBAC(did),
@@ -11,7 +11,7 @@ const defaultLogger = require('@abtnode/logger')('blocklet-runtime-monitor');
11
11
 
12
12
  const { Op } = require('sequelize');
13
13
  const { isInstanceWorker } = require('@abtnode/util/lib/pm2/is-instence-worker');
14
- const { getRuntimeInfo, getDockerRuntimeInfoByDockerName } = require('../util/blocklet');
14
+ const { getRuntimeInfo } = require('../util/blocklet');
15
15
 
16
16
  const insertThrottleMap = new Map();
17
17
 
@@ -73,9 +73,10 @@ class BlockletRuntimeMonitor extends EventEmitter {
73
73
  const {
74
74
  meta: { did: blockletDid },
75
75
  status,
76
+ greenStatus,
76
77
  } = blocklet;
77
78
 
78
- if (status !== BlockletStatus.running) {
79
+ if (status !== BlockletStatus.running && greenStatus !== BlockletStatus.running) {
79
80
  if (this.data[blockletDid]) {
80
81
  Object.keys(this.data[blockletDid]).forEach((key) => {
81
82
  this.data[blockletDid][key].runtimeInfo = {};
@@ -105,14 +106,18 @@ class BlockletRuntimeMonitor extends EventEmitter {
105
106
  blocklet,
106
107
  async (component, { id: componentId, ancestors }) => {
107
108
  const { meta } = component;
108
- if (!isGatewayBlocklet(meta) && hasStartEngine(meta) && component.status === BlockletStatus.running) {
109
- const processId = getComponentProcessId(component, ancestors);
109
+ if (
110
+ !isGatewayBlocklet(meta) &&
111
+ hasStartEngine(meta) &&
112
+ (component.status === BlockletStatus.running || component.greenStatus === BlockletStatus.running)
113
+ ) {
114
+ const _processId = getComponentProcessId(component, ancestors);
115
+ const processId = component.greenStatus === BlockletStatus.running ? `${_processId}-green` : _processId;
116
+
110
117
  try {
111
118
  const runtimeInfo = await getRuntimeInfo(processId);
112
- const dockerName = component.environments?.find((x) => x.key === 'BLOCKLET_DOCKER_NAME')?.value;
113
- const dockerRuntimeInfo = dockerName ? await getDockerRuntimeInfoByDockerName(dockerName) : {};
114
119
 
115
- this.data[blockletDid][componentId] = { runtimeInfo: { ...runtimeInfo, ...dockerRuntimeInfo } };
120
+ this.data[blockletDid][componentId] = { runtimeInfo };
116
121
 
117
122
  if (!component.mountPoint || component.mountPoint === '/') {
118
123
  this.data[blockletDid].app.runtimeInfo = cloneDeep(runtimeInfo);