tensorlake 0.5.29 → 0.5.30

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.d.cts CHANGED
@@ -109,6 +109,7 @@ interface CreateSandboxResponse {
109
109
  sandboxId: string;
110
110
  status: SandboxStatus;
111
111
  routingHint?: string;
112
+ ingressEndpoint?: string;
112
113
  name?: string | null;
113
114
  terminationReason?: string;
114
115
  errorDetails?: unknown;
@@ -133,12 +134,14 @@ interface SandboxInfo {
133
134
  name?: string;
134
135
  allowUnauthenticatedAccess?: boolean;
135
136
  exposedPorts?: number[];
137
+ ingressEndpoint?: string;
136
138
  sandboxUrl?: string;
137
139
  routingHint?: string;
138
140
  }
139
141
  interface SandboxPortAccess {
140
142
  allowUnauthenticatedAccess: boolean;
141
143
  exposedPorts: number[];
144
+ ingressEndpoint?: string;
142
145
  sandboxUrl?: string;
143
146
  }
144
147
  /** Sandbox information plus the archival timestamp. */
@@ -337,6 +340,9 @@ interface SandboxOptions {
337
340
  organizationId?: string;
338
341
  projectId?: string;
339
342
  routingHint?: string;
343
+ resolveProxyInfo?: (identifier: string) => Promise<SandboxInfo & {
344
+ readonly traceId: string;
345
+ }>;
340
346
  }
341
347
  interface CreateAndConnectOptions extends CreateSandboxOptions {
342
348
  poolId?: string;
@@ -509,19 +515,22 @@ declare class Pty {
509
515
  declare class Sandbox {
510
516
  readonly sandboxId: string;
511
517
  traceId: string | null;
518
+ private readonly proxy;
512
519
  private readonly http;
513
- private readonly baseUrl;
514
- private readonly wsHeaders;
515
520
  private ownsSandbox;
516
521
  private lifecycleClient;
517
522
  private lifecycleIdentifier;
518
523
  private sandboxName;
519
524
  constructor(options: SandboxOptions);
525
+ private get baseUrl();
526
+ private get wsHeaders();
520
527
  get name(): string | null;
521
528
  /** @internal Used by client wiring to keep locally cached name in sync. */
522
529
  _setName(name: string | null): void;
523
530
  /** @internal Used by lifecycle operations to pin to canonical sandbox ID. */
524
531
  _setLifecycleIdentifier(identifier: string): void;
532
+ /** @internal Used by the lazy proxy resolver. */
533
+ _getLifecycleIdentifier(): string;
525
534
  /** @internal Used by SandboxClient.createAndConnect to set ownership. */
526
535
  _setOwner(client: SandboxClient): void;
527
536
  /**
@@ -534,9 +543,9 @@ declare class Sandbox {
534
543
  /**
535
544
  * Attach to an existing sandbox and return a connected handle.
536
545
  *
537
- * Returns immediately without contacting the server. Call `sandbox.info()`
538
- * to fetch the current state on demand. Does **not** auto-resume a suspended
539
- * sandbox — call `sandbox.resume()` explicitly.
546
+ * When `proxyUrl` is omitted, resolves the sandbox first so the handle uses
547
+ * the correct cloud/region ingress endpoint. Does **not** auto-resume a
548
+ * suspended sandbox — call `sandbox.resume()` explicitly.
540
549
  */
541
550
  static connect(options: ConnectOptions & Partial<SandboxClientOptions>): Promise<Sandbox>;
542
551
  /** Get information about a snapshot by ID. No sandbox handle needed. */
@@ -1014,6 +1023,15 @@ declare class APIClient {
1014
1023
  requestOutput(applicationName: string, requestId: string): Promise<RequestOutput>;
1015
1024
  }
1016
1025
 
1026
+ /**
1027
+ * Build a public sandbox URL from a server-provided ingress endpoint.
1028
+ *
1029
+ * `port` omitted or `9501` returns the management URL:
1030
+ * `https://<sandbox-id>.<ingress-host>`. User ports use the public
1031
+ * `<port>-<sandbox-id>.<ingress-host>` form.
1032
+ */
1033
+ declare function sandboxUrlFromIngressEndpoint(ingressEndpoint: string, sandboxId: string, port?: number): string;
1034
+
1017
1035
  /** Base exception for all sandbox-related errors. */
1018
1036
  declare class SandboxException extends Error {
1019
1037
  constructor(message: string);
@@ -1062,4 +1080,4 @@ declare class RequestExecutionError extends Error {
1062
1080
  constructor(message: string, functionName?: string);
1063
1081
  }
1064
1082
 
1065
- export { APIClient, type ApiKeyIntrospection, type ApplicationBuildContext, type ApplicationBuildImageResult, type ApplicationBuildResponse, type ApplicationManifest, type ApplicationSummary, type ArchivedSandboxInfo, type BinaryPayload, type BuildInfo, type BuildLogEntry, type CheckpointOptions, type CheckpointType, CloudClient, type CloudClientOptions, type CommandResult, type ConnectDesktopOptions, type ConnectOptions, type ContainerResourcesInfo, ContainerState, type CreateAndConnectOptions, type CreateApplicationBuildImageRequest, type CreateApplicationBuildRequest, type CreatePoolOptions, type CreatePtyOptions, type CreatePtySessionOptions, type CreateSandboxOptions, type CreateSandboxPoolResponse, type CreateSandboxResponse, type CreateSnapshotResponse, type CreateTunnelOptions, type DaemonInfo, Desktop, type DesktopDoubleClickOptions, type DesktopPointerOptions, type DirectoryEntry, type HealthResponse, type ListArchivedSandboxesOptions, type ListArchivedSandboxesResponse, type ListDirectoryResponse, type MouseButton, type NetworkConfig, type NewSecret, type OutputEvent, OutputMode, type OutputResponse, type PoolContainerInfo, PoolInUseError, PoolNotFoundError, type ProcessInfo, ProcessStatus, type ProcessUser, type ProcessUserSpec, Pty, type PtyConnectionOptions, type PtyDataHandler, type PtyExitHandler, type PtySessionInfo, RemoteAPIError, type RequestErrorInfo, RequestExecutionError, RequestFailedError, type RequestInput, type RequestMetadata, RequestNotFinishedError, type RequestOutput, type RunOptions, Sandbox, SandboxClient, type SandboxClientOptions, SandboxConnectionError, SandboxError, SandboxException, type SandboxInfo, SandboxNotFoundError, type SandboxOptions, type SandboxPoolInfo, type SandboxPortAccess, SandboxStatus, type Secret, type SecretsList, type SecretsPagination, type SendSignalResponse, type SnapshotAndWaitOptions, type SnapshotInfo, type SnapshotOptions, SnapshotStatus, type SnapshotType, type SnapshotWaitCondition, type StartImageBuildRequest, type StartProcessOptions, StdinMode, type SuspendResumeOptions, TcpTunnel, type TunnelAddress, type UpdatePoolOptions, type UpsertSecretResponse };
1083
+ export { APIClient, type ApiKeyIntrospection, type ApplicationBuildContext, type ApplicationBuildImageResult, type ApplicationBuildResponse, type ApplicationManifest, type ApplicationSummary, type ArchivedSandboxInfo, type BinaryPayload, type BuildInfo, type BuildLogEntry, type CheckpointOptions, type CheckpointType, CloudClient, type CloudClientOptions, type CommandResult, type ConnectDesktopOptions, type ConnectOptions, type ContainerResourcesInfo, ContainerState, type CreateAndConnectOptions, type CreateApplicationBuildImageRequest, type CreateApplicationBuildRequest, type CreatePoolOptions, type CreatePtyOptions, type CreatePtySessionOptions, type CreateSandboxOptions, type CreateSandboxPoolResponse, type CreateSandboxResponse, type CreateSnapshotResponse, type CreateTunnelOptions, type DaemonInfo, Desktop, type DesktopDoubleClickOptions, type DesktopPointerOptions, type DirectoryEntry, type HealthResponse, type ListArchivedSandboxesOptions, type ListArchivedSandboxesResponse, type ListDirectoryResponse, type MouseButton, type NetworkConfig, type NewSecret, type OutputEvent, OutputMode, type OutputResponse, type PoolContainerInfo, PoolInUseError, PoolNotFoundError, type ProcessInfo, ProcessStatus, type ProcessUser, type ProcessUserSpec, Pty, type PtyConnectionOptions, type PtyDataHandler, type PtyExitHandler, type PtySessionInfo, RemoteAPIError, type RequestErrorInfo, RequestExecutionError, RequestFailedError, type RequestInput, type RequestMetadata, RequestNotFinishedError, type RequestOutput, type RunOptions, Sandbox, SandboxClient, type SandboxClientOptions, SandboxConnectionError, SandboxError, SandboxException, type SandboxInfo, SandboxNotFoundError, type SandboxOptions, type SandboxPoolInfo, type SandboxPortAccess, SandboxStatus, type Secret, type SecretsList, type SecretsPagination, type SendSignalResponse, type SnapshotAndWaitOptions, type SnapshotInfo, type SnapshotOptions, SnapshotStatus, type SnapshotType, type SnapshotWaitCondition, type StartImageBuildRequest, type StartProcessOptions, StdinMode, type SuspendResumeOptions, TcpTunnel, type TunnelAddress, type UpdatePoolOptions, type UpsertSecretResponse, sandboxUrlFromIngressEndpoint };
package/dist/index.d.ts CHANGED
@@ -109,6 +109,7 @@ interface CreateSandboxResponse {
109
109
  sandboxId: string;
110
110
  status: SandboxStatus;
111
111
  routingHint?: string;
112
+ ingressEndpoint?: string;
112
113
  name?: string | null;
113
114
  terminationReason?: string;
114
115
  errorDetails?: unknown;
@@ -133,12 +134,14 @@ interface SandboxInfo {
133
134
  name?: string;
134
135
  allowUnauthenticatedAccess?: boolean;
135
136
  exposedPorts?: number[];
137
+ ingressEndpoint?: string;
136
138
  sandboxUrl?: string;
137
139
  routingHint?: string;
138
140
  }
139
141
  interface SandboxPortAccess {
140
142
  allowUnauthenticatedAccess: boolean;
141
143
  exposedPorts: number[];
144
+ ingressEndpoint?: string;
142
145
  sandboxUrl?: string;
143
146
  }
144
147
  /** Sandbox information plus the archival timestamp. */
@@ -337,6 +340,9 @@ interface SandboxOptions {
337
340
  organizationId?: string;
338
341
  projectId?: string;
339
342
  routingHint?: string;
343
+ resolveProxyInfo?: (identifier: string) => Promise<SandboxInfo & {
344
+ readonly traceId: string;
345
+ }>;
340
346
  }
341
347
  interface CreateAndConnectOptions extends CreateSandboxOptions {
342
348
  poolId?: string;
@@ -509,19 +515,22 @@ declare class Pty {
509
515
  declare class Sandbox {
510
516
  readonly sandboxId: string;
511
517
  traceId: string | null;
518
+ private readonly proxy;
512
519
  private readonly http;
513
- private readonly baseUrl;
514
- private readonly wsHeaders;
515
520
  private ownsSandbox;
516
521
  private lifecycleClient;
517
522
  private lifecycleIdentifier;
518
523
  private sandboxName;
519
524
  constructor(options: SandboxOptions);
525
+ private get baseUrl();
526
+ private get wsHeaders();
520
527
  get name(): string | null;
521
528
  /** @internal Used by client wiring to keep locally cached name in sync. */
522
529
  _setName(name: string | null): void;
523
530
  /** @internal Used by lifecycle operations to pin to canonical sandbox ID. */
524
531
  _setLifecycleIdentifier(identifier: string): void;
532
+ /** @internal Used by the lazy proxy resolver. */
533
+ _getLifecycleIdentifier(): string;
525
534
  /** @internal Used by SandboxClient.createAndConnect to set ownership. */
526
535
  _setOwner(client: SandboxClient): void;
527
536
  /**
@@ -534,9 +543,9 @@ declare class Sandbox {
534
543
  /**
535
544
  * Attach to an existing sandbox and return a connected handle.
536
545
  *
537
- * Returns immediately without contacting the server. Call `sandbox.info()`
538
- * to fetch the current state on demand. Does **not** auto-resume a suspended
539
- * sandbox — call `sandbox.resume()` explicitly.
546
+ * When `proxyUrl` is omitted, resolves the sandbox first so the handle uses
547
+ * the correct cloud/region ingress endpoint. Does **not** auto-resume a
548
+ * suspended sandbox — call `sandbox.resume()` explicitly.
540
549
  */
541
550
  static connect(options: ConnectOptions & Partial<SandboxClientOptions>): Promise<Sandbox>;
542
551
  /** Get information about a snapshot by ID. No sandbox handle needed. */
@@ -1014,6 +1023,15 @@ declare class APIClient {
1014
1023
  requestOutput(applicationName: string, requestId: string): Promise<RequestOutput>;
1015
1024
  }
1016
1025
 
1026
+ /**
1027
+ * Build a public sandbox URL from a server-provided ingress endpoint.
1028
+ *
1029
+ * `port` omitted or `9501` returns the management URL:
1030
+ * `https://<sandbox-id>.<ingress-host>`. User ports use the public
1031
+ * `<port>-<sandbox-id>.<ingress-host>` form.
1032
+ */
1033
+ declare function sandboxUrlFromIngressEndpoint(ingressEndpoint: string, sandboxId: string, port?: number): string;
1034
+
1017
1035
  /** Base exception for all sandbox-related errors. */
1018
1036
  declare class SandboxException extends Error {
1019
1037
  constructor(message: string);
@@ -1062,4 +1080,4 @@ declare class RequestExecutionError extends Error {
1062
1080
  constructor(message: string, functionName?: string);
1063
1081
  }
1064
1082
 
1065
- export { APIClient, type ApiKeyIntrospection, type ApplicationBuildContext, type ApplicationBuildImageResult, type ApplicationBuildResponse, type ApplicationManifest, type ApplicationSummary, type ArchivedSandboxInfo, type BinaryPayload, type BuildInfo, type BuildLogEntry, type CheckpointOptions, type CheckpointType, CloudClient, type CloudClientOptions, type CommandResult, type ConnectDesktopOptions, type ConnectOptions, type ContainerResourcesInfo, ContainerState, type CreateAndConnectOptions, type CreateApplicationBuildImageRequest, type CreateApplicationBuildRequest, type CreatePoolOptions, type CreatePtyOptions, type CreatePtySessionOptions, type CreateSandboxOptions, type CreateSandboxPoolResponse, type CreateSandboxResponse, type CreateSnapshotResponse, type CreateTunnelOptions, type DaemonInfo, Desktop, type DesktopDoubleClickOptions, type DesktopPointerOptions, type DirectoryEntry, type HealthResponse, type ListArchivedSandboxesOptions, type ListArchivedSandboxesResponse, type ListDirectoryResponse, type MouseButton, type NetworkConfig, type NewSecret, type OutputEvent, OutputMode, type OutputResponse, type PoolContainerInfo, PoolInUseError, PoolNotFoundError, type ProcessInfo, ProcessStatus, type ProcessUser, type ProcessUserSpec, Pty, type PtyConnectionOptions, type PtyDataHandler, type PtyExitHandler, type PtySessionInfo, RemoteAPIError, type RequestErrorInfo, RequestExecutionError, RequestFailedError, type RequestInput, type RequestMetadata, RequestNotFinishedError, type RequestOutput, type RunOptions, Sandbox, SandboxClient, type SandboxClientOptions, SandboxConnectionError, SandboxError, SandboxException, type SandboxInfo, SandboxNotFoundError, type SandboxOptions, type SandboxPoolInfo, type SandboxPortAccess, SandboxStatus, type Secret, type SecretsList, type SecretsPagination, type SendSignalResponse, type SnapshotAndWaitOptions, type SnapshotInfo, type SnapshotOptions, SnapshotStatus, type SnapshotType, type SnapshotWaitCondition, type StartImageBuildRequest, type StartProcessOptions, StdinMode, type SuspendResumeOptions, TcpTunnel, type TunnelAddress, type UpdatePoolOptions, type UpsertSecretResponse };
1083
+ export { APIClient, type ApiKeyIntrospection, type ApplicationBuildContext, type ApplicationBuildImageResult, type ApplicationBuildResponse, type ApplicationManifest, type ApplicationSummary, type ArchivedSandboxInfo, type BinaryPayload, type BuildInfo, type BuildLogEntry, type CheckpointOptions, type CheckpointType, CloudClient, type CloudClientOptions, type CommandResult, type ConnectDesktopOptions, type ConnectOptions, type ContainerResourcesInfo, ContainerState, type CreateAndConnectOptions, type CreateApplicationBuildImageRequest, type CreateApplicationBuildRequest, type CreatePoolOptions, type CreatePtyOptions, type CreatePtySessionOptions, type CreateSandboxOptions, type CreateSandboxPoolResponse, type CreateSandboxResponse, type CreateSnapshotResponse, type CreateTunnelOptions, type DaemonInfo, Desktop, type DesktopDoubleClickOptions, type DesktopPointerOptions, type DirectoryEntry, type HealthResponse, type ListArchivedSandboxesOptions, type ListArchivedSandboxesResponse, type ListDirectoryResponse, type MouseButton, type NetworkConfig, type NewSecret, type OutputEvent, OutputMode, type OutputResponse, type PoolContainerInfo, PoolInUseError, PoolNotFoundError, type ProcessInfo, ProcessStatus, type ProcessUser, type ProcessUserSpec, Pty, type PtyConnectionOptions, type PtyDataHandler, type PtyExitHandler, type PtySessionInfo, RemoteAPIError, type RequestErrorInfo, RequestExecutionError, RequestFailedError, type RequestInput, type RequestMetadata, RequestNotFinishedError, type RequestOutput, type RunOptions, Sandbox, SandboxClient, type SandboxClientOptions, SandboxConnectionError, SandboxError, SandboxException, type SandboxInfo, SandboxNotFoundError, type SandboxOptions, type SandboxPoolInfo, type SandboxPortAccess, SandboxStatus, type Secret, type SecretsList, type SecretsPagination, type SendSignalResponse, type SnapshotAndWaitOptions, type SnapshotInfo, type SnapshotOptions, SnapshotStatus, type SnapshotType, type SnapshotWaitCondition, type StartImageBuildRequest, type StartProcessOptions, StdinMode, type SuspendResumeOptions, TcpTunnel, type TunnelAddress, type UpdatePoolOptions, type UpsertSecretResponse, sandboxUrlFromIngressEndpoint };
package/dist/index.js CHANGED
@@ -19,7 +19,7 @@ var SDK_VERSION, API_URL, API_KEY, NAMESPACE, SANDBOX_PROXY_URL, DEFAULT_HTTP_TI
19
19
  var init_defaults = __esm({
20
20
  "src/defaults.ts"() {
21
21
  "use strict";
22
- SDK_VERSION = "0.5.29";
22
+ SDK_VERSION = "0.5.30";
23
23
  API_URL = process.env.TENSORLAKE_API_URL ?? "https://api.tensorlake.ai";
24
24
  API_KEY = process.env.TENSORLAKE_API_KEY ?? void 0;
25
25
  NAMESPACE = process.env.INDEXIFY_NAMESPACE ?? "default";
@@ -2957,6 +2957,14 @@ function resolveProxyTarget(proxyUrl, sandboxId) {
2957
2957
  };
2958
2958
  }
2959
2959
  }
2960
+ function sandboxUrlFromIngressEndpoint(ingressEndpoint, sandboxId, port = 9501) {
2961
+ const parsed = new URL(ingressEndpoint);
2962
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
2963
+ throw new Error("ingressEndpoint must be an absolute http(s) URL");
2964
+ }
2965
+ const label = port === 9501 ? sandboxId : `${port}-${sandboxId}`;
2966
+ return `${parsed.protocol}//${label}.${parsed.host}`;
2967
+ }
2960
2968
  function resolveSandboxLifecycleUrl(apiUrl) {
2961
2969
  if (isLocalhost(apiUrl)) return apiUrl;
2962
2970
  try {
@@ -3016,7 +3024,7 @@ function sendPtyFrame(socket, frame) {
3016
3024
  socket.send(frame, (error) => error ? reject(error) : resolve());
3017
3025
  });
3018
3026
  }
3019
- var DEFAULT_PROCESS_USER, PTY_OP_DATA, PTY_OP_RESIZE, PTY_OP_READY, PTY_OP_EXIT, Pty, Sandbox;
3027
+ var DEFAULT_PROCESS_USER, SandboxProxyConnection, PTY_OP_DATA, PTY_OP_RESIZE, PTY_OP_READY, PTY_OP_EXIT, Pty, Sandbox;
3020
3028
  var init_sandbox = __esm({
3021
3029
  "src/sandbox.ts"() {
3022
3030
  "use strict";
@@ -3029,6 +3037,98 @@ var init_sandbox = __esm({
3029
3037
  init_sse();
3030
3038
  init_url();
3031
3039
  DEFAULT_PROCESS_USER = "tl-user";
3040
+ SandboxProxyConnection = class {
3041
+ constructor(sandbox, options) {
3042
+ this.sandbox = sandbox;
3043
+ this.options = options;
3044
+ this.routingHint = options.routingHint;
3045
+ this.http = this.configureProxy(
3046
+ options.proxyUrl ?? SANDBOX_PROXY_URL,
3047
+ options.sandboxId,
3048
+ options.routingHint
3049
+ );
3050
+ this.resolveProxyInfo = options.resolveProxyInfo;
3051
+ }
3052
+ baseUrl = "";
3053
+ wsHeaders = {};
3054
+ http;
3055
+ resolveProxyInfo;
3056
+ resolvePromise = null;
3057
+ routingHint;
3058
+ async ensureResolved() {
3059
+ if (this.resolveProxyInfo == null) {
3060
+ return;
3061
+ }
3062
+ if (this.resolvePromise != null) {
3063
+ return this.resolvePromise;
3064
+ }
3065
+ this.resolvePromise = this.resolveProxyInfo(this.sandbox._getLifecycleIdentifier()).then((info) => {
3066
+ this.resolveProxyInfo = void 0;
3067
+ this.sandbox.traceId = info.traceId;
3068
+ this.sandbox._setLifecycleIdentifier(info.sandboxId);
3069
+ this.sandbox._setName(info.name ?? null);
3070
+ this.routingHint = this.routingHint ?? info.routingHint;
3071
+ const proxyUrl = info.ingressEndpoint ?? this.options.proxyUrl ?? SANDBOX_PROXY_URL;
3072
+ const nextHttp = this.configureProxy(proxyUrl, info.sandboxId, this.routingHint);
3073
+ this.http.close();
3074
+ this.http = nextHttp;
3075
+ }).finally(() => {
3076
+ this.resolvePromise = null;
3077
+ });
3078
+ return this.resolvePromise;
3079
+ }
3080
+ async requestJson(method, path2, options) {
3081
+ await this.ensureResolved();
3082
+ return this.http.requestJson(method, path2, options);
3083
+ }
3084
+ async requestBytes(method, path2, options) {
3085
+ await this.ensureResolved();
3086
+ return this.http.requestBytes(method, path2, options);
3087
+ }
3088
+ async requestStream(method, path2, options) {
3089
+ await this.ensureResolved();
3090
+ return this.http.requestStream(method, path2, options);
3091
+ }
3092
+ async requestResponse(method, path2, options) {
3093
+ await this.ensureResolved();
3094
+ return this.http.requestResponse(method, path2, options);
3095
+ }
3096
+ close() {
3097
+ this.http.close();
3098
+ }
3099
+ configureProxy(proxyUrl, sandboxId, routingHint) {
3100
+ const { baseUrl, hostHeader, sandboxIdHeader } = resolveProxyTarget(
3101
+ proxyUrl,
3102
+ sandboxId
3103
+ );
3104
+ this.baseUrl = baseUrl;
3105
+ this.wsHeaders = {};
3106
+ if (this.options.apiKey) {
3107
+ this.wsHeaders.Authorization = `Bearer ${this.options.apiKey}`;
3108
+ }
3109
+ if (this.options.organizationId) {
3110
+ this.wsHeaders["X-Forwarded-Organization-Id"] = this.options.organizationId;
3111
+ }
3112
+ if (this.options.projectId) {
3113
+ this.wsHeaders["X-Forwarded-Project-Id"] = this.options.projectId;
3114
+ }
3115
+ if (hostHeader) {
3116
+ this.wsHeaders.Host = hostHeader;
3117
+ }
3118
+ if (sandboxIdHeader) {
3119
+ this.wsHeaders["X-Tensorlake-Sandbox-Id"] = sandboxIdHeader;
3120
+ }
3121
+ return new HttpClient({
3122
+ baseUrl,
3123
+ apiKey: this.options.apiKey,
3124
+ organizationId: this.options.organizationId,
3125
+ projectId: this.options.projectId,
3126
+ hostHeader,
3127
+ sandboxIdHeader,
3128
+ routingHint
3129
+ });
3130
+ }
3131
+ };
3032
3132
  PTY_OP_DATA = 0;
3033
3133
  PTY_OP_RESIZE = 1;
3034
3134
  PTY_OP_READY = 2;
@@ -3194,9 +3294,8 @@ var init_sandbox = __esm({
3194
3294
  Sandbox = class {
3195
3295
  sandboxId;
3196
3296
  traceId = null;
3297
+ proxy;
3197
3298
  http;
3198
- baseUrl;
3199
- wsHeaders;
3200
3299
  ownsSandbox = false;
3201
3300
  lifecycleClient = null;
3202
3301
  lifecycleIdentifier;
@@ -3204,34 +3303,14 @@ var init_sandbox = __esm({
3204
3303
  constructor(options) {
3205
3304
  this.sandboxId = options.sandboxId;
3206
3305
  this.lifecycleIdentifier = options.sandboxId;
3207
- const proxyUrl = options.proxyUrl ?? SANDBOX_PROXY_URL;
3208
- const { baseUrl, hostHeader, sandboxIdHeader } = resolveProxyTarget(proxyUrl, options.sandboxId);
3209
- this.baseUrl = baseUrl;
3210
- this.wsHeaders = {};
3211
- if (options.apiKey) {
3212
- this.wsHeaders.Authorization = `Bearer ${options.apiKey}`;
3213
- }
3214
- if (options.organizationId) {
3215
- this.wsHeaders["X-Forwarded-Organization-Id"] = options.organizationId;
3216
- }
3217
- if (options.projectId) {
3218
- this.wsHeaders["X-Forwarded-Project-Id"] = options.projectId;
3219
- }
3220
- if (hostHeader) {
3221
- this.wsHeaders.Host = hostHeader;
3222
- }
3223
- if (sandboxIdHeader) {
3224
- this.wsHeaders["X-Tensorlake-Sandbox-Id"] = sandboxIdHeader;
3225
- }
3226
- this.http = new HttpClient({
3227
- baseUrl,
3228
- apiKey: options.apiKey,
3229
- organizationId: options.organizationId,
3230
- projectId: options.projectId,
3231
- hostHeader,
3232
- sandboxIdHeader,
3233
- routingHint: options.routingHint
3234
- });
3306
+ this.proxy = new SandboxProxyConnection(this, options);
3307
+ this.http = this.proxy;
3308
+ }
3309
+ get baseUrl() {
3310
+ return this.proxy.baseUrl;
3311
+ }
3312
+ get wsHeaders() {
3313
+ return this.proxy.wsHeaders;
3235
3314
  }
3236
3315
  get name() {
3237
3316
  return this.sandboxName;
@@ -3244,6 +3323,10 @@ var init_sandbox = __esm({
3244
3323
  _setLifecycleIdentifier(identifier) {
3245
3324
  this.lifecycleIdentifier = identifier;
3246
3325
  }
3326
+ /** @internal Used by the lazy proxy resolver. */
3327
+ _getLifecycleIdentifier() {
3328
+ return this.lifecycleIdentifier;
3329
+ }
3247
3330
  /** @internal Used by SandboxClient.createAndConnect to set ownership. */
3248
3331
  _setOwner(client) {
3249
3332
  this.ownsSandbox = true;
@@ -3270,9 +3353,9 @@ var init_sandbox = __esm({
3270
3353
  /**
3271
3354
  * Attach to an existing sandbox and return a connected handle.
3272
3355
  *
3273
- * Returns immediately without contacting the server. Call `sandbox.info()`
3274
- * to fetch the current state on demand. Does **not** auto-resume a suspended
3275
- * sandbox — call `sandbox.resume()` explicitly.
3356
+ * When `proxyUrl` is omitted, resolves the sandbox first so the handle uses
3357
+ * the correct cloud/region ingress endpoint. Does **not** auto-resume a
3358
+ * suspended sandbox — call `sandbox.resume()` explicitly.
3276
3359
  */
3277
3360
  static async connect(options) {
3278
3361
  const { SandboxClient: SandboxClient2 } = await Promise.resolve().then(() => (init_client(), client_exports));
@@ -3686,6 +3769,7 @@ var init_sandbox = __esm({
3686
3769
  }
3687
3770
  /** Attach to an existing PTY session by ID and token and return a connected `Pty` handle. */
3688
3771
  async connectPty(sessionId, token, options) {
3772
+ await this.proxy.ensureResolved();
3689
3773
  const wsUrl = new URL(this.ptyWsUrl(sessionId, token));
3690
3774
  const authToken = wsUrl.searchParams.get("token") ?? token;
3691
3775
  const pty = new Pty({
@@ -3711,6 +3795,7 @@ var init_sandbox = __esm({
3711
3795
  }
3712
3796
  /** Open a TCP tunnel to a port inside the sandbox and return the local listener. */
3713
3797
  async createTunnel(remotePort, options) {
3798
+ await this.proxy.ensureResolved();
3714
3799
  return TcpTunnel.listen({
3715
3800
  baseUrl: this.baseUrl,
3716
3801
  wsHeaders: this.wsHeaders,
@@ -3722,6 +3807,7 @@ var init_sandbox = __esm({
3722
3807
  }
3723
3808
  /** Connect to a sandbox VNC session for programmatic desktop control. */
3724
3809
  async connectDesktop(options) {
3810
+ await this.proxy.ensureResolved();
3725
3811
  const port = options?.port ?? 5901;
3726
3812
  const connectTimeout = options?.connectTimeout ?? 10;
3727
3813
  const startMs = Date.now();
@@ -4041,6 +4127,7 @@ var init_client = __esm({
4041
4127
  return {
4042
4128
  allowUnauthenticatedAccess: info.allowUnauthenticatedAccess ?? false,
4043
4129
  exposedPorts: dedupeAndSortPorts(info.exposedPorts ?? []),
4130
+ ingressEndpoint: info.ingressEndpoint,
4044
4131
  sandboxUrl: info.sandboxUrl
4045
4132
  };
4046
4133
  }
@@ -4314,7 +4401,8 @@ var init_client = __esm({
4314
4401
  apiKey: this.apiKey,
4315
4402
  organizationId: this.organizationId,
4316
4403
  projectId: this.projectId,
4317
- routingHint
4404
+ routingHint,
4405
+ resolveProxyInfo: proxyUrl == null ? async (currentIdentifier) => this.get(currentIdentifier) : void 0
4318
4406
  });
4319
4407
  }
4320
4408
  /**
@@ -4330,8 +4418,12 @@ var init_client = __esm({
4330
4418
  const startupTimeout = options?.startupTimeout ?? 60;
4331
4419
  const result = options?.poolId != null ? await this.claim(options.poolId) : await this.create(options);
4332
4420
  const requestedName = options?.poolId != null ? null : options?.name ?? null;
4333
- const finishConnect = (routingHint, name) => {
4334
- const sandbox = this.connect(result.sandboxId, options?.proxyUrl, routingHint);
4421
+ const finishConnect = (routingHint, name, ingressEndpoint) => {
4422
+ const sandbox = this.connect(
4423
+ result.sandboxId,
4424
+ options?.proxyUrl ?? ingressEndpoint,
4425
+ routingHint
4426
+ );
4335
4427
  sandbox._setOwner(this);
4336
4428
  sandbox.traceId = result.traceId;
4337
4429
  sandbox._setLifecycleIdentifier(result.sandboxId);
@@ -4339,7 +4431,7 @@ var init_client = __esm({
4339
4431
  return sandbox;
4340
4432
  };
4341
4433
  if (result.status === "running" /* RUNNING */) {
4342
- return finishConnect(result.routingHint, result.name);
4434
+ return finishConnect(result.routingHint, result.name, result.ingressEndpoint);
4343
4435
  }
4344
4436
  if (result.status === "suspended" /* SUSPENDED */ || result.status === "terminated" /* TERMINATED */) {
4345
4437
  throw new SandboxError(
@@ -4353,7 +4445,7 @@ var init_client = __esm({
4353
4445
  while (Date.now() < deadline) {
4354
4446
  const info = await this.get(result.sandboxId);
4355
4447
  if (info.status === "running" /* RUNNING */) {
4356
- return finishConnect(info.routingHint, info.name);
4448
+ return finishConnect(info.routingHint, info.name, info.ingressEndpoint);
4357
4449
  }
4358
4450
  if (info.status === "suspended" /* SUSPENDED */ || info.status === "terminated" /* TERMINATED */) {
4359
4451
  throw new SandboxError(
@@ -5121,6 +5213,7 @@ var APIClient = class {
5121
5213
  // src/index.ts
5122
5214
  init_sandbox_image();
5123
5215
  init_image();
5216
+ init_url();
5124
5217
  init_errors();
5125
5218
  init_models();
5126
5219
  export {
@@ -5150,6 +5243,7 @@ export {
5150
5243
  StdinMode,
5151
5244
  TcpTunnel,
5152
5245
  createSandboxImage,
5153
- dockerfileContent
5246
+ dockerfileContent,
5247
+ sandboxUrlFromIngressEndpoint
5154
5248
  };
5155
5249
  //# sourceMappingURL=index.js.map