@alibaba-group/opensandbox 0.1.4 → 0.1.6

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/index.js CHANGED
@@ -13,8 +13,43 @@ import {
13
13
  SandboxUnhealthyException,
14
14
  SandboxesAdapter,
15
15
  createExecdClient,
16
- createLifecycleClient
17
- } from "./chunk-OYTPXLWE.js";
16
+ createLifecycleClient,
17
+ throwOnOpenApiFetchError
18
+ } from "./chunk-AFWIGM3C.js";
19
+
20
+ // src/openapi/egressClient.ts
21
+ import createClient from "openapi-fetch";
22
+ function createEgressClient(opts) {
23
+ const createClientFn = createClient.default ?? createClient;
24
+ return createClientFn({
25
+ baseUrl: opts.baseUrl,
26
+ headers: opts.headers,
27
+ fetch: opts.fetch
28
+ });
29
+ }
30
+
31
+ // src/adapters/egressAdapter.ts
32
+ var EgressAdapter = class {
33
+ constructor(client) {
34
+ this.client = client;
35
+ }
36
+ async getPolicy() {
37
+ const { data, error, response } = await this.client.GET("/policy");
38
+ throwOnOpenApiFetchError({ error, response }, "Get sandbox egress policy failed");
39
+ const raw = data;
40
+ if (!raw || typeof raw !== "object" || !raw.policy || typeof raw.policy !== "object") {
41
+ throw new Error("Get sandbox egress policy failed: unexpected response shape");
42
+ }
43
+ return raw.policy;
44
+ }
45
+ async patchRules(rules) {
46
+ const body = rules;
47
+ const { error, response } = await this.client.PATCH("/policy", {
48
+ body
49
+ });
50
+ throwOnOpenApiFetchError({ error, response }, "Patch sandbox egress rules failed");
51
+ }
52
+ };
18
53
 
19
54
  // src/factory/defaultAdapterFactory.ts
20
55
  var DefaultAdapterFactory = class {
@@ -57,6 +92,20 @@ var DefaultAdapterFactory = class {
57
92
  metrics
58
93
  };
59
94
  }
95
+ createEgressStack(opts) {
96
+ const headers = {
97
+ ...opts.connectionConfig.headers ?? {},
98
+ ...opts.endpointHeaders ?? {}
99
+ };
100
+ const egressClient = createEgressClient({
101
+ baseUrl: opts.egressBaseUrl,
102
+ headers,
103
+ fetch: opts.connectionConfig.fetch
104
+ });
105
+ return {
106
+ egress: new EgressAdapter(egressClient)
107
+ };
108
+ }
60
109
  };
61
110
  function createDefaultAdapterFactory() {
62
111
  return new DefaultAdapterFactory();
@@ -64,6 +113,7 @@ function createDefaultAdapterFactory() {
64
113
 
65
114
  // src/core/constants.ts
66
115
  var DEFAULT_EXECD_PORT = 44772;
116
+ var DEFAULT_EGRESS_PORT = 18080;
67
117
  var DEFAULT_ENTRYPOINT = ["tail", "-f", "/dev/null"];
68
118
  var DEFAULT_RESOURCE_LIMITS = {
69
119
  cpu: "1",
@@ -73,7 +123,7 @@ var DEFAULT_TIMEOUT_SECONDS = 600;
73
123
  var DEFAULT_READY_TIMEOUT_SECONDS = 30;
74
124
  var DEFAULT_HEALTH_CHECK_POLLING_INTERVAL_MILLIS = 200;
75
125
  var DEFAULT_REQUEST_TIMEOUT_SECONDS = 30;
76
- var DEFAULT_USER_AGENT = "OpenSandbox-JS-SDK/0.1.4";
126
+ var DEFAULT_USER_AGENT = "OpenSandbox-JS-SDK/0.1.6";
77
127
 
78
128
  // src/config/connection.ts
79
129
  function isNodeRuntime() {
@@ -394,6 +444,7 @@ var SandboxManager = class _SandboxManager {
394
444
  };
395
445
 
396
446
  // src/sandbox.ts
447
+ var HOST_PATH_PATTERN = /^([/]|[A-Za-z]:[\\/])/;
397
448
  function sleep(ms) {
398
449
  return new Promise((r) => setTimeout(r, ms));
399
450
  }
@@ -430,7 +481,8 @@ var Sandbox = class _Sandbox {
430
481
  _Sandbox._priv.set(this, {
431
482
  adapterFactory: opts.adapterFactory,
432
483
  lifecycleBaseUrl: opts.lifecycleBaseUrl,
433
- execdBaseUrl: opts.execdBaseUrl
484
+ execdBaseUrl: opts.execdBaseUrl,
485
+ egress: opts.egress
434
486
  });
435
487
  this.sandboxes = opts.sandboxes;
436
488
  this.commands = opts.commands;
@@ -439,6 +491,26 @@ var Sandbox = class _Sandbox {
439
491
  this.metrics = opts.metrics;
440
492
  }
441
493
  static async create(opts) {
494
+ if (opts.volumes) {
495
+ for (const vol of opts.volumes) {
496
+ const backendsSpecified = [vol.host, vol.pvc, vol.ossfs].filter((b) => b != null).length;
497
+ if (backendsSpecified === 0) {
498
+ throw new Error(
499
+ `Volume '${vol.name}' must specify exactly one backend (host, pvc, ossfs), but none was provided.`
500
+ );
501
+ }
502
+ if (backendsSpecified > 1) {
503
+ throw new Error(
504
+ `Volume '${vol.name}' must specify exactly one backend (host, pvc, ossfs), but multiple were provided.`
505
+ );
506
+ }
507
+ if (vol.host && !HOST_PATH_PATTERN.test(vol.host.path)) {
508
+ throw new Error(
509
+ "Host path must be an absolute path starting with '/' or a Windows drive letter (e.g. 'C:\\' or 'D:/')"
510
+ );
511
+ }
512
+ }
513
+ }
442
514
  const baseConnectionConfig = opts.connectionConfig instanceof ConnectionConfig ? opts.connectionConfig : new ConnectionConfig(opts.connectionConfig);
443
515
  const connectionConfig = baseConnectionConfig.withTransportIfMissing();
444
516
  const lifecycleBaseUrl = connectionConfig.getBaseUrl();
@@ -453,25 +525,16 @@ var Sandbox = class _Sandbox {
453
525
  await connectionConfig.closeTransport();
454
526
  throw err;
455
527
  }
456
- if (opts.volumes) {
457
- for (const vol of opts.volumes) {
458
- const backendsSpecified = [vol.host, vol.pvc].filter((b) => b !== void 0).length;
459
- if (backendsSpecified === 0) {
460
- throw new Error(
461
- `Volume '${vol.name}' must specify exactly one backend (host, pvc), but none was provided.`
462
- );
463
- }
464
- if (backendsSpecified > 1) {
465
- throw new Error(
466
- `Volume '${vol.name}' must specify exactly one backend (host, pvc), but multiple were provided.`
467
- );
468
- }
469
- }
528
+ const rawTimeout = opts.timeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS;
529
+ const timeoutSeconds = opts.timeoutSeconds === null ? null : Math.floor(rawTimeout);
530
+ if (timeoutSeconds !== null && !Number.isFinite(timeoutSeconds)) {
531
+ throw new Error(
532
+ `timeoutSeconds must be a finite number, got ${opts.timeoutSeconds}`
533
+ );
470
534
  }
471
535
  const req = {
472
536
  image: toImageSpec(opts.image),
473
537
  entrypoint: opts.entrypoint ?? DEFAULT_ENTRYPOINT,
474
- timeout: Math.floor(opts.timeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS),
475
538
  resourceLimits: opts.resource ?? DEFAULT_RESOURCE_LIMITS,
476
539
  env: opts.env ?? {},
477
540
  metadata: opts.metadata ?? {},
@@ -482,6 +545,9 @@ var Sandbox = class _Sandbox {
482
545
  volumes: opts.volumes,
483
546
  extensions: opts.extensions ?? {}
484
547
  };
548
+ if (timeoutSeconds !== null) {
549
+ req.timeout = timeoutSeconds;
550
+ }
485
551
  let sandboxId;
486
552
  try {
487
553
  const created = await sandboxes.createSandbox(req);
@@ -491,12 +557,23 @@ var Sandbox = class _Sandbox {
491
557
  DEFAULT_EXECD_PORT,
492
558
  connectionConfig.useServerProxy
493
559
  );
560
+ const egressEndpoint = await sandboxes.getSandboxEndpoint(
561
+ sandboxId,
562
+ DEFAULT_EGRESS_PORT,
563
+ connectionConfig.useServerProxy
564
+ );
494
565
  const execdBaseUrl = `${connectionConfig.protocol}://${endpoint.endpoint}`;
566
+ const egressBaseUrl = `${connectionConfig.protocol}://${egressEndpoint.endpoint}`;
495
567
  const { commands, files, health, metrics } = adapterFactory.createExecdStack({
496
568
  connectionConfig,
497
569
  execdBaseUrl,
498
570
  endpointHeaders: endpoint.headers
499
571
  });
572
+ const { egress } = adapterFactory.createEgressStack({
573
+ connectionConfig,
574
+ egressBaseUrl,
575
+ endpointHeaders: egressEndpoint.headers
576
+ });
500
577
  const sbx = new _Sandbox({
501
578
  id: sandboxId,
502
579
  connectionConfig,
@@ -507,7 +584,8 @@ var Sandbox = class _Sandbox {
507
584
  commands,
508
585
  files,
509
586
  health,
510
- metrics
587
+ metrics,
588
+ egress
511
589
  });
512
590
  if (!(opts.skipHealthCheck ?? false)) {
513
591
  await sbx.waitUntilReady({
@@ -549,12 +627,23 @@ var Sandbox = class _Sandbox {
549
627
  DEFAULT_EXECD_PORT,
550
628
  connectionConfig.useServerProxy
551
629
  );
630
+ const egressEndpoint = await sandboxes.getSandboxEndpoint(
631
+ opts.sandboxId,
632
+ DEFAULT_EGRESS_PORT,
633
+ connectionConfig.useServerProxy
634
+ );
552
635
  const execdBaseUrl = `${connectionConfig.protocol}://${endpoint.endpoint}`;
636
+ const egressBaseUrl = `${connectionConfig.protocol}://${egressEndpoint.endpoint}`;
553
637
  const { commands, files, health, metrics } = adapterFactory.createExecdStack({
554
638
  connectionConfig,
555
639
  execdBaseUrl,
556
640
  endpointHeaders: endpoint.headers
557
641
  });
642
+ const { egress } = adapterFactory.createEgressStack({
643
+ connectionConfig,
644
+ egressBaseUrl,
645
+ endpointHeaders: egressEndpoint.headers
646
+ });
558
647
  const sbx = new _Sandbox({
559
648
  id: opts.sandboxId,
560
649
  connectionConfig,
@@ -565,7 +654,8 @@ var Sandbox = class _Sandbox {
565
654
  commands,
566
655
  files,
567
656
  health,
568
- metrics
657
+ metrics,
658
+ egress
569
659
  });
570
660
  if (!(opts.skipHealthCheck ?? false)) {
571
661
  await sbx.waitUntilReady({
@@ -653,6 +743,12 @@ var Sandbox = class _Sandbox {
653
743
  ).toISOString();
654
744
  return await this.sandboxes.renewSandboxExpiration(this.id, { expiresAt });
655
745
  }
746
+ async getEgressPolicy() {
747
+ return await _Sandbox._priv.get(this).egress.getPolicy();
748
+ }
749
+ async patchEgressRules(rules) {
750
+ await _Sandbox._priv.get(this).egress.patchRules(rules);
751
+ }
656
752
  /**
657
753
  * Get sandbox endpoint for a port (STRICT: no scheme), e.g. "localhost:44772" or "domain/route/.../44772".
658
754
  */
@@ -672,21 +768,39 @@ var Sandbox = class _Sandbox {
672
768
  }
673
769
  async waitUntilReady(opts) {
674
770
  const deadline = Date.now() + opts.readyTimeoutSeconds * 1e3;
771
+ let attempt = 0;
772
+ let errorDetail = "Health check returned false continuously.";
773
+ const buildTimeoutMessage = () => {
774
+ const context = `domain=${this.connectionConfig.domain}, useServerProxy=${this.connectionConfig.useServerProxy}`;
775
+ let suggestion = "If this sandbox runs in Docker bridge or remote-network mode, consider enabling useServerProxy=true.";
776
+ if (!this.connectionConfig.useServerProxy) {
777
+ suggestion += " You can also configure server-side [docker].host_ip for direct endpoint access.";
778
+ }
779
+ return `Sandbox health check timed out after ${opts.readyTimeoutSeconds}s (${attempt} attempts). ${errorDetail} Connection context: ${context}. ${suggestion}`;
780
+ };
675
781
  while (true) {
676
782
  if (Date.now() > deadline) {
677
783
  throw new SandboxReadyTimeoutException({
678
- message: `Sandbox not ready: timed out waiting for health check (timeoutSeconds=${opts.readyTimeoutSeconds})`
784
+ message: buildTimeoutMessage()
679
785
  });
680
786
  }
787
+ attempt++;
681
788
  try {
682
789
  if (opts.healthCheck) {
683
790
  const ok = await opts.healthCheck(this);
684
- if (ok) return;
791
+ if (ok) {
792
+ return;
793
+ }
685
794
  } else {
686
795
  const ok = await this.health.ping();
687
- if (ok) return;
796
+ if (ok) {
797
+ return;
798
+ }
688
799
  }
689
- } catch {
800
+ errorDetail = "Health check returned false continuously.";
801
+ } catch (err) {
802
+ const message = err instanceof Error ? err.message : String(err);
803
+ errorDetail = `Last health check error: ${message}`;
690
804
  }
691
805
  await sleep(opts.pollingIntervalMillis);
692
806
  }
@@ -694,6 +808,7 @@ var Sandbox = class _Sandbox {
694
808
  };
695
809
  export {
696
810
  ConnectionConfig,
811
+ DEFAULT_EGRESS_PORT,
697
812
  DEFAULT_ENTRYPOINT,
698
813
  DEFAULT_EXECD_PORT,
699
814
  DEFAULT_HEALTH_CHECK_POLLING_INTERVAL_MILLIS,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/factory/defaultAdapterFactory.ts","../src/core/constants.ts","../src/config/connection.ts","../src/manager.ts","../src/sandbox.ts"],"sourcesContent":["// Copyright 2026 Alibaba Group Holding Ltd.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n// http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { createExecdClient } from \"../openapi/execdClient.js\";\nimport { createLifecycleClient } from \"../openapi/lifecycleClient.js\";\n\nimport { CommandsAdapter } from \"../adapters/commandsAdapter.js\";\nimport { FilesystemAdapter } from \"../adapters/filesystemAdapter.js\";\nimport { HealthAdapter } from \"../adapters/healthAdapter.js\";\nimport { MetricsAdapter } from \"../adapters/metricsAdapter.js\";\nimport { SandboxesAdapter } from \"../adapters/sandboxesAdapter.js\";\n\nimport type { AdapterFactory, CreateExecdStackOptions, CreateLifecycleStackOptions, ExecdStack, LifecycleStack } from \"./adapterFactory.js\";\n\nexport class DefaultAdapterFactory implements AdapterFactory {\n createLifecycleStack(opts: CreateLifecycleStackOptions): LifecycleStack {\n const lifecycleClient = createLifecycleClient({\n baseUrl: opts.lifecycleBaseUrl,\n apiKey: opts.connectionConfig.apiKey,\n headers: opts.connectionConfig.headers,\n fetch: opts.connectionConfig.fetch,\n });\n const sandboxes = new SandboxesAdapter(lifecycleClient);\n return { sandboxes };\n }\n\n createExecdStack(opts: CreateExecdStackOptions): ExecdStack {\n const headers: Record<string, string> = {\n ...(opts.connectionConfig.headers ?? {}),\n ...(opts.endpointHeaders ?? {}),\n };\n const execdClient = createExecdClient({\n baseUrl: opts.execdBaseUrl,\n headers,\n fetch: opts.connectionConfig.fetch,\n });\n\n const health = new HealthAdapter(execdClient);\n const metrics = new MetricsAdapter(execdClient);\n const files = new FilesystemAdapter(execdClient, {\n baseUrl: opts.execdBaseUrl,\n fetch: opts.connectionConfig.fetch,\n headers,\n });\n const commands = new CommandsAdapter(execdClient, {\n baseUrl: opts.execdBaseUrl,\n fetch: opts.connectionConfig.sseFetch,\n headers,\n });\n\n return {\n commands,\n files,\n health,\n metrics,\n };\n }\n}\n\nexport function createDefaultAdapterFactory(): AdapterFactory {\n return new DefaultAdapterFactory();\n}","// Copyright 2026 Alibaba Group Holding Ltd.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n// http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nexport const DEFAULT_EXECD_PORT = 44772;\n\nexport const DEFAULT_ENTRYPOINT: string[] = [\"tail\", \"-f\", \"/dev/null\"];\n\nexport const DEFAULT_RESOURCE_LIMITS: Record<string, string> = {\n cpu: \"1\",\n memory: \"2Gi\",\n};\n\nexport const DEFAULT_TIMEOUT_SECONDS = 600;\nexport const DEFAULT_READY_TIMEOUT_SECONDS = 30;\nexport const DEFAULT_HEALTH_CHECK_POLLING_INTERVAL_MILLIS = 200;\n\nexport const DEFAULT_REQUEST_TIMEOUT_SECONDS = 30;\nexport const DEFAULT_USER_AGENT = \"OpenSandbox-JS-SDK/0.1.4\";","// Copyright 2026 Alibaba Group Holding Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport {DEFAULT_USER_AGENT} from \"../core/constants.js\";\n\nexport type ConnectionProtocol = \"http\" | \"https\";\n\n/**\n * Options for {@link ConnectionConfig}.\n *\n * Most users only need `domain`, `protocol`, and `apiKey`.\n */\nexport interface ConnectionConfigOptions {\n /**\n * API server domain (host[:port]) without scheme.\n * Examples:\n * - \"localhost:8080\"\n * - \"api.opensandbox.io\"\n *\n * You may also pass a full URL (e.g. \"http://localhost:8080\" or \"https://api.example.com\").\n * If the URL includes a path, it will be preserved and `/v1` will be appended automatically.\n */\n domain?: string;\n protocol?: ConnectionProtocol;\n apiKey?: string;\n headers?: Record<string, string>;\n\n /**\n * Request timeout applied to all SDK HTTP calls (best-effort; wraps fetch).\n * Defaults to 30 seconds.\n */\n requestTimeoutSeconds?: number;\n /**\n * Enable basic debug logging for HTTP requests (best-effort).\n */\n debug?: boolean;\n /**\n * Use sandbox server as proxy for process execd requests.\n * Useful when the client SDK cannot access the created sandbox directly.\n */\n useServerProxy?: boolean;\n}\n\nfunction isNodeRuntime(): boolean {\n const p = (globalThis as any)?.process;\n return !!p?.versions?.node;\n}\n\nfunction redactHeaders(\n headers: Record<string, string>\n): Record<string, string> {\n const out: Record<string, string> = { ...headers };\n for (const k of Object.keys(out)) {\n if (k.toLowerCase() === \"open-sandbox-api-key\") out[k] = \"***\";\n }\n return out;\n}\n\nfunction readEnv(name: string): string | undefined {\n const env = (globalThis as any)?.process?.env;\n const v = env?.[name];\n return typeof v === \"string\" && v.length ? v : undefined;\n}\n\nfunction stripTrailingSlashes(s: string): string {\n return s.replace(/\\/+$/, \"\");\n}\n\nfunction stripV1Suffix(s: string): string {\n const trimmed = stripTrailingSlashes(s);\n return trimmed.endsWith(\"/v1\") ? trimmed.slice(0, -3) : trimmed;\n}\n\nconst DEFAULT_KEEPALIVE_TIMEOUT_MS = 30_000;\n\nfunction normalizeDomainBase(input: string): {\n protocol?: ConnectionProtocol;\n domainBase: string;\n} {\n // Accept a full URL and preserve its path prefix (if any).\n if (input.startsWith(\"http://\") || input.startsWith(\"https://\")) {\n const u = new URL(input);\n const proto = u.protocol === \"https:\" ? \"https\" : \"http\";\n // Keep origin + pathname, drop query/hash.\n const base = `${u.origin}${u.pathname}`;\n return { protocol: proto, domainBase: stripV1Suffix(base) };\n }\n\n // No scheme: treat as \"host[:port]\" or \"host[:port]/prefix\" and normalize trailing \"/v1\" or \"/\".\n return { domainBase: stripV1Suffix(input) };\n}\n\nfunction createNodeFetch(): {\n fetch: typeof fetch;\n close: () => Promise<void>;\n} {\n if (!isNodeRuntime()) {\n return {\n fetch,\n close: async () => {\n // Browser fetch has no pooled dispatcher to close.\n },\n };\n }\n\n const baseFetch = fetch;\n let dispatcher: unknown | undefined;\n let dispatcherPromise: Promise<unknown> | null = null;\n\n const nodeFetch: typeof fetch = async (input: RequestInfo | URL, init?: RequestInit) => {\n dispatcherPromise ??= (async () => {\n try {\n const mod = await import(\"undici\");\n const Agent = (mod as { Agent?: new (...args: any[]) => unknown }).Agent;\n if (!Agent) {\n return undefined;\n }\n dispatcher = new Agent({\n keepAliveTimeout: DEFAULT_KEEPALIVE_TIMEOUT_MS,\n keepAliveMaxTimeout: DEFAULT_KEEPALIVE_TIMEOUT_MS,\n });\n return dispatcher;\n } catch {\n return undefined;\n }\n })();\n\n if (dispatcherPromise) {\n await dispatcherPromise;\n }\n\n if (dispatcher) {\n const mergedInit = { ...(init ?? {}), dispatcher } as RequestInit & {\n dispatcher?: unknown;\n };\n return baseFetch(input, mergedInit as RequestInit);\n }\n\n return baseFetch(input, init);\n };\n\n return {\n fetch: nodeFetch,\n close: async () => {\n if (dispatcherPromise) {\n await dispatcherPromise.catch(() => undefined);\n }\n if (\n dispatcher &&\n typeof dispatcher === \"object\" &&\n typeof (dispatcher as any).close === \"function\"\n ) {\n try {\n await (dispatcher as any).close();\n } catch {\n // swallow close errors\n }\n }\n },\n };\n}\n\nfunction createTimedFetch(opts: {\n baseFetch: typeof fetch;\n timeoutSeconds: number;\n debug: boolean;\n defaultHeaders?: Record<string, string>;\n label: string;\n}): typeof fetch {\n const baseFetch = opts.baseFetch;\n const timeoutSeconds = opts.timeoutSeconds;\n const debug = opts.debug;\n const defaultHeaders = opts.defaultHeaders ?? {};\n const label = opts.label;\n\n return async (input: RequestInfo | URL, init?: RequestInit) => {\n const method = init?.method ?? \"GET\";\n const url =\n typeof input === \"string\"\n ? input\n : (input as any)?.toString?.() ?? String(input);\n\n const ac = new AbortController();\n const timeoutMs = Math.floor(timeoutSeconds * 1000);\n const t =\n Number.isFinite(timeoutMs) && timeoutMs > 0\n ? setTimeout(\n () =>\n ac.abort(\n new Error(\n `[${label}] Request timed out (timeoutSeconds=${timeoutSeconds})`\n )\n ),\n timeoutMs\n )\n : undefined;\n\n const onAbort = () =>\n ac.abort((init?.signal as any)?.reason ?? new Error(\"Aborted\"));\n if (init?.signal) {\n if (init.signal.aborted) onAbort();\n else\n init.signal.addEventListener(\"abort\", onAbort, { once: true } as any);\n }\n\n const mergedInit: RequestInit = {\n ...init,\n signal: ac.signal,\n };\n\n if (debug) {\n const mergedHeaders = {\n ...defaultHeaders,\n ...((init?.headers ?? {}) as any),\n };\n // eslint-disable-next-line no-console\n console.log(\n `[opensandbox:${label}] ->`,\n method,\n url,\n redactHeaders(mergedHeaders)\n );\n }\n\n try {\n const res = await baseFetch(input, mergedInit);\n if (debug) {\n // eslint-disable-next-line no-console\n console.log(`[opensandbox:${label}] <-`, method, url, res.status);\n }\n return res;\n } finally {\n if (t) clearTimeout(t);\n if (init?.signal)\n init.signal.removeEventListener(\"abort\", onAbort as any);\n }\n };\n}\n\nexport class ConnectionConfig {\n readonly protocol: ConnectionProtocol;\n readonly domain: string;\n readonly apiKey?: string;\n readonly headers: Record<string, string>;\n private _fetch: typeof fetch | null;\n private _sseFetch: typeof fetch | null;\n readonly requestTimeoutSeconds: number;\n readonly debug: boolean;\n readonly userAgent: string = DEFAULT_USER_AGENT;\n /**\n * Use sandbox server as proxy for endpoint requests (default false).\n */\n readonly useServerProxy: boolean;\n private _closeTransport: () => Promise<void>;\n private _closePromise: Promise<void> | null = null;\n private _transportInitialized = false;\n\n /**\n * Create a connection configuration.\n *\n * Environment variables (optional):\n * - `OPEN_SANDBOX_DOMAIN` (default: `localhost:8080`)\n * - `OPEN_SANDBOX_API_KEY`\n */\n constructor(opts: ConnectionConfigOptions = {}) {\n const envDomain = readEnv(\"OPEN_SANDBOX_DOMAIN\");\n const envApiKey = readEnv(\"OPEN_SANDBOX_API_KEY\");\n\n const rawDomain = opts.domain ?? envDomain ?? \"localhost:8080\";\n const normalized = normalizeDomainBase(rawDomain);\n\n // If the domain includes a scheme, it overrides `protocol`.\n this.protocol = normalized.protocol ?? opts.protocol ?? \"http\";\n this.domain = normalized.domainBase;\n this.apiKey = opts.apiKey ?? envApiKey;\n this.requestTimeoutSeconds =\n typeof opts.requestTimeoutSeconds === \"number\"\n ? opts.requestTimeoutSeconds\n : 30;\n this.debug = !!opts.debug;\n this.useServerProxy = !!opts.useServerProxy;\n\n const headers: Record<string, string> = { ...(opts.headers ?? {}) };\n // Attach API key via header unless the user already provided one.\n if (this.apiKey && !headers[\"OPEN-SANDBOX-API-KEY\"]) {\n headers[\"OPEN-SANDBOX-API-KEY\"] = this.apiKey;\n }\n // Best-effort user-agent (Node only).\n if (\n isNodeRuntime() &&\n this.userAgent &&\n !headers[\"user-agent\"] &&\n !headers[\"User-Agent\"]\n ) {\n headers[\"user-agent\"] = this.userAgent;\n }\n this.headers = headers;\n this._fetch = null;\n this._sseFetch = null;\n this._closeTransport = async () => {\n // Init with empty close call\n };\n this._transportInitialized = false;\n }\n\n get fetch(): typeof fetch {\n return this._fetch ?? fetch;\n }\n\n get sseFetch(): typeof fetch {\n return this._sseFetch ?? fetch;\n }\n\n getBaseUrl(): string {\n // If `domain` already contains a scheme, treat it as a full base URL prefix.\n if (\n this.domain.startsWith(\"http://\") ||\n this.domain.startsWith(\"https://\")\n ) {\n return `${stripV1Suffix(this.domain)}/v1`;\n }\n return `${this.protocol}://${stripV1Suffix(this.domain)}/v1`;\n }\n\n private initializeTransport(): void {\n if (this._transportInitialized) return;\n\n const { fetch: baseFetch, close } = createNodeFetch();\n this._fetch = createTimedFetch({\n baseFetch,\n timeoutSeconds: this.requestTimeoutSeconds,\n debug: this.debug,\n defaultHeaders: this.headers,\n label: \"http\",\n });\n this._sseFetch = createTimedFetch({\n baseFetch,\n timeoutSeconds: 0,\n debug: this.debug,\n defaultHeaders: this.headers,\n label: \"sse\",\n });\n this._closeTransport = close;\n this._transportInitialized = true;\n }\n /**\n * Ensure this configuration has transport helpers (fetch/SSE) allocated.\n *\n * On Node.js this creates a dedicated `undici` dispatcher; on browsers it\n * simply reuses the global fetch. Returns either `this` or a cloned config\n * with the transport initialized.\n */\n withTransportIfMissing(): ConnectionConfig {\n if (this._transportInitialized) {\n return this;\n }\n\n const clone = new ConnectionConfig({\n domain: this.domain,\n protocol: this.protocol,\n apiKey: this.apiKey,\n headers: { ...this.headers },\n requestTimeoutSeconds: this.requestTimeoutSeconds,\n debug: this.debug,\n useServerProxy: this.useServerProxy,\n });\n clone.initializeTransport();\n return clone;\n }\n\n /**\n * Close the Node.js agent owned by this configuration.\n */\n async closeTransport(): Promise<void> {\n if (!this._transportInitialized) return;\n this._closePromise ??= this._closeTransport();\n await this._closePromise;\n }\n}\n","// Copyright 2026 Alibaba Group Holding Ltd.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n// http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { ConnectionConfig, type ConnectionConfigOptions } from \"./config/connection.js\";\nimport { createDefaultAdapterFactory } from \"./factory/defaultAdapterFactory.js\";\nimport type { AdapterFactory } from \"./factory/adapterFactory.js\";\n\nimport type { ListSandboxesResponse, SandboxId, SandboxInfo } from \"./models/sandboxes.js\";\nimport type { Sandboxes } from \"./services/sandboxes.js\";\n\nexport interface SandboxManagerOptions {\n /**\n * Connection configuration for calling the OpenSandbox Lifecycle API.\n */\n connectionConfig?: ConnectionConfig | ConnectionConfigOptions;\n /**\n * Advanced override: inject a custom adapter factory (custom transports, dependency injection).\n */\n adapterFactory?: AdapterFactory;\n}\n\nexport interface SandboxFilter {\n /**\n * Filter by sandbox lifecycle states.\n */\n states?: string[];\n /**\n * Filter by metadata key-value pairs.\n */\n metadata?: Record<string, string>;\n /**\n * Pagination page number (1-indexed).\n */\n page?: number;\n /**\n * Number of items per page.\n */\n pageSize?: number;\n}\n\n/**\n * Administrative interface for managing sandboxes (list/get/pause/resume/kill/renew).\n *\n * For interacting *inside* a sandbox, use {@link Sandbox}.\n */\nexport class SandboxManager {\n private readonly sandboxes: Sandboxes;\n private readonly connectionConfig: ConnectionConfig;\n\n private constructor(opts: { sandboxes: Sandboxes; connectionConfig: ConnectionConfig }) {\n this.sandboxes = opts.sandboxes;\n this.connectionConfig = opts.connectionConfig;\n }\n\n static create(opts: SandboxManagerOptions = {}): SandboxManager {\n const baseConnectionConfig = opts.connectionConfig instanceof ConnectionConfig\n ? opts.connectionConfig\n : new ConnectionConfig(opts.connectionConfig);\n const connectionConfig = baseConnectionConfig.withTransportIfMissing();\n const lifecycleBaseUrl = connectionConfig.getBaseUrl();\n const adapterFactory = opts.adapterFactory ?? createDefaultAdapterFactory();\n let sandboxes: Sandboxes;\n try {\n sandboxes = adapterFactory.createLifecycleStack({\n connectionConfig,\n lifecycleBaseUrl,\n }).sandboxes;\n } catch (err) {\n void connectionConfig.closeTransport().catch(() => undefined);\n throw err;\n }\n return new SandboxManager({ sandboxes, connectionConfig });\n }\n\n listSandboxInfos(filter: SandboxFilter = {}): Promise<ListSandboxesResponse> {\n return this.sandboxes.listSandboxes({\n states: filter.states,\n metadata: filter.metadata,\n page: filter.page,\n pageSize: filter.pageSize,\n });\n }\n\n getSandboxInfo(sandboxId: SandboxId): Promise<SandboxInfo> {\n return this.sandboxes.getSandbox(sandboxId);\n }\n\n killSandbox(sandboxId: SandboxId): Promise<void> {\n return this.sandboxes.deleteSandbox(sandboxId);\n }\n\n pauseSandbox(sandboxId: SandboxId): Promise<void> {\n return this.sandboxes.pauseSandbox(sandboxId);\n }\n\n resumeSandbox(sandboxId: SandboxId): Promise<void> {\n return this.sandboxes.resumeSandbox(sandboxId);\n }\n\n /**\n * Renew expiration by setting expiresAt to now + timeoutSeconds.\n */\n async renewSandbox(sandboxId: SandboxId, timeoutSeconds: number): Promise<void> {\n const expiresAt = new Date(Date.now() + timeoutSeconds * 1000).toISOString();\n await this.sandboxes.renewSandboxExpiration(sandboxId, { expiresAt });\n }\n\n /**\n * Release the HTTP agent resources allocated for this manager instance.\n *\n * Each manager clone owns a scoped `ConnectionConfig` clone.\n *\n * This mirrors the Python SDK's default transport lifecycle.\n */\n async close(): Promise<void> {\n await this.connectionConfig.closeTransport();\n }\n}","// Copyright 2026 Alibaba Group Holding Ltd.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n// http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport {\n DEFAULT_ENTRYPOINT,\n DEFAULT_EXECD_PORT,\n DEFAULT_HEALTH_CHECK_POLLING_INTERVAL_MILLIS,\n DEFAULT_READY_TIMEOUT_SECONDS,\n DEFAULT_RESOURCE_LIMITS,\n DEFAULT_TIMEOUT_SECONDS,\n} from \"./core/constants.js\";\nimport { ConnectionConfig, type ConnectionConfigOptions } from \"./config/connection.js\";\nimport type { SandboxFiles } from \"./services/filesystem.js\";\nimport { createDefaultAdapterFactory } from \"./factory/defaultAdapterFactory.js\";\nimport type { AdapterFactory } from \"./factory/adapterFactory.js\";\n\nimport type { Sandboxes } from \"./services/sandboxes.js\";\nimport type { ExecdCommands } from \"./services/execdCommands.js\";\nimport type { ExecdHealth } from \"./services/execdHealth.js\";\nimport type { ExecdMetrics } from \"./services/execdMetrics.js\";\nimport type {\n CreateSandboxRequest,\n Endpoint,\n NetworkPolicy,\n RenewSandboxExpirationResponse,\n SandboxId,\n SandboxInfo,\n Volume,\n} from \"./models/sandboxes.js\";\nimport { SandboxReadyTimeoutException } from \"./core/exceptions.js\";\n\nexport interface SandboxCreateOptions {\n /**\n * Connection configuration for calling the OpenSandbox Lifecycle API and the sandbox's execd API.\n */\n connectionConfig?: ConnectionConfig | ConnectionConfigOptions;\n /**\n * Advanced override: inject a custom adapter factory (custom transports, dependency injection).\n */\n adapterFactory?: AdapterFactory;\n\n /**\n * Container image uri, e.g. `python:3.11`\n */\n image:\n | string\n | { uri: string; auth?: { username: string; password: string } };\n\n /**\n * Entrypoint command for the sandbox (defaults to tail -f /dev/null).\n */\n entrypoint?: string[];\n /**\n * Environment variables to inject into the sandbox runtime.\n */\n env?: Record<string, string>;\n /**\n * Custom metadata tags (used for filtering/management).\n */\n metadata?: Record<string, string>;\n /**\n * Optional outbound network policy for the sandbox.\n * If provided without defaultAction, defaults to \"deny\".\n */\n networkPolicy?: NetworkPolicy;\n /**\n * Optional list of volume mounts for persistent storage.\n * Each volume specifies a backend (host path or PVC) and mount configuration.\n */\n volumes?: Volume[];\n /**\n * Opaque extension parameters passed through to the server as-is.\n */\n extensions?: Record<string, string>;\n\n /**\n * Resource limits applied to the sandbox container.\n *\n * This is forwarded to the Lifecycle API as `resourceLimits`.\n */\n resource?: Record<string, string>;\n /**\n * Sandbox timeout in seconds.\n */\n timeoutSeconds?: number;\n\n /**\n * Skip readiness checks during create/connect.\n *\n * When true, the SDK will not wait for lifecycle state `Running` or perform the health check.\n * The returned sandbox instance may not be ready yet.\n */\n skipHealthCheck?: boolean;\n /**\n * Optional custom readiness check used by {@link Sandbox.waitUntilReady}.\n *\n * If provided, the SDK will call this function during readiness checks instead of\n * using the default `execd` ping check.\n */\n healthCheck?: (sbx: Sandbox) => boolean | Promise<boolean>;\n readyTimeoutSeconds?: number;\n healthCheckPollingInterval?: number;\n}\n\nexport interface SandboxConnectOptions {\n /**\n * Connection configuration for calling the OpenSandbox APIs.\n */\n connectionConfig?: ConnectionConfig | ConnectionConfigOptions;\n /**\n * Advanced override: inject a custom adapter factory (custom transports, dependency injection).\n */\n adapterFactory?: AdapterFactory;\n /**\n * ID of the existing sandbox to connect to.\n */\n sandboxId: SandboxId;\n\n /**\n * Skip readiness checks after connecting.\n */\n skipHealthCheck?: boolean;\n /**\n * Optional custom readiness check used by {@link Sandbox.waitUntilReady}.\n */\n healthCheck?: (sbx: Sandbox) => boolean | Promise<boolean>;\n /**\n * Max time to wait for readiness.\n */\n readyTimeoutSeconds?: number;\n /**\n * Polling interval for readiness checks (milliseconds).\n */\n healthCheckPollingInterval?: number;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nfunction toImageSpec(\n image: SandboxCreateOptions[\"image\"]\n): CreateSandboxRequest[\"image\"] {\n if (typeof image === \"string\") return { uri: image };\n return { uri: image.uri, auth: image.auth };\n}\n\nexport class Sandbox {\n readonly id: SandboxId;\n readonly connectionConfig: ConnectionConfig;\n\n /**\n * Lifecycle (sandbox management) service.\n */\n readonly sandboxes: Sandboxes;\n\n /**\n * Execd services.\n */\n readonly commands: ExecdCommands;\n /**\n * High-level filesystem facade (JS-friendly).\n */\n readonly files: SandboxFiles;\n readonly health: ExecdHealth;\n readonly metrics: ExecdMetrics;\n\n /**\n * Internal state kept out of the public instance shape.\n *\n * This avoids nominal typing issues when multiple copies of the SDK exist in a dependency graph.\n */\n private static readonly _priv = new WeakMap<\n Sandbox,\n {\n adapterFactory: AdapterFactory;\n lifecycleBaseUrl: string;\n execdBaseUrl: string;\n }\n >();\n\n private constructor(opts: {\n id: SandboxId;\n connectionConfig: ConnectionConfig;\n adapterFactory: AdapterFactory;\n lifecycleBaseUrl: string;\n execdBaseUrl: string;\n sandboxes: Sandboxes;\n commands: ExecdCommands;\n files: SandboxFiles;\n health: ExecdHealth;\n metrics: ExecdMetrics;\n }) {\n this.id = opts.id;\n this.connectionConfig = opts.connectionConfig;\n Sandbox._priv.set(this, {\n adapterFactory: opts.adapterFactory,\n lifecycleBaseUrl: opts.lifecycleBaseUrl,\n execdBaseUrl: opts.execdBaseUrl,\n });\n\n this.sandboxes = opts.sandboxes;\n this.commands = opts.commands;\n this.files = opts.files;\n this.health = opts.health;\n this.metrics = opts.metrics;\n }\n\n static async create(opts: SandboxCreateOptions): Promise<Sandbox> {\n const baseConnectionConfig =\n opts.connectionConfig instanceof ConnectionConfig\n ? opts.connectionConfig\n : new ConnectionConfig(opts.connectionConfig);\n const connectionConfig = baseConnectionConfig.withTransportIfMissing();\n const lifecycleBaseUrl = connectionConfig.getBaseUrl();\n const adapterFactory = opts.adapterFactory ?? createDefaultAdapterFactory();\n\n let sandboxes: Sandboxes;\n try {\n sandboxes = adapterFactory.createLifecycleStack({\n connectionConfig,\n lifecycleBaseUrl,\n }).sandboxes;\n } catch (err) {\n await connectionConfig.closeTransport();\n throw err;\n }\n\n // Validate volumes: exactly one backend must be specified per volume\n if (opts.volumes) {\n for (const vol of opts.volumes) {\n const backendsSpecified = [vol.host, vol.pvc].filter((b) => b !== undefined).length;\n if (backendsSpecified === 0) {\n throw new Error(\n `Volume '${vol.name}' must specify exactly one backend (host, pvc), but none was provided.`\n );\n }\n if (backendsSpecified > 1) {\n throw new Error(\n `Volume '${vol.name}' must specify exactly one backend (host, pvc), but multiple were provided.`\n );\n }\n }\n }\n\n const req: CreateSandboxRequest = {\n image: toImageSpec(opts.image),\n entrypoint: opts.entrypoint ?? DEFAULT_ENTRYPOINT,\n timeout: Math.floor(opts.timeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS),\n resourceLimits: opts.resource ?? DEFAULT_RESOURCE_LIMITS,\n env: opts.env ?? {},\n metadata: opts.metadata ?? {},\n networkPolicy: opts.networkPolicy\n ? {\n ...opts.networkPolicy,\n defaultAction: opts.networkPolicy.defaultAction ?? \"deny\",\n }\n : undefined,\n volumes: opts.volumes,\n extensions: opts.extensions ?? {},\n };\n\n let sandboxId: SandboxId | undefined;\n try {\n const created = await sandboxes.createSandbox(req);\n sandboxId = created.id as SandboxId;\n\n const endpoint = await sandboxes.getSandboxEndpoint(\n sandboxId,\n DEFAULT_EXECD_PORT,\n connectionConfig.useServerProxy\n );\n const execdBaseUrl = `${connectionConfig.protocol}://${endpoint.endpoint}`;\n\n const { commands, files, health, metrics } =\n adapterFactory.createExecdStack({\n connectionConfig,\n execdBaseUrl,\n endpointHeaders: endpoint.headers,\n });\n\n const sbx = new Sandbox({\n id: sandboxId,\n connectionConfig,\n adapterFactory,\n lifecycleBaseUrl,\n execdBaseUrl,\n sandboxes,\n commands,\n files,\n health,\n metrics,\n });\n\n if (!(opts.skipHealthCheck ?? false)) {\n await sbx.waitUntilReady({\n readyTimeoutSeconds:\n opts.readyTimeoutSeconds ?? DEFAULT_READY_TIMEOUT_SECONDS,\n pollingIntervalMillis:\n opts.healthCheckPollingInterval ??\n DEFAULT_HEALTH_CHECK_POLLING_INTERVAL_MILLIS,\n healthCheck: opts.healthCheck,\n });\n }\n\n return sbx;\n } catch (err) {\n if (sandboxId) {\n try {\n await sandboxes.deleteSandbox(sandboxId);\n } catch {\n // Ignore cleanup failure; surface original error.\n }\n }\n await connectionConfig.closeTransport();\n throw err;\n }\n }\n\n static async connect(opts: SandboxConnectOptions): Promise<Sandbox> {\n const baseConnectionConfig =\n opts.connectionConfig instanceof ConnectionConfig\n ? opts.connectionConfig\n : new ConnectionConfig(opts.connectionConfig);\n const connectionConfig = baseConnectionConfig.withTransportIfMissing();\n const adapterFactory = opts.adapterFactory ?? createDefaultAdapterFactory();\n const lifecycleBaseUrl = connectionConfig.getBaseUrl();\n\n let sandboxes: Sandboxes;\n try {\n sandboxes = adapterFactory.createLifecycleStack({\n connectionConfig,\n lifecycleBaseUrl,\n }).sandboxes;\n } catch (err) {\n await connectionConfig.closeTransport();\n throw err;\n }\n\n try {\n const endpoint = await sandboxes.getSandboxEndpoint(\n opts.sandboxId,\n DEFAULT_EXECD_PORT,\n connectionConfig.useServerProxy\n );\n const execdBaseUrl = `${connectionConfig.protocol}://${endpoint.endpoint}`;\n const { commands, files, health, metrics } =\n adapterFactory.createExecdStack({\n connectionConfig,\n execdBaseUrl,\n endpointHeaders: endpoint.headers,\n });\n\n const sbx = new Sandbox({\n id: opts.sandboxId,\n connectionConfig,\n adapterFactory,\n lifecycleBaseUrl,\n execdBaseUrl,\n sandboxes,\n commands,\n files,\n health,\n metrics,\n });\n\n if (!(opts.skipHealthCheck ?? false)) {\n await sbx.waitUntilReady({\n readyTimeoutSeconds:\n opts.readyTimeoutSeconds ?? DEFAULT_READY_TIMEOUT_SECONDS,\n pollingIntervalMillis:\n opts.healthCheckPollingInterval ??\n DEFAULT_HEALTH_CHECK_POLLING_INTERVAL_MILLIS,\n healthCheck: opts.healthCheck,\n });\n }\n\n return sbx;\n } catch (err) {\n await connectionConfig.closeTransport();\n throw err;\n }\n }\n\n async getInfo(): Promise<SandboxInfo> {\n return await this.sandboxes.getSandbox(this.id);\n }\n\n async isHealthy(): Promise<boolean> {\n try {\n return await this.health.ping();\n } catch {\n return false;\n }\n }\n\n async getMetrics() {\n return await this.metrics.getMetrics();\n }\n\n async pause(): Promise<void> {\n await this.sandboxes.pauseSandbox(this.id);\n }\n\n /**\n * Resume a paused sandbox and return a fresh, connected Sandbox instance.\n *\n * After resume, the execd endpoint may change, so this method returns a new\n * {@link Sandbox} instance with a refreshed execd base URL.\n */\n async resume(\n opts: {\n skipHealthCheck?: boolean;\n readyTimeoutSeconds?: number;\n healthCheckPollingInterval?: number;\n } = {}\n ): Promise<Sandbox> {\n await this.sandboxes.resumeSandbox(this.id);\n return await Sandbox.connect({\n sandboxId: this.id,\n connectionConfig: this.connectionConfig,\n adapterFactory: Sandbox._priv.get(this)!.adapterFactory,\n skipHealthCheck: opts.skipHealthCheck ?? false,\n readyTimeoutSeconds: opts.readyTimeoutSeconds,\n healthCheckPollingInterval: opts.healthCheckPollingInterval,\n });\n }\n\n /**\n * Resume a paused sandbox by id, then connect to its execd endpoint.\n */\n static async resume(opts: SandboxConnectOptions): Promise<Sandbox> {\n const baseConnectionConfig =\n opts.connectionConfig instanceof ConnectionConfig\n ? opts.connectionConfig\n : new ConnectionConfig(opts.connectionConfig);\n const adapterFactory = opts.adapterFactory ?? createDefaultAdapterFactory();\n const resumeConnectionConfig = baseConnectionConfig.withTransportIfMissing();\n const lifecycleBaseUrl = resumeConnectionConfig.getBaseUrl();\n\n let sandboxes: Sandboxes;\n try {\n sandboxes = adapterFactory.createLifecycleStack({\n connectionConfig: resumeConnectionConfig,\n lifecycleBaseUrl,\n }).sandboxes;\n await sandboxes.resumeSandbox(opts.sandboxId);\n } catch (err) {\n await resumeConnectionConfig.closeTransport();\n throw err;\n }\n\n await resumeConnectionConfig.closeTransport();\n return await Sandbox.connect({ ...opts, connectionConfig: baseConnectionConfig, adapterFactory });\n }\n\n async kill(): Promise<void> {\n await this.sandboxes.deleteSandbox(this.id);\n }\n\n /**\n * Release any client-side resources (e.g. Node.js HTTP agents) owned by this Sandbox instance.\n */\n async close(): Promise<void> {\n await this.connectionConfig.closeTransport();\n }\n\n /**\n * Renew expiration by setting expiresAt to now + timeoutSeconds.\n */\n async renew(timeoutSeconds: number): Promise<RenewSandboxExpirationResponse> {\n const expiresAt = new Date(\n Date.now() + timeoutSeconds * 1000\n ).toISOString();\n return await this.sandboxes.renewSandboxExpiration(this.id, { expiresAt });\n }\n\n /**\n * Get sandbox endpoint for a port (STRICT: no scheme), e.g. \"localhost:44772\" or \"domain/route/.../44772\".\n */\n async getEndpoint(port: number): Promise<Endpoint> {\n return await this.sandboxes.getSandboxEndpoint(\n this.id,\n port,\n this.connectionConfig.useServerProxy\n );\n }\n\n /**\n * Get absolute endpoint URL with scheme (convenience for HTTP clients).\n */\n async getEndpointUrl(port: number): Promise<string> {\n const ep = await this.getEndpoint(port);\n return `${this.connectionConfig.protocol}://${ep.endpoint}`;\n }\n\n async waitUntilReady(opts: {\n readyTimeoutSeconds: number;\n pollingIntervalMillis: number;\n healthCheck?: (sbx: Sandbox) => boolean | Promise<boolean>;\n }): Promise<void> {\n const deadline = Date.now() + opts.readyTimeoutSeconds * 1000;\n\n // Wait until execd becomes reachable and passes health check.\n while (true) {\n if (Date.now() > deadline) {\n throw new SandboxReadyTimeoutException({\n message: `Sandbox not ready: timed out waiting for health check (timeoutSeconds=${opts.readyTimeoutSeconds})`,\n });\n }\n try {\n if (opts.healthCheck) {\n const ok = await opts.healthCheck(this);\n if (ok) return;\n } else {\n const ok = await this.health.ping();\n if (ok) return;\n }\n } catch {\n // ignore and retry\n }\n await sleep(opts.pollingIntervalMillis);\n }\n }\n}"],"mappings":";;;;;;;;;;;;;;;;;;;AAyBO,IAAM,wBAAN,MAAsD;AAAA,EAC3D,qBAAqB,MAAmD;AACtE,UAAM,kBAAkB,sBAAsB;AAAA,MAC5C,SAAS,KAAK;AAAA,MACd,QAAQ,KAAK,iBAAiB;AAAA,MAC9B,SAAS,KAAK,iBAAiB;AAAA,MAC/B,OAAO,KAAK,iBAAiB;AAAA,IAC/B,CAAC;AACD,UAAM,YAAY,IAAI,iBAAiB,eAAe;AACtD,WAAO,EAAE,UAAU;AAAA,EACrB;AAAA,EAEA,iBAAiB,MAA2C;AAC1D,UAAM,UAAkC;AAAA,MACtC,GAAI,KAAK,iBAAiB,WAAW,CAAC;AAAA,MACtC,GAAI,KAAK,mBAAmB,CAAC;AAAA,IAC/B;AACA,UAAM,cAAc,kBAAkB;AAAA,MACpC,SAAS,KAAK;AAAA,MACd;AAAA,MACA,OAAO,KAAK,iBAAiB;AAAA,IAC/B,CAAC;AAED,UAAM,SAAS,IAAI,cAAc,WAAW;AAC5C,UAAM,UAAU,IAAI,eAAe,WAAW;AAC9C,UAAM,QAAQ,IAAI,kBAAkB,aAAa;AAAA,MAC/C,SAAS,KAAK;AAAA,MACd,OAAO,KAAK,iBAAiB;AAAA,MAC7B;AAAA,IACF,CAAC;AACD,UAAM,WAAW,IAAI,gBAAgB,aAAa;AAAA,MAChD,SAAS,KAAK;AAAA,MACd,OAAO,KAAK,iBAAiB;AAAA,MAC7B;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,8BAA8C;AAC5D,SAAO,IAAI,sBAAsB;AACnC;;;AC1DO,IAAM,qBAAqB;AAE3B,IAAM,qBAA+B,CAAC,QAAQ,MAAM,WAAW;AAE/D,IAAM,0BAAkD;AAAA,EAC7D,KAAK;AAAA,EACL,QAAQ;AACV;AAEO,IAAM,0BAA0B;AAChC,IAAM,gCAAgC;AACtC,IAAM,+CAA+C;AAErD,IAAM,kCAAkC;AACxC,IAAM,qBAAqB;;;AC0BlC,SAAS,gBAAyB;AAChC,QAAM,IAAK,YAAoB;AAC/B,SAAO,CAAC,CAAC,GAAG,UAAU;AACxB;AAEA,SAAS,cACP,SACwB;AACxB,QAAM,MAA8B,EAAE,GAAG,QAAQ;AACjD,aAAW,KAAK,OAAO,KAAK,GAAG,GAAG;AAChC,QAAI,EAAE,YAAY,MAAM,uBAAwB,KAAI,CAAC,IAAI;AAAA,EAC3D;AACA,SAAO;AACT;AAEA,SAAS,QAAQ,MAAkC;AACjD,QAAM,MAAO,YAAoB,SAAS;AAC1C,QAAM,IAAI,MAAM,IAAI;AACpB,SAAO,OAAO,MAAM,YAAY,EAAE,SAAS,IAAI;AACjD;AAEA,SAAS,qBAAqB,GAAmB;AAC/C,SAAO,EAAE,QAAQ,QAAQ,EAAE;AAC7B;AAEA,SAAS,cAAc,GAAmB;AACxC,QAAM,UAAU,qBAAqB,CAAC;AACtC,SAAO,QAAQ,SAAS,KAAK,IAAI,QAAQ,MAAM,GAAG,EAAE,IAAI;AAC1D;AAEA,IAAM,+BAA+B;AAErC,SAAS,oBAAoB,OAG3B;AAEA,MAAI,MAAM,WAAW,SAAS,KAAK,MAAM,WAAW,UAAU,GAAG;AAC/D,UAAM,IAAI,IAAI,IAAI,KAAK;AACvB,UAAM,QAAQ,EAAE,aAAa,WAAW,UAAU;AAElD,UAAM,OAAO,GAAG,EAAE,MAAM,GAAG,EAAE,QAAQ;AACrC,WAAO,EAAE,UAAU,OAAO,YAAY,cAAc,IAAI,EAAE;AAAA,EAC5D;AAGA,SAAO,EAAE,YAAY,cAAc,KAAK,EAAE;AAC5C;AAEA,SAAS,kBAGP;AACA,MAAI,CAAC,cAAc,GAAG;AACpB,WAAO;AAAA,MACL;AAAA,MACA,OAAO,YAAY;AAAA,MAEnB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YAAY;AAClB,MAAI;AACJ,MAAI,oBAA6C;AAEjD,QAAM,YAA0B,OAAO,OAA0B,SAAuB;AACtF,2BAAuB,YAAY;AACjC,UAAI;AACF,cAAM,MAAM,MAAM,OAAO,QAAQ;AACjC,cAAM,QAAS,IAAoD;AACnE,YAAI,CAAC,OAAO;AACV,iBAAO;AAAA,QACT;AACA,qBAAa,IAAI,MAAM;AAAA,UACrB,kBAAkB;AAAA,UAClB,qBAAqB;AAAA,QACvB,CAAC;AACD,eAAO;AAAA,MACT,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF,GAAG;AAEH,QAAI,mBAAmB;AACrB,YAAM;AAAA,IACR;AAEA,QAAI,YAAY;AACd,YAAM,aAAa,EAAE,GAAI,QAAQ,CAAC,GAAI,WAAW;AAGjD,aAAO,UAAU,OAAO,UAAyB;AAAA,IACnD;AAEA,WAAO,UAAU,OAAO,IAAI;AAAA,EAC9B;AAEA,SAAO;AAAA,IACL,OAAO;AAAA,IACP,OAAO,YAAY;AACjB,UAAI,mBAAmB;AACrB,cAAM,kBAAkB,MAAM,MAAM,MAAS;AAAA,MAC/C;AACA,UACE,cACA,OAAO,eAAe,YACtB,OAAQ,WAAmB,UAAU,YACrC;AACA,YAAI;AACF,gBAAO,WAAmB,MAAM;AAAA,QAClC,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,iBAAiB,MAMT;AACf,QAAM,YAAY,KAAK;AACvB,QAAM,iBAAiB,KAAK;AAC5B,QAAM,QAAQ,KAAK;AACnB,QAAM,iBAAiB,KAAK,kBAAkB,CAAC;AAC/C,QAAM,QAAQ,KAAK;AAEnB,SAAO,OAAO,OAA0B,SAAuB;AAC7D,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,MACJ,OAAO,UAAU,WACb,QACC,OAAe,WAAW,KAAK,OAAO,KAAK;AAElD,UAAM,KAAK,IAAI,gBAAgB;AAC/B,UAAM,YAAY,KAAK,MAAM,iBAAiB,GAAI;AAClD,UAAM,IACJ,OAAO,SAAS,SAAS,KAAK,YAAY,IACtC;AAAA,MACE,MACE,GAAG;AAAA,QACD,IAAI;AAAA,UACF,IAAI,KAAK,uCAAuC,cAAc;AAAA,QAChE;AAAA,MACF;AAAA,MACF;AAAA,IACF,IACA;AAEN,UAAM,UAAU,MACd,GAAG,MAAO,MAAM,QAAgB,UAAU,IAAI,MAAM,SAAS,CAAC;AAChE,QAAI,MAAM,QAAQ;AAChB,UAAI,KAAK,OAAO,QAAS,SAAQ;AAAA;AAE/B,aAAK,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAQ;AAAA,IACxE;AAEA,UAAM,aAA0B;AAAA,MAC9B,GAAG;AAAA,MACH,QAAQ,GAAG;AAAA,IACb;AAEA,QAAI,OAAO;AACT,YAAM,gBAAgB;AAAA,QACpB,GAAG;AAAA,QACH,GAAK,MAAM,WAAW,CAAC;AAAA,MACzB;AAEA,cAAQ;AAAA,QACN,gBAAgB,KAAK;AAAA,QACrB;AAAA,QACA;AAAA,QACA,cAAc,aAAa;AAAA,MAC7B;AAAA,IACF;AAEA,QAAI;AACF,YAAM,MAAM,MAAM,UAAU,OAAO,UAAU;AAC7C,UAAI,OAAO;AAET,gBAAQ,IAAI,gBAAgB,KAAK,QAAQ,QAAQ,KAAK,IAAI,MAAM;AAAA,MAClE;AACA,aAAO;AAAA,IACT,UAAE;AACA,UAAI,EAAG,cAAa,CAAC;AACrB,UAAI,MAAM;AACR,aAAK,OAAO,oBAAoB,SAAS,OAAc;AAAA,IAC3D;AAAA,EACF;AACF;AAEO,IAAM,mBAAN,MAAM,kBAAiB;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACD;AAAA,EACA;AAAA,EACC;AAAA,EACA;AAAA,EACA,YAAoB;AAAA;AAAA;AAAA;AAAA,EAIpB;AAAA,EACD;AAAA,EACA,gBAAsC;AAAA,EACtC,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAShC,YAAY,OAAgC,CAAC,GAAG;AAC9C,UAAM,YAAY,QAAQ,qBAAqB;AAC/C,UAAM,YAAY,QAAQ,sBAAsB;AAEhD,UAAM,YAAY,KAAK,UAAU,aAAa;AAC9C,UAAM,aAAa,oBAAoB,SAAS;AAGhD,SAAK,WAAW,WAAW,YAAY,KAAK,YAAY;AACxD,SAAK,SAAS,WAAW;AACzB,SAAK,SAAS,KAAK,UAAU;AAC7B,SAAK,wBACH,OAAO,KAAK,0BAA0B,WAClC,KAAK,wBACL;AACN,SAAK,QAAQ,CAAC,CAAC,KAAK;AACpB,SAAK,iBAAiB,CAAC,CAAC,KAAK;AAE7B,UAAM,UAAkC,EAAE,GAAI,KAAK,WAAW,CAAC,EAAG;AAElE,QAAI,KAAK,UAAU,CAAC,QAAQ,sBAAsB,GAAG;AACnD,cAAQ,sBAAsB,IAAI,KAAK;AAAA,IACzC;AAEA,QACE,cAAc,KACd,KAAK,aACL,CAAC,QAAQ,YAAY,KACrB,CAAC,QAAQ,YAAY,GACrB;AACA,cAAQ,YAAY,IAAI,KAAK;AAAA,IAC/B;AACA,SAAK,UAAU;AACf,SAAK,SAAS;AACd,SAAK,YAAY;AACjB,SAAK,kBAAkB,YAAY;AAAA,IAEnC;AACA,SAAK,wBAAwB;AAAA,EAC/B;AAAA,EAEA,IAAI,QAAsB;AACxB,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA,EAEA,IAAI,WAAyB;AAC3B,WAAO,KAAK,aAAa;AAAA,EAC3B;AAAA,EAEA,aAAqB;AAEnB,QACE,KAAK,OAAO,WAAW,SAAS,KAChC,KAAK,OAAO,WAAW,UAAU,GACjC;AACA,aAAO,GAAG,cAAc,KAAK,MAAM,CAAC;AAAA,IACtC;AACA,WAAO,GAAG,KAAK,QAAQ,MAAM,cAAc,KAAK,MAAM,CAAC;AAAA,EACzD;AAAA,EAEQ,sBAA4B;AAClC,QAAI,KAAK,sBAAuB;AAEhC,UAAM,EAAE,OAAO,WAAW,MAAM,IAAI,gBAAgB;AACpD,SAAK,SAAS,iBAAiB;AAAA,MAC7B;AAAA,MACA,gBAAgB,KAAK;AAAA,MACrB,OAAO,KAAK;AAAA,MACZ,gBAAgB,KAAK;AAAA,MACrB,OAAO;AAAA,IACT,CAAC;AACD,SAAK,YAAY,iBAAiB;AAAA,MAChC;AAAA,MACA,gBAAgB;AAAA,MAChB,OAAO,KAAK;AAAA,MACZ,gBAAgB,KAAK;AAAA,MACrB,OAAO;AAAA,IACT,CAAC;AACD,SAAK,kBAAkB;AACvB,SAAK,wBAAwB;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,yBAA2C;AACzC,QAAI,KAAK,uBAAuB;AAC9B,aAAO;AAAA,IACT;AAEA,UAAM,QAAQ,IAAI,kBAAiB;AAAA,MACjC,QAAQ,KAAK;AAAA,MACb,UAAU,KAAK;AAAA,MACf,QAAQ,KAAK;AAAA,MACb,SAAS,EAAE,GAAG,KAAK,QAAQ;AAAA,MAC3B,uBAAuB,KAAK;AAAA,MAC5B,OAAO,KAAK;AAAA,MACZ,gBAAgB,KAAK;AAAA,IACvB,CAAC;AACD,UAAM,oBAAoB;AAC1B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAgC;AACpC,QAAI,CAAC,KAAK,sBAAuB;AACjC,SAAK,kBAAkB,KAAK,gBAAgB;AAC5C,UAAM,KAAK;AAAA,EACb;AACF;;;AC7UO,IAAM,iBAAN,MAAM,gBAAe;AAAA,EACT;AAAA,EACA;AAAA,EAET,YAAY,MAAoE;AACtF,SAAK,YAAY,KAAK;AACtB,SAAK,mBAAmB,KAAK;AAAA,EAC/B;AAAA,EAEA,OAAO,OAAO,OAA8B,CAAC,GAAmB;AAC9D,UAAM,uBAAuB,KAAK,4BAA4B,mBAC1D,KAAK,mBACL,IAAI,iBAAiB,KAAK,gBAAgB;AAC9C,UAAM,mBAAmB,qBAAqB,uBAAuB;AACrE,UAAM,mBAAmB,iBAAiB,WAAW;AACrD,UAAM,iBAAiB,KAAK,kBAAkB,4BAA4B;AAC1E,QAAI;AACJ,QAAI;AACF,kBAAY,eAAe,qBAAqB;AAAA,QAC9C;AAAA,QACA;AAAA,MACF,CAAC,EAAE;AAAA,IACL,SAAS,KAAK;AACZ,WAAK,iBAAiB,eAAe,EAAE,MAAM,MAAM,MAAS;AAC5D,YAAM;AAAA,IACR;AACA,WAAO,IAAI,gBAAe,EAAE,WAAW,iBAAiB,CAAC;AAAA,EAC3D;AAAA,EAEA,iBAAiB,SAAwB,CAAC,GAAmC;AAC3E,WAAO,KAAK,UAAU,cAAc;AAAA,MAClC,QAAQ,OAAO;AAAA,MACf,UAAU,OAAO;AAAA,MACjB,MAAM,OAAO;AAAA,MACb,UAAU,OAAO;AAAA,IACnB,CAAC;AAAA,EACH;AAAA,EAEA,eAAe,WAA4C;AACzD,WAAO,KAAK,UAAU,WAAW,SAAS;AAAA,EAC5C;AAAA,EAEA,YAAY,WAAqC;AAC/C,WAAO,KAAK,UAAU,cAAc,SAAS;AAAA,EAC/C;AAAA,EAEA,aAAa,WAAqC;AAChD,WAAO,KAAK,UAAU,aAAa,SAAS;AAAA,EAC9C;AAAA,EAEA,cAAc,WAAqC;AACjD,WAAO,KAAK,UAAU,cAAc,SAAS;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,WAAsB,gBAAuC;AAC9E,UAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,iBAAiB,GAAI,EAAE,YAAY;AAC3E,UAAM,KAAK,UAAU,uBAAuB,WAAW,EAAE,UAAU,CAAC;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,QAAuB;AAC3B,UAAM,KAAK,iBAAiB,eAAe;AAAA,EAC7C;AACF;;;ACmBA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAC7C;AAEA,SAAS,YACP,OAC+B;AAC/B,MAAI,OAAO,UAAU,SAAU,QAAO,EAAE,KAAK,MAAM;AACnD,SAAO,EAAE,KAAK,MAAM,KAAK,MAAM,MAAM,KAAK;AAC5C;AAEO,IAAM,UAAN,MAAM,SAAQ;AAAA,EACV;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT,OAAwB,QAAQ,oBAAI,QAOlC;AAAA,EAEM,YAAY,MAWjB;AACD,SAAK,KAAK,KAAK;AACf,SAAK,mBAAmB,KAAK;AAC7B,aAAQ,MAAM,IAAI,MAAM;AAAA,MACtB,gBAAgB,KAAK;AAAA,MACrB,kBAAkB,KAAK;AAAA,MACvB,cAAc,KAAK;AAAA,IACrB,CAAC;AAED,SAAK,YAAY,KAAK;AACtB,SAAK,WAAW,KAAK;AACrB,SAAK,QAAQ,KAAK;AAClB,SAAK,SAAS,KAAK;AACnB,SAAK,UAAU,KAAK;AAAA,EACtB;AAAA,EAEA,aAAa,OAAO,MAA8C;AAChE,UAAM,uBACJ,KAAK,4BAA4B,mBAC7B,KAAK,mBACL,IAAI,iBAAiB,KAAK,gBAAgB;AAChD,UAAM,mBAAmB,qBAAqB,uBAAuB;AACrE,UAAM,mBAAmB,iBAAiB,WAAW;AACrD,UAAM,iBAAiB,KAAK,kBAAkB,4BAA4B;AAE1E,QAAI;AACJ,QAAI;AACF,kBAAY,eAAe,qBAAqB;AAAA,QAC9C;AAAA,QACA;AAAA,MACF,CAAC,EAAE;AAAA,IACL,SAAS,KAAK;AACZ,YAAM,iBAAiB,eAAe;AACtC,YAAM;AAAA,IACR;AAGA,QAAI,KAAK,SAAS;AAChB,iBAAW,OAAO,KAAK,SAAS;AAC9B,cAAM,oBAAoB,CAAC,IAAI,MAAM,IAAI,GAAG,EAAE,OAAO,CAAC,MAAM,MAAM,MAAS,EAAE;AAC7E,YAAI,sBAAsB,GAAG;AAC3B,gBAAM,IAAI;AAAA,YACR,WAAW,IAAI,IAAI;AAAA,UACrB;AAAA,QACF;AACA,YAAI,oBAAoB,GAAG;AACzB,gBAAM,IAAI;AAAA,YACR,WAAW,IAAI,IAAI;AAAA,UACrB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,MAA4B;AAAA,MAChC,OAAO,YAAY,KAAK,KAAK;AAAA,MAC7B,YAAY,KAAK,cAAc;AAAA,MAC/B,SAAS,KAAK,MAAM,KAAK,kBAAkB,uBAAuB;AAAA,MAClE,gBAAgB,KAAK,YAAY;AAAA,MACjC,KAAK,KAAK,OAAO,CAAC;AAAA,MAClB,UAAU,KAAK,YAAY,CAAC;AAAA,MAC5B,eAAe,KAAK,gBAChB;AAAA,QACE,GAAG,KAAK;AAAA,QACR,eAAe,KAAK,cAAc,iBAAiB;AAAA,MACrD,IACA;AAAA,MACJ,SAAS,KAAK;AAAA,MACd,YAAY,KAAK,cAAc,CAAC;AAAA,IAClC;AAEA,QAAI;AACJ,QAAI;AACF,YAAM,UAAU,MAAM,UAAU,cAAc,GAAG;AACjD,kBAAY,QAAQ;AAEpB,YAAM,WAAW,MAAM,UAAU;AAAA,QAC/B;AAAA,QACA;AAAA,QACA,iBAAiB;AAAA,MACnB;AACA,YAAM,eAAe,GAAG,iBAAiB,QAAQ,MAAM,SAAS,QAAQ;AAExE,YAAM,EAAE,UAAU,OAAO,QAAQ,QAAQ,IACvC,eAAe,iBAAiB;AAAA,QAC9B;AAAA,QACA;AAAA,QACA,iBAAiB,SAAS;AAAA,MAC5B,CAAC;AAEH,YAAM,MAAM,IAAI,SAAQ;AAAA,QACtB,IAAI;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAED,UAAI,EAAE,KAAK,mBAAmB,QAAQ;AACpC,cAAM,IAAI,eAAe;AAAA,UACvB,qBACE,KAAK,uBAAuB;AAAA,UAC9B,uBACE,KAAK,8BACL;AAAA,UACF,aAAa,KAAK;AAAA,QACpB,CAAC;AAAA,MACH;AAEA,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,UAAI,WAAW;AACb,YAAI;AACF,gBAAM,UAAU,cAAc,SAAS;AAAA,QACzC,QAAQ;AAAA,QAER;AAAA,MACF;AACA,YAAM,iBAAiB,eAAe;AACtC,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,aAAa,QAAQ,MAA+C;AAClE,UAAM,uBACJ,KAAK,4BAA4B,mBAC7B,KAAK,mBACL,IAAI,iBAAiB,KAAK,gBAAgB;AAChD,UAAM,mBAAmB,qBAAqB,uBAAuB;AACrE,UAAM,iBAAiB,KAAK,kBAAkB,4BAA4B;AAC1E,UAAM,mBAAmB,iBAAiB,WAAW;AAErD,QAAI;AACJ,QAAI;AACF,kBAAY,eAAe,qBAAqB;AAAA,QAC9C;AAAA,QACA;AAAA,MACF,CAAC,EAAE;AAAA,IACL,SAAS,KAAK;AACZ,YAAM,iBAAiB,eAAe;AACtC,YAAM;AAAA,IACR;AAEA,QAAI;AACF,YAAM,WAAW,MAAM,UAAU;AAAA,QAC/B,KAAK;AAAA,QACL;AAAA,QACA,iBAAiB;AAAA,MACnB;AACA,YAAM,eAAe,GAAG,iBAAiB,QAAQ,MAAM,SAAS,QAAQ;AACxE,YAAM,EAAE,UAAU,OAAO,QAAQ,QAAQ,IACvC,eAAe,iBAAiB;AAAA,QAC9B;AAAA,QACA;AAAA,QACA,iBAAiB,SAAS;AAAA,MAC5B,CAAC;AAEH,YAAM,MAAM,IAAI,SAAQ;AAAA,QACtB,IAAI,KAAK;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAED,UAAI,EAAE,KAAK,mBAAmB,QAAQ;AACpC,cAAM,IAAI,eAAe;AAAA,UACvB,qBACE,KAAK,uBAAuB;AAAA,UAC9B,uBACE,KAAK,8BACL;AAAA,UACF,aAAa,KAAK;AAAA,QACpB,CAAC;AAAA,MACH;AAEA,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,YAAM,iBAAiB,eAAe;AACtC,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,UAAgC;AACpC,WAAO,MAAM,KAAK,UAAU,WAAW,KAAK,EAAE;AAAA,EAChD;AAAA,EAEA,MAAM,YAA8B;AAClC,QAAI;AACF,aAAO,MAAM,KAAK,OAAO,KAAK;AAAA,IAChC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,aAAa;AACjB,WAAO,MAAM,KAAK,QAAQ,WAAW;AAAA,EACvC;AAAA,EAEA,MAAM,QAAuB;AAC3B,UAAM,KAAK,UAAU,aAAa,KAAK,EAAE;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OACJ,OAII,CAAC,GACa;AAClB,UAAM,KAAK,UAAU,cAAc,KAAK,EAAE;AAC1C,WAAO,MAAM,SAAQ,QAAQ;AAAA,MAC3B,WAAW,KAAK;AAAA,MAChB,kBAAkB,KAAK;AAAA,MACvB,gBAAgB,SAAQ,MAAM,IAAI,IAAI,EAAG;AAAA,MACzC,iBAAiB,KAAK,mBAAmB;AAAA,MACzC,qBAAqB,KAAK;AAAA,MAC1B,4BAA4B,KAAK;AAAA,IACnC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,OAAO,MAA+C;AACjE,UAAM,uBACJ,KAAK,4BAA4B,mBAC7B,KAAK,mBACL,IAAI,iBAAiB,KAAK,gBAAgB;AAChD,UAAM,iBAAiB,KAAK,kBAAkB,4BAA4B;AAC1E,UAAM,yBAAyB,qBAAqB,uBAAuB;AAC3E,UAAM,mBAAmB,uBAAuB,WAAW;AAE3D,QAAI;AACJ,QAAI;AACF,kBAAY,eAAe,qBAAqB;AAAA,QAC9C,kBAAkB;AAAA,QAClB;AAAA,MACF,CAAC,EAAE;AACH,YAAM,UAAU,cAAc,KAAK,SAAS;AAAA,IAC9C,SAAS,KAAK;AACZ,YAAM,uBAAuB,eAAe;AAC5C,YAAM;AAAA,IACR;AAEA,UAAM,uBAAuB,eAAe;AAC5C,WAAO,MAAM,SAAQ,QAAQ,EAAE,GAAG,MAAM,kBAAkB,sBAAsB,eAAe,CAAC;AAAA,EAClG;AAAA,EAEA,MAAM,OAAsB;AAC1B,UAAM,KAAK,UAAU,cAAc,KAAK,EAAE;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAuB;AAC3B,UAAM,KAAK,iBAAiB,eAAe;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM,gBAAiE;AAC3E,UAAM,YAAY,IAAI;AAAA,MACpB,KAAK,IAAI,IAAI,iBAAiB;AAAA,IAChC,EAAE,YAAY;AACd,WAAO,MAAM,KAAK,UAAU,uBAAuB,KAAK,IAAI,EAAE,UAAU,CAAC;AAAA,EAC3E;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,MAAiC;AACjD,WAAO,MAAM,KAAK,UAAU;AAAA,MAC1B,KAAK;AAAA,MACL;AAAA,MACA,KAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAAe,MAA+B;AAClD,UAAM,KAAK,MAAM,KAAK,YAAY,IAAI;AACtC,WAAO,GAAG,KAAK,iBAAiB,QAAQ,MAAM,GAAG,QAAQ;AAAA,EAC3D;AAAA,EAEA,MAAM,eAAe,MAIH;AAChB,UAAM,WAAW,KAAK,IAAI,IAAI,KAAK,sBAAsB;AAGzD,WAAO,MAAM;AACX,UAAI,KAAK,IAAI,IAAI,UAAU;AACzB,cAAM,IAAI,6BAA6B;AAAA,UACrC,SAAS,yEAAyE,KAAK,mBAAmB;AAAA,QAC5G,CAAC;AAAA,MACH;AACA,UAAI;AACF,YAAI,KAAK,aAAa;AACpB,gBAAM,KAAK,MAAM,KAAK,YAAY,IAAI;AACtC,cAAI,GAAI;AAAA,QACV,OAAO;AACL,gBAAM,KAAK,MAAM,KAAK,OAAO,KAAK;AAClC,cAAI,GAAI;AAAA,QACV;AAAA,MACF,QAAQ;AAAA,MAER;AACA,YAAM,MAAM,KAAK,qBAAqB;AAAA,IACxC;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/openapi/egressClient.ts","../src/adapters/egressAdapter.ts","../src/factory/defaultAdapterFactory.ts","../src/core/constants.ts","../src/config/connection.ts","../src/manager.ts","../src/sandbox.ts"],"sourcesContent":["// Copyright 2026 Alibaba Group Holding Ltd.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n// http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport createClient from \"openapi-fetch\";\nimport type { Client } from \"openapi-fetch\";\n\nimport type { paths as EgressPaths } from \"../api/egress.js\";\n\nexport type EgressClient = Client<EgressPaths>;\n\nexport interface CreateEgressClientOptions {\n /**\n * Base URL to the sandbox egress sidecar API.\n */\n baseUrl: string;\n /**\n * Extra headers applied to every request.\n */\n headers?: Record<string, string>;\n /**\n * Custom fetch implementation.\n */\n fetch?: typeof fetch;\n}\n\nexport function createEgressClient(opts: CreateEgressClientOptions): EgressClient {\n const createClientFn =\n (createClient as unknown as { default?: typeof createClient }).default ?? createClient;\n return createClientFn<EgressPaths>({\n baseUrl: opts.baseUrl,\n headers: opts.headers,\n fetch: opts.fetch,\n });\n}\n","// Copyright 2026 Alibaba Group Holding Ltd.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n// http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport type { EgressClient } from \"../openapi/egressClient.js\";\nimport { throwOnOpenApiFetchError } from \"./openapiError.js\";\nimport type { paths as EgressPaths } from \"../api/egress.js\";\nimport type { NetworkPolicy, NetworkRule } from \"../models/sandboxes.js\";\nimport type { Egress } from \"../services/egress.js\";\n\ntype ApiGetPolicyOk =\n EgressPaths[\"/policy\"][\"get\"][\"responses\"][200][\"content\"][\"application/json\"];\ntype ApiPatchRulesRequest =\n EgressPaths[\"/policy\"][\"patch\"][\"requestBody\"][\"content\"][\"application/json\"];\n\nexport class EgressAdapter implements Egress {\n constructor(private readonly client: EgressClient) {}\n\n async getPolicy(): Promise<NetworkPolicy> {\n const { data, error, response } = await this.client.GET(\"/policy\");\n throwOnOpenApiFetchError({ error, response }, \"Get sandbox egress policy failed\");\n const raw = data as ApiGetPolicyOk | undefined;\n if (!raw || typeof raw !== \"object\" || !raw.policy || typeof raw.policy !== \"object\") {\n throw new Error(\"Get sandbox egress policy failed: unexpected response shape\");\n }\n return raw.policy as NetworkPolicy;\n }\n\n async patchRules(rules: NetworkRule[]): Promise<void> {\n const body: ApiPatchRulesRequest = rules as unknown as ApiPatchRulesRequest;\n const { error, response } = await this.client.PATCH(\"/policy\", {\n body,\n });\n throwOnOpenApiFetchError({ error, response }, \"Patch sandbox egress rules failed\");\n }\n}\n","// Copyright 2026 Alibaba Group Holding Ltd.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n// http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { createExecdClient } from \"../openapi/execdClient.js\";\nimport { createEgressClient } from \"../openapi/egressClient.js\";\nimport { createLifecycleClient } from \"../openapi/lifecycleClient.js\";\n\nimport { CommandsAdapter } from \"../adapters/commandsAdapter.js\";\nimport { EgressAdapter } from \"../adapters/egressAdapter.js\";\nimport { FilesystemAdapter } from \"../adapters/filesystemAdapter.js\";\nimport { HealthAdapter } from \"../adapters/healthAdapter.js\";\nimport { MetricsAdapter } from \"../adapters/metricsAdapter.js\";\nimport { SandboxesAdapter } from \"../adapters/sandboxesAdapter.js\";\n\nimport type {\n AdapterFactory,\n CreateEgressStackOptions,\n CreateExecdStackOptions,\n CreateLifecycleStackOptions,\n EgressStack,\n ExecdStack,\n LifecycleStack,\n} from \"./adapterFactory.js\";\n\nexport class DefaultAdapterFactory implements AdapterFactory {\n createLifecycleStack(opts: CreateLifecycleStackOptions): LifecycleStack {\n const lifecycleClient = createLifecycleClient({\n baseUrl: opts.lifecycleBaseUrl,\n apiKey: opts.connectionConfig.apiKey,\n headers: opts.connectionConfig.headers,\n fetch: opts.connectionConfig.fetch,\n });\n const sandboxes = new SandboxesAdapter(lifecycleClient);\n return { sandboxes };\n }\n\n createExecdStack(opts: CreateExecdStackOptions): ExecdStack {\n const headers: Record<string, string> = {\n ...(opts.connectionConfig.headers ?? {}),\n ...(opts.endpointHeaders ?? {}),\n };\n const execdClient = createExecdClient({\n baseUrl: opts.execdBaseUrl,\n headers,\n fetch: opts.connectionConfig.fetch,\n });\n\n const health = new HealthAdapter(execdClient);\n const metrics = new MetricsAdapter(execdClient);\n const files = new FilesystemAdapter(execdClient, {\n baseUrl: opts.execdBaseUrl,\n fetch: opts.connectionConfig.fetch,\n headers,\n });\n const commands = new CommandsAdapter(execdClient, {\n baseUrl: opts.execdBaseUrl,\n fetch: opts.connectionConfig.sseFetch,\n headers,\n });\n\n return {\n commands,\n files,\n health,\n metrics,\n };\n }\n\n createEgressStack(opts: CreateEgressStackOptions): EgressStack {\n const headers: Record<string, string> = {\n ...(opts.connectionConfig.headers ?? {}),\n ...(opts.endpointHeaders ?? {}),\n };\n const egressClient = createEgressClient({\n baseUrl: opts.egressBaseUrl,\n headers,\n fetch: opts.connectionConfig.fetch,\n });\n return {\n egress: new EgressAdapter(egressClient),\n };\n }\n}\n\nexport function createDefaultAdapterFactory(): AdapterFactory {\n return new DefaultAdapterFactory();\n}\n","// Copyright 2026 Alibaba Group Holding Ltd.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n// http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nexport const DEFAULT_EXECD_PORT = 44772;\nexport const DEFAULT_EGRESS_PORT = 18080;\n\nexport const DEFAULT_ENTRYPOINT: string[] = [\"tail\", \"-f\", \"/dev/null\"];\n\nexport const DEFAULT_RESOURCE_LIMITS: Record<string, string> = {\n cpu: \"1\",\n memory: \"2Gi\",\n};\n\nexport const DEFAULT_TIMEOUT_SECONDS = 600;\nexport const DEFAULT_READY_TIMEOUT_SECONDS = 30;\nexport const DEFAULT_HEALTH_CHECK_POLLING_INTERVAL_MILLIS = 200;\n\nexport const DEFAULT_REQUEST_TIMEOUT_SECONDS = 30;\nexport const DEFAULT_USER_AGENT = \"OpenSandbox-JS-SDK/0.1.6\";\n","// Copyright 2026 Alibaba Group Holding Ltd.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport {DEFAULT_USER_AGENT} from \"../core/constants.js\";\n\nexport type ConnectionProtocol = \"http\" | \"https\";\n\n/**\n * Options for {@link ConnectionConfig}.\n *\n * Most users only need `domain`, `protocol`, and `apiKey`.\n */\nexport interface ConnectionConfigOptions {\n /**\n * API server domain (host[:port]) without scheme.\n * Examples:\n * - \"localhost:8080\"\n * - \"api.opensandbox.io\"\n *\n * You may also pass a full URL (e.g. \"http://localhost:8080\" or \"https://api.example.com\").\n * If the URL includes a path, it will be preserved and `/v1` will be appended automatically.\n */\n domain?: string;\n protocol?: ConnectionProtocol;\n apiKey?: string;\n headers?: Record<string, string>;\n\n /**\n * Request timeout applied to all SDK HTTP calls (best-effort; wraps fetch).\n * Defaults to 30 seconds.\n */\n requestTimeoutSeconds?: number;\n /**\n * Enable basic debug logging for HTTP requests (best-effort).\n */\n debug?: boolean;\n /**\n * Use sandbox server as proxy for process execd requests.\n * Useful when the client SDK cannot access the created sandbox directly.\n */\n useServerProxy?: boolean;\n}\n\nfunction isNodeRuntime(): boolean {\n const p = (globalThis as any)?.process;\n return !!p?.versions?.node;\n}\n\nfunction redactHeaders(\n headers: Record<string, string>\n): Record<string, string> {\n const out: Record<string, string> = { ...headers };\n for (const k of Object.keys(out)) {\n if (k.toLowerCase() === \"open-sandbox-api-key\") out[k] = \"***\";\n }\n return out;\n}\n\nfunction readEnv(name: string): string | undefined {\n const env = (globalThis as any)?.process?.env;\n const v = env?.[name];\n return typeof v === \"string\" && v.length ? v : undefined;\n}\n\nfunction stripTrailingSlashes(s: string): string {\n return s.replace(/\\/+$/, \"\");\n}\n\nfunction stripV1Suffix(s: string): string {\n const trimmed = stripTrailingSlashes(s);\n return trimmed.endsWith(\"/v1\") ? trimmed.slice(0, -3) : trimmed;\n}\n\nconst DEFAULT_KEEPALIVE_TIMEOUT_MS = 30_000;\n\nfunction normalizeDomainBase(input: string): {\n protocol?: ConnectionProtocol;\n domainBase: string;\n} {\n // Accept a full URL and preserve its path prefix (if any).\n if (input.startsWith(\"http://\") || input.startsWith(\"https://\")) {\n const u = new URL(input);\n const proto = u.protocol === \"https:\" ? \"https\" : \"http\";\n // Keep origin + pathname, drop query/hash.\n const base = `${u.origin}${u.pathname}`;\n return { protocol: proto, domainBase: stripV1Suffix(base) };\n }\n\n // No scheme: treat as \"host[:port]\" or \"host[:port]/prefix\" and normalize trailing \"/v1\" or \"/\".\n return { domainBase: stripV1Suffix(input) };\n}\n\nfunction createNodeFetch(): {\n fetch: typeof fetch;\n close: () => Promise<void>;\n} {\n if (!isNodeRuntime()) {\n return {\n fetch,\n close: async () => {\n // Browser fetch has no pooled dispatcher to close.\n },\n };\n }\n\n const baseFetch = fetch;\n let dispatcher: unknown | undefined;\n let dispatcherPromise: Promise<unknown> | null = null;\n\n const nodeFetch: typeof fetch = async (input: RequestInfo | URL, init?: RequestInit) => {\n dispatcherPromise ??= (async () => {\n try {\n const mod = await import(\"undici\");\n const Agent = (mod as { Agent?: new (...args: any[]) => unknown }).Agent;\n if (!Agent) {\n return undefined;\n }\n dispatcher = new Agent({\n keepAliveTimeout: DEFAULT_KEEPALIVE_TIMEOUT_MS,\n keepAliveMaxTimeout: DEFAULT_KEEPALIVE_TIMEOUT_MS,\n });\n return dispatcher;\n } catch {\n return undefined;\n }\n })();\n\n if (dispatcherPromise) {\n await dispatcherPromise;\n }\n\n if (dispatcher) {\n const mergedInit = { ...(init ?? {}), dispatcher } as RequestInit & {\n dispatcher?: unknown;\n };\n return baseFetch(input, mergedInit as RequestInit);\n }\n\n return baseFetch(input, init);\n };\n\n return {\n fetch: nodeFetch,\n close: async () => {\n if (dispatcherPromise) {\n await dispatcherPromise.catch(() => undefined);\n }\n if (\n dispatcher &&\n typeof dispatcher === \"object\" &&\n typeof (dispatcher as any).close === \"function\"\n ) {\n try {\n await (dispatcher as any).close();\n } catch {\n // swallow close errors\n }\n }\n },\n };\n}\n\nfunction createTimedFetch(opts: {\n baseFetch: typeof fetch;\n timeoutSeconds: number;\n debug: boolean;\n defaultHeaders?: Record<string, string>;\n label: string;\n}): typeof fetch {\n const baseFetch = opts.baseFetch;\n const timeoutSeconds = opts.timeoutSeconds;\n const debug = opts.debug;\n const defaultHeaders = opts.defaultHeaders ?? {};\n const label = opts.label;\n\n return async (input: RequestInfo | URL, init?: RequestInit) => {\n const method = init?.method ?? \"GET\";\n const url =\n typeof input === \"string\"\n ? input\n : (input as any)?.toString?.() ?? String(input);\n\n const ac = new AbortController();\n const timeoutMs = Math.floor(timeoutSeconds * 1000);\n const t =\n Number.isFinite(timeoutMs) && timeoutMs > 0\n ? setTimeout(\n () =>\n ac.abort(\n new Error(\n `[${label}] Request timed out (timeoutSeconds=${timeoutSeconds})`\n )\n ),\n timeoutMs\n )\n : undefined;\n\n const onAbort = () =>\n ac.abort((init?.signal as any)?.reason ?? new Error(\"Aborted\"));\n if (init?.signal) {\n if (init.signal.aborted) onAbort();\n else\n init.signal.addEventListener(\"abort\", onAbort, { once: true } as any);\n }\n\n const mergedInit: RequestInit = {\n ...init,\n signal: ac.signal,\n };\n\n if (debug) {\n const mergedHeaders = {\n ...defaultHeaders,\n ...((init?.headers ?? {}) as any),\n };\n // eslint-disable-next-line no-console\n console.log(\n `[opensandbox:${label}] ->`,\n method,\n url,\n redactHeaders(mergedHeaders)\n );\n }\n\n try {\n const res = await baseFetch(input, mergedInit);\n if (debug) {\n // eslint-disable-next-line no-console\n console.log(`[opensandbox:${label}] <-`, method, url, res.status);\n }\n return res;\n } finally {\n if (t) clearTimeout(t);\n if (init?.signal)\n init.signal.removeEventListener(\"abort\", onAbort as any);\n }\n };\n}\n\nexport class ConnectionConfig {\n readonly protocol: ConnectionProtocol;\n readonly domain: string;\n readonly apiKey?: string;\n readonly headers: Record<string, string>;\n private _fetch: typeof fetch | null;\n private _sseFetch: typeof fetch | null;\n readonly requestTimeoutSeconds: number;\n readonly debug: boolean;\n readonly userAgent: string = DEFAULT_USER_AGENT;\n /**\n * Use sandbox server as proxy for endpoint requests (default false).\n */\n readonly useServerProxy: boolean;\n private _closeTransport: () => Promise<void>;\n private _closePromise: Promise<void> | null = null;\n private _transportInitialized = false;\n\n /**\n * Create a connection configuration.\n *\n * Environment variables (optional):\n * - `OPEN_SANDBOX_DOMAIN` (default: `localhost:8080`)\n * - `OPEN_SANDBOX_API_KEY`\n */\n constructor(opts: ConnectionConfigOptions = {}) {\n const envDomain = readEnv(\"OPEN_SANDBOX_DOMAIN\");\n const envApiKey = readEnv(\"OPEN_SANDBOX_API_KEY\");\n\n const rawDomain = opts.domain ?? envDomain ?? \"localhost:8080\";\n const normalized = normalizeDomainBase(rawDomain);\n\n // If the domain includes a scheme, it overrides `protocol`.\n this.protocol = normalized.protocol ?? opts.protocol ?? \"http\";\n this.domain = normalized.domainBase;\n this.apiKey = opts.apiKey ?? envApiKey;\n this.requestTimeoutSeconds =\n typeof opts.requestTimeoutSeconds === \"number\"\n ? opts.requestTimeoutSeconds\n : 30;\n this.debug = !!opts.debug;\n this.useServerProxy = !!opts.useServerProxy;\n\n const headers: Record<string, string> = { ...(opts.headers ?? {}) };\n // Attach API key via header unless the user already provided one.\n if (this.apiKey && !headers[\"OPEN-SANDBOX-API-KEY\"]) {\n headers[\"OPEN-SANDBOX-API-KEY\"] = this.apiKey;\n }\n // Best-effort user-agent (Node only).\n if (\n isNodeRuntime() &&\n this.userAgent &&\n !headers[\"user-agent\"] &&\n !headers[\"User-Agent\"]\n ) {\n headers[\"user-agent\"] = this.userAgent;\n }\n this.headers = headers;\n this._fetch = null;\n this._sseFetch = null;\n this._closeTransport = async () => {\n // Init with empty close call\n };\n this._transportInitialized = false;\n }\n\n get fetch(): typeof fetch {\n return this._fetch ?? fetch;\n }\n\n get sseFetch(): typeof fetch {\n return this._sseFetch ?? fetch;\n }\n\n getBaseUrl(): string {\n // If `domain` already contains a scheme, treat it as a full base URL prefix.\n if (\n this.domain.startsWith(\"http://\") ||\n this.domain.startsWith(\"https://\")\n ) {\n return `${stripV1Suffix(this.domain)}/v1`;\n }\n return `${this.protocol}://${stripV1Suffix(this.domain)}/v1`;\n }\n\n private initializeTransport(): void {\n if (this._transportInitialized) return;\n\n const { fetch: baseFetch, close } = createNodeFetch();\n this._fetch = createTimedFetch({\n baseFetch,\n timeoutSeconds: this.requestTimeoutSeconds,\n debug: this.debug,\n defaultHeaders: this.headers,\n label: \"http\",\n });\n this._sseFetch = createTimedFetch({\n baseFetch,\n timeoutSeconds: 0,\n debug: this.debug,\n defaultHeaders: this.headers,\n label: \"sse\",\n });\n this._closeTransport = close;\n this._transportInitialized = true;\n }\n /**\n * Ensure this configuration has transport helpers (fetch/SSE) allocated.\n *\n * On Node.js this creates a dedicated `undici` dispatcher; on browsers it\n * simply reuses the global fetch. Returns either `this` or a cloned config\n * with the transport initialized.\n */\n withTransportIfMissing(): ConnectionConfig {\n if (this._transportInitialized) {\n return this;\n }\n\n const clone = new ConnectionConfig({\n domain: this.domain,\n protocol: this.protocol,\n apiKey: this.apiKey,\n headers: { ...this.headers },\n requestTimeoutSeconds: this.requestTimeoutSeconds,\n debug: this.debug,\n useServerProxy: this.useServerProxy,\n });\n clone.initializeTransport();\n return clone;\n }\n\n /**\n * Close the Node.js agent owned by this configuration.\n */\n async closeTransport(): Promise<void> {\n if (!this._transportInitialized) return;\n this._closePromise ??= this._closeTransport();\n await this._closePromise;\n }\n}\n","// Copyright 2026 Alibaba Group Holding Ltd.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n// http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { ConnectionConfig, type ConnectionConfigOptions } from \"./config/connection.js\";\nimport { createDefaultAdapterFactory } from \"./factory/defaultAdapterFactory.js\";\nimport type { AdapterFactory } from \"./factory/adapterFactory.js\";\n\nimport type { ListSandboxesResponse, SandboxId, SandboxInfo } from \"./models/sandboxes.js\";\nimport type { Sandboxes } from \"./services/sandboxes.js\";\n\nexport interface SandboxManagerOptions {\n /**\n * Connection configuration for calling the OpenSandbox Lifecycle API.\n */\n connectionConfig?: ConnectionConfig | ConnectionConfigOptions;\n /**\n * Advanced override: inject a custom adapter factory (custom transports, dependency injection).\n */\n adapterFactory?: AdapterFactory;\n}\n\nexport interface SandboxFilter {\n /**\n * Filter by sandbox lifecycle states.\n */\n states?: string[];\n /**\n * Filter by metadata key-value pairs.\n */\n metadata?: Record<string, string>;\n /**\n * Pagination page number (1-indexed).\n */\n page?: number;\n /**\n * Number of items per page.\n */\n pageSize?: number;\n}\n\n/**\n * Administrative interface for managing sandboxes (list/get/pause/resume/kill/renew).\n *\n * For interacting *inside* a sandbox, use {@link Sandbox}.\n */\nexport class SandboxManager {\n private readonly sandboxes: Sandboxes;\n private readonly connectionConfig: ConnectionConfig;\n\n private constructor(opts: { sandboxes: Sandboxes; connectionConfig: ConnectionConfig }) {\n this.sandboxes = opts.sandboxes;\n this.connectionConfig = opts.connectionConfig;\n }\n\n static create(opts: SandboxManagerOptions = {}): SandboxManager {\n const baseConnectionConfig = opts.connectionConfig instanceof ConnectionConfig\n ? opts.connectionConfig\n : new ConnectionConfig(opts.connectionConfig);\n const connectionConfig = baseConnectionConfig.withTransportIfMissing();\n const lifecycleBaseUrl = connectionConfig.getBaseUrl();\n const adapterFactory = opts.adapterFactory ?? createDefaultAdapterFactory();\n let sandboxes: Sandboxes;\n try {\n sandboxes = adapterFactory.createLifecycleStack({\n connectionConfig,\n lifecycleBaseUrl,\n }).sandboxes;\n } catch (err) {\n void connectionConfig.closeTransport().catch(() => undefined);\n throw err;\n }\n return new SandboxManager({ sandboxes, connectionConfig });\n }\n\n listSandboxInfos(filter: SandboxFilter = {}): Promise<ListSandboxesResponse> {\n return this.sandboxes.listSandboxes({\n states: filter.states,\n metadata: filter.metadata,\n page: filter.page,\n pageSize: filter.pageSize,\n });\n }\n\n getSandboxInfo(sandboxId: SandboxId): Promise<SandboxInfo> {\n return this.sandboxes.getSandbox(sandboxId);\n }\n\n killSandbox(sandboxId: SandboxId): Promise<void> {\n return this.sandboxes.deleteSandbox(sandboxId);\n }\n\n pauseSandbox(sandboxId: SandboxId): Promise<void> {\n return this.sandboxes.pauseSandbox(sandboxId);\n }\n\n resumeSandbox(sandboxId: SandboxId): Promise<void> {\n return this.sandboxes.resumeSandbox(sandboxId);\n }\n\n /**\n * Renew expiration by setting expiresAt to now + timeoutSeconds.\n */\n async renewSandbox(sandboxId: SandboxId, timeoutSeconds: number): Promise<void> {\n const expiresAt = new Date(Date.now() + timeoutSeconds * 1000).toISOString();\n await this.sandboxes.renewSandboxExpiration(sandboxId, { expiresAt });\n }\n\n /**\n * Release the HTTP agent resources allocated for this manager instance.\n *\n * Each manager clone owns a scoped `ConnectionConfig` clone.\n *\n * This mirrors the Python SDK's default transport lifecycle.\n */\n async close(): Promise<void> {\n await this.connectionConfig.closeTransport();\n }\n}","// Copyright 2026 Alibaba Group Holding Ltd.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n// \n// http://www.apache.org/licenses/LICENSE-2.0\n// \n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport {\n DEFAULT_ENTRYPOINT,\n DEFAULT_EGRESS_PORT,\n DEFAULT_EXECD_PORT,\n DEFAULT_HEALTH_CHECK_POLLING_INTERVAL_MILLIS,\n DEFAULT_READY_TIMEOUT_SECONDS,\n DEFAULT_RESOURCE_LIMITS,\n DEFAULT_TIMEOUT_SECONDS,\n} from \"./core/constants.js\";\nimport { ConnectionConfig, type ConnectionConfigOptions } from \"./config/connection.js\";\nimport type { SandboxFiles } from \"./services/filesystem.js\";\nimport type { Egress } from \"./services/egress.js\";\nimport { createDefaultAdapterFactory } from \"./factory/defaultAdapterFactory.js\";\nimport type { AdapterFactory } from \"./factory/adapterFactory.js\";\n\nimport type { Sandboxes } from \"./services/sandboxes.js\";\nimport type { ExecdCommands } from \"./services/execdCommands.js\";\nimport type { ExecdHealth } from \"./services/execdHealth.js\";\nimport type { ExecdMetrics } from \"./services/execdMetrics.js\";\nimport type {\n CreateSandboxRequest,\n Endpoint,\n NetworkPolicy,\n NetworkRule,\n RenewSandboxExpirationResponse,\n SandboxId,\n SandboxInfo,\n Volume,\n} from \"./models/sandboxes.js\";\nimport { SandboxReadyTimeoutException } from \"./core/exceptions.js\";\n\nconst HOST_PATH_PATTERN = /^([/]|[A-Za-z]:[\\\\/])/;\n\nexport interface SandboxCreateOptions {\n /**\n * Connection configuration for calling the OpenSandbox Lifecycle API and the sandbox's execd API.\n */\n connectionConfig?: ConnectionConfig | ConnectionConfigOptions;\n /**\n * Advanced override: inject a custom adapter factory (custom transports, dependency injection).\n */\n adapterFactory?: AdapterFactory;\n\n /**\n * Container image uri, e.g. `python:3.11`\n */\n image:\n | string\n | { uri: string; auth?: { username: string; password: string } };\n\n /**\n * Entrypoint command for the sandbox (defaults to tail -f /dev/null).\n */\n entrypoint?: string[];\n /**\n * Environment variables to inject into the sandbox runtime.\n */\n env?: Record<string, string>;\n /**\n * Custom metadata tags (used for filtering/management).\n */\n metadata?: Record<string, string>;\n /**\n * Optional outbound network policy for the sandbox.\n * If provided without defaultAction, defaults to \"deny\".\n */\n networkPolicy?: NetworkPolicy;\n /**\n * Optional list of volume mounts for persistent storage.\n * Each volume specifies a backend (host path, PVC, or OSSFS) and mount configuration.\n */\n volumes?: Volume[];\n /**\n * Opaque extension parameters passed through to the server as-is.\n */\n extensions?: Record<string, string>;\n\n /**\n * Resource limits applied to the sandbox container.\n *\n * This is forwarded to the Lifecycle API as `resourceLimits`.\n */\n resource?: Record<string, string>;\n /**\n * Sandbox timeout in seconds. Set to `null` to require explicit cleanup.\n */\n timeoutSeconds?: number | null;\n\n /**\n * Skip readiness checks during create/connect.\n *\n * When true, the SDK will not wait for lifecycle state `Running` or perform the health check.\n * The returned sandbox instance may not be ready yet.\n */\n skipHealthCheck?: boolean;\n /**\n * Optional custom readiness check used by {@link Sandbox.waitUntilReady}.\n *\n * If provided, the SDK will call this function during readiness checks instead of\n * using the default `execd` ping check.\n */\n healthCheck?: (sbx: Sandbox) => boolean | Promise<boolean>;\n readyTimeoutSeconds?: number;\n healthCheckPollingInterval?: number;\n}\n\nexport interface SandboxConnectOptions {\n /**\n * Connection configuration for calling the OpenSandbox APIs.\n */\n connectionConfig?: ConnectionConfig | ConnectionConfigOptions;\n /**\n * Advanced override: inject a custom adapter factory (custom transports, dependency injection).\n */\n adapterFactory?: AdapterFactory;\n /**\n * ID of the existing sandbox to connect to.\n */\n sandboxId: SandboxId;\n\n /**\n * Skip readiness checks after connecting.\n */\n skipHealthCheck?: boolean;\n /**\n * Optional custom readiness check used by {@link Sandbox.waitUntilReady}.\n */\n healthCheck?: (sbx: Sandbox) => boolean | Promise<boolean>;\n /**\n * Max time to wait for readiness.\n */\n readyTimeoutSeconds?: number;\n /**\n * Polling interval for readiness checks (milliseconds).\n */\n healthCheckPollingInterval?: number;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nfunction toImageSpec(\n image: SandboxCreateOptions[\"image\"]\n): CreateSandboxRequest[\"image\"] {\n if (typeof image === \"string\") return { uri: image };\n return { uri: image.uri, auth: image.auth };\n}\n\nexport class Sandbox {\n readonly id: SandboxId;\n readonly connectionConfig: ConnectionConfig;\n\n /**\n * Lifecycle (sandbox management) service.\n */\n readonly sandboxes: Sandboxes;\n\n /**\n * Execd services.\n */\n readonly commands: ExecdCommands;\n /**\n * High-level filesystem facade (JS-friendly).\n */\n readonly files: SandboxFiles;\n readonly health: ExecdHealth;\n readonly metrics: ExecdMetrics;\n\n /**\n * Internal state kept out of the public instance shape.\n *\n * This avoids nominal typing issues when multiple copies of the SDK exist in a dependency graph.\n */\n private static readonly _priv = new WeakMap<\n Sandbox,\n {\n adapterFactory: AdapterFactory;\n lifecycleBaseUrl: string;\n execdBaseUrl: string;\n egress: Egress;\n }\n >();\n\n private constructor(opts: {\n id: SandboxId;\n connectionConfig: ConnectionConfig;\n adapterFactory: AdapterFactory;\n lifecycleBaseUrl: string;\n execdBaseUrl: string;\n sandboxes: Sandboxes;\n commands: ExecdCommands;\n files: SandboxFiles;\n health: ExecdHealth;\n metrics: ExecdMetrics;\n egress: Egress;\n }) {\n this.id = opts.id;\n this.connectionConfig = opts.connectionConfig;\n Sandbox._priv.set(this, {\n adapterFactory: opts.adapterFactory,\n lifecycleBaseUrl: opts.lifecycleBaseUrl,\n execdBaseUrl: opts.execdBaseUrl,\n egress: opts.egress,\n });\n\n this.sandboxes = opts.sandboxes;\n this.commands = opts.commands;\n this.files = opts.files;\n this.health = opts.health;\n this.metrics = opts.metrics;\n }\n\n static async create(opts: SandboxCreateOptions): Promise<Sandbox> {\n // Validate volumes before allocating transport resources.\n if (opts.volumes) {\n for (const vol of opts.volumes) {\n const backendsSpecified = [vol.host, vol.pvc, vol.ossfs].filter((b) => b != null).length;\n if (backendsSpecified === 0) {\n throw new Error(\n `Volume '${vol.name}' must specify exactly one backend (host, pvc, ossfs), but none was provided.`\n );\n }\n if (backendsSpecified > 1) {\n throw new Error(\n `Volume '${vol.name}' must specify exactly one backend (host, pvc, ossfs), but multiple were provided.`\n );\n }\n if (vol.host && !HOST_PATH_PATTERN.test(vol.host.path)) {\n throw new Error(\n \"Host path must be an absolute path starting with '/' or a Windows drive letter (e.g. 'C:\\\\' or 'D:/')\"\n );\n }\n }\n }\n\n const baseConnectionConfig =\n opts.connectionConfig instanceof ConnectionConfig\n ? opts.connectionConfig\n : new ConnectionConfig(opts.connectionConfig);\n const connectionConfig = baseConnectionConfig.withTransportIfMissing();\n const lifecycleBaseUrl = connectionConfig.getBaseUrl();\n const adapterFactory = opts.adapterFactory ?? createDefaultAdapterFactory();\n\n let sandboxes: Sandboxes;\n try {\n sandboxes = adapterFactory.createLifecycleStack({\n connectionConfig,\n lifecycleBaseUrl,\n }).sandboxes;\n } catch (err) {\n await connectionConfig.closeTransport();\n throw err;\n }\n\n const rawTimeout = opts.timeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS;\n const timeoutSeconds =\n opts.timeoutSeconds === null\n ? null\n : Math.floor(rawTimeout);\n if (timeoutSeconds !== null && !Number.isFinite(timeoutSeconds)) {\n throw new Error(\n `timeoutSeconds must be a finite number, got ${opts.timeoutSeconds}`\n );\n }\n\n const req: CreateSandboxRequest = {\n image: toImageSpec(opts.image),\n entrypoint: opts.entrypoint ?? DEFAULT_ENTRYPOINT,\n resourceLimits: opts.resource ?? DEFAULT_RESOURCE_LIMITS,\n env: opts.env ?? {},\n metadata: opts.metadata ?? {},\n networkPolicy: opts.networkPolicy\n ? {\n ...opts.networkPolicy,\n defaultAction: opts.networkPolicy.defaultAction ?? \"deny\",\n }\n : undefined,\n volumes: opts.volumes,\n extensions: opts.extensions ?? {},\n };\n if (timeoutSeconds !== null) {\n req.timeout = timeoutSeconds;\n }\n\n let sandboxId: SandboxId | undefined;\n try {\n const created = await sandboxes.createSandbox(req);\n sandboxId = created.id as SandboxId;\n\n const endpoint = await sandboxes.getSandboxEndpoint(\n sandboxId,\n DEFAULT_EXECD_PORT,\n connectionConfig.useServerProxy\n );\n const egressEndpoint = await sandboxes.getSandboxEndpoint(\n sandboxId,\n DEFAULT_EGRESS_PORT,\n connectionConfig.useServerProxy\n );\n const execdBaseUrl = `${connectionConfig.protocol}://${endpoint.endpoint}`;\n const egressBaseUrl = `${connectionConfig.protocol}://${egressEndpoint.endpoint}`;\n\n const { commands, files, health, metrics } =\n adapterFactory.createExecdStack({\n connectionConfig,\n execdBaseUrl,\n endpointHeaders: endpoint.headers,\n });\n const { egress } = adapterFactory.createEgressStack({\n connectionConfig,\n egressBaseUrl,\n endpointHeaders: egressEndpoint.headers,\n });\n\n const sbx = new Sandbox({\n id: sandboxId,\n connectionConfig,\n adapterFactory,\n lifecycleBaseUrl,\n execdBaseUrl,\n sandboxes,\n commands,\n files,\n health,\n metrics,\n egress,\n });\n\n if (!(opts.skipHealthCheck ?? false)) {\n await sbx.waitUntilReady({\n readyTimeoutSeconds:\n opts.readyTimeoutSeconds ?? DEFAULT_READY_TIMEOUT_SECONDS,\n pollingIntervalMillis:\n opts.healthCheckPollingInterval ??\n DEFAULT_HEALTH_CHECK_POLLING_INTERVAL_MILLIS,\n healthCheck: opts.healthCheck,\n });\n }\n\n return sbx;\n } catch (err) {\n if (sandboxId) {\n try {\n await sandboxes.deleteSandbox(sandboxId);\n } catch {\n // Ignore cleanup failure; surface original error.\n }\n }\n await connectionConfig.closeTransport();\n throw err;\n }\n }\n\n static async connect(opts: SandboxConnectOptions): Promise<Sandbox> {\n const baseConnectionConfig =\n opts.connectionConfig instanceof ConnectionConfig\n ? opts.connectionConfig\n : new ConnectionConfig(opts.connectionConfig);\n const connectionConfig = baseConnectionConfig.withTransportIfMissing();\n const adapterFactory = opts.adapterFactory ?? createDefaultAdapterFactory();\n const lifecycleBaseUrl = connectionConfig.getBaseUrl();\n\n let sandboxes: Sandboxes;\n try {\n sandboxes = adapterFactory.createLifecycleStack({\n connectionConfig,\n lifecycleBaseUrl,\n }).sandboxes;\n } catch (err) {\n await connectionConfig.closeTransport();\n throw err;\n }\n\n try {\n const endpoint = await sandboxes.getSandboxEndpoint(\n opts.sandboxId,\n DEFAULT_EXECD_PORT,\n connectionConfig.useServerProxy\n );\n const egressEndpoint = await sandboxes.getSandboxEndpoint(\n opts.sandboxId,\n DEFAULT_EGRESS_PORT,\n connectionConfig.useServerProxy\n );\n const execdBaseUrl = `${connectionConfig.protocol}://${endpoint.endpoint}`;\n const egressBaseUrl = `${connectionConfig.protocol}://${egressEndpoint.endpoint}`;\n const { commands, files, health, metrics } =\n adapterFactory.createExecdStack({\n connectionConfig,\n execdBaseUrl,\n endpointHeaders: endpoint.headers,\n });\n const { egress } = adapterFactory.createEgressStack({\n connectionConfig,\n egressBaseUrl,\n endpointHeaders: egressEndpoint.headers,\n });\n\n const sbx = new Sandbox({\n id: opts.sandboxId,\n connectionConfig,\n adapterFactory,\n lifecycleBaseUrl,\n execdBaseUrl,\n sandboxes,\n commands,\n files,\n health,\n metrics,\n egress,\n });\n\n if (!(opts.skipHealthCheck ?? false)) {\n await sbx.waitUntilReady({\n readyTimeoutSeconds:\n opts.readyTimeoutSeconds ?? DEFAULT_READY_TIMEOUT_SECONDS,\n pollingIntervalMillis:\n opts.healthCheckPollingInterval ??\n DEFAULT_HEALTH_CHECK_POLLING_INTERVAL_MILLIS,\n healthCheck: opts.healthCheck,\n });\n }\n\n return sbx;\n } catch (err) {\n await connectionConfig.closeTransport();\n throw err;\n }\n }\n\n async getInfo(): Promise<SandboxInfo> {\n return await this.sandboxes.getSandbox(this.id);\n }\n\n async isHealthy(): Promise<boolean> {\n try {\n return await this.health.ping();\n } catch {\n return false;\n }\n }\n\n async getMetrics() {\n return await this.metrics.getMetrics();\n }\n\n async pause(): Promise<void> {\n await this.sandboxes.pauseSandbox(this.id);\n }\n\n /**\n * Resume a paused sandbox and return a fresh, connected Sandbox instance.\n *\n * After resume, the execd endpoint may change, so this method returns a new\n * {@link Sandbox} instance with a refreshed execd base URL.\n */\n async resume(\n opts: {\n skipHealthCheck?: boolean;\n readyTimeoutSeconds?: number;\n healthCheckPollingInterval?: number;\n } = {}\n ): Promise<Sandbox> {\n await this.sandboxes.resumeSandbox(this.id);\n return await Sandbox.connect({\n sandboxId: this.id,\n connectionConfig: this.connectionConfig,\n adapterFactory: Sandbox._priv.get(this)!.adapterFactory,\n skipHealthCheck: opts.skipHealthCheck ?? false,\n readyTimeoutSeconds: opts.readyTimeoutSeconds,\n healthCheckPollingInterval: opts.healthCheckPollingInterval,\n });\n }\n\n /**\n * Resume a paused sandbox by id, then connect to its execd endpoint.\n */\n static async resume(opts: SandboxConnectOptions): Promise<Sandbox> {\n const baseConnectionConfig =\n opts.connectionConfig instanceof ConnectionConfig\n ? opts.connectionConfig\n : new ConnectionConfig(opts.connectionConfig);\n const adapterFactory = opts.adapterFactory ?? createDefaultAdapterFactory();\n const resumeConnectionConfig = baseConnectionConfig.withTransportIfMissing();\n const lifecycleBaseUrl = resumeConnectionConfig.getBaseUrl();\n\n let sandboxes: Sandboxes;\n try {\n sandboxes = adapterFactory.createLifecycleStack({\n connectionConfig: resumeConnectionConfig,\n lifecycleBaseUrl,\n }).sandboxes;\n await sandboxes.resumeSandbox(opts.sandboxId);\n } catch (err) {\n await resumeConnectionConfig.closeTransport();\n throw err;\n }\n\n await resumeConnectionConfig.closeTransport();\n return await Sandbox.connect({ ...opts, connectionConfig: baseConnectionConfig, adapterFactory });\n }\n\n async kill(): Promise<void> {\n await this.sandboxes.deleteSandbox(this.id);\n }\n\n /**\n * Release any client-side resources (e.g. Node.js HTTP agents) owned by this Sandbox instance.\n */\n async close(): Promise<void> {\n await this.connectionConfig.closeTransport();\n }\n\n /**\n * Renew expiration by setting expiresAt to now + timeoutSeconds.\n */\n async renew(timeoutSeconds: number): Promise<RenewSandboxExpirationResponse> {\n const expiresAt = new Date(\n Date.now() + timeoutSeconds * 1000\n ).toISOString();\n return await this.sandboxes.renewSandboxExpiration(this.id, { expiresAt });\n }\n\n async getEgressPolicy(): Promise<NetworkPolicy> {\n return await Sandbox._priv.get(this)!.egress.getPolicy();\n }\n\n async patchEgressRules(rules: NetworkRule[]): Promise<void> {\n await Sandbox._priv.get(this)!.egress.patchRules(rules);\n }\n\n /**\n * Get sandbox endpoint for a port (STRICT: no scheme), e.g. \"localhost:44772\" or \"domain/route/.../44772\".\n */\n async getEndpoint(port: number): Promise<Endpoint> {\n return await this.sandboxes.getSandboxEndpoint(\n this.id,\n port,\n this.connectionConfig.useServerProxy\n );\n }\n\n /**\n * Get absolute endpoint URL with scheme (convenience for HTTP clients).\n */\n async getEndpointUrl(port: number): Promise<string> {\n const ep = await this.getEndpoint(port);\n return `${this.connectionConfig.protocol}://${ep.endpoint}`;\n }\n\n async waitUntilReady(opts: {\n readyTimeoutSeconds: number;\n pollingIntervalMillis: number;\n healthCheck?: (sbx: Sandbox) => boolean | Promise<boolean>;\n }): Promise<void> {\n const deadline = Date.now() + opts.readyTimeoutSeconds * 1000;\n let attempt = 0;\n let errorDetail = \"Health check returned false continuously.\";\n\n const buildTimeoutMessage = () => {\n const context = `domain=${this.connectionConfig.domain}, useServerProxy=${this.connectionConfig.useServerProxy}`;\n let suggestion =\n \"If this sandbox runs in Docker bridge or remote-network mode, consider enabling useServerProxy=true.\";\n if (!this.connectionConfig.useServerProxy) {\n suggestion += \" You can also configure server-side [docker].host_ip for direct endpoint access.\";\n }\n return `Sandbox health check timed out after ${opts.readyTimeoutSeconds}s (${attempt} attempts). ${errorDetail} Connection context: ${context}. ${suggestion}`;\n };\n\n // Wait until execd becomes reachable and passes health check.\n while (true) {\n if (Date.now() > deadline) {\n throw new SandboxReadyTimeoutException({\n message: buildTimeoutMessage(),\n });\n }\n attempt++;\n try {\n if (opts.healthCheck) {\n const ok = await opts.healthCheck(this);\n if (ok) {\n return;\n }\n } else {\n const ok = await this.health.ping();\n if (ok) {\n return;\n }\n }\n errorDetail = \"Health check returned false continuously.\";\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n errorDetail = `Last health check error: ${message}`;\n }\n await sleep(opts.pollingIntervalMillis);\n }\n }\n}\n"],"mappings":"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","names":[]}