1
+ interface Organization {
2
+ name : string ;
3
+ slug : string ;
4
+ type : string ;
5
+ overages : boolean ;
6
+ blocked_reads : boolean ;
7
+ blocked_writes : boolean ;
8
+ plan_id : string ;
9
+ plan_timeline : string ;
10
+ platform : string ;
11
+ }
12
+
13
+ interface Database {
14
+ Name : string ;
15
+ DbId : string ;
16
+ Hostname : string ;
17
+ block_reads : boolean ;
18
+ block_writes : boolean ;
19
+ regions : string [ ] ;
20
+ primaryRegion : string ;
21
+ group : string ;
22
+ delete_protection : boolean ;
23
+ parent ?: {
24
+ id : string ;
25
+ name : string ;
26
+ branched_at : string ;
27
+ } ;
28
+ }
29
+
30
+ interface DatabasesResponse {
31
+ databases : Database [ ] ;
32
+ }
33
+
34
+ interface Group {
35
+ name : string ;
36
+ version : string ;
37
+ uuid : string ;
38
+ locations : string [ ] ;
39
+ primary : string ;
40
+ delete_protection : boolean ;
41
+ }
42
+
43
+ interface GroupsResponse {
44
+ groups : Group [ ] ;
45
+ }
46
+
47
+ async function getAuthToken (
48
+ executeCommand : (
49
+ args : Fig . ExecuteCommandInput
50
+ ) => Promise < Fig . ExecuteCommandOutput >
51
+ ) : Promise < string | null > {
52
+ try {
53
+ const { stdout } = await executeCommand ( {
54
+ command : "turso" ,
55
+ args : [ "auth" , "token" ] ,
56
+ } ) ;
57
+
58
+ // Extract JWT token using regex
59
+ const tokenMatch = stdout . match (
60
+ / e y [ A - Z a - z 0 - 9 _ - ] + \. [ A - Z a - z 0 - 9 _ - ] + \. [ A - Z a - z 0 - 9 _ - ] + /
61
+ ) ;
62
+ return tokenMatch ? tokenMatch [ 0 ] : null ;
63
+ } catch ( error ) {
64
+ return null ;
65
+ }
66
+ }
67
+
68
+ async function fetchOrganizations (
69
+ token : string ,
70
+ executeCommand : (
71
+ args : Fig . ExecuteCommandInput
72
+ ) => Promise < Fig . ExecuteCommandOutput >
73
+ ) : Promise < Organization [ ] > {
74
+ try {
75
+ const { stdout, stderr } = await executeCommand ( {
76
+ command : "curl" ,
77
+ args : [
78
+ "-s" ,
79
+ "-H" ,
80
+ `Authorization: Bearer ${ token } ` ,
81
+ "https://api.turso.tech/v1/organizations" ,
82
+ ] ,
83
+ } ) ;
84
+
85
+ if ( stderr ) return [ ] ;
86
+
87
+ return JSON . parse ( stdout ) ;
88
+ } catch ( error ) {
89
+ return [ ] ;
90
+ }
91
+ }
92
+
93
+ async function fetchDatabases (
94
+ token : string ,
95
+ orgSlug : string ,
96
+ executeCommand : (
97
+ args : Fig . ExecuteCommandInput
98
+ ) => Promise < Fig . ExecuteCommandOutput >
99
+ ) : Promise < DatabasesResponse > {
100
+ try {
101
+ const { stdout, stderr } = await executeCommand ( {
102
+ command : "curl" ,
103
+ args : [
104
+ "-s" ,
105
+ "-H" ,
106
+ `Authorization: Bearer ${ token } ` ,
107
+ `https://api.turso.tech/v1/organizations/${ orgSlug } /databases` ,
108
+ ] ,
109
+ } ) ;
110
+
111
+ if ( stderr ) return { databases : [ ] } ;
112
+
113
+ return JSON . parse ( stdout ) ;
114
+ } catch ( error ) {
115
+ return { databases : [ ] } ;
116
+ }
117
+ }
118
+
119
+ async function fetchGroups (
120
+ token : string ,
121
+ orgSlug : string ,
122
+ executeCommand : (
123
+ args : Fig . ExecuteCommandInput
124
+ ) => Promise < Fig . ExecuteCommandOutput >
125
+ ) : Promise < GroupsResponse > {
126
+ try {
127
+ const { stdout, stderr } = await executeCommand ( {
128
+ command : "curl" ,
129
+ args : [
130
+ "-s" ,
131
+ "-H" ,
132
+ `Authorization: Bearer ${ token } ` ,
133
+ `https://api.turso.tech/v1/organizations/${ orgSlug } /groups` ,
134
+ ] ,
135
+ } ) ;
136
+
137
+ if ( stderr ) return { groups : [ ] } ;
138
+
139
+ return JSON . parse ( stdout ) ;
140
+ } catch ( error ) {
141
+ return { groups : [ ] } ;
142
+ }
143
+ }
144
+
145
+ // Reusable generators for autocompletion
146
+ const databaseGenerator : Fig . Generator = {
147
+ custom : async ( tokens , executeCommand ) => {
148
+ try {
149
+ const token = await getAuthToken ( executeCommand ) ;
150
+ if ( ! token ) return [ ] ;
151
+
152
+ const organizations = await fetchOrganizations ( token , executeCommand ) ;
153
+ if ( ! organizations || organizations . length === 0 ) return [ ] ;
154
+
155
+ const orgSlug = organizations [ 0 ] . slug ;
156
+ const databases = await fetchDatabases ( token , orgSlug , executeCommand ) ;
157
+
158
+ if ( ! databases || ! databases . databases ) return [ ] ;
159
+
160
+ return databases . databases . map ( ( db ) => ( {
161
+ name : db . Name ,
162
+ description : `Database in ${ db . regions . join ( ", " ) } regions` ,
163
+ icon : "fig://icon?type=box" ,
164
+ } ) ) ;
165
+ } catch ( error ) {
166
+ return [ ] ;
167
+ }
168
+ } ,
169
+ } ;
170
+
171
+ const groupGenerator : Fig . Generator = {
172
+ custom : async ( tokens , executeCommand ) => {
173
+ try {
174
+ const token = await getAuthToken ( executeCommand ) ;
175
+ if ( ! token ) return [ ] ;
176
+
177
+ const organizations = await fetchOrganizations ( token , executeCommand ) ;
178
+ if ( ! organizations || organizations . length === 0 ) return [ ] ;
179
+
180
+ const orgSlug = organizations [ 0 ] . slug ;
181
+ const groups = await fetchGroups ( token , orgSlug , executeCommand ) ;
182
+
183
+ if ( ! groups || ! groups . groups ) return [ ] ;
184
+
185
+ return groups . groups . map ( ( group ) => ( {
186
+ name : group . name ,
187
+ description : `Group in ${ group . locations . join ( ", " ) } locations` ,
188
+ icon : "fig://icon?type=box" ,
189
+ } ) ) ;
190
+ } catch ( error ) {
191
+ return [ ] ;
192
+ }
193
+ } ,
194
+ } ;
195
+
196
+ const organizationGenerator : Fig . Generator = {
197
+ custom : async ( tokens , executeCommand ) => {
198
+ try {
199
+ const token = await getAuthToken ( executeCommand ) ;
200
+ if ( ! token ) return [ ] ;
201
+
202
+ const organizations = await fetchOrganizations ( token , executeCommand ) ;
203
+ if ( ! organizations || organizations . length === 0 ) return [ ] ;
204
+
205
+ return organizations . map ( ( org ) => ( {
206
+ name : org . slug ,
207
+ description : `${ org . name } (${ org . type } , ${ org . plan_id } )` ,
208
+ icon : "fig://icon?type=box" ,
209
+ } ) ) ;
210
+ } catch ( error ) {
211
+ return [ ] ;
212
+ }
213
+ } ,
214
+ } ;
215
+
1
216
const completionSpec : Fig . Spec = {
2
217
name : "turso" ,
3
218
description : "Turso CLI for managing Turso databases" ,
@@ -38,6 +253,9 @@ const completionSpec: Fig.Spec = {
38
253
{
39
254
name : "revoke" ,
40
255
description : "Revoke an API token" ,
256
+ args : {
257
+ name : "api-token-name" ,
258
+ } ,
41
259
} ,
42
260
] ,
43
261
} ,
@@ -90,7 +308,7 @@ const completionSpec: Fig.Spec = {
90
308
name : "autoupdate" ,
91
309
description : "Configure autoupdate behavior" ,
92
310
args : {
93
- name : "on| off" ,
311
+ suggestions : [ "on" , " off"] ,
94
312
} ,
95
313
} ,
96
314
{
@@ -134,13 +352,15 @@ const completionSpec: Fig.Spec = {
134
352
description : "Destroy a database" ,
135
353
args : {
136
354
name : "name" ,
355
+ generators : databaseGenerator ,
137
356
} ,
138
357
} ,
139
358
{
140
359
name : "export" ,
141
360
description : "Export a database snapshot from Turso to SQLite file" ,
142
361
args : {
143
362
name : "name" ,
363
+ generators : databaseGenerator ,
144
364
} ,
145
365
} ,
146
366
{
@@ -157,6 +377,8 @@ const completionSpec: Fig.Spec = {
157
377
description : "Inspect database" ,
158
378
args : {
159
379
name : "name" ,
380
+ isVariadic : true ,
381
+ generators : databaseGenerator ,
160
382
} ,
161
383
} ,
162
384
{
@@ -172,6 +394,7 @@ const completionSpec: Fig.Spec = {
172
394
description : "Replicate a database" ,
173
395
args : {
174
396
name : "name" ,
397
+ generators : databaseGenerator ,
175
398
} ,
176
399
} ,
177
400
{
@@ -183,6 +406,7 @@ const completionSpec: Fig.Spec = {
183
406
description : "Show information from a database" ,
184
407
args : {
185
408
name : "name" ,
409
+ generators : databaseGenerator ,
186
410
} ,
187
411
} ,
188
412
{
@@ -198,6 +422,7 @@ const completionSpec: Fig.Spec = {
198
422
description : "Updates the database to the latest turso version" ,
199
423
args : {
200
424
name : "name" ,
425
+ generators : databaseGenerator ,
201
426
} ,
202
427
} ,
203
428
] ,
@@ -215,6 +440,7 @@ const completionSpec: Fig.Spec = {
215
440
description : "Manage group config" ,
216
441
args : {
217
442
name : "name" ,
443
+ generators : groupGenerator ,
218
444
} ,
219
445
} ,
220
446
{
@@ -229,6 +455,7 @@ const completionSpec: Fig.Spec = {
229
455
description : "Destroy a database group" ,
230
456
args : {
231
457
name : "name" ,
458
+ generators : groupGenerator ,
232
459
} ,
233
460
} ,
234
461
{
@@ -259,13 +486,15 @@ const completionSpec: Fig.Spec = {
259
486
description : "Unarchive a database group" ,
260
487
args : {
261
488
name : "name" ,
489
+ generators : groupGenerator ,
262
490
} ,
263
491
} ,
264
492
{
265
493
name : "update" ,
266
494
description : "Updates the group" ,
267
495
args : {
268
496
name : "name" ,
497
+ generators : groupGenerator ,
269
498
} ,
270
499
} ,
271
500
] ,
@@ -391,6 +620,7 @@ const completionSpec: Fig.Spec = {
391
620
"Switch to an organization as the context for your commands" ,
392
621
args : {
393
622
name : "organization" ,
623
+ generators : organizationGenerator ,
394
624
} ,
395
625
} ,
396
626
] ,
0 commit comments