@vercel/sandbox 2.0.0-beta.2 → 2.0.0-beta.20
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 +48 -1
- package/dist/_virtual/rolldown_runtime.cjs +29 -0
- package/dist/api-client/api-client.cjs +445 -0
- package/dist/api-client/api-client.cjs.map +1 -0
- package/dist/api-client/api-client.d.cts +6235 -0
- package/dist/api-client/api-client.d.ts +6229 -706
- package/dist/api-client/api-client.js +436 -472
- package/dist/api-client/api-client.js.map +1 -1
- package/dist/api-client/api-error.cjs +32 -0
- package/dist/api-client/api-error.cjs.map +1 -0
- package/dist/api-client/api-error.d.cts +29 -0
- package/dist/api-client/api-error.d.ts +21 -16
- package/dist/api-client/api-error.js +28 -32
- package/dist/api-client/api-error.js.map +1 -1
- package/dist/api-client/base-client.cjs +126 -0
- package/dist/api-client/base-client.cjs.map +1 -0
- package/dist/api-client/base-client.d.cts +38 -0
- package/dist/api-client/base-client.d.ts +31 -36
- package/dist/api-client/base-client.js +114 -118
- package/dist/api-client/base-client.js.map +1 -1
- package/dist/api-client/file-writer.cjs +62 -0
- package/dist/api-client/file-writer.cjs.map +1 -0
- package/dist/api-client/file-writer.d.cts +66 -0
- package/dist/api-client/file-writer.d.ts +56 -42
- package/dist/api-client/file-writer.js +57 -61
- package/dist/api-client/file-writer.js.map +1 -1
- package/dist/api-client/index.cjs +2 -0
- package/dist/api-client/index.d.ts +2 -2
- package/dist/api-client/index.js +4 -21
- package/dist/api-client/validators.cjs +229 -0
- package/dist/api-client/validators.cjs.map +1 -0
- package/dist/api-client/validators.d.cts +26885 -0
- package/dist/api-client/validators.d.ts +26732 -3706
- package/dist/api-client/validators.js +198 -191
- package/dist/api-client/validators.js.map +1 -1
- package/dist/api-client/with-retry.cjs +89 -0
- package/dist/api-client/with-retry.cjs.map +1 -0
- package/dist/api-client/with-retry.d.cts +10 -0
- package/dist/api-client/with-retry.d.ts +9 -13
- package/dist/api-client/with-retry.js +81 -102
- package/dist/api-client/with-retry.js.map +1 -1
- package/dist/auth/api.cjs +29 -0
- package/dist/auth/api.cjs.map +1 -0
- package/dist/auth/api.js +26 -25
- package/dist/auth/api.js.map +1 -1
- package/dist/auth/error.cjs +13 -0
- package/dist/auth/error.cjs.map +1 -0
- package/dist/auth/error.js +11 -11
- package/dist/auth/error.js.map +1 -1
- package/dist/auth/file.cjs +64 -0
- package/dist/auth/file.cjs.map +1 -0
- package/dist/auth/file.d.cts +26 -0
- package/dist/auth/file.d.ts +19 -15
- package/dist/auth/file.js +49 -64
- package/dist/auth/file.js.map +1 -1
- package/dist/auth/index.cjs +11 -0
- package/dist/auth/index.d.cts +5 -0
- package/dist/auth/index.d.ts +5 -6
- package/dist/auth/index.js +6 -27
- package/dist/auth/linked-project.cjs +38 -0
- package/dist/auth/linked-project.cjs.map +1 -0
- package/dist/auth/linked-project.js +30 -64
- package/dist/auth/linked-project.js.map +1 -1
- package/dist/auth/oauth.cjs +205 -0
- package/dist/auth/oauth.cjs.map +1 -0
- package/dist/auth/oauth.d.cts +135 -0
- package/dist/auth/oauth.d.ts +113 -109
- package/dist/auth/oauth.js +185 -252
- package/dist/auth/oauth.js.map +1 -1
- package/dist/auth/poll-for-token.cjs +82 -0
- package/dist/auth/poll-for-token.cjs.map +1 -0
- package/dist/auth/poll-for-token.d.cts +28 -0
- package/dist/auth/poll-for-token.d.ts +23 -15
- package/dist/auth/poll-for-token.js +79 -64
- package/dist/auth/poll-for-token.js.map +1 -1
- package/dist/auth/project.cjs +178 -0
- package/dist/auth/project.cjs.map +1 -0
- package/dist/auth/project.d.cts +40 -0
- package/dist/auth/project.d.ts +19 -19
- package/dist/auth/project.js +169 -72
- package/dist/auth/project.js.map +1 -1
- package/dist/auth/zod.cjs +22 -0
- package/dist/auth/zod.cjs.map +1 -0
- package/dist/auth/zod.js +18 -17
- package/dist/auth/zod.js.map +1 -1
- package/dist/command.cjs +328 -0
- package/dist/command.cjs.map +1 -0
- package/dist/command.d.cts +289 -0
- package/dist/command.d.ts +265 -171
- package/dist/command.js +323 -226
- package/dist/command.js.map +1 -1
- package/dist/constants.d.cts +5 -0
- package/dist/constants.d.ts +5 -1
- package/dist/filesystem.cjs +499 -0
- package/dist/filesystem.cjs.map +1 -0
- package/dist/filesystem.d.cts +258 -0
- package/dist/filesystem.d.ts +258 -0
- package/dist/filesystem.js +497 -0
- package/dist/filesystem.js.map +1 -0
- package/dist/index.cjs +15 -0
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -6
- package/dist/index.js +8 -17
- package/dist/network-policy.d.cts +156 -0
- package/dist/network-policy.d.ts +88 -28
- package/dist/sandbox.cjs +816 -0
- package/dist/sandbox.cjs.map +1 -0
- package/dist/sandbox.d.cts +2847 -0
- package/dist/sandbox.d.ts +2834 -628
- package/dist/sandbox.js +808 -557
- package/dist/sandbox.js.map +1 -1
- package/dist/session.cjs +527 -0
- package/dist/session.cjs.map +1 -0
- package/dist/session.d.cts +410 -0
- package/dist/session.d.ts +403 -368
- package/dist/session.js +524 -489
- package/dist/session.js.map +1 -1
- package/dist/snapshot.cjs +204 -0
- package/dist/snapshot.cjs.map +1 -0
- package/dist/snapshot.d.cts +161 -0
- package/dist/snapshot.d.ts +152 -92
- package/dist/snapshot.js +201 -114
- package/dist/snapshot.js.map +1 -1
- package/dist/utils/array.cjs +17 -0
- package/dist/utils/array.cjs.map +1 -0
- package/dist/utils/array.js +12 -15
- package/dist/utils/array.js.map +1 -1
- package/dist/utils/consume-readable.cjs +18 -0
- package/dist/utils/consume-readable.cjs.map +1 -0
- package/dist/utils/consume-readable.js +13 -12
- package/dist/utils/consume-readable.js.map +1 -1
- package/dist/utils/decode-base64-url.cjs +15 -0
- package/dist/utils/decode-base64-url.cjs.map +1 -0
- package/dist/utils/decode-base64-url.js +10 -9
- package/dist/utils/decode-base64-url.js.map +1 -1
- package/dist/utils/dev-credentials.cjs +142 -0
- package/dist/utils/dev-credentials.cjs.map +1 -0
- package/dist/utils/dev-credentials.js +126 -184
- package/dist/utils/dev-credentials.js.map +1 -1
- package/dist/utils/get-credentials.cjs +123 -0
- package/dist/utils/get-credentials.cjs.map +1 -0
- package/dist/utils/get-credentials.d.cts +21 -0
- package/dist/utils/get-credentials.d.ts +19 -61
- package/dist/utils/get-credentials.js +106 -140
- package/dist/utils/get-credentials.js.map +1 -1
- package/dist/utils/log.cjs +25 -0
- package/dist/utils/log.cjs.map +1 -0
- package/dist/utils/log.js +15 -17
- package/dist/utils/log.js.map +1 -1
- package/dist/utils/network-policy.cjs +49 -0
- package/dist/utils/network-policy.cjs.map +1 -0
- package/dist/utils/network-policy.js +42 -77
- package/dist/utils/network-policy.js.map +1 -1
- package/dist/utils/normalizePath.cjs +27 -0
- package/dist/utils/normalizePath.cjs.map +1 -0
- package/dist/utils/normalizePath.js +21 -28
- package/dist/utils/normalizePath.js.map +1 -1
- package/dist/utils/paginator.cjs +41 -0
- package/dist/utils/paginator.cjs.map +1 -0
- package/dist/utils/paginator.d.cts +16 -0
- package/dist/utils/paginator.d.ts +16 -0
- package/dist/utils/paginator.js +40 -0
- package/dist/utils/paginator.js.map +1 -0
- package/dist/utils/resolveSignal.cjs +20 -0
- package/dist/utils/resolveSignal.cjs.map +1 -0
- package/dist/utils/resolveSignal.d.cts +15 -0
- package/dist/utils/resolveSignal.d.ts +12 -10
- package/dist/utils/resolveSignal.js +14 -17
- package/dist/utils/resolveSignal.js.map +1 -1
- package/dist/utils/sandbox-snapshot.cjs +14 -0
- package/dist/utils/sandbox-snapshot.cjs.map +1 -0
- package/dist/utils/sandbox-snapshot.d.cts +10 -0
- package/dist/utils/sandbox-snapshot.d.ts +11 -0
- package/dist/utils/sandbox-snapshot.js +14 -0
- package/dist/utils/sandbox-snapshot.js.map +1 -0
- package/dist/utils/types.cjs +13 -0
- package/dist/utils/types.cjs.map +1 -0
- package/dist/utils/types.d.cts +11 -0
- package/dist/utils/types.d.ts +5 -7
- package/dist/utils/types.js +8 -8
- package/dist/utils/types.js.map +1 -1
- package/dist/version.cjs +7 -0
- package/dist/version.cjs.map +1 -0
- package/dist/version.js +5 -5
- package/dist/version.js.map +1 -1
- package/package.json +23 -3
- package/dist/api-client/index.js.map +0 -1
- package/dist/auth/api.d.ts +0 -6
- package/dist/auth/error.d.ts +0 -11
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/linked-project.d.ts +0 -10
- package/dist/auth/zod.d.ts +0 -5
- package/dist/constants.js +0 -3
- package/dist/constants.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/network-policy.js +0 -3
- package/dist/network-policy.js.map +0 -1
- package/dist/utils/array.d.ts +0 -9
- package/dist/utils/consume-readable.d.ts +0 -5
- package/dist/utils/convert-sandbox.d.ts +0 -6
- package/dist/utils/convert-sandbox.js +0 -14
- package/dist/utils/convert-sandbox.js.map +0 -1
- package/dist/utils/decode-base64-url.d.ts +0 -7
- package/dist/utils/dev-credentials.d.ts +0 -37
- package/dist/utils/log.d.ts +0 -2
- package/dist/utils/network-policy.d.ts +0 -7
- package/dist/utils/normalizePath.d.ts +0 -17
- package/dist/version.d.ts +0 -1
|
@@ -1,478 +1,442 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const normalizePath_1 = require("../utils/normalizePath");
|
|
18
|
-
const oidc_1 = require("@vercel/oidc");
|
|
19
|
-
const network_policy_1 = require("../utils/network-policy");
|
|
20
|
-
const types_1 = require("../utils/types");
|
|
21
|
-
const promises_1 = require("node:timers/promises");
|
|
1
|
+
import { APIError, StreamError } from "./api-error.js";
|
|
2
|
+
import { BaseClient, parseOrThrow } from "./base-client.js";
|
|
3
|
+
import { CommandFinishedResponse, CommandResponse, CreateSnapshotResponse, EmptyResponse, LogLine, SandboxAndSessionResponse, SandboxesPaginationResponse, SessionAndRoutesResponse, SessionResponse, SessionsResponse, SnapshotResponse, SnapshotsResponse, StopSessionResponse, UpdateSandboxResponse } from "./validators.js";
|
|
4
|
+
import { FileWriter } from "./file-writer.js";
|
|
5
|
+
import { VERSION } from "../version.js";
|
|
6
|
+
import { consumeReadable } from "../utils/consume-readable.js";
|
|
7
|
+
import { normalizePath } from "../utils/normalizePath.js";
|
|
8
|
+
import { toAPINetworkPolicy } from "../utils/network-policy.js";
|
|
9
|
+
import { getPrivateParams } from "../utils/types.js";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { Readable } from "stream";
|
|
12
|
+
import jsonlines from "jsonlines";
|
|
13
|
+
import os from "os";
|
|
14
|
+
import { getVercelOidcToken } from "@vercel/oidc";
|
|
15
|
+
|
|
16
|
+
//#region src/api-client/api-client.ts
|
|
22
17
|
function decodeUnverifiedToken(token) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
class APIClient extends base_client_1.BaseClient {
|
|
38
|
-
constructor(params) {
|
|
39
|
-
super({
|
|
40
|
-
baseUrl: params.baseUrl ?? "https://vercel.com/api",
|
|
41
|
-
token: params.token,
|
|
42
|
-
debug: false,
|
|
43
|
-
fetch: params.fetch,
|
|
44
|
-
});
|
|
45
|
-
this.teamId = params.teamId;
|
|
46
|
-
this.isJwtToken = false;
|
|
47
|
-
const claims = decodeUnverifiedToken(params.token);
|
|
48
|
-
if (claims) {
|
|
49
|
-
this.isJwtToken = true;
|
|
50
|
-
this.projectId = claims.project_id;
|
|
51
|
-
this.teamId = claims.owner_id;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
async ensureValidToken() {
|
|
55
|
-
if (!this.isJwtToken) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
try {
|
|
59
|
-
// Use getVercelOidcToken to refresh the token with team/project scope
|
|
60
|
-
const freshToken = await (0, oidc_1.getVercelOidcToken)({
|
|
61
|
-
expirationBufferMs: 5 * 60 * 1000, // 5 minutes
|
|
62
|
-
team: this.teamId,
|
|
63
|
-
project: this.projectId,
|
|
64
|
-
});
|
|
65
|
-
// Update token if it changed
|
|
66
|
-
if (freshToken !== this.token) {
|
|
67
|
-
this.token = freshToken;
|
|
68
|
-
const claims = decodeUnverifiedToken(freshToken);
|
|
69
|
-
if (claims) {
|
|
70
|
-
this.teamId = claims.owner_id;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
catch {
|
|
75
|
-
// Ignore refresh errors and continue with current token
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
async request(path, params) {
|
|
79
|
-
await this.ensureValidToken();
|
|
80
|
-
return super.request(path, {
|
|
81
|
-
...params,
|
|
82
|
-
query: { teamId: this.teamId, ...params?.query },
|
|
83
|
-
headers: {
|
|
84
|
-
"content-type": "application/json",
|
|
85
|
-
"user-agent": `vercel/sandbox/${version_1.VERSION} (Node.js/${process.version}; ${os_1.default.platform()}/${os_1.default.arch()})`,
|
|
86
|
-
...params?.headers,
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
async getSandbox(params) {
|
|
91
|
-
const privateParams = (0, types_1.getPrivateParams)(params);
|
|
92
|
-
let querystring = new URLSearchParams(privateParams).toString();
|
|
93
|
-
querystring = querystring ? `?${querystring}` : "";
|
|
94
|
-
return (0, base_client_1.parseOrThrow)(validators_1.SandboxAndRoutesResponse, await this.request(`/v1/sandboxes/${params.sandboxId}${querystring}`, {
|
|
95
|
-
signal: params.signal,
|
|
96
|
-
}));
|
|
97
|
-
}
|
|
98
|
-
async createSandbox(params) {
|
|
99
|
-
const privateParams = (0, types_1.getPrivateParams)(params);
|
|
100
|
-
return (0, base_client_1.parseOrThrow)(validators_1.NamedSandboxAndSessionResponse, await this.request("/v1/sandboxes/named", {
|
|
101
|
-
method: "POST",
|
|
102
|
-
body: JSON.stringify({
|
|
103
|
-
projectId: params.projectId,
|
|
104
|
-
ports: params.ports,
|
|
105
|
-
source: params.source,
|
|
106
|
-
timeout: params.timeout,
|
|
107
|
-
resources: params.resources,
|
|
108
|
-
runtime: params.runtime,
|
|
109
|
-
name: params.name,
|
|
110
|
-
persistent: params.persistent,
|
|
111
|
-
networkPolicy: params.networkPolicy
|
|
112
|
-
? (0, network_policy_1.toAPINetworkPolicy)(params.networkPolicy)
|
|
113
|
-
: undefined,
|
|
114
|
-
env: params.env,
|
|
115
|
-
...privateParams,
|
|
116
|
-
}),
|
|
117
|
-
signal: params.signal,
|
|
118
|
-
}));
|
|
119
|
-
}
|
|
120
|
-
async runCommand(params) {
|
|
121
|
-
if (params.wait) {
|
|
122
|
-
const response = await this.request(`/v1/sandboxes/${params.sandboxId}/cmd`, {
|
|
123
|
-
method: "POST",
|
|
124
|
-
body: JSON.stringify({
|
|
125
|
-
command: params.command,
|
|
126
|
-
args: params.args,
|
|
127
|
-
cwd: params.cwd,
|
|
128
|
-
env: params.env,
|
|
129
|
-
sudo: params.sudo,
|
|
130
|
-
wait: true,
|
|
131
|
-
}),
|
|
132
|
-
signal: params.signal,
|
|
133
|
-
});
|
|
134
|
-
if (!response.ok) {
|
|
135
|
-
await (0, base_client_1.parseOrThrow)(zod_1.z.any(), response);
|
|
136
|
-
}
|
|
137
|
-
if (response.headers.get("content-type") !== "application/x-ndjson") {
|
|
138
|
-
throw new api_error_1.APIError(response, {
|
|
139
|
-
message: "Expected a stream of command data",
|
|
140
|
-
sandboxId: params.sandboxId,
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
if (response.body === null) {
|
|
144
|
-
throw new api_error_1.APIError(response, {
|
|
145
|
-
message: "No response body",
|
|
146
|
-
sandboxId: params.sandboxId,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
const jsonlinesStream = jsonlines_1.default.parse();
|
|
150
|
-
pipe(response.body, jsonlinesStream).catch((err) => {
|
|
151
|
-
console.error("Error piping command stream:", err);
|
|
152
|
-
});
|
|
153
|
-
const iterator = jsonlinesStream[Symbol.asyncIterator]();
|
|
154
|
-
const commandChunk = await iterator.next();
|
|
155
|
-
const { command } = validators_1.CommandResponse.parse(commandChunk.value);
|
|
156
|
-
const finished = (async () => {
|
|
157
|
-
const finishedChunk = await iterator.next();
|
|
158
|
-
const { command } = validators_1.CommandFinishedResponse.parse(finishedChunk.value);
|
|
159
|
-
return command;
|
|
160
|
-
})();
|
|
161
|
-
return { command, finished };
|
|
162
|
-
}
|
|
163
|
-
return (0, base_client_1.parseOrThrow)(validators_1.CommandResponse, await this.request(`/v1/sandboxes/${params.sandboxId}/cmd`, {
|
|
164
|
-
method: "POST",
|
|
165
|
-
body: JSON.stringify({
|
|
166
|
-
command: params.command,
|
|
167
|
-
args: params.args,
|
|
168
|
-
cwd: params.cwd,
|
|
169
|
-
env: params.env,
|
|
170
|
-
sudo: params.sudo,
|
|
171
|
-
}),
|
|
172
|
-
signal: params.signal,
|
|
173
|
-
}));
|
|
174
|
-
}
|
|
175
|
-
async getCommand(params) {
|
|
176
|
-
return params.wait
|
|
177
|
-
? (0, base_client_1.parseOrThrow)(validators_1.CommandFinishedResponse, await this.request(`/v1/sandboxes/${params.sandboxId}/cmd/${params.cmdId}`, { signal: params.signal, query: { wait: "true" } }))
|
|
178
|
-
: (0, base_client_1.parseOrThrow)(validators_1.CommandResponse, await this.request(`/v1/sandboxes/${params.sandboxId}/cmd/${params.cmdId}`, { signal: params.signal }));
|
|
179
|
-
}
|
|
180
|
-
async mkDir(params) {
|
|
181
|
-
return (0, base_client_1.parseOrThrow)(validators_1.EmptyResponse, await this.request(`/v1/sandboxes/${params.sandboxId}/fs/mkdir`, {
|
|
182
|
-
method: "POST",
|
|
183
|
-
body: JSON.stringify({ path: params.path, cwd: params.cwd }),
|
|
184
|
-
signal: params.signal,
|
|
185
|
-
}));
|
|
186
|
-
}
|
|
187
|
-
getFileWriter(params) {
|
|
188
|
-
const writer = new file_writer_1.FileWriter();
|
|
189
|
-
return {
|
|
190
|
-
response: (async () => {
|
|
191
|
-
return this.request(`/v1/sandboxes/${params.sandboxId}/fs/write`, {
|
|
192
|
-
method: "POST",
|
|
193
|
-
headers: {
|
|
194
|
-
"content-type": "application/gzip",
|
|
195
|
-
"x-cwd": params.extractDir,
|
|
196
|
-
},
|
|
197
|
-
body: await (0, consume_readable_1.consumeReadable)(writer.readable),
|
|
198
|
-
signal: params.signal,
|
|
199
|
-
});
|
|
200
|
-
})(),
|
|
201
|
-
writer,
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
async listSandboxes(params) {
|
|
205
|
-
return (0, base_client_1.parseOrThrow)(validators_1.SandboxesResponse, await this.request(`/v1/sandboxes`, {
|
|
206
|
-
query: {
|
|
207
|
-
project: params.projectId,
|
|
208
|
-
name: params.name,
|
|
209
|
-
limit: params.limit,
|
|
210
|
-
since: typeof params.since === "number"
|
|
211
|
-
? params.since
|
|
212
|
-
: params.since?.getTime(),
|
|
213
|
-
until: typeof params.until === "number"
|
|
214
|
-
? params.until
|
|
215
|
-
: params.until?.getTime(),
|
|
216
|
-
},
|
|
217
|
-
method: "GET",
|
|
218
|
-
signal: params.signal,
|
|
219
|
-
}));
|
|
220
|
-
}
|
|
221
|
-
async listSnapshots(params) {
|
|
222
|
-
return (0, base_client_1.parseOrThrow)(validators_1.SnapshotsResponse, await this.request(`/v1/sandboxes/snapshots`, {
|
|
223
|
-
query: {
|
|
224
|
-
project: params.projectId,
|
|
225
|
-
name: params.name,
|
|
226
|
-
limit: params.limit,
|
|
227
|
-
since: typeof params.since === "number"
|
|
228
|
-
? params.since
|
|
229
|
-
: params.since?.getTime(),
|
|
230
|
-
until: typeof params.until === "number"
|
|
231
|
-
? params.until
|
|
232
|
-
: params.until?.getTime(),
|
|
233
|
-
},
|
|
234
|
-
method: "GET",
|
|
235
|
-
signal: params.signal,
|
|
236
|
-
}));
|
|
237
|
-
}
|
|
238
|
-
async writeFiles(params) {
|
|
239
|
-
const { writer, response } = this.getFileWriter({
|
|
240
|
-
sandboxId: params.sandboxId,
|
|
241
|
-
extractDir: params.extractDir,
|
|
242
|
-
signal: params.signal,
|
|
243
|
-
});
|
|
244
|
-
for (const file of params.files) {
|
|
245
|
-
await writer.addFile({
|
|
246
|
-
name: (0, normalizePath_1.normalizePath)({
|
|
247
|
-
filePath: file.path,
|
|
248
|
-
extractDir: params.extractDir,
|
|
249
|
-
cwd: params.cwd,
|
|
250
|
-
}),
|
|
251
|
-
content: file.content,
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
writer.end();
|
|
255
|
-
await (0, base_client_1.parseOrThrow)(validators_1.EmptyResponse, await response);
|
|
256
|
-
}
|
|
257
|
-
async readFile(params) {
|
|
258
|
-
const response = await this.request(`/v1/sandboxes/${params.sandboxId}/fs/read`, {
|
|
259
|
-
method: "POST",
|
|
260
|
-
body: JSON.stringify({ path: params.path, cwd: params.cwd }),
|
|
261
|
-
signal: params.signal,
|
|
262
|
-
});
|
|
263
|
-
if (response.status === 404) {
|
|
264
|
-
return null;
|
|
265
|
-
}
|
|
266
|
-
if (response.body === null) {
|
|
267
|
-
return null;
|
|
268
|
-
}
|
|
269
|
-
return stream_1.Readable.fromWeb(response.body);
|
|
270
|
-
}
|
|
271
|
-
async killCommand(params) {
|
|
272
|
-
return (0, base_client_1.parseOrThrow)(validators_1.CommandResponse, await this.request(`/v1/sandboxes/${params.sandboxId}/${params.commandId}/kill`, {
|
|
273
|
-
method: "POST",
|
|
274
|
-
body: JSON.stringify({ signal: params.signal }),
|
|
275
|
-
signal: params.abortSignal,
|
|
276
|
-
}));
|
|
277
|
-
}
|
|
278
|
-
getLogs(params) {
|
|
279
|
-
const self = this;
|
|
280
|
-
const disposer = new AbortController();
|
|
281
|
-
const signal = !params.signal
|
|
282
|
-
? disposer.signal
|
|
283
|
-
: mergeSignals(params.signal, disposer.signal);
|
|
284
|
-
const generator = (async function* () {
|
|
285
|
-
const url = `/v1/sandboxes/${params.sandboxId}/cmd/${params.cmdId}/logs`;
|
|
286
|
-
const response = await self.request(url, {
|
|
287
|
-
method: "GET",
|
|
288
|
-
signal,
|
|
289
|
-
});
|
|
290
|
-
if (!response.ok) {
|
|
291
|
-
await (0, base_client_1.parseOrThrow)(zod_1.z.any(), response);
|
|
292
|
-
}
|
|
293
|
-
if (response.headers.get("content-type") !== "application/x-ndjson") {
|
|
294
|
-
throw new api_error_1.APIError(response, {
|
|
295
|
-
message: "Expected a stream of logs",
|
|
296
|
-
sandboxId: params.sandboxId,
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
if (response.body === null) {
|
|
300
|
-
throw new api_error_1.APIError(response, {
|
|
301
|
-
message: "No response body",
|
|
302
|
-
sandboxId: params.sandboxId,
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
const jsonlinesStream = jsonlines_1.default.parse();
|
|
306
|
-
pipe(response.body, jsonlinesStream).catch((err) => {
|
|
307
|
-
console.error("Error piping logs:", err);
|
|
308
|
-
});
|
|
309
|
-
for await (const chunk of jsonlinesStream) {
|
|
310
|
-
const parsed = validators_1.LogLine.parse(chunk);
|
|
311
|
-
if (parsed.stream === "error") {
|
|
312
|
-
throw new api_error_1.StreamError(parsed.data.code, parsed.data.message, params.sandboxId);
|
|
313
|
-
}
|
|
314
|
-
yield parsed;
|
|
315
|
-
}
|
|
316
|
-
})();
|
|
317
|
-
return Object.assign(generator, {
|
|
318
|
-
[Symbol.dispose]() {
|
|
319
|
-
disposer.abort("Disposed");
|
|
320
|
-
},
|
|
321
|
-
close: () => disposer.abort("Disposed"),
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
|
-
async stopSandbox(params) {
|
|
325
|
-
const url = `/v1/sandboxes/${params.sandboxId}/stop`;
|
|
326
|
-
const response = await (0, base_client_1.parseOrThrow)(validators_1.SandboxResponse, await this.request(url, { method: "POST", signal: params.signal }));
|
|
327
|
-
if (params.blocking) {
|
|
328
|
-
let sandbox = response.json.sandbox;
|
|
329
|
-
while (sandbox.status !== "stopped" && sandbox.status !== "failed" && sandbox.status !== "aborted") {
|
|
330
|
-
await (0, promises_1.setTimeout)(500, undefined, { signal: params.signal });
|
|
331
|
-
const poll = await this.getSandbox({
|
|
332
|
-
sandboxId: params.sandboxId,
|
|
333
|
-
signal: params.signal,
|
|
334
|
-
});
|
|
335
|
-
sandbox = poll.json.sandbox;
|
|
336
|
-
response.json.sandbox = sandbox;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
return response;
|
|
340
|
-
}
|
|
341
|
-
async updateNetworkPolicy(params) {
|
|
342
|
-
const url = `/v1/sandboxes/${params.sandboxId}/network-policy`;
|
|
343
|
-
return (0, base_client_1.parseOrThrow)(validators_1.UpdateNetworkPolicyResponse, await this.request(url, {
|
|
344
|
-
method: "POST",
|
|
345
|
-
body: JSON.stringify((0, network_policy_1.toAPINetworkPolicy)(params.networkPolicy)),
|
|
346
|
-
signal: params.signal,
|
|
347
|
-
}));
|
|
348
|
-
}
|
|
349
|
-
async extendTimeout(params) {
|
|
350
|
-
const url = `/v1/sandboxes/${params.sandboxId}/extend-timeout`;
|
|
351
|
-
return (0, base_client_1.parseOrThrow)(validators_1.ExtendTimeoutResponse, await this.request(url, {
|
|
352
|
-
method: "POST",
|
|
353
|
-
body: JSON.stringify({ duration: params.duration }),
|
|
354
|
-
signal: params.signal,
|
|
355
|
-
}));
|
|
356
|
-
}
|
|
357
|
-
async createSnapshot(params) {
|
|
358
|
-
const url = `/v1/sandboxes/${params.sandboxId}/snapshot`;
|
|
359
|
-
const body = params.expiration === undefined
|
|
360
|
-
? undefined
|
|
361
|
-
: JSON.stringify({ expiration: params.expiration });
|
|
362
|
-
return (0, base_client_1.parseOrThrow)(validators_1.CreateSnapshotResponse, await this.request(url, {
|
|
363
|
-
method: "POST",
|
|
364
|
-
body,
|
|
365
|
-
signal: params.signal,
|
|
366
|
-
}));
|
|
367
|
-
}
|
|
368
|
-
async deleteSnapshot(params) {
|
|
369
|
-
const url = `/v1/sandboxes/snapshots/${params.snapshotId}`;
|
|
370
|
-
return (0, base_client_1.parseOrThrow)(validators_1.SnapshotResponse, await this.request(url, { method: "DELETE", signal: params.signal }));
|
|
371
|
-
}
|
|
372
|
-
async getSnapshot(params) {
|
|
373
|
-
const url = `/v1/sandboxes/snapshots/${params.snapshotId}`;
|
|
374
|
-
return (0, base_client_1.parseOrThrow)(validators_1.SnapshotResponse, await this.request(url, { signal: params.signal }));
|
|
375
|
-
}
|
|
376
|
-
async getNamedSandbox(params) {
|
|
377
|
-
const query = {
|
|
378
|
-
projectId: params.projectId,
|
|
379
|
-
};
|
|
380
|
-
if (params.resume !== undefined) {
|
|
381
|
-
query.resume = String(params.resume);
|
|
382
|
-
}
|
|
383
|
-
return (0, base_client_1.parseOrThrow)(validators_1.NamedSandboxAndSessionResponse, await this.request(`/v1/sandboxes/named/${encodeURIComponent(params.name)}`, {
|
|
384
|
-
query,
|
|
385
|
-
signal: params.signal,
|
|
386
|
-
}));
|
|
387
|
-
}
|
|
388
|
-
async listNamedSandboxes(params) {
|
|
389
|
-
const result = await (0, base_client_1.parseOrThrow)(validators_1.NamedSandboxesPaginationResponse, await this.request(`/v1/sandboxes/named`, {
|
|
390
|
-
query: {
|
|
391
|
-
project: params.projectId,
|
|
392
|
-
limit: params.limit,
|
|
393
|
-
sortBy: params.sortBy,
|
|
394
|
-
namePrefix: params.namePrefix,
|
|
395
|
-
cursor: params.cursor,
|
|
396
|
-
},
|
|
397
|
-
method: "GET",
|
|
398
|
-
signal: params.signal,
|
|
399
|
-
}));
|
|
400
|
-
return {
|
|
401
|
-
...result,
|
|
402
|
-
json: {
|
|
403
|
-
sandboxes: result.json.namedSandboxes,
|
|
404
|
-
pagination: result.json.pagination,
|
|
405
|
-
},
|
|
406
|
-
};
|
|
407
|
-
}
|
|
408
|
-
async updateNamedSandbox(params) {
|
|
409
|
-
return (0, base_client_1.parseOrThrow)(validators_1.UpdateNamedSandboxResponse, await this.request(`/v1/sandboxes/named/${encodeURIComponent(params.name)}`, {
|
|
410
|
-
method: "PATCH",
|
|
411
|
-
query: {
|
|
412
|
-
projectId: params.projectId,
|
|
413
|
-
},
|
|
414
|
-
body: JSON.stringify({
|
|
415
|
-
persistent: params.persistent,
|
|
416
|
-
resources: params.resources,
|
|
417
|
-
runtime: params.runtime,
|
|
418
|
-
timeout: params.timeout,
|
|
419
|
-
networkPolicy: params.networkPolicy
|
|
420
|
-
? (0, network_policy_1.toAPINetworkPolicy)(params.networkPolicy)
|
|
421
|
-
: undefined,
|
|
422
|
-
}),
|
|
423
|
-
signal: params.signal,
|
|
424
|
-
}));
|
|
425
|
-
}
|
|
426
|
-
async deleteNamedSandbox(params) {
|
|
427
|
-
return (0, base_client_1.parseOrThrow)(validators_1.UpdateNamedSandboxResponse, await this.request(`/v1/sandboxes/named/${encodeURIComponent(params.name)}`, {
|
|
428
|
-
method: "DELETE",
|
|
429
|
-
query: {
|
|
430
|
-
projectId: params.projectId,
|
|
431
|
-
preserveSandboxes: "false",
|
|
432
|
-
preserveSnapshots: params.preserveSnapshots !== undefined
|
|
433
|
-
? String(params.preserveSnapshots)
|
|
434
|
-
: undefined,
|
|
435
|
-
},
|
|
436
|
-
signal: params.signal,
|
|
437
|
-
}));
|
|
438
|
-
}
|
|
18
|
+
if (token.split(".").length !== 3) return null;
|
|
19
|
+
try {
|
|
20
|
+
const payload = JSON.parse(Buffer.from(token.split(".")[1], "base64url").toString("utf8"));
|
|
21
|
+
if (payload.owner_id) return {
|
|
22
|
+
owner_id: payload.owner_id,
|
|
23
|
+
project_id: payload.project_id
|
|
24
|
+
};
|
|
25
|
+
return null;
|
|
26
|
+
} catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
439
29
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
30
|
+
var APIClient = class extends BaseClient {
|
|
31
|
+
constructor(params) {
|
|
32
|
+
super({
|
|
33
|
+
baseUrl: params.baseUrl ?? "https://vercel.com/api",
|
|
34
|
+
token: params.token,
|
|
35
|
+
debug: false,
|
|
36
|
+
fetch: params.fetch
|
|
37
|
+
});
|
|
38
|
+
this.teamId = params.teamId;
|
|
39
|
+
this.isJwtToken = false;
|
|
40
|
+
const claims = decodeUnverifiedToken(params.token);
|
|
41
|
+
if (claims) {
|
|
42
|
+
this.isJwtToken = true;
|
|
43
|
+
this.projectId = claims.project_id;
|
|
44
|
+
this.teamId = claims.owner_id;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async ensureValidToken() {
|
|
48
|
+
if (!this.isJwtToken) return;
|
|
49
|
+
try {
|
|
50
|
+
const freshToken = await getVercelOidcToken({
|
|
51
|
+
expirationBufferMs: 300 * 1e3,
|
|
52
|
+
team: this.teamId,
|
|
53
|
+
project: this.projectId
|
|
54
|
+
});
|
|
55
|
+
if (freshToken !== this.token) {
|
|
56
|
+
this.token = freshToken;
|
|
57
|
+
const claims = decodeUnverifiedToken(freshToken);
|
|
58
|
+
if (claims) this.teamId = claims.owner_id;
|
|
59
|
+
}
|
|
60
|
+
} catch {}
|
|
61
|
+
}
|
|
62
|
+
async request(path, params) {
|
|
63
|
+
await this.ensureValidToken();
|
|
64
|
+
return super.request(path, {
|
|
65
|
+
...params,
|
|
66
|
+
query: {
|
|
67
|
+
teamId: this.teamId,
|
|
68
|
+
...params?.query
|
|
69
|
+
},
|
|
70
|
+
headers: {
|
|
71
|
+
"content-type": "application/json",
|
|
72
|
+
"user-agent": `vercel/sandbox/${VERSION} (Node.js/${process.version}; ${os.platform()}/${os.arch()})`,
|
|
73
|
+
...params?.headers
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
async getSession(params) {
|
|
78
|
+
const privateParams = getPrivateParams(params);
|
|
79
|
+
let querystring = new URLSearchParams(privateParams).toString();
|
|
80
|
+
querystring = querystring ? `?${querystring}` : "";
|
|
81
|
+
return parseOrThrow(SessionAndRoutesResponse, await this.request(`/v2/sandboxes/sessions/${params.sessionId}${querystring}`, { signal: params.signal }));
|
|
82
|
+
}
|
|
83
|
+
async createSandbox(params) {
|
|
84
|
+
const privateParams = getPrivateParams(params);
|
|
85
|
+
return parseOrThrow(SandboxAndSessionResponse, await this.request("/v2/sandboxes", {
|
|
86
|
+
method: "POST",
|
|
87
|
+
body: JSON.stringify({
|
|
88
|
+
projectId: params.projectId,
|
|
89
|
+
ports: params.ports,
|
|
90
|
+
source: params.source,
|
|
91
|
+
timeout: params.timeout,
|
|
92
|
+
resources: params.resources,
|
|
93
|
+
runtime: params.runtime,
|
|
94
|
+
name: params.name,
|
|
95
|
+
persistent: params.persistent,
|
|
96
|
+
networkPolicy: params.networkPolicy ? toAPINetworkPolicy(params.networkPolicy) : void 0,
|
|
97
|
+
env: params.env,
|
|
98
|
+
tags: params.tags,
|
|
99
|
+
snapshotExpiration: params.snapshotExpiration,
|
|
100
|
+
...privateParams
|
|
101
|
+
}),
|
|
102
|
+
signal: params.signal
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
async runCommand(params) {
|
|
106
|
+
if (params.wait) {
|
|
107
|
+
const response = await this.request(`/v2/sandboxes/sessions/${params.sessionId}/cmd`, {
|
|
108
|
+
method: "POST",
|
|
109
|
+
body: JSON.stringify({
|
|
110
|
+
command: params.command,
|
|
111
|
+
args: params.args,
|
|
112
|
+
cwd: params.cwd,
|
|
113
|
+
env: params.env,
|
|
114
|
+
sudo: params.sudo,
|
|
115
|
+
wait: true
|
|
116
|
+
}),
|
|
117
|
+
signal: params.signal
|
|
118
|
+
});
|
|
119
|
+
if (!response.ok) await parseOrThrow(z.any(), response);
|
|
120
|
+
if (response.headers.get("content-type") !== "application/x-ndjson") throw new APIError(response, {
|
|
121
|
+
message: "Expected a stream of command data",
|
|
122
|
+
sessionId: params.sessionId
|
|
123
|
+
});
|
|
124
|
+
if (response.body === null) throw new APIError(response, {
|
|
125
|
+
message: "No response body",
|
|
126
|
+
sessionId: params.sessionId
|
|
127
|
+
});
|
|
128
|
+
const jsonlinesStream = jsonlines.parse();
|
|
129
|
+
pipe(response.body, jsonlinesStream, { signal: params.signal }).catch((err) => {
|
|
130
|
+
console.error("Error piping command stream:", err);
|
|
131
|
+
});
|
|
132
|
+
const iterator = jsonlinesStream[Symbol.asyncIterator]();
|
|
133
|
+
const commandChunk = await iterator.next();
|
|
134
|
+
if (commandChunk.done) throw new StreamError("stream_ended_early", "Stream ended before command data was received", params.sessionId);
|
|
135
|
+
const { command } = CommandResponse.parse(commandChunk.value);
|
|
136
|
+
return {
|
|
137
|
+
command,
|
|
138
|
+
finished: (async () => {
|
|
139
|
+
const finishedChunk = await iterator.next();
|
|
140
|
+
if (finishedChunk.done) throw new StreamError("stream_ended_early", "Stream ended before command finished", params.sessionId);
|
|
141
|
+
const { command: command$1 } = CommandFinishedResponse.parse(finishedChunk.value);
|
|
142
|
+
return command$1;
|
|
143
|
+
})()
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return parseOrThrow(CommandResponse, await this.request(`/v2/sandboxes/sessions/${params.sessionId}/cmd`, {
|
|
147
|
+
method: "POST",
|
|
148
|
+
body: JSON.stringify({
|
|
149
|
+
command: params.command,
|
|
150
|
+
args: params.args,
|
|
151
|
+
cwd: params.cwd,
|
|
152
|
+
env: params.env,
|
|
153
|
+
sudo: params.sudo
|
|
154
|
+
}),
|
|
155
|
+
signal: params.signal
|
|
156
|
+
}));
|
|
157
|
+
}
|
|
158
|
+
async getCommand(params) {
|
|
159
|
+
return params.wait ? parseOrThrow(CommandFinishedResponse, await this.request(`/v2/sandboxes/sessions/${params.sessionId}/cmd/${params.cmdId}`, {
|
|
160
|
+
signal: params.signal,
|
|
161
|
+
query: { wait: "true" }
|
|
162
|
+
})) : parseOrThrow(CommandResponse, await this.request(`/v2/sandboxes/sessions/${params.sessionId}/cmd/${params.cmdId}`, { signal: params.signal }));
|
|
163
|
+
}
|
|
164
|
+
async mkDir(params) {
|
|
165
|
+
return parseOrThrow(EmptyResponse, await this.request(`/v2/sandboxes/sessions/${params.sessionId}/fs/mkdir`, {
|
|
166
|
+
method: "POST",
|
|
167
|
+
body: JSON.stringify({
|
|
168
|
+
path: params.path,
|
|
169
|
+
cwd: params.cwd
|
|
170
|
+
}),
|
|
171
|
+
signal: params.signal
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
174
|
+
getFileWriter(params) {
|
|
175
|
+
const writer = new FileWriter();
|
|
176
|
+
return {
|
|
177
|
+
response: (async () => {
|
|
178
|
+
return this.request(`/v2/sandboxes/sessions/${params.sessionId}/fs/write`, {
|
|
179
|
+
method: "POST",
|
|
180
|
+
headers: {
|
|
181
|
+
"content-type": "application/gzip",
|
|
182
|
+
"x-cwd": params.extractDir
|
|
183
|
+
},
|
|
184
|
+
body: await consumeReadable(writer.readable),
|
|
185
|
+
signal: params.signal
|
|
186
|
+
});
|
|
187
|
+
})(),
|
|
188
|
+
writer
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
async listSessions(params) {
|
|
192
|
+
return parseOrThrow(SessionsResponse, await this.request(`/v2/sandboxes/sessions`, {
|
|
193
|
+
query: {
|
|
194
|
+
project: params.projectId,
|
|
195
|
+
name: params.name,
|
|
196
|
+
limit: params.limit,
|
|
197
|
+
cursor: params.cursor,
|
|
198
|
+
sortOrder: params.sortOrder
|
|
199
|
+
},
|
|
200
|
+
method: "GET",
|
|
201
|
+
signal: params.signal
|
|
202
|
+
}));
|
|
203
|
+
}
|
|
204
|
+
async listSnapshots(params) {
|
|
205
|
+
return parseOrThrow(SnapshotsResponse, await this.request(`/v2/sandboxes/snapshots`, {
|
|
206
|
+
query: {
|
|
207
|
+
project: params.projectId,
|
|
208
|
+
name: params.name,
|
|
209
|
+
limit: params.limit,
|
|
210
|
+
cursor: params.cursor,
|
|
211
|
+
sortOrder: params.sortOrder
|
|
212
|
+
},
|
|
213
|
+
method: "GET",
|
|
214
|
+
signal: params.signal
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
async writeFiles(params) {
|
|
218
|
+
const { writer, response } = this.getFileWriter({
|
|
219
|
+
sessionId: params.sessionId,
|
|
220
|
+
extractDir: params.extractDir,
|
|
221
|
+
signal: params.signal
|
|
222
|
+
});
|
|
223
|
+
for (const file of params.files) await writer.addFile({
|
|
224
|
+
name: normalizePath({
|
|
225
|
+
filePath: file.path,
|
|
226
|
+
extractDir: params.extractDir,
|
|
227
|
+
cwd: params.cwd
|
|
228
|
+
}),
|
|
229
|
+
content: file.content,
|
|
230
|
+
mode: file.mode
|
|
231
|
+
});
|
|
232
|
+
writer.end();
|
|
233
|
+
await parseOrThrow(EmptyResponse, await response);
|
|
234
|
+
}
|
|
235
|
+
async readFile(params) {
|
|
236
|
+
const response = await this.request(`/v2/sandboxes/sessions/${params.sessionId}/fs/read`, {
|
|
237
|
+
method: "POST",
|
|
238
|
+
body: JSON.stringify({
|
|
239
|
+
path: params.path,
|
|
240
|
+
cwd: params.cwd
|
|
241
|
+
}),
|
|
242
|
+
signal: params.signal
|
|
243
|
+
});
|
|
244
|
+
if (response.status === 404) return null;
|
|
245
|
+
if (!response.ok) await parseOrThrow(z.any(), response);
|
|
246
|
+
if (response.body === null) return null;
|
|
247
|
+
return Readable.fromWeb(response.body);
|
|
248
|
+
}
|
|
249
|
+
async killCommand(params) {
|
|
250
|
+
return parseOrThrow(CommandResponse, await this.request(`/v2/sandboxes/sessions/${params.sessionId}/cmd/${params.commandId}/kill`, {
|
|
251
|
+
method: "POST",
|
|
252
|
+
body: JSON.stringify({ signal: params.signal }),
|
|
253
|
+
signal: params.abortSignal
|
|
254
|
+
}));
|
|
255
|
+
}
|
|
256
|
+
getLogs(params) {
|
|
257
|
+
const self = this;
|
|
258
|
+
const disposer = new AbortController();
|
|
259
|
+
const signal = !params.signal ? disposer.signal : mergeSignals(params.signal, disposer.signal);
|
|
260
|
+
const generator = (async function* () {
|
|
261
|
+
const url = `/v2/sandboxes/sessions/${params.sessionId}/cmd/${params.cmdId}/logs`;
|
|
262
|
+
const response = await self.request(url, {
|
|
263
|
+
method: "GET",
|
|
264
|
+
signal
|
|
265
|
+
});
|
|
266
|
+
if (!response.ok) await parseOrThrow(z.any(), response);
|
|
267
|
+
if (response.headers.get("content-type") !== "application/x-ndjson") throw new APIError(response, {
|
|
268
|
+
message: "Expected a stream of logs",
|
|
269
|
+
sessionId: params.sessionId
|
|
270
|
+
});
|
|
271
|
+
if (response.body === null) throw new APIError(response, {
|
|
272
|
+
message: "No response body",
|
|
273
|
+
sessionId: params.sessionId
|
|
274
|
+
});
|
|
275
|
+
const jsonlinesStream = jsonlines.parse();
|
|
276
|
+
pipe(response.body, jsonlinesStream, { signal }).catch((err) => {
|
|
277
|
+
console.error("Error piping logs:", err);
|
|
278
|
+
});
|
|
279
|
+
for await (const chunk of jsonlinesStream) {
|
|
280
|
+
const parsed = LogLine.parse(chunk);
|
|
281
|
+
if (parsed.stream === "error") throw new StreamError(parsed.data.code, parsed.data.message, params.sessionId);
|
|
282
|
+
yield parsed;
|
|
283
|
+
}
|
|
284
|
+
})();
|
|
285
|
+
return Object.assign(generator, {
|
|
286
|
+
[Symbol.dispose]() {
|
|
287
|
+
disposer.abort("Disposed");
|
|
288
|
+
},
|
|
289
|
+
close: () => disposer.abort("Disposed")
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
async stopSession(params) {
|
|
293
|
+
const url = `/v2/sandboxes/sessions/${params.sessionId}/stop`;
|
|
294
|
+
return parseOrThrow(StopSessionResponse, await this.request(url, {
|
|
295
|
+
method: "POST",
|
|
296
|
+
signal: params.signal
|
|
297
|
+
}));
|
|
298
|
+
}
|
|
299
|
+
async updateNetworkPolicy(params) {
|
|
300
|
+
const url = `/v2/sandboxes/sessions/${params.sessionId}/network-policy`;
|
|
301
|
+
return parseOrThrow(SessionResponse, await this.request(url, {
|
|
302
|
+
method: "POST",
|
|
303
|
+
body: JSON.stringify(toAPINetworkPolicy(params.networkPolicy)),
|
|
304
|
+
signal: params.signal
|
|
305
|
+
}));
|
|
306
|
+
}
|
|
307
|
+
async extendTimeout(params) {
|
|
308
|
+
const url = `/v2/sandboxes/sessions/${params.sessionId}/extend-timeout`;
|
|
309
|
+
return parseOrThrow(SessionResponse, await this.request(url, {
|
|
310
|
+
method: "POST",
|
|
311
|
+
body: JSON.stringify({ duration: params.duration }),
|
|
312
|
+
signal: params.signal
|
|
313
|
+
}));
|
|
314
|
+
}
|
|
315
|
+
async createSnapshot(params) {
|
|
316
|
+
const url = `/v2/sandboxes/sessions/${params.sessionId}/snapshot`;
|
|
317
|
+
const body = params.expiration === void 0 ? void 0 : JSON.stringify({ expiration: params.expiration });
|
|
318
|
+
return parseOrThrow(CreateSnapshotResponse, await this.request(url, {
|
|
319
|
+
method: "POST",
|
|
320
|
+
body,
|
|
321
|
+
signal: params.signal
|
|
322
|
+
}));
|
|
323
|
+
}
|
|
324
|
+
async deleteSnapshot(params) {
|
|
325
|
+
const url = `/v2/sandboxes/snapshots/${params.snapshotId}`;
|
|
326
|
+
return parseOrThrow(SnapshotResponse, await this.request(url, {
|
|
327
|
+
method: "DELETE",
|
|
328
|
+
signal: params.signal
|
|
329
|
+
}));
|
|
330
|
+
}
|
|
331
|
+
async getSnapshot(params) {
|
|
332
|
+
const url = `/v2/sandboxes/snapshots/${params.snapshotId}`;
|
|
333
|
+
return parseOrThrow(SnapshotResponse, await this.request(url, { signal: params.signal }));
|
|
334
|
+
}
|
|
335
|
+
async getSandbox(params) {
|
|
336
|
+
const privateParams = getPrivateParams(params);
|
|
337
|
+
const query = {
|
|
338
|
+
projectId: params.projectId,
|
|
339
|
+
...privateParams
|
|
340
|
+
};
|
|
341
|
+
if (params.resume !== void 0) query.resume = String(params.resume);
|
|
342
|
+
return parseOrThrow(SandboxAndSessionResponse, await this.request(`/v2/sandboxes/${encodeURIComponent(params.name)}`, {
|
|
343
|
+
query,
|
|
344
|
+
signal: params.signal
|
|
345
|
+
}));
|
|
346
|
+
}
|
|
347
|
+
async listSandboxes(params) {
|
|
348
|
+
return parseOrThrow(SandboxesPaginationResponse, await this.request(`/v2/sandboxes`, {
|
|
349
|
+
query: {
|
|
350
|
+
project: params.projectId,
|
|
351
|
+
limit: params.limit,
|
|
352
|
+
sortBy: params.sortBy,
|
|
353
|
+
sortOrder: params.sortOrder,
|
|
354
|
+
namePrefix: params.namePrefix,
|
|
355
|
+
cursor: params.cursor,
|
|
356
|
+
tags: toTagsFilter(params.tags)
|
|
357
|
+
},
|
|
358
|
+
method: "GET",
|
|
359
|
+
signal: params.signal
|
|
360
|
+
}));
|
|
361
|
+
}
|
|
362
|
+
async updateSandbox(params) {
|
|
363
|
+
return parseOrThrow(UpdateSandboxResponse, await this.request(`/v2/sandboxes/${encodeURIComponent(params.name)}`, {
|
|
364
|
+
method: "PATCH",
|
|
365
|
+
query: { projectId: params.projectId },
|
|
366
|
+
body: JSON.stringify({
|
|
367
|
+
persistent: params.persistent,
|
|
368
|
+
resources: params.resources,
|
|
369
|
+
runtime: params.runtime,
|
|
370
|
+
timeout: params.timeout,
|
|
371
|
+
networkPolicy: params.networkPolicy ? toAPINetworkPolicy(params.networkPolicy) : void 0,
|
|
372
|
+
tags: params.tags,
|
|
373
|
+
ports: params.ports,
|
|
374
|
+
snapshotExpiration: params.snapshotExpiration,
|
|
375
|
+
currentSnapshotId: params.currentSnapshotId
|
|
376
|
+
}),
|
|
377
|
+
signal: params.signal
|
|
378
|
+
}));
|
|
379
|
+
}
|
|
380
|
+
async deleteSandbox(params) {
|
|
381
|
+
return parseOrThrow(UpdateSandboxResponse, await this.request(`/v2/sandboxes/${encodeURIComponent(params.name)}`, {
|
|
382
|
+
method: "DELETE",
|
|
383
|
+
query: { projectId: params.projectId },
|
|
384
|
+
signal: params.signal
|
|
385
|
+
}));
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
async function pipe(readable, output, options) {
|
|
389
|
+
const reader = readable.getReader();
|
|
390
|
+
let aborted = false;
|
|
391
|
+
const signal = options?.signal;
|
|
392
|
+
const onAbort = () => {
|
|
393
|
+
aborted = true;
|
|
394
|
+
const reason = signal?.reason ?? new DOMException("The operation was aborted.", "AbortError");
|
|
395
|
+
reader.cancel(reason).catch(() => {});
|
|
396
|
+
if ("destroy" in output && typeof output.destroy === "function") {
|
|
397
|
+
output.destroy(reason);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
output.emit("error", reason);
|
|
401
|
+
output.end();
|
|
402
|
+
};
|
|
403
|
+
if (signal) if (signal.aborted) onAbort();
|
|
404
|
+
else signal.addEventListener("abort", onAbort, { once: true });
|
|
405
|
+
try {
|
|
406
|
+
while (true) {
|
|
407
|
+
const read = await reader.read();
|
|
408
|
+
if (read.value) output.write(Buffer.from(read.value));
|
|
409
|
+
if (read.done) break;
|
|
410
|
+
}
|
|
411
|
+
} catch (err) {
|
|
412
|
+
if (!aborted) output.emit("error", err);
|
|
413
|
+
} finally {
|
|
414
|
+
signal?.removeEventListener("abort", onAbort);
|
|
415
|
+
if (!aborted) output.end();
|
|
416
|
+
}
|
|
460
417
|
}
|
|
461
418
|
function mergeSignals(...signals) {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
419
|
+
const controller = new AbortController();
|
|
420
|
+
const onAbort = () => {
|
|
421
|
+
controller.abort();
|
|
422
|
+
for (const signal of signals) signal.removeEventListener("abort", onAbort);
|
|
423
|
+
};
|
|
424
|
+
for (const signal of signals) {
|
|
425
|
+
if (signal.aborted) {
|
|
426
|
+
controller.abort();
|
|
427
|
+
break;
|
|
428
|
+
}
|
|
429
|
+
signal.addEventListener("abort", onAbort);
|
|
430
|
+
}
|
|
431
|
+
return controller.signal;
|
|
432
|
+
}
|
|
433
|
+
function toTagsFilter(tags) {
|
|
434
|
+
if (tags === void 0) return void 0;
|
|
435
|
+
const entries = Object.entries(tags);
|
|
436
|
+
if (entries.length === 0) return void 0;
|
|
437
|
+
return entries.map(([key, value]) => `${key}:${value}`);
|
|
477
438
|
}
|
|
439
|
+
|
|
440
|
+
//#endregion
|
|
441
|
+
export { APIClient };
|
|
478
442
|
//# sourceMappingURL=api-client.js.map
|