@cloudflare/sandbox 0.13.0-next.788.1 → 0.13.0-next.802.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/dist/bridge/index.js +4 -4
- package/dist/{contexts-1EsLHByO.d.ts → contexts-DNFVmC9N.d.ts} +4 -1
- package/dist/contexts-DNFVmC9N.d.ts.map +1 -0
- package/dist/errors/index.d.ts +2 -2
- package/dist/errors/index.js +2 -2
- package/dist/{errors-QYlSkVGz.js → errors--yR3zLC_.js} +2 -2
- package/dist/{errors-QYlSkVGz.js.map → errors--yR3zLC_.js.map} +1 -1
- package/dist/{errors-CXR0xBpw.js → errors-Bb3s6nBS.js} +7 -1
- package/dist/errors-Bb3s6nBS.js.map +1 -0
- package/dist/extensions/index.js +3 -3
- package/dist/{extensions-Be5HnDGt.js → extensions-BKL2zqL4.js} +3 -3
- package/dist/{extensions-Be5HnDGt.js.map → extensions-BKL2zqL4.js.map} +1 -1
- package/dist/git/index.js +3 -3
- package/dist/{index-HNYBk-az.d.ts → index-CfpTXmNv.d.ts} +2 -2
- package/dist/{index-HNYBk-az.d.ts.map → index-CfpTXmNv.d.ts.map} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/interpreter/index.js +3 -3
- package/dist/openai/index.js +1 -1
- package/dist/opencode/index.d.ts +1 -1
- package/dist/opencode/index.js +3 -3
- package/dist/{sandbox-pJ4JSnDx.js → sandbox-CaesWCLh.js} +115 -24
- package/dist/sandbox-CaesWCLh.js.map +1 -0
- package/package.json +1 -1
- package/dist/contexts-1EsLHByO.d.ts.map +0 -1
- package/dist/errors-CXR0xBpw.js.map +0 -1
- package/dist/sandbox-pJ4JSnDx.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { i as ErrorCode, n as getSuggestion, r as getHttpStatus } from "./errors-
|
|
2
|
-
import { $ as TerminalControlError, G as BackupRestoreError, H as BackupCreateError, Q as StaleTerminalHandleError, U as BackupExpiredError, W as BackupNotFoundError, X as OperationInterruptedError, Z as RPCTransportError, _ as StaleProcessHandleError, n as RuntimeIdentityInactiveError, p as ProcessNotFoundError, q as InvalidBackupConfigError, r as RuntimeControlProtocolError, t as createErrorFromResponse, tt as SandboxError, v as CustomDomainRequiredError } from "./errors
|
|
1
|
+
import { i as ErrorCode, n as getSuggestion, r as getHttpStatus } from "./errors-Bb3s6nBS.js";
|
|
2
|
+
import { $ as TerminalControlError, G as BackupRestoreError, H as BackupCreateError, Q as StaleTerminalHandleError, U as BackupExpiredError, W as BackupNotFoundError, X as OperationInterruptedError, Z as RPCTransportError, _ as StaleProcessHandleError, n as RuntimeIdentityInactiveError, p as ProcessNotFoundError, q as InvalidBackupConfigError, r as RuntimeControlProtocolError, t as createErrorFromResponse, tt as SandboxError, v as CustomDomainRequiredError } from "./errors--yR3zLC_.js";
|
|
3
3
|
import { a as TraceContext, d as partitionEnvVars, i as createNoOpLogger, o as logCanonicalEvent, r as createLogger, t as parseSSEFrames, u as getEnvString } from "./dist-n_eniPAR.js";
|
|
4
|
-
import { a as PullSubscriptionTarget, i as createSandboxProcess, o as openRemoteSubscription, r as sandboxRuntimeCall, s as translateRPCError, t as SandboxExtension } from "./extensions-
|
|
4
|
+
import { a as PullSubscriptionTarget, i as createSandboxProcess, o as openRemoteSubscription, r as sandboxRuntimeCall, s as translateRPCError, t as SandboxExtension } from "./extensions-BKL2zqL4.js";
|
|
5
5
|
import { Container, ContainerProxy, getContainer, switchPort } from "@cloudflare/containers";
|
|
6
6
|
import { RpcTarget } from "cloudflare:workers";
|
|
7
7
|
import { AwsClient } from "aws4fetch";
|
|
@@ -161,6 +161,19 @@ function isDurableObjectCodeUpdateReset(error) {
|
|
|
161
161
|
return false;
|
|
162
162
|
}
|
|
163
163
|
/**
|
|
164
|
+
* Whether an error was raised because the Durable Object itself was reset, by
|
|
165
|
+
* a code update or a storage startup failure, rather than by the operation
|
|
166
|
+
* that observed it.
|
|
167
|
+
*/
|
|
168
|
+
function isDurableObjectReset(error) {
|
|
169
|
+
for (const candidate of selfAndCauses(error)) {
|
|
170
|
+
const message = errorMessageOf(candidate);
|
|
171
|
+
if (SUPERSEDED_ISOLATE_PATTERN.test(message)) return true;
|
|
172
|
+
if (DO_STORAGE_STARTUP_RESET_PATTERN.test(message)) return true;
|
|
173
|
+
}
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
164
177
|
* Whether an error represents a transient platform lifecycle/storage failure,
|
|
165
178
|
* not an application-level sandbox failure.
|
|
166
179
|
*/
|
|
@@ -2516,11 +2529,6 @@ async function mountR2EgressBucket(context, bucket, mountPath, options) {
|
|
|
2516
2529
|
const lifecycle = await context.lifecycle.capture(context.runtime);
|
|
2517
2530
|
passwordFilePath = generatePasswordFilePath();
|
|
2518
2531
|
additionalHeaderFilePath = generateS3FSAdditionalHeaderFilePath();
|
|
2519
|
-
await createPasswordFile(context.s3fsHost, passwordFilePath, bucket, {
|
|
2520
|
-
accessKeyId: "x",
|
|
2521
|
-
secretAccessKey: "x"
|
|
2522
|
-
});
|
|
2523
|
-
await createDisableExpectHeaderFile(context.s3fsHost, additionalHeaderFilePath);
|
|
2524
2532
|
mountInfo = {
|
|
2525
2533
|
mountId: crypto.randomUUID(),
|
|
2526
2534
|
mountType: "r2-egress",
|
|
@@ -2532,14 +2540,21 @@ async function mountR2EgressBucket(context, bucket, mountPath, options) {
|
|
|
2532
2540
|
prefix,
|
|
2533
2541
|
readOnly: options.readOnly ?? false
|
|
2534
2542
|
};
|
|
2535
|
-
await
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
+
await allOrFirstError([
|
|
2544
|
+
createPasswordFile(context.s3fsHost, passwordFilePath, bucket, {
|
|
2545
|
+
accessKeyId: "x",
|
|
2546
|
+
secretAccessKey: "x"
|
|
2547
|
+
}),
|
|
2548
|
+
createDisableExpectHeaderFile(context.s3fsHost, additionalHeaderFilePath),
|
|
2549
|
+
configureR2EgressOutbound(context.getOutboundHost(), { buckets: {
|
|
2550
|
+
...buildR2EgressParams(context.registry).buckets,
|
|
2551
|
+
[bucket]: {
|
|
2552
|
+
prefix,
|
|
2553
|
+
readOnly: options.readOnly ?? false
|
|
2554
|
+
}
|
|
2555
|
+
} }),
|
|
2556
|
+
context.runRuntimeCall("mount.ensureDirectory", (control) => control.mounts.ensureDirectory(mountPath))
|
|
2557
|
+
]);
|
|
2543
2558
|
s3fsStarted = true;
|
|
2544
2559
|
await executeS3FSMount(context.s3fsHost, {
|
|
2545
2560
|
bucket,
|
|
@@ -2603,6 +2618,14 @@ async function mountR2EgressBucket(context, bucket, mountPath, options) {
|
|
|
2603
2618
|
});
|
|
2604
2619
|
}
|
|
2605
2620
|
}
|
|
2621
|
+
/**
|
|
2622
|
+
* Like `Promise.all`, but waits for every step to settle before rejecting, so
|
|
2623
|
+
* cleanup never runs while a support-file write or route update is in flight.
|
|
2624
|
+
*/
|
|
2625
|
+
async function allOrFirstError(steps) {
|
|
2626
|
+
const failure = (await Promise.allSettled(steps)).find((result) => result.status === "rejected");
|
|
2627
|
+
if (failure) throw failure.reason;
|
|
2628
|
+
}
|
|
2606
2629
|
|
|
2607
2630
|
//#endregion
|
|
2608
2631
|
//#region src/storage-mount/validation/credentials.ts
|
|
@@ -4601,8 +4624,13 @@ async function forwardPreviewRequest(tcpPort, request, lease) {
|
|
|
4601
4624
|
};
|
|
4602
4625
|
} catch (error) {
|
|
4603
4626
|
release();
|
|
4627
|
+
if (interruptedError) throw interruptedError;
|
|
4628
|
+
if (isDurableObjectReset(error)) throw error;
|
|
4604
4629
|
if (error instanceof Error && error.message.includes("Network connection lost.")) return { status: "network-lost" };
|
|
4605
|
-
|
|
4630
|
+
return {
|
|
4631
|
+
status: "failed",
|
|
4632
|
+
error
|
|
4633
|
+
};
|
|
4606
4634
|
}
|
|
4607
4635
|
}
|
|
4608
4636
|
function retainPreviewBody(body, release, bindInterrupt) {
|
|
@@ -4754,10 +4782,6 @@ function buildPreviewProxyRequest(request, { port, sandboxId, sandboxName }) {
|
|
|
4754
4782
|
headers.set("X-Forwarded-Host", url.hostname);
|
|
4755
4783
|
headers.set("X-Forwarded-Proto", url.protocol.replace(":", ""));
|
|
4756
4784
|
headers.set("X-Sandbox-Name", sandboxName ?? sandboxId);
|
|
4757
|
-
if (request.headers.get("Upgrade")?.toLowerCase() === "websocket") return new Request(request, {
|
|
4758
|
-
headers,
|
|
4759
|
-
redirect: "manual"
|
|
4760
|
-
});
|
|
4761
4785
|
return new Request(proxyURL, {
|
|
4762
4786
|
method: request.method,
|
|
4763
4787
|
headers,
|
|
@@ -5091,6 +5115,13 @@ var PreviewService = class {
|
|
|
5091
5115
|
if (!container?.running) return this.stalePreviewURLResponse();
|
|
5092
5116
|
const result = await forwardPreviewRequest(container.getTcpPort(port), request, lease);
|
|
5093
5117
|
if (result.status === "network-lost") return this.stalePreviewURLResponse();
|
|
5118
|
+
if (result.status === "failed") {
|
|
5119
|
+
this.deps.logger.error("Preview request to container port failed", result.error instanceof Error ? result.error : new Error(String(result.error)), {
|
|
5120
|
+
port,
|
|
5121
|
+
method: request.method
|
|
5122
|
+
});
|
|
5123
|
+
return new Response(`Could not reach port ${port} in the container`, { status: 502 });
|
|
5124
|
+
}
|
|
5094
5125
|
return result.response;
|
|
5095
5126
|
}
|
|
5096
5127
|
async validatePreviewURLForRuntime(port, token) {
|
|
@@ -7589,6 +7620,22 @@ function randomId(size = 20) {
|
|
|
7589
7620
|
function createQuickTunnelId() {
|
|
7590
7621
|
return `quick-${randomId()}`;
|
|
7591
7622
|
}
|
|
7623
|
+
/**
|
|
7624
|
+
* The run holding `request.port` when the container rejected `request`
|
|
7625
|
+
* with a port conflict, or `null` when the conflict does not name both
|
|
7626
|
+
* the active run and its tunnel, which `stopTunnelRun` needs.
|
|
7627
|
+
*/
|
|
7628
|
+
function conflictingRunOnPort(error, request) {
|
|
7629
|
+
const e = error;
|
|
7630
|
+
if (e?.code !== "TUNNEL_RUN_CONFLICT") return null;
|
|
7631
|
+
const runId = e.context?.activeRunId;
|
|
7632
|
+
const tunnelId = e.context?.activeTunnelId;
|
|
7633
|
+
if (e.context?.port !== request.port || typeof runId !== "string" || typeof tunnelId !== "string" || runId === request.runId) return null;
|
|
7634
|
+
return {
|
|
7635
|
+
tunnelId,
|
|
7636
|
+
runId
|
|
7637
|
+
};
|
|
7638
|
+
}
|
|
7592
7639
|
var TunnelProvisioner = class {
|
|
7593
7640
|
#host;
|
|
7594
7641
|
#zoneNamePromise = null;
|
|
@@ -7596,7 +7643,7 @@ var TunnelProvisioner = class {
|
|
|
7596
7643
|
this.#host = host;
|
|
7597
7644
|
}
|
|
7598
7645
|
async provisionQuickTunnel(tunnels, port, tunnelRunId, tunnelId = createQuickTunnelId()) {
|
|
7599
|
-
const result = await this.#
|
|
7646
|
+
const result = await this.#ensureQuickTunnelRun(tunnels, {
|
|
7600
7647
|
mode: "quick",
|
|
7601
7648
|
tunnelId,
|
|
7602
7649
|
runId: tunnelRunId,
|
|
@@ -7712,6 +7759,26 @@ var TunnelProvisioner = class {
|
|
|
7712
7759
|
async #ensureTunnelRun(tunnels, request) {
|
|
7713
7760
|
return await tunnels.ensureTunnelRun(request);
|
|
7714
7761
|
}
|
|
7762
|
+
/**
|
|
7763
|
+
* Start a quick tunnel run. The Durable Object owns every tunnel run in
|
|
7764
|
+
* its container and holds the port lock, so a different run already on
|
|
7765
|
+
* the port lost its storage record. Stop it and retry once instead of
|
|
7766
|
+
* failing every later `get()` for the port.
|
|
7767
|
+
*/
|
|
7768
|
+
async #ensureQuickTunnelRun(tunnels, request) {
|
|
7769
|
+
try {
|
|
7770
|
+
return await this.#ensureTunnelRun(tunnels, request);
|
|
7771
|
+
} catch (error) {
|
|
7772
|
+
const orphan = conflictingRunOnPort(error, request);
|
|
7773
|
+
if (!orphan) throw error;
|
|
7774
|
+
this.#host.logger?.warn("tunnel.get: stopping orphaned run on port", {
|
|
7775
|
+
port: request.port,
|
|
7776
|
+
...orphan
|
|
7777
|
+
});
|
|
7778
|
+
await tunnels.stopTunnelRun(orphan);
|
|
7779
|
+
return await this.#ensureTunnelRun(tunnels, request);
|
|
7780
|
+
}
|
|
7781
|
+
}
|
|
7715
7782
|
async #getZoneName(config) {
|
|
7716
7783
|
if (!this.#zoneNamePromise) {
|
|
7717
7784
|
const pending = getZoneName({
|
|
@@ -7944,13 +8011,37 @@ var TunnelService = class {
|
|
|
7944
8011
|
await this.#assertSandboxLifetime(lifetime, "committing");
|
|
7945
8012
|
return spawned;
|
|
7946
8013
|
} catch (error) {
|
|
7947
|
-
|
|
8014
|
+
try {
|
|
8015
|
+
if (committedInfo) await this.#invalidateCommittedPortIfUnchanged(port, committedInfo, lease.runtime, runId);
|
|
8016
|
+
} finally {
|
|
8017
|
+
await this.#stopAbandonedQuickRun(lease.tunnels, port, {
|
|
8018
|
+
tunnelId,
|
|
8019
|
+
runId
|
|
8020
|
+
});
|
|
8021
|
+
}
|
|
7948
8022
|
throw error;
|
|
7949
8023
|
} finally {
|
|
7950
8024
|
hold.release();
|
|
7951
8025
|
}
|
|
7952
8026
|
});
|
|
7953
8027
|
}
|
|
8028
|
+
/**
|
|
8029
|
+
* Stop a quick tunnel run that provisioning is giving up on, so its
|
|
8030
|
+
* cloudflared does not keep holding the port without a stored record.
|
|
8031
|
+
* Best effort: the run may never have started, or may have died with a
|
|
8032
|
+
* replaced runtime.
|
|
8033
|
+
*/
|
|
8034
|
+
async #stopAbandonedQuickRun(tunnels, port, run) {
|
|
8035
|
+
try {
|
|
8036
|
+
await tunnels.stopTunnelRun(run);
|
|
8037
|
+
} catch (error) {
|
|
8038
|
+
this.#host.logger.warn("tunnel.get: abandoned run cleanup failed", {
|
|
8039
|
+
port,
|
|
8040
|
+
...run,
|
|
8041
|
+
error: error instanceof Error ? error.message : String(error)
|
|
8042
|
+
});
|
|
8043
|
+
}
|
|
8044
|
+
}
|
|
7954
8045
|
async #provisionNamedTunnel(port, name) {
|
|
7955
8046
|
const lifetime = await this.#host.currentLifetime?.getOrCreate();
|
|
7956
8047
|
return await this.#host.runProvision(async (lease) => {
|
|
@@ -10111,4 +10202,4 @@ var Sandbox = class extends Container {
|
|
|
10111
10202
|
|
|
10112
10203
|
//#endregion
|
|
10113
10204
|
export { proxyTerminal as _, responseToAsyncIterable as a, collectFile as b, BucketUnmountError as c, S3FSMountError as d, parsePreviewRoute as f, validateTunnelName as g, validatePort as h, parseSSEStream as i, InvalidMountConfigError as l, SandboxSecurityError as m, getSandbox as n, ContainerProxy$1 as o, withPreviewProxyMetadata as p, asyncIterableToSSEStream as r, BucketMountError as s, Sandbox as t, MissingCredentialsError as u, isDurableObjectCodeUpdateReset as v, streamFile as x, isPlatformTransientError as y };
|
|
10114
|
-
//# sourceMappingURL=sandbox-
|
|
10205
|
+
//# sourceMappingURL=sandbox-CaesWCLh.js.map
|