@exedev/sdk 0.1.0 → 0.2.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 CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  Official JavaScript/TypeScript SDK for the [exe.dev](https://exe.dev) HTTPS API.
4
4
 
5
- ## Install
6
-
7
5
  ```sh
8
6
  npm install @exedev/sdk
9
7
  ```
@@ -14,91 +12,156 @@ npm install @exedev/sdk
14
12
  import exedev from "@exedev/sdk";
15
13
 
16
14
  const exe = exedev({ token: process.env.EXE_TOKEN! });
17
-
18
- // Every exe.dev command is a method. Positional arguments are parameters;
19
- // flags go in an options object, spelled as on the command line.
20
15
  const vm = await exe.new({ name: "my-vm", image: "ubuntu:24.04", tag: ["dev"] });
21
- console.log(vm.https_url);
22
-
23
- const { vms } = await exe.ls();
24
- await exe.resize("my-vm", { memory: "8GB" });
25
- await exe.pause("my-vm");
26
- await exe.resume("my-vm");
27
- await exe.shareAdd("my-vm", "friend@example.com", { message: "have a look" });
28
- await exe.rm("my-vm");
29
-
30
- // Run a raw command line.
31
- const result = await exe.exec("help");
32
- console.log(result.body);
16
+ // new waits for SSH by default. No create-then-ssh retry loop is needed.
17
+ try {
18
+ console.log(vm.name, vm.httpsUrl);
19
+ const result = await vm.ssh("uname -a");
20
+ console.log(result.exitCode, result.stdout, result.stderr);
21
+ await vm.shareAdd("friend@example.com", { message: "have a look" });
22
+ } finally {
23
+ await vm.rm();
24
+ }
33
25
  ```
34
26
 
35
- ## Authentication
27
+ ## Client and VM API
28
+
29
+ `exedev({ token, baseURL?, fetch? })` creates a client. `baseURL` defaults to
30
+ `https://exe.dev`; `fetch` defaults to the global implementation. Named imports
31
+ of `exedev`, `ExedevClient`, and `VM` are also available.
32
+
33
+ - `exe.new(options?)` creates a VM and returns a `VM` object.
34
+ - `exe.ls(nameOrPattern?, options?)` returns `VM[]`.
35
+ - `exe.vm(name)` references an existing VM without making a request.
36
+ - `vm.refresh(options?)` refreshes its metadata and returns the same object.
37
+ - `vm.ssh(command, options?)` runs a shell command on that VM.
38
+ - `vm.cp({ name?, ...options })` copies it and returns a new `VM` object.
39
+ - Lifecycle and VM-scoped commands are methods on the VM: `vm.rm()`,
40
+ `vm.pause()`, `vm.resume()`, `vm.restart()`, `vm.rename(newName)`,
41
+ `vm.resize(options)`, `vm.stat(options)`, `vm.tag(tags)`, `vm.comment(text)`,
42
+ `vm.shareShow()`, `vm.sharePort(port)`, and the other generated VM commands.
43
+ - Account commands remain on the client: `exe.whoami()`, `exe.sshKeyList()`,
44
+ `exe.integrationsList()`, `exe.billingPlan()`, etc.
45
+
46
+ There is no parallel raw-command API or client-level `ssh`, `cp`, or `rm`.
47
+ Options for generated commands retain CLI flag names (for example,
48
+ `{ "no-email": true }`); each method carries the server's help text.
49
+ Methods with known JSON responses reject malformed JSON; other account/VM
50
+ commands may return JSON or text and are typed as `unknown`.
51
+
52
+ `vm.name` is the current name. `vm.httpsUrl`, `vm.sshDest`, and `vm.tags` expose
53
+ common metadata. `vm.info` is a read-only snapshot with `status`, `region`,
54
+ `comment`, `createdAt`, and `setupError` when available. A reference from
55
+ `exe.vm(name)` initially knows only its name. Copies do not invent a web URL;
56
+ call `refresh()` to fetch it. A successful `rename()` updates the same object
57
+ and invalidates old destinations; other references do not automatically change.
58
+
59
+ ## Readiness and cancellation
60
+
61
+ `new`, `cp`, `restart`, and `resume` wait for SSH by default. Pass
62
+ `{ waitUntil: "created" }` to return without probing, including when the token
63
+ has no `ssh` permission. `vm.waitUntilReady({ timeoutMs?, signal? })` explicitly
64
+ waits later. The default readiness deadline is 60 seconds **after** creation or
65
+ the lifecycle operation returns, including probe requests and backoff.
66
+
67
+ Readiness runs only the harmless command `true`, retrying transient connection
68
+ failures. It does not wait for application servers or setup scripts, and it
69
+ never retries a user command or the creation request.
70
+
71
+ If waiting fails, `VMReadyError.vm` gives you the VM for inspection or cleanup;
72
+ it is not automatically deleted. All operations accept an `AbortSignal`.
73
+ Caller cancellation preserves `signal.reason`, including during streaming and
74
+ callbacks, rather than wrapping it in another error. An aborted creation may
75
+ still have created a VM; use an explicit name or `ls()` to recover it.
76
+
77
+ ## Running commands
78
+
79
+ `vm.ssh()` resolves to `{ exitCode, stdout, stderr, stdoutBytes, stderrBytes,
80
+ captured }`. A nonzero exit code is a result, not an exception. Byte arrays
81
+ preserve binary output; strings are decoded as UTF-8. The command is a shell
82
+ script: quote any untrusted values you interpolate into it.
36
83
 
37
- Generate an API token via SSH:
38
-
39
- ```sh
40
- ssh exe.dev ssh-key generate-api-key --label=my-app --exp=30d
84
+ ```ts
85
+ await vm.ssh("make", {
86
+ capture: false,
87
+ onStdout: (chunk) => { process.stdout.write(chunk); },
88
+ onStderr: (chunk) => { process.stderr.write(chunk); },
89
+ });
41
90
  ```
42
91
 
43
- See the [HTTPS API docs](https://exe.dev/docs/https-api) for full details on
44
- authentication, token permissions, and scoping.
45
-
46
- ## API
92
+ Callbacks are awaited serially, with incremental UTF-8 decoding per stream.
93
+ Their cross-stream order is approximate. Throwing from a callback cancels the
94
+ response and rejects with that error.
47
95
 
48
- ### `exedev(options)`
96
+ Output is captured by default, with an **8 MiB combined limit** on stdout and
97
+ stderr. Change it with `maxOutputBytes`; exceeding it cancels the response and
98
+ throws `SSHStreamError` with code `output_limit`. Set `capture: false` for
99
+ bounded-memory streaming of arbitrarily long output: callbacks still receive
100
+ it, but result/error output is empty and `captured` is false. The capture limit
101
+ is ignored in this mode. Invalid or oversized NDJSON frames are always rejected.
49
102
 
50
- | Option | Type | Required | Default |
51
- | --------- | ------ | -------- | ------------------- |
52
- | `token` | string | Yes | |
53
- | `baseURL` | string | No | `https://exe.dev` |
54
- | `fetch` | function | No | global `fetch` |
103
+ ## Errors
55
104
 
56
- ### Commands
105
+ - `ExeAPIError`: `operation` and HTTP `status`. The message, stack, and ordinary
106
+ serialization omit request arguments and server response bodies. Explicitly
107
+ call `error.details().body` for diagnostics; this may contain secrets.
108
+ - `ExeProtocolError`: an incompatible response, including malformed JSON or a
109
+ server that does not support NDJSON SSH output.
110
+ - `SSHStreamError`: interrupted/invalid output or a capture limit. `code` is
111
+ `interrupted`, `protocol`, or `output_limit`; getters provide captured partial
112
+ output. The exit status is unknown. `details()` exposes opt-in server diagnostics.
113
+ - `VMReadyError`: readiness failed; `vm` and `cause` are available.
57
114
 
58
- Each public exe.dev command that runs over the HTTPS API is a method, named by
59
- camel-casing its path: `ls`, `new`, `ssh-key list` is `sshKeyList`,
60
- `team settings auto-join` is `teamSettingsAutoJoin`. Each method's doc comment
61
- is the command's own help text, so `help <command>` and your editor agree.
115
+ Errors do not establish that an operation never ran. Do not blindly retry a
116
+ mutation or remote command after a transport failure.
62
117
 
63
- Methods resolve to the command's JSON output, typed for the commands listed in
64
- `CommandResults` (`src/types.ts`) and `unknown` otherwise. They reject with
65
- `ExeAPIError` (`status`, `command`, `body`) when a command fails. Every
66
- options object accepts `signal` (an `AbortSignal`) for cancellation.
67
-
68
- The command methods live in `src/commands.gen.ts`, which is generated from the
69
- exe.dev command tree; don't edit it by hand. To pick up new commands, run
70
- `npm run sync-commands -- path/to/exe` (default `../exe`) with an up-to-date
71
- checkout of the exe.dev repository, then `npm test`.
118
+ ## Authentication
72
119
 
73
- ### Named import
120
+ Generate a token via SSH:
74
121
 
75
- ```ts
76
- import { exedev } from "@exedev/sdk";
122
+ ```sh
123
+ ssh exe.dev ssh-key generate-api-key --label=my-app --exp=30d --cmds="new,ls,ssh,rm"
77
124
  ```
78
125
 
126
+ See the [HTTPS API docs](https://exe.dev/docs/https-api) for permissions and scoping.
127
+
79
128
  ## Development
80
129
 
130
+ **All of `src/` is generated.** Edit `cmd/gensdkjs` and its TypeScript templates
131
+ in the exe.dev repository, then run `go run ./cmd/gensdkjs` there. Copy the
132
+ outputs into this checkout and test:
133
+
81
134
  ```sh
82
135
  npm install
136
+ npm run sync-commands -- ../exe
83
137
  npm test
84
138
  ```
85
139
 
86
- `npm test` builds the package, then runs the unit tests and the integration
87
- tests. The integration tests run against the real exe.dev API and create,
88
- restart, rename and delete a VM. They need a tag-scoped API token, which can
89
- only see and touch VMs with its tag, and they fail without one (set
90
- `EXE_SKIP_INTEGRATION=1` to skip them). To create the token:
140
+ `npm test` builds the package, checks the public TypeScript API, and runs unit
141
+ and live integration tests. Live tests require a tag-scoped token and create,
142
+ copy, execute commands on, restart, rename, and delete their own test VMs.
143
+ They read `$EXE_TOKEN`, or `$EXE_TOKEN_FILE` (a bare token or JSON containing
144
+ `token`), or `~/.config/exedev/sdk-test-token`. The expected tag is `sdk-test`
145
+ (override with `$EXE_TEST_TAG`). To create a test token:
91
146
 
92
147
  ```sh
93
- mkdir -p ~/.config/exedev
94
- ssh exe.dev 'ssh-key generate-api-key --label=sdk-test --tag=sdk-test --exp=30d --cmds="help,ls,new,whoami,stat,rm,restart,rename,ssh-key list,share show" --json' \
95
- | jq -r .token > ~/.config/exedev/sdk-test-token
96
- chmod 600 ~/.config/exedev/sdk-test-token
148
+ ssh exe.dev 'ssh-key generate-api-key --label=sdk-test --tag=sdk-test --exp=30d --cmds="ls,new,whoami,stat,rm,restart,rename,cp,ssh,ssh-key list,share show" --json'
97
149
  ```
98
150
 
99
- The tests read the token from `$EXE_TOKEN` or `~/.config/exedev/sdk-test-token`.
100
- They check that the VM they create is tagged `sdk-test` (override with
101
- `$EXE_TEST_TAG`). Revoke the token with `ssh exe.dev ssh-key remove sdk-test`.
151
+ Set `EXE_SKIP_INTEGRATION=1` to run without live access. Set
152
+ `EXE_SKIP_SSH_INTEGRATION=1` to exercise only the live control plane when the
153
+ server has not yet deployed NDJSON SSH support; this explicitly skips live SSH
154
+ and readiness assertions, not the corresponding unit tests. The full live
155
+ suite requires that protocol and does not silently fall back to raw SSH output.
156
+
157
+ The generator's Go tests check regeneration and command grammar assumptions.
158
+ Server-side wire-contract tests exercise creation, listing, copying, and SSH.
159
+ To run the generated SDK end-to-end against the local Go HTTP/SSH fixture:
160
+
161
+ ```sh
162
+ # In the exe.dev checkout, with this SDK's npm dependencies installed:
163
+ EXE_SDK_JS_DIR=/absolute/path/to/exe-sdk-js go test ./execore -run TestSDKJSHTTP
164
+ ```
102
165
 
103
166
  ## License
104
167
 
package/dist/client.d.ts CHANGED
@@ -1,59 +1,69 @@
1
- import { Commands } from "./commands.gen.js";
2
1
  import type { Arg, CallOptions, FlagKind } from "./commands.gen.js";
3
2
  export interface ExedevOptions {
4
- /** Bearer token (exe0.* or exe1.*). */
3
+ /** API bearer token. */
5
4
  token: string;
6
- /** Base URL for the API. Defaults to "https://exe.dev". */
5
+ /** Defaults to https://exe.dev. */
7
6
  baseURL?: string;
8
- /** fetch implementation. Defaults to the global fetch. */
7
+ /** Defaults to global fetch. */
9
8
  fetch?: typeof fetch;
10
9
  }
11
- /** @deprecated Use CallOptions. */
12
- export type ExecOptions = CallOptions;
13
- export interface ExecResult {
14
- /** HTTP status code. */
15
- status: number;
16
- /** Raw response body. */
17
- body: string;
18
- /** Whether the request succeeded (2xx). */
19
- ok: boolean;
10
+ export interface SSHOptions extends CallOptions {
11
+ /** Awaited serially as UTF-8 output arrives. Throwing cancels the response. */
12
+ onStdout?: (data: string) => void | Promise<void>;
13
+ onStderr?: (data: string) => void | Promise<void>;
14
+ /** Retain output in the result/error. Set false for bounded-memory streaming. Default true. */
15
+ capture?: boolean;
16
+ /** Maximum combined captured bytes. Default 8 MiB. Ignored with capture: false. */
17
+ maxOutputBytes?: number;
20
18
  }
21
- /**
22
- * An exe.dev API client. Each exe.dev command is a method (see Commands);
23
- * exec runs a raw command line.
24
- *
25
- * Command methods resolve to the command's parsed JSON output and reject with
26
- * ExeAPIError when the command fails.
27
- */
28
- export declare class ExedevClient extends Commands {
19
+ export interface SSHResult {
20
+ readonly exitCode: number;
21
+ readonly captured: boolean;
22
+ readonly stdout: string;
23
+ readonly stderr: string;
24
+ readonly stdoutBytes: Uint8Array;
25
+ readonly stderrBytes: Uint8Array;
26
+ }
27
+ /** API rejection. Neither requests nor response bodies appear in default logging. */
28
+ export declare class ExeAPIError extends Error {
29
+ #private;
30
+ readonly operation: string;
31
+ readonly status: number;
32
+ constructor(operation: string, status: number, body: string);
33
+ /** Opt-in server diagnostics; may contain secrets. Does not establish whether an operation ran. */
34
+ details(): {
35
+ body: string;
36
+ };
37
+ }
38
+ export declare class ExeProtocolError extends Error {
39
+ readonly operation: string;
40
+ constructor(operation: string);
41
+ }
42
+ /** The command's exit status is unknown; captured output is only a prefix. Do not blindly retry. */
43
+ export declare class SSHStreamError extends Error {
44
+ #private;
45
+ readonly code: "interrupted" | "protocol" | "output_limit";
46
+ readonly captured: boolean;
47
+ constructor(code: "interrupted" | "protocol" | "output_limit", captured: boolean, stdout: Uint8Array, stderr: Uint8Array, detail?: string);
48
+ get stdoutBytes(): Uint8Array;
49
+ get stderrBytes(): Uint8Array;
50
+ get stdout(): string;
51
+ get stderr(): string;
52
+ /** Opt-in server diagnostics; may contain secrets. */
53
+ details(): {
54
+ message?: string;
55
+ };
56
+ }
57
+ /** Internal transport, deliberately not exported from the package entry point. */
58
+ export declare class Transport {
29
59
  #private;
30
60
  constructor(opts: ExedevOptions);
31
- /** Executes a raw command line against the exe.dev API. */
32
- exec(command: string, options?: CallOptions): Promise<ExecResult>;
33
- protected run(path: string, args: readonly Arg[], options: CallOptions | undefined, flags: Readonly<Record<string, FlagKind>>): Promise<any>;
61
+ call(path: string, args: readonly Arg[], options: CallOptions | undefined, flags: Readonly<Record<string, FlagKind>>, json?: boolean): Promise<any>;
62
+ ssh(vm: string, command: string, options?: SSHOptions): Promise<SSHResult>;
34
63
  }
35
- /**
36
- * Create an exe.dev API client.
37
- *
38
- * @example
39
- * ```ts
40
- * import exedev from "@exedev/sdk";
41
- *
42
- * const exe = exedev({ token: process.env.EXE_TOKEN! });
43
- * const { vms } = await exe.ls();
44
- * console.log(vms);
45
- * ```
46
- */
47
- export default function exedev(opts: ExedevOptions): ExedevClient;
48
- /** Builds the command line for a generated command method. */
49
64
  export declare function commandLine(path: string, args: readonly Arg[], options: CallOptions | undefined, flags: Readonly<Record<string, FlagKind>>): string;
50
- /** Quotes s for the exe.dev command-line parser (POSIX shell rules). */
51
65
  export declare function quote(s: string): string;
52
- /** Error thrown when the exe.dev API reports a failed command. */
53
- export declare class ExeAPIError extends Error {
54
- readonly command: string;
55
- readonly status: number;
56
- readonly body: string;
57
- constructor(command: string, status: number, body: string);
58
- }
66
+ /** Stop waiting for an uncooperative fetch/body/callback when the caller cancels. */
67
+ export declare function abortable<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T>;
68
+ export declare function delay(ms: number, signal: AbortSignal): Promise<void>;
59
69
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEpE,MAAM,WAAW,aAAa;IAC5B,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,mCAAmC;AACnC,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC;AAEtC,MAAM,WAAW,UAAU;IACzB,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,EAAE,EAAE,OAAO,CAAC;CACb;AAED;;;;;;GAMG;AACH,qBAAa,YAAa,SAAQ,QAAQ;;gBAK5B,IAAI,EAAE,aAAa;IAU/B,2DAA2D;IACrD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;cAcvD,GAAG,CACjB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,GAAG,EAAE,EACpB,OAAO,EAAE,WAAW,GAAG,SAAS,EAChC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,GACxC,OAAO,CAAC,GAAG,CAAC;CAiBhB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,YAAY,CAEhE;AAED,8DAA8D;AAC9D,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,GAAG,EAAE,EACpB,OAAO,EAAE,WAAW,GAAG,SAAS,EAChC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,GACxC,MAAM,CA2CR;AAED,wEAAwE;AACxE,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAKvC;AA4BD,kEAAkE;AAClE,qBAAa,WAAY,SAAQ,KAAK;IACpC,SAAgB,OAAO,EAAE,MAAM,CAAC;IAChC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,IAAI,EAAE,MAAM,CAAC;gBAEjB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAO1D"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}