@exedev/sdk 0.1.0 → 0.3.0
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.
- package/README.md +165 -59
- package/dist/client.d.ts +70 -43
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +319 -101
- package/dist/client.js.map +1 -1
- package/dist/commands.gen.d.ts +358 -293
- package/dist/commands.gen.d.ts.map +1 -1
- package/dist/commands.gen.js +905 -511
- package/dist/commands.gen.js.map +1 -1
- package/dist/index.d.ts +7 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +327 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
package/dist/commands.gen.js
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|
// Code generated by "go run ./cmd/gensdkjs" in the exe.dev repository. DO NOT EDIT.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import { Transport, ExeAPIError, ExeProtocolError, SSHStreamError, abortable, delay, isErrorDocument } from "./client.js";
|
|
3
|
+
export class ExedevClient {
|
|
4
|
+
#transport;
|
|
5
|
+
constructor(options) { this.#transport = new Transport(options); }
|
|
6
|
+
/** Reference an existing VM without a request. Use refresh() to fetch its metadata. */
|
|
7
|
+
vm(name) {
|
|
8
|
+
return new VM(this.#transport, { name: vmName(name), tags: [] });
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Delete VMs in one request; the server deletes several at a time. Unlike
|
|
12
|
+
* vm.rm(), VMs that were missing or could not be deleted do not throw: they
|
|
13
|
+
* are listed in failed, with reasons in errors. Requires rm permission.
|
|
14
|
+
*/
|
|
15
|
+
async rm(vms, options) {
|
|
16
|
+
// A string is iterable: rm("abc") must not delete a, b, and c.
|
|
17
|
+
if (!Array.isArray(vms))
|
|
18
|
+
throw new TypeError("exedev: rm takes an array of VMs or VM names");
|
|
19
|
+
const names = [...new Set(vms.map(vmName))];
|
|
20
|
+
if (names.length === 0)
|
|
21
|
+
return { deleted: [], failed: [], not_found: [], errors: {} };
|
|
22
|
+
return rmResult(await this.#transport.documents("rm", [names], options, {}));
|
|
23
|
+
}
|
|
8
24
|
/**
|
|
9
25
|
* Browse documentation
|
|
10
26
|
*
|
|
@@ -12,8 +28,9 @@ export class Commands {
|
|
|
12
28
|
*
|
|
13
29
|
* Tag-scoped API keys may run this command.
|
|
14
30
|
*/
|
|
15
|
-
doc(slugOrQueries, options) {
|
|
16
|
-
|
|
31
|
+
async doc(slugOrQueries, options) {
|
|
32
|
+
const result = await this.#transport.call("doc", [slugOrQueries], options, {}, false);
|
|
33
|
+
return result;
|
|
17
34
|
}
|
|
18
35
|
/**
|
|
19
36
|
* List your VMs
|
|
@@ -22,11 +39,12 @@ export class Commands {
|
|
|
22
39
|
*
|
|
23
40
|
* Tag-scoped API keys may run this command.
|
|
24
41
|
*/
|
|
25
|
-
ls(nameOrPattern, options) {
|
|
26
|
-
|
|
42
|
+
async ls(nameOrPattern, options) {
|
|
43
|
+
const result = await this.#transport.call("ls", [nameOrPattern], options, {
|
|
27
44
|
group: "string",
|
|
28
45
|
l: "bool",
|
|
29
|
-
});
|
|
46
|
+
}, true);
|
|
47
|
+
return listVMs(this.#transport, result);
|
|
30
48
|
}
|
|
31
49
|
/**
|
|
32
50
|
* Create a new VM
|
|
@@ -45,8 +63,10 @@ export class Commands {
|
|
|
45
63
|
*
|
|
46
64
|
* Tag-scoped API keys may run this command.
|
|
47
65
|
*/
|
|
48
|
-
new(options) {
|
|
49
|
-
|
|
66
|
+
async new(options) {
|
|
67
|
+
const ready = readiness(options ?? {});
|
|
68
|
+
const { waitUntil, timeoutMs, ...flags } = options ?? {};
|
|
69
|
+
const result = await this.#transport.call("new", [], flags, {
|
|
50
70
|
comment: "string",
|
|
51
71
|
cpu: "number",
|
|
52
72
|
disk: "string",
|
|
@@ -64,297 +84,22 @@ export class Commands {
|
|
|
64
84
|
"setup-script": "string",
|
|
65
85
|
standalone: "bool",
|
|
66
86
|
tag: "repeated",
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
* Usage: `rm <vmname>...`
|
|
73
|
-
*
|
|
74
|
-
* Tag-scoped API keys may run this command.
|
|
75
|
-
*/
|
|
76
|
-
rm(vmnames, options) {
|
|
77
|
-
return this.run("rm", [vmnames], options, {});
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Restart a VM
|
|
81
|
-
*
|
|
82
|
-
* Usage: `restart <vmname>`
|
|
83
|
-
*
|
|
84
|
-
* Tag-scoped API keys may run this command.
|
|
85
|
-
*/
|
|
86
|
-
restart(vmname, options) {
|
|
87
|
-
return this.run("restart", [vmname], options, {});
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* Pause a VM (snapshot RAM to disk, free its CPU and memory)
|
|
91
|
-
*
|
|
92
|
-
* Usage: `pause <vmname>`
|
|
93
|
-
*
|
|
94
|
-
* CLI examples:
|
|
95
|
-
* ```
|
|
96
|
-
* pause my-vm # snapshot RAM to disk; resume later with 'resume my-vm'
|
|
97
|
-
* ```
|
|
98
|
-
*
|
|
99
|
-
* Tag-scoped API keys may run this command.
|
|
100
|
-
*/
|
|
101
|
-
pause(vmname, options) {
|
|
102
|
-
return this.run("pause", [vmname], options, {});
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Resume a paused VM (restore RAM from disk)
|
|
106
|
-
*
|
|
107
|
-
* Usage: `resume <vmname>`
|
|
108
|
-
*
|
|
109
|
-
* Tag-scoped API keys may run this command.
|
|
110
|
-
*/
|
|
111
|
-
resume(vmname, options) {
|
|
112
|
-
return this.run("resume", [vmname], options, {});
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* rename a vm
|
|
116
|
-
*
|
|
117
|
-
* Usage: `rename <oldname> <newname>`
|
|
118
|
-
*
|
|
119
|
-
* Tag-scoped API keys may run this command.
|
|
120
|
-
*/
|
|
121
|
-
rename(oldname, newname, options) {
|
|
122
|
-
return this.run("rename", [oldname, newname], options, {});
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Add or remove tags on a VM
|
|
126
|
-
*
|
|
127
|
-
* Usage: `tag [-d] <vm> <tag-name> [tag-name...]`
|
|
128
|
-
*
|
|
129
|
-
* CLI examples:
|
|
130
|
-
* ```
|
|
131
|
-
* tag my-vm prod web # add tags
|
|
132
|
-
* tag -d my-vm prod web # remove tags
|
|
133
|
-
* ```
|
|
134
|
-
*
|
|
135
|
-
* Tag-scoped API keys may run this command.
|
|
136
|
-
*/
|
|
137
|
-
tag(vm, tagNames, options) {
|
|
138
|
-
return this.run("tag", [vm, tagNames], options, {
|
|
139
|
-
d: "bool",
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Copy an existing VM
|
|
144
|
-
*
|
|
145
|
-
* Usage: `cp <source-vm> [new-name] [--pool=<name>] [--memory=<size>] [--cpu=<count>] [--disk=<size>]`
|
|
146
|
-
*
|
|
147
|
-
* CLI examples:
|
|
148
|
-
* ```
|
|
149
|
-
* cp my-vm # copy with auto-generated name
|
|
150
|
-
* cp my-vm my-vm-copy # copy with specific name
|
|
151
|
-
* cp my-vm --cpu=4 --memory=16GB # copy with different resources
|
|
152
|
-
* cp my-vm my-pool-copy --pool=build # copy into a team pool
|
|
153
|
-
* cp my-vm --copy-tags=false # copy without tags
|
|
154
|
-
* ```
|
|
155
|
-
*
|
|
156
|
-
* Tag-scoped API keys may run this command.
|
|
157
|
-
*/
|
|
158
|
-
cp(sourceVm, newName, options) {
|
|
159
|
-
return this.run("cp", [sourceVm, newName], options, {
|
|
160
|
-
"copy-tags": "bool",
|
|
161
|
-
cpu: "number",
|
|
162
|
-
disk: "string",
|
|
163
|
-
memory: "string",
|
|
164
|
-
pool: "string",
|
|
165
|
-
sandbox: "bool",
|
|
166
|
-
standalone: "bool",
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* Resize a VM's resources (memory, CPU, disk)
|
|
171
|
-
*
|
|
172
|
-
* Usage: `resize <vmname> [--memory=<size>] [--cpu=<count>] [--disk=<size>]`
|
|
173
|
-
*
|
|
174
|
-
* Tag-scoped API keys may run this command.
|
|
175
|
-
*/
|
|
176
|
-
resize(vmname, options) {
|
|
177
|
-
return this.run("resize", [vmname], options, {
|
|
178
|
-
cpu: "number",
|
|
179
|
-
disk: "string",
|
|
180
|
-
memory: "string",
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Set or clear a short comment on a VM
|
|
185
|
-
*
|
|
186
|
-
* Usage: `comment <hostname> <text>`
|
|
187
|
-
*
|
|
188
|
-
* CLI examples:
|
|
189
|
-
* ```
|
|
190
|
-
* comment my-vm staging copy
|
|
191
|
-
* comment my-vm "" # clear the comment
|
|
192
|
-
* ```
|
|
193
|
-
*
|
|
194
|
-
* Tag-scoped API keys may run this command.
|
|
195
|
-
*/
|
|
196
|
-
comment(hostname, text, options) {
|
|
197
|
-
return this.run("comment", [hostname, text], options, {});
|
|
198
|
-
}
|
|
199
|
-
/**
|
|
200
|
-
* Link a custom domain to a VM
|
|
201
|
-
*
|
|
202
|
-
* Usage: `domain add [--wildcard] <vm> <domain>`
|
|
203
|
-
*/
|
|
204
|
-
domainAdd(vm, domain, options) {
|
|
205
|
-
return this.run("domain add", [vm, domain], options, {
|
|
206
|
-
wildcard: "bool",
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* Remove a custom domain from a VM
|
|
211
|
-
*
|
|
212
|
-
* Usage: `domain rm <vm> <domain>`
|
|
213
|
-
*/
|
|
214
|
-
domainRm(vm, domain, options) {
|
|
215
|
-
return this.run("domain rm", [vm, domain], options, {});
|
|
87
|
+
}, true);
|
|
88
|
+
const vm = new VM(this.#transport, vmInfo(result, "new"));
|
|
89
|
+
if (ready)
|
|
90
|
+
await vm.waitUntilReady(ready);
|
|
91
|
+
return vm;
|
|
216
92
|
}
|
|
217
93
|
/**
|
|
218
94
|
* List custom domains for a VM (or -a for all your VMs)
|
|
219
95
|
*
|
|
220
96
|
* Usage: `domain ls <vm> | domain ls -a`
|
|
221
97
|
*/
|
|
222
|
-
domainLs(args, options) {
|
|
223
|
-
|
|
98
|
+
async domainLs(args, options) {
|
|
99
|
+
const result = await this.#transport.call("domain ls", [args], options, {
|
|
224
100
|
a: "bool",
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Show current shares for a VM
|
|
229
|
-
*
|
|
230
|
-
* Usage: `share show <vm>`
|
|
231
|
-
*
|
|
232
|
-
* Tag-scoped API keys may run this command.
|
|
233
|
-
*/
|
|
234
|
-
shareShow(vm, options) {
|
|
235
|
-
return this.run("share show", [vm], options, {
|
|
236
|
-
qr: "bool",
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
/**
|
|
240
|
-
* Set the HTTP proxy port for a VM
|
|
241
|
-
*
|
|
242
|
-
* Usage: `share port <vm> [port]`
|
|
243
|
-
*
|
|
244
|
-
* CLI examples:
|
|
245
|
-
* ```
|
|
246
|
-
* share port mybox 8080
|
|
247
|
-
* ```
|
|
248
|
-
*
|
|
249
|
-
* Tag-scoped API keys may run this command.
|
|
250
|
-
*/
|
|
251
|
-
sharePort(vm, port, options) {
|
|
252
|
-
return this.run("share port", [vm, port], options, {});
|
|
253
|
-
}
|
|
254
|
-
/**
|
|
255
|
-
* Make the HTTP proxy publicly accessible
|
|
256
|
-
*
|
|
257
|
-
* Usage: `share set-public <vm>`
|
|
258
|
-
*
|
|
259
|
-
* Tag-scoped API keys may run this command.
|
|
260
|
-
*/
|
|
261
|
-
shareSetPublic(vm, options) {
|
|
262
|
-
return this.run("share set-public", [vm], options, {});
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Restrict the HTTP proxy to authenticated users
|
|
266
|
-
*
|
|
267
|
-
* Usage: `share set-private <vm>`
|
|
268
|
-
*
|
|
269
|
-
* Tag-scoped API keys may run this command.
|
|
270
|
-
*/
|
|
271
|
-
shareSetPrivate(vm, options) {
|
|
272
|
-
return this.run("share set-private", [vm], options, {});
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Share VM with a user via email, or grant shell access with --root
|
|
276
|
-
*
|
|
277
|
-
* Usage: `share add <vm> <email|team> [--root] [--message='...']`
|
|
278
|
-
*
|
|
279
|
-
* CLI examples:
|
|
280
|
-
* ```
|
|
281
|
-
* share add mybox user@example.com
|
|
282
|
-
* share add mybox user@example.com --message='Check this out'
|
|
283
|
-
* share add mybox team
|
|
284
|
-
* share add mybox teammate@example.com --root
|
|
285
|
-
* share add mybox team --root
|
|
286
|
-
* ```
|
|
287
|
-
*
|
|
288
|
-
* Tag-scoped API keys may run this command.
|
|
289
|
-
*/
|
|
290
|
-
shareAdd(vm, emailOrTeam, options) {
|
|
291
|
-
return this.run("share add", [vm, emailOrTeam], options, {
|
|
292
|
-
message: "string",
|
|
293
|
-
qr: "bool",
|
|
294
|
-
root: "bool",
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* Revoke a user's access to a VM, or downgrade shell access to web with --root
|
|
299
|
-
*
|
|
300
|
-
* Usage: `share remove <vm> <email|team> [--root]`
|
|
301
|
-
*
|
|
302
|
-
* CLI examples:
|
|
303
|
-
* ```
|
|
304
|
-
* share remove mybox user@example.com
|
|
305
|
-
* share remove mybox team
|
|
306
|
-
* share remove mybox teammate@example.com --root
|
|
307
|
-
* share remove mybox team --root
|
|
308
|
-
* ```
|
|
309
|
-
*
|
|
310
|
-
* Tag-scoped API keys may run this command.
|
|
311
|
-
*/
|
|
312
|
-
shareRemove(vm, emailOrTeam, options) {
|
|
313
|
-
return this.run("share remove", [vm, emailOrTeam], options, {
|
|
314
|
-
root: "bool",
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
/**
|
|
318
|
-
* Create a shareable link for a VM
|
|
319
|
-
*
|
|
320
|
-
* Usage: `share add-link <vm>`
|
|
321
|
-
*
|
|
322
|
-
* Tag-scoped API keys may run this command.
|
|
323
|
-
*/
|
|
324
|
-
shareAddLink(vm, options) {
|
|
325
|
-
return this.run("share add-link", [vm], options, {
|
|
326
|
-
qr: "bool",
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* Revoke a shareable link
|
|
331
|
-
*
|
|
332
|
-
* Usage: `share remove-link <vm> <token>`
|
|
333
|
-
*
|
|
334
|
-
* Tag-scoped API keys may run this command.
|
|
335
|
-
*/
|
|
336
|
-
shareRemoveLink(vm, token, options) {
|
|
337
|
-
return this.run("share remove-link", [vm, token], options, {});
|
|
338
|
-
}
|
|
339
|
-
/**
|
|
340
|
-
* Enable or disable inbound email for a VM
|
|
341
|
-
*
|
|
342
|
-
* Usage: `share receive-email <vm> [on|off] [--reply-policy=all|known|owner|none]`
|
|
343
|
-
*
|
|
344
|
-
* CLI examples:
|
|
345
|
-
* ```
|
|
346
|
-
* share receive-email mybox on
|
|
347
|
-
* share receive-email mybox off
|
|
348
|
-
* share receive-email mybox --reply-policy=known
|
|
349
|
-
* share receive-email mybox
|
|
350
|
-
* ```
|
|
351
|
-
*
|
|
352
|
-
* Tag-scoped API keys may run this command.
|
|
353
|
-
*/
|
|
354
|
-
shareReceiveEmail(vm, onOrOff, options) {
|
|
355
|
-
return this.run("share receive-email", [vm, onOrOff], options, {
|
|
356
|
-
"reply-policy": "string",
|
|
357
|
-
});
|
|
101
|
+
}, false);
|
|
102
|
+
return result;
|
|
358
103
|
}
|
|
359
104
|
/**
|
|
360
105
|
* Show user information (email, keys, etc)
|
|
@@ -363,8 +108,9 @@ export class Commands {
|
|
|
363
108
|
*
|
|
364
109
|
* Tag-scoped API keys may run this command.
|
|
365
110
|
*/
|
|
366
|
-
whoami(options) {
|
|
367
|
-
|
|
111
|
+
async whoami(options) {
|
|
112
|
+
const result = await this.#transport.call("whoami", [], options, {}, true);
|
|
113
|
+
return result;
|
|
368
114
|
}
|
|
369
115
|
/**
|
|
370
116
|
* List all SSH keys associated with your account
|
|
@@ -373,8 +119,9 @@ export class Commands {
|
|
|
373
119
|
*
|
|
374
120
|
* Tag-scoped API keys may run this command.
|
|
375
121
|
*/
|
|
376
|
-
sshKeyList(options) {
|
|
377
|
-
|
|
122
|
+
async sshKeyList(options) {
|
|
123
|
+
const result = await this.#transport.call("ssh-key list", [], options, {}, false);
|
|
124
|
+
return result;
|
|
378
125
|
}
|
|
379
126
|
/**
|
|
380
127
|
* Add a new SSH key to your account
|
|
@@ -399,10 +146,11 @@ export class Commands {
|
|
|
399
146
|
*
|
|
400
147
|
* Tag-scoped API keys may run this command.
|
|
401
148
|
*/
|
|
402
|
-
sshKeyAdd(publicKey, options) {
|
|
403
|
-
|
|
149
|
+
async sshKeyAdd(publicKey, options) {
|
|
150
|
+
const result = await this.#transport.call("ssh-key add", [publicKey], options, {
|
|
404
151
|
tag: "string",
|
|
405
|
-
});
|
|
152
|
+
}, false);
|
|
153
|
+
return result;
|
|
406
154
|
}
|
|
407
155
|
/**
|
|
408
156
|
* Remove an SSH key from your account
|
|
@@ -411,8 +159,9 @@ export class Commands {
|
|
|
411
159
|
*
|
|
412
160
|
* Tag-scoped API keys may run this command.
|
|
413
161
|
*/
|
|
414
|
-
sshKeyRemove(nameOrFingerprintOrPublicKey, options) {
|
|
415
|
-
|
|
162
|
+
async sshKeyRemove(nameOrFingerprintOrPublicKey, options) {
|
|
163
|
+
const result = await this.#transport.call("ssh-key remove", [nameOrFingerprintOrPublicKey], options, {}, false);
|
|
164
|
+
return result;
|
|
416
165
|
}
|
|
417
166
|
/**
|
|
418
167
|
* Rename an SSH key
|
|
@@ -421,8 +170,9 @@ export class Commands {
|
|
|
421
170
|
*
|
|
422
171
|
* Tag-scoped API keys may run this command.
|
|
423
172
|
*/
|
|
424
|
-
sshKeyRename(oldName, newName, options) {
|
|
425
|
-
|
|
173
|
+
async sshKeyRename(oldName, newName, options) {
|
|
174
|
+
const result = await this.#transport.call("ssh-key rename", [oldName, newName], options, {}, false);
|
|
175
|
+
return result;
|
|
426
176
|
}
|
|
427
177
|
/**
|
|
428
178
|
* Generate an API key for the exe.dev HTTPS API or for a specific VM
|
|
@@ -440,21 +190,23 @@ export class Commands {
|
|
|
440
190
|
*
|
|
441
191
|
* Tag-scoped API keys may run this command.
|
|
442
192
|
*/
|
|
443
|
-
sshKeyGenerateApiKey(options) {
|
|
444
|
-
|
|
193
|
+
async sshKeyGenerateApiKey(options) {
|
|
194
|
+
const result = await this.#transport.call("ssh-key generate-api-key", [], options, {
|
|
445
195
|
cmds: "string",
|
|
446
196
|
exp: "string",
|
|
447
197
|
label: "string",
|
|
448
198
|
vm: "string",
|
|
449
|
-
});
|
|
199
|
+
}, false);
|
|
200
|
+
return result;
|
|
450
201
|
}
|
|
451
202
|
/**
|
|
452
203
|
* Set your preferred region for new VMs.
|
|
453
204
|
*
|
|
454
205
|
* Usage: `set-region <region-code>`
|
|
455
206
|
*/
|
|
456
|
-
setRegion(regionCode, options) {
|
|
457
|
-
|
|
207
|
+
async setRegion(regionCode, options) {
|
|
208
|
+
const result = await this.#transport.call("set-region", [regionCode], options, {}, false);
|
|
209
|
+
return result;
|
|
458
210
|
}
|
|
459
211
|
/**
|
|
460
212
|
* List your integrations
|
|
@@ -463,37 +215,40 @@ export class Commands {
|
|
|
463
215
|
*
|
|
464
216
|
* Tag-scoped API keys may run this command.
|
|
465
217
|
*/
|
|
466
|
-
integrationsList(options) {
|
|
467
|
-
|
|
218
|
+
async integrationsList(options) {
|
|
219
|
+
const result = await this.#transport.call("integrations list", [], options, {
|
|
468
220
|
usage: "bool",
|
|
469
|
-
});
|
|
221
|
+
}, false);
|
|
222
|
+
return result;
|
|
470
223
|
}
|
|
471
224
|
/**
|
|
472
225
|
* Set up GitHub integration
|
|
473
226
|
*
|
|
474
227
|
* Usage: `integrations setup github [--list|--verify|-d]`
|
|
475
228
|
*/
|
|
476
|
-
integrationsSetupGithub(options) {
|
|
477
|
-
|
|
229
|
+
async integrationsSetupGithub(options) {
|
|
230
|
+
const result = await this.#transport.call("integrations setup github", [], options, {
|
|
478
231
|
d: "bool",
|
|
479
232
|
delete: "bool",
|
|
480
233
|
list: "bool",
|
|
481
234
|
verify: "bool",
|
|
482
|
-
});
|
|
235
|
+
}, false);
|
|
236
|
+
return result;
|
|
483
237
|
}
|
|
484
238
|
/**
|
|
485
239
|
* Set up ChatGPT account access for LLM integrations
|
|
486
240
|
*
|
|
487
241
|
* Usage: `integrations setup chatgpt [--name=<account-name>|--list|--verify|-d]`
|
|
488
242
|
*/
|
|
489
|
-
integrationsSetupChatgpt(options) {
|
|
490
|
-
|
|
243
|
+
async integrationsSetupChatgpt(options) {
|
|
244
|
+
const result = await this.#transport.call("integrations setup chatgpt", [], options, {
|
|
491
245
|
d: "bool",
|
|
492
246
|
delete: "bool",
|
|
493
247
|
list: "bool",
|
|
494
248
|
name: "string",
|
|
495
249
|
verify: "bool",
|
|
496
|
-
});
|
|
250
|
+
}, false);
|
|
251
|
+
return result;
|
|
497
252
|
}
|
|
498
253
|
/**
|
|
499
254
|
* Add a new integration
|
|
@@ -502,8 +257,8 @@ export class Commands {
|
|
|
502
257
|
*
|
|
503
258
|
* Usage: `integrations add <type> [--default | --name=<name> [--team] [args...]]`
|
|
504
259
|
*/
|
|
505
|
-
integrationsAdd(type, options) {
|
|
506
|
-
|
|
260
|
+
async integrationsAdd(type, options) {
|
|
261
|
+
const result = await this.#transport.call("integrations add", [type], options, {
|
|
507
262
|
"act-as-user": "bool",
|
|
508
263
|
attach: "repeated",
|
|
509
264
|
bearer: "string",
|
|
@@ -521,27 +276,30 @@ export class Commands {
|
|
|
521
276
|
"strip-prefix": "string",
|
|
522
277
|
target: "string",
|
|
523
278
|
team: "bool",
|
|
524
|
-
});
|
|
279
|
+
}, false);
|
|
280
|
+
return result;
|
|
525
281
|
}
|
|
526
282
|
/**
|
|
527
283
|
* Remove an integration
|
|
528
284
|
*
|
|
529
285
|
* Usage: `integrations remove <name> [--team]`
|
|
530
286
|
*/
|
|
531
|
-
integrationsRemove(name, options) {
|
|
532
|
-
|
|
287
|
+
async integrationsRemove(name, options) {
|
|
288
|
+
const result = await this.#transport.call("integrations remove", [name], options, {
|
|
533
289
|
team: "bool",
|
|
534
|
-
});
|
|
290
|
+
}, false);
|
|
291
|
+
return result;
|
|
535
292
|
}
|
|
536
293
|
/**
|
|
537
294
|
* Test an integration's credential (connection check)
|
|
538
295
|
*
|
|
539
296
|
* Usage: `integrations test <name> [--team]`
|
|
540
297
|
*/
|
|
541
|
-
integrationsTest(name, options) {
|
|
542
|
-
|
|
298
|
+
async integrationsTest(name, options) {
|
|
299
|
+
const result = await this.#transport.call("integrations test", [name], options, {
|
|
543
300
|
team: "bool",
|
|
544
|
-
});
|
|
301
|
+
}, false);
|
|
302
|
+
return result;
|
|
545
303
|
}
|
|
546
304
|
/**
|
|
547
305
|
* Edit an integration
|
|
@@ -550,8 +308,8 @@ export class Commands {
|
|
|
550
308
|
*
|
|
551
309
|
* Usage: `integrations edit <name> [--team] [args...]`
|
|
552
310
|
*/
|
|
553
|
-
integrationsEdit(name, args, options) {
|
|
554
|
-
|
|
311
|
+
async integrationsEdit(name, args, options) {
|
|
312
|
+
const result = await this.#transport.call("integrations edit", [name, args], options, {
|
|
555
313
|
"act-as-user": "bool",
|
|
556
314
|
bearer: "string",
|
|
557
315
|
"clear-header": "bool",
|
|
@@ -566,7 +324,8 @@ export class Commands {
|
|
|
566
324
|
target: "string",
|
|
567
325
|
team: "bool",
|
|
568
326
|
"webhook-url": "string",
|
|
569
|
-
});
|
|
327
|
+
}, false);
|
|
328
|
+
return result;
|
|
570
329
|
}
|
|
571
330
|
/**
|
|
572
331
|
* Attach an integration to a VM, tag, or all VMs
|
|
@@ -594,32 +353,35 @@ export class Commands {
|
|
|
594
353
|
* int attach gmail vm:dev1 --for 2h
|
|
595
354
|
* ```
|
|
596
355
|
*/
|
|
597
|
-
integrationsAttach(name, spec, options) {
|
|
598
|
-
|
|
356
|
+
async integrationsAttach(name, spec, options) {
|
|
357
|
+
const result = await this.#transport.call("integrations attach", [name, spec], options, {
|
|
599
358
|
for: "string",
|
|
600
359
|
team: "bool",
|
|
601
360
|
until: "string",
|
|
602
|
-
});
|
|
361
|
+
}, false);
|
|
362
|
+
return result;
|
|
603
363
|
}
|
|
604
364
|
/**
|
|
605
365
|
* Detach an integration from a VM, tag, or all VMs
|
|
606
366
|
*
|
|
607
367
|
* Usage: `integrations detach <name> <spec> [--team]`
|
|
608
368
|
*/
|
|
609
|
-
integrationsDetach(name, spec, options) {
|
|
610
|
-
|
|
369
|
+
async integrationsDetach(name, spec, options) {
|
|
370
|
+
const result = await this.#transport.call("integrations detach", [name, spec], options, {
|
|
611
371
|
team: "bool",
|
|
612
|
-
});
|
|
372
|
+
}, false);
|
|
373
|
+
return result;
|
|
613
374
|
}
|
|
614
375
|
/**
|
|
615
376
|
* Rename an integration
|
|
616
377
|
*
|
|
617
378
|
* Usage: `integrations rename <name> <new-name> [--team]`
|
|
618
379
|
*/
|
|
619
|
-
integrationsRename(name, newName, options) {
|
|
620
|
-
|
|
380
|
+
async integrationsRename(name, newName, options) {
|
|
381
|
+
const result = await this.#transport.call("integrations rename", [name, newName], options, {
|
|
621
382
|
team: "bool",
|
|
622
|
-
});
|
|
383
|
+
}, false);
|
|
384
|
+
return result;
|
|
623
385
|
}
|
|
624
386
|
/**
|
|
625
387
|
* Browse the catalog of ready-made service integrations
|
|
@@ -632,74 +394,83 @@ export class Commands {
|
|
|
632
394
|
* int catalog stripe
|
|
633
395
|
* ```
|
|
634
396
|
*/
|
|
635
|
-
integrationsCatalog(serviceOrSearchTerm, options) {
|
|
636
|
-
|
|
397
|
+
async integrationsCatalog(serviceOrSearchTerm, options) {
|
|
398
|
+
const result = await this.#transport.call("integrations catalog", [serviceOrSearchTerm], options, {}, false);
|
|
399
|
+
return result;
|
|
637
400
|
}
|
|
638
401
|
/**
|
|
639
402
|
* View and manage your team
|
|
640
403
|
*/
|
|
641
|
-
team(options) {
|
|
642
|
-
|
|
404
|
+
async team(options) {
|
|
405
|
+
const result = await this.#transport.call("team", [], options, {}, false);
|
|
406
|
+
return result;
|
|
643
407
|
}
|
|
644
408
|
/**
|
|
645
409
|
* Disband your team
|
|
646
410
|
*
|
|
647
411
|
* Usage: `team disable`
|
|
648
412
|
*/
|
|
649
|
-
teamDisable(options) {
|
|
650
|
-
|
|
413
|
+
async teamDisable(options) {
|
|
414
|
+
const result = await this.#transport.call("team disable", [], options, {
|
|
651
415
|
yes: "bool",
|
|
652
|
-
});
|
|
416
|
+
}, false);
|
|
417
|
+
return result;
|
|
653
418
|
}
|
|
654
419
|
/**
|
|
655
420
|
* List team members
|
|
656
421
|
*
|
|
657
422
|
* Usage: `team members`
|
|
658
423
|
*/
|
|
659
|
-
teamMembers(options) {
|
|
660
|
-
|
|
424
|
+
async teamMembers(options) {
|
|
425
|
+
const result = await this.#transport.call("team members", [], options, {}, false);
|
|
426
|
+
return result;
|
|
661
427
|
}
|
|
662
428
|
/**
|
|
663
429
|
* Show team pool, disk, and bandwidth usage for the billing period
|
|
664
430
|
*
|
|
665
431
|
* Usage: `team usage`
|
|
666
432
|
*/
|
|
667
|
-
teamUsage(options) {
|
|
668
|
-
|
|
433
|
+
async teamUsage(options) {
|
|
434
|
+
const result = await this.#transport.call("team usage", [], options, {}, false);
|
|
435
|
+
return result;
|
|
669
436
|
}
|
|
670
437
|
/**
|
|
671
438
|
* Add a user to the team
|
|
672
439
|
*
|
|
673
440
|
* Usage: `team add <email> [<user|admin|billing_owner>]`
|
|
674
441
|
*/
|
|
675
|
-
teamAdd(email, userOrAdminOrBillingOwner, options) {
|
|
676
|
-
|
|
442
|
+
async teamAdd(email, userOrAdminOrBillingOwner, options) {
|
|
443
|
+
const result = await this.#transport.call("team add", [email, userOrAdminOrBillingOwner], options, {}, false);
|
|
444
|
+
return result;
|
|
677
445
|
}
|
|
678
446
|
/**
|
|
679
447
|
* Remove a user from the team
|
|
680
448
|
*
|
|
681
449
|
* Usage: `team remove <email> [--transfer-vms-to <email>]`
|
|
682
450
|
*/
|
|
683
|
-
teamRemove(email, options) {
|
|
684
|
-
|
|
451
|
+
async teamRemove(email, options) {
|
|
452
|
+
const result = await this.#transport.call("team remove", [email], options, {
|
|
685
453
|
"transfer-vms-to": "string",
|
|
686
|
-
});
|
|
454
|
+
}, false);
|
|
455
|
+
return result;
|
|
687
456
|
}
|
|
688
457
|
/**
|
|
689
458
|
* Change a team member's role
|
|
690
459
|
*
|
|
691
460
|
* Usage: `team role <email> <user|admin|billing_owner>`
|
|
692
461
|
*/
|
|
693
|
-
teamRole(email, userOrAdminOrBillingOwner, options) {
|
|
694
|
-
|
|
462
|
+
async teamRole(email, userOrAdminOrBillingOwner, options) {
|
|
463
|
+
const result = await this.#transport.call("team role", [email, userOrAdminOrBillingOwner], options, {}, false);
|
|
464
|
+
return result;
|
|
695
465
|
}
|
|
696
466
|
/**
|
|
697
467
|
* Rename your team
|
|
698
468
|
*
|
|
699
469
|
* Usage: `team rename <name>`
|
|
700
470
|
*/
|
|
701
|
-
teamRename(name, options) {
|
|
702
|
-
|
|
471
|
+
async teamRename(name, options) {
|
|
472
|
+
const result = await this.#transport.call("team rename", [name], options, {}, false);
|
|
473
|
+
return result;
|
|
703
474
|
}
|
|
704
475
|
/**
|
|
705
476
|
* Show your team's plan
|
|
@@ -712,18 +483,19 @@ export class Commands {
|
|
|
712
483
|
* team billing plan --all # plans your team can switch to
|
|
713
484
|
* ```
|
|
714
485
|
*/
|
|
715
|
-
teamBillingPlan(options) {
|
|
716
|
-
|
|
486
|
+
async teamBillingPlan(options) {
|
|
487
|
+
const result = await this.#transport.call("team billing plan", [], options, {
|
|
717
488
|
all: "bool",
|
|
718
|
-
});
|
|
489
|
+
}, false);
|
|
490
|
+
return result;
|
|
719
491
|
}
|
|
720
492
|
/**
|
|
721
493
|
* Update team billing information
|
|
722
494
|
*
|
|
723
495
|
* Usage: `team billing update [--email=<email>] [--name=<name>] [--business-name=<name>] [--phone=<phone>] [--address-line1=<line>] [--address-line2=<line>] [--address-city=<city>] [--address-state=<state>] [--address-postal-code=<code>] [--address-country=<country>] [--tax-id-type=<type>] [--tax-id-value=<value>]`
|
|
724
496
|
*/
|
|
725
|
-
teamBillingUpdate(options) {
|
|
726
|
-
|
|
497
|
+
async teamBillingUpdate(options) {
|
|
498
|
+
const result = await this.#transport.call("team billing update", [], options, {
|
|
727
499
|
"address-city": "string",
|
|
728
500
|
"address-country": "string",
|
|
729
501
|
"address-line1": "string",
|
|
@@ -736,127 +508,142 @@ export class Commands {
|
|
|
736
508
|
phone: "string",
|
|
737
509
|
"tax-id-type": "string",
|
|
738
510
|
"tax-id-value": "string",
|
|
739
|
-
});
|
|
511
|
+
}, false);
|
|
512
|
+
return result;
|
|
740
513
|
}
|
|
741
514
|
/**
|
|
742
515
|
* Transfer a VM to another team member
|
|
743
516
|
*
|
|
744
517
|
* Usage: `team transfer <vm_name> <target_email>`
|
|
745
518
|
*/
|
|
746
|
-
teamTransfer(vmName, targetEmail, options) {
|
|
747
|
-
|
|
519
|
+
async teamTransfer(vmName, targetEmail, options) {
|
|
520
|
+
const result = await this.#transport.call("team transfer", [vmName, targetEmail], options, {}, false);
|
|
521
|
+
return result;
|
|
748
522
|
}
|
|
749
523
|
/**
|
|
750
524
|
* View and manage team auth settings
|
|
751
525
|
*
|
|
752
526
|
* Usage: `team auth`
|
|
753
527
|
*/
|
|
754
|
-
teamAuth(options) {
|
|
755
|
-
|
|
528
|
+
async teamAuth(options) {
|
|
529
|
+
const result = await this.#transport.call("team auth", [], options, {}, false);
|
|
530
|
+
return result;
|
|
756
531
|
}
|
|
757
532
|
/**
|
|
758
533
|
* Require OIDC for web login (web|off)
|
|
759
534
|
*
|
|
760
535
|
* Usage: `team auth require-oidc <web|off>`
|
|
761
536
|
*/
|
|
762
|
-
teamAuthRequireOidc(webOrOff, options) {
|
|
763
|
-
|
|
537
|
+
async teamAuthRequireOidc(webOrOff, options) {
|
|
538
|
+
const result = await this.#transport.call("team auth require-oidc", [webOrOff], options, {}, false);
|
|
539
|
+
return result;
|
|
764
540
|
}
|
|
765
541
|
/**
|
|
766
542
|
* Set the team auth provider (default, google, oidc)
|
|
767
543
|
*
|
|
768
544
|
* Usage: `team auth set <default|google|oidc> [--issuer-url=<url> --client-id=<id> --client-secret=<secret>]`
|
|
769
545
|
*/
|
|
770
|
-
teamAuthSet(defaultOrGoogleOrOidc, options) {
|
|
771
|
-
|
|
546
|
+
async teamAuthSet(defaultOrGoogleOrOidc, options) {
|
|
547
|
+
const result = await this.#transport.call("team auth set", [defaultOrGoogleOrOidc], options, {
|
|
772
548
|
"client-id": "string",
|
|
773
549
|
"client-secret": "string",
|
|
774
550
|
"display-name": "string",
|
|
775
551
|
"issuer-url": "string",
|
|
776
|
-
});
|
|
552
|
+
}, false);
|
|
553
|
+
return result;
|
|
777
554
|
}
|
|
778
555
|
/**
|
|
779
556
|
* View and manage team settings
|
|
780
557
|
*
|
|
781
558
|
* Usage: `team settings`
|
|
782
559
|
*/
|
|
783
|
-
teamSettings(options) {
|
|
784
|
-
|
|
560
|
+
async teamSettings(options) {
|
|
561
|
+
const result = await this.#transport.call("team settings", [], options, {}, false);
|
|
562
|
+
return result;
|
|
785
563
|
}
|
|
786
564
|
/**
|
|
787
565
|
* View and manage automatic VM placement
|
|
788
566
|
*
|
|
789
567
|
* Usage: `team settings vm-placement`
|
|
790
568
|
*/
|
|
791
|
-
teamSettingsVmPlacement(options) {
|
|
792
|
-
|
|
569
|
+
async teamSettingsVmPlacement(options) {
|
|
570
|
+
const result = await this.#transport.call("team settings vm-placement", [], options, {}, false);
|
|
571
|
+
return result;
|
|
793
572
|
}
|
|
794
573
|
/**
|
|
795
574
|
* Use ordinary VM placement
|
|
796
575
|
*
|
|
797
576
|
* Usage: `team settings vm-placement default`
|
|
798
577
|
*/
|
|
799
|
-
teamSettingsVmPlacementDefault(options) {
|
|
800
|
-
|
|
578
|
+
async teamSettingsVmPlacementDefault(options) {
|
|
579
|
+
const result = await this.#transport.call("team settings vm-placement default", [], options, {}, false);
|
|
580
|
+
return result;
|
|
801
581
|
}
|
|
802
582
|
/**
|
|
803
583
|
* Send bare new commands to a shared team pool
|
|
804
584
|
*
|
|
805
585
|
* Usage: `team settings vm-placement pool <name>`
|
|
806
586
|
*/
|
|
807
|
-
teamSettingsVmPlacementPool(name, options) {
|
|
808
|
-
|
|
587
|
+
async teamSettingsVmPlacementPool(name, options) {
|
|
588
|
+
const result = await this.#transport.call("team settings vm-placement pool", [name], options, {}, false);
|
|
589
|
+
return result;
|
|
809
590
|
}
|
|
810
591
|
/**
|
|
811
592
|
* Create or reuse one team pool per member for bare new commands
|
|
812
593
|
*
|
|
813
594
|
* Usage: `team settings vm-placement member-pool --cpus=N [--max-vms=N]`
|
|
814
595
|
*/
|
|
815
|
-
teamSettingsVmPlacementMemberPool(options) {
|
|
816
|
-
|
|
596
|
+
async teamSettingsVmPlacementMemberPool(options) {
|
|
597
|
+
const result = await this.#transport.call("team settings vm-placement member-pool", [], options, {
|
|
817
598
|
cpus: "number",
|
|
818
599
|
"max-vms": "number",
|
|
819
|
-
});
|
|
600
|
+
}, false);
|
|
601
|
+
return result;
|
|
820
602
|
}
|
|
821
603
|
/**
|
|
822
604
|
* Keep bare new commands outside pools while migrating (legacy)
|
|
823
605
|
*
|
|
824
606
|
* Usage: `team settings vm-placement poolless`
|
|
825
607
|
*/
|
|
826
|
-
teamSettingsVmPlacementPoolless(options) {
|
|
827
|
-
|
|
608
|
+
async teamSettingsVmPlacementPoolless(options) {
|
|
609
|
+
const result = await this.#transport.call("team settings vm-placement poolless", [], options, {}, false);
|
|
610
|
+
return result;
|
|
828
611
|
}
|
|
829
612
|
/**
|
|
830
613
|
* Set who can create standalone VMs
|
|
831
614
|
*
|
|
832
615
|
* Usage: `team settings standalone <off|admins-only|all-users>`
|
|
833
616
|
*/
|
|
834
|
-
teamSettingsStandalone(offOrAdminsOnlyOrAllUsers, options) {
|
|
835
|
-
|
|
617
|
+
async teamSettingsStandalone(offOrAdminsOnlyOrAllUsers, options) {
|
|
618
|
+
const result = await this.#transport.call("team settings standalone", [offOrAdminsOnlyOrAllUsers], options, {}, false);
|
|
619
|
+
return result;
|
|
836
620
|
}
|
|
837
621
|
/**
|
|
838
622
|
* Allow or block the exe.dev LLM gateway (your own API keys are unaffected)
|
|
839
623
|
*
|
|
840
624
|
* Usage: `team settings llm-gateway <on|off>`
|
|
841
625
|
*/
|
|
842
|
-
teamSettingsLlmGateway(onOrOff, options) {
|
|
843
|
-
|
|
626
|
+
async teamSettingsLlmGateway(onOrOff, options) {
|
|
627
|
+
const result = await this.#transport.call("team settings llm-gateway", [onOrOff], options, {}, false);
|
|
628
|
+
return result;
|
|
844
629
|
}
|
|
845
630
|
/**
|
|
846
631
|
* Allow team VMs to share CPU cores with each other
|
|
847
632
|
*
|
|
848
633
|
* Usage: `team settings core-sharing <on|off>`
|
|
849
634
|
*/
|
|
850
|
-
teamSettingsCoreSharing(onOrOff, options) {
|
|
851
|
-
|
|
635
|
+
async teamSettingsCoreSharing(onOrOff, options) {
|
|
636
|
+
const result = await this.#transport.call("team settings core-sharing", [onOrOff], options, {}, false);
|
|
637
|
+
return result;
|
|
852
638
|
}
|
|
853
639
|
/**
|
|
854
640
|
* Set who can share team VMs
|
|
855
641
|
*
|
|
856
642
|
* Usage: `team settings vm-sharing <admins-only|all-members>`
|
|
857
643
|
*/
|
|
858
|
-
teamSettingsVmSharing(adminsOnlyOrAllMembers, options) {
|
|
859
|
-
|
|
644
|
+
async teamSettingsVmSharing(adminsOnlyOrAllMembers, options) {
|
|
645
|
+
const result = await this.#transport.call("team settings vm-sharing", [adminsOnlyOrAllMembers], options, {}, false);
|
|
646
|
+
return result;
|
|
860
647
|
}
|
|
861
648
|
/**
|
|
862
649
|
* Set how long members stay signed in on the web and mobile apps
|
|
@@ -869,16 +656,18 @@ export class Commands {
|
|
|
869
656
|
* team settings session-length default
|
|
870
657
|
* ```
|
|
871
658
|
*/
|
|
872
|
-
teamSettingsSessionLength(length, options) {
|
|
873
|
-
|
|
659
|
+
async teamSettingsSessionLength(length, options) {
|
|
660
|
+
const result = await this.#transport.call("team settings session-length", [length], options, {}, false);
|
|
661
|
+
return result;
|
|
874
662
|
}
|
|
875
663
|
/**
|
|
876
664
|
* Allow users from your email domain to join this team on signup
|
|
877
665
|
*
|
|
878
666
|
* Usage: `team settings auto-join <on|off>`
|
|
879
667
|
*/
|
|
880
|
-
teamSettingsAutoJoin(onOrOff, options) {
|
|
881
|
-
|
|
668
|
+
async teamSettingsAutoJoin(onOrOff, options) {
|
|
669
|
+
const result = await this.#transport.call("team settings auto-join", [onOrOff], options, {}, false);
|
|
670
|
+
return result;
|
|
882
671
|
}
|
|
883
672
|
/**
|
|
884
673
|
* List all VMs across your team
|
|
@@ -887,42 +676,46 @@ export class Commands {
|
|
|
887
676
|
*
|
|
888
677
|
* Tag-scoped API keys may run this command.
|
|
889
678
|
*/
|
|
890
|
-
teamVmLs(nameOrPattern, options) {
|
|
891
|
-
|
|
679
|
+
async teamVmLs(nameOrPattern, options) {
|
|
680
|
+
const result = await this.#transport.call("team vm ls", [nameOrPattern], options, {
|
|
892
681
|
group: "string",
|
|
893
682
|
l: "bool",
|
|
894
|
-
});
|
|
683
|
+
}, false);
|
|
684
|
+
return result;
|
|
895
685
|
}
|
|
896
686
|
/**
|
|
897
687
|
* Create a pool: reserved capacity for your team's VMs
|
|
898
688
|
*
|
|
899
689
|
* Usage: `pool new <name> --cpus=N [--region=<region>] [--max-vms=M]`
|
|
900
690
|
*/
|
|
901
|
-
poolNew(name, options) {
|
|
902
|
-
|
|
691
|
+
async poolNew(name, options) {
|
|
692
|
+
const result = await this.#transport.call("pool new", [name], options, {
|
|
903
693
|
cpus: "number",
|
|
904
694
|
"max-vms": "number",
|
|
905
695
|
region: "string",
|
|
906
|
-
});
|
|
696
|
+
}, false);
|
|
697
|
+
return result;
|
|
907
698
|
}
|
|
908
699
|
/**
|
|
909
700
|
* Show your team's dedicated hosts, where its new pools are placed
|
|
910
701
|
*
|
|
911
702
|
* Usage: `pool hosts`
|
|
912
703
|
*/
|
|
913
|
-
poolHosts(options) {
|
|
914
|
-
|
|
704
|
+
async poolHosts(options) {
|
|
705
|
+
const result = await this.#transport.call("pool hosts", [], options, {}, false);
|
|
706
|
+
return result;
|
|
915
707
|
}
|
|
916
708
|
/**
|
|
917
709
|
* List your team's pools, or show live or historical usage with --usage
|
|
918
710
|
*
|
|
919
711
|
* Usage: `pool list [pool-name] [--usage [--range=live|24h|7d|30d]]`
|
|
920
712
|
*/
|
|
921
|
-
poolList(poolName, options) {
|
|
922
|
-
|
|
713
|
+
async poolList(poolName, options) {
|
|
714
|
+
const result = await this.#transport.call("pool list", [poolName], options, {
|
|
923
715
|
range: "string",
|
|
924
716
|
usage: "bool",
|
|
925
|
-
});
|
|
717
|
+
}, false);
|
|
718
|
+
return result;
|
|
926
719
|
}
|
|
927
720
|
/**
|
|
928
721
|
* Adopt a VM into a pool; this can take several minutes
|
|
@@ -934,11 +727,12 @@ export class Commands {
|
|
|
934
727
|
* pool adopt --vm=builder --pool=compile
|
|
935
728
|
* ```
|
|
936
729
|
*/
|
|
937
|
-
poolAdopt(options) {
|
|
938
|
-
|
|
730
|
+
async poolAdopt(options) {
|
|
731
|
+
const result = await this.#transport.call("pool adopt", [], options, {
|
|
939
732
|
pool: "string",
|
|
940
733
|
vm: "string",
|
|
941
|
-
});
|
|
734
|
+
}, false);
|
|
735
|
+
return result;
|
|
942
736
|
}
|
|
943
737
|
/**
|
|
944
738
|
* Detach a VM from its pool into its own standalone capacity (--poolless leaves it outside any pool)
|
|
@@ -951,39 +745,43 @@ export class Commands {
|
|
|
951
745
|
* pool detach --vm=builder --poolless
|
|
952
746
|
* ```
|
|
953
747
|
*/
|
|
954
|
-
poolDetach(options) {
|
|
955
|
-
|
|
748
|
+
async poolDetach(options) {
|
|
749
|
+
const result = await this.#transport.call("pool detach", [], options, {
|
|
956
750
|
poolless: "bool",
|
|
957
751
|
vm: "string",
|
|
958
|
-
});
|
|
752
|
+
}, false);
|
|
753
|
+
return result;
|
|
959
754
|
}
|
|
960
755
|
/**
|
|
961
756
|
* Change a pool's CPU capacity or VM cap
|
|
962
757
|
*
|
|
963
758
|
* Usage: `pool resize <name> --cpus=N | pool resize <name> --max-vms=N [--force]`
|
|
964
759
|
*/
|
|
965
|
-
poolResize(args, options) {
|
|
966
|
-
|
|
760
|
+
async poolResize(args, options) {
|
|
761
|
+
const result = await this.#transport.call("pool resize", [args], options, {
|
|
967
762
|
cpus: "number",
|
|
968
763
|
force: "bool",
|
|
969
764
|
"max-vms": "string",
|
|
970
|
-
});
|
|
765
|
+
}, false);
|
|
766
|
+
return result;
|
|
971
767
|
}
|
|
972
768
|
/**
|
|
973
769
|
* Rename a pool without changing its capacity or VMs
|
|
974
770
|
*
|
|
975
771
|
* Usage: `pool rename <old-name> <new-name>`
|
|
976
772
|
*/
|
|
977
|
-
poolRename(oldName, newName, options) {
|
|
978
|
-
|
|
773
|
+
async poolRename(oldName, newName, options) {
|
|
774
|
+
const result = await this.#transport.call("pool rename", [oldName, newName], options, {}, false);
|
|
775
|
+
return result;
|
|
979
776
|
}
|
|
980
777
|
/**
|
|
981
778
|
* Delete a pool (refused while it has VMs; --force detaches them)
|
|
982
779
|
*
|
|
983
780
|
* Usage: `pool delete <name> [--force]`
|
|
984
781
|
*/
|
|
985
|
-
poolDelete(name, options) {
|
|
986
|
-
|
|
782
|
+
async poolDelete(name, options) {
|
|
783
|
+
const result = await this.#transport.call("pool delete", [name], options, {}, false);
|
|
784
|
+
return result;
|
|
987
785
|
}
|
|
988
786
|
/**
|
|
989
787
|
* Show your current plan and resource limits
|
|
@@ -996,10 +794,11 @@ export class Commands {
|
|
|
996
794
|
* billing plan --all # plans you can switch to
|
|
997
795
|
* ```
|
|
998
796
|
*/
|
|
999
|
-
billingPlan(options) {
|
|
1000
|
-
|
|
797
|
+
async billingPlan(options) {
|
|
798
|
+
const result = await this.#transport.call("billing plan", [], options, {
|
|
1001
799
|
all: "bool",
|
|
1002
|
-
});
|
|
800
|
+
}, false);
|
|
801
|
+
return result;
|
|
1003
802
|
}
|
|
1004
803
|
/**
|
|
1005
804
|
* Show VM resource usage against your plan quotas
|
|
@@ -1012,19 +811,21 @@ export class Commands {
|
|
|
1012
811
|
* billing credits usage # Shelley/LLM credit spend instead
|
|
1013
812
|
* ```
|
|
1014
813
|
*/
|
|
1015
|
-
billingUsage(options) {
|
|
1016
|
-
|
|
814
|
+
async billingUsage(options) {
|
|
815
|
+
const result = await this.#transport.call("billing usage", [], options, {
|
|
1017
816
|
group: "string",
|
|
1018
817
|
range: "string",
|
|
1019
|
-
});
|
|
818
|
+
}, false);
|
|
819
|
+
return result;
|
|
1020
820
|
}
|
|
1021
821
|
/**
|
|
1022
822
|
* Show Shelley credit balances
|
|
1023
823
|
*
|
|
1024
824
|
* Usage: `billing credits [usage|transactions|buy]`
|
|
1025
825
|
*/
|
|
1026
|
-
billingCredits(options) {
|
|
1027
|
-
|
|
826
|
+
async billingCredits(options) {
|
|
827
|
+
const result = await this.#transport.call("billing credits", [], options, {}, false);
|
|
828
|
+
return result;
|
|
1028
829
|
}
|
|
1029
830
|
/**
|
|
1030
831
|
* Show Shelley (LLM) credit spend by model, day, or VM
|
|
@@ -1038,22 +839,24 @@ export class Commands {
|
|
|
1038
839
|
* billing credits usage --month=2026-05 --group=box
|
|
1039
840
|
* ```
|
|
1040
841
|
*/
|
|
1041
|
-
billingCreditsUsage(options) {
|
|
1042
|
-
|
|
842
|
+
async billingCreditsUsage(options) {
|
|
843
|
+
const result = await this.#transport.call("billing credits usage", [], options, {
|
|
1043
844
|
detail: "bool",
|
|
1044
845
|
group: "string",
|
|
1045
846
|
month: "string",
|
|
1046
|
-
});
|
|
847
|
+
}, false);
|
|
848
|
+
return result;
|
|
1047
849
|
}
|
|
1048
850
|
/**
|
|
1049
851
|
* Show your credit purchases and gifts
|
|
1050
852
|
*
|
|
1051
853
|
* Usage: `billing credits transactions [--limit=N]`
|
|
1052
854
|
*/
|
|
1053
|
-
billingCreditsTransactions(options) {
|
|
1054
|
-
|
|
855
|
+
async billingCreditsTransactions(options) {
|
|
856
|
+
const result = await this.#transport.call("billing credits transactions", [], options, {
|
|
1055
857
|
limit: "string",
|
|
1056
|
-
});
|
|
858
|
+
}, false);
|
|
859
|
+
return result;
|
|
1057
860
|
}
|
|
1058
861
|
/**
|
|
1059
862
|
* Buy Shelley credits with your personal payment method
|
|
@@ -1066,19 +869,21 @@ export class Commands {
|
|
|
1066
869
|
* billing credits buy 100 --yes
|
|
1067
870
|
* ```
|
|
1068
871
|
*/
|
|
1069
|
-
billingCreditsBuy(dollars, options) {
|
|
1070
|
-
|
|
872
|
+
async billingCreditsBuy(dollars, options) {
|
|
873
|
+
const result = await this.#transport.call("billing credits buy", [dollars], options, {
|
|
1071
874
|
"idempotency-key": "string",
|
|
1072
875
|
yes: "bool",
|
|
1073
|
-
});
|
|
876
|
+
}, false);
|
|
877
|
+
return result;
|
|
1074
878
|
}
|
|
1075
879
|
/**
|
|
1076
880
|
* Show invite rewards you've earned
|
|
1077
881
|
*
|
|
1078
882
|
* Usage: `billing rewards`
|
|
1079
883
|
*/
|
|
1080
|
-
billingRewards(options) {
|
|
1081
|
-
|
|
884
|
+
async billingRewards(options) {
|
|
885
|
+
const result = await this.#transport.call("billing rewards", [], options, {}, false);
|
|
886
|
+
return result;
|
|
1082
887
|
}
|
|
1083
888
|
/**
|
|
1084
889
|
* Change your subscription capacity
|
|
@@ -1091,27 +896,30 @@ export class Commands {
|
|
|
1091
896
|
* billing capacity --cpu=4 --yes
|
|
1092
897
|
* ```
|
|
1093
898
|
*/
|
|
1094
|
-
billingCapacity(options) {
|
|
1095
|
-
|
|
899
|
+
async billingCapacity(options) {
|
|
900
|
+
const result = await this.#transport.call("billing capacity", [], options, {
|
|
1096
901
|
cpu: "number",
|
|
1097
902
|
yes: "bool",
|
|
1098
|
-
});
|
|
903
|
+
}, false);
|
|
904
|
+
return result;
|
|
1099
905
|
}
|
|
1100
906
|
/**
|
|
1101
907
|
* Show your payment methods
|
|
1102
908
|
*
|
|
1103
909
|
* Usage: `billing payment [list]`
|
|
1104
910
|
*/
|
|
1105
|
-
billingPayment(options) {
|
|
1106
|
-
|
|
911
|
+
async billingPayment(options) {
|
|
912
|
+
const result = await this.#transport.call("billing payment", [], options, {}, false);
|
|
913
|
+
return result;
|
|
1107
914
|
}
|
|
1108
915
|
/**
|
|
1109
916
|
* List all payment methods on file
|
|
1110
917
|
*
|
|
1111
918
|
* Usage: `billing payment list`
|
|
1112
919
|
*/
|
|
1113
|
-
billingPaymentList(options) {
|
|
1114
|
-
|
|
920
|
+
async billingPaymentList(options) {
|
|
921
|
+
const result = await this.#transport.call("billing payment list", [], options, {}, false);
|
|
922
|
+
return result;
|
|
1115
923
|
}
|
|
1116
924
|
/**
|
|
1117
925
|
* Remove a saved payment method
|
|
@@ -1123,8 +931,9 @@ export class Commands {
|
|
|
1123
931
|
* billing payment remove 4f1c2a9b8d3e
|
|
1124
932
|
* ```
|
|
1125
933
|
*/
|
|
1126
|
-
billingPaymentRemove(ref, options) {
|
|
1127
|
-
|
|
934
|
+
async billingPaymentRemove(ref, options) {
|
|
935
|
+
const result = await this.#transport.call("billing payment remove", [ref], options, {}, false);
|
|
936
|
+
return result;
|
|
1128
937
|
}
|
|
1129
938
|
/**
|
|
1130
939
|
* Make a saved payment method the default
|
|
@@ -1136,32 +945,35 @@ export class Commands {
|
|
|
1136
945
|
* billing payment default 4f1c2a9b8d3e
|
|
1137
946
|
* ```
|
|
1138
947
|
*/
|
|
1139
|
-
billingPaymentDefault(ref, options) {
|
|
1140
|
-
|
|
948
|
+
async billingPaymentDefault(ref, options) {
|
|
949
|
+
const result = await this.#transport.call("billing payment default", [ref], options, {}, false);
|
|
950
|
+
return result;
|
|
1141
951
|
}
|
|
1142
952
|
/**
|
|
1143
953
|
* Open the billing management page
|
|
1144
954
|
*
|
|
1145
955
|
* Usage: `billing manage`
|
|
1146
956
|
*/
|
|
1147
|
-
billingManage(options) {
|
|
1148
|
-
|
|
957
|
+
async billingManage(options) {
|
|
958
|
+
const result = await this.#transport.call("billing manage", [], options, {}, false);
|
|
959
|
+
return result;
|
|
1149
960
|
}
|
|
1150
961
|
/**
|
|
1151
962
|
* Open the personal plan activation page
|
|
1152
963
|
*
|
|
1153
964
|
* Usage: `billing activate`
|
|
1154
965
|
*/
|
|
1155
|
-
billingActivate(options) {
|
|
1156
|
-
|
|
966
|
+
async billingActivate(options) {
|
|
967
|
+
const result = await this.#transport.call("billing activate", [], options, {}, false);
|
|
968
|
+
return result;
|
|
1157
969
|
}
|
|
1158
970
|
/**
|
|
1159
971
|
* Update your billing contact information
|
|
1160
972
|
*
|
|
1161
973
|
* Usage: `billing update [--email=<email>] [--name=<name>] [--business-name=<name>] [--phone=<phone>] [--address-line1=<line>] [--address-line2=<line>] [--address-city=<city>] [--address-state=<state>] [--address-postal-code=<code>] [--address-country=<country>] [--tax-id-type=<type>] [--tax-id-value=<value>]`
|
|
1162
974
|
*/
|
|
1163
|
-
billingUpdate(options) {
|
|
1164
|
-
|
|
975
|
+
async billingUpdate(options) {
|
|
976
|
+
const result = await this.#transport.call("billing update", [], options, {
|
|
1165
977
|
"address-city": "string",
|
|
1166
978
|
"address-country": "string",
|
|
1167
979
|
"address-line1": "string",
|
|
@@ -1174,15 +986,17 @@ export class Commands {
|
|
|
1174
986
|
phone: "string",
|
|
1175
987
|
"tax-id-type": "string",
|
|
1176
988
|
"tax-id-value": "string",
|
|
1177
|
-
});
|
|
989
|
+
}, false);
|
|
990
|
+
return result;
|
|
1178
991
|
}
|
|
1179
992
|
/**
|
|
1180
993
|
* Show recent invoices
|
|
1181
994
|
*
|
|
1182
995
|
* Usage: `billing invoices`
|
|
1183
996
|
*/
|
|
1184
|
-
billingInvoices(options) {
|
|
1185
|
-
|
|
997
|
+
async billingInvoices(options) {
|
|
998
|
+
const result = await this.#transport.call("billing invoices", [], options, {}, false);
|
|
999
|
+
return result;
|
|
1186
1000
|
}
|
|
1187
1001
|
/**
|
|
1188
1002
|
* List invoices for your personal or team account
|
|
@@ -1194,10 +1008,11 @@ export class Commands {
|
|
|
1194
1008
|
* billing invoices list --account=team
|
|
1195
1009
|
* ```
|
|
1196
1010
|
*/
|
|
1197
|
-
billingInvoicesList(options) {
|
|
1198
|
-
|
|
1011
|
+
async billingInvoicesList(options) {
|
|
1012
|
+
const result = await this.#transport.call("billing invoices list", [], options, {
|
|
1199
1013
|
account: "string",
|
|
1200
|
-
});
|
|
1014
|
+
}, false);
|
|
1015
|
+
return result;
|
|
1201
1016
|
}
|
|
1202
1017
|
/**
|
|
1203
1018
|
* Show one invoice with its usage breakdown
|
|
@@ -1209,10 +1024,11 @@ export class Commands {
|
|
|
1209
1024
|
* billing invoices show in_1Abc --vms
|
|
1210
1025
|
* ```
|
|
1211
1026
|
*/
|
|
1212
|
-
billingInvoicesShow(id, options) {
|
|
1213
|
-
|
|
1027
|
+
async billingInvoicesShow(id, options) {
|
|
1028
|
+
const result = await this.#transport.call("billing invoices show", [id], options, {
|
|
1214
1029
|
vms: "bool",
|
|
1215
|
-
});
|
|
1030
|
+
}, false);
|
|
1031
|
+
return result;
|
|
1216
1032
|
}
|
|
1217
1033
|
/**
|
|
1218
1034
|
* Show credit purchase receipts and purchases (this billing account only)
|
|
@@ -1224,11 +1040,12 @@ export class Commands {
|
|
|
1224
1040
|
* billing receipts --from=2026-01-01 --to=2026-06-30
|
|
1225
1041
|
* ```
|
|
1226
1042
|
*/
|
|
1227
|
-
billingReceipts(options) {
|
|
1228
|
-
|
|
1043
|
+
async billingReceipts(options) {
|
|
1044
|
+
const result = await this.#transport.call("billing receipts", [], options, {
|
|
1229
1045
|
from: "string",
|
|
1230
1046
|
to: "string",
|
|
1231
|
-
});
|
|
1047
|
+
}, false);
|
|
1048
|
+
return result;
|
|
1232
1049
|
}
|
|
1233
1050
|
/**
|
|
1234
1051
|
* Open a consolidated credit purchase statement
|
|
@@ -1240,105 +1057,528 @@ export class Commands {
|
|
|
1240
1057
|
* billing statement --from=2026-01-01 --to=2026-06-30
|
|
1241
1058
|
* ```
|
|
1242
1059
|
*/
|
|
1243
|
-
billingStatement(options) {
|
|
1244
|
-
|
|
1060
|
+
async billingStatement(options) {
|
|
1061
|
+
const result = await this.#transport.call("billing statement", [], options, {
|
|
1245
1062
|
from: "string",
|
|
1246
1063
|
to: "string",
|
|
1247
|
-
});
|
|
1064
|
+
}, false);
|
|
1065
|
+
return result;
|
|
1248
1066
|
}
|
|
1249
1067
|
/**
|
|
1250
1068
|
* Connect a marketplace subscription to your team
|
|
1251
1069
|
*
|
|
1252
1070
|
* Usage: `billing provider link <aws|azure> --token=<link-token> [--size=<team-size>] [--team-name=<name>]`
|
|
1253
1071
|
*/
|
|
1254
|
-
billingProviderLink(awsOrAzure, options) {
|
|
1255
|
-
|
|
1072
|
+
async billingProviderLink(awsOrAzure, options) {
|
|
1073
|
+
const result = await this.#transport.call("billing provider link", [awsOrAzure], options, {
|
|
1256
1074
|
size: "string",
|
|
1257
1075
|
"team-name": "string",
|
|
1258
1076
|
token: "string",
|
|
1259
|
-
});
|
|
1077
|
+
}, false);
|
|
1078
|
+
return result;
|
|
1260
1079
|
}
|
|
1261
1080
|
/**
|
|
1262
1081
|
* Manage your invite link and rewards
|
|
1263
1082
|
*/
|
|
1264
|
-
invite(options) {
|
|
1265
|
-
|
|
1083
|
+
async invite(options) {
|
|
1084
|
+
const result = await this.#transport.call("invite", [], options, {}, false);
|
|
1085
|
+
return result;
|
|
1266
1086
|
}
|
|
1267
1087
|
/**
|
|
1268
1088
|
* Show your active invite link and reward
|
|
1269
1089
|
*
|
|
1270
1090
|
* Usage: `invite show`
|
|
1271
1091
|
*/
|
|
1272
|
-
inviteShow(options) {
|
|
1273
|
-
|
|
1092
|
+
async inviteShow(options) {
|
|
1093
|
+
const result = await this.#transport.call("invite show", [], options, {}, false);
|
|
1094
|
+
return result;
|
|
1274
1095
|
}
|
|
1275
1096
|
/**
|
|
1276
1097
|
* Print only your active invite link
|
|
1277
1098
|
*
|
|
1278
1099
|
* Usage: `invite link`
|
|
1279
1100
|
*/
|
|
1280
|
-
inviteLink(options) {
|
|
1281
|
-
|
|
1101
|
+
async inviteLink(options) {
|
|
1102
|
+
const result = await this.#transport.call("invite link", [], options, {}, false);
|
|
1103
|
+
return result;
|
|
1282
1104
|
}
|
|
1283
1105
|
/**
|
|
1284
1106
|
* List invite rewards you can use
|
|
1285
1107
|
*
|
|
1286
1108
|
* Usage: `invite rewards`
|
|
1287
1109
|
*/
|
|
1288
|
-
inviteRewards(options) {
|
|
1289
|
-
|
|
1110
|
+
async inviteRewards(options) {
|
|
1111
|
+
const result = await this.#transport.call("invite rewards", [], options, {}, false);
|
|
1112
|
+
return result;
|
|
1290
1113
|
}
|
|
1291
1114
|
/**
|
|
1292
1115
|
* Choose the reward for your invite link
|
|
1293
1116
|
*
|
|
1294
1117
|
* Usage: `invite set-reward standard|bonus-credits|extra-memory|extra-disk`
|
|
1295
1118
|
*/
|
|
1296
|
-
inviteSetReward(standardOrBonusCreditsOrExtraMemoryOrExtraDisk, options) {
|
|
1297
|
-
|
|
1119
|
+
async inviteSetReward(standardOrBonusCreditsOrExtraMemoryOrExtraDisk, options) {
|
|
1120
|
+
const result = await this.#transport.call("invite set-reward", [standardOrBonusCreditsOrExtraMemoryOrExtraDisk], options, {}, false);
|
|
1121
|
+
return result;
|
|
1298
1122
|
}
|
|
1299
1123
|
/**
|
|
1300
1124
|
* Show signups, upgrades, and reward status
|
|
1301
1125
|
*
|
|
1302
1126
|
* Usage: `invite activity`
|
|
1303
1127
|
*/
|
|
1304
|
-
inviteActivity(options) {
|
|
1305
|
-
|
|
1128
|
+
async inviteActivity(options) {
|
|
1129
|
+
const result = await this.#transport.call("invite activity", [], options, {}, false);
|
|
1130
|
+
return result;
|
|
1306
1131
|
}
|
|
1307
1132
|
/**
|
|
1308
1133
|
* Request more trial invites
|
|
1309
1134
|
*
|
|
1310
1135
|
* Usage: `invite request`
|
|
1311
1136
|
*/
|
|
1312
|
-
inviteRequest(options) {
|
|
1313
|
-
|
|
1137
|
+
async inviteRequest(options) {
|
|
1138
|
+
const result = await this.#transport.call("invite request", [], options, {}, false);
|
|
1139
|
+
return result;
|
|
1314
1140
|
}
|
|
1315
1141
|
/**
|
|
1316
1142
|
* Open the invites page
|
|
1317
1143
|
*
|
|
1318
1144
|
* Usage: `invite manage`
|
|
1319
1145
|
*/
|
|
1320
|
-
inviteManage(options) {
|
|
1321
|
-
|
|
1146
|
+
async inviteManage(options) {
|
|
1147
|
+
const result = await this.#transport.call("invite manage", [], options, {}, false);
|
|
1148
|
+
return result;
|
|
1322
1149
|
}
|
|
1323
1150
|
/**
|
|
1324
|
-
*
|
|
1151
|
+
* Generate a magic link to log in to the website
|
|
1325
1152
|
*
|
|
1326
|
-
* Usage: `
|
|
1153
|
+
* Usage: `browser`
|
|
1154
|
+
*/
|
|
1155
|
+
async browser(options) {
|
|
1156
|
+
const result = await this.#transport.call("browser", [], options, {
|
|
1157
|
+
qr: "bool",
|
|
1158
|
+
}, false);
|
|
1159
|
+
return result;
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
/** A VM reference. info is a snapshot; refresh() fetches current metadata. */
|
|
1163
|
+
export class VM {
|
|
1164
|
+
#transport;
|
|
1165
|
+
#info;
|
|
1166
|
+
/** @internal Obtain VMs through exe.new(), exe.ls(), exe.vm(), or vm.cp(). */
|
|
1167
|
+
constructor(transport, info) {
|
|
1168
|
+
this.#transport = transport;
|
|
1169
|
+
this.#info = Object.freeze({ ...info, tags: Object.freeze([...info.tags]) });
|
|
1170
|
+
}
|
|
1171
|
+
get info() { return this.#info; }
|
|
1172
|
+
get name() { return this.#info.name; }
|
|
1173
|
+
get httpsUrl() { return this.#info.httpsUrl; }
|
|
1174
|
+
get sshDest() { return this.#info.sshDest; }
|
|
1175
|
+
get tags() { return this.#info.tags; }
|
|
1176
|
+
/** Run a shell command once. Nonzero exit codes are results, not exceptions. */
|
|
1177
|
+
ssh(command, options) {
|
|
1178
|
+
return this.#transport.ssh(this.name, command, options);
|
|
1179
|
+
}
|
|
1180
|
+
/** Refresh metadata without changing this reference's identity. Requires ls permission. */
|
|
1181
|
+
async refresh(options) {
|
|
1182
|
+
const result = await this.#transport.call("ls", [this.name], options, {}, true);
|
|
1183
|
+
const vm = listVMs(this.#transport, result).find((vm) => vm.name === this.name);
|
|
1184
|
+
if (!vm)
|
|
1185
|
+
throw new ExeAPIError("ls", 404, "VM not found");
|
|
1186
|
+
this.#info = vm.info;
|
|
1187
|
+
return this;
|
|
1188
|
+
}
|
|
1189
|
+
/**
|
|
1190
|
+
* Probe SSH with `true` until it exits successfully. Never reruns a user command.
|
|
1191
|
+
* With waitUntil: "setup", then poll exe-setup.service until the setup script
|
|
1192
|
+
* has finished, throwing VMSetupError (as VMReadyError's cause) if it failed.
|
|
1193
|
+
* Images without that unit (anything but exeuntu) have no setup to wait for.
|
|
1194
|
+
* This does not wait for application servers. Requires ssh permission.
|
|
1195
|
+
*/
|
|
1196
|
+
async waitUntilReady(options = {}) {
|
|
1197
|
+
const { waitUntil = "ssh" } = options;
|
|
1198
|
+
if (waitUntil !== "ssh" && waitUntil !== "setup")
|
|
1199
|
+
throw new TypeError("exedev: waitUntil must be ssh or setup");
|
|
1200
|
+
const timeoutMs = readyTimeout(options.timeoutMs, waitUntil);
|
|
1201
|
+
options.signal?.throwIfAborted();
|
|
1202
|
+
const controller = new AbortController();
|
|
1203
|
+
const abort = () => controller.abort(options.signal.reason);
|
|
1204
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
1205
|
+
const timer = setTimeout(() => controller.abort(new DOMException(waitUntil === "setup" ? "setup did not finish in time" : "SSH readiness timed out", "TimeoutError")), timeoutMs);
|
|
1206
|
+
let backoff = 100;
|
|
1207
|
+
try {
|
|
1208
|
+
while (true) {
|
|
1209
|
+
try {
|
|
1210
|
+
const probe = waitUntil === "setup" ? setupProbe : "true";
|
|
1211
|
+
const result = await abortable(this.ssh(probe, {
|
|
1212
|
+
signal: controller.signal, capture: waitUntil === "setup", maxOutputBytes: 1 << 20,
|
|
1213
|
+
}), controller.signal);
|
|
1214
|
+
controller.signal.throwIfAborted();
|
|
1215
|
+
if (result.exitCode !== 0)
|
|
1216
|
+
throw new ExeProtocolError("ssh readiness probe");
|
|
1217
|
+
if (waitUntil === "ssh")
|
|
1218
|
+
return this;
|
|
1219
|
+
const state = setupState(result.stdout);
|
|
1220
|
+
if (state === "done")
|
|
1221
|
+
return this;
|
|
1222
|
+
if (state instanceof VMSetupError)
|
|
1223
|
+
throw state;
|
|
1224
|
+
backoff = Math.max(backoff, 1000);
|
|
1225
|
+
}
|
|
1226
|
+
catch (err) {
|
|
1227
|
+
controller.signal.throwIfAborted();
|
|
1228
|
+
// /exec reports these failures before a remote command starts, and
|
|
1229
|
+
// probes are safe to rerun after a lost connection. Other rejections
|
|
1230
|
+
// (not found, permissions, no SSH configured) fail fast.
|
|
1231
|
+
const retry = err instanceof SSHStreamError && err.code === "interrupted" ||
|
|
1232
|
+
err instanceof ExeAPIError && err.status === 422 &&
|
|
1233
|
+
/failed to (?:connect|dial|create session|run command on VM)/i.test(err.details().body);
|
|
1234
|
+
if (!retry)
|
|
1235
|
+
throw err;
|
|
1236
|
+
}
|
|
1237
|
+
await delay(backoff, controller.signal);
|
|
1238
|
+
backoff = Math.min(backoff * 2, 2000);
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
catch (err) {
|
|
1242
|
+
options.signal?.throwIfAborted();
|
|
1243
|
+
throw new VMReadyError(this, err);
|
|
1244
|
+
}
|
|
1245
|
+
finally {
|
|
1246
|
+
clearTimeout(timer);
|
|
1247
|
+
options.signal?.removeEventListener("abort", abort);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Delete a VM
|
|
1252
|
+
*
|
|
1253
|
+
* Usage: `rm <vmname>...`
|
|
1327
1254
|
*
|
|
1328
1255
|
* Tag-scoped API keys may run this command.
|
|
1329
1256
|
*/
|
|
1330
|
-
|
|
1331
|
-
|
|
1257
|
+
async rm(options) {
|
|
1258
|
+
const result = await this.#transport.documents("rm", [this.name], options, {});
|
|
1259
|
+
const summary = rmResult(result);
|
|
1260
|
+
if (summary.failed.length === 0 && summary.deleted.length === 1)
|
|
1261
|
+
return summary;
|
|
1262
|
+
throw new ExeAPIError("rm", summary.not_found?.length ? 404 : 422, result.body);
|
|
1332
1263
|
}
|
|
1333
1264
|
/**
|
|
1334
|
-
*
|
|
1265
|
+
* Restart a VM
|
|
1335
1266
|
*
|
|
1336
|
-
* Usage: `
|
|
1267
|
+
* Usage: `restart <vmname>`
|
|
1268
|
+
*
|
|
1269
|
+
* Tag-scoped API keys may run this command.
|
|
1270
|
+
*/
|
|
1271
|
+
async restart(options) {
|
|
1272
|
+
const ready = readiness(options ?? {});
|
|
1273
|
+
const { waitUntil, timeoutMs, ...flags } = options ?? {};
|
|
1274
|
+
const result = await this.#transport.call("restart", [this.name], flags, {}, true);
|
|
1275
|
+
if (ready)
|
|
1276
|
+
await this.waitUntilReady(ready);
|
|
1277
|
+
return this;
|
|
1278
|
+
}
|
|
1279
|
+
/**
|
|
1280
|
+
* Pause a VM (snapshot RAM to disk, free its CPU and memory)
|
|
1281
|
+
*
|
|
1282
|
+
* Usage: `pause <vmname>`
|
|
1283
|
+
*
|
|
1284
|
+
* CLI examples:
|
|
1285
|
+
* ```
|
|
1286
|
+
* pause my-vm # snapshot RAM to disk; resume later with 'resume my-vm'
|
|
1287
|
+
* ```
|
|
1288
|
+
*
|
|
1289
|
+
* Tag-scoped API keys may run this command.
|
|
1290
|
+
*/
|
|
1291
|
+
async pause(options) {
|
|
1292
|
+
const result = await this.#transport.call("pause", [this.name], options, {}, true);
|
|
1293
|
+
return result;
|
|
1294
|
+
}
|
|
1295
|
+
/**
|
|
1296
|
+
* Resume a paused VM (restore RAM from disk)
|
|
1297
|
+
*
|
|
1298
|
+
* Usage: `resume <vmname>`
|
|
1299
|
+
*
|
|
1300
|
+
* Tag-scoped API keys may run this command.
|
|
1301
|
+
*/
|
|
1302
|
+
async resume(options) {
|
|
1303
|
+
const ready = readiness(options ?? {});
|
|
1304
|
+
const { waitUntil, timeoutMs, ...flags } = options ?? {};
|
|
1305
|
+
const result = await this.#transport.call("resume", [this.name], flags, {}, true);
|
|
1306
|
+
if (ready)
|
|
1307
|
+
await this.waitUntilReady(ready);
|
|
1308
|
+
return this;
|
|
1309
|
+
}
|
|
1310
|
+
/**
|
|
1311
|
+
* rename a vm
|
|
1312
|
+
*
|
|
1313
|
+
* Usage: `rename <oldname> <newname>`
|
|
1314
|
+
*
|
|
1315
|
+
* Tag-scoped API keys may run this command.
|
|
1337
1316
|
*/
|
|
1338
|
-
|
|
1339
|
-
|
|
1317
|
+
async rename(newname, options) {
|
|
1318
|
+
if (newname === this.name)
|
|
1319
|
+
return this;
|
|
1320
|
+
const result = await this.#transport.call("rename", [this.name, newname], options, {}, true);
|
|
1321
|
+
if (result?.new_name !== newname || result?.old_name !== this.name)
|
|
1322
|
+
throw new ExeProtocolError("rename");
|
|
1323
|
+
// Destinations and other metadata may have changed. Do not invent URLs.
|
|
1324
|
+
this.#info = Object.freeze({ name: newname, tags: this.tags });
|
|
1325
|
+
return this;
|
|
1326
|
+
}
|
|
1327
|
+
/**
|
|
1328
|
+
* Add or remove tags on a VM
|
|
1329
|
+
*
|
|
1330
|
+
* Usage: `tag [-d] <vm> <tag-name> [tag-name...]`
|
|
1331
|
+
*
|
|
1332
|
+
* CLI examples:
|
|
1333
|
+
* ```
|
|
1334
|
+
* tag my-vm prod web # add tags
|
|
1335
|
+
* tag -d my-vm prod web # remove tags
|
|
1336
|
+
* ```
|
|
1337
|
+
*
|
|
1338
|
+
* Tag-scoped API keys may run this command.
|
|
1339
|
+
*/
|
|
1340
|
+
async tag(tagNames, options) {
|
|
1341
|
+
const result = await this.#transport.call("tag", [this.name, tagNames], options, {
|
|
1342
|
+
d: "bool",
|
|
1343
|
+
}, true);
|
|
1344
|
+
return result;
|
|
1345
|
+
}
|
|
1346
|
+
/**
|
|
1347
|
+
* Copy an existing VM
|
|
1348
|
+
*
|
|
1349
|
+
* Usage: `cp <source-vm> [new-name] [--pool=<name>] [--memory=<size>] [--cpu=<count>] [--disk=<size>]`
|
|
1350
|
+
*
|
|
1351
|
+
* CLI examples:
|
|
1352
|
+
* ```
|
|
1353
|
+
* cp my-vm # copy with auto-generated name
|
|
1354
|
+
* cp my-vm my-vm-copy # copy with specific name
|
|
1355
|
+
* cp my-vm --cpu=4 --memory=16GB # copy with different resources
|
|
1356
|
+
* cp my-vm my-pool-copy --pool=build # copy into a team pool
|
|
1357
|
+
* cp my-vm --copy-tags=false # copy without tags
|
|
1358
|
+
* ```
|
|
1359
|
+
*
|
|
1360
|
+
* Tag-scoped API keys may run this command.
|
|
1361
|
+
*/
|
|
1362
|
+
async cp(options) {
|
|
1363
|
+
const ready = readiness(options ?? {});
|
|
1364
|
+
const { waitUntil, timeoutMs, name, ...flags } = options ?? {};
|
|
1365
|
+
const result = await this.#transport.call("cp", [this.name, name], flags, {
|
|
1366
|
+
"copy-tags": "bool",
|
|
1367
|
+
cpu: "number",
|
|
1368
|
+
disk: "string",
|
|
1369
|
+
memory: "string",
|
|
1370
|
+
pool: "string",
|
|
1371
|
+
sandbox: "bool",
|
|
1372
|
+
standalone: "bool",
|
|
1373
|
+
}, true);
|
|
1374
|
+
const vm = new VM(this.#transport, vmInfo(result, "cp"));
|
|
1375
|
+
if (ready)
|
|
1376
|
+
await vm.waitUntilReady(ready);
|
|
1377
|
+
return vm;
|
|
1378
|
+
}
|
|
1379
|
+
/**
|
|
1380
|
+
* Resize a VM's resources (memory, CPU, disk)
|
|
1381
|
+
*
|
|
1382
|
+
* Usage: `resize <vmname> [--memory=<size>] [--cpu=<count>] [--disk=<size>]`
|
|
1383
|
+
*
|
|
1384
|
+
* Tag-scoped API keys may run this command.
|
|
1385
|
+
*/
|
|
1386
|
+
async resize(options) {
|
|
1387
|
+
const result = await this.#transport.call("resize", [this.name], options, {
|
|
1388
|
+
cpu: "number",
|
|
1389
|
+
disk: "string",
|
|
1390
|
+
memory: "string",
|
|
1391
|
+
}, true);
|
|
1392
|
+
return result;
|
|
1393
|
+
}
|
|
1394
|
+
/**
|
|
1395
|
+
* Set or clear a short comment on a VM
|
|
1396
|
+
*
|
|
1397
|
+
* Usage: `comment <hostname> <text>`
|
|
1398
|
+
*
|
|
1399
|
+
* CLI examples:
|
|
1400
|
+
* ```
|
|
1401
|
+
* comment my-vm staging copy
|
|
1402
|
+
* comment my-vm "" # clear the comment
|
|
1403
|
+
* ```
|
|
1404
|
+
*
|
|
1405
|
+
* Tag-scoped API keys may run this command.
|
|
1406
|
+
*/
|
|
1407
|
+
async comment(text, options) {
|
|
1408
|
+
const result = await this.#transport.call("comment", [this.name, text], options, {}, true);
|
|
1409
|
+
return result;
|
|
1410
|
+
}
|
|
1411
|
+
/**
|
|
1412
|
+
* Link a custom domain to a VM
|
|
1413
|
+
*
|
|
1414
|
+
* Usage: `domain add [--wildcard] <vm> <domain>`
|
|
1415
|
+
*/
|
|
1416
|
+
async domainAdd(domain, options) {
|
|
1417
|
+
const result = await this.#transport.call("domain add", [this.name, domain], options, {
|
|
1418
|
+
wildcard: "bool",
|
|
1419
|
+
}, true);
|
|
1420
|
+
return result;
|
|
1421
|
+
}
|
|
1422
|
+
/**
|
|
1423
|
+
* Remove a custom domain from a VM
|
|
1424
|
+
*
|
|
1425
|
+
* Usage: `domain rm <vm> <domain>`
|
|
1426
|
+
*/
|
|
1427
|
+
async domainRm(domain, options) {
|
|
1428
|
+
const result = await this.#transport.call("domain rm", [this.name, domain], options, {}, true);
|
|
1429
|
+
return result;
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* Show current shares for a VM
|
|
1433
|
+
*
|
|
1434
|
+
* Usage: `share show <vm>`
|
|
1435
|
+
*
|
|
1436
|
+
* Tag-scoped API keys may run this command.
|
|
1437
|
+
*/
|
|
1438
|
+
async shareShow(options) {
|
|
1439
|
+
const result = await this.#transport.call("share show", [this.name], options, {
|
|
1340
1440
|
qr: "bool",
|
|
1341
|
-
});
|
|
1441
|
+
}, true);
|
|
1442
|
+
return result;
|
|
1443
|
+
}
|
|
1444
|
+
/**
|
|
1445
|
+
* Set the HTTP proxy port for a VM
|
|
1446
|
+
*
|
|
1447
|
+
* Usage: `share port <vm> [port]`
|
|
1448
|
+
*
|
|
1449
|
+
* CLI examples:
|
|
1450
|
+
* ```
|
|
1451
|
+
* share port mybox 8080
|
|
1452
|
+
* ```
|
|
1453
|
+
*
|
|
1454
|
+
* Tag-scoped API keys may run this command.
|
|
1455
|
+
*/
|
|
1456
|
+
async sharePort(port, options) {
|
|
1457
|
+
const result = await this.#transport.call("share port", [this.name, port], options, {}, true);
|
|
1458
|
+
return result;
|
|
1459
|
+
}
|
|
1460
|
+
/**
|
|
1461
|
+
* Make the HTTP proxy publicly accessible
|
|
1462
|
+
*
|
|
1463
|
+
* Usage: `share set-public <vm>`
|
|
1464
|
+
*
|
|
1465
|
+
* Tag-scoped API keys may run this command.
|
|
1466
|
+
*/
|
|
1467
|
+
async shareSetPublic(options) {
|
|
1468
|
+
const result = await this.#transport.call("share set-public", [this.name], options, {}, true);
|
|
1469
|
+
return result;
|
|
1470
|
+
}
|
|
1471
|
+
/**
|
|
1472
|
+
* Restrict the HTTP proxy to authenticated users
|
|
1473
|
+
*
|
|
1474
|
+
* Usage: `share set-private <vm>`
|
|
1475
|
+
*
|
|
1476
|
+
* Tag-scoped API keys may run this command.
|
|
1477
|
+
*/
|
|
1478
|
+
async shareSetPrivate(options) {
|
|
1479
|
+
const result = await this.#transport.call("share set-private", [this.name], options, {}, true);
|
|
1480
|
+
return result;
|
|
1481
|
+
}
|
|
1482
|
+
/**
|
|
1483
|
+
* Share VM with a user via email, or grant shell access with --root
|
|
1484
|
+
*
|
|
1485
|
+
* Usage: `share add <vm> <email|team> [--root] [--message='...']`
|
|
1486
|
+
*
|
|
1487
|
+
* CLI examples:
|
|
1488
|
+
* ```
|
|
1489
|
+
* share add mybox user@example.com
|
|
1490
|
+
* share add mybox user@example.com --message='Check this out'
|
|
1491
|
+
* share add mybox team
|
|
1492
|
+
* share add mybox teammate@example.com --root
|
|
1493
|
+
* share add mybox team --root
|
|
1494
|
+
* ```
|
|
1495
|
+
*
|
|
1496
|
+
* Tag-scoped API keys may run this command.
|
|
1497
|
+
*/
|
|
1498
|
+
async shareAdd(emailOrTeam, options) {
|
|
1499
|
+
const result = await this.#transport.call("share add", [this.name, emailOrTeam], options, {
|
|
1500
|
+
message: "string",
|
|
1501
|
+
qr: "bool",
|
|
1502
|
+
root: "bool",
|
|
1503
|
+
}, true);
|
|
1504
|
+
return result;
|
|
1505
|
+
}
|
|
1506
|
+
/**
|
|
1507
|
+
* Revoke a user's access to a VM, or downgrade shell access to web with --root
|
|
1508
|
+
*
|
|
1509
|
+
* Usage: `share remove <vm> <email|team> [--root]`
|
|
1510
|
+
*
|
|
1511
|
+
* CLI examples:
|
|
1512
|
+
* ```
|
|
1513
|
+
* share remove mybox user@example.com
|
|
1514
|
+
* share remove mybox team
|
|
1515
|
+
* share remove mybox teammate@example.com --root
|
|
1516
|
+
* share remove mybox team --root
|
|
1517
|
+
* ```
|
|
1518
|
+
*
|
|
1519
|
+
* Tag-scoped API keys may run this command.
|
|
1520
|
+
*/
|
|
1521
|
+
async shareRemove(emailOrTeam, options) {
|
|
1522
|
+
const result = await this.#transport.call("share remove", [this.name, emailOrTeam], options, {
|
|
1523
|
+
root: "bool",
|
|
1524
|
+
}, true);
|
|
1525
|
+
return result;
|
|
1526
|
+
}
|
|
1527
|
+
/**
|
|
1528
|
+
* Create a shareable link for a VM
|
|
1529
|
+
*
|
|
1530
|
+
* Usage: `share add-link <vm>`
|
|
1531
|
+
*
|
|
1532
|
+
* Tag-scoped API keys may run this command.
|
|
1533
|
+
*/
|
|
1534
|
+
async shareAddLink(options) {
|
|
1535
|
+
const result = await this.#transport.call("share add-link", [this.name], options, {
|
|
1536
|
+
qr: "bool",
|
|
1537
|
+
}, true);
|
|
1538
|
+
return result;
|
|
1539
|
+
}
|
|
1540
|
+
/**
|
|
1541
|
+
* Revoke a shareable link
|
|
1542
|
+
*
|
|
1543
|
+
* Usage: `share remove-link <vm> <token>`
|
|
1544
|
+
*
|
|
1545
|
+
* Tag-scoped API keys may run this command.
|
|
1546
|
+
*/
|
|
1547
|
+
async shareRemoveLink(token, options) {
|
|
1548
|
+
const result = await this.#transport.call("share remove-link", [this.name, token], options, {}, true);
|
|
1549
|
+
return result;
|
|
1550
|
+
}
|
|
1551
|
+
/**
|
|
1552
|
+
* Enable or disable inbound email for a VM
|
|
1553
|
+
*
|
|
1554
|
+
* Usage: `share receive-email <vm> [on|off] [--reply-policy=all|known|owner|none]`
|
|
1555
|
+
*
|
|
1556
|
+
* CLI examples:
|
|
1557
|
+
* ```
|
|
1558
|
+
* share receive-email mybox on
|
|
1559
|
+
* share receive-email mybox off
|
|
1560
|
+
* share receive-email mybox --reply-policy=known
|
|
1561
|
+
* share receive-email mybox
|
|
1562
|
+
* ```
|
|
1563
|
+
*
|
|
1564
|
+
* Tag-scoped API keys may run this command.
|
|
1565
|
+
*/
|
|
1566
|
+
async shareReceiveEmail(onOrOff, options) {
|
|
1567
|
+
const result = await this.#transport.call("share receive-email", [this.name, onOrOff], options, {
|
|
1568
|
+
"reply-policy": "string",
|
|
1569
|
+
}, true);
|
|
1570
|
+
return result;
|
|
1571
|
+
}
|
|
1572
|
+
/**
|
|
1573
|
+
* Install or upgrade Shelley to the current version
|
|
1574
|
+
*
|
|
1575
|
+
* Usage: `shelley install <vm>`
|
|
1576
|
+
*
|
|
1577
|
+
* Tag-scoped API keys may run this command.
|
|
1578
|
+
*/
|
|
1579
|
+
async shelleyInstall(options) {
|
|
1580
|
+
const result = await this.#transport.call("shelley install", [this.name], options, {}, true);
|
|
1581
|
+
return result;
|
|
1342
1582
|
}
|
|
1343
1583
|
/**
|
|
1344
1584
|
* Allow exe.dev support to log in to a VM
|
|
@@ -1347,8 +1587,9 @@ export class Commands {
|
|
|
1347
1587
|
*
|
|
1348
1588
|
* Tag-scoped API keys may run this command.
|
|
1349
1589
|
*/
|
|
1350
|
-
grantSupportRoot(
|
|
1351
|
-
|
|
1590
|
+
async grantSupportRoot(onOrOff, options) {
|
|
1591
|
+
const result = await this.#transport.call("grant-support-root", [this.name, onOrOff], options, {}, false);
|
|
1592
|
+
return result;
|
|
1352
1593
|
}
|
|
1353
1594
|
/**
|
|
1354
1595
|
* Show vCPU, disk, IO, and network (RX/TX) metrics for a VM
|
|
@@ -1364,10 +1605,163 @@ export class Commands {
|
|
|
1364
1605
|
*
|
|
1365
1606
|
* Tag-scoped API keys may run this command.
|
|
1366
1607
|
*/
|
|
1367
|
-
stat(
|
|
1368
|
-
|
|
1608
|
+
async stat(options) {
|
|
1609
|
+
const result = await this.#transport.call("stat", [this.name], options, {
|
|
1369
1610
|
range: "string",
|
|
1370
|
-
});
|
|
1611
|
+
}, true);
|
|
1612
|
+
return result;
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
/** Readiness failed after a VM was obtained/created. The VM is not deleted. */
|
|
1616
|
+
export class VMReadyError extends Error {
|
|
1617
|
+
vm;
|
|
1618
|
+
constructor(vm, cause) {
|
|
1619
|
+
super(`exedev: VM ${vm.name} ${readyFailure(cause)}`, { cause });
|
|
1620
|
+
this.vm = vm;
|
|
1621
|
+
this.name = "VMReadyError";
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
function readyFailure(cause) {
|
|
1625
|
+
if (cause instanceof VMSetupError)
|
|
1626
|
+
return cause.message.replace(/^exedev: /, "");
|
|
1627
|
+
if (cause instanceof ExeAPIError && cause.status === 403 && cause.operation === "ssh") {
|
|
1628
|
+
return `is not known to be ready: this token may not run ssh, which readiness needs (use waitUntil: "created")`;
|
|
1629
|
+
}
|
|
1630
|
+
if (cause instanceof DOMException && cause.name === "TimeoutError")
|
|
1631
|
+
return `is not ready: ${cause.message}`;
|
|
1632
|
+
return "is not SSH-ready";
|
|
1633
|
+
}
|
|
1634
|
+
/** The VM's setup script failed. details() has the end of its journal. */
|
|
1635
|
+
export class VMSetupError extends Error {
|
|
1636
|
+
result;
|
|
1637
|
+
exitCode;
|
|
1638
|
+
signal;
|
|
1639
|
+
#output;
|
|
1640
|
+
constructor(
|
|
1641
|
+
/** systemd's Result for exe-setup.service, e.g. "exit-code", "signal", or "timeout". */
|
|
1642
|
+
result, exitCode, signal, output) {
|
|
1643
|
+
super(`exedev: setup script failed (${exitCode !== undefined ? `exit code ${exitCode}` : signal !== undefined ? `signal ${signal}` : result})`);
|
|
1644
|
+
this.result = result;
|
|
1645
|
+
this.exitCode = exitCode;
|
|
1646
|
+
this.signal = signal;
|
|
1647
|
+
this.name = "VMSetupError";
|
|
1648
|
+
this.#output = output;
|
|
1649
|
+
}
|
|
1650
|
+
/** The script's last journal lines; may contain secrets. */
|
|
1651
|
+
details() { return { output: this.#output }; }
|
|
1652
|
+
}
|
|
1653
|
+
function readyTimeout(value, waitUntil) {
|
|
1654
|
+
value ??= waitUntil === "setup" ? 600_000 : 60_000;
|
|
1655
|
+
if (!Number.isSafeInteger(value) || value <= 0 || value > 2_147_483_647) {
|
|
1656
|
+
throw new TypeError("exedev: timeoutMs must be a positive integer no greater than 2147483647");
|
|
1657
|
+
}
|
|
1658
|
+
return value;
|
|
1659
|
+
}
|
|
1660
|
+
function readiness(options) {
|
|
1661
|
+
const { waitUntil = "ssh", timeoutMs, signal } = options;
|
|
1662
|
+
if (waitUntil !== "ssh" && waitUntil !== "setup" && waitUntil !== "created") {
|
|
1663
|
+
throw new TypeError("exedev: waitUntil must be ssh, setup, or created");
|
|
1664
|
+
}
|
|
1665
|
+
readyTimeout(timeoutMs, waitUntil); // Validate before creating/copying/restarting a VM.
|
|
1666
|
+
return waitUntil === "created" ? undefined : { waitUntil, timeoutMs, signal };
|
|
1667
|
+
}
|
|
1668
|
+
// Report exe-setup.service's state, and on failure the end of its journal.
|
|
1669
|
+
// exessh can answer before exe-init hands PID 1 to systemd, and then before
|
|
1670
|
+
// systemd's bus is up ("Failed to connect to bus"): both are "booting".
|
|
1671
|
+
const setupProbe = `if [ ! -d /run/systemd/system ]; then
|
|
1672
|
+
if [ -e /etc/systemd/system/exe-setup.service ]; then echo State=booting; else echo State=unsupported; fi
|
|
1673
|
+
exit 0
|
|
1674
|
+
fi
|
|
1675
|
+
props=$(systemctl show exe-setup.service -p LoadState -p ActiveState -p Job -p Result -p ExecMainCode -p ExecMainStatus -p ExecMainExitTimestampMonotonic -p ConditionResult -p ConditionTimestampMonotonic 2>/dev/null) || { echo State=booting; exit 0; }
|
|
1676
|
+
echo "$props"
|
|
1677
|
+
echo "SystemState=$(systemctl is-system-running 2>/dev/null)"
|
|
1678
|
+
if [ "$(systemctl show exe-setup.service -p ActiveState --value)" = failed ]; then
|
|
1679
|
+
echo ---
|
|
1680
|
+
journalctl -b -u exe-setup.service -o cat --no-pager -n 50 2>&1
|
|
1681
|
+
fi`;
|
|
1682
|
+
/** "done" covers success and having no setup script, or no setup runner, to wait for. */
|
|
1683
|
+
function setupState(output) {
|
|
1684
|
+
const [head, ...journal] = output.split("\n---\n");
|
|
1685
|
+
const p = {};
|
|
1686
|
+
for (const line of head.split("\n")) {
|
|
1687
|
+
const at = line.indexOf("=");
|
|
1688
|
+
if (at > 0)
|
|
1689
|
+
p[line.slice(0, at)] = line.slice(at + 1).trim();
|
|
1690
|
+
}
|
|
1691
|
+
const number = (key) => /^\d+$/.test(p[key] ?? "") ? Number(p[key]) : undefined;
|
|
1692
|
+
if (p.State === "booting")
|
|
1693
|
+
return "pending";
|
|
1694
|
+
if (p.State === "unsupported" || p.LoadState === "not-found")
|
|
1695
|
+
return "done";
|
|
1696
|
+
if (!p.LoadState || !p.ActiveState)
|
|
1697
|
+
throw new ExeProtocolError("ssh setup probe");
|
|
1698
|
+
if (p.Job && p.Job !== "0" || ["activating", "deactivating", "reloading"].includes(p.ActiveState))
|
|
1699
|
+
return "pending";
|
|
1700
|
+
if (p.ActiveState === "failed" || number("ExecMainExitTimestampMonotonic") && p.Result !== "success") {
|
|
1701
|
+
// ExecMainCode: 1 exited, 2 killed, 3 dumped core. ExecMainStatus is the code or signal.
|
|
1702
|
+
const code = number("ExecMainCode"), status = number("ExecMainStatus");
|
|
1703
|
+
return new VMSetupError(p.Result || "failed", code === 1 ? status : undefined, code === 2 || code === 3 ? status : undefined, journal.join("\n---\n"));
|
|
1704
|
+
}
|
|
1705
|
+
if (number("ExecMainExitTimestampMonotonic"))
|
|
1706
|
+
return "done";
|
|
1707
|
+
if (number("ConditionTimestampMonotonic") && p.ConditionResult === "no")
|
|
1708
|
+
return "done";
|
|
1709
|
+
// Not reached yet while the system boots; otherwise it is not going to run.
|
|
1710
|
+
return ["initializing", "starting"].includes(p.SystemState) ? "pending" : "done";
|
|
1711
|
+
}
|
|
1712
|
+
function rmResult(value) {
|
|
1713
|
+
const summary = value.docs?.filter((doc) => !isErrorDocument(doc));
|
|
1714
|
+
const strings = (v) => Array.isArray(v) && v.every((s) => typeof s === "string");
|
|
1715
|
+
const obj = summary?.length === 1 ? summary[0] : undefined;
|
|
1716
|
+
if (!obj || typeof obj !== "object" || !strings(obj.deleted) || !strings(obj.failed) ||
|
|
1717
|
+
obj.not_found !== undefined && !strings(obj.not_found) ||
|
|
1718
|
+
obj.errors !== undefined && (typeof obj.errors !== "object" || obj.errors === null || Array.isArray(obj.errors) ||
|
|
1719
|
+
!Object.values(obj.errors).every((s) => typeof s === "string"))) {
|
|
1720
|
+
throw new ExeProtocolError("rm");
|
|
1721
|
+
}
|
|
1722
|
+
return obj;
|
|
1723
|
+
}
|
|
1724
|
+
function vmName(name) {
|
|
1725
|
+
if (name instanceof VM)
|
|
1726
|
+
return name.name;
|
|
1727
|
+
if (typeof name !== "string" || !/^[a-zA-Z0-9][a-zA-Z0-9-]*$/.test(name)) {
|
|
1728
|
+
throw new TypeError("exedev: expected a VM name, not a command or SSH destination");
|
|
1729
|
+
}
|
|
1730
|
+
return name;
|
|
1731
|
+
}
|
|
1732
|
+
function vmInfo(value, operation) {
|
|
1733
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
1734
|
+
throw new ExeProtocolError(operation);
|
|
1735
|
+
const obj = value;
|
|
1736
|
+
const string = (key, required = false) => {
|
|
1737
|
+
const value = obj[key];
|
|
1738
|
+
if (value === undefined && !required)
|
|
1739
|
+
return undefined;
|
|
1740
|
+
if (typeof value !== "string" || required && !value)
|
|
1741
|
+
throw new ExeProtocolError(operation);
|
|
1742
|
+
return value;
|
|
1743
|
+
};
|
|
1744
|
+
const name = string(operation === "cp" ? "name" : "vm_name", true);
|
|
1745
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9-]*$/.test(name))
|
|
1746
|
+
throw new ExeProtocolError(operation);
|
|
1747
|
+
const tags = obj.tags ?? [];
|
|
1748
|
+
if (!Array.isArray(tags) || !tags.every((tag) => typeof tag === "string"))
|
|
1749
|
+
throw new ExeProtocolError(operation);
|
|
1750
|
+
return {
|
|
1751
|
+
name, tags,
|
|
1752
|
+
sshDest: string(operation === "cp" ? "ssh" : "ssh_dest", true),
|
|
1753
|
+
httpsUrl: string("https_url", operation !== "cp"),
|
|
1754
|
+
status: string(operation === "cp" ? "state" : "status"),
|
|
1755
|
+
region: string("region"),
|
|
1756
|
+
comment: string("comment"),
|
|
1757
|
+
createdAt: string("created_at"),
|
|
1758
|
+
promptError: string("error"),
|
|
1759
|
+
};
|
|
1760
|
+
}
|
|
1761
|
+
function listVMs(transport, value) {
|
|
1762
|
+
if (!value || typeof value !== "object" || !("vms" in value) || !Array.isArray(value.vms)) {
|
|
1763
|
+
throw new ExeProtocolError("ls");
|
|
1371
1764
|
}
|
|
1765
|
+
return value.vms.map((row) => new VM(transport, vmInfo(row, "ls")));
|
|
1372
1766
|
}
|
|
1373
1767
|
//# sourceMappingURL=commands.gen.js.map
|