@alibaba-group/opensandbox 0.1.1-dev0 → 0.1.2-dev0
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/dist/chunk-NFNOESEY.js +926 -0
- package/dist/chunk-NFNOESEY.js.map +1 -0
- package/dist/cjs/index.cjs +1625 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/internal.cjs +920 -0
- package/dist/cjs/internal.cjs.map +1 -0
- package/dist/index.d.ts +367 -22
- package/dist/index.js +678 -20
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +2513 -19
- package/dist/internal.js +18 -30
- package/dist/internal.js.map +1 -1
- package/dist/sandboxes-HBCO9ttf.d.ts +352 -0
- package/package.json +7 -2
- package/src/api/lifecycle.ts +32 -0
- package/src/config/connection.ts +3 -1
- package/src/core/constants.ts +1 -1
- package/dist/adapters/commandsAdapter.d.ts +0 -22
- package/dist/adapters/commandsAdapter.d.ts.map +0 -1
- package/dist/adapters/commandsAdapter.js +0 -77
- package/dist/adapters/commandsAdapter.js.map +0 -1
- package/dist/adapters/filesystemAdapter.d.ts +0 -52
- package/dist/adapters/filesystemAdapter.d.ts.map +0 -1
- package/dist/adapters/filesystemAdapter.js +0 -443
- package/dist/adapters/filesystemAdapter.js.map +0 -1
- package/dist/adapters/healthAdapter.d.ts +0 -8
- package/dist/adapters/healthAdapter.d.ts.map +0 -1
- package/dist/adapters/healthAdapter.js +0 -26
- package/dist/adapters/healthAdapter.js.map +0 -1
- package/dist/adapters/metricsAdapter.d.ts +0 -9
- package/dist/adapters/metricsAdapter.d.ts.map +0 -1
- package/dist/adapters/metricsAdapter.js +0 -44
- package/dist/adapters/metricsAdapter.js.map +0 -1
- package/dist/adapters/openapiError.d.ts +0 -5
- package/dist/adapters/openapiError.d.ts.map +0 -1
- package/dist/adapters/openapiError.js +0 -34
- package/dist/adapters/openapiError.js.map +0 -1
- package/dist/adapters/sandboxesAdapter.d.ts +0 -18
- package/dist/adapters/sandboxesAdapter.d.ts.map +0 -1
- package/dist/adapters/sandboxesAdapter.js +0 -147
- package/dist/adapters/sandboxesAdapter.js.map +0 -1
- package/dist/adapters/sse.d.ts +0 -9
- package/dist/adapters/sse.d.ts.map +0 -1
- package/dist/adapters/sse.js +0 -87
- package/dist/adapters/sse.js.map +0 -1
- package/dist/api/execd.d.ts +0 -1555
- package/dist/api/execd.d.ts.map +0 -1
- package/dist/api/execd.js +0 -15
- package/dist/api/execd.js.map +0 -1
- package/dist/api/lifecycle.d.ts +0 -787
- package/dist/api/lifecycle.d.ts.map +0 -1
- package/dist/api/lifecycle.js +0 -15
- package/dist/api/lifecycle.js.map +0 -1
- package/dist/config/connection.d.ts +0 -69
- package/dist/config/connection.d.ts.map +0 -1
- package/dist/config/connection.js +0 -281
- package/dist/config/connection.js.map +0 -1
- package/dist/core/constants.d.ts +0 -9
- package/dist/core/constants.d.ts.map +0 -1
- package/dist/core/constants.js +0 -25
- package/dist/core/constants.js.map +0 -1
- package/dist/core/exceptions.d.ts +0 -74
- package/dist/core/exceptions.d.ts.map +0 -1
- package/dist/core/exceptions.js +0 -104
- package/dist/core/exceptions.js.map +0 -1
- package/dist/factory/adapterFactory.d.ts +0 -33
- package/dist/factory/adapterFactory.d.ts.map +0 -1
- package/dist/factory/adapterFactory.js +0 -15
- package/dist/factory/adapterFactory.js.map +0 -1
- package/dist/factory/defaultAdapterFactory.d.ts +0 -7
- package/dist/factory/defaultAdapterFactory.d.ts.map +0 -1
- package/dist/factory/defaultAdapterFactory.js +0 -61
- package/dist/factory/defaultAdapterFactory.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/internal.d.ts.map +0 -1
- package/dist/manager.d.ts +0 -42
- package/dist/manager.d.ts.map +0 -1
- package/dist/manager.js +0 -86
- package/dist/manager.js.map +0 -1
- package/dist/models/execd.d.ts +0 -54
- package/dist/models/execd.d.ts.map +0 -1
- package/dist/models/execd.js +0 -15
- package/dist/models/execd.js.map +0 -1
- package/dist/models/execution.d.ts +0 -52
- package/dist/models/execution.d.ts.map +0 -1
- package/dist/models/execution.js +0 -15
- package/dist/models/execution.js.map +0 -1
- package/dist/models/executionEventDispatcher.d.ts +0 -15
- package/dist/models/executionEventDispatcher.d.ts.map +0 -1
- package/dist/models/executionEventDispatcher.js +0 -96
- package/dist/models/executionEventDispatcher.js.map +0 -1
- package/dist/models/filesystem.d.ts +0 -77
- package/dist/models/filesystem.d.ts.map +0 -1
- package/dist/models/filesystem.js +0 -15
- package/dist/models/filesystem.js.map +0 -1
- package/dist/models/sandboxes.d.ts +0 -105
- package/dist/models/sandboxes.d.ts.map +0 -1
- package/dist/models/sandboxes.js +0 -16
- package/dist/models/sandboxes.js.map +0 -1
- package/dist/openapi/execdClient.d.ts +0 -25
- package/dist/openapi/execdClient.d.ts.map +0 -1
- package/dist/openapi/execdClient.js +0 -22
- package/dist/openapi/execdClient.js.map +0 -1
- package/dist/openapi/lifecycleClient.d.ts +0 -28
- package/dist/openapi/lifecycleClient.d.ts.map +0 -1
- package/dist/openapi/lifecycleClient.js +0 -36
- package/dist/openapi/lifecycleClient.js.map +0 -1
- package/dist/sandbox.d.ts +0 -136
- package/dist/sandbox.d.ts.map +0 -1
- package/dist/sandbox.js +0 -303
- package/dist/sandbox.js.map +0 -1
- package/dist/services/execdCommands.d.ts +0 -19
- package/dist/services/execdCommands.d.ts.map +0 -1
- package/dist/services/execdCommands.js +0 -15
- package/dist/services/execdCommands.js.map +0 -1
- package/dist/services/execdHealth.d.ts +0 -4
- package/dist/services/execdHealth.d.ts.map +0 -1
- package/dist/services/execdHealth.js +0 -15
- package/dist/services/execdHealth.js.map +0 -1
- package/dist/services/execdMetrics.d.ts +0 -5
- package/dist/services/execdMetrics.d.ts.map +0 -1
- package/dist/services/execdMetrics.js +0 -15
- package/dist/services/execdMetrics.js.map +0 -1
- package/dist/services/filesystem.d.ts +0 -30
- package/dist/services/filesystem.d.ts.map +0 -1
- package/dist/services/filesystem.js +0 -15
- package/dist/services/filesystem.js.map +0 -1
- package/dist/services/sandboxes.d.ts +0 -12
- package/dist/services/sandboxes.d.ts.map +0 -1
- package/dist/services/sandboxes.js +0 -15
- package/dist/services/sandboxes.js.map +0 -1
|
@@ -0,0 +1,926 @@
|
|
|
1
|
+
// src/core/exceptions.ts
|
|
2
|
+
var SandboxError = class {
|
|
3
|
+
constructor(code, message) {
|
|
4
|
+
this.code = code;
|
|
5
|
+
this.message = message;
|
|
6
|
+
}
|
|
7
|
+
static INTERNAL_UNKNOWN_ERROR = "INTERNAL_UNKNOWN_ERROR";
|
|
8
|
+
static READY_TIMEOUT = "READY_TIMEOUT";
|
|
9
|
+
static UNHEALTHY = "UNHEALTHY";
|
|
10
|
+
static INVALID_ARGUMENT = "INVALID_ARGUMENT";
|
|
11
|
+
static UNEXPECTED_RESPONSE = "UNEXPECTED_RESPONSE";
|
|
12
|
+
};
|
|
13
|
+
var SandboxException = class extends Error {
|
|
14
|
+
name = "SandboxException";
|
|
15
|
+
error;
|
|
16
|
+
cause;
|
|
17
|
+
constructor(opts = {}) {
|
|
18
|
+
super(opts.message);
|
|
19
|
+
this.cause = opts.cause;
|
|
20
|
+
this.error = opts.error ?? new SandboxError(SandboxError.INTERNAL_UNKNOWN_ERROR);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
var SandboxApiException = class extends SandboxException {
|
|
24
|
+
name = "SandboxApiException";
|
|
25
|
+
statusCode;
|
|
26
|
+
requestId;
|
|
27
|
+
rawBody;
|
|
28
|
+
constructor(opts) {
|
|
29
|
+
super({
|
|
30
|
+
message: opts.message,
|
|
31
|
+
cause: opts.cause,
|
|
32
|
+
error: opts.error ?? new SandboxError(SandboxError.UNEXPECTED_RESPONSE, opts.message)
|
|
33
|
+
});
|
|
34
|
+
this.statusCode = opts.statusCode;
|
|
35
|
+
this.requestId = opts.requestId;
|
|
36
|
+
this.rawBody = opts.rawBody;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
var SandboxInternalException = class extends SandboxException {
|
|
40
|
+
name = "SandboxInternalException";
|
|
41
|
+
constructor(opts) {
|
|
42
|
+
super({
|
|
43
|
+
message: opts.message,
|
|
44
|
+
cause: opts.cause,
|
|
45
|
+
error: new SandboxError(SandboxError.INTERNAL_UNKNOWN_ERROR, opts.message)
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var SandboxUnhealthyException = class extends SandboxException {
|
|
50
|
+
name = "SandboxUnhealthyException";
|
|
51
|
+
constructor(opts) {
|
|
52
|
+
super({
|
|
53
|
+
message: opts.message,
|
|
54
|
+
cause: opts.cause,
|
|
55
|
+
error: new SandboxError(SandboxError.UNHEALTHY, opts.message)
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var SandboxReadyTimeoutException = class extends SandboxException {
|
|
60
|
+
name = "SandboxReadyTimeoutException";
|
|
61
|
+
constructor(opts) {
|
|
62
|
+
super({
|
|
63
|
+
message: opts.message,
|
|
64
|
+
cause: opts.cause,
|
|
65
|
+
error: new SandboxError(SandboxError.READY_TIMEOUT, opts.message)
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
var InvalidArgumentException = class extends SandboxException {
|
|
70
|
+
name = "InvalidArgumentException";
|
|
71
|
+
constructor(opts) {
|
|
72
|
+
super({
|
|
73
|
+
message: opts.message,
|
|
74
|
+
cause: opts.cause,
|
|
75
|
+
error: new SandboxError(SandboxError.INVALID_ARGUMENT, opts.message)
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// src/openapi/execdClient.ts
|
|
81
|
+
import createClient from "openapi-fetch";
|
|
82
|
+
function createExecdClient(opts) {
|
|
83
|
+
return createClient({
|
|
84
|
+
baseUrl: opts.baseUrl,
|
|
85
|
+
headers: opts.headers,
|
|
86
|
+
fetch: opts.fetch
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/openapi/lifecycleClient.ts
|
|
91
|
+
import createClient2 from "openapi-fetch";
|
|
92
|
+
function readEnvApiKey() {
|
|
93
|
+
const env = globalThis?.process?.env;
|
|
94
|
+
const v = env?.OPEN_SANDBOX_API_KEY;
|
|
95
|
+
return typeof v === "string" && v.length ? v : void 0;
|
|
96
|
+
}
|
|
97
|
+
function createLifecycleClient(opts = {}) {
|
|
98
|
+
const apiKey = opts.apiKey ?? readEnvApiKey();
|
|
99
|
+
const headers = {
|
|
100
|
+
...opts.headers ?? {}
|
|
101
|
+
};
|
|
102
|
+
if (apiKey && !headers["OPEN-SANDBOX-API-KEY"]) {
|
|
103
|
+
headers["OPEN-SANDBOX-API-KEY"] = apiKey;
|
|
104
|
+
}
|
|
105
|
+
return createClient2({
|
|
106
|
+
baseUrl: opts.baseUrl ?? "http://localhost:8080/v1",
|
|
107
|
+
headers,
|
|
108
|
+
fetch: opts.fetch
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// src/models/executionEventDispatcher.ts
|
|
113
|
+
function extractText(results) {
|
|
114
|
+
if (!results || typeof results !== "object") return void 0;
|
|
115
|
+
const r = results;
|
|
116
|
+
const v = r["text/plain"] ?? r.text ?? r.textPlain;
|
|
117
|
+
return v == null ? void 0 : String(v);
|
|
118
|
+
}
|
|
119
|
+
var ExecutionEventDispatcher = class {
|
|
120
|
+
constructor(execution, handlers) {
|
|
121
|
+
this.execution = execution;
|
|
122
|
+
this.handlers = handlers;
|
|
123
|
+
}
|
|
124
|
+
async dispatch(ev) {
|
|
125
|
+
await this.handlers?.onEvent?.(ev);
|
|
126
|
+
const ts = ev.timestamp ?? Date.now();
|
|
127
|
+
switch (ev.type) {
|
|
128
|
+
case "init": {
|
|
129
|
+
const id = ev.text ?? "";
|
|
130
|
+
if (id) this.execution.id = id;
|
|
131
|
+
const init = { id, timestamp: ts };
|
|
132
|
+
await this.handlers?.onInit?.(init);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
case "stdout": {
|
|
136
|
+
const msg = { text: ev.text ?? "", timestamp: ts, isError: false };
|
|
137
|
+
this.execution.logs.stdout.push(msg);
|
|
138
|
+
await this.handlers?.onStdout?.(msg);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
case "stderr": {
|
|
142
|
+
const msg = { text: ev.text ?? "", timestamp: ts, isError: true };
|
|
143
|
+
this.execution.logs.stderr.push(msg);
|
|
144
|
+
await this.handlers?.onStderr?.(msg);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
case "result": {
|
|
148
|
+
const r = { text: extractText(ev.results), timestamp: ts, raw: ev.results };
|
|
149
|
+
this.execution.result.push(r);
|
|
150
|
+
await this.handlers?.onResult?.(r);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
case "execution_count": {
|
|
154
|
+
const c = ev.execution_count;
|
|
155
|
+
if (typeof c === "number") this.execution.executionCount = c;
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
case "execution_complete": {
|
|
159
|
+
const ms = ev.execution_time;
|
|
160
|
+
const complete = { timestamp: ts, executionTimeMs: typeof ms === "number" ? ms : 0 };
|
|
161
|
+
this.execution.complete = complete;
|
|
162
|
+
await this.handlers?.onExecutionComplete?.(complete);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
case "error": {
|
|
166
|
+
const e = ev.error;
|
|
167
|
+
if (e) {
|
|
168
|
+
const err = {
|
|
169
|
+
name: String(e.ename ?? e.name ?? ""),
|
|
170
|
+
value: String(e.evalue ?? e.value ?? ""),
|
|
171
|
+
timestamp: ts,
|
|
172
|
+
traceback: Array.isArray(e.traceback) ? e.traceback.map(String) : []
|
|
173
|
+
};
|
|
174
|
+
this.execution.error = err;
|
|
175
|
+
await this.handlers?.onError?.(err);
|
|
176
|
+
}
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
default:
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// src/adapters/openapiError.ts
|
|
186
|
+
function throwOnOpenApiFetchError(result, fallbackMessage) {
|
|
187
|
+
if (!result.error) return;
|
|
188
|
+
const requestId = result.response.headers.get("x-request-id") ?? void 0;
|
|
189
|
+
const status = result.response.status ?? 0;
|
|
190
|
+
const err = result.error;
|
|
191
|
+
const message = err?.message ?? err?.error?.message ?? fallbackMessage;
|
|
192
|
+
const code = err?.code ?? err?.error?.code;
|
|
193
|
+
const msg = err?.message ?? err?.error?.message ?? message;
|
|
194
|
+
throw new SandboxApiException({
|
|
195
|
+
message: msg,
|
|
196
|
+
statusCode: status,
|
|
197
|
+
requestId,
|
|
198
|
+
error: code ? new SandboxError(String(code), String(msg ?? "")) : new SandboxError(SandboxError.UNEXPECTED_RESPONSE, String(msg ?? "")),
|
|
199
|
+
rawBody: result.error
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// src/adapters/sse.ts
|
|
204
|
+
function tryParseJson(line) {
|
|
205
|
+
try {
|
|
206
|
+
return JSON.parse(line);
|
|
207
|
+
} catch {
|
|
208
|
+
return void 0;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async function* parseJsonEventStream(res, opts) {
|
|
212
|
+
if (!res.ok) {
|
|
213
|
+
const text = await res.text().catch(() => "");
|
|
214
|
+
const parsed = tryParseJson(text);
|
|
215
|
+
const err = parsed && typeof parsed === "object" ? parsed : void 0;
|
|
216
|
+
const requestId = res.headers.get("x-request-id") ?? void 0;
|
|
217
|
+
const message = err?.message ?? opts?.fallbackErrorMessage ?? `Stream request failed (status=${res.status})`;
|
|
218
|
+
const code = err?.code ? String(err.code) : SandboxError.UNEXPECTED_RESPONSE;
|
|
219
|
+
throw new SandboxApiException({
|
|
220
|
+
message,
|
|
221
|
+
statusCode: res.status,
|
|
222
|
+
requestId,
|
|
223
|
+
error: new SandboxError(code, err?.message ? String(err.message) : message),
|
|
224
|
+
rawBody: parsed ?? text
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
if (!res.body) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const reader = res.body.getReader();
|
|
231
|
+
const decoder = new TextDecoder("utf-8");
|
|
232
|
+
let buf = "";
|
|
233
|
+
while (true) {
|
|
234
|
+
const { value, done } = await reader.read();
|
|
235
|
+
if (done) break;
|
|
236
|
+
buf += decoder.decode(value, { stream: true });
|
|
237
|
+
let idx;
|
|
238
|
+
while ((idx = buf.indexOf("\n")) >= 0) {
|
|
239
|
+
const rawLine = buf.slice(0, idx);
|
|
240
|
+
buf = buf.slice(idx + 1);
|
|
241
|
+
const line = rawLine.trim();
|
|
242
|
+
if (!line) continue;
|
|
243
|
+
if (line.startsWith(":")) continue;
|
|
244
|
+
if (line.startsWith("event:") || line.startsWith("id:") || line.startsWith("retry:")) continue;
|
|
245
|
+
const jsonLine = line.startsWith("data:") ? line.slice("data:".length).trim() : line;
|
|
246
|
+
if (!jsonLine) continue;
|
|
247
|
+
const parsed = tryParseJson(jsonLine);
|
|
248
|
+
if (!parsed) continue;
|
|
249
|
+
yield parsed;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
buf += decoder.decode();
|
|
253
|
+
const last = buf.trim();
|
|
254
|
+
if (last) {
|
|
255
|
+
const jsonLine = last.startsWith("data:") ? last.slice("data:".length).trim() : last;
|
|
256
|
+
const parsed = tryParseJson(jsonLine);
|
|
257
|
+
if (parsed) yield parsed;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// src/adapters/commandsAdapter.ts
|
|
262
|
+
function joinUrl(baseUrl, pathname) {
|
|
263
|
+
const base = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
264
|
+
const path = pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
265
|
+
return `${base}${path}`;
|
|
266
|
+
}
|
|
267
|
+
function toRunCommandRequest(command, opts) {
|
|
268
|
+
return {
|
|
269
|
+
command,
|
|
270
|
+
cwd: opts?.workingDirectory,
|
|
271
|
+
background: !!opts?.background
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
var CommandsAdapter = class {
|
|
275
|
+
constructor(client, opts) {
|
|
276
|
+
this.client = client;
|
|
277
|
+
this.opts = opts;
|
|
278
|
+
this.fetch = opts.fetch ?? fetch;
|
|
279
|
+
}
|
|
280
|
+
fetch;
|
|
281
|
+
async interrupt(sessionId) {
|
|
282
|
+
const { error, response } = await this.client.DELETE("/command", {
|
|
283
|
+
params: { query: { id: sessionId } }
|
|
284
|
+
});
|
|
285
|
+
throwOnOpenApiFetchError({ error, response }, "Interrupt command failed");
|
|
286
|
+
}
|
|
287
|
+
async *runStream(command, opts, signal) {
|
|
288
|
+
const url = joinUrl(this.opts.baseUrl, "/command");
|
|
289
|
+
const body = JSON.stringify(toRunCommandRequest(command, opts));
|
|
290
|
+
const res = await this.fetch(url, {
|
|
291
|
+
method: "POST",
|
|
292
|
+
headers: {
|
|
293
|
+
"accept": "text/event-stream",
|
|
294
|
+
"content-type": "application/json",
|
|
295
|
+
...this.opts.headers ?? {}
|
|
296
|
+
},
|
|
297
|
+
body,
|
|
298
|
+
signal
|
|
299
|
+
});
|
|
300
|
+
for await (const ev of parseJsonEventStream(res, { fallbackErrorMessage: "Run command failed" })) {
|
|
301
|
+
yield ev;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
async run(command, opts, handlers, signal) {
|
|
305
|
+
const execution = {
|
|
306
|
+
logs: { stdout: [], stderr: [] },
|
|
307
|
+
result: []
|
|
308
|
+
};
|
|
309
|
+
const dispatcher = new ExecutionEventDispatcher(execution, handlers);
|
|
310
|
+
for await (const ev of this.runStream(command, opts, signal)) {
|
|
311
|
+
if (ev.type === "init" && (ev.text ?? "") === "" && execution.id) {
|
|
312
|
+
ev.text = execution.id;
|
|
313
|
+
}
|
|
314
|
+
await dispatcher.dispatch(ev);
|
|
315
|
+
}
|
|
316
|
+
return execution;
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
// src/adapters/filesystemAdapter.ts
|
|
321
|
+
function joinUrl2(baseUrl, pathname) {
|
|
322
|
+
const base = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
323
|
+
const path = pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
324
|
+
return `${base}${path}`;
|
|
325
|
+
}
|
|
326
|
+
function toUploadBlob(data) {
|
|
327
|
+
if (typeof data === "string") return new Blob([data]);
|
|
328
|
+
if (data instanceof Blob) return data;
|
|
329
|
+
if (data instanceof ArrayBuffer) return new Blob([data]);
|
|
330
|
+
const copied = Uint8Array.from(data);
|
|
331
|
+
return new Blob([copied.buffer]);
|
|
332
|
+
}
|
|
333
|
+
function isReadableStream(v) {
|
|
334
|
+
return !!v && typeof v.getReader === "function";
|
|
335
|
+
}
|
|
336
|
+
function isAsyncIterable(v) {
|
|
337
|
+
return !!v && typeof v[Symbol.asyncIterator] === "function";
|
|
338
|
+
}
|
|
339
|
+
function isNodeRuntime() {
|
|
340
|
+
const p = globalThis?.process;
|
|
341
|
+
return !!p?.versions?.node;
|
|
342
|
+
}
|
|
343
|
+
async function collectBytes(source) {
|
|
344
|
+
const chunks = [];
|
|
345
|
+
let total = 0;
|
|
346
|
+
if (isReadableStream(source)) {
|
|
347
|
+
const reader = source.getReader();
|
|
348
|
+
try {
|
|
349
|
+
while (true) {
|
|
350
|
+
const { done, value } = await reader.read();
|
|
351
|
+
if (done) break;
|
|
352
|
+
if (value) {
|
|
353
|
+
chunks.push(value);
|
|
354
|
+
total += value.length;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
} finally {
|
|
358
|
+
reader.releaseLock();
|
|
359
|
+
}
|
|
360
|
+
} else {
|
|
361
|
+
for await (const chunk of source) {
|
|
362
|
+
chunks.push(chunk);
|
|
363
|
+
total += chunk.length;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const out = new Uint8Array(total);
|
|
367
|
+
let offset = 0;
|
|
368
|
+
for (const chunk of chunks) {
|
|
369
|
+
out.set(chunk, offset);
|
|
370
|
+
offset += chunk.length;
|
|
371
|
+
}
|
|
372
|
+
return out;
|
|
373
|
+
}
|
|
374
|
+
function toReadableStream(it) {
|
|
375
|
+
const RS = ReadableStream;
|
|
376
|
+
if (typeof RS?.from === "function") return RS.from(it);
|
|
377
|
+
const iterator = it[Symbol.asyncIterator]();
|
|
378
|
+
return new ReadableStream({
|
|
379
|
+
async pull(controller) {
|
|
380
|
+
const r = await iterator.next();
|
|
381
|
+
if (r.done) {
|
|
382
|
+
controller.close();
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
controller.enqueue(r.value);
|
|
386
|
+
},
|
|
387
|
+
async cancel() {
|
|
388
|
+
await iterator.return?.();
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
function basename(p) {
|
|
393
|
+
const parts = p.split("/").filter(Boolean);
|
|
394
|
+
return parts.length ? parts[parts.length - 1] : "file";
|
|
395
|
+
}
|
|
396
|
+
function encodeUtf8(s) {
|
|
397
|
+
return new TextEncoder().encode(s);
|
|
398
|
+
}
|
|
399
|
+
async function* multipartUploadBody(opts) {
|
|
400
|
+
const b = opts.boundary;
|
|
401
|
+
yield encodeUtf8(`--${b}\r
|
|
402
|
+
`);
|
|
403
|
+
yield encodeUtf8(
|
|
404
|
+
`Content-Disposition: form-data; name="metadata"; filename="metadata"\r
|
|
405
|
+
`
|
|
406
|
+
);
|
|
407
|
+
yield encodeUtf8(`Content-Type: application/json\r
|
|
408
|
+
\r
|
|
409
|
+
`);
|
|
410
|
+
yield encodeUtf8(opts.metadataJson);
|
|
411
|
+
yield encodeUtf8(`\r
|
|
412
|
+
`);
|
|
413
|
+
yield encodeUtf8(`--${b}\r
|
|
414
|
+
`);
|
|
415
|
+
yield encodeUtf8(
|
|
416
|
+
`Content-Disposition: form-data; name="file"; filename="${opts.fileName}"\r
|
|
417
|
+
`
|
|
418
|
+
);
|
|
419
|
+
yield encodeUtf8(`Content-Type: ${opts.fileContentType}\r
|
|
420
|
+
\r
|
|
421
|
+
`);
|
|
422
|
+
if (isReadableStream(opts.file)) {
|
|
423
|
+
const reader = opts.file.getReader();
|
|
424
|
+
try {
|
|
425
|
+
while (true) {
|
|
426
|
+
const { done, value } = await reader.read();
|
|
427
|
+
if (done) break;
|
|
428
|
+
if (value) yield value;
|
|
429
|
+
}
|
|
430
|
+
} finally {
|
|
431
|
+
reader.releaseLock();
|
|
432
|
+
}
|
|
433
|
+
} else {
|
|
434
|
+
for await (const chunk of opts.file) {
|
|
435
|
+
yield chunk;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
yield encodeUtf8(`\r
|
|
439
|
+
--${b}--\r
|
|
440
|
+
`);
|
|
441
|
+
}
|
|
442
|
+
function toPermission(e) {
|
|
443
|
+
return {
|
|
444
|
+
mode: e.mode ?? 755,
|
|
445
|
+
owner: e.owner,
|
|
446
|
+
group: e.group
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
var FilesystemAdapter = class {
|
|
450
|
+
constructor(client, opts) {
|
|
451
|
+
this.client = client;
|
|
452
|
+
this.opts = opts;
|
|
453
|
+
this.fetch = opts.fetch ?? fetch;
|
|
454
|
+
}
|
|
455
|
+
fetch;
|
|
456
|
+
static Api = {
|
|
457
|
+
// This is intentionally derived from OpenAPI schema types so API changes surface quickly.
|
|
458
|
+
SearchFilesOk: null,
|
|
459
|
+
FilesInfoOk: null,
|
|
460
|
+
MakeDirsRequest: null,
|
|
461
|
+
SetPermissionsRequest: null,
|
|
462
|
+
MoveFilesRequest: null,
|
|
463
|
+
ReplaceContentsRequest: null
|
|
464
|
+
};
|
|
465
|
+
parseIsoDate(field, v) {
|
|
466
|
+
if (typeof v !== "string" || !v) {
|
|
467
|
+
throw new Error(`Invalid ${field}: expected ISO string, got ${typeof v}`);
|
|
468
|
+
}
|
|
469
|
+
const d = new Date(v);
|
|
470
|
+
if (Number.isNaN(d.getTime())) {
|
|
471
|
+
throw new Error(`Invalid ${field}: ${v}`);
|
|
472
|
+
}
|
|
473
|
+
return d;
|
|
474
|
+
}
|
|
475
|
+
static _ApiFileInfo = null;
|
|
476
|
+
mapApiFileInfo(raw) {
|
|
477
|
+
const { path, size, created_at, modified_at, mode, owner, group, ...rest } = raw;
|
|
478
|
+
return {
|
|
479
|
+
...rest,
|
|
480
|
+
path,
|
|
481
|
+
size,
|
|
482
|
+
mode,
|
|
483
|
+
owner,
|
|
484
|
+
group,
|
|
485
|
+
createdAt: created_at ? this.parseIsoDate("createdAt", created_at) : void 0,
|
|
486
|
+
modifiedAt: modified_at ? this.parseIsoDate("modifiedAt", modified_at) : void 0
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
async getFileInfo(paths) {
|
|
490
|
+
const { data, error, response } = await this.client.GET("/files/info", {
|
|
491
|
+
params: { query: { path: paths } }
|
|
492
|
+
});
|
|
493
|
+
throwOnOpenApiFetchError({ error, response }, "Get file info failed");
|
|
494
|
+
const raw = data;
|
|
495
|
+
if (!raw) return {};
|
|
496
|
+
if (typeof raw !== "object") {
|
|
497
|
+
throw new Error(
|
|
498
|
+
`Get file info failed: unexpected response shape (got ${typeof raw})`
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
const out = {};
|
|
502
|
+
for (const [k, v] of Object.entries(raw)) {
|
|
503
|
+
if (!v || typeof v !== "object") {
|
|
504
|
+
throw new Error(
|
|
505
|
+
`Get file info failed: invalid file info for path=${k}`
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
out[k] = this.mapApiFileInfo(v);
|
|
509
|
+
}
|
|
510
|
+
return out;
|
|
511
|
+
}
|
|
512
|
+
async deleteFiles(paths) {
|
|
513
|
+
const { error, response } = await this.client.DELETE("/files", {
|
|
514
|
+
params: { query: { path: paths } }
|
|
515
|
+
});
|
|
516
|
+
throwOnOpenApiFetchError({ error, response }, "Delete files failed");
|
|
517
|
+
}
|
|
518
|
+
async createDirectories(entries) {
|
|
519
|
+
const map = {};
|
|
520
|
+
for (const e of entries) {
|
|
521
|
+
map[e.path] = toPermission(e);
|
|
522
|
+
}
|
|
523
|
+
const body = map;
|
|
524
|
+
const { error, response } = await this.client.POST("/directories", {
|
|
525
|
+
body
|
|
526
|
+
});
|
|
527
|
+
throwOnOpenApiFetchError({ error, response }, "Create directories failed");
|
|
528
|
+
}
|
|
529
|
+
async deleteDirectories(paths) {
|
|
530
|
+
const { error, response } = await this.client.DELETE("/directories", {
|
|
531
|
+
params: { query: { path: paths } }
|
|
532
|
+
});
|
|
533
|
+
throwOnOpenApiFetchError({ error, response }, "Delete directories failed");
|
|
534
|
+
}
|
|
535
|
+
async setPermissions(entries) {
|
|
536
|
+
const req = {};
|
|
537
|
+
for (const e of entries) {
|
|
538
|
+
req[e.path] = toPermission(e);
|
|
539
|
+
}
|
|
540
|
+
const body = req;
|
|
541
|
+
const { error, response } = await this.client.POST("/files/permissions", {
|
|
542
|
+
body
|
|
543
|
+
});
|
|
544
|
+
throwOnOpenApiFetchError({ error, response }, "Set permissions failed");
|
|
545
|
+
}
|
|
546
|
+
async moveFiles(entries) {
|
|
547
|
+
const req = entries.map((e) => ({
|
|
548
|
+
src: e.src,
|
|
549
|
+
dest: e.dest
|
|
550
|
+
}));
|
|
551
|
+
const body = req;
|
|
552
|
+
const { error, response } = await this.client.POST("/files/mv", {
|
|
553
|
+
body
|
|
554
|
+
});
|
|
555
|
+
throwOnOpenApiFetchError({ error, response }, "Move files failed");
|
|
556
|
+
}
|
|
557
|
+
async replaceContents(entries) {
|
|
558
|
+
const req = {};
|
|
559
|
+
for (const e of entries) {
|
|
560
|
+
req[e.path] = { old: e.oldContent, new: e.newContent };
|
|
561
|
+
}
|
|
562
|
+
const body = req;
|
|
563
|
+
const { error, response } = await this.client.POST("/files/replace", {
|
|
564
|
+
body
|
|
565
|
+
});
|
|
566
|
+
throwOnOpenApiFetchError({ error, response }, "Replace contents failed");
|
|
567
|
+
}
|
|
568
|
+
async search(entry) {
|
|
569
|
+
const { data, error, response } = await this.client.GET("/files/search", {
|
|
570
|
+
params: { query: { path: entry.path, pattern: entry.pattern } }
|
|
571
|
+
});
|
|
572
|
+
throwOnOpenApiFetchError({ error, response }, "Search files failed");
|
|
573
|
+
const ok = data;
|
|
574
|
+
if (!ok) return [];
|
|
575
|
+
if (!Array.isArray(ok)) {
|
|
576
|
+
throw new Error(
|
|
577
|
+
`Search files failed: unexpected response shape (expected array, got ${typeof ok})`
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
return ok.map((x) => this.mapApiFileInfo(x));
|
|
581
|
+
}
|
|
582
|
+
async uploadFile(meta, data) {
|
|
583
|
+
const url = joinUrl2(this.opts.baseUrl, "/files/upload");
|
|
584
|
+
const fileName = basename(meta.path);
|
|
585
|
+
const metadataJson = JSON.stringify(meta);
|
|
586
|
+
if (isReadableStream(data) || isAsyncIterable(data)) {
|
|
587
|
+
if (!isNodeRuntime()) {
|
|
588
|
+
const bytes = await collectBytes(data);
|
|
589
|
+
return await this.uploadFile(meta, bytes);
|
|
590
|
+
}
|
|
591
|
+
const boundary = `opensandbox_${Math.random().toString(16).slice(2)}_${Date.now()}`;
|
|
592
|
+
const bodyIt = multipartUploadBody({
|
|
593
|
+
boundary,
|
|
594
|
+
metadataJson,
|
|
595
|
+
fileName,
|
|
596
|
+
fileContentType: "application/octet-stream",
|
|
597
|
+
file: data
|
|
598
|
+
});
|
|
599
|
+
const stream = toReadableStream(bodyIt);
|
|
600
|
+
const res2 = await this.fetch(url, {
|
|
601
|
+
method: "POST",
|
|
602
|
+
headers: {
|
|
603
|
+
"content-type": `multipart/form-data; boundary=${boundary}`,
|
|
604
|
+
...this.opts.headers ?? {}
|
|
605
|
+
},
|
|
606
|
+
body: stream,
|
|
607
|
+
// Node fetch (undici) requires duplex for streaming request bodies.
|
|
608
|
+
duplex: "half"
|
|
609
|
+
});
|
|
610
|
+
if (!res2.ok) {
|
|
611
|
+
const requestId = res2.headers.get("x-request-id") ?? void 0;
|
|
612
|
+
const rawBody = await res2.text().catch(() => void 0);
|
|
613
|
+
throw new SandboxApiException({
|
|
614
|
+
message: `Upload failed (status=${res2.status})`,
|
|
615
|
+
statusCode: res2.status,
|
|
616
|
+
requestId,
|
|
617
|
+
error: new SandboxError(
|
|
618
|
+
SandboxError.UNEXPECTED_RESPONSE,
|
|
619
|
+
"Upload failed"
|
|
620
|
+
),
|
|
621
|
+
rawBody
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
const form = new FormData();
|
|
627
|
+
form.append(
|
|
628
|
+
"metadata",
|
|
629
|
+
new Blob([metadataJson], { type: "application/json" }),
|
|
630
|
+
"metadata"
|
|
631
|
+
);
|
|
632
|
+
if (typeof data === "string") {
|
|
633
|
+
const textBlob = new Blob([data], { type: "text/plain; charset=utf-8" });
|
|
634
|
+
form.append("file", textBlob, fileName);
|
|
635
|
+
} else {
|
|
636
|
+
const blob = toUploadBlob(data);
|
|
637
|
+
const fileBlob = blob.type ? blob : new Blob([blob], { type: "application/octet-stream" });
|
|
638
|
+
form.append("file", fileBlob, fileName);
|
|
639
|
+
}
|
|
640
|
+
const res = await this.fetch(url, {
|
|
641
|
+
method: "POST",
|
|
642
|
+
headers: {
|
|
643
|
+
...this.opts.headers ?? {}
|
|
644
|
+
},
|
|
645
|
+
body: form
|
|
646
|
+
});
|
|
647
|
+
if (!res.ok) {
|
|
648
|
+
const requestId = res.headers.get("x-request-id") ?? void 0;
|
|
649
|
+
const rawBody = await res.text().catch(() => void 0);
|
|
650
|
+
throw new SandboxApiException({
|
|
651
|
+
message: `Upload failed (status=${res.status})`,
|
|
652
|
+
statusCode: res.status,
|
|
653
|
+
requestId,
|
|
654
|
+
error: new SandboxError(
|
|
655
|
+
SandboxError.UNEXPECTED_RESPONSE,
|
|
656
|
+
"Upload failed"
|
|
657
|
+
),
|
|
658
|
+
rawBody
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
async readBytes(path, opts) {
|
|
663
|
+
const url = joinUrl2(this.opts.baseUrl, "/files/download") + `?path=${encodeURIComponent(path)}`;
|
|
664
|
+
const res = await this.fetch(url, {
|
|
665
|
+
method: "GET",
|
|
666
|
+
headers: {
|
|
667
|
+
...this.opts.headers ?? {},
|
|
668
|
+
...opts?.range ? { Range: opts.range } : {}
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
if (!res.ok) {
|
|
672
|
+
const requestId = res.headers.get("x-request-id") ?? void 0;
|
|
673
|
+
const rawBody = await res.text().catch(() => void 0);
|
|
674
|
+
throw new SandboxApiException({
|
|
675
|
+
message: "Download failed",
|
|
676
|
+
statusCode: res.status,
|
|
677
|
+
requestId,
|
|
678
|
+
error: new SandboxError(
|
|
679
|
+
SandboxError.UNEXPECTED_RESPONSE,
|
|
680
|
+
"Download failed"
|
|
681
|
+
),
|
|
682
|
+
rawBody
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
const ab = await res.arrayBuffer();
|
|
686
|
+
return new Uint8Array(ab);
|
|
687
|
+
}
|
|
688
|
+
readBytesStream(path, opts) {
|
|
689
|
+
return this.downloadStream(path, opts);
|
|
690
|
+
}
|
|
691
|
+
async *downloadStream(path, opts) {
|
|
692
|
+
const url = joinUrl2(this.opts.baseUrl, "/files/download") + `?path=${encodeURIComponent(path)}`;
|
|
693
|
+
const res = await this.fetch(url, {
|
|
694
|
+
method: "GET",
|
|
695
|
+
headers: {
|
|
696
|
+
...this.opts.headers ?? {},
|
|
697
|
+
...opts?.range ? { Range: opts.range } : {}
|
|
698
|
+
}
|
|
699
|
+
});
|
|
700
|
+
if (!res.ok) {
|
|
701
|
+
const requestId = res.headers.get("x-request-id") ?? void 0;
|
|
702
|
+
const rawBody = await res.text().catch(() => void 0);
|
|
703
|
+
throw new SandboxApiException({
|
|
704
|
+
message: "Download stream failed",
|
|
705
|
+
statusCode: res.status,
|
|
706
|
+
requestId,
|
|
707
|
+
error: new SandboxError(
|
|
708
|
+
SandboxError.UNEXPECTED_RESPONSE,
|
|
709
|
+
"Download stream failed"
|
|
710
|
+
),
|
|
711
|
+
rawBody
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
const body = res.body;
|
|
715
|
+
if (!body) return;
|
|
716
|
+
const reader = body.getReader();
|
|
717
|
+
while (true) {
|
|
718
|
+
const { done, value } = await reader.read();
|
|
719
|
+
if (done) return;
|
|
720
|
+
if (value) yield value;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
async readFile(path, opts) {
|
|
724
|
+
const bytes = await this.readBytes(path, { range: opts?.range });
|
|
725
|
+
const encoding = opts?.encoding ?? "utf-8";
|
|
726
|
+
return new TextDecoder(encoding).decode(bytes);
|
|
727
|
+
}
|
|
728
|
+
async writeFiles(entries) {
|
|
729
|
+
for (const e of entries) {
|
|
730
|
+
const meta = {
|
|
731
|
+
path: e.path,
|
|
732
|
+
owner: e.owner,
|
|
733
|
+
group: e.group,
|
|
734
|
+
mode: e.mode
|
|
735
|
+
};
|
|
736
|
+
await this.uploadFile(meta, e.data ?? "");
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
// src/adapters/healthAdapter.ts
|
|
742
|
+
var HealthAdapter = class {
|
|
743
|
+
constructor(client) {
|
|
744
|
+
this.client = client;
|
|
745
|
+
}
|
|
746
|
+
async ping() {
|
|
747
|
+
const { error, response } = await this.client.GET("/ping");
|
|
748
|
+
throwOnOpenApiFetchError({ error, response }, "Execd ping failed");
|
|
749
|
+
return true;
|
|
750
|
+
}
|
|
751
|
+
};
|
|
752
|
+
|
|
753
|
+
// src/adapters/metricsAdapter.ts
|
|
754
|
+
function normalizeMetrics(m) {
|
|
755
|
+
const cpuCount = m.cpu_count ?? 0;
|
|
756
|
+
const cpuUsedPercentage = m.cpu_used_pct ?? 0;
|
|
757
|
+
const memoryTotalMiB = m.mem_total_mib ?? 0;
|
|
758
|
+
const memoryUsedMiB = m.mem_used_mib ?? 0;
|
|
759
|
+
const timestamp = m.timestamp ?? 0;
|
|
760
|
+
return {
|
|
761
|
+
cpuCount: Number(cpuCount),
|
|
762
|
+
cpuUsedPercentage: Number(cpuUsedPercentage),
|
|
763
|
+
memoryTotalMiB: Number(memoryTotalMiB),
|
|
764
|
+
memoryUsedMiB: Number(memoryUsedMiB),
|
|
765
|
+
timestamp: Number(timestamp)
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
var MetricsAdapter = class {
|
|
769
|
+
constructor(client) {
|
|
770
|
+
this.client = client;
|
|
771
|
+
}
|
|
772
|
+
async getMetrics() {
|
|
773
|
+
const { data, error, response } = await this.client.GET("/metrics");
|
|
774
|
+
throwOnOpenApiFetchError({ error, response }, "Get execd metrics failed");
|
|
775
|
+
const ok = data;
|
|
776
|
+
if (!ok || typeof ok !== "object") {
|
|
777
|
+
throw new Error("Get execd metrics failed: unexpected response shape");
|
|
778
|
+
}
|
|
779
|
+
return normalizeMetrics(ok);
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
|
|
783
|
+
// src/adapters/sandboxesAdapter.ts
|
|
784
|
+
function encodeMetadataFilter(metadata) {
|
|
785
|
+
const parts = [];
|
|
786
|
+
for (const [k, v] of Object.entries(metadata)) {
|
|
787
|
+
parts.push(`${k}=${v}`);
|
|
788
|
+
}
|
|
789
|
+
return parts.join("&");
|
|
790
|
+
}
|
|
791
|
+
var SandboxesAdapter = class {
|
|
792
|
+
constructor(client) {
|
|
793
|
+
this.client = client;
|
|
794
|
+
}
|
|
795
|
+
parseIsoDate(field, v) {
|
|
796
|
+
if (typeof v !== "string" || !v) {
|
|
797
|
+
throw new Error(`Invalid ${field}: expected ISO string, got ${typeof v}`);
|
|
798
|
+
}
|
|
799
|
+
const d = new Date(v);
|
|
800
|
+
if (Number.isNaN(d.getTime())) {
|
|
801
|
+
throw new Error(`Invalid ${field}: ${v}`);
|
|
802
|
+
}
|
|
803
|
+
return d;
|
|
804
|
+
}
|
|
805
|
+
mapSandboxInfo(raw) {
|
|
806
|
+
return {
|
|
807
|
+
...raw ?? {},
|
|
808
|
+
createdAt: this.parseIsoDate("createdAt", raw?.createdAt),
|
|
809
|
+
expiresAt: this.parseIsoDate("expiresAt", raw?.expiresAt)
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
async createSandbox(req) {
|
|
813
|
+
const body = req;
|
|
814
|
+
const { data, error, response } = await this.client.POST("/sandboxes", {
|
|
815
|
+
body
|
|
816
|
+
});
|
|
817
|
+
throwOnOpenApiFetchError({ error, response }, "Create sandbox failed");
|
|
818
|
+
const raw = data;
|
|
819
|
+
if (!raw || typeof raw !== "object") {
|
|
820
|
+
throw new Error("Create sandbox failed: unexpected response shape");
|
|
821
|
+
}
|
|
822
|
+
return {
|
|
823
|
+
...raw ?? {},
|
|
824
|
+
createdAt: this.parseIsoDate("createdAt", raw?.createdAt),
|
|
825
|
+
expiresAt: this.parseIsoDate("expiresAt", raw?.expiresAt)
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
async getSandbox(sandboxId) {
|
|
829
|
+
const { data, error, response } = await this.client.GET("/sandboxes/{sandboxId}", {
|
|
830
|
+
params: { path: { sandboxId } }
|
|
831
|
+
});
|
|
832
|
+
throwOnOpenApiFetchError({ error, response }, "Get sandbox failed");
|
|
833
|
+
const ok = data;
|
|
834
|
+
if (!ok || typeof ok !== "object") {
|
|
835
|
+
throw new Error("Get sandbox failed: unexpected response shape");
|
|
836
|
+
}
|
|
837
|
+
return this.mapSandboxInfo(ok);
|
|
838
|
+
}
|
|
839
|
+
async listSandboxes(params = {}) {
|
|
840
|
+
const query = {};
|
|
841
|
+
if (params.states?.length) query.state = params.states;
|
|
842
|
+
if (params.metadata && Object.keys(params.metadata).length) {
|
|
843
|
+
query.metadata = encodeMetadataFilter(params.metadata);
|
|
844
|
+
}
|
|
845
|
+
if (params.page != null) query.page = params.page;
|
|
846
|
+
if (params.pageSize != null) query.pageSize = params.pageSize;
|
|
847
|
+
const { data, error, response } = await this.client.GET("/sandboxes", {
|
|
848
|
+
params: { query }
|
|
849
|
+
});
|
|
850
|
+
throwOnOpenApiFetchError({ error, response }, "List sandboxes failed");
|
|
851
|
+
const raw = data;
|
|
852
|
+
if (!raw || typeof raw !== "object") {
|
|
853
|
+
throw new Error("List sandboxes failed: unexpected response shape");
|
|
854
|
+
}
|
|
855
|
+
const itemsRaw = raw.items;
|
|
856
|
+
if (!Array.isArray(itemsRaw)) throw new Error("List sandboxes failed: unexpected items shape");
|
|
857
|
+
return {
|
|
858
|
+
...raw ?? {},
|
|
859
|
+
items: itemsRaw.map((x) => this.mapSandboxInfo(x))
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
async deleteSandbox(sandboxId) {
|
|
863
|
+
const { error, response } = await this.client.DELETE("/sandboxes/{sandboxId}", {
|
|
864
|
+
params: { path: { sandboxId } }
|
|
865
|
+
});
|
|
866
|
+
throwOnOpenApiFetchError({ error, response }, "Delete sandbox failed");
|
|
867
|
+
}
|
|
868
|
+
async pauseSandbox(sandboxId) {
|
|
869
|
+
const { error, response } = await this.client.POST("/sandboxes/{sandboxId}/pause", {
|
|
870
|
+
params: { path: { sandboxId } }
|
|
871
|
+
});
|
|
872
|
+
throwOnOpenApiFetchError({ error, response }, "Pause sandbox failed");
|
|
873
|
+
}
|
|
874
|
+
async resumeSandbox(sandboxId) {
|
|
875
|
+
const { error, response } = await this.client.POST("/sandboxes/{sandboxId}/resume", {
|
|
876
|
+
params: { path: { sandboxId } }
|
|
877
|
+
});
|
|
878
|
+
throwOnOpenApiFetchError({ error, response }, "Resume sandbox failed");
|
|
879
|
+
}
|
|
880
|
+
async renewSandboxExpiration(sandboxId, req) {
|
|
881
|
+
const body = req;
|
|
882
|
+
const { data, error, response } = await this.client.POST("/sandboxes/{sandboxId}/renew-expiration", {
|
|
883
|
+
params: { path: { sandboxId } },
|
|
884
|
+
body
|
|
885
|
+
});
|
|
886
|
+
throwOnOpenApiFetchError({ error, response }, "Renew sandbox expiration failed");
|
|
887
|
+
const raw = data;
|
|
888
|
+
if (!raw || typeof raw !== "object") {
|
|
889
|
+
throw new Error("Renew sandbox expiration failed: unexpected response shape");
|
|
890
|
+
}
|
|
891
|
+
return {
|
|
892
|
+
...raw ?? {},
|
|
893
|
+
expiresAt: raw?.expiresAt ? this.parseIsoDate("expiresAt", raw.expiresAt) : void 0
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
async getSandboxEndpoint(sandboxId, port) {
|
|
897
|
+
const { data, error, response } = await this.client.GET("/sandboxes/{sandboxId}/endpoints/{port}", {
|
|
898
|
+
params: { path: { sandboxId, port } }
|
|
899
|
+
});
|
|
900
|
+
throwOnOpenApiFetchError({ error, response }, "Get sandbox endpoint failed");
|
|
901
|
+
const ok = data;
|
|
902
|
+
if (!ok || typeof ok !== "object") {
|
|
903
|
+
throw new Error("Get sandbox endpoint failed: unexpected response shape");
|
|
904
|
+
}
|
|
905
|
+
return ok;
|
|
906
|
+
}
|
|
907
|
+
};
|
|
908
|
+
|
|
909
|
+
export {
|
|
910
|
+
SandboxError,
|
|
911
|
+
SandboxException,
|
|
912
|
+
SandboxApiException,
|
|
913
|
+
SandboxInternalException,
|
|
914
|
+
SandboxUnhealthyException,
|
|
915
|
+
SandboxReadyTimeoutException,
|
|
916
|
+
InvalidArgumentException,
|
|
917
|
+
createExecdClient,
|
|
918
|
+
createLifecycleClient,
|
|
919
|
+
ExecutionEventDispatcher,
|
|
920
|
+
CommandsAdapter,
|
|
921
|
+
FilesystemAdapter,
|
|
922
|
+
HealthAdapter,
|
|
923
|
+
MetricsAdapter,
|
|
924
|
+
SandboxesAdapter
|
|
925
|
+
};
|
|
926
|
+
//# sourceMappingURL=chunk-NFNOESEY.js.map
|