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,412 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.connectionsList = connectionsList;
4
+ exports.connectionsGet = connectionsGet;
5
+ exports.connectionsCreate = connectionsCreate;
6
+ exports.connectionsUpdate = connectionsUpdate;
7
+ exports.connectionsDelete = connectionsDelete;
8
+ exports.connectionsBrowse = connectionsBrowse;
9
+ exports.connectionsDescribe = connectionsDescribe;
10
+ const api_1 = require("../api");
11
+ const colors_1 = require("../colors");
12
+ const prompt_1 = require("../prompt");
13
+ async function connectionsList(options, token, baseUrl, jsonOutput, debug = false, profile) {
14
+ try {
15
+ const client = await api_1.ApiClient.create(token, baseUrl, debug, profile);
16
+ let result;
17
+ if (options.all || options.page || options.pageSize || options.search) {
18
+ // Fetch with parameters - workspace API doesn't support pagination the same way
19
+ // For now, fetch from workspace API without pagination
20
+ const params = new URLSearchParams();
21
+ if (options.search)
22
+ params.append('search', options.search);
23
+ const queryString = params.toString();
24
+ const path = `/connections${queryString ? '?' + queryString : ''}`;
25
+ result = await client.getWorkspace(path);
26
+ }
27
+ else {
28
+ // Fetch default (no pagination)
29
+ result = await client.getWorkspace('/connections');
30
+ }
31
+ if (jsonOutput) {
32
+ console.log(JSON.stringify(result));
33
+ }
34
+ else {
35
+ const connections = Array.isArray(result) ? result : (result.data || result.results || result);
36
+ const total = result.total || connections.length;
37
+ console.log((0, colors_1.bold)(`\nConnections (${total}):\n`));
38
+ connections.forEach((conn) => {
39
+ console.log((0, colors_1.bold)('ID: ') + conn.id);
40
+ console.log(' Name: ' + conn.name);
41
+ console.log(' Type: ' + (conn.provider_id || conn.type));
42
+ console.log(' Privacy: ' + (conn.privacy || 'unknown'));
43
+ // Show sharing scope if available
44
+ if (conn.sharingScope) {
45
+ console.log(' Sharing: ' + conn.sharingScope);
46
+ }
47
+ // Show owner email from workspace API
48
+ if (conn.ownerEmail) {
49
+ console.log(' Owner: ' + conn.ownerEmail);
50
+ }
51
+ else if (conn.config?.credentials?.client_email) {
52
+ console.log(' Owner: ' + conn.config.credentials.client_email);
53
+ }
54
+ else if (conn.user_id) {
55
+ console.log(' User ID: ' + conn.user_id);
56
+ }
57
+ // Show map count if available
58
+ if (conn.mapcount !== undefined) {
59
+ console.log(' Maps using: ' + conn.mapcount);
60
+ }
61
+ if (conn.description)
62
+ console.log(' Description: ' + conn.description);
63
+ console.log(' Created: ' + new Date(conn.created_at).toLocaleString());
64
+ console.log(' Updated: ' + new Date(conn.updated_at).toLocaleString());
65
+ console.log('');
66
+ });
67
+ if (options.all) {
68
+ console.log((0, colors_1.dim)(`Fetched all ${total} connections`));
69
+ }
70
+ else if (result.total && result.page_size) {
71
+ const totalPages = Math.ceil(result.total / result.page_size);
72
+ console.log((0, colors_1.dim)(`Page ${result.page || 1} of ${totalPages} (use --all to fetch all pages)`));
73
+ }
74
+ }
75
+ }
76
+ catch (err) {
77
+ if (jsonOutput) {
78
+ console.log(JSON.stringify({ success: false, error: err.message }));
79
+ }
80
+ else {
81
+ if (err.message.includes('401') || err.message.includes('Token not defined')) {
82
+ console.log((0, colors_1.error)('βœ— Authentication required'));
83
+ console.log('Please run: carto auth login');
84
+ }
85
+ else {
86
+ console.log((0, colors_1.error)('βœ— Failed to list connections: ' + err.message));
87
+ }
88
+ }
89
+ process.exit(1);
90
+ }
91
+ }
92
+ async function connectionsGet(connectionId, token, baseUrl, jsonOutput, debug = false, profile) {
93
+ try {
94
+ const client = await api_1.ApiClient.create(token, baseUrl, debug, profile);
95
+ const result = await client.getWorkspace(`/connections/${connectionId}`);
96
+ if (jsonOutput) {
97
+ console.log(JSON.stringify(result));
98
+ }
99
+ else {
100
+ console.log((0, colors_1.bold)('\nConnection Details:\n'));
101
+ console.log((0, colors_1.bold)('ID: ') + result.id);
102
+ console.log((0, colors_1.bold)('Name: ') + result.name);
103
+ console.log((0, colors_1.bold)('Type: ') + (result.provider_id || result.type));
104
+ console.log((0, colors_1.bold)('Privacy: ') + (result.privacy || 'unknown'));
105
+ // Show sharing scope if available
106
+ if (result.sharingScope) {
107
+ console.log((0, colors_1.bold)('Sharing: ') + result.sharingScope);
108
+ }
109
+ // Show owner email from workspace API
110
+ if (result.ownerEmail) {
111
+ console.log((0, colors_1.bold)('Owner: ') + result.ownerEmail);
112
+ }
113
+ else if (result.config?.credentials?.client_email) {
114
+ console.log((0, colors_1.bold)('Owner: ') + result.config.credentials.client_email);
115
+ }
116
+ else if (result.user_id) {
117
+ console.log((0, colors_1.bold)('User ID: ') + result.user_id);
118
+ }
119
+ // Show map count if available
120
+ if (result.mapcount !== undefined) {
121
+ console.log((0, colors_1.bold)('Maps using: ') + result.mapcount);
122
+ }
123
+ if (result.description)
124
+ console.log((0, colors_1.bold)('Description: ') + result.description);
125
+ console.log((0, colors_1.bold)('Created: ') + new Date(result.created_at).toLocaleString());
126
+ console.log((0, colors_1.bold)('Updated: ') + new Date(result.updated_at).toLocaleString());
127
+ if (result.parameters) {
128
+ console.log((0, colors_1.bold)('\nParameters:'));
129
+ Object.entries(result.parameters).forEach(([key, value]) => {
130
+ console.log(` ${key}: ${value}`);
131
+ });
132
+ }
133
+ }
134
+ }
135
+ catch (err) {
136
+ if (jsonOutput) {
137
+ console.log(JSON.stringify({ success: false, error: err.message }));
138
+ }
139
+ else {
140
+ console.log((0, colors_1.error)('βœ— Failed to get connection: ' + err.message));
141
+ }
142
+ process.exit(1);
143
+ }
144
+ }
145
+ async function connectionsCreate(body, token, baseUrl, jsonOutput, debug = false, profile) {
146
+ try {
147
+ const client = await api_1.ApiClient.create(token, baseUrl, debug, profile);
148
+ const result = await client.post('/v3/connections', body);
149
+ if (jsonOutput) {
150
+ console.log(JSON.stringify(result));
151
+ }
152
+ else {
153
+ console.log((0, colors_1.success)('βœ“ Connection created successfully'));
154
+ console.log((0, colors_1.bold)('\nID: ') + result.id);
155
+ console.log((0, colors_1.bold)('Name: ') + result.name);
156
+ console.log((0, colors_1.bold)('Type: ') + result.type);
157
+ }
158
+ }
159
+ catch (err) {
160
+ if (jsonOutput) {
161
+ console.log(JSON.stringify({ success: false, error: err.message }));
162
+ }
163
+ else {
164
+ console.log((0, colors_1.error)('βœ— Failed to create connection: ' + err.message));
165
+ }
166
+ process.exit(1);
167
+ }
168
+ }
169
+ async function connectionsUpdate(connectionId, body, token, baseUrl, jsonOutput, debug = false, profile) {
170
+ try {
171
+ const client = await api_1.ApiClient.create(token, baseUrl, debug, profile);
172
+ const result = await client.patch(`/v3/connections/${connectionId}`, body);
173
+ if (jsonOutput) {
174
+ console.log(JSON.stringify(result));
175
+ }
176
+ else {
177
+ console.log((0, colors_1.success)('βœ“ Connection updated successfully'));
178
+ console.log((0, colors_1.bold)('\nID: ') + result.id);
179
+ console.log((0, colors_1.bold)('Name: ') + result.name);
180
+ console.log((0, colors_1.bold)('Type: ') + result.type);
181
+ }
182
+ }
183
+ catch (err) {
184
+ if (jsonOutput) {
185
+ console.log(JSON.stringify({ success: false, error: err.message }));
186
+ }
187
+ else {
188
+ console.log((0, colors_1.error)('βœ— Failed to update connection: ' + err.message));
189
+ }
190
+ process.exit(1);
191
+ }
192
+ }
193
+ async function connectionsDelete(connectionId, token, baseUrl, jsonOutput, debug = false, profile, yes) {
194
+ try {
195
+ const client = await api_1.ApiClient.create(token, baseUrl, debug, profile);
196
+ // Skip confirmation if --yes or --json flag is set
197
+ const skipConfirmation = yes || jsonOutput;
198
+ if (!skipConfirmation) {
199
+ // Fetch connection details to show in confirmation prompt
200
+ let connectionDetails;
201
+ try {
202
+ connectionDetails = await client.getWorkspace(`/connections/${connectionId}`);
203
+ }
204
+ catch (err) {
205
+ // If we can't fetch details, proceed with generic message
206
+ console.log((0, colors_1.warning)('\n⚠️ Warning: This will permanently delete this connection.'));
207
+ console.log((0, colors_1.warning)(` Connection ID: ${connectionId}`));
208
+ }
209
+ if (connectionDetails) {
210
+ console.log((0, colors_1.warning)('\n⚠️ Warning: This will permanently delete:'));
211
+ console.log(` Connection: "${connectionDetails.name}"`);
212
+ console.log(` Type: ${connectionDetails.provider_id || connectionDetails.type}`);
213
+ console.log(` ID: ${connectionId}`);
214
+ if (connectionDetails.mapcount !== undefined && connectionDetails.mapcount > 0) {
215
+ console.log((0, colors_1.warning)(` ⚠️ This connection is used by ${connectionDetails.mapcount} map(s)`));
216
+ }
217
+ }
218
+ console.log('');
219
+ const confirmed = await (0, prompt_1.promptForConfirmation)("Type 'delete' to confirm: ", 'delete');
220
+ if (!confirmed) {
221
+ console.log('\nDeletion cancelled');
222
+ process.exit(0);
223
+ }
224
+ console.log('');
225
+ }
226
+ await client.delete(`/v3/connections/${connectionId}`);
227
+ if (jsonOutput) {
228
+ console.log(JSON.stringify({ success: true, message: 'Connection deleted successfully', id: connectionId }));
229
+ }
230
+ else {
231
+ console.log((0, colors_1.success)(`βœ“ Connection ${connectionId} deleted successfully`));
232
+ }
233
+ }
234
+ catch (err) {
235
+ if (jsonOutput) {
236
+ console.log(JSON.stringify({ success: false, error: err.message }));
237
+ }
238
+ else {
239
+ console.log((0, colors_1.error)('βœ— Failed to delete connection: ' + err.message));
240
+ }
241
+ process.exit(1);
242
+ }
243
+ }
244
+ /**
245
+ * Helper function to resolve connection name to ID
246
+ */
247
+ async function resolveConnectionId(client, nameOrId) {
248
+ // If it looks like a UUID, return it as-is
249
+ if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(nameOrId)) {
250
+ return nameOrId;
251
+ }
252
+ // Otherwise, look up by name
253
+ const connections = await client.getWorkspace('/connections');
254
+ const connectionsList = Array.isArray(connections) ? connections : (connections.data || connections.results || []);
255
+ const found = connectionsList.find((c) => c.name === nameOrId);
256
+ if (!found) {
257
+ throw new Error(`Connection "${nameOrId}" not found`);
258
+ }
259
+ return found.id;
260
+ }
261
+ async function connectionsBrowse(connectionName, path, options, token, baseUrl, jsonOutput, debug = false, profile) {
262
+ try {
263
+ const client = await api_1.ApiClient.create(token, baseUrl, debug, profile);
264
+ // Resolve connection name to ID
265
+ const connectionId = await resolveConnectionId(client, connectionName);
266
+ // Build the resource path
267
+ let resourcePath = `/connections/${connectionId}/resources/`;
268
+ if (path) {
269
+ // URL encode the path
270
+ resourcePath += encodeURIComponent(path);
271
+ }
272
+ // Add pagination parameters
273
+ const params = new URLSearchParams();
274
+ params.append('pageSize', options.pageSize || '30');
275
+ params.append('page', options.page || '1');
276
+ resourcePath += '?' + params.toString();
277
+ const result = await client.getWorkspace(resourcePath);
278
+ if (jsonOutput) {
279
+ console.log(JSON.stringify(result));
280
+ }
281
+ else {
282
+ const children = result.children || [];
283
+ const type = result.type || 'connection';
284
+ const provider = result.provider || 'unknown';
285
+ console.log((0, colors_1.bold)(`\n${connectionName} (${provider}):`));
286
+ if (path) {
287
+ console.log((0, colors_1.dim)(`Path: ${path}\n`));
288
+ }
289
+ else {
290
+ console.log('');
291
+ }
292
+ if (children.length === 0) {
293
+ console.log((0, colors_1.dim)('No resources found'));
294
+ }
295
+ else {
296
+ children.forEach((child) => {
297
+ const icon = child.type === 'project' ? 'πŸ“' :
298
+ child.type === 'dataset' ? 'πŸ“‚' :
299
+ child.type === 'table' ? 'πŸ“Š' :
300
+ child.type === 'view' ? 'πŸ‘οΈ ' : 'β€’';
301
+ console.log(`${icon} ${(0, colors_1.bold)(child.name)} ${(0, colors_1.dim)(`(${child.type})`)}`);
302
+ if (child.location) {
303
+ console.log(` Location: ${child.location}`);
304
+ }
305
+ if (child._links?.resources) {
306
+ console.log((0, colors_1.dim)(` Path: ${child.id}`));
307
+ }
308
+ console.log('');
309
+ });
310
+ console.log((0, colors_1.dim)(`Total: ${result.totalChildren || children.length} ${type === 'connection' ? 'projects' : type === 'project' ? 'datasets' : 'resources'}`));
311
+ if (result.totalChildren > children.length) {
312
+ const currentPage = result.page || 1;
313
+ const pageSize = result.pageSize || 30;
314
+ const totalPages = Math.ceil(result.totalChildren / pageSize);
315
+ console.log((0, colors_1.dim)(`Page ${currentPage} of ${totalPages} (use --page <n> to see more)`));
316
+ }
317
+ }
318
+ }
319
+ }
320
+ catch (err) {
321
+ if (jsonOutput) {
322
+ console.log(JSON.stringify({ success: false, error: err.message }));
323
+ }
324
+ else {
325
+ if (err.message.includes('401') || err.message.includes('Token not defined')) {
326
+ console.log((0, colors_1.error)('βœ— Authentication required'));
327
+ console.log('Please run: carto auth login');
328
+ }
329
+ else {
330
+ console.log((0, colors_1.error)('βœ— Failed to browse connection: ' + err.message));
331
+ }
332
+ }
333
+ process.exit(1);
334
+ }
335
+ }
336
+ async function connectionsDescribe(connectionName, tablePath, token, baseUrl, jsonOutput, debug = false, profile) {
337
+ try {
338
+ const client = await api_1.ApiClient.create(token, baseUrl, debug, profile);
339
+ // Resolve connection name to ID
340
+ const connectionId = await resolveConnectionId(client, connectionName);
341
+ // Build the resource path with type=table to get schema details
342
+ const resourcePath = `/connections/${connectionId}/resources/${encodeURIComponent(tablePath)}?type=table`;
343
+ const result = await client.getWorkspace(resourcePath);
344
+ if (jsonOutput) {
345
+ console.log(JSON.stringify(result));
346
+ }
347
+ else {
348
+ console.log((0, colors_1.bold)('\nTable Details:\n'));
349
+ console.log((0, colors_1.bold)('ID: ') + result.id);
350
+ console.log((0, colors_1.bold)('Name: ') + result.name);
351
+ console.log((0, colors_1.bold)('Type: ') + result.type);
352
+ console.log((0, colors_1.bold)('Provider: ') + result.provider);
353
+ if (result.geomField) {
354
+ console.log((0, colors_1.bold)('Geometry Column: ') + result.geomField);
355
+ }
356
+ if (result.nrows !== undefined) {
357
+ console.log((0, colors_1.bold)('Rows: ') + result.nrows.toLocaleString());
358
+ }
359
+ if (result.size !== undefined) {
360
+ const sizeMB = (result.size / (1024 * 1024)).toFixed(2);
361
+ console.log((0, colors_1.bold)('Size: ') + `${sizeMB} MB`);
362
+ }
363
+ if (result.tableRegion) {
364
+ console.log((0, colors_1.bold)('Region: ') + result.tableRegion);
365
+ }
366
+ if (result.lastModified) {
367
+ console.log((0, colors_1.bold)('Last Modified: ') + new Date(result.lastModified).toLocaleString());
368
+ }
369
+ // Display schema
370
+ if (result.schema && result.schema.length > 0) {
371
+ console.log((0, colors_1.bold)('\nSchema:'));
372
+ console.log('');
373
+ result.schema.forEach((col) => {
374
+ const isGeom = col.name === result.geomField;
375
+ const colName = isGeom ? `${col.name} πŸ—ΊοΈ` : col.name;
376
+ console.log(` ${(0, colors_1.bold)(colName)}`);
377
+ console.log(` Type: ${col.type}`);
378
+ // Show original type if available
379
+ const originalCol = result.originalSchema?.find((c) => c.name === col.name);
380
+ if (originalCol && originalCol.type !== col.type) {
381
+ console.log((0, colors_1.dim)(` Original: ${originalCol.type}`));
382
+ }
383
+ console.log('');
384
+ });
385
+ console.log((0, colors_1.dim)(`Total columns: ${result.schema.length}`));
386
+ }
387
+ // Display optimization info if available
388
+ if (result.optimization?.actions) {
389
+ console.log((0, colors_1.bold)('\nOptimization:'));
390
+ result.optimization.actions.forEach((action) => {
391
+ const status = action.enabled ? 'βœ“' : 'βœ—';
392
+ console.log(` ${status} ${action.type}`);
393
+ });
394
+ }
395
+ }
396
+ }
397
+ catch (err) {
398
+ if (jsonOutput) {
399
+ console.log(JSON.stringify({ success: false, error: err.message }));
400
+ }
401
+ else {
402
+ if (err.message.includes('401') || err.message.includes('Token not defined')) {
403
+ console.log((0, colors_1.error)('βœ— Authentication required'));
404
+ console.log('Please run: carto auth login');
405
+ }
406
+ else {
407
+ console.log((0, colors_1.error)('βœ— Failed to describe table: ' + err.message));
408
+ }
409
+ }
410
+ process.exit(1);
411
+ }
412
+ }