@abtnode/core 1.17.8-beta-20260109-075740-5f484e08 → 1.17.8-beta-20260113-015027-32a1cec4

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 (65) 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/util/blocklet/app-utils.js +192 -0
  51. package/lib/util/blocklet/blocklet-loader.js +258 -0
  52. package/lib/util/blocklet/config-manager.js +232 -0
  53. package/lib/util/blocklet/did-document.js +240 -0
  54. package/lib/util/blocklet/environment.js +555 -0
  55. package/lib/util/blocklet/health-check.js +449 -0
  56. package/lib/util/blocklet/install-utils.js +365 -0
  57. package/lib/util/blocklet/logo.js +57 -0
  58. package/lib/util/blocklet/meta-utils.js +269 -0
  59. package/lib/util/blocklet/port-manager.js +141 -0
  60. package/lib/util/blocklet/process-manager.js +504 -0
  61. package/lib/util/blocklet/runtime-info.js +105 -0
  62. package/lib/util/blocklet/validation.js +418 -0
  63. package/lib/util/blocklet.js +98 -3066
  64. package/lib/util/wallet-app-notification.js +40 -0
  65. package/package.json +22 -22
@@ -0,0 +1,403 @@
1
+ const { joinURL } = require('ufo');
2
+ const logger = require('@abtnode/logger')('@abtnode/core:api:team:org-member');
3
+ const { WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
4
+ const { CustomError } = require('@blocklet/error');
5
+ const { sendToUser } = require('@blocklet/sdk/lib/util/send-notification');
6
+ const { getBlockletInfo } = require('@blocklet/meta/lib/info');
7
+ const { getWalletDid } = require('@blocklet/meta/lib/did-utils');
8
+ const { Joi } = require('@arcblock/validator');
9
+ const { getEmailServiceProvider } = require('@abtnode/auth/lib/email');
10
+
11
+ const { getOrgInviteLink, isOrgOwner, isAdmingPath } = require('../../util/org');
12
+ const { getBlocklet } = require('../../util/blocklet');
13
+
14
+ /**
15
+ * Add org member
16
+ * @param {Object} api - TeamAPI instance
17
+ * @param {Object} params
18
+ * @param {string} params.teamDid - Team DID
19
+ * @param {string} params.orgId - Org ID
20
+ * @param {string} params.userDid - User DID
21
+ * @param {Object} context
22
+ * @returns {Promise<Object>}
23
+ */
24
+ async function addOrgMember(api, { teamDid, orgId, userDid }, context) {
25
+ try {
26
+ const state = await api.getOrgState(teamDid);
27
+ return state.addOrgMember({ orgId, userDid }, context);
28
+ } catch (err) {
29
+ logger.error('Add member to org failed', { err, teamDid, orgId, userDid });
30
+ throw err;
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Update org member
36
+ * @param {Object} api - TeamAPI instance
37
+ * @param {Object} params
38
+ * @param {string} params.teamDid - Team DID
39
+ * @param {string} params.orgId - Org ID
40
+ * @param {string} params.userDid - User DID
41
+ * @param {string} params.status - Status
42
+ * @param {Object} context
43
+ * @returns {Promise<Object>}
44
+ */
45
+ async function updateOrgMember(api, { teamDid, orgId, userDid, status }, context) {
46
+ try {
47
+ const state = await api.getOrgState(teamDid);
48
+ return state.updateOrgMember({ orgId, userDid, status }, context);
49
+ } catch (err) {
50
+ logger.error('Update member in org failed', { err, teamDid, orgId, userDid, status });
51
+ throw err;
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Send invitation notification
57
+ * @param {Object} api - TeamAPI instance
58
+ * @param {Object} params
59
+ * @returns {Promise<void>}
60
+ */
61
+ async function sendInvitationNotification(
62
+ api,
63
+ { teamDid, invitor, org, role, successUserDids, inviteLink, email, inviteType, blocklet }
64
+ ) {
65
+ try {
66
+ const userInfo = await api.getUser({
67
+ teamDid,
68
+ user: { did: invitor.did },
69
+ options: { enableConnectedAccount: true },
70
+ });
71
+
72
+ // 检测是否开启了 email 服务
73
+ const provider = getEmailServiceProvider(blocklet);
74
+
75
+ const translate = {
76
+ en: {
77
+ title: 'Inviting you to join the organization',
78
+ description: `<${userInfo.fullName}(did:abt:${userInfo.did})> invites you to join the ${org.name} organization, role is ${role}.<br/>After accepting, you will be able to access the resources and collaboration content of the organization.<br/><br/>Please click the button below to handle the invitation.<br/><br/>If you don't want to join, you can ignore this notification.`,
79
+ accept: 'Accept',
80
+ },
81
+ zh: {
82
+ title: '邀请您加入组织',
83
+ description: `<${userInfo.fullName}(did:abt:${userInfo.did})> 邀请您加入 ${org.name} 组织,角色为 ${role}。<br/>接受后,你将能够访问该组织的资源和协作内容。<br/><br/>请点击下方按钮处理邀请。<br/><br/>如果你不想加入,可以忽略此通知。`,
84
+ accept: '接受',
85
+ },
86
+ };
87
+ const content = translate[userInfo.locale || 'en'] || translate.en;
88
+
89
+ const message = {
90
+ title: content.title,
91
+ body: content.description,
92
+ actions: [
93
+ {
94
+ name: content.accept,
95
+ title: content.accept,
96
+ link: inviteLink,
97
+ },
98
+ ],
99
+ };
100
+
101
+ if (inviteType === 'internal') {
102
+ await api.createNotification({
103
+ teamDid,
104
+ receiver: successUserDids,
105
+ entityId: teamDid,
106
+ source: 'system',
107
+ severity: 'info',
108
+ ...message,
109
+ });
110
+ logger.info('Invite notification sent successfully', {
111
+ teamDid,
112
+ orgId: org.id,
113
+ sentToUsers: successUserDids,
114
+ sentCount: successUserDids.length,
115
+ });
116
+ } else if (inviteType === 'external' && provider && email) {
117
+ // 当 service 开启 email 服务时才会发送邮件通知
118
+ const emailInputSchema = Joi.string().email().required();
119
+ const { error } = emailInputSchema.validate(email);
120
+ if (error) {
121
+ throw new CustomError(400, error.message);
122
+ }
123
+ const nodeInfo = await api.node.read();
124
+ const blockletInfo = getBlockletInfo(blocklet, nodeInfo.sk);
125
+ const sender = {
126
+ appDid: blockletInfo.wallet.address,
127
+ appSk: blockletInfo.wallet.secretKey,
128
+ };
129
+
130
+ await sendToUser(email, message, sender, undefined, 'send-to-mail');
131
+ logger.info('Send invitation notification to email completed', {
132
+ teamDid,
133
+ orgId: org.id,
134
+ email,
135
+ });
136
+ }
137
+ } catch (notificationErr) {
138
+ // 通知发送失败不影响邀请的成功,只记录警告
139
+ logger.warn('Failed to send invitation notification, but invitations were created successfully', {
140
+ notificationErr,
141
+ teamDid,
142
+ orgId: org.id,
143
+ successUserDids,
144
+ });
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Get federated master blocklet info
150
+ * @param {Object} params
151
+ * @param {Object} params.blocklet - Blocklet
152
+ * @returns {Object|undefined}
153
+ */
154
+ function getFederatedMasterBlockletInfo({ blocklet }) {
155
+ const sites = blocklet.settings?.federated?.sites || [];
156
+ const federatedMaster = sites.find((item) => item.isMaster !== false);
157
+ const federatedCurrent = sites.find((item) => item.appId === blocklet.appDid);
158
+ const isFederated = !!federatedMaster || !!federatedCurrent;
159
+ if (!isFederated) {
160
+ return undefined;
161
+ }
162
+
163
+ const formatBlockletInfo = (federateBlocklet) => ({
164
+ appId: federateBlocklet?.appId,
165
+ appName: federateBlocklet?.appName,
166
+ appDescription: federateBlocklet?.appDescription,
167
+ appLogo: federateBlocklet?.appLogo,
168
+ appPid: federateBlocklet?.appPid,
169
+ appUrl: federateBlocklet?.appUrl,
170
+ version: federateBlocklet?.version,
171
+ sourceAppPid: federateBlocklet?.appPid,
172
+ provider: 'wallet',
173
+ });
174
+
175
+ const blocklets = [];
176
+ if (federatedCurrent?.status === 'approved') {
177
+ blocklets.push(formatBlockletInfo(federatedMaster));
178
+ }
179
+ if (federatedCurrent) {
180
+ blocklets.push({
181
+ ...formatBlockletInfo(federatedCurrent),
182
+ sourceAppPid: null,
183
+ });
184
+ } else {
185
+ const blockletInfo = getBlockletInfo(blocklet, undefined, { returnWallet: false });
186
+ blocklets.push({
187
+ ...formatBlockletInfo(blockletInfo),
188
+ appPid: blocklet?.appPid,
189
+ appLogo: joinURL(blockletInfo.appUrl, WELLKNOWN_SERVICE_PATH_PREFIX, '/blocklet/logo'),
190
+ sourceAppPid: null,
191
+ });
192
+ }
193
+
194
+ return blocklets[0];
195
+ }
196
+
197
+ /**
198
+ * Get org (internal helper - imported from org-query-manager to avoid circular dependency)
199
+ * @param {Object} api - TeamAPI instance
200
+ * @param {Object} params
201
+ * @param {string} params.teamDid - Team DID
202
+ * @param {string} params.id - Org ID
203
+ * @param {Object} context
204
+ * @returns {Promise<Object>}
205
+ */
206
+ async function _getOrg(api, { teamDid, id }, context) {
207
+ const state = await api.getOrgState(teamDid);
208
+ return state.get({ id }, context);
209
+ }
210
+
211
+ /**
212
+ * Invite members to org
213
+ * @param {Object} api - TeamAPI instance
214
+ * @param {Object} params
215
+ * @param {string} params.teamDid - Team DID
216
+ * @param {string} params.orgId - Org ID
217
+ * @param {Array} params.userDids - User DIDs
218
+ * @param {string} params.role - Role
219
+ * @param {string} params.inviteType - Invite type
220
+ * @param {string} params.email - Email
221
+ * @param {Object} context
222
+ * @returns {Promise<Object>}
223
+ */
224
+ async function inviteMembersToOrg(api, { teamDid, orgId, userDids, role, inviteType = 'internal', email }, context) {
225
+ try {
226
+ const state = await api.getOrgState(teamDid);
227
+ const { user } = context || {};
228
+ if (!user) {
229
+ throw new CustomError(400, 'User is required');
230
+ }
231
+ const org = await _getOrg(api, { teamDid, id: orgId }, context);
232
+ if (!org) {
233
+ throw new CustomError(400, 'Org not found');
234
+ }
235
+
236
+ // dashboard 或者非 org owner 无法邀请成员
237
+ if (isAdmingPath(context) || !isOrgOwner(user, org)) {
238
+ throw new CustomError(403, "You cannot invite members to other users' org");
239
+ }
240
+
241
+ if (inviteType === 'internal' && userDids.length === 0) {
242
+ throw new CustomError(400, 'You must invite at least one user');
243
+ }
244
+
245
+ // Step 1: 批量添加成员到组织 - 记录添加成功和添加失败的用户 DID
246
+ const successUserDids = [];
247
+ const failedUserDids = [];
248
+ const skipInviteUserDids = [];
249
+
250
+ // 内部邀请
251
+ if (inviteType === 'internal') {
252
+ for (const userDid of userDids) {
253
+ try {
254
+ // eslint-disable-next-line no-await-in-loop
255
+ const currentUser = await api.getUser({
256
+ teamDid,
257
+ user: { did: userDid },
258
+ });
259
+ const walletDid = getWalletDid(currentUser);
260
+ // 如果当前用户不是钱包用户,则跳过邀请 (参考颁发通行证逻辑)
261
+ const skipInvite = walletDid !== userDid;
262
+ if (skipInvite) {
263
+ skipInviteUserDids.push(userDid);
264
+ }
265
+ const status = skipInvite ? 'active' : 'inviting';
266
+ // eslint-disable-next-line no-await-in-loop
267
+ await state.addOrgMember({ orgId, userDid, status }, context);
268
+ successUserDids.push(userDid);
269
+ } catch (addErr) {
270
+ failedUserDids.push(userDid);
271
+ logger.warn('Failed to add user to org', { userDid, orgId, error: addErr.message });
272
+ }
273
+ }
274
+
275
+ logger.info('Batch add members to org completed', {
276
+ teamDid,
277
+ orgId,
278
+ totalUsers: userDids.length,
279
+ successCount: successUserDids.length,
280
+ failedCount: failedUserDids.length,
281
+ });
282
+
283
+ // 如果没有成功添加的用户,直接返回结果
284
+ if (successUserDids.length === 0) {
285
+ logger.warn('No users were successfully added to org', { teamDid, orgId, failedUserDids });
286
+ throw new CustomError(500, 'No users were successfully added to org');
287
+ }
288
+ }
289
+
290
+ // 要排除 OAuth 用户
291
+ const inviteUserDids = successUserDids.filter((did) => !skipInviteUserDids.includes(did));
292
+
293
+ if (skipInviteUserDids.length > 0) {
294
+ logger.info('OAuth users were successfully added to org', { teamDid, orgId, skipInviteUserDids });
295
+ // 向 OAuth 用户颁发通行证
296
+ for (const userDid of skipInviteUserDids) {
297
+ // eslint-disable-next-line no-await-in-loop
298
+ await api.issuePassportToUser({
299
+ teamDid,
300
+ userDid,
301
+ role,
302
+ notification: {},
303
+ });
304
+ }
305
+ }
306
+
307
+ // 如果没有其他用户,那么直接返回即可
308
+ if (inviteType === 'internal' && inviteUserDids.length === 0) {
309
+ return {
310
+ successDids: successUserDids,
311
+ failedDids: failedUserDids,
312
+ };
313
+ }
314
+
315
+ // Previous Step 2: 要判断站点是否是站点群内,如果是站点群中,需要使用 master 的 appPid 作为 sourceAppPid 创建邀请链接
316
+
317
+ const blocklet = await getBlocklet({ did: teamDid, states: api.states, dataDirs: api.dataDirs });
318
+ const masterBlockletInfo = getFederatedMasterBlockletInfo({ blocklet });
319
+
320
+ // Step 2: 创建邀请链接,只创建添加成功的用户邀请链接
321
+
322
+ const inviteInfo = await api.createMemberInvitation(
323
+ {
324
+ teamDid,
325
+ role,
326
+ expireTime: api.memberInvitationExpireTime,
327
+ orgId,
328
+ inviteUserDids: inviteType === 'internal' ? inviteUserDids : [],
329
+ sourceAppPid: masterBlockletInfo?.appPid,
330
+ },
331
+ context
332
+ );
333
+
334
+ const inviteLink = getOrgInviteLink(inviteInfo, blocklet);
335
+
336
+ logger.info('Invite link created for successful users', {
337
+ teamDid,
338
+ orgId,
339
+ inviteId: inviteInfo.inviteId,
340
+ userCount: successUserDids.length,
341
+ });
342
+
343
+ // Step 3: 发送邀请通知,只发送添加成功的用户邀请通知
344
+
345
+ sendInvitationNotification(api, {
346
+ teamDid,
347
+ invitor: user,
348
+ org,
349
+ role,
350
+ successUserDids,
351
+ email,
352
+ inviteType,
353
+ inviteLink,
354
+ blocklet,
355
+ });
356
+
357
+ // 返回成功和失败的用户列表
358
+ return {
359
+ successDids: successUserDids,
360
+ failedDids: failedUserDids,
361
+ inviteLink,
362
+ };
363
+ } catch (err) {
364
+ logger.error('Invite users to org failed', { err, teamDid, orgId, userDids, role });
365
+ throw err;
366
+ }
367
+ }
368
+
369
+ /**
370
+ * Remove org member
371
+ * @param {Object} api - TeamAPI instance
372
+ * @param {Object} params
373
+ * @param {string} params.teamDid - Team DID
374
+ * @param {string} params.orgId - Org ID
375
+ * @param {string} params.userDid - User DID
376
+ * @param {Object} context
377
+ * @returns {Promise<Object>}
378
+ */
379
+ async function removeOrgMember(api, { teamDid, orgId, userDid }, context) {
380
+ try {
381
+ const state = await api.getOrgState(teamDid);
382
+ const roles = await api.getRoles({ teamDid, orgId });
383
+ const result = await state.removeOrgMember({ orgId, userDid }, context);
384
+ try {
385
+ await state.removeOrgRelatedData({ roles, orgId, userDid });
386
+ } catch (err) {
387
+ logger.error('Failed to remove user related passports', { err, teamDid, roles, userDid });
388
+ }
389
+ return result;
390
+ } catch (err) {
391
+ logger.error('Remove member from org failed', { err, teamDid, orgId, userDid });
392
+ throw err;
393
+ }
394
+ }
395
+
396
+ module.exports = {
397
+ addOrgMember,
398
+ updateOrgMember,
399
+ sendInvitationNotification,
400
+ getFederatedMasterBlockletInfo,
401
+ inviteMembersToOrg,
402
+ removeOrgMember,
403
+ };
@@ -0,0 +1,126 @@
1
+ const logger = require('@abtnode/logger')('@abtnode/core:api:team:org-query');
2
+ const { getUserAvatarUrl } = require('@abtnode/util/lib/user');
3
+
4
+ const { getBlocklet } = require('../../util/blocklet');
5
+
6
+ /**
7
+ * Get orgs
8
+ * @param {Object} api - TeamAPI instance
9
+ * @param {Object} params
10
+ * @param {string} params.teamDid - Team DID
11
+ * @param {Object} context
12
+ * @returns {Promise<Object>}
13
+ */
14
+ async function getOrgs(api, { teamDid, ...payload }, context) {
15
+ try {
16
+ const state = await api.getOrgState(teamDid);
17
+ const { passports, orgs, ...rest } = await state.list(payload, context);
18
+ const { includePassports = true } = payload.options || {};
19
+ if (includePassports) {
20
+ // 获取每个组织的 passports
21
+ const orgPassports = await Promise.all(orgs.map((o) => api.getRoles({ teamDid, orgId: o.id })));
22
+
23
+ orgs.forEach((o, index) => {
24
+ const roles = orgPassports[index]; // 获取每个组织的角色
25
+ // 过滤 passports
26
+ o.passports = passports.filter((p) => roles.some((r) => r.name === p.name));
27
+ });
28
+ } else {
29
+ orgs.forEach((o) => {
30
+ o.passports = [];
31
+ });
32
+ }
33
+
34
+ return {
35
+ ...rest,
36
+ orgs,
37
+ };
38
+ } catch (err) {
39
+ logger.error('Failed to get orgs', { err, teamDid });
40
+ throw err;
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Get org
46
+ * @param {Object} api - TeamAPI instance
47
+ * @param {Object} params
48
+ * @param {string} params.teamDid - Team DID
49
+ * @param {string} params.id - Org ID
50
+ * @param {Object} context
51
+ * @returns {Promise<Object>}
52
+ */
53
+ async function getOrg(api, { teamDid, id }, context) {
54
+ try {
55
+ const state = await api.getOrgState(teamDid);
56
+ return state.get({ id }, context);
57
+ } catch (err) {
58
+ logger.error('Failed to get org', { err, teamDid, id });
59
+ throw err;
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Get org members
65
+ * @param {Object} api - TeamAPI instance
66
+ * @param {Object} params
67
+ * @param {string} params.teamDid - Team DID
68
+ * @param {string} params.orgId - Org ID
69
+ * @param {Object} params.paging - Paging
70
+ * @param {Object} context
71
+ * @returns {Promise<Object>}
72
+ */
73
+ async function getOrgMembers(api, { teamDid, orgId, paging }, context) {
74
+ try {
75
+ const state = await api.getOrgState(teamDid);
76
+ const result = await state.getOrgMembers({ orgId, paging, options: { includePassport: true } }, context);
77
+ const info = await api.node.read();
78
+ const isServer = api.teamManager.isNodeTeam(teamDid);
79
+ const blocklet = await getBlocklet({ did: teamDid, states: api.states, dataDirs: api.dataDirs });
80
+ const baseUrl = blocklet.environmentObj.BLOCKLET_APP_URL;
81
+ const roles = await api.getRoles({ teamDid, orgId });
82
+ result.users.forEach((item) => {
83
+ if (item?.user?.avatar) {
84
+ item.user.avatar = getUserAvatarUrl(baseUrl, item.user.avatar, info, isServer);
85
+ }
86
+ if (item?.user?.passports?.length > 0) {
87
+ item.user.passports = item.user.passports.filter((passport) =>
88
+ roles.some((roleItem) => roleItem.name === passport.name)
89
+ );
90
+ }
91
+ });
92
+
93
+ return result;
94
+ } catch (err) {
95
+ logger.error('Get org members failed', { err, teamDid, orgId });
96
+ throw err;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Get org invitable users
102
+ * @param {Object} api - TeamAPI instance
103
+ * @param {Object} params
104
+ * @param {string} params.teamDid - Team DID
105
+ * @param {string} params.id - Org ID
106
+ * @param {string} params.query - Query
107
+ * @param {Object} params.paging - Paging
108
+ * @param {Object} context
109
+ * @returns {Promise<Object>}
110
+ */
111
+ async function getOrgInvitableUsers(api, { teamDid, id, query, paging }, context) {
112
+ try {
113
+ const state = await api.getOrgState(teamDid);
114
+ return state.getOrgInvitableUsers({ id, query, paging }, context);
115
+ } catch (err) {
116
+ logger.error('Get org invitable users failed', { err, teamDid, id });
117
+ throw err;
118
+ }
119
+ }
120
+
121
+ module.exports = {
122
+ getOrgs,
123
+ getOrg,
124
+ getOrgMembers,
125
+ getOrgInvitableUsers,
126
+ };