carto-cli 0.1.0-rc.1

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,459 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.usersList = usersList;
4
+ exports.usersGet = usersGet;
5
+ exports.usersInvite = usersInvite;
6
+ exports.usersResendInvitation = usersResendInvitation;
7
+ exports.usersCancelInvitation = usersCancelInvitation;
8
+ exports.usersDelete = usersDelete;
9
+ exports.usersInvitations = usersInvitations;
10
+ const api_1 = require("../api");
11
+ const colors_1 = require("../colors");
12
+ /**
13
+ * List all users in the organization
14
+ */
15
+ async function usersList(options, token, baseUrl, jsonOutput, debug = false, profile) {
16
+ try {
17
+ const client = await api_1.ApiClient.create(token, baseUrl, debug, profile);
18
+ let users;
19
+ if (options.all) {
20
+ // Fetch all pages automatically
21
+ // Note: We'll use a simple pagination approach since we don't know the exact API pagination format
22
+ let page = 1;
23
+ const pageSize = 100;
24
+ const allUsers = [];
25
+ let hasMore = true;
26
+ while (hasMore) {
27
+ const params = new URLSearchParams();
28
+ params.append('page', page.toString());
29
+ params.append('page_size', pageSize.toString());
30
+ if (options.role)
31
+ params.append('role', options.role);
32
+ if (options.search)
33
+ params.append('search', options.search);
34
+ const queryString = params.toString();
35
+ const url = `/accounts/users${queryString ? '?' + queryString : ''}`;
36
+ const result = await client.getAccounts(url, true);
37
+ const pageUsers = Array.isArray(result) ? result : (result.data || result.results || []);
38
+ if (pageUsers.length === 0) {
39
+ hasMore = false;
40
+ }
41
+ else {
42
+ allUsers.push(...pageUsers);
43
+ if (pageUsers.length < pageSize) {
44
+ hasMore = false;
45
+ }
46
+ page++;
47
+ }
48
+ }
49
+ users = allUsers;
50
+ }
51
+ else {
52
+ // Fetch with pagination parameters or defaults
53
+ const params = new URLSearchParams();
54
+ if (options.page)
55
+ params.append('page', options.page);
56
+ if (options.pageSize)
57
+ params.append('page_size', options.pageSize);
58
+ if (options.role)
59
+ params.append('role', options.role);
60
+ if (options.search)
61
+ params.append('search', options.search);
62
+ const queryString = params.toString();
63
+ const url = `/accounts/users${queryString ? '?' + queryString : ''}`;
64
+ const result = await client.getAccounts(url, true);
65
+ users = Array.isArray(result) ? result : (result.data || result.results || []);
66
+ }
67
+ if (jsonOutput) {
68
+ console.log(JSON.stringify(users));
69
+ }
70
+ else {
71
+ console.log((0, colors_1.bold)(`\nUsers (${users.length}):\n`));
72
+ users.forEach((user) => {
73
+ console.log((0, colors_1.bold)('Name: ') + (user.name || 'N/A'));
74
+ console.log(' Email: ' + user.email);
75
+ console.log(' User ID: ' + user.user_id);
76
+ if (user.app_metadata?.roles && user.app_metadata.roles.length > 0) {
77
+ console.log(' Roles: ' + user.app_metadata.roles.join(', '));
78
+ }
79
+ console.log(' Verified: ' + (user.email_verified ? 'Yes' : 'No'));
80
+ console.log(' Created: ' + new Date(user.created_at).toLocaleString());
81
+ if (user.user_metadata) {
82
+ console.log(' Organization: ' + user.user_metadata.account_name + ' (' + user.user_metadata.account_id + ')');
83
+ }
84
+ if (user.groups && user.groups.length > 0) {
85
+ console.log(' Groups: ' + user.groups.join(', '));
86
+ }
87
+ console.log('');
88
+ });
89
+ if (options.all) {
90
+ console.log((0, colors_1.dim)(`Fetched all ${users.length} users`));
91
+ }
92
+ }
93
+ }
94
+ catch (err) {
95
+ if (jsonOutput) {
96
+ console.log(JSON.stringify({ success: false, error: err.message }));
97
+ }
98
+ else {
99
+ if (err.message.includes('401') || err.message.includes('Token not defined')) {
100
+ console.log((0, colors_1.error)('✗ Authentication required'));
101
+ console.log('Please run: carto auth login');
102
+ }
103
+ else if (err.message.includes('403')) {
104
+ console.log((0, colors_1.error)('✗ Access denied'));
105
+ console.log('You may not have sufficient permissions to view users.');
106
+ }
107
+ else {
108
+ console.log((0, colors_1.error)('✗ Failed to list users: ' + err.message));
109
+ }
110
+ }
111
+ process.exit(1);
112
+ }
113
+ }
114
+ /**
115
+ * Get detailed information about a specific user
116
+ */
117
+ async function usersGet(userIdOrEmail, token, baseUrl, jsonOutput, debug = false, profile) {
118
+ try {
119
+ const client = await api_1.ApiClient.create(token, baseUrl, debug, profile);
120
+ // Search for the user (works for both email and user_id)
121
+ let searchTerm = userIdOrEmail;
122
+ // For user IDs, we need to search through all users since there's no GET /accounts/users/{id} endpoint
123
+ const searchUrl = `/accounts/users${searchTerm.includes('@') ? '?search=' + encodeURIComponent(searchTerm) : ''}`;
124
+ const searchResults = await client.getAccounts(searchUrl, true);
125
+ const users = Array.isArray(searchResults) ? searchResults : (searchResults.data || searchResults.results || []);
126
+ // Find exact match (by email or user_id)
127
+ let user;
128
+ if (userIdOrEmail.includes('@')) {
129
+ user = users.find((u) => u.email.toLowerCase() === userIdOrEmail.toLowerCase());
130
+ }
131
+ else {
132
+ user = users.find((u) => u.user_id === userIdOrEmail);
133
+ }
134
+ if (!user) {
135
+ throw new Error(`User not found: ${userIdOrEmail}`);
136
+ }
137
+ if (jsonOutput) {
138
+ console.log(JSON.stringify(user));
139
+ }
140
+ else {
141
+ console.log((0, colors_1.bold)('\n=== User Details ===\n'));
142
+ console.log((0, colors_1.bold)('User ID: ') + user.user_id);
143
+ console.log((0, colors_1.bold)('Name: ') + (user.name || 'N/A'));
144
+ console.log((0, colors_1.bold)('Email: ') + user.email);
145
+ console.log((0, colors_1.bold)('Nickname: ') + (user.nickname || 'N/A'));
146
+ console.log((0, colors_1.bold)('Email Verified: ') + (user.email_verified ? 'Yes' : 'No'));
147
+ console.log((0, colors_1.bold)('Created: ') + new Date(user.created_at).toLocaleString());
148
+ if (user.picture) {
149
+ console.log((0, colors_1.bold)('Picture: ') + user.picture);
150
+ }
151
+ if (user.user_metadata) {
152
+ console.log((0, colors_1.bold)('\nOrganization:'));
153
+ console.log(' Account ID: ' + user.user_metadata.account_id);
154
+ console.log(' Account Name: ' + user.user_metadata.account_name);
155
+ console.log(' Tenant: ' + user.user_metadata.tenant_domain + ' (' + user.user_metadata.tenant_id + ')');
156
+ }
157
+ if (user.app_metadata?.roles && user.app_metadata.roles.length > 0) {
158
+ console.log((0, colors_1.bold)('\nRoles: ') + user.app_metadata.roles.join(', '));
159
+ }
160
+ if (user.groups && user.groups.length > 0) {
161
+ console.log((0, colors_1.bold)('\nGroups: ') + user.groups.join(', '));
162
+ }
163
+ if (user.identities && user.identities.length > 0) {
164
+ console.log((0, colors_1.bold)('\nIdentities:'));
165
+ user.identities.forEach((identity) => {
166
+ console.log(` - ${identity.provider} (${identity.connection})`);
167
+ });
168
+ }
169
+ }
170
+ }
171
+ catch (err) {
172
+ if (jsonOutput) {
173
+ console.log(JSON.stringify({ success: false, error: err.message }));
174
+ }
175
+ else {
176
+ if (err.message.includes('401') || err.message.includes('Token not defined')) {
177
+ console.log((0, colors_1.error)('✗ Authentication required'));
178
+ console.log('Please run: carto auth login');
179
+ }
180
+ else if (err.message.includes('403')) {
181
+ console.log((0, colors_1.error)('✗ Access denied'));
182
+ console.log('You may not have sufficient permissions to view this user.');
183
+ }
184
+ else if (err.message.includes('404')) {
185
+ console.log((0, colors_1.error)('✗ User not found: ' + userIdOrEmail));
186
+ }
187
+ else {
188
+ console.log((0, colors_1.error)('✗ Failed to get user details: ' + err.message));
189
+ }
190
+ }
191
+ process.exit(1);
192
+ }
193
+ }
194
+ /**
195
+ * Invite new users to the organization
196
+ */
197
+ async function usersInvite(emails, role, token, baseUrl, jsonOutput, debug = false, profile) {
198
+ try {
199
+ const client = await api_1.ApiClient.create(token, baseUrl, debug, profile);
200
+ // Validate role
201
+ const validRoles = ['Builder', 'Viewer', 'Guest'];
202
+ if (!validRoles.includes(role)) {
203
+ throw new Error(`Invalid role: ${role}. Valid roles are: ${validRoles.join(', ')}`);
204
+ }
205
+ // Prepare request body
206
+ const body = {
207
+ email: emails,
208
+ target_role: role
209
+ };
210
+ const url = `/accounts/invite`;
211
+ const results = await client.postAccounts(url, body, true);
212
+ if (jsonOutput) {
213
+ console.log(JSON.stringify({ success: true, results }));
214
+ }
215
+ else {
216
+ console.log((0, colors_1.success)('\n✓ Invitation(s) sent\n'));
217
+ results.forEach((result) => {
218
+ if (result.code === 200 && result.status === 'sent') {
219
+ console.log((0, colors_1.success)('✓ ') + result.destination + ' - ' + (0, colors_1.info)(result.status));
220
+ }
221
+ else {
222
+ console.log((0, colors_1.error)('✗ ') + result.destination + ' - ' + (0, colors_1.error)(result.status));
223
+ if (result.message) {
224
+ console.log(' ' + (0, colors_1.dim)(result.message));
225
+ }
226
+ }
227
+ });
228
+ console.log('');
229
+ console.log((0, colors_1.info)(`Role: ${role}`));
230
+ }
231
+ }
232
+ catch (err) {
233
+ if (jsonOutput) {
234
+ console.log(JSON.stringify({ success: false, error: err.message }));
235
+ }
236
+ else {
237
+ if (err.message.includes('401') || err.message.includes('Token not defined')) {
238
+ console.log((0, colors_1.error)('✗ Authentication required'));
239
+ console.log('Please run: carto auth login');
240
+ }
241
+ else if (err.message.includes('403')) {
242
+ console.log((0, colors_1.error)('✗ Access denied'));
243
+ console.log('You may not have sufficient permissions to invite users.');
244
+ }
245
+ else {
246
+ console.log((0, colors_1.error)('✗ Failed to invite users: ' + err.message));
247
+ }
248
+ }
249
+ process.exit(1);
250
+ }
251
+ }
252
+ /**
253
+ * Resend a pending invitation
254
+ */
255
+ async function usersResendInvitation(token, apiToken, baseUrl, jsonOutput, debug = false, profile) {
256
+ try {
257
+ const client = await api_1.ApiClient.create(apiToken, baseUrl, debug, profile);
258
+ const url = `/accounts/invitations/re-send`;
259
+ const body = { token };
260
+ const result = await client.postAccounts(url, body, true);
261
+ if (jsonOutput) {
262
+ console.log(JSON.stringify({ success: true, ...result }));
263
+ }
264
+ else {
265
+ console.log((0, colors_1.success)('\n✓ Invitation resent successfully\n'));
266
+ }
267
+ }
268
+ catch (err) {
269
+ if (jsonOutput) {
270
+ console.log(JSON.stringify({ success: false, error: err.message }));
271
+ }
272
+ else {
273
+ if (err.message.includes('401') || err.message.includes('Token not defined')) {
274
+ console.log((0, colors_1.error)('✗ Authentication required'));
275
+ console.log('Please run: carto auth login');
276
+ }
277
+ else if (err.message.includes('403')) {
278
+ console.log((0, colors_1.error)('✗ Access denied'));
279
+ console.log('You may not have sufficient permissions to resend invitations.');
280
+ }
281
+ else if (err.message.includes('404')) {
282
+ console.log((0, colors_1.error)('✗ Invitation not found'));
283
+ }
284
+ else {
285
+ console.log((0, colors_1.error)('✗ Failed to resend invitation: ' + err.message));
286
+ }
287
+ }
288
+ process.exit(1);
289
+ }
290
+ }
291
+ /**
292
+ * Cancel a pending invitation
293
+ */
294
+ async function usersCancelInvitation(token, apiToken, baseUrl, jsonOutput, debug = false, profile) {
295
+ try {
296
+ const client = await api_1.ApiClient.create(apiToken, baseUrl, debug, profile);
297
+ const url = `/accounts/invite/${token}`;
298
+ const response = await client.deleteAccounts(url, true);
299
+ if (jsonOutput) {
300
+ console.log(JSON.stringify({ success: true, ...response }));
301
+ }
302
+ else {
303
+ console.log((0, colors_1.success)('\n✓ Invitation cancelled successfully\n'));
304
+ if (response.status) {
305
+ console.log((0, colors_1.info)(`Status: ${response.status}`));
306
+ }
307
+ }
308
+ }
309
+ catch (err) {
310
+ if (jsonOutput) {
311
+ console.log(JSON.stringify({ success: false, error: err.message }));
312
+ }
313
+ else {
314
+ if (err.message.includes('401') || err.message.includes('Token not defined')) {
315
+ console.log((0, colors_1.error)('✗ Authentication required'));
316
+ console.log('Please run: carto auth login');
317
+ }
318
+ else if (err.message.includes('403')) {
319
+ console.log((0, colors_1.error)('✗ Access denied'));
320
+ console.log('You may not have sufficient permissions to cancel invitations.');
321
+ }
322
+ else if (err.message.includes('404')) {
323
+ console.log((0, colors_1.error)('✗ Invitation not found'));
324
+ }
325
+ else {
326
+ console.log((0, colors_1.error)('✗ Failed to cancel invitation: ' + err.message));
327
+ }
328
+ }
329
+ process.exit(1);
330
+ }
331
+ }
332
+ /**
333
+ * Helper function to resolve user identifier (email or user_id) to user_id
334
+ */
335
+ async function resolveUserId(userIdOrEmail, client) {
336
+ // If it's already a user ID format, return it directly
337
+ if (!userIdOrEmail.includes('@')) {
338
+ return { userId: userIdOrEmail, email: '' };
339
+ }
340
+ // It's an email, search for the user
341
+ const searchUrl = `/accounts/users?search=${encodeURIComponent(userIdOrEmail)}`;
342
+ const searchResults = await client.getAccounts(searchUrl, true);
343
+ const users = Array.isArray(searchResults) ? searchResults : (searchResults.data || searchResults.results || []);
344
+ const user = users.find((u) => u.email.toLowerCase() === userIdOrEmail.toLowerCase());
345
+ if (!user) {
346
+ throw new Error(`User not found: ${userIdOrEmail}`);
347
+ }
348
+ return { userId: user.user_id, email: user.email };
349
+ }
350
+ /**
351
+ * Delete a user from the organization
352
+ */
353
+ async function usersDelete(userIdOrEmail, receiverUserIdOrEmail, apiToken, baseUrl, jsonOutput, debug = false, profile) {
354
+ try {
355
+ const client = await api_1.ApiClient.create(apiToken, baseUrl, debug, profile);
356
+ // Resolve both user identifiers to user IDs
357
+ const userToDelete = await resolveUserId(userIdOrEmail, client);
358
+ const receiverUser = await resolveUserId(receiverUserIdOrEmail, client);
359
+ // URL encode the user IDs
360
+ const encodedUserId = encodeURIComponent(userToDelete.userId);
361
+ const encodedReceiverUserId = encodeURIComponent(receiverUser.userId);
362
+ const url = `/users/${encodedUserId}?resourcesReceiverUserId=${encodedReceiverUserId}`;
363
+ const response = await client.deleteAccounts(url, true);
364
+ if (jsonOutput) {
365
+ console.log(JSON.stringify({
366
+ success: true,
367
+ deletedUserId: userToDelete.userId,
368
+ deletedUserEmail: userToDelete.email || userIdOrEmail,
369
+ receiverUserId: receiverUser.userId,
370
+ receiverUserEmail: receiverUser.email || receiverUserIdOrEmail,
371
+ ...response
372
+ }));
373
+ }
374
+ else {
375
+ console.log((0, colors_1.success)('\n✓ User deleted successfully\n'));
376
+ console.log((0, colors_1.info)(`Deleted user: ${userToDelete.email || userToDelete.userId}`));
377
+ console.log((0, colors_1.info)(`Resources transferred to: ${receiverUser.email || receiverUser.userId}`));
378
+ }
379
+ }
380
+ catch (err) {
381
+ if (jsonOutput) {
382
+ console.log(JSON.stringify({ success: false, error: err.message }));
383
+ }
384
+ else {
385
+ if (err.message.includes('401') || err.message.includes('Token not defined')) {
386
+ console.log((0, colors_1.error)('✗ Authentication required'));
387
+ console.log('Please run: carto auth login');
388
+ }
389
+ else if (err.message.includes('403')) {
390
+ console.log((0, colors_1.error)('✗ Access denied'));
391
+ console.log('You may not have sufficient permissions to delete users.');
392
+ }
393
+ else if (err.message.includes('404') || err.message.includes('User not found')) {
394
+ console.log((0, colors_1.error)('✗ User not found: ' + err.message));
395
+ }
396
+ else {
397
+ console.log((0, colors_1.error)('✗ Failed to delete user: ' + err.message));
398
+ }
399
+ }
400
+ process.exit(1);
401
+ }
402
+ }
403
+ /**
404
+ * List pending invitations
405
+ */
406
+ async function usersInvitations(token, baseUrl, jsonOutput, debug = false, profile) {
407
+ try {
408
+ const client = await api_1.ApiClient.create(token, baseUrl, debug, profile);
409
+ const url = `/accounts/invitations/in-progress`;
410
+ const invitations = await client.getAccounts(url, true);
411
+ if (jsonOutput) {
412
+ console.log(JSON.stringify(invitations));
413
+ }
414
+ else {
415
+ const invitationList = invitations.invitations || [];
416
+ if (invitationList.length === 0) {
417
+ console.log((0, colors_1.info)('\nNo pending invitations'));
418
+ }
419
+ else {
420
+ console.log((0, colors_1.bold)(`\nPending Invitations (${invitationList.length}):\n`));
421
+ invitationList.forEach((invitation) => {
422
+ console.log((0, colors_1.bold)('Email: ') + invitation.recipient);
423
+ if (invitation.targetRole) {
424
+ console.log(' Role: ' + invitation.targetRole);
425
+ }
426
+ if (invitation.requestedAt) {
427
+ console.log(' Sent: ' + new Date(invitation.requestedAt).toLocaleString());
428
+ }
429
+ if (invitation.status) {
430
+ console.log(' Status: ' + invitation.status);
431
+ }
432
+ if (invitation.expired !== undefined) {
433
+ console.log(' Expired: ' + (invitation.expired ? 'Yes' : 'No'));
434
+ }
435
+ console.log('');
436
+ });
437
+ }
438
+ }
439
+ }
440
+ catch (err) {
441
+ if (jsonOutput) {
442
+ console.log(JSON.stringify({ success: false, error: err.message }));
443
+ }
444
+ else {
445
+ if (err.message.includes('401') || err.message.includes('Token not defined')) {
446
+ console.log((0, colors_1.error)('✗ Authentication required'));
447
+ console.log('Please run: carto auth login');
448
+ }
449
+ else if (err.message.includes('403')) {
450
+ console.log((0, colors_1.error)('✗ Access denied'));
451
+ console.log('You may not have sufficient permissions to view invitations.');
452
+ }
453
+ else {
454
+ console.log((0, colors_1.error)('✗ Failed to list invitations: ' + err.message));
455
+ }
456
+ }
457
+ process.exit(1);
458
+ }
459
+ }