@abtnode/core 1.16.52-beta-20251002-030549-0f91dab2 → 1.16.52-beta-20251005-235515-42ad5caf

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.
@@ -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);
@@ -10,6 +10,7 @@ const isArray = require('lodash/isArray');
10
10
  const isString = require('lodash/isString');
11
11
  const mapValues = require('lodash/mapValues');
12
12
  const map = require('lodash/map');
13
+ const omit = require('lodash/omit');
13
14
  const { joinURL } = require('ufo');
14
15
  const { Op } = require('sequelize');
15
16
  const { getDisplayName } = require('@blocklet/meta/lib/util');
@@ -273,13 +274,15 @@ const getLogContent = async (action, args, context, result, info, node) => {
273
274
  expandSite(args.id, info, node),
274
275
  expandUser(
275
276
  args.teamDid,
276
- args.userDid || get(args, 'user.did') || args.ownerDid || args.did,
277
+ args.userDid || get(args, 'user.did') || args.ownerDid || args.did || context.user.did,
277
278
  args.passportId,
278
279
  info,
279
280
  node
280
281
  ),
281
282
  ]);
282
283
 
284
+ const prefix = process.env.NODE_ENV === 'production' ? info.routing.adminPath : '';
285
+
283
286
  switch (action) {
284
287
  // blocklets
285
288
  case 'installBlocklet':
@@ -684,7 +687,6 @@ const getLogContent = async (action, args, context, result, info, node) => {
684
687
  case 'followUser':
685
688
  case 'unfollowUser':
686
689
  const followerUser = await node.getUser({ teamDid: args.teamDid, user: { did: args.followerDid } });
687
- const prefix = process.env.NODE_ENV === 'production' ? info.routing.adminPath : '';
688
690
  return `[${followerUser.fullName}](${joinURL(prefix, '/team/members')}) ${action === 'followUser' ? 'followed' : 'unfollowed'} user ${user}`;
689
691
 
690
692
  // connect to aigne
@@ -693,6 +695,49 @@ const getLogContent = async (action, args, context, result, info, node) => {
693
695
  case 'disconnectToAigne':
694
696
  return `Disconnect to Aigne(${args.url})`;
695
697
 
698
+ // org 相关
699
+ case 'createOrg':
700
+ return `${user} created an org(${args.name})`;
701
+ case 'deleteOrg':
702
+ return `${user} deleted the org(${args.id})`;
703
+ case 'updateOrg':
704
+ return `${user} updated the org(${args.org.name}): \n${Object.keys(omit(args.org, ['id']))
705
+ .map((x) => `- ${x}: ${args.org[x]}`)
706
+ .join('\n')}`;
707
+ case 'removeOrgMember': {
708
+ const [member, org, operator] = await Promise.all([
709
+ node.getUser({ teamDid: args.teamDid, user: { did: args.userDid } }),
710
+ node.getOrg({ teamDid: args.teamDid, id: args.orgId }, context),
711
+ node.getUser({ teamDid: args.teamDid, user: { did: context.user.did } }),
712
+ ]);
713
+ return `[${operator.fullName}](${joinURL(prefix, '/team/members')}) removed a member([${member.fullName}](${joinURL(prefix, '/team/members')})) from the org(${org.name})`;
714
+ }
715
+ case 'inviteMembersToOrg': {
716
+ const [operator, joinedOrg] = await Promise.all([
717
+ node.getUser({ teamDid: args.teamDid, user: { did: context.user.did } }),
718
+ node.getOrg({ teamDid: args.teamDid, id: args.orgId }, context),
719
+ ]);
720
+ if (args.inviteType === 'internal') {
721
+ const dids = args.userDids || [];
722
+ const { users } = await node.getUsers({ teamDid: args.teamDid, dids: dids.slice(0, 5) });
723
+ const invitedMembers = users.length < dids.length ? [...users, '...'] : users;
724
+ return `[${operator.fullName}](${joinURL(prefix, '/team/members')}) invited ${dids.length} ${dids.length > 1 ? 'members' : 'member'} to join the org(${joinedOrg.name}): \n${invitedMembers.map((x) => (x.fullName ? `- [${x.fullName}](${joinURL(prefix, '/team/members')})` : `- ${x}`)).join('\n')}`;
725
+ }
726
+ return `[${operator.fullName}](${joinURL(prefix, '/team/members')}) invited members to join the org(${joinedOrg.name})`;
727
+ }
728
+ case 'addOrgResource': {
729
+ const org = await node.getOrg({ teamDid: args.teamDid, id: args.orgId }, context);
730
+ const resourceIds = (args.resourceIds || []).slice(0, 5);
731
+ const displayResourceIds = resourceIds.length < args.resourceIds.length ? [...resourceIds, '...'] : resourceIds;
732
+ return `${user} added ${resourceIds.length} ${resourceIds.length > 1 ? 'resources' : 'resource'} to the org(${org.name}): \n${displayResourceIds.map((x) => `- ${x}`).join('\n')}`;
733
+ }
734
+ case 'migrateOrgResource': {
735
+ const org = await node.getOrg({ teamDid: args.teamDid, id: args.to }, context);
736
+ const resourceIds = (args.resourceIds || []).slice(0, 5);
737
+ const displayResourceIds = resourceIds.length < args.resourceIds.length ? [...resourceIds, '...'] : resourceIds;
738
+ return `${user} migrated ${resourceIds.length} ${resourceIds.length > 1 ? 'resources' : 'resource'} to the org(${org.name}): \n${displayResourceIds.map((x) => `- ${x}`).join('\n')}`;
739
+ }
740
+
696
741
  default:
697
742
  return action;
698
743
  }
@@ -797,6 +842,13 @@ const getLogCategory = (action) => {
797
842
  case 'updateUserInfo':
798
843
  case 'followUser':
799
844
  case 'unfollowUser':
845
+ case 'createOrg':
846
+ case 'updateOrg':
847
+ case 'deleteOrg':
848
+ case 'removeOrgMember':
849
+ case 'inviteMembersToOrg':
850
+ case 'addOrgResource':
851
+ case 'migrateOrgResource':
800
852
  return 'team';
801
853
 
802
854
  // accessKeys
@@ -198,7 +198,10 @@ class BlockletState extends BaseState {
198
198
 
199
199
  async getBlockletStatus(did) {
200
200
  const doc = await this.getBlocklet(did);
201
- return doc ? doc.status : null;
201
+ if (!doc) {
202
+ return null;
203
+ }
204
+ return doc.status;
202
205
  }
203
206
 
204
207
  async hasBlocklet(did) {
@@ -469,7 +472,7 @@ class BlockletState extends BaseState {
469
472
  /**
470
473
  * refresh ports for blocklet if occupied during starting workflow
471
474
  */
472
- async refreshBlockletPorts(did, componentDids = []) {
475
+ async refreshBlockletPorts(did, componentDids = [], isGreen = false) {
473
476
  const blocklet = await this.getBlocklet(did);
474
477
  if (!blocklet) {
475
478
  throw new CustomError(404, `Blocklet does not exist on refresh: ${did}`);
@@ -479,9 +482,12 @@ class BlockletState extends BaseState {
479
482
 
480
483
  await forEachComponentV2(blocklet, async (component) => {
481
484
  if (!shouldSkipComponent(component.meta.did, componentDids)) {
482
- component.ports = await refreshPorts(component.ports, {
483
- blackList: [...occupiedExternalPorts.keys(), ...occupiedInternalPorts.keys()],
484
- });
485
+ component[isGreen ? 'greenPorts' : 'ports'] = await refreshPorts(
486
+ component[isGreen ? 'greenPorts' : 'ports'] || component.ports,
487
+ {
488
+ blackList: [...occupiedExternalPorts.keys(), ...occupiedInternalPorts.keys()],
489
+ }
490
+ );
485
491
  }
486
492
  });
487
493
 
@@ -556,7 +562,11 @@ class BlockletState extends BaseState {
556
562
  * componentDids?: Array<Did>
557
563
  * }}
558
564
  */
559
- async setBlockletStatus(did, status, { componentDids, operator = 'daemon' } = {}) {
565
+ async setBlockletStatus(
566
+ did,
567
+ status,
568
+ { componentDids, operator = 'daemon', isGreen = false, isGreenAndBlue = false } = {}
569
+ ) {
560
570
  logger.info('setBlockletStatus', { did, status, componentDids, operator });
561
571
  if (typeof status === 'undefined') {
562
572
  throw new Error('Unsupported blocklet status');
@@ -589,7 +599,11 @@ class BlockletState extends BaseState {
589
599
  return;
590
600
  }
591
601
 
592
- component.status = status;
602
+ component[isGreen ? 'greenStatus' : 'status'] = status;
603
+ if (isGreenAndBlue) {
604
+ component.greenStatus = status;
605
+ component.status = status;
606
+ }
593
607
  if (status === BlockletStatus.running) {
594
608
  component.startedAt = new Date();
595
609
  component.stoppedAt = null;
@@ -602,7 +616,8 @@ class BlockletState extends BaseState {
602
616
  component.inProgressStart = Date.now();
603
617
  });
604
618
 
605
- const updateData = pick(doc, ['status', 'children']);
619
+ const isSetStatus = status === BlockletStatus.downloading || status === BlockletStatus.waiting;
620
+ const updateData = isSetStatus ? pick(doc, ['status', 'children']) : pick(doc, ['children']);
606
621
  updateData.operator = operator;
607
622
 
608
623
  const res = await this.updateBlocklet(did, updateData);
@@ -18,6 +18,7 @@ const BackupState = require('./backup');
18
18
  const TrafficInsightState = require('./traffic-insight');
19
19
  const RuntimeInsightState = require('./runtime-insight');
20
20
  const BlacklistState = require('./blacklist');
21
+ const OrgState = require('./org');
21
22
 
22
23
  const { getDbFilePath } = require('../util');
23
24
 
@@ -46,6 +47,7 @@ const init = (dataDirs, config = {}) => {
46
47
  const trafficInsight = new TrafficInsightState(models.TrafficInsight, config);
47
48
  const runtimeInsight = new RuntimeInsightState(models.RuntimeInsight, { ...config, maxPageSize: 8640 });
48
49
  const blacklistState = new BlacklistState(models.Blacklist, config);
50
+ const orgState = new OrgState(models.Org, config, models);
49
51
 
50
52
  return {
51
53
  node: nodeState,
@@ -64,6 +66,7 @@ const init = (dataDirs, config = {}) => {
64
66
  trafficInsight,
65
67
  runtimeInsight,
66
68
  blacklist: blacklistState,
69
+ org: orgState,
67
70
  };
68
71
  };
69
72