@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,198 @@
1
+ const { withoutTrailingSlash } = require('ufo');
2
+ const logger = require('@abtnode/logger')('@abtnode/core:api:team:store');
3
+ const ensureServerEndpoint = require('@abtnode/util/lib/ensure-server-endpoint');
4
+
5
+ const StoreUtil = require('../../util/store');
6
+
7
+ const sanitizeUrl = (url) => {
8
+ if (!url) {
9
+ throw new Error('Registry URL should not be empty');
10
+ }
11
+
12
+ return url.trim();
13
+ };
14
+
15
+ /**
16
+ * Add store
17
+ * @param {Object} api - TeamAPI instance
18
+ * @param {Object} params
19
+ * @param {string} params.teamDid - Team DID
20
+ * @param {string} params.url - Store URL
21
+ * @param {string} params.scope - Scope
22
+ * @param {Object} context
23
+ * @returns {Promise<Object>}
24
+ */
25
+ // eslint-disable-next-line no-unused-vars
26
+ async function addStore(api, { teamDid, url, scope = '' }, context) {
27
+ logger.info('add store', { teamDid, url, scope });
28
+
29
+ const sanitized = withoutTrailingSlash(await StoreUtil.getStoreUrl(url));
30
+ const storeList = await api.teamManager.getStoreList(teamDid);
31
+ const exists = storeList.some((x) => {
32
+ if (x.url === sanitized) {
33
+ if (!x.scope) {
34
+ return true;
35
+ }
36
+
37
+ return x.scope === scope;
38
+ }
39
+
40
+ return false;
41
+ });
42
+
43
+ if (exists) {
44
+ throw new Error(`Blocklet Store already exist: ${sanitized}`);
45
+ }
46
+
47
+ const store = await StoreUtil.getStoreMeta(sanitized);
48
+
49
+ storeList.push({ ...store, scope, url: sanitized, protected: false });
50
+
51
+ return api.teamManager.updateStoreList(teamDid, storeList);
52
+ }
53
+
54
+ /**
55
+ * Add endpoint
56
+ * @param {Object} api - TeamAPI instance
57
+ * @param {Object} params
58
+ * @param {string} params.teamDid - Team DID
59
+ * @param {string} params.url - Endpoint URL
60
+ * @param {Object} context
61
+ * @returns {Promise<Object>}
62
+ */
63
+ async function addEndpoint(api, { teamDid, url }, context) {
64
+ const userDid = context?.user?.did;
65
+ const { endpoint, appPid, appName, appDescription } = await ensureServerEndpoint(url);
66
+ const endpointList = await api.teamManager.getEndpointList(teamDid);
67
+
68
+ if (!appPid) {
69
+ throw new Error('current url not blocklet url');
70
+ }
71
+
72
+ if (!endpoint) {
73
+ throw new Error('current url not blocklet url');
74
+ }
75
+
76
+ const index = endpointList.findIndex((x) => x.id === appPid);
77
+ if (index !== -1) {
78
+ endpointList[index].url = url;
79
+ } else {
80
+ endpointList.push({ id: appPid, appName, appDescription, scope: userDid, url, endpoint, protected: false });
81
+ }
82
+
83
+ return api.teamManager.updateEndpointList(teamDid, endpointList);
84
+ }
85
+
86
+ /**
87
+ * Delete endpoint
88
+ * @param {Object} api - TeamAPI instance
89
+ * @param {Object} params
90
+ * @param {string} params.teamDid - Team DID
91
+ * @param {string} params.did - Endpoint DID
92
+ * @param {string} params.projectId - Project ID
93
+ * @param {Object} context
94
+ * @returns {Promise<Object>}
95
+ */
96
+ async function deleteEndpoint(api, { teamDid, did, projectId }, context) {
97
+ const endpointList = await api.teamManager.getEndpointList(teamDid);
98
+
99
+ const index = endpointList.findIndex((x) => x.id === did);
100
+ if (index === -1) {
101
+ throw new Error(`Blocklet Endpoint does not exist: ${did}`);
102
+ }
103
+ endpointList.splice(index, 1);
104
+
105
+ if (projectId) {
106
+ const { projectState } = await api.teamManager.getProjectState(teamDid);
107
+ await projectState.deleteConnectedEndpoint({ projectId, endpointId: did, createdBy: context?.user?.did });
108
+ }
109
+
110
+ return api.teamManager.updateEndpointList(teamDid, endpointList);
111
+ }
112
+
113
+ /**
114
+ * Check if store exists
115
+ * @param {Object} api - TeamAPI instance
116
+ * @param {Object} params
117
+ * @param {string} params.teamDid - Team DID
118
+ * @param {string} params.url - Store URL
119
+ * @param {string} params.scope - Scope
120
+ * @param {Object} context
121
+ * @returns {Promise<boolean>}
122
+ */
123
+ async function existsStore(api, { teamDid, url, scope }, context) {
124
+ const sanitized = withoutTrailingSlash(await StoreUtil.getStoreUrl(url));
125
+ const storeList = await api.teamManager.getStoreList(teamDid);
126
+ const did = context?.user?.did;
127
+ const exists = storeList.some((x) => {
128
+ if (x.url !== sanitized) {
129
+ return false;
130
+ }
131
+ if (x.scope && x.scope === did) {
132
+ return true;
133
+ }
134
+ if (!x.scope || x.scope === 'studio') {
135
+ return true;
136
+ }
137
+ return x.scope === scope;
138
+ });
139
+
140
+ return exists;
141
+ }
142
+
143
+ /**
144
+ * Delete store
145
+ * @param {Object} api - TeamAPI instance
146
+ * @param {Object} params
147
+ * @param {string} params.teamDid - Team DID
148
+ * @param {string} params.url - Store URL
149
+ * @param {string} params.projectId - Project ID
150
+ * @param {string} params.scope - Scope
151
+ * @param {Object} context
152
+ * @returns {Promise<Object>}
153
+ */
154
+ // eslint-disable-next-line no-unused-vars
155
+ async function deleteStore(api, { teamDid, url, projectId, scope }, context) {
156
+ logger.info('delete registry', { url });
157
+ const sanitized = sanitizeUrl(url);
158
+
159
+ const storeList = await api.teamManager.getStoreList(teamDid);
160
+ let storeIndex;
161
+ if (scope) {
162
+ storeIndex = storeList.findIndex((x) => {
163
+ if (x.protected) {
164
+ return false;
165
+ }
166
+ return x.url === sanitized && x.scope === scope;
167
+ });
168
+ if (storeIndex === -1) {
169
+ throw new Error(`No permission to delete the Store registry: ${sanitized}`);
170
+ }
171
+ } else {
172
+ storeIndex = storeList.findIndex((x) => x.url === sanitized && !x.scope);
173
+ if (storeIndex === -1) {
174
+ throw new Error(`Store registry does not exist: ${sanitized}`);
175
+ }
176
+ }
177
+
178
+ if (projectId && scope) {
179
+ const { projectState } = await api.teamManager.getProjectState(teamDid);
180
+ const store = await StoreUtil.getStoreMeta(sanitized);
181
+ await projectState.deleteConnectedStore({
182
+ projectId,
183
+ storeId: store.id,
184
+ createdBy: scope === 'studio' ? null : context?.user?.did,
185
+ });
186
+ }
187
+ storeList.splice(storeIndex, 1);
188
+ return api.teamManager.updateStoreList(teamDid, storeList);
189
+ }
190
+
191
+ module.exports = {
192
+ sanitizeUrl,
193
+ addStore,
194
+ addEndpoint,
195
+ deleteEndpoint,
196
+ existsStore,
197
+ deleteStore,
198
+ };
@@ -0,0 +1,230 @@
1
+ const pick = require('lodash/pick');
2
+ const logger = require('@abtnode/logger')('@abtnode/core:api:team:tag');
3
+ const { Joi } = require('@arcblock/validator');
4
+
5
+ const taggingSchema = Joi.object({
6
+ tagId: Joi.number().required(),
7
+ taggableIds: Joi.array().items(Joi.string()).min(1).required().messages({
8
+ 'any.required': 'Must specify tagging.taggableIds to create',
9
+ 'array.base': 'taggableIds must be an array',
10
+ 'array.min': 'taggableIds must contain at least one element',
11
+ }),
12
+ taggableType: Joi.string().required().messages({
13
+ 'any.required': 'Must specify tagging.taggableType to create',
14
+ 'string.base': 'taggableType must be a string',
15
+ }),
16
+ });
17
+
18
+ /**
19
+ * Create tagging
20
+ * @param {Object} api - TeamAPI instance
21
+ * @param {Object} params
22
+ * @param {string} params.teamDid - Team DID
23
+ * @param {Object} params.tagging - Tagging data
24
+ * @returns {Promise<Array>}
25
+ */
26
+ async function createTagging(api, { teamDid, tagging }) {
27
+ const state = await api.getTaggingState(teamDid);
28
+
29
+ const { error, value } = taggingSchema.validate(tagging, { stripUnknown: true });
30
+ if (error) {
31
+ throw new Error(error.details.map((d) => d.message).join('; '));
32
+ }
33
+
34
+ const fns = value.taggableIds.map(async (id) => {
35
+ const found = await state.findOne({ tagId: tagging.tagId, taggableId: id });
36
+ if (found) return found;
37
+
38
+ return state.insert({ tagId: tagging.tagId, taggableId: id, taggableType: tagging.taggableType });
39
+ });
40
+
41
+ const docs = await Promise.all(fns);
42
+ logger.info('tagging created successfully', { teamDid, tagging });
43
+ return docs;
44
+ }
45
+
46
+ /**
47
+ * Delete tagging
48
+ * @param {Object} api - TeamAPI instance
49
+ * @param {Object} params
50
+ * @param {string} params.teamDid - Team DID
51
+ * @param {Object} params.tagging - Tagging data
52
+ * @returns {Promise<Array>}
53
+ */
54
+ async function deleteTagging(api, { teamDid, tagging }) {
55
+ const { error, value } = taggingSchema.validate(tagging, { stripUnknown: true });
56
+ if (error) {
57
+ throw new Error(error.details.map((d) => d.message).join('; '));
58
+ }
59
+
60
+ const state = await api.getTaggingState(teamDid);
61
+
62
+ const { tagId, taggableIds } = value;
63
+ const fns = taggableIds.map((id) => {
64
+ return state.remove({ tagId, taggableId: id });
65
+ });
66
+
67
+ const docs = await Promise.all(fns);
68
+ logger.info('tagging deleted successfully', { teamDid, tagging });
69
+
70
+ return docs;
71
+ }
72
+
73
+ /**
74
+ * Get tag
75
+ * @param {Object} api - TeamAPI instance
76
+ * @param {Object} params
77
+ * @param {string} params.teamDid - Team DID
78
+ * @param {Object} params.tag - Tag data
79
+ * @returns {Promise<Object>}
80
+ */
81
+ async function getTag(api, { teamDid, tag }) {
82
+ const state = await api.getTagState(teamDid);
83
+ return state.findOne({ id: tag.id });
84
+ }
85
+
86
+ /**
87
+ * Create tag
88
+ * @param {Object} api - TeamAPI instance
89
+ * @param {Object} params
90
+ * @param {string} params.teamDid - Team DID
91
+ * @param {Object} params.tag - Tag data
92
+ * @param {Object} context
93
+ * @returns {Promise<Object>}
94
+ */
95
+ async function createTag(api, { teamDid, tag }, context = {}) {
96
+ if (!tag.title) {
97
+ throw new Error('Must specify tag.title to create');
98
+ }
99
+ if (!tag.color || !tag.color.match(/^#[0-9a-f]{6}$/i)) {
100
+ throw new Error('Must specify hex encoded tag.color to create');
101
+ }
102
+ if (!tag.slug) {
103
+ throw new Error('Must specify tag.slug to create');
104
+ }
105
+
106
+ const state = await api.getTagState(teamDid);
107
+ const tagData = pick(tag, ['title', 'description', 'color', 'slug', 'type', 'componentDid', 'parentId']);
108
+ tagData.createdBy = context.user.did;
109
+ tagData.updatedBy = context.user.did;
110
+ const doc = await state.insert(tagData);
111
+ logger.info('tags created successfully', { teamDid, tag });
112
+ return doc;
113
+ }
114
+
115
+ /**
116
+ * Update tag
117
+ * @param {Object} api - TeamAPI instance
118
+ * @param {Object} params
119
+ * @param {string} params.teamDid - Team DID
120
+ * @param {Object} params.tag - Tag data
121
+ * @param {Object} context
122
+ * @returns {Promise<Object>}
123
+ */
124
+ async function updateTag(api, { teamDid, tag }, context = {}) {
125
+ if (!tag.id) {
126
+ throw new Error('Must specify tag.id to update');
127
+ }
128
+
129
+ const keys = ['title', 'description', 'color', 'slug', 'type', 'componentDid', 'parentId'];
130
+ const tagData = Object.fromEntries(keys.map((key) => [key, tag[key] ?? null]));
131
+ tagData.updatedBy = context.user.did;
132
+
133
+ const state = await api.getTagState(teamDid);
134
+ const result = await state.updateById(tag.id, tagData);
135
+ logger.info('tags updated successfully', { teamDid, tag, result });
136
+ return state.findOne({ id: tag.id });
137
+ }
138
+
139
+ /**
140
+ * Delete tag
141
+ * @param {Object} api - TeamAPI instance
142
+ * @param {Object} params
143
+ * @param {string} params.teamDid - Team DID
144
+ * @param {Object} params.tag - Tag data
145
+ * @param {number} params.moveTo - Move to tag id
146
+ * @returns {Promise<Object>}
147
+ */
148
+ async function deleteTag(api, { teamDid, tag, moveTo }) {
149
+ if (!tag.id) {
150
+ throw new Error('Must specify tag.id to delete');
151
+ }
152
+
153
+ const state = await api.getTagState(teamDid);
154
+ const taggingState = await api.getTaggingState(teamDid);
155
+
156
+ if (moveTo) {
157
+ const records = await taggingState.find({ tagId: tag.id });
158
+ const checkPairs = records.map((r) => ({ taggableId: r.taggableId, taggableType: r.taggableType }));
159
+ const existing = await taggingState.find({ tagId: moveTo, $or: checkPairs });
160
+
161
+ const existingSet = new Set(existing.map((e) => `${e.taggableId}:${e.taggableType}`));
162
+ const toUpdate = [];
163
+ const toDelete = [];
164
+
165
+ for (const record of records) {
166
+ const key = `${record.taggableId}:${record.taggableType}`;
167
+ if (existingSet.has(key)) {
168
+ toDelete.push(record);
169
+ logger.info('tag already at moveTo, will delete record', { teamDid, tag, record });
170
+ } else {
171
+ toUpdate.push(record);
172
+ }
173
+ }
174
+
175
+ if (toUpdate.length > 0) {
176
+ await Promise.all(
177
+ toUpdate.map((record) =>
178
+ taggingState
179
+ .update(
180
+ { tagId: record.tagId, taggableId: record.taggableId, taggableType: record.taggableType },
181
+ { $set: { tagId: moveTo } }
182
+ )
183
+ .then(() => {
184
+ logger.info('tag moved successfully', { teamDid, tag, record, moveTo });
185
+ })
186
+ )
187
+ );
188
+ }
189
+
190
+ if (toDelete.length > 0) {
191
+ await Promise.all(
192
+ toDelete.map((record) =>
193
+ taggingState.remove(record).then(() => {
194
+ logger.info('tagging deleted successfully', { teamDid, tag, record });
195
+ })
196
+ )
197
+ );
198
+ }
199
+ }
200
+
201
+ const doc = await state.remove({ id: tag.id });
202
+ await taggingState.remove({ tagId: tag.id });
203
+ logger.info('tags deleted successfully', { teamDid, tag });
204
+ return doc;
205
+ }
206
+
207
+ /**
208
+ * Get tags
209
+ * @param {Object} api - TeamAPI instance
210
+ * @param {Object} params
211
+ * @param {string} params.teamDid - Team DID
212
+ * @param {Object} params.paging - Paging options
213
+ * @returns {Promise<Object>}
214
+ */
215
+ async function getTags(api, { teamDid, paging }) {
216
+ const state = await api.getTagState(teamDid);
217
+ const result = await state.paginate({}, { createdAt: -1 }, { pageSize: 20, ...paging });
218
+ return { tags: result.list, paging: result.paging };
219
+ }
220
+
221
+ module.exports = {
222
+ taggingSchema,
223
+ createTagging,
224
+ deleteTagging,
225
+ getTag,
226
+ createTag,
227
+ updateTag,
228
+ deleteTag,
229
+ getTags,
230
+ };
@@ -0,0 +1,132 @@
1
+ const { joinURL } = require('ufo');
2
+ const logger = require('@abtnode/logger')('@abtnode/core:api:team:user-auth');
3
+ const { ROLES } = require('@abtnode/constant');
4
+ const { TeamEvents } = require('@blocklet/constant');
5
+
6
+ /**
7
+ * Send new member notification
8
+ * @param {Object} api - TeamAPI instance
9
+ * @param {Object} user - User
10
+ * @param {Object} nodeInfo - Node info
11
+ * @returns {Promise<void>}
12
+ */
13
+ async function sendNewMemberNotification(api, user, nodeInfo) {
14
+ if (nodeInfo.nodeOwner && user.did !== nodeInfo.nodeOwner.did) {
15
+ const actionPath = '/team/members';
16
+ const action = process.env.NODE_ENV === 'production' ? joinURL(nodeInfo.routing.adminPath, actionPath) : actionPath;
17
+ await api.teamManager.createNotification({
18
+ title: 'New member join',
19
+ description: `User with Name (${user.fullName}) and DID (${user.did}) has joined this server`,
20
+ entityType: 'node',
21
+ action,
22
+ entityId: user.did,
23
+ severity: 'success',
24
+ });
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Login user
30
+ * @param {Object} api - TeamAPI instance
31
+ * @param {Object} params
32
+ * @param {string} params.teamDid - Team DID
33
+ * @param {Object} params.user - User
34
+ * @param {boolean} params.notify - Send notification
35
+ * @param {boolean} params.force - Force login
36
+ * @returns {Promise<Object>}
37
+ */
38
+ async function loginUser(api, { teamDid, user, notify = true, force = false }) {
39
+ const state = await api.getUserState(teamDid);
40
+ const nodeInfo = await api.node.read();
41
+
42
+ if (user.role === ROLES.OWNER) {
43
+ if (teamDid !== nodeInfo.did && !force) {
44
+ throw new Error('Cannot add user of owner role');
45
+ }
46
+ if (await state.count({ role: ROLES.OWNER })) {
47
+ throw new Error('The owner already exists');
48
+ }
49
+ }
50
+
51
+ const { _action, ...doc } = await state.loginUser(user);
52
+ if (_action === 'update') {
53
+ logger.info('user updated successfully', { teamDid, userDid: user.did });
54
+ api.emit(TeamEvents.userUpdated, { teamDid, user: doc });
55
+ } else if (_action === 'add') {
56
+ api.createDefaultOrgForUser({ teamDid, user });
57
+
58
+ if (teamDid === nodeInfo.did && nodeInfo.nodeOwner && user.did !== nodeInfo.nodeOwner.did && notify) {
59
+ await sendNewMemberNotification(api, user, nodeInfo);
60
+ }
61
+
62
+ logger.info('user added successfully', { teamDid, userDid: user.did, userPk: user.pk, userName: user.fullName });
63
+ api.emit(TeamEvents.userAdded, { teamDid, user: doc });
64
+ }
65
+ return doc;
66
+ }
67
+
68
+ /**
69
+ * Disconnect user account
70
+ * @param {Object} api - TeamAPI instance
71
+ * @param {Object} params
72
+ * @param {string} params.teamDid - Team DID
73
+ * @param {Object} params.connectedAccount - Connected account
74
+ * @returns {Promise<Object>}
75
+ */
76
+ async function disconnectUserAccount(api, { teamDid, connectedAccount }) {
77
+ const state = await api.getUserState(teamDid);
78
+ const result = await state.disconnectUserAccount(connectedAccount);
79
+
80
+ logger.info('user disconnect account successfully', {
81
+ teamDid,
82
+ connectedAccountDid: connectedAccount.did,
83
+ connectedAccountPk: connectedAccount.pk,
84
+ connectedAccountProvider: connectedAccount.provider,
85
+ });
86
+ return result;
87
+ }
88
+
89
+ /**
90
+ * Add user
91
+ * @param {Object} api - TeamAPI instance
92
+ * @param {Object} params
93
+ * @param {string} params.teamDid - Team DID
94
+ * @param {Object} params.user - User
95
+ * @param {boolean} params.force - Force add
96
+ * @returns {Promise<Object>}
97
+ */
98
+ async function addUser(api, { teamDid, user, force = false }) {
99
+ const state = await api.getUserState(teamDid);
100
+
101
+ if (user.role === ROLES.OWNER) {
102
+ const nodeInfo = await api.node.read();
103
+
104
+ if (teamDid !== nodeInfo.did && !force) {
105
+ throw new Error('Cannot add user of owner role');
106
+ }
107
+
108
+ if (await state.count({ role: ROLES.OWNER })) {
109
+ throw new Error('The owner already exists');
110
+ }
111
+ }
112
+
113
+ const doc = await state.addUser(user);
114
+
115
+ logger.info('user added successfully', { teamDid, userDid: user.did, userPk: user.pk, userName: user.fullName });
116
+
117
+ const nodeInfo = await api.node.read();
118
+ if (teamDid === nodeInfo.did && nodeInfo.nodeOwner && user.did !== nodeInfo.nodeOwner.did) {
119
+ await sendNewMemberNotification(api, user, nodeInfo);
120
+ }
121
+
122
+ api.emit(TeamEvents.userAdded, { teamDid, user: doc });
123
+
124
+ return doc;
125
+ }
126
+
127
+ module.exports = {
128
+ sendNewMemberNotification,
129
+ loginUser,
130
+ disconnectUserAccount,
131
+ addUser,
132
+ };
@@ -0,0 +1,78 @@
1
+ /**
2
+ * User Manager - Orchestrates user management operations
3
+ *
4
+ * This module re-exports functionality from specialized sub-modules:
5
+ * - user-auth-manager.js: User authentication and login operations
6
+ * - user-query-manager.js: User query and search operations
7
+ * - user-social-manager.js: User follow, invite, and webhook operations
8
+ * - user-update-manager.js: User update and modification operations
9
+ */
10
+
11
+ const { sendNewMemberNotification, loginUser, disconnectUserAccount, addUser } = require('./user-auth-manager');
12
+ const {
13
+ getUsers,
14
+ getUsersCount,
15
+ getUsersCountPerRole,
16
+ getUser,
17
+ getConnectedAccount,
18
+ isEmailUsed,
19
+ isPhoneUsed,
20
+ getUserByDid,
21
+ isUserValid,
22
+ isPassportValid,
23
+ isConnectedAccount,
24
+ getOwner,
25
+ } = require('./user-query-manager');
26
+ const {
27
+ USER_RELATION_ACTIONS,
28
+ USER_RELATION_QUERIES,
29
+ userFollowAction,
30
+ getUserFollows,
31
+ getUserFollowStats,
32
+ checkFollowing,
33
+ getUserInvites,
34
+ createWebhookDisabledNotification,
35
+ updateWebHookState,
36
+ } = require('./user-social-manager');
37
+ const {
38
+ updateUser,
39
+ updateUserAddress,
40
+ updateUserTags,
41
+ removeUser,
42
+ updateUserApproval,
43
+ switchProfile,
44
+ } = require('./user-update-manager');
45
+
46
+ module.exports = {
47
+ USER_RELATION_ACTIONS,
48
+ USER_RELATION_QUERIES,
49
+ sendNewMemberNotification,
50
+ loginUser,
51
+ disconnectUserAccount,
52
+ addUser,
53
+ getUsers,
54
+ getUsersCount,
55
+ getUsersCountPerRole,
56
+ getUser,
57
+ getConnectedAccount,
58
+ isEmailUsed,
59
+ isPhoneUsed,
60
+ getUserByDid,
61
+ isUserValid,
62
+ isPassportValid,
63
+ isConnectedAccount,
64
+ getOwner,
65
+ userFollowAction,
66
+ getUserFollows,
67
+ getUserFollowStats,
68
+ checkFollowing,
69
+ getUserInvites,
70
+ createWebhookDisabledNotification,
71
+ updateWebHookState,
72
+ updateUser,
73
+ updateUserAddress,
74
+ updateUserTags,
75
+ removeUser,
76
+ updateUserApproval,
77
+ switchProfile,
78
+ };