@alibaba-group/opensandbox 0.1.3 → 0.1.5

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/src/index.ts CHANGED
@@ -33,15 +33,19 @@ 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
+ OSSFS,
43
+ PVC,
41
44
  RenewSandboxExpirationRequest,
42
45
  RenewSandboxExpirationResponse,
43
46
  SandboxId,
44
47
  SandboxInfo,
48
+ Volume,
45
49
  } from "./models/sandboxes.js";
46
50
 
47
51
  export type { Sandboxes } from "./services/sandboxes.js";
@@ -63,8 +67,9 @@ export type {
63
67
 
64
68
  export type {
65
69
  CommandExecution,
70
+ CommandLogs,
71
+ CommandStatus,
66
72
  RunCommandOpts,
67
- RunCommandRequest,
68
73
  ServerStreamEvent,
69
74
  CodeContextRequest,
70
75
  SupportedLanguage,
@@ -87,6 +92,7 @@ export { ExecutionEventDispatcher } from "./models/executionEventDispatcher.js";
87
92
 
88
93
  export {
89
94
  DEFAULT_ENTRYPOINT,
95
+ DEFAULT_EGRESS_PORT,
90
96
  DEFAULT_EXECD_PORT,
91
97
  DEFAULT_RESOURCE_LIMITS,
92
98
  DEFAULT_TIMEOUT_SECONDS,
@@ -108,4 +114,4 @@ export type {
108
114
  SetPermissionEntry,
109
115
  WriteEntry,
110
116
  } from "./models/filesystem.js";
111
- export type { SandboxFiles } from "./services/filesystem.js";
117
+ export type { SandboxFiles } from "./services/filesystem.js";
@@ -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,38 @@ 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
+ * Unix user ID used to run the command process.
68
+ */
69
+ uid?: number;
70
+ /**
71
+ * Unix group ID used to run the command process. Requires `uid`.
72
+ */
73
+ gid?: number;
74
+ /**
75
+ * Environment variables injected into the command process.
76
+ */
77
+ envs?: Record<string, string>;
78
+ }
79
+
80
+ export interface CommandStatus {
81
+ id?: string;
82
+ content?: string;
83
+ running?: boolean;
84
+ exitCode?: number | null;
85
+ error?: string;
86
+ startedAt?: Date;
87
+ finishedAt?: Date | null;
88
+ }
89
+
90
+ export interface CommandLogs {
91
+ content: string;
92
+ cursor?: number;
67
93
  }
68
94
 
69
95
  export type CommandExecution = Execution;
@@ -54,6 +54,7 @@ export interface Execution {
54
54
  result: ExecutionResult[];
55
55
  error?: ExecutionError;
56
56
  complete?: ExecutionComplete;
57
+ exitCode?: number | null;
57
58
  }
58
59
 
59
60
  export interface ExecutionHandlers {
@@ -68,4 +69,4 @@ export interface ExecutionHandlers {
68
69
  onExecutionComplete?: (c: ExecutionComplete) => void | Promise<void>;
69
70
  onError?: (err: ExecutionError) => void | Promise<void>;
70
71
  onInit?: (init: ExecutionInit) => void | Promise<void>;
71
- }
72
+ }
@@ -62,6 +62,114 @@ 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
+ * Alibaba Cloud OSS mount backend via ossfs.
97
+ *
98
+ * The runtime mounts a host-side OSS path under `storage.ossfs_mount_root`
99
+ * so the container sees the bucket contents at the specified mount path.
100
+ *
101
+ * In Docker runtime, OSSFS backend requires OpenSandbox Server to run on a Linux host with FUSE support.
102
+ */
103
+ export interface OSSFS extends Record<string, unknown> {
104
+ /**
105
+ * OSS bucket name.
106
+ */
107
+ bucket: string;
108
+ /**
109
+ * OSS endpoint (e.g., "oss-cn-hangzhou.aliyuncs.com").
110
+ */
111
+ endpoint: string;
112
+ /**
113
+ * ossfs major version used by runtime mount integration.
114
+ * @default "2.0"
115
+ */
116
+ version?: "1.0" | "2.0";
117
+ /**
118
+ * Additional ossfs mount options.
119
+ *
120
+ * - `1.0`: mounts with `ossfs ... -o <option>`
121
+ * - `2.0`: mounts with `ossfs2 mount ... -c <config-file>` and encodes options as `--<option>` lines in the config file
122
+ */
123
+ options?: string[];
124
+ /**
125
+ * OSS access key ID for inline credentials mode.
126
+ */
127
+ accessKeyId: string;
128
+ /**
129
+ * OSS access key secret for inline credentials mode.
130
+ */
131
+ accessKeySecret: string;
132
+ }
133
+
134
+ /**
135
+ * Storage mount definition for a sandbox.
136
+ *
137
+ * Each volume entry contains:
138
+ * - A unique name identifier
139
+ * - Exactly one backend (host, pvc, ossfs) with backend-specific fields
140
+ * - Common mount settings (mountPath, readOnly, subPath)
141
+ */
142
+ export interface Volume extends Record<string, unknown> {
143
+ /**
144
+ * Unique identifier for the volume within the sandbox.
145
+ */
146
+ name: string;
147
+ /**
148
+ * Host path bind mount backend (mutually exclusive with pvc, ossfs).
149
+ */
150
+ host?: Host;
151
+ /**
152
+ * Kubernetes PVC mount backend (mutually exclusive with host, ossfs).
153
+ */
154
+ pvc?: PVC;
155
+ /**
156
+ * Alibaba Cloud OSSFS mount backend (mutually exclusive with host, pvc).
157
+ */
158
+ ossfs?: OSSFS;
159
+ /**
160
+ * Absolute path inside the container where the volume is mounted.
161
+ */
162
+ mountPath: string;
163
+ /**
164
+ * If true, the volume is mounted as read-only. Defaults to false (read-write).
165
+ */
166
+ readOnly?: boolean;
167
+ /**
168
+ * Optional subdirectory under the backend path to mount.
169
+ */
170
+ subPath?: string;
171
+ }
172
+
65
173
  export type SandboxState =
66
174
  | "Creating"
67
175
  | "Running"
@@ -92,7 +200,7 @@ export interface SandboxInfo extends Record<string, unknown> {
92
200
  /**
93
201
  * Sandbox expiration time (server-side TTL).
94
202
  */
95
- expiresAt: Date;
203
+ expiresAt: Date | null;
96
204
  }
97
205
 
98
206
  export interface CreateSandboxRequest extends Record<string, unknown> {
@@ -101,7 +209,7 @@ export interface CreateSandboxRequest extends Record<string, unknown> {
101
209
  /**
102
210
  * Timeout in seconds (server semantics).
103
211
  */
104
- timeout: number;
212
+ timeout?: number | null;
105
213
  resourceLimits: ResourceLimits;
106
214
  env?: Record<string, string>;
107
215
  metadata?: Record<string, string>;
@@ -109,6 +217,10 @@ export interface CreateSandboxRequest extends Record<string, unknown> {
109
217
  * Optional outbound network policy for the sandbox.
110
218
  */
111
219
  networkPolicy?: NetworkPolicy;
220
+ /**
221
+ * Optional list of volume mounts for persistent storage.
222
+ */
223
+ volumes?: Volume[];
112
224
  extensions?: Record<string, unknown>;
113
225
  }
114
226
 
@@ -119,7 +231,7 @@ export interface CreateSandboxResponse extends Record<string, unknown> {
119
231
  /**
120
232
  * Sandbox expiration time after creation.
121
233
  */
122
- expiresAt: Date;
234
+ expiresAt: Date | null;
123
235
  /**
124
236
  * Sandbox creation time.
125
237
  */
@@ -153,6 +265,11 @@ export interface RenewSandboxExpirationResponse extends Record<string, unknown>
153
265
 
154
266
  export interface Endpoint extends Record<string, unknown> {
155
267
  endpoint: string;
268
+ /**
269
+ * Headers that must be included on every request targeting this endpoint
270
+ * (e.g. when the server requires them for routing or auth). Omit or empty if not required.
271
+ */
272
+ headers?: Record<string, string>;
156
273
  }
157
274
 
158
275
  export interface ListSandboxesParams {
@@ -168,4 +285,4 @@ export interface ListSandboxesParams {
168
285
  metadata?: Record<string, string>;
169
286
  page?: number;
170
287
  pageSize?: number;
171
- };
288
+ };
@@ -0,0 +1,45 @@
1
+ // Copyright 2026 Alibaba Group Holding Ltd.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ import createClient from "openapi-fetch";
16
+ import type { Client } from "openapi-fetch";
17
+
18
+ import type { paths as EgressPaths } from "../api/egress.js";
19
+
20
+ export type EgressClient = Client<EgressPaths>;
21
+
22
+ export interface CreateEgressClientOptions {
23
+ /**
24
+ * Base URL to the sandbox egress sidecar API.
25
+ */
26
+ baseUrl: string;
27
+ /**
28
+ * Extra headers applied to every request.
29
+ */
30
+ headers?: Record<string, string>;
31
+ /**
32
+ * Custom fetch implementation.
33
+ */
34
+ fetch?: typeof fetch;
35
+ }
36
+
37
+ export function createEgressClient(opts: CreateEgressClientOptions): EgressClient {
38
+ const createClientFn =
39
+ (createClient as unknown as { default?: typeof createClient }).default ?? createClient;
40
+ return createClientFn<EgressPaths>({
41
+ baseUrl: opts.baseUrl,
42
+ headers: opts.headers,
43
+ fetch: opts.fetch,
44
+ });
45
+ }
package/src/sandbox.ts CHANGED
@@ -14,6 +14,7 @@
14
14
 
15
15
  import {
16
16
  DEFAULT_ENTRYPOINT,
17
+ DEFAULT_EGRESS_PORT,
17
18
  DEFAULT_EXECD_PORT,
18
19
  DEFAULT_HEALTH_CHECK_POLLING_INTERVAL_MILLIS,
19
20
  DEFAULT_READY_TIMEOUT_SECONDS,
@@ -22,6 +23,7 @@ import {
22
23
  } from "./core/constants.js";
23
24
  import { ConnectionConfig, type ConnectionConfigOptions } from "./config/connection.js";
24
25
  import type { SandboxFiles } from "./services/filesystem.js";
26
+ import type { Egress } from "./services/egress.js";
25
27
  import { createDefaultAdapterFactory } from "./factory/defaultAdapterFactory.js";
26
28
  import type { AdapterFactory } from "./factory/adapterFactory.js";
27
29
 
@@ -33,9 +35,11 @@ import type {
33
35
  CreateSandboxRequest,
34
36
  Endpoint,
35
37
  NetworkPolicy,
38
+ NetworkRule,
36
39
  RenewSandboxExpirationResponse,
37
40
  SandboxId,
38
41
  SandboxInfo,
42
+ Volume,
39
43
  } from "./models/sandboxes.js";
40
44
  import { SandboxReadyTimeoutException } from "./core/exceptions.js";
41
45
 
@@ -73,6 +77,11 @@ export interface SandboxCreateOptions {
73
77
  * If provided without defaultAction, defaults to "deny".
74
78
  */
75
79
  networkPolicy?: NetworkPolicy;
80
+ /**
81
+ * Optional list of volume mounts for persistent storage.
82
+ * Each volume specifies a backend (host path or PVC) and mount configuration.
83
+ */
84
+ volumes?: Volume[];
76
85
  /**
77
86
  * Opaque extension parameters passed through to the server as-is.
78
87
  */
@@ -85,9 +94,9 @@ export interface SandboxCreateOptions {
85
94
  */
86
95
  resource?: Record<string, string>;
87
96
  /**
88
- * Sandbox timeout in seconds.
97
+ * Sandbox timeout in seconds. Set to `null` to require explicit cleanup.
89
98
  */
90
- timeoutSeconds?: number;
99
+ timeoutSeconds?: number | null;
91
100
 
92
101
  /**
93
102
  * Skip readiness checks during create/connect.
@@ -181,6 +190,7 @@ export class Sandbox {
181
190
  adapterFactory: AdapterFactory;
182
191
  lifecycleBaseUrl: string;
183
192
  execdBaseUrl: string;
193
+ egress: Egress;
184
194
  }
185
195
  >();
186
196
 
@@ -195,6 +205,7 @@ export class Sandbox {
195
205
  files: SandboxFiles;
196
206
  health: ExecdHealth;
197
207
  metrics: ExecdMetrics;
208
+ egress: Egress;
198
209
  }) {
199
210
  this.id = opts.id;
200
211
  this.connectionConfig = opts.connectionConfig;
@@ -202,6 +213,7 @@ export class Sandbox {
202
213
  adapterFactory: opts.adapterFactory,
203
214
  lifecycleBaseUrl: opts.lifecycleBaseUrl,
204
215
  execdBaseUrl: opts.execdBaseUrl,
216
+ egress: opts.egress,
205
217
  });
206
218
 
207
219
  this.sandboxes = opts.sandboxes;
@@ -231,10 +243,37 @@ export class Sandbox {
231
243
  throw err;
232
244
  }
233
245
 
246
+ // Validate volumes: exactly one backend must be specified per volume
247
+ if (opts.volumes) {
248
+ for (const vol of opts.volumes) {
249
+ const backendsSpecified = [vol.host, vol.pvc, vol.ossfs].filter((b) => b != null).length;
250
+ if (backendsSpecified === 0) {
251
+ throw new Error(
252
+ `Volume '${vol.name}' must specify exactly one backend (host, pvc, ossfs), but none was provided.`
253
+ );
254
+ }
255
+ if (backendsSpecified > 1) {
256
+ throw new Error(
257
+ `Volume '${vol.name}' must specify exactly one backend (host, pvc, ossfs), but multiple were provided.`
258
+ );
259
+ }
260
+ }
261
+ }
262
+
263
+ const rawTimeout = opts.timeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS;
264
+ const timeoutSeconds =
265
+ opts.timeoutSeconds === null
266
+ ? null
267
+ : Math.floor(rawTimeout);
268
+ if (timeoutSeconds !== null && !Number.isFinite(timeoutSeconds)) {
269
+ throw new Error(
270
+ `timeoutSeconds must be a finite number, got ${opts.timeoutSeconds}`
271
+ );
272
+ }
273
+
234
274
  const req: CreateSandboxRequest = {
235
275
  image: toImageSpec(opts.image),
236
276
  entrypoint: opts.entrypoint ?? DEFAULT_ENTRYPOINT,
237
- timeout: Math.floor(opts.timeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS),
238
277
  resourceLimits: opts.resource ?? DEFAULT_RESOURCE_LIMITS,
239
278
  env: opts.env ?? {},
240
279
  metadata: opts.metadata ?? {},
@@ -244,8 +283,12 @@ export class Sandbox {
244
283
  defaultAction: opts.networkPolicy.defaultAction ?? "deny",
245
284
  }
246
285
  : undefined,
286
+ volumes: opts.volumes,
247
287
  extensions: opts.extensions ?? {},
248
288
  };
289
+ if (timeoutSeconds !== null) {
290
+ req.timeout = timeoutSeconds;
291
+ }
249
292
 
250
293
  let sandboxId: SandboxId | undefined;
251
294
  try {
@@ -254,15 +297,28 @@ export class Sandbox {
254
297
 
255
298
  const endpoint = await sandboxes.getSandboxEndpoint(
256
299
  sandboxId,
257
- DEFAULT_EXECD_PORT
300
+ DEFAULT_EXECD_PORT,
301
+ connectionConfig.useServerProxy
302
+ );
303
+ const egressEndpoint = await sandboxes.getSandboxEndpoint(
304
+ sandboxId,
305
+ DEFAULT_EGRESS_PORT,
306
+ connectionConfig.useServerProxy
258
307
  );
259
308
  const execdBaseUrl = `${connectionConfig.protocol}://${endpoint.endpoint}`;
309
+ const egressBaseUrl = `${connectionConfig.protocol}://${egressEndpoint.endpoint}`;
260
310
 
261
311
  const { commands, files, health, metrics } =
262
312
  adapterFactory.createExecdStack({
263
313
  connectionConfig,
264
314
  execdBaseUrl,
315
+ endpointHeaders: endpoint.headers,
265
316
  });
317
+ const { egress } = adapterFactory.createEgressStack({
318
+ connectionConfig,
319
+ egressBaseUrl,
320
+ endpointHeaders: egressEndpoint.headers,
321
+ });
266
322
 
267
323
  const sbx = new Sandbox({
268
324
  id: sandboxId,
@@ -275,6 +331,7 @@ export class Sandbox {
275
331
  files,
276
332
  health,
277
333
  metrics,
334
+ egress,
278
335
  });
279
336
 
280
337
  if (!(opts.skipHealthCheck ?? false)) {
@@ -325,14 +382,27 @@ export class Sandbox {
325
382
  try {
326
383
  const endpoint = await sandboxes.getSandboxEndpoint(
327
384
  opts.sandboxId,
328
- DEFAULT_EXECD_PORT
385
+ DEFAULT_EXECD_PORT,
386
+ connectionConfig.useServerProxy
387
+ );
388
+ const egressEndpoint = await sandboxes.getSandboxEndpoint(
389
+ opts.sandboxId,
390
+ DEFAULT_EGRESS_PORT,
391
+ connectionConfig.useServerProxy
329
392
  );
330
393
  const execdBaseUrl = `${connectionConfig.protocol}://${endpoint.endpoint}`;
394
+ const egressBaseUrl = `${connectionConfig.protocol}://${egressEndpoint.endpoint}`;
331
395
  const { commands, files, health, metrics } =
332
396
  adapterFactory.createExecdStack({
333
397
  connectionConfig,
334
398
  execdBaseUrl,
399
+ endpointHeaders: endpoint.headers,
335
400
  });
401
+ const { egress } = adapterFactory.createEgressStack({
402
+ connectionConfig,
403
+ egressBaseUrl,
404
+ endpointHeaders: egressEndpoint.headers,
405
+ });
336
406
 
337
407
  const sbx = new Sandbox({
338
408
  id: opts.sandboxId,
@@ -345,6 +415,7 @@ export class Sandbox {
345
415
  files,
346
416
  health,
347
417
  metrics,
418
+ egress,
348
419
  });
349
420
 
350
421
  if (!(opts.skipHealthCheck ?? false)) {
@@ -458,11 +529,23 @@ export class Sandbox {
458
529
  return await this.sandboxes.renewSandboxExpiration(this.id, { expiresAt });
459
530
  }
460
531
 
532
+ async getEgressPolicy(): Promise<NetworkPolicy> {
533
+ return await Sandbox._priv.get(this)!.egress.getPolicy();
534
+ }
535
+
536
+ async patchEgressRules(rules: NetworkRule[]): Promise<void> {
537
+ await Sandbox._priv.get(this)!.egress.patchRules(rules);
538
+ }
539
+
461
540
  /**
462
541
  * Get sandbox endpoint for a port (STRICT: no scheme), e.g. "localhost:44772" or "domain/route/.../44772".
463
542
  */
464
543
  async getEndpoint(port: number): Promise<Endpoint> {
465
- return await this.sandboxes.getSandboxEndpoint(this.id, port);
544
+ return await this.sandboxes.getSandboxEndpoint(
545
+ this.id,
546
+ port,
547
+ this.connectionConfig.useServerProxy
548
+ );
466
549
  }
467
550
 
468
551
  /**
@@ -479,26 +562,45 @@ export class Sandbox {
479
562
  healthCheck?: (sbx: Sandbox) => boolean | Promise<boolean>;
480
563
  }): Promise<void> {
481
564
  const deadline = Date.now() + opts.readyTimeoutSeconds * 1000;
565
+ let attempt = 0;
566
+ let errorDetail = "Health check returned false continuously.";
567
+
568
+ const buildTimeoutMessage = () => {
569
+ const context = `domain=${this.connectionConfig.domain}, useServerProxy=${this.connectionConfig.useServerProxy}`;
570
+ let suggestion =
571
+ "If this sandbox runs in Docker bridge or remote-network mode, consider enabling useServerProxy=true.";
572
+ if (!this.connectionConfig.useServerProxy) {
573
+ suggestion += " You can also configure server-side [docker].host_ip for direct endpoint access.";
574
+ }
575
+ return `Sandbox health check timed out after ${opts.readyTimeoutSeconds}s (${attempt} attempts). ${errorDetail} Connection context: ${context}. ${suggestion}`;
576
+ };
482
577
 
483
578
  // Wait until execd becomes reachable and passes health check.
484
579
  while (true) {
485
580
  if (Date.now() > deadline) {
486
581
  throw new SandboxReadyTimeoutException({
487
- message: `Sandbox not ready: timed out waiting for health check (timeoutSeconds=${opts.readyTimeoutSeconds})`,
582
+ message: buildTimeoutMessage(),
488
583
  });
489
584
  }
585
+ attempt++;
490
586
  try {
491
587
  if (opts.healthCheck) {
492
588
  const ok = await opts.healthCheck(this);
493
- if (ok) return;
589
+ if (ok) {
590
+ return;
591
+ }
494
592
  } else {
495
593
  const ok = await this.health.ping();
496
- if (ok) return;
594
+ if (ok) {
595
+ return;
596
+ }
497
597
  }
498
- } catch {
499
- // ignore and retry
598
+ errorDetail = "Health check returned false continuously.";
599
+ } catch (err) {
600
+ const message = err instanceof Error ? err.message : String(err);
601
+ errorDetail = `Last health check error: ${message}`;
500
602
  }
501
603
  await sleep(opts.pollingIntervalMillis);
502
604
  }
503
605
  }
504
- }
606
+ }
@@ -0,0 +1,27 @@
1
+ // Copyright 2026 Alibaba Group Holding Ltd.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ import type { NetworkPolicy, NetworkRule } from "../models/sandboxes.js";
16
+
17
+ export interface Egress {
18
+ getPolicy(): Promise<NetworkPolicy>;
19
+ /**
20
+ * Patch egress rules with sidecar merge semantics.
21
+ *
22
+ * Incoming rules take priority over existing rules with the same target.
23
+ * Existing rules for other targets remain unchanged. Within one patch payload,
24
+ * the first rule for a target wins. The current defaultAction is preserved.
25
+ */
26
+ patchRules(rules: NetworkRule[]): Promise<void>;
27
+ }
@@ -13,7 +13,13 @@
13
13
  // limitations under the License.
14
14
 
15
15
  import type { ExecutionHandlers } from "../models/execution.js";
16
- import type { CommandExecution, RunCommandOpts, ServerStreamEvent } from "../models/execd.js";
16
+ import type {
17
+ CommandExecution,
18
+ CommandLogs,
19
+ CommandStatus,
20
+ RunCommandOpts,
21
+ ServerStreamEvent,
22
+ } from "../models/execd.js";
17
23
 
18
24
  export interface ExecdCommands {
19
25
  /**
@@ -32,4 +38,37 @@ export interface ExecdCommands {
32
38
  * Note: Execd spec uses `DELETE /command?id=<sessionId>`.
33
39
  */
34
40
  interrupt(sessionId: string): Promise<void>;
35
- }
41
+
42
+ /**
43
+ * Get the current running status for a command id.
44
+ */
45
+ getCommandStatus(commandId: string): Promise<CommandStatus>;
46
+
47
+ /**
48
+ * Get background command logs (non-streamed).
49
+ */
50
+ getBackgroundCommandLogs(commandId: string, cursor?: number): Promise<CommandLogs>;
51
+
52
+ /**
53
+ * Create a bash session with optional working directory.
54
+ * Returns session ID for use with runInSession and deleteSession.
55
+ */
56
+ createSession(options?: { workingDirectory?: string }): Promise<string>;
57
+
58
+ /**
59
+ * Run a shell command in an existing bash session (SSE stream, same event shape as run).
60
+ * Optional workingDirectory and timeout apply to this run only; session state (e.g. env) persists.
61
+ */
62
+ runInSession(
63
+ sessionId: string,
64
+ command: string,
65
+ options?: { workingDirectory?: string; timeout?: number },
66
+ handlers?: ExecutionHandlers,
67
+ signal?: AbortSignal,
68
+ ): Promise<CommandExecution>;
69
+
70
+ /**
71
+ * Delete a bash session by ID. Frees resources; session ID must have been returned by createSession.
72
+ */
73
+ deleteSession(sessionId: string): Promise<void>;
74
+ }
@@ -38,5 +38,9 @@ export interface Sandboxes {
38
38
  req: RenewSandboxExpirationRequest,
39
39
  ): Promise<RenewSandboxExpirationResponse>;
40
40
 
41
- getSandboxEndpoint(sandboxId: SandboxId, port: number): Promise<Endpoint>;
42
- }
41
+ getSandboxEndpoint(
42
+ sandboxId: SandboxId,
43
+ port: number,
44
+ useServerProxy?: boolean
45
+ ): Promise<Endpoint>;
46
+ }