@cloudflare/sandbox 0.12.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/bridge/index.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/openai/index.d.ts +1 -1
- package/dist/opencode/index.d.ts +1 -1
- package/dist/{sandbox-D3N9M5EI.d.ts → sandbox-C8l-pMlL.d.ts} +9 -8
- package/dist/{sandbox-D3N9M5EI.d.ts.map → sandbox-C8l-pMlL.d.ts.map} +1 -1
- package/dist/{sandbox-Duj2gvUC.js → sandbox-DKG3H156.js} +79 -78
- package/dist/sandbox-DKG3H156.js.map +1 -0
- package/package.json +1 -1
- package/dist/sandbox-Duj2gvUC.js.map +0 -1
|
@@ -719,6 +719,53 @@ function createErrorFromResponse(errorResponse, options) {
|
|
|
719
719
|
}
|
|
720
720
|
}
|
|
721
721
|
|
|
722
|
+
//#endregion
|
|
723
|
+
//#region src/response-retry.ts
|
|
724
|
+
const DEFAULT_INITIAL_RETRY_DELAY_MS = 3e3;
|
|
725
|
+
const DEFAULT_MAX_RETRY_DELAY_MS = 3e4;
|
|
726
|
+
const RETRYABLE_WEBSOCKET_UPGRADE_STATUSES = new Set([
|
|
727
|
+
500,
|
|
728
|
+
502,
|
|
729
|
+
503,
|
|
730
|
+
504
|
|
731
|
+
]);
|
|
732
|
+
function isRetryableWebSocketUpgradeResponse(response) {
|
|
733
|
+
return RETRYABLE_WEBSOCKET_UPGRADE_STATUSES.has(response.status);
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Retry Response-returning operations while their response remains retryable.
|
|
737
|
+
* The retry budget covers the whole operation; each attempt owns any
|
|
738
|
+
* per-request timeout inside the caller-provided `fetchResponse` function.
|
|
739
|
+
*/
|
|
740
|
+
async function fetchWithResponseRetry(fetchResponse, options) {
|
|
741
|
+
const startTime = Date.now();
|
|
742
|
+
let attempt = 0;
|
|
743
|
+
while (true) {
|
|
744
|
+
const response = await fetchResponse();
|
|
745
|
+
if (!options.shouldRetry(response)) return response;
|
|
746
|
+
const elapsed = Date.now() - startTime;
|
|
747
|
+
const remaining = options.retryTimeoutMs - elapsed;
|
|
748
|
+
if (remaining <= options.minTimeForRetryMs) {
|
|
749
|
+
options.onRetryExhausted?.({
|
|
750
|
+
attempts: attempt + 1,
|
|
751
|
+
elapsedMs: elapsed,
|
|
752
|
+
response
|
|
753
|
+
});
|
|
754
|
+
return response;
|
|
755
|
+
}
|
|
756
|
+
const delay = Math.min(DEFAULT_INITIAL_RETRY_DELAY_MS * 2 ** attempt, DEFAULT_MAX_RETRY_DELAY_MS);
|
|
757
|
+
options.logger.info(options.retryLogMessage, {
|
|
758
|
+
status: response.status,
|
|
759
|
+
attempt: attempt + 1,
|
|
760
|
+
delayMs: delay,
|
|
761
|
+
remainingSec: Math.floor(remaining / 1e3),
|
|
762
|
+
...options.getRetryLogContext?.(response)
|
|
763
|
+
});
|
|
764
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
765
|
+
attempt++;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
722
769
|
//#endregion
|
|
723
770
|
//#region src/clients/transport/base-transport.ts
|
|
724
771
|
/**
|
|
@@ -754,30 +801,17 @@ var BaseTransport = class {
|
|
|
754
801
|
* transport-specific doFetch() with retry logic for container startup.
|
|
755
802
|
*/
|
|
756
803
|
async fetch(path$1, options) {
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
this.logger.info("Container not ready, retrying", {
|
|
767
|
-
status: response.status,
|
|
768
|
-
attempt: attempt + 1,
|
|
769
|
-
delayMs: delay,
|
|
770
|
-
remainingSec: Math.floor(remaining / 1e3),
|
|
771
|
-
mode: this.getMode()
|
|
772
|
-
});
|
|
773
|
-
await this.sleep(delay);
|
|
774
|
-
attempt++;
|
|
775
|
-
continue;
|
|
776
|
-
}
|
|
777
|
-
this.logger.error("Container failed to become ready", /* @__PURE__ */ new Error(`Failed after ${attempt + 1} attempts over ${Math.floor(elapsed / 1e3)}s`));
|
|
804
|
+
return fetchWithResponseRetry(() => this.doFetch(path$1, options), {
|
|
805
|
+
retryTimeoutMs: this.retryTimeoutMs,
|
|
806
|
+
minTimeForRetryMs: MIN_TIME_FOR_RETRY_MS$1,
|
|
807
|
+
logger: this.logger,
|
|
808
|
+
retryLogMessage: "Container not ready, retrying",
|
|
809
|
+
shouldRetry: (response) => response.status === 503,
|
|
810
|
+
getRetryLogContext: () => ({ mode: this.getMode() }),
|
|
811
|
+
onRetryExhausted: ({ attempts, elapsedMs }) => {
|
|
812
|
+
this.logger.error("Container failed to become ready", /* @__PURE__ */ new Error(`Failed after ${attempts} attempts over ${Math.floor(elapsedMs / 1e3)}s`));
|
|
778
813
|
}
|
|
779
|
-
|
|
780
|
-
}
|
|
814
|
+
});
|
|
781
815
|
}
|
|
782
816
|
/**
|
|
783
817
|
* Build a URL targeting the container's HTTP server.
|
|
@@ -817,12 +851,6 @@ var BaseTransport = class {
|
|
|
817
851
|
if (!response.body) throw new Error("No response body for streaming");
|
|
818
852
|
return response.body;
|
|
819
853
|
}
|
|
820
|
-
/**
|
|
821
|
-
* Sleep utility for retry delays
|
|
822
|
-
*/
|
|
823
|
-
sleep(ms) {
|
|
824
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
825
|
-
}
|
|
826
854
|
};
|
|
827
855
|
|
|
828
856
|
//#endregion
|
|
@@ -991,24 +1019,13 @@ var WebSocketTransport = class extends BaseTransport {
|
|
|
991
1019
|
else await this.connectViaWebSocket();
|
|
992
1020
|
}
|
|
993
1021
|
async fetchUpgradeWithRetry(attemptUpgrade) {
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
if (remaining <= MIN_TIME_FOR_CONNECT_RETRY_MS) return response;
|
|
1002
|
-
const delay = Math.min(3e3 * 2 ** attempt, 3e4);
|
|
1003
|
-
this.logger.info("WebSocket container not ready, retrying", {
|
|
1004
|
-
status: response.status,
|
|
1005
|
-
attempt: attempt + 1,
|
|
1006
|
-
delayMs: delay,
|
|
1007
|
-
remainingSec: Math.floor(remaining / 1e3)
|
|
1008
|
-
});
|
|
1009
|
-
await this.sleep(delay);
|
|
1010
|
-
attempt++;
|
|
1011
|
-
}
|
|
1022
|
+
return fetchWithResponseRetry(attemptUpgrade, {
|
|
1023
|
+
retryTimeoutMs: this.getRetryTimeoutMs(),
|
|
1024
|
+
minTimeForRetryMs: MIN_TIME_FOR_CONNECT_RETRY_MS,
|
|
1025
|
+
logger: this.logger,
|
|
1026
|
+
retryLogMessage: "WebSocket upgrade returned retryable status, retrying",
|
|
1027
|
+
shouldRetry: isRetryableWebSocketUpgradeResponse
|
|
1028
|
+
});
|
|
1012
1029
|
}
|
|
1013
1030
|
/**
|
|
1014
1031
|
* Connect using fetch-based WebSocket (Cloudflare Workers style)
|
|
@@ -2377,7 +2394,7 @@ var SandboxClient = class {
|
|
|
2377
2394
|
this.watch = new WatchClient(clientOptions);
|
|
2378
2395
|
}
|
|
2379
2396
|
/**
|
|
2380
|
-
* Update the
|
|
2397
|
+
* Update the transport retry budget without recreating the client.
|
|
2381
2398
|
*
|
|
2382
2399
|
* In WebSocket mode a single shared transport is used, so one update covers
|
|
2383
2400
|
* every sub-client. In HTTP mode each sub-client owns its own transport, so
|
|
@@ -2464,7 +2481,6 @@ const DISABLE_SESSION_TOKEN = "__DISABLE_SESSION__";
|
|
|
2464
2481
|
const DEFAULT_CONNECT_TIMEOUT_MS = 3e4;
|
|
2465
2482
|
const DEFAULT_RETRY_TIMEOUT_MS = 12e4;
|
|
2466
2483
|
const MIN_TIME_FOR_RETRY_MS = 15e3;
|
|
2467
|
-
const MAX_RETRY_BACKOFF_MS = 3e4;
|
|
2468
2484
|
/**
|
|
2469
2485
|
* Manages a capnweb WebSocket RPC session to the container.
|
|
2470
2486
|
*
|
|
@@ -2542,7 +2558,7 @@ var ContainerControlConnection = class {
|
|
|
2542
2558
|
this.connectPromise = null;
|
|
2543
2559
|
}
|
|
2544
2560
|
/**
|
|
2545
|
-
* Update the
|
|
2561
|
+
* Update the upgrade retry budget without recreating the connection. Takes
|
|
2546
2562
|
* effect on the next `connect()`; an in-flight connect uses the value
|
|
2547
2563
|
* captured at start. Mirrors `WebSocketTransport.setRetryTimeoutMs`.
|
|
2548
2564
|
*/
|
|
@@ -2606,30 +2622,18 @@ var ContainerControlConnection = class {
|
|
|
2606
2622
|
}
|
|
2607
2623
|
}
|
|
2608
2624
|
/**
|
|
2609
|
-
* Issue WebSocket upgrade fetches, retrying transient
|
|
2610
|
-
*
|
|
2611
|
-
*
|
|
2612
|
-
* runs out. Mirrors `WebSocketTransport.fetchUpgradeWithRetry` so both
|
|
2613
|
-
* transports behave the same way during container startup.
|
|
2625
|
+
* Issue WebSocket upgrade fetches, retrying transient control-plane
|
|
2626
|
+
* unavailability responses until either the upgrade succeeds, a
|
|
2627
|
+
* non-retryable status is returned, or the retry budget runs out.
|
|
2614
2628
|
*/
|
|
2615
2629
|
async fetchUpgradeWithRetry() {
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
if (remaining <= MIN_TIME_FOR_RETRY_MS) return response;
|
|
2624
|
-
const delay = Math.min(3e3 * 2 ** attempt, MAX_RETRY_BACKOFF_MS);
|
|
2625
|
-
this.logger.info("ContainerControlConnection upgrade returned 503, retrying", {
|
|
2626
|
-
attempt: attempt + 1,
|
|
2627
|
-
delayMs: delay,
|
|
2628
|
-
remainingSec: Math.floor(remaining / 1e3)
|
|
2629
|
-
});
|
|
2630
|
-
await this.sleep(delay);
|
|
2631
|
-
attempt++;
|
|
2632
|
-
}
|
|
2630
|
+
return fetchWithResponseRetry(() => this.fetchUpgradeAttempt(), {
|
|
2631
|
+
retryTimeoutMs: this.retryTimeoutMs,
|
|
2632
|
+
minTimeForRetryMs: MIN_TIME_FOR_RETRY_MS,
|
|
2633
|
+
logger: this.logger,
|
|
2634
|
+
retryLogMessage: "ContainerControlConnection upgrade returned retryable status, retrying",
|
|
2635
|
+
shouldRetry: isRetryableWebSocketUpgradeResponse
|
|
2636
|
+
});
|
|
2633
2637
|
}
|
|
2634
2638
|
/**
|
|
2635
2639
|
* Single WebSocket-upgrade fetch attempt. Owns its own AbortController so
|
|
@@ -2653,9 +2657,6 @@ var ContainerControlConnection = class {
|
|
|
2653
2657
|
clearTimeout(timeout);
|
|
2654
2658
|
}
|
|
2655
2659
|
}
|
|
2656
|
-
sleep(ms) {
|
|
2657
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2658
|
-
}
|
|
2659
2660
|
};
|
|
2660
2661
|
/**
|
|
2661
2662
|
* RPC transport that queues sends and blocks receives until a WebSocket
|
|
@@ -3032,7 +3033,7 @@ var ContainerControlClient = class {
|
|
|
3032
3033
|
return wrapStub(this.getConnection().rpc().interpreter, this.renewActivity);
|
|
3033
3034
|
}
|
|
3034
3035
|
/**
|
|
3035
|
-
* Update the
|
|
3036
|
+
* Update the upgrade retry budget. Applies to the current connection
|
|
3036
3037
|
* (if any) and is remembered for any future connections created after the
|
|
3037
3038
|
* client is torn down and reconnected.
|
|
3038
3039
|
*/
|
|
@@ -5833,7 +5834,7 @@ async function pruneTunnelsForRestart(storage) {
|
|
|
5833
5834
|
* This file is auto-updated by .github/changeset-version.ts during releases
|
|
5834
5835
|
* DO NOT EDIT MANUALLY - Changes will be overwritten on the next version bump
|
|
5835
5836
|
*/
|
|
5836
|
-
const SDK_VERSION = "0.12.
|
|
5837
|
+
const SDK_VERSION = "0.12.1";
|
|
5837
5838
|
|
|
5838
5839
|
//#endregion
|
|
5839
5840
|
//#region src/sandbox.ts
|
|
@@ -9984,4 +9985,4 @@ var Sandbox = class Sandbox extends Container {
|
|
|
9984
9985
|
|
|
9985
9986
|
//#endregion
|
|
9986
9987
|
export { FileClient as A, RPCTransportError as B, collectFile as C, ProcessClient as D, UtilityClient as E, BackupNotFoundError as F, BackupRestoreError as I, InvalidBackupConfigError as L, BackupClient as M, BackupCreateError as N, PortClient as O, BackupExpiredError as P, ProcessExitedBeforeReadyError as R, validateTunnelName as S, SandboxClient as T, SessionTerminatedError as V, responseToAsyncIterable as _, PREVIEW_PROXY_HEADER as a, sanitizeSandboxId as b, PREVIEW_PROXY_SANDBOX_ID_HEADER as c, BucketUnmountError as d, InvalidMountConfigError as f, parseSSEStream as g, asyncIterableToSSEStream as h, proxyTerminal as i, CommandClient as j, GitClient as k, PREVIEW_PROXY_TOKEN_HEADER as l, S3FSMountError as m, Sandbox as n, PREVIEW_PROXY_HEADERS as o, MissingCredentialsError as p, getSandbox as r, PREVIEW_PROXY_PORT_HEADER as s, ContainerProxy$1 as t, BucketMountError as u, CodeInterpreter as v, streamFile as w, validatePort as x, SandboxSecurityError as y, ProcessReadyTimeoutError as z };
|
|
9987
|
-
//# sourceMappingURL=sandbox-
|
|
9988
|
+
//# sourceMappingURL=sandbox-DKG3H156.js.map
|