@remotehost/sdk 0.1.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/LICENSE.md +21 -0
- package/README.md +89 -0
- package/THIRD-PARTY-NOTICES.md +51 -0
- package/dist/client.d.ts +29 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +121 -0
- package/dist/commands.d.ts +15 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +19 -0
- package/dist/errors.d.ts +25 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +77 -0
- package/dist/files.d.ts +36 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +61 -0
- package/dist/generated/schema.d.ts +4217 -0
- package/dist/generated/schema.d.ts.map +1 -0
- package/dist/generated/schema.js +5 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/internal.d.ts +18 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +21 -0
- package/dist/metrics.d.ts +15 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +24 -0
- package/dist/previews.d.ts +27 -0
- package/dist/previews.d.ts.map +1 -0
- package/dist/previews.js +35 -0
- package/dist/request-options.d.ts +7 -0
- package/dist/request-options.d.ts.map +1 -0
- package/dist/request-options.js +27 -0
- package/dist/sandboxes.d.ts +115 -0
- package/dist/sandboxes.d.ts.map +1 -0
- package/dist/sandboxes.js +234 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/package.json +62 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 RemoteHost, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# RemoteHost TypeScript SDK
|
|
2
|
+
|
|
3
|
+
The official server-side TypeScript SDK for the RemoteHost API, licensed under MIT.
|
|
4
|
+
|
|
5
|
+
Source, issues, and contributions: [remotehostai/sdk](https://github.com/remotehostai/sdk).
|
|
6
|
+
|
|
7
|
+
The low-level request and response types in `src/generated` are generated from
|
|
8
|
+
`apps/api/generated/openapi.json`. The public resource API is maintained by hand
|
|
9
|
+
in the rest of `src`.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install @remotehost/sdk
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import RemoteHost from "@remotehost/sdk";
|
|
21
|
+
|
|
22
|
+
const remotehost = new RemoteHost({
|
|
23
|
+
apiKey: process.env.REMOTEHOST_API_KEY,
|
|
24
|
+
orgId: "org_123",
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const sandbox = await remotehost.sandboxes.create({
|
|
28
|
+
projectId: "project_123",
|
|
29
|
+
agent: "codex",
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
console.log(sandbox.id, sandbox.status);
|
|
33
|
+
const result = await sandbox.commands.run("pnpm test");
|
|
34
|
+
const source = await sandbox.files.readText("src/index.ts");
|
|
35
|
+
const preview = await sandbox.previews.create({ port: 3000 });
|
|
36
|
+
await sandbox.sleep();
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`apiKey` defaults to `REMOTEHOST_API_KEY` in server environments. Browser use
|
|
40
|
+
is rejected by default to prevent accidentally exposing a secret key. Sandbox
|
|
41
|
+
creation waits until the sandbox is running and the agent inside it answers,
|
|
42
|
+
so the first command works; pass `waitForReady: false` to get the
|
|
43
|
+
provisioning response immediately.
|
|
44
|
+
|
|
45
|
+
API failures throw `RemoteHostAPIError` with `status`, `code` (for example
|
|
46
|
+
`rate_limited` or `limit_reached`), `requestId`, and the response body.
|
|
47
|
+
|
|
48
|
+
For endpoints without a convenience resource, use the fully typed
|
|
49
|
+
`remotehost.raw` OpenAPI client. Generated `paths`, `operations`, and
|
|
50
|
+
`components` types are available from `@remotehost/sdk/openapi`.
|
|
51
|
+
|
|
52
|
+
See the [SDK guide](https://docs.remotehost.ai/docs/sdk) for commands, files,
|
|
53
|
+
previews, metrics, lifecycle methods, errors, retries, and cancellation.
|
|
54
|
+
|
|
55
|
+
## Development
|
|
56
|
+
|
|
57
|
+
The public repository is a standalone source mirror maintained from RemoteHost's
|
|
58
|
+
monorepo. Clone it to inspect the implementation, run tests, or contribute a fix:
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
git clone https://github.com/remotehostai/sdk.git
|
|
62
|
+
cd sdk
|
|
63
|
+
npm ci
|
|
64
|
+
npm test
|
|
65
|
+
npm run typecheck
|
|
66
|
+
npm run build
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The generated API types are checked in, so building does not require access to
|
|
70
|
+
the API server or the monorepo. Do not edit `src/generated/schema.ts` by hand;
|
|
71
|
+
report contract changes in an issue so they can be regenerated upstream.
|
|
72
|
+
|
|
73
|
+
Public pull requests are welcome. Maintainers integrate changes into the
|
|
74
|
+
monorepo and synchronize them back here. Published versions have matching
|
|
75
|
+
`v<version>` tags and GitHub releases; `main` may contain an unpublished snapshot.
|
|
76
|
+
See [CONTRIBUTING.md](https://github.com/remotehostai/sdk/blob/main/CONTRIBUTING.md).
|
|
77
|
+
|
|
78
|
+
For development inside the monorepo:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
pnpm --filter @remotehost/sdk generate
|
|
82
|
+
pnpm --filter @remotehost/sdk test
|
|
83
|
+
pnpm --filter @remotehost/sdk build
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
[MIT](LICENSE.md). Dependencies retain their own licenses; see
|
|
89
|
+
[THIRD-PARTY-NOTICES.md](THIRD-PARTY-NOTICES.md).
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
The SDK uses the following separately licensed open-source dependencies.
|
|
4
|
+
|
|
5
|
+
## openapi-fetch 0.17.0
|
|
6
|
+
|
|
7
|
+
MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2023 Drew Powers
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
|
|
29
|
+
## openapi-typescript-helpers 0.1.0
|
|
30
|
+
|
|
31
|
+
MIT License
|
|
32
|
+
|
|
33
|
+
Copyright (c) 2023 Drew Powers
|
|
34
|
+
|
|
35
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
36
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
37
|
+
in the Software without restriction, including without limitation the rights
|
|
38
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
39
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
40
|
+
furnished to do so, subject to the following conditions:
|
|
41
|
+
|
|
42
|
+
The above copyright notice and this permission notice shall be included in all
|
|
43
|
+
copies or substantial portions of the Software.
|
|
44
|
+
|
|
45
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
46
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
47
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
48
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
49
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
50
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
51
|
+
SOFTWARE.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { APIClient } from "./internal.js";
|
|
2
|
+
import { Sandboxes } from "./sandboxes.js";
|
|
3
|
+
export type RemoteHostOptions = {
|
|
4
|
+
/** Secret API key. Defaults to REMOTEHOST_API_KEY outside browsers. */
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
/** API root, including `/v1`. */
|
|
7
|
+
baseURL?: string;
|
|
8
|
+
/** Default organization for organization-scoped operations. */
|
|
9
|
+
orgId?: string;
|
|
10
|
+
/** Custom Fetch implementation, useful for tests and non-Node runtimes. */
|
|
11
|
+
fetch?: (request: Request) => Promise<Response>;
|
|
12
|
+
/** Headers included with every request. Authorization and SDK version are managed by the SDK. */
|
|
13
|
+
headers?: HeadersInit;
|
|
14
|
+
/** Maximum automatic retries for safe GET and HEAD requests. Defaults to 2. */
|
|
15
|
+
maxRetries?: number;
|
|
16
|
+
/** Default deadline for one HTTP request. Defaults to 10 minutes. */
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
/** Allow secret-key use in a browser. This can expose the key to users. */
|
|
19
|
+
dangerouslyAllowBrowser?: boolean;
|
|
20
|
+
};
|
|
21
|
+
/** Server-side client for the RemoteHost API. */
|
|
22
|
+
export declare class RemoteHost {
|
|
23
|
+
/** Fully typed access to every operation in the generated OpenAPI contract. */
|
|
24
|
+
readonly raw: APIClient;
|
|
25
|
+
/** Create, list, and retrieve sandboxes. */
|
|
26
|
+
readonly sandboxes: Sandboxes;
|
|
27
|
+
constructor(options?: RemoteHostOptions);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAO3C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,uEAAuE;IACvE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChD,iGAAiG;IACjG,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC,CAAC;AAEF,iDAAiD;AACjD,qBAAa,UAAU;IACrB,+EAA+E;IAC/E,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IACxB,4CAA4C;IAC5C,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;gBAElB,OAAO,GAAE,iBAAsB;CAuC5C"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import createClient from "openapi-fetch";
|
|
2
|
+
import { RemoteHostConfigurationError } from "./errors.js";
|
|
3
|
+
import { Sandboxes } from "./sandboxes.js";
|
|
4
|
+
import { VERSION } from "./version.js";
|
|
5
|
+
const DEFAULT_BASE_URL = "https://api.remotehost.ai/v1";
|
|
6
|
+
const DEFAULT_TIMEOUT_MS = 10 * 60 * 1000;
|
|
7
|
+
const DEFAULT_MAX_RETRIES = 2;
|
|
8
|
+
/** Server-side client for the RemoteHost API. */
|
|
9
|
+
export class RemoteHost {
|
|
10
|
+
/** Fully typed access to every operation in the generated OpenAPI contract. */
|
|
11
|
+
raw;
|
|
12
|
+
/** Create, list, and retrieve sandboxes. */
|
|
13
|
+
sandboxes;
|
|
14
|
+
constructor(options = {}) {
|
|
15
|
+
if (isBrowser() && !options.dangerouslyAllowBrowser) {
|
|
16
|
+
throw new RemoteHostConfigurationError("RemoteHost API keys must not be exposed in browser code. Use a server environment, or explicitly set dangerouslyAllowBrowser if you understand the risk.");
|
|
17
|
+
}
|
|
18
|
+
const apiKey = options.apiKey ?? readEnvironmentVariable("REMOTEHOST_API_KEY");
|
|
19
|
+
if (!apiKey) {
|
|
20
|
+
throw new RemoteHostConfigurationError("Missing API key. Pass apiKey or set REMOTEHOST_API_KEY.");
|
|
21
|
+
}
|
|
22
|
+
const headers = new Headers(options.headers);
|
|
23
|
+
headers.set("authorization", `Bearer ${apiKey}`);
|
|
24
|
+
headers.set("x-remotehost-sdk-version", VERSION);
|
|
25
|
+
const fetcher = options.fetch ?? globalThis.fetch;
|
|
26
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
27
|
+
const maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
28
|
+
if (!Number.isInteger(maxRetries) || maxRetries < 0) {
|
|
29
|
+
throw new RemoteHostConfigurationError("maxRetries must be a non-negative integer.");
|
|
30
|
+
}
|
|
31
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
32
|
+
throw new RemoteHostConfigurationError("timeoutMs must be a positive number.");
|
|
33
|
+
}
|
|
34
|
+
const api = createClient({
|
|
35
|
+
baseUrl: trimTrailingSlash(options.baseURL ?? DEFAULT_BASE_URL),
|
|
36
|
+
fetch: createReliableFetch(fetcher, { maxRetries, timeoutMs }),
|
|
37
|
+
headers,
|
|
38
|
+
});
|
|
39
|
+
this.raw = api;
|
|
40
|
+
this.sandboxes = new Sandboxes(api, options.orgId);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function isBrowser() {
|
|
44
|
+
return typeof window !== "undefined" && typeof window.document !== "undefined";
|
|
45
|
+
}
|
|
46
|
+
function readEnvironmentVariable(name) {
|
|
47
|
+
const runtime = globalThis;
|
|
48
|
+
return runtime.process?.env?.[name];
|
|
49
|
+
}
|
|
50
|
+
function trimTrailingSlash(url) {
|
|
51
|
+
return url.replace(/\/+$/, "");
|
|
52
|
+
}
|
|
53
|
+
function createReliableFetch(fetcher, options) {
|
|
54
|
+
return async (request) => {
|
|
55
|
+
const retryable = request.method === "GET" || request.method === "HEAD";
|
|
56
|
+
let attempt = 0;
|
|
57
|
+
while (true) {
|
|
58
|
+
const timeout = AbortSignal.timeout(options.timeoutMs);
|
|
59
|
+
const signal = AbortSignal.any([request.signal, timeout]);
|
|
60
|
+
try {
|
|
61
|
+
const response = await fetcher(new Request(request, { signal }));
|
|
62
|
+
if (!retryable || attempt >= options.maxRetries || !isRetryableStatus(response.status)) {
|
|
63
|
+
return response;
|
|
64
|
+
}
|
|
65
|
+
await response.body?.cancel().catch(() => undefined);
|
|
66
|
+
await delay(retryDelayMs(response, attempt), request.signal);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (request.signal.aborted || errorName(error) === "TimeoutError") {
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
if (!retryable || attempt >= options.maxRetries) {
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
await delay(backoffMs(attempt), request.signal);
|
|
76
|
+
}
|
|
77
|
+
attempt += 1;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function isRetryableStatus(status) {
|
|
82
|
+
return status === 408 || status === 409 || status === 429 || status >= 500;
|
|
83
|
+
}
|
|
84
|
+
function retryDelayMs(response, attempt) {
|
|
85
|
+
const retryAfter = response.headers.get("retry-after");
|
|
86
|
+
if (retryAfter) {
|
|
87
|
+
const seconds = Number(retryAfter);
|
|
88
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
89
|
+
return Math.min(seconds * 1000, 60_000);
|
|
90
|
+
}
|
|
91
|
+
const date = Date.parse(retryAfter);
|
|
92
|
+
if (Number.isFinite(date)) {
|
|
93
|
+
return Math.min(Math.max(date - Date.now(), 0), 60_000);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return backoffMs(attempt);
|
|
97
|
+
}
|
|
98
|
+
function backoffMs(attempt) {
|
|
99
|
+
const exponential = Math.min(500 * 2 ** attempt, 8_000);
|
|
100
|
+
return Math.round(exponential * (0.75 + Math.random() * 0.5));
|
|
101
|
+
}
|
|
102
|
+
async function delay(ms, signal) {
|
|
103
|
+
await new Promise((resolve, reject) => {
|
|
104
|
+
if (signal.aborted) {
|
|
105
|
+
reject(signal.reason);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const onAbort = () => {
|
|
109
|
+
clearTimeout(timer);
|
|
110
|
+
reject(signal.reason);
|
|
111
|
+
};
|
|
112
|
+
const timer = setTimeout(() => {
|
|
113
|
+
signal.removeEventListener("abort", onAbort);
|
|
114
|
+
resolve();
|
|
115
|
+
}, ms);
|
|
116
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function errorName(error) {
|
|
120
|
+
return error instanceof Error ? error.name : null;
|
|
121
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { components } from "./generated/schema.js";
|
|
2
|
+
import type { APIClient } from "./internal.js";
|
|
3
|
+
import type { RequestOptions } from "./request-options.js";
|
|
4
|
+
export type CommandResult = components["schemas"]["ExecSandboxResult"];
|
|
5
|
+
export type RunCommandOptions = RequestOptions & {
|
|
6
|
+
timeoutSeconds?: number;
|
|
7
|
+
};
|
|
8
|
+
export declare class SandboxCommands {
|
|
9
|
+
private readonly api;
|
|
10
|
+
private readonly sandboxId;
|
|
11
|
+
constructor(api: APIClient, sandboxId: string);
|
|
12
|
+
/** Run a non-interactive command to completion and capture its exit code and output. */
|
|
13
|
+
run(command: string, options?: RunCommandOptions): Promise<CommandResult>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,mBAAmB,CAAC,CAAC;AAEvE,MAAM,MAAM,iBAAiB,GAAG,cAAc,GAAG;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,qBAAa,eAAe;IAExB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBADT,GAAG,EAAE,SAAS,EACd,SAAS,EAAE,MAAM;IAGpC,wFAAwF;IAClF,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,aAAa,CAAC;CAUpF"}
|
package/dist/commands.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { unwrap } from "./internal.js";
|
|
2
|
+
import { requestSignal } from "./request-options.js";
|
|
3
|
+
export class SandboxCommands {
|
|
4
|
+
api;
|
|
5
|
+
sandboxId;
|
|
6
|
+
constructor(api, sandboxId) {
|
|
7
|
+
this.api = api;
|
|
8
|
+
this.sandboxId = sandboxId;
|
|
9
|
+
}
|
|
10
|
+
/** Run a non-interactive command to completion and capture its exit code and output. */
|
|
11
|
+
async run(command, options = {}) {
|
|
12
|
+
const { timeoutSeconds } = options;
|
|
13
|
+
return unwrap(this.api.POST("/sandboxes/{sandboxId}/exec", {
|
|
14
|
+
params: { path: { sandboxId: this.sandboxId } },
|
|
15
|
+
body: { command, timeoutSeconds },
|
|
16
|
+
signal: requestSignal(options),
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare class RemoteHostError extends Error {
|
|
2
|
+
constructor(message: string, options?: ErrorOptions);
|
|
3
|
+
}
|
|
4
|
+
export declare class RemoteHostConfigurationError extends RemoteHostError {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
export declare class RemoteHostConnectionError extends RemoteHostError {
|
|
8
|
+
constructor(message: string, options?: ErrorOptions);
|
|
9
|
+
}
|
|
10
|
+
export declare class RemoteHostTimeoutError extends RemoteHostConnectionError {
|
|
11
|
+
constructor(message?: string, options?: ErrorOptions);
|
|
12
|
+
}
|
|
13
|
+
export declare class RemoteHostAPIError extends RemoteHostError {
|
|
14
|
+
readonly status: number;
|
|
15
|
+
/**
|
|
16
|
+
* Machine-readable reason when the API sets one, for example `rate_limited`,
|
|
17
|
+
* `limit_reached`, `plan_required`, or `snapshot_in_progress`. Null otherwise.
|
|
18
|
+
*/
|
|
19
|
+
readonly code: string | null;
|
|
20
|
+
readonly requestId: string | null;
|
|
21
|
+
readonly headers: Headers;
|
|
22
|
+
readonly body: unknown;
|
|
23
|
+
constructor(response: Response, body: unknown);
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAIpD;AAED,qBAAa,4BAA6B,SAAQ,eAAe;gBACnD,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,yBAA0B,SAAQ,eAAe;gBAChD,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;CAIpD;AAED,qBAAa,sBAAuB,SAAQ,yBAAyB;gBACvD,OAAO,SAA0C,EAAE,OAAO,CAAC,EAAE,YAAY;CAItF;AAED,qBAAa,kBAAmB,SAAQ,eAAe;IACrD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;gBAEX,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO;CAS9C"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export class RemoteHostError extends Error {
|
|
2
|
+
constructor(message, options) {
|
|
3
|
+
super(message, options);
|
|
4
|
+
this.name = "RemoteHostError";
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export class RemoteHostConfigurationError extends RemoteHostError {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "RemoteHostConfigurationError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class RemoteHostConnectionError extends RemoteHostError {
|
|
14
|
+
constructor(message, options) {
|
|
15
|
+
super(message, options);
|
|
16
|
+
this.name = "RemoteHostConnectionError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export class RemoteHostTimeoutError extends RemoteHostConnectionError {
|
|
20
|
+
constructor(message = "The RemoteHost API request timed out.", options) {
|
|
21
|
+
super(message, options);
|
|
22
|
+
this.name = "RemoteHostTimeoutError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export class RemoteHostAPIError extends RemoteHostError {
|
|
26
|
+
status;
|
|
27
|
+
/**
|
|
28
|
+
* Machine-readable reason when the API sets one, for example `rate_limited`,
|
|
29
|
+
* `limit_reached`, `plan_required`, or `snapshot_in_progress`. Null otherwise.
|
|
30
|
+
*/
|
|
31
|
+
code;
|
|
32
|
+
requestId;
|
|
33
|
+
headers;
|
|
34
|
+
body;
|
|
35
|
+
constructor(response, body) {
|
|
36
|
+
super(readErrorMessage(body) ?? `${response.status} ${response.statusText}`.trim());
|
|
37
|
+
this.name = "RemoteHostAPIError";
|
|
38
|
+
this.status = response.status;
|
|
39
|
+
this.code = readErrorCode(body);
|
|
40
|
+
this.requestId = response.headers.get("x-request-id");
|
|
41
|
+
this.headers = response.headers;
|
|
42
|
+
this.body = body;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function readErrorCode(body) {
|
|
46
|
+
if (body &&
|
|
47
|
+
typeof body === "object" &&
|
|
48
|
+
"error" in body &&
|
|
49
|
+
body.error &&
|
|
50
|
+
typeof body.error === "object" &&
|
|
51
|
+
"code" in body.error &&
|
|
52
|
+
typeof body.error.code === "string") {
|
|
53
|
+
return body.error.code;
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
function readErrorMessage(body) {
|
|
58
|
+
if (!body || typeof body !== "object") {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
if ("error" in body) {
|
|
62
|
+
const error = body.error;
|
|
63
|
+
if (typeof error === "string") {
|
|
64
|
+
return error;
|
|
65
|
+
}
|
|
66
|
+
if (error &&
|
|
67
|
+
typeof error === "object" &&
|
|
68
|
+
"message" in error &&
|
|
69
|
+
typeof error.message === "string") {
|
|
70
|
+
return error.message;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if ("message" in body && typeof body.message === "string") {
|
|
74
|
+
return body.message;
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
package/dist/files.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { components } from "./generated/schema.js";
|
|
2
|
+
import type { APIClient } from "./internal.js";
|
|
3
|
+
import type { RequestOptions } from "./request-options.js";
|
|
4
|
+
export type FilesystemEntry = components["schemas"]["FilesystemEntry"];
|
|
5
|
+
export type FileEncoding = "utf8" | "base64";
|
|
6
|
+
export type ListFilesResult = {
|
|
7
|
+
path: string;
|
|
8
|
+
truncated: boolean;
|
|
9
|
+
entries: FilesystemEntry[];
|
|
10
|
+
};
|
|
11
|
+
export type ReadFileResult = {
|
|
12
|
+
path: string;
|
|
13
|
+
content: string;
|
|
14
|
+
encoding: FileEncoding;
|
|
15
|
+
size: number;
|
|
16
|
+
};
|
|
17
|
+
export type WriteFileResult = {
|
|
18
|
+
path: string;
|
|
19
|
+
size: number;
|
|
20
|
+
};
|
|
21
|
+
export declare class SandboxFiles {
|
|
22
|
+
private readonly api;
|
|
23
|
+
private readonly sandboxId;
|
|
24
|
+
constructor(api: APIClient, sandboxId: string);
|
|
25
|
+
/** List direct children of a directory. Relative paths resolve beneath `/code`. */
|
|
26
|
+
list(path?: string, options?: RequestOptions): Promise<ListFilesResult>;
|
|
27
|
+
/** Read a file with its transport encoding preserved. */
|
|
28
|
+
read(path: string, options?: RequestOptions): Promise<ReadFileResult>;
|
|
29
|
+
/** Read a UTF-8 file, decoding a base64 response when necessary. */
|
|
30
|
+
readText(path: string, options?: RequestOptions): Promise<string>;
|
|
31
|
+
/** Read a file as bytes. */
|
|
32
|
+
readBytes(path: string, options?: RequestOptions): Promise<Uint8Array>;
|
|
33
|
+
/** Write UTF-8 text or binary bytes. Individual writes are limited to 2 MiB. */
|
|
34
|
+
write(path: string, content: string | Uint8Array, options?: RequestOptions): Promise<WriteFileResult>;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,iBAAiB,CAAC,CAAC;AACvE,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE7C,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,YAAY,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,qBAAa,YAAY;IAErB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBADT,GAAG,EAAE,SAAS,EACd,SAAS,EAAE,MAAM;IAGpC,mFAAmF;IACnF,IAAI,CAAC,IAAI,SAAU,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,eAAe,CAAC;IAS5E,yDAAyD;IACzD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,cAAc,CAAC;IASzE,oEAAoE;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,MAAM,CAAC;IAO3E,4BAA4B;IACtB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,UAAU,CAAC;IAOhF,gFAAgF;IAChF,KAAK,CACH,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GAAG,UAAU,EAC5B,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,eAAe,CAAC;CAc5B"}
|
package/dist/files.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { unwrap } from "./internal.js";
|
|
2
|
+
import { requestSignal } from "./request-options.js";
|
|
3
|
+
export class SandboxFiles {
|
|
4
|
+
api;
|
|
5
|
+
sandboxId;
|
|
6
|
+
constructor(api, sandboxId) {
|
|
7
|
+
this.api = api;
|
|
8
|
+
this.sandboxId = sandboxId;
|
|
9
|
+
}
|
|
10
|
+
/** List direct children of a directory. Relative paths resolve beneath `/code`. */
|
|
11
|
+
list(path = "/code", options = {}) {
|
|
12
|
+
return unwrap(this.api.GET("/sandboxes/{sandboxId}/files", {
|
|
13
|
+
params: { path: { sandboxId: this.sandboxId }, query: { path } },
|
|
14
|
+
signal: requestSignal(options),
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
/** Read a file with its transport encoding preserved. */
|
|
18
|
+
read(path, options = {}) {
|
|
19
|
+
return unwrap(this.api.GET("/sandboxes/{sandboxId}/file", {
|
|
20
|
+
params: { path: { sandboxId: this.sandboxId }, query: { path } },
|
|
21
|
+
signal: requestSignal(options),
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
/** Read a UTF-8 file, decoding a base64 response when necessary. */
|
|
25
|
+
async readText(path, options = {}) {
|
|
26
|
+
const file = await this.read(path, options);
|
|
27
|
+
return file.encoding === "base64"
|
|
28
|
+
? new TextDecoder().decode(base64ToBytes(file.content))
|
|
29
|
+
: file.content;
|
|
30
|
+
}
|
|
31
|
+
/** Read a file as bytes. */
|
|
32
|
+
async readBytes(path, options = {}) {
|
|
33
|
+
const file = await this.read(path, options);
|
|
34
|
+
return file.encoding === "base64"
|
|
35
|
+
? base64ToBytes(file.content)
|
|
36
|
+
: new TextEncoder().encode(file.content);
|
|
37
|
+
}
|
|
38
|
+
/** Write UTF-8 text or binary bytes. Individual writes are limited to 2 MiB. */
|
|
39
|
+
write(path, content, options = {}) {
|
|
40
|
+
const body = typeof content === "string"
|
|
41
|
+
? { path, content, encoding: "utf8" }
|
|
42
|
+
: { path, content: bytesToBase64(content), encoding: "base64" };
|
|
43
|
+
return unwrap(this.api.PUT("/sandboxes/{sandboxId}/file", {
|
|
44
|
+
params: { path: { sandboxId: this.sandboxId } },
|
|
45
|
+
body,
|
|
46
|
+
signal: requestSignal(options),
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function base64ToBytes(value) {
|
|
51
|
+
const binary = atob(value);
|
|
52
|
+
return Uint8Array.from(binary, (character) => character.charCodeAt(0));
|
|
53
|
+
}
|
|
54
|
+
function bytesToBase64(value) {
|
|
55
|
+
const chunkSize = 0x8000;
|
|
56
|
+
let binary = "";
|
|
57
|
+
for (let offset = 0; offset < value.length; offset += chunkSize) {
|
|
58
|
+
binary += String.fromCharCode(...value.subarray(offset, offset + chunkSize));
|
|
59
|
+
}
|
|
60
|
+
return btoa(binary);
|
|
61
|
+
}
|