@alibaba-group/opensandbox 0.1.3-dev1 → 0.1.4
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 +1 -0
- package/dist/{chunk-4EF4ODU2.js → chunk-OYTPXLWE.js} +56 -4
- package/dist/chunk-OYTPXLWE.js.map +1 -0
- package/dist/cjs/index.cjs +99 -13
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/internal.cjs +55 -3
- package/dist/cjs/internal.cjs.map +1 -1
- package/dist/index.d.ts +18 -3
- package/dist/index.js +45 -11
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +83 -3
- package/dist/internal.js +1 -1
- package/dist/{sandboxes-CLy12BN1.d.ts → sandboxes-Dc0G4ShU.d.ts} +95 -7
- package/package.json +1 -1
- package/src/adapters/commandsAdapter.ts +67 -2
- package/src/adapters/sandboxesAdapter.ts +6 -2
- package/src/api/execd.ts +8 -0
- package/src/api/lifecycle.ts +71 -1
- package/src/config/connection.ts +11 -0
- package/src/core/constants.ts +1 -1
- package/src/factory/adapterFactory.ts +1 -0
- package/src/factory/defaultAdapterFactory.ts +7 -3
- package/src/index.ts +5 -1
- package/src/models/execd.ts +20 -6
- package/src/models/sandboxes.ts +74 -0
- package/src/sandbox.ts +35 -3
- package/src/services/execdCommands.ts +17 -1
- package/src/services/sandboxes.ts +5 -1
- package/dist/chunk-4EF4ODU2.js.map +0 -1
|
@@ -169,11 +169,6 @@ interface ServerStreamEvent extends Record<string, unknown> {
|
|
|
169
169
|
results?: Record<string, unknown>;
|
|
170
170
|
error?: Record<string, unknown>;
|
|
171
171
|
}
|
|
172
|
-
interface RunCommandRequest extends Record<string, unknown> {
|
|
173
|
-
command: string;
|
|
174
|
-
cwd?: string;
|
|
175
|
-
background?: boolean;
|
|
176
|
-
}
|
|
177
172
|
interface CodeContextRequest extends Record<string, unknown> {
|
|
178
173
|
language: string;
|
|
179
174
|
}
|
|
@@ -187,6 +182,24 @@ interface RunCommandOpts {
|
|
|
187
182
|
* Run command in detached mode.
|
|
188
183
|
*/
|
|
189
184
|
background?: boolean;
|
|
185
|
+
/**
|
|
186
|
+
* Maximum execution time in seconds; server will terminate the command when reached.
|
|
187
|
+
* If omitted, the server will not enforce any timeout.
|
|
188
|
+
*/
|
|
189
|
+
timeoutSeconds?: number;
|
|
190
|
+
}
|
|
191
|
+
interface CommandStatus {
|
|
192
|
+
id?: string;
|
|
193
|
+
content?: string;
|
|
194
|
+
running?: boolean;
|
|
195
|
+
exitCode?: number | null;
|
|
196
|
+
error?: string;
|
|
197
|
+
startedAt?: Date;
|
|
198
|
+
finishedAt?: Date | null;
|
|
199
|
+
}
|
|
200
|
+
interface CommandLogs {
|
|
201
|
+
content: string;
|
|
202
|
+
cursor?: number;
|
|
190
203
|
}
|
|
191
204
|
type CommandExecution = Execution;
|
|
192
205
|
interface Metrics extends Record<string, unknown> {
|
|
@@ -223,6 +236,14 @@ interface ExecdCommands {
|
|
|
223
236
|
* Note: Execd spec uses `DELETE /command?id=<sessionId>`.
|
|
224
237
|
*/
|
|
225
238
|
interrupt(sessionId: string): Promise<void>;
|
|
239
|
+
/**
|
|
240
|
+
* Get the current running status for a command id.
|
|
241
|
+
*/
|
|
242
|
+
getCommandStatus(commandId: string): Promise<CommandStatus>;
|
|
243
|
+
/**
|
|
244
|
+
* Get background command logs (non-streamed).
|
|
245
|
+
*/
|
|
246
|
+
getBackgroundCommandLogs(commandId: string, cursor?: number): Promise<CommandLogs>;
|
|
226
247
|
}
|
|
227
248
|
|
|
228
249
|
interface ExecdHealth {
|
|
@@ -275,6 +296,64 @@ interface NetworkPolicy extends Record<string, unknown> {
|
|
|
275
296
|
*/
|
|
276
297
|
egress?: NetworkRule[];
|
|
277
298
|
}
|
|
299
|
+
/**
|
|
300
|
+
* Host path bind mount backend.
|
|
301
|
+
*
|
|
302
|
+
* Maps a directory on the host filesystem into the container.
|
|
303
|
+
* Only available when the runtime supports host mounts.
|
|
304
|
+
*/
|
|
305
|
+
interface Host extends Record<string, unknown> {
|
|
306
|
+
/**
|
|
307
|
+
* Absolute path on the host filesystem to mount.
|
|
308
|
+
*/
|
|
309
|
+
path: string;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Kubernetes PersistentVolumeClaim mount backend.
|
|
313
|
+
*
|
|
314
|
+
* References an existing PVC in the same namespace as the sandbox pod.
|
|
315
|
+
* Only available in Kubernetes runtime.
|
|
316
|
+
*/
|
|
317
|
+
interface PVC extends Record<string, unknown> {
|
|
318
|
+
/**
|
|
319
|
+
* Name of the PersistentVolumeClaim in the same namespace.
|
|
320
|
+
*/
|
|
321
|
+
claimName: string;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Storage mount definition for a sandbox.
|
|
325
|
+
*
|
|
326
|
+
* Each volume entry contains:
|
|
327
|
+
* - A unique name identifier
|
|
328
|
+
* - Exactly one backend (host, pvc) with backend-specific fields
|
|
329
|
+
* - Common mount settings (mountPath, readOnly, subPath)
|
|
330
|
+
*/
|
|
331
|
+
interface Volume extends Record<string, unknown> {
|
|
332
|
+
/**
|
|
333
|
+
* Unique identifier for the volume within the sandbox.
|
|
334
|
+
*/
|
|
335
|
+
name: string;
|
|
336
|
+
/**
|
|
337
|
+
* Host path bind mount backend (mutually exclusive with pvc).
|
|
338
|
+
*/
|
|
339
|
+
host?: Host;
|
|
340
|
+
/**
|
|
341
|
+
* Kubernetes PVC mount backend (mutually exclusive with host).
|
|
342
|
+
*/
|
|
343
|
+
pvc?: PVC;
|
|
344
|
+
/**
|
|
345
|
+
* Absolute path inside the container where the volume is mounted.
|
|
346
|
+
*/
|
|
347
|
+
mountPath: string;
|
|
348
|
+
/**
|
|
349
|
+
* If true, the volume is mounted as read-only. Defaults to false (read-write).
|
|
350
|
+
*/
|
|
351
|
+
readOnly?: boolean;
|
|
352
|
+
/**
|
|
353
|
+
* Optional subdirectory under the backend path to mount.
|
|
354
|
+
*/
|
|
355
|
+
subPath?: string;
|
|
356
|
+
}
|
|
278
357
|
type SandboxState = "Creating" | "Running" | "Pausing" | "Paused" | "Resuming" | "Deleting" | "Deleted" | "Error" | string;
|
|
279
358
|
interface SandboxStatus extends Record<string, unknown> {
|
|
280
359
|
state: SandboxState;
|
|
@@ -310,6 +389,10 @@ interface CreateSandboxRequest extends Record<string, unknown> {
|
|
|
310
389
|
* Optional outbound network policy for the sandbox.
|
|
311
390
|
*/
|
|
312
391
|
networkPolicy?: NetworkPolicy;
|
|
392
|
+
/**
|
|
393
|
+
* Optional list of volume mounts for persistent storage.
|
|
394
|
+
*/
|
|
395
|
+
volumes?: Volume[];
|
|
313
396
|
extensions?: Record<string, unknown>;
|
|
314
397
|
}
|
|
315
398
|
interface CreateSandboxResponse extends Record<string, unknown> {
|
|
@@ -348,6 +431,11 @@ interface RenewSandboxExpirationResponse extends Record<string, unknown> {
|
|
|
348
431
|
}
|
|
349
432
|
interface Endpoint extends Record<string, unknown> {
|
|
350
433
|
endpoint: string;
|
|
434
|
+
/**
|
|
435
|
+
* Headers that must be included on every request targeting this endpoint
|
|
436
|
+
* (e.g. when the server requires them for routing or auth). Omit or empty if not required.
|
|
437
|
+
*/
|
|
438
|
+
headers?: Record<string, string>;
|
|
351
439
|
}
|
|
352
440
|
interface ListSandboxesParams {
|
|
353
441
|
/**
|
|
@@ -372,7 +460,7 @@ interface Sandboxes {
|
|
|
372
460
|
pauseSandbox(sandboxId: SandboxId): Promise<void>;
|
|
373
461
|
resumeSandbox(sandboxId: SandboxId): Promise<void>;
|
|
374
462
|
renewSandboxExpiration(sandboxId: SandboxId, req: RenewSandboxExpirationRequest): Promise<RenewSandboxExpirationResponse>;
|
|
375
|
-
getSandboxEndpoint(sandboxId: SandboxId, port: number): Promise<Endpoint>;
|
|
463
|
+
getSandboxEndpoint(sandboxId: SandboxId, port: number, useServerProxy?: boolean): Promise<Endpoint>;
|
|
376
464
|
}
|
|
377
465
|
|
|
378
|
-
export type {
|
|
466
|
+
export type { Permission as A, PingResponse as B, CodeContextRequest as C, RenameFileItem as D, ExecdCommands as E, FileInfo as F, RenewSandboxExpirationRequest as G, Host as H, ReplaceFileContentItem as I, RunCommandOpts as J, SearchEntry as K, ListSandboxesResponse as L, Metrics as M, NetworkPolicy as N, OutputMessage as O, PVC as P, SearchFilesResponse as Q, RenewSandboxExpirationResponse as R, Sandboxes as S, SetPermissionEntry as T, SupportedLanguage as U, Volume as V, WriteEntry as W, SandboxFiles as a, ExecdHealth as b, ExecdMetrics as c, SandboxId as d, SandboxInfo as e, Execution as f, ExecutionHandlers as g, ServerStreamEvent as h, SandboxMetrics as i, Endpoint as j, CommandExecution as k, CommandLogs as l, CommandStatus as m, ContentReplaceEntry as n, CreateSandboxRequest as o, CreateSandboxResponse as p, ExecutionComplete as q, ExecutionError as r, ExecutionInit as s, ExecutionResult as t, FileMetadata as u, FilesInfoResponse as v, ListSandboxesParams as w, MoveEntry as x, NetworkRule as y, NetworkRuleAction as z };
|
package/package.json
CHANGED
|
@@ -16,7 +16,13 @@ import type { ExecdClient } from "../openapi/execdClient.js";
|
|
|
16
16
|
import { throwOnOpenApiFetchError } from "./openapiError.js";
|
|
17
17
|
import { parseJsonEventStream } from "./sse.js";
|
|
18
18
|
import type { paths as ExecdPaths } from "../api/execd.js";
|
|
19
|
-
import type {
|
|
19
|
+
import type {
|
|
20
|
+
CommandExecution,
|
|
21
|
+
CommandLogs,
|
|
22
|
+
CommandStatus,
|
|
23
|
+
RunCommandOpts,
|
|
24
|
+
ServerStreamEvent,
|
|
25
|
+
} from "../models/execd.js";
|
|
20
26
|
import type { ExecdCommands } from "../services/execdCommands.js";
|
|
21
27
|
import type { ExecutionHandlers } from "../models/execution.js";
|
|
22
28
|
import { ExecutionEventDispatcher } from "../models/executionEventDispatcher.js";
|
|
@@ -29,13 +35,34 @@ function joinUrl(baseUrl: string, pathname: string): string {
|
|
|
29
35
|
|
|
30
36
|
type ApiRunCommandRequest =
|
|
31
37
|
ExecdPaths["/command"]["post"]["requestBody"]["content"]["application/json"];
|
|
38
|
+
type ApiCommandStatusOk =
|
|
39
|
+
ExecdPaths["/command/status/{id}"]["get"]["responses"][200]["content"]["application/json"];
|
|
40
|
+
type ApiCommandLogsOk =
|
|
41
|
+
ExecdPaths["/command/{id}/logs"]["get"]["responses"][200]["content"]["text/plain"];
|
|
32
42
|
|
|
33
43
|
function toRunCommandRequest(command: string, opts?: RunCommandOpts): ApiRunCommandRequest {
|
|
34
|
-
|
|
44
|
+
const body: ApiRunCommandRequest = {
|
|
35
45
|
command,
|
|
36
46
|
cwd: opts?.workingDirectory,
|
|
37
47
|
background: !!opts?.background,
|
|
38
48
|
};
|
|
49
|
+
if (opts?.timeoutSeconds != null) {
|
|
50
|
+
body.timeout = Math.round(opts.timeoutSeconds * 1000);
|
|
51
|
+
}
|
|
52
|
+
return body;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function parseOptionalDate(value: unknown, field: string): Date | undefined {
|
|
56
|
+
if (value == null) return undefined;
|
|
57
|
+
if (value instanceof Date) return value;
|
|
58
|
+
if (typeof value !== "string") {
|
|
59
|
+
throw new Error(`Invalid ${field}: expected ISO string, got ${typeof value}`);
|
|
60
|
+
}
|
|
61
|
+
const parsed = new Date(value);
|
|
62
|
+
if (Number.isNaN(parsed.getTime())) {
|
|
63
|
+
throw new Error(`Invalid ${field}: ${value}`);
|
|
64
|
+
}
|
|
65
|
+
return parsed;
|
|
39
66
|
}
|
|
40
67
|
|
|
41
68
|
export interface CommandsAdapterOptions {
|
|
@@ -64,6 +91,44 @@ export class CommandsAdapter implements ExecdCommands {
|
|
|
64
91
|
throwOnOpenApiFetchError({ error, response }, "Interrupt command failed");
|
|
65
92
|
}
|
|
66
93
|
|
|
94
|
+
async getCommandStatus(commandId: string): Promise<CommandStatus> {
|
|
95
|
+
const { data, error, response } = await this.client.GET("/command/status/{id}", {
|
|
96
|
+
params: { path: { id: commandId } },
|
|
97
|
+
});
|
|
98
|
+
throwOnOpenApiFetchError({ error, response }, "Get command status failed");
|
|
99
|
+
const ok = data as ApiCommandStatusOk | undefined;
|
|
100
|
+
if (!ok || typeof ok !== "object") {
|
|
101
|
+
throw new Error("Get command status failed: unexpected response shape");
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
id: ok.id,
|
|
105
|
+
content: ok.content,
|
|
106
|
+
running: ok.running,
|
|
107
|
+
exitCode: ok.exit_code ?? null,
|
|
108
|
+
error: ok.error,
|
|
109
|
+
startedAt: parseOptionalDate(ok.started_at, "startedAt"),
|
|
110
|
+
finishedAt: parseOptionalDate(ok.finished_at, "finishedAt") ?? null,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async getBackgroundCommandLogs(commandId: string, cursor?: number): Promise<CommandLogs> {
|
|
115
|
+
const { data, error, response } = await this.client.GET("/command/{id}/logs", {
|
|
116
|
+
params: { path: { id: commandId }, query: cursor == null ? {} : { cursor } },
|
|
117
|
+
parseAs: "text",
|
|
118
|
+
});
|
|
119
|
+
throwOnOpenApiFetchError({ error, response }, "Get command logs failed");
|
|
120
|
+
const ok = data as ApiCommandLogsOk | undefined;
|
|
121
|
+
if (typeof ok !== "string") {
|
|
122
|
+
throw new Error("Get command logs failed: unexpected response shape");
|
|
123
|
+
}
|
|
124
|
+
const cursorHeader = response.headers.get("EXECD-COMMANDS-TAIL-CURSOR");
|
|
125
|
+
const parsedCursor = (cursorHeader != null && cursorHeader !== "") ? Number(cursorHeader) : undefined;
|
|
126
|
+
return {
|
|
127
|
+
content: ok,
|
|
128
|
+
cursor: Number.isFinite(parsedCursor ?? NaN) ? parsedCursor : undefined,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
67
132
|
async *runStream(
|
|
68
133
|
command: string,
|
|
69
134
|
opts?: RunCommandOpts,
|
|
@@ -173,9 +173,13 @@ export class SandboxesAdapter implements Sandboxes {
|
|
|
173
173
|
} as RenewSandboxExpirationResponse;
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
async getSandboxEndpoint(
|
|
176
|
+
async getSandboxEndpoint(
|
|
177
|
+
sandboxId: SandboxId,
|
|
178
|
+
port: number,
|
|
179
|
+
useServerProxy = false
|
|
180
|
+
): Promise<Endpoint> {
|
|
177
181
|
const { data, error, response } = await this.client.GET("/sandboxes/{sandboxId}/endpoints/{port}", {
|
|
178
|
-
params: { path: { sandboxId, port } },
|
|
182
|
+
params: { path: { sandboxId, port }, query: { use_server_proxy: useServerProxy } },
|
|
179
183
|
});
|
|
180
184
|
throwOnOpenApiFetchError({ error, response }, "Get sandbox endpoint failed");
|
|
181
185
|
const ok = data as ApiEndpointOk | undefined;
|
package/src/api/execd.ts
CHANGED
|
@@ -157,6 +157,8 @@ export interface paths {
|
|
|
157
157
|
* @description Executes a shell command and streams the output in real-time using SSE (Server-Sent Events).
|
|
158
158
|
* The command can run in foreground or background mode. The response includes stdout, stderr,
|
|
159
159
|
* execution status, and completion events.
|
|
160
|
+
* Optionally specify `timeout` (milliseconds) to enforce a maximum runtime; the server will
|
|
161
|
+
* terminate the process when the timeout is reached.
|
|
160
162
|
*/
|
|
161
163
|
post: operations["runCommand"];
|
|
162
164
|
/**
|
|
@@ -519,6 +521,12 @@ export interface components {
|
|
|
519
521
|
* @example false
|
|
520
522
|
*/
|
|
521
523
|
background: boolean;
|
|
524
|
+
/**
|
|
525
|
+
* Format: int64
|
|
526
|
+
* @description Maximum allowed execution time in milliseconds before the command is forcefully terminated by the server. If omitted, the server will not enforce any timeout.
|
|
527
|
+
* @example 60000
|
|
528
|
+
*/
|
|
529
|
+
timeout?: number;
|
|
522
530
|
};
|
|
523
531
|
/** @description Command execution status (foreground or background) */
|
|
524
532
|
CommandStatusResponse: {
|
package/src/api/lifecycle.ts
CHANGED
|
@@ -394,7 +394,10 @@ export interface paths {
|
|
|
394
394
|
*/
|
|
395
395
|
get: {
|
|
396
396
|
parameters: {
|
|
397
|
-
query?:
|
|
397
|
+
query?: {
|
|
398
|
+
/** @description Whether to return a server-proxied URL */
|
|
399
|
+
use_server_proxy?: boolean;
|
|
400
|
+
};
|
|
398
401
|
header?: never;
|
|
399
402
|
path: {
|
|
400
403
|
/** @description Unique sandbox identifier */
|
|
@@ -642,6 +645,12 @@ export interface components {
|
|
|
642
645
|
* the sidecar starts in allow-all mode until updated.
|
|
643
646
|
*/
|
|
644
647
|
networkPolicy?: components["schemas"]["NetworkPolicy"];
|
|
648
|
+
/**
|
|
649
|
+
* @description Storage mounts for the sandbox. Each volume entry specifies a named backend-specific
|
|
650
|
+
* storage source and common mount settings. Exactly one backend type must be specified
|
|
651
|
+
* per volume entry.
|
|
652
|
+
*/
|
|
653
|
+
volumes?: components["schemas"]["Volume"][];
|
|
645
654
|
/**
|
|
646
655
|
* @description Opaque container for provider-specific or transient parameters not supported by the core API.
|
|
647
656
|
*
|
|
@@ -715,6 +724,10 @@ export interface components {
|
|
|
715
724
|
* Example: endpoint.opensandbox.io/sandboxes/abc123/port/8080
|
|
716
725
|
*/
|
|
717
726
|
endpoint: string;
|
|
727
|
+
/** @description Requests targeting the sandbox must include the corresponding header(s). */
|
|
728
|
+
headers?: {
|
|
729
|
+
[key: string]: string;
|
|
730
|
+
};
|
|
718
731
|
};
|
|
719
732
|
/**
|
|
720
733
|
* @description Egress network policy matching the sidecar `/policy` request body.
|
|
@@ -742,6 +755,63 @@ export interface components {
|
|
|
742
755
|
*/
|
|
743
756
|
target: string;
|
|
744
757
|
};
|
|
758
|
+
/**
|
|
759
|
+
* @description Storage mount definition for a sandbox. Each volume entry contains:
|
|
760
|
+
* - A unique name identifier
|
|
761
|
+
* - Exactly one backend struct (host, pvc, etc.) with backend-specific fields
|
|
762
|
+
* - Common mount settings (mountPath, readOnly, subPath)
|
|
763
|
+
*/
|
|
764
|
+
Volume: {
|
|
765
|
+
/**
|
|
766
|
+
* @description Unique identifier for the volume within the sandbox.
|
|
767
|
+
* Must be a valid DNS label (lowercase alphanumeric, hyphens allowed, max 63 chars).
|
|
768
|
+
*/
|
|
769
|
+
name: string;
|
|
770
|
+
host?: components["schemas"]["Host"];
|
|
771
|
+
pvc?: components["schemas"]["PVC"];
|
|
772
|
+
/**
|
|
773
|
+
* @description Absolute path inside the container where the volume is mounted.
|
|
774
|
+
* Must start with '/'.
|
|
775
|
+
*/
|
|
776
|
+
mountPath: string;
|
|
777
|
+
/**
|
|
778
|
+
* @description If true, the volume is mounted as read-only. Defaults to false (read-write).
|
|
779
|
+
* @default false
|
|
780
|
+
*/
|
|
781
|
+
readOnly: boolean;
|
|
782
|
+
/**
|
|
783
|
+
* @description Optional subdirectory under the backend path to mount.
|
|
784
|
+
* Must be a relative path without '..' components.
|
|
785
|
+
*/
|
|
786
|
+
subPath?: string;
|
|
787
|
+
};
|
|
788
|
+
/**
|
|
789
|
+
* @description Host path bind mount backend. Maps a directory on the host filesystem
|
|
790
|
+
* into the container. Only available when the runtime supports host mounts.
|
|
791
|
+
*
|
|
792
|
+
* Security note: Host paths are restricted by server-side allowlist.
|
|
793
|
+
* Users must specify paths under permitted prefixes.
|
|
794
|
+
*/
|
|
795
|
+
Host: {
|
|
796
|
+
/**
|
|
797
|
+
* @description Absolute path on the host filesystem to mount.
|
|
798
|
+
* Must start with '/' and be under an allowed prefix.
|
|
799
|
+
*/
|
|
800
|
+
path: string;
|
|
801
|
+
};
|
|
802
|
+
/**
|
|
803
|
+
* @description Kubernetes PersistentVolumeClaim mount backend. References an existing
|
|
804
|
+
* PVC in the same namespace as the sandbox pod.
|
|
805
|
+
*
|
|
806
|
+
* Only available in Kubernetes runtime.
|
|
807
|
+
*/
|
|
808
|
+
PVC: {
|
|
809
|
+
/**
|
|
810
|
+
* @description Name of the PersistentVolumeClaim in the same namespace.
|
|
811
|
+
* Must be a valid Kubernetes resource name.
|
|
812
|
+
*/
|
|
813
|
+
claimName: string;
|
|
814
|
+
};
|
|
745
815
|
};
|
|
746
816
|
responses: {
|
|
747
817
|
/** @description Error response envelope */
|
package/src/config/connection.ts
CHANGED
|
@@ -45,6 +45,11 @@ export interface ConnectionConfigOptions {
|
|
|
45
45
|
* Enable basic debug logging for HTTP requests (best-effort).
|
|
46
46
|
*/
|
|
47
47
|
debug?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Use sandbox server as proxy for process execd requests.
|
|
50
|
+
* Useful when the client SDK cannot access the created sandbox directly.
|
|
51
|
+
*/
|
|
52
|
+
useServerProxy?: boolean;
|
|
48
53
|
}
|
|
49
54
|
|
|
50
55
|
function isNodeRuntime(): boolean {
|
|
@@ -253,6 +258,10 @@ export class ConnectionConfig {
|
|
|
253
258
|
readonly requestTimeoutSeconds: number;
|
|
254
259
|
readonly debug: boolean;
|
|
255
260
|
readonly userAgent: string = DEFAULT_USER_AGENT;
|
|
261
|
+
/**
|
|
262
|
+
* Use sandbox server as proxy for endpoint requests (default false).
|
|
263
|
+
*/
|
|
264
|
+
readonly useServerProxy: boolean;
|
|
256
265
|
private _closeTransport: () => Promise<void>;
|
|
257
266
|
private _closePromise: Promise<void> | null = null;
|
|
258
267
|
private _transportInitialized = false;
|
|
@@ -280,6 +289,7 @@ export class ConnectionConfig {
|
|
|
280
289
|
? opts.requestTimeoutSeconds
|
|
281
290
|
: 30;
|
|
282
291
|
this.debug = !!opts.debug;
|
|
292
|
+
this.useServerProxy = !!opts.useServerProxy;
|
|
283
293
|
|
|
284
294
|
const headers: Record<string, string> = { ...(opts.headers ?? {}) };
|
|
285
295
|
// Attach API key via header unless the user already provided one.
|
|
@@ -363,6 +373,7 @@ export class ConnectionConfig {
|
|
|
363
373
|
headers: { ...this.headers },
|
|
364
374
|
requestTimeoutSeconds: this.requestTimeoutSeconds,
|
|
365
375
|
debug: this.debug,
|
|
376
|
+
useServerProxy: this.useServerProxy,
|
|
366
377
|
});
|
|
367
378
|
clone.initializeTransport();
|
|
368
379
|
return clone;
|
package/src/core/constants.ts
CHANGED
|
@@ -26,4 +26,4 @@ export const DEFAULT_READY_TIMEOUT_SECONDS = 30;
|
|
|
26
26
|
export const DEFAULT_HEALTH_CHECK_POLLING_INTERVAL_MILLIS = 200;
|
|
27
27
|
|
|
28
28
|
export const DEFAULT_REQUEST_TIMEOUT_SECONDS = 30;
|
|
29
|
-
export const DEFAULT_USER_AGENT = "OpenSandbox-JS-SDK/0.1.
|
|
29
|
+
export const DEFAULT_USER_AGENT = "OpenSandbox-JS-SDK/0.1.4";
|
|
@@ -36,9 +36,13 @@ export class DefaultAdapterFactory implements AdapterFactory {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
createExecdStack(opts: CreateExecdStackOptions): ExecdStack {
|
|
39
|
+
const headers: Record<string, string> = {
|
|
40
|
+
...(opts.connectionConfig.headers ?? {}),
|
|
41
|
+
...(opts.endpointHeaders ?? {}),
|
|
42
|
+
};
|
|
39
43
|
const execdClient = createExecdClient({
|
|
40
44
|
baseUrl: opts.execdBaseUrl,
|
|
41
|
-
headers
|
|
45
|
+
headers,
|
|
42
46
|
fetch: opts.connectionConfig.fetch,
|
|
43
47
|
});
|
|
44
48
|
|
|
@@ -47,12 +51,12 @@ export class DefaultAdapterFactory implements AdapterFactory {
|
|
|
47
51
|
const files = new FilesystemAdapter(execdClient, {
|
|
48
52
|
baseUrl: opts.execdBaseUrl,
|
|
49
53
|
fetch: opts.connectionConfig.fetch,
|
|
50
|
-
headers
|
|
54
|
+
headers,
|
|
51
55
|
});
|
|
52
56
|
const commands = new CommandsAdapter(execdClient, {
|
|
53
57
|
baseUrl: opts.execdBaseUrl,
|
|
54
58
|
fetch: opts.connectionConfig.sseFetch,
|
|
55
|
-
headers
|
|
59
|
+
headers,
|
|
56
60
|
});
|
|
57
61
|
|
|
58
62
|
return {
|
package/src/index.ts
CHANGED
|
@@ -33,15 +33,18 @@ export type {
|
|
|
33
33
|
CreateSandboxRequest,
|
|
34
34
|
CreateSandboxResponse,
|
|
35
35
|
Endpoint,
|
|
36
|
+
Host,
|
|
36
37
|
ListSandboxesParams,
|
|
37
38
|
ListSandboxesResponse,
|
|
38
39
|
NetworkPolicy,
|
|
39
40
|
NetworkRule,
|
|
40
41
|
NetworkRuleAction,
|
|
42
|
+
PVC,
|
|
41
43
|
RenewSandboxExpirationRequest,
|
|
42
44
|
RenewSandboxExpirationResponse,
|
|
43
45
|
SandboxId,
|
|
44
46
|
SandboxInfo,
|
|
47
|
+
Volume,
|
|
45
48
|
} from "./models/sandboxes.js";
|
|
46
49
|
|
|
47
50
|
export type { Sandboxes } from "./services/sandboxes.js";
|
|
@@ -63,8 +66,9 @@ export type {
|
|
|
63
66
|
|
|
64
67
|
export type {
|
|
65
68
|
CommandExecution,
|
|
69
|
+
CommandLogs,
|
|
70
|
+
CommandStatus,
|
|
66
71
|
RunCommandOpts,
|
|
67
|
-
RunCommandRequest,
|
|
68
72
|
ServerStreamEvent,
|
|
69
73
|
CodeContextRequest,
|
|
70
74
|
SupportedLanguage,
|
package/src/models/execd.ts
CHANGED
|
@@ -37,12 +37,6 @@ export interface ServerStreamEvent extends Record<string, unknown> {
|
|
|
37
37
|
error?: Record<string, unknown>;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
export interface RunCommandRequest extends Record<string, unknown> {
|
|
41
|
-
command: string;
|
|
42
|
-
cwd?: string;
|
|
43
|
-
background?: boolean;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
40
|
export interface CodeContextRequest extends Record<string, unknown> {
|
|
47
41
|
language: string;
|
|
48
42
|
}
|
|
@@ -64,6 +58,26 @@ export interface RunCommandOpts {
|
|
|
64
58
|
* Run command in detached mode.
|
|
65
59
|
*/
|
|
66
60
|
background?: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Maximum execution time in seconds; server will terminate the command when reached.
|
|
63
|
+
* If omitted, the server will not enforce any timeout.
|
|
64
|
+
*/
|
|
65
|
+
timeoutSeconds?: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface CommandStatus {
|
|
69
|
+
id?: string;
|
|
70
|
+
content?: string;
|
|
71
|
+
running?: boolean;
|
|
72
|
+
exitCode?: number | null;
|
|
73
|
+
error?: string;
|
|
74
|
+
startedAt?: Date;
|
|
75
|
+
finishedAt?: Date | null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface CommandLogs {
|
|
79
|
+
content: string;
|
|
80
|
+
cursor?: number;
|
|
67
81
|
}
|
|
68
82
|
|
|
69
83
|
export type CommandExecution = Execution;
|
package/src/models/sandboxes.ts
CHANGED
|
@@ -62,6 +62,71 @@ export interface NetworkPolicy extends Record<string, unknown> {
|
|
|
62
62
|
egress?: NetworkRule[];
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
// ============================================================================
|
|
66
|
+
// Volume Models
|
|
67
|
+
// ============================================================================
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Host path bind mount backend.
|
|
71
|
+
*
|
|
72
|
+
* Maps a directory on the host filesystem into the container.
|
|
73
|
+
* Only available when the runtime supports host mounts.
|
|
74
|
+
*/
|
|
75
|
+
export interface Host extends Record<string, unknown> {
|
|
76
|
+
/**
|
|
77
|
+
* Absolute path on the host filesystem to mount.
|
|
78
|
+
*/
|
|
79
|
+
path: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Kubernetes PersistentVolumeClaim mount backend.
|
|
84
|
+
*
|
|
85
|
+
* References an existing PVC in the same namespace as the sandbox pod.
|
|
86
|
+
* Only available in Kubernetes runtime.
|
|
87
|
+
*/
|
|
88
|
+
export interface PVC extends Record<string, unknown> {
|
|
89
|
+
/**
|
|
90
|
+
* Name of the PersistentVolumeClaim in the same namespace.
|
|
91
|
+
*/
|
|
92
|
+
claimName: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Storage mount definition for a sandbox.
|
|
97
|
+
*
|
|
98
|
+
* Each volume entry contains:
|
|
99
|
+
* - A unique name identifier
|
|
100
|
+
* - Exactly one backend (host, pvc) with backend-specific fields
|
|
101
|
+
* - Common mount settings (mountPath, readOnly, subPath)
|
|
102
|
+
*/
|
|
103
|
+
export interface Volume extends Record<string, unknown> {
|
|
104
|
+
/**
|
|
105
|
+
* Unique identifier for the volume within the sandbox.
|
|
106
|
+
*/
|
|
107
|
+
name: string;
|
|
108
|
+
/**
|
|
109
|
+
* Host path bind mount backend (mutually exclusive with pvc).
|
|
110
|
+
*/
|
|
111
|
+
host?: Host;
|
|
112
|
+
/**
|
|
113
|
+
* Kubernetes PVC mount backend (mutually exclusive with host).
|
|
114
|
+
*/
|
|
115
|
+
pvc?: PVC;
|
|
116
|
+
/**
|
|
117
|
+
* Absolute path inside the container where the volume is mounted.
|
|
118
|
+
*/
|
|
119
|
+
mountPath: string;
|
|
120
|
+
/**
|
|
121
|
+
* If true, the volume is mounted as read-only. Defaults to false (read-write).
|
|
122
|
+
*/
|
|
123
|
+
readOnly?: boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Optional subdirectory under the backend path to mount.
|
|
126
|
+
*/
|
|
127
|
+
subPath?: string;
|
|
128
|
+
}
|
|
129
|
+
|
|
65
130
|
export type SandboxState =
|
|
66
131
|
| "Creating"
|
|
67
132
|
| "Running"
|
|
@@ -109,6 +174,10 @@ export interface CreateSandboxRequest extends Record<string, unknown> {
|
|
|
109
174
|
* Optional outbound network policy for the sandbox.
|
|
110
175
|
*/
|
|
111
176
|
networkPolicy?: NetworkPolicy;
|
|
177
|
+
/**
|
|
178
|
+
* Optional list of volume mounts for persistent storage.
|
|
179
|
+
*/
|
|
180
|
+
volumes?: Volume[];
|
|
112
181
|
extensions?: Record<string, unknown>;
|
|
113
182
|
}
|
|
114
183
|
|
|
@@ -153,6 +222,11 @@ export interface RenewSandboxExpirationResponse extends Record<string, unknown>
|
|
|
153
222
|
|
|
154
223
|
export interface Endpoint extends Record<string, unknown> {
|
|
155
224
|
endpoint: string;
|
|
225
|
+
/**
|
|
226
|
+
* Headers that must be included on every request targeting this endpoint
|
|
227
|
+
* (e.g. when the server requires them for routing or auth). Omit or empty if not required.
|
|
228
|
+
*/
|
|
229
|
+
headers?: Record<string, string>;
|
|
156
230
|
}
|
|
157
231
|
|
|
158
232
|
export interface ListSandboxesParams {
|