@cloudflare/sandbox 0.7.12 → 0.7.14
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/Dockerfile +6 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +125 -30
- package/dist/index.js.map +1 -1
- package/dist/openai/index.d.ts +1 -1
- package/dist/opencode/index.d.ts +1 -1
- package/dist/opencode/index.d.ts.map +1 -1
- package/dist/{sandbox-Buy5jfCP.d.ts → sandbox-CUee1P3v.d.ts} +15 -1
- package/dist/sandbox-CUee1P3v.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/sandbox-Buy5jfCP.d.ts.map +0 -1
package/Dockerfile
CHANGED
|
@@ -199,6 +199,12 @@ ENTRYPOINT ["/container-server/sandbox"]
|
|
|
199
199
|
# ============================================================================
|
|
200
200
|
FROM runtime-base AS opencode
|
|
201
201
|
|
|
202
|
+
RUN --mount=type=secret,id=wrangler_ca \
|
|
203
|
+
if [ -f /run/secrets/wrangler_ca ] && [ -s /run/secrets/wrangler_ca ]; then \
|
|
204
|
+
cp /run/secrets/wrangler_ca /usr/local/share/ca-certificates/wrangler-dev-ca.crt && \
|
|
205
|
+
update-ca-certificates; \
|
|
206
|
+
fi
|
|
207
|
+
|
|
202
208
|
# Install OpenCode CLI via npm (avoids GitHub API rate limits)
|
|
203
209
|
RUN npm i -g opencode-ai \
|
|
204
210
|
&& opencode --version
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as DirectoryBackup, A as DesktopStopResponse, At as WaitForPortOptions, B as ExecuteResponse, Bt as CreateContextOptions, C as ClickOptions, Ct as ProcessStartResult, D as DesktopStartOptions, Dt as SessionOptions, E as DesktopClient, Et as SandboxOptions, F as ScreenshotRegion, Ft as ExecuteRequest, G as HttpClientOptions, H as BaseApiResponse, Ht as ExecutionResult, I as ScreenshotResponse, It as ExposePortRequest, J as SessionRequest, K as RequestConfig, L as ScrollDirection, Lt as StartProcessRequest, M as ScreenSizeResponse, Mt as isExecResult, N as ScreenshotBytesResponse, Nt as isProcess, O as DesktopStartResponse, Ot as StreamOptions, P as ScreenshotOptions, Pt as isProcessStatus, Q as BucketProvider, R as TypeOptions, Rt as PtyOptions, S as WriteFileRequest, St as ProcessOptions, T as Desktop, Tt as RestoreBackupResult, U as ContainerStub, Ut as RunCodeOptions, V as BackupClient, Vt as Execution, W as ErrorResponse, X as BaseExecOptions, Y as BackupOptions, Z as BucketCredentials, _ as GitClient, _t as ProcessCleanupResult, a as CreateSessionRequest, at as FileMetadata, b as MkdirRequest, bt as ProcessListResult, c as DeleteSessionResponse, ct as GitCheckoutResult, d as ProcessClient, dt as LogEvent, et as ExecEvent, f as PortClient, ft as MountBucketOptions, g as GitCheckoutRequest, gt as Process, h as InterpreterClient, ht as PortListResult, i as CommandsResponse, it as FileChunk, j as KeyInput, jt as WatchOptions, k as DesktopStatusResponse, kt as WaitForLogResult, l as PingResponse, lt as ISandbox, m as ExecutionCallbacks, mt as PortExposeResult, n as getSandbox, nt as ExecResult, o as CreateSessionResponse, ot as FileStreamEvent, p as UnexposePortRequest, pt as PortCloseResult, q as ResponseHandler, r as SandboxClient, rt as ExecutionSession, s as DeleteSessionRequest, st as FileWatchSSEEvent, t as Sandbox, tt as ExecOptions, u as UtilityClient, ut as ListFilesOptions, v as FileClient, vt as ProcessInfoResult, w as CursorPositionResponse, wt as ProcessStatus, x as ReadFileRequest, xt as ProcessLogsResult, y as FileOperationRequest, yt as ProcessKillResult, z as CommandClient, zt as CodeContext } from "./sandbox-
|
|
1
|
+
import { $ as DirectoryBackup, A as DesktopStopResponse, At as WaitForPortOptions, B as ExecuteResponse, Bt as CreateContextOptions, C as ClickOptions, Ct as ProcessStartResult, D as DesktopStartOptions, Dt as SessionOptions, E as DesktopClient, Et as SandboxOptions, F as ScreenshotRegion, Ft as ExecuteRequest, G as HttpClientOptions, H as BaseApiResponse, Ht as ExecutionResult, I as ScreenshotResponse, It as ExposePortRequest, J as SessionRequest, K as RequestConfig, L as ScrollDirection, Lt as StartProcessRequest, M as ScreenSizeResponse, Mt as isExecResult, N as ScreenshotBytesResponse, Nt as isProcess, O as DesktopStartResponse, Ot as StreamOptions, P as ScreenshotOptions, Pt as isProcessStatus, Q as BucketProvider, R as TypeOptions, Rt as PtyOptions, S as WriteFileRequest, St as ProcessOptions, T as Desktop, Tt as RestoreBackupResult, U as ContainerStub, Ut as RunCodeOptions, V as BackupClient, Vt as Execution, W as ErrorResponse, X as BaseExecOptions, Y as BackupOptions, Z as BucketCredentials, _ as GitClient, _t as ProcessCleanupResult, a as CreateSessionRequest, at as FileMetadata, b as MkdirRequest, bt as ProcessListResult, c as DeleteSessionResponse, ct as GitCheckoutResult, d as ProcessClient, dt as LogEvent, et as ExecEvent, f as PortClient, ft as MountBucketOptions, g as GitCheckoutRequest, gt as Process, h as InterpreterClient, ht as PortListResult, i as CommandsResponse, it as FileChunk, j as KeyInput, jt as WatchOptions, k as DesktopStatusResponse, kt as WaitForLogResult, l as PingResponse, lt as ISandbox, m as ExecutionCallbacks, mt as PortExposeResult, n as getSandbox, nt as ExecResult, o as CreateSessionResponse, ot as FileStreamEvent, p as UnexposePortRequest, pt as PortCloseResult, q as ResponseHandler, r as SandboxClient, rt as ExecutionSession, s as DeleteSessionRequest, st as FileWatchSSEEvent, t as Sandbox, tt as ExecOptions, u as UtilityClient, ut as ListFilesOptions, v as FileClient, vt as ProcessInfoResult, w as CursorPositionResponse, wt as ProcessStatus, x as ReadFileRequest, xt as ProcessLogsResult, y as FileOperationRequest, yt as ProcessKillResult, z as CommandClient, zt as CodeContext } from "./sandbox-CUee1P3v.js";
|
|
2
2
|
import { a as DesktopCoordinateErrorContext, d as ErrorResponse$1, f as OperationType, i as BackupRestoreContext, l as ProcessExitedBeforeReadyContext, n as BackupExpiredContext, o as DesktopErrorContext, p as ErrorCode, r as BackupNotFoundContext, s as InvalidBackupConfigContext, t as BackupCreateContext, u as ProcessReadyTimeoutContext } from "./contexts-CeQR115r.js";
|
|
3
3
|
|
|
4
4
|
//#region src/errors/classes.d.ts
|
package/dist/index.js
CHANGED
|
@@ -1123,7 +1123,22 @@ var WebSocketTransport = class extends BaseTransport {
|
|
|
1123
1123
|
if (!firstMessageReceived) {
|
|
1124
1124
|
firstMessageReceived = true;
|
|
1125
1125
|
const pending = this.pendingRequests.get(id);
|
|
1126
|
-
if (pending)
|
|
1126
|
+
if (pending) {
|
|
1127
|
+
pending.streamController = streamController;
|
|
1128
|
+
if (pending.bufferedChunks) {
|
|
1129
|
+
try {
|
|
1130
|
+
for (const buffered of pending.bufferedChunks) streamController.enqueue(buffered);
|
|
1131
|
+
} catch (error) {
|
|
1132
|
+
this.logger.debug("Failed to flush buffered chunks, cleaning up", {
|
|
1133
|
+
id,
|
|
1134
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1135
|
+
});
|
|
1136
|
+
if (pending.timeoutId) clearTimeout(pending.timeoutId);
|
|
1137
|
+
this.pendingRequests.delete(id);
|
|
1138
|
+
}
|
|
1139
|
+
pending.bufferedChunks = void 0;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1127
1142
|
resolveStream(stream);
|
|
1128
1143
|
}
|
|
1129
1144
|
}
|
|
@@ -1194,7 +1209,12 @@ var WebSocketTransport = class extends BaseTransport {
|
|
|
1194
1209
|
pending.onFirstChunk = void 0;
|
|
1195
1210
|
}
|
|
1196
1211
|
if (!pending.streamController) {
|
|
1197
|
-
|
|
1212
|
+
if (!pending.bufferedChunks) pending.bufferedChunks = [];
|
|
1213
|
+
const encoder$1 = new TextEncoder();
|
|
1214
|
+
let sseData$1;
|
|
1215
|
+
if (chunk.event) sseData$1 = `event: ${chunk.event}\ndata: ${chunk.data}\n\n`;
|
|
1216
|
+
else sseData$1 = `data: ${chunk.data}\n\n`;
|
|
1217
|
+
pending.bufferedChunks.push(encoder$1.encode(sseData$1));
|
|
1198
1218
|
return;
|
|
1199
1219
|
}
|
|
1200
1220
|
const encoder = new TextEncoder();
|
|
@@ -2975,6 +2995,7 @@ async function proxyTerminal(stub, sessionId, request, options) {
|
|
|
2975
2995
|
const params = new URLSearchParams({ sessionId });
|
|
2976
2996
|
if (options?.cols) params.set("cols", String(options.cols));
|
|
2977
2997
|
if (options?.rows) params.set("rows", String(options.rows));
|
|
2998
|
+
if (options?.shell) params.set("shell", options.shell);
|
|
2978
2999
|
const ptyUrl = `http://localhost/ws/pty?${params}`;
|
|
2979
3000
|
const ptyRequest = new Request(ptyUrl, request);
|
|
2980
3001
|
return stub.fetch(switchPort(ptyRequest, 3e3));
|
|
@@ -3328,7 +3349,7 @@ function buildS3fsSource(bucket, prefix) {
|
|
|
3328
3349
|
* This file is auto-updated by .github/changeset-version.ts during releases
|
|
3329
3350
|
* DO NOT EDIT MANUALLY - Changes will be overwritten on the next version bump
|
|
3330
3351
|
*/
|
|
3331
|
-
const SDK_VERSION = "0.7.
|
|
3352
|
+
const SDK_VERSION = "0.7.14";
|
|
3332
3353
|
|
|
3333
3354
|
//#endregion
|
|
3334
3355
|
//#region src/sandbox.ts
|
|
@@ -3569,6 +3590,7 @@ var Sandbox = class Sandbox extends Container {
|
|
|
3569
3590
|
async setKeepAlive(keepAlive) {
|
|
3570
3591
|
this.keepAliveEnabled = keepAlive;
|
|
3571
3592
|
await this.ctx.storage.put("keepAliveEnabled", keepAlive);
|
|
3593
|
+
if (!keepAlive) this.renewActivityTimeout();
|
|
3572
3594
|
}
|
|
3573
3595
|
async setEnvVars(envVars) {
|
|
3574
3596
|
const { toSet, toUnset } = partitionEnvVars(envVars);
|
|
@@ -3848,22 +3870,84 @@ var Sandbox = class Sandbox extends Container {
|
|
|
3848
3870
|
}
|
|
3849
3871
|
});
|
|
3850
3872
|
} catch (e) {
|
|
3851
|
-
if (this.isNoInstanceError(e))
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3873
|
+
if (this.isNoInstanceError(e)) {
|
|
3874
|
+
const errorBody$1 = {
|
|
3875
|
+
code: ErrorCode.INTERNAL_ERROR,
|
|
3876
|
+
message: "Container is currently provisioning. This can take several minutes on first deployment.",
|
|
3877
|
+
context: { phase: "provisioning" },
|
|
3878
|
+
httpStatus: 503,
|
|
3879
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3880
|
+
suggestion: "This is expected during first deployment. The SDK will retry automatically."
|
|
3881
|
+
};
|
|
3882
|
+
return new Response(JSON.stringify(errorBody$1), {
|
|
3883
|
+
status: 503,
|
|
3884
|
+
headers: {
|
|
3885
|
+
"Content-Type": "application/json",
|
|
3886
|
+
"Retry-After": "10"
|
|
3887
|
+
}
|
|
3888
|
+
});
|
|
3889
|
+
}
|
|
3890
|
+
if (this.isPermanentStartupError(e)) {
|
|
3891
|
+
this.logger.error("Permanent container startup error, returning 500", e instanceof Error ? e : new Error(String(e)));
|
|
3892
|
+
const errorBody$1 = {
|
|
3893
|
+
code: ErrorCode.INTERNAL_ERROR,
|
|
3894
|
+
message: "Container failed to start due to a permanent error. Check your container configuration.",
|
|
3895
|
+
context: {
|
|
3896
|
+
phase: "startup",
|
|
3897
|
+
error: e instanceof Error ? e.message : String(e)
|
|
3898
|
+
},
|
|
3899
|
+
httpStatus: 500,
|
|
3900
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3901
|
+
suggestion: "This error will not resolve with retries. Check container logs, image name, and resource limits."
|
|
3902
|
+
};
|
|
3903
|
+
return new Response(JSON.stringify(errorBody$1), {
|
|
3904
|
+
status: 500,
|
|
3905
|
+
headers: { "Content-Type": "application/json" }
|
|
3906
|
+
});
|
|
3907
|
+
}
|
|
3855
3908
|
if (this.isTransientStartupError(e)) {
|
|
3856
3909
|
if (staleStateDetected) {
|
|
3857
3910
|
this.logger.warn("Container startup failed after stale state detection, aborting DO for recovery", { error: e instanceof Error ? e.message : String(e) });
|
|
3858
3911
|
this.ctx.abort();
|
|
3859
3912
|
} else this.logger.debug("Transient container startup error, returning 503", { error: e instanceof Error ? e.message : String(e) });
|
|
3860
|
-
|
|
3913
|
+
const errorBody$1 = {
|
|
3914
|
+
code: ErrorCode.INTERNAL_ERROR,
|
|
3915
|
+
message: "Container is starting. Please retry in a moment.",
|
|
3916
|
+
context: {
|
|
3917
|
+
phase: "startup",
|
|
3918
|
+
error: e instanceof Error ? e.message : String(e)
|
|
3919
|
+
},
|
|
3920
|
+
httpStatus: 503,
|
|
3921
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3922
|
+
suggestion: "The container is booting. The SDK will retry automatically."
|
|
3923
|
+
};
|
|
3924
|
+
return new Response(JSON.stringify(errorBody$1), {
|
|
3861
3925
|
status: 503,
|
|
3862
|
-
headers: {
|
|
3926
|
+
headers: {
|
|
3927
|
+
"Content-Type": "application/json",
|
|
3928
|
+
"Retry-After": "3"
|
|
3929
|
+
}
|
|
3863
3930
|
});
|
|
3864
3931
|
}
|
|
3865
|
-
this.logger.
|
|
3866
|
-
|
|
3932
|
+
this.logger.warn("Unrecognized container startup error, returning 503 for retry", { error: e instanceof Error ? e.message : String(e) });
|
|
3933
|
+
const errorBody = {
|
|
3934
|
+
code: ErrorCode.INTERNAL_ERROR,
|
|
3935
|
+
message: "Container is starting. Please retry in a moment.",
|
|
3936
|
+
context: {
|
|
3937
|
+
phase: "startup",
|
|
3938
|
+
error: e instanceof Error ? e.message : String(e)
|
|
3939
|
+
},
|
|
3940
|
+
httpStatus: 503,
|
|
3941
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3942
|
+
suggestion: "The SDK will retry automatically. If this persists, the container may need redeployment."
|
|
3943
|
+
};
|
|
3944
|
+
return new Response(JSON.stringify(errorBody), {
|
|
3945
|
+
status: 503,
|
|
3946
|
+
headers: {
|
|
3947
|
+
"Content-Type": "application/json",
|
|
3948
|
+
"Retry-After": "5"
|
|
3949
|
+
}
|
|
3950
|
+
});
|
|
3867
3951
|
}
|
|
3868
3952
|
}
|
|
3869
3953
|
return await super.containerFetch(requestOrUrl, portOrInit, portParam);
|
|
@@ -3909,6 +3993,30 @@ var Sandbox = class Sandbox extends Container {
|
|
|
3909
3993
|
].some((pattern) => msg.includes(pattern));
|
|
3910
3994
|
}
|
|
3911
3995
|
/**
|
|
3996
|
+
* Helper: Check if error is a permanent startup failure that will never recover
|
|
3997
|
+
*
|
|
3998
|
+
* These errors indicate resource exhaustion, misconfiguration, or missing images.
|
|
3999
|
+
* Retrying will never succeed, so the SDK should fail fast with HTTP 500.
|
|
4000
|
+
*
|
|
4001
|
+
* Error sources (traced from platform internals):
|
|
4002
|
+
* - Container runtime: OOM, PID limit
|
|
4003
|
+
* - Scheduling/provisioning: no matching app, no namespace configured
|
|
4004
|
+
* - workerd container-client.c++: no such image
|
|
4005
|
+
* - @cloudflare/containers: did not call start
|
|
4006
|
+
*/
|
|
4007
|
+
isPermanentStartupError(error) {
|
|
4008
|
+
if (!(error instanceof Error)) return false;
|
|
4009
|
+
const msg = error.message.toLowerCase();
|
|
4010
|
+
return [
|
|
4011
|
+
"ran out of memory",
|
|
4012
|
+
"too many subprocesses",
|
|
4013
|
+
"no application that matches",
|
|
4014
|
+
"no container application assigned",
|
|
4015
|
+
"no such image",
|
|
4016
|
+
"did not call start"
|
|
4017
|
+
].some((pattern) => msg.includes(pattern));
|
|
4018
|
+
}
|
|
4019
|
+
/**
|
|
3912
4020
|
* Helper: Parse containerFetch arguments (supports multiple signatures)
|
|
3913
4021
|
*/
|
|
3914
4022
|
parseContainerFetchArgs(requestOrUrl, portOrInit, portParam) {
|
|
@@ -4168,9 +4276,6 @@ var Sandbox = class Sandbox extends Container {
|
|
|
4168
4276
|
}
|
|
4169
4277
|
try {
|
|
4170
4278
|
const streamProcessor = async () => {
|
|
4171
|
-
const DEBOUNCE_MS = 50;
|
|
4172
|
-
let lastCheckTime = 0;
|
|
4173
|
-
let pendingCheck = false;
|
|
4174
4279
|
const checkPattern = () => {
|
|
4175
4280
|
const stdoutResult = this.matchPattern(collectedStdout, pattern);
|
|
4176
4281
|
if (stdoutResult) return stdoutResult;
|
|
@@ -4183,27 +4288,17 @@ var Sandbox = class Sandbox extends Container {
|
|
|
4183
4288
|
const data = event.data || "";
|
|
4184
4289
|
if (event.type === "stdout") collectedStdout += data;
|
|
4185
4290
|
else collectedStderr += data;
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
if (now - lastCheckTime >= DEBOUNCE_MS) {
|
|
4189
|
-
lastCheckTime = now;
|
|
4190
|
-
pendingCheck = false;
|
|
4191
|
-
const result = checkPattern();
|
|
4192
|
-
if (result) return result;
|
|
4193
|
-
}
|
|
4291
|
+
const result = checkPattern();
|
|
4292
|
+
if (result) return result;
|
|
4194
4293
|
}
|
|
4195
4294
|
if (event.type === "exit") {
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
if (result) return result;
|
|
4199
|
-
}
|
|
4295
|
+
const result = checkPattern();
|
|
4296
|
+
if (result) return result;
|
|
4200
4297
|
throw this.createExitedBeforeReadyError(processId, command, conditionStr, event.exitCode ?? 1);
|
|
4201
4298
|
}
|
|
4202
4299
|
}
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
if (result) return result;
|
|
4206
|
-
}
|
|
4300
|
+
const finalResult = checkPattern();
|
|
4301
|
+
if (finalResult) return finalResult;
|
|
4207
4302
|
throw this.createExitedBeforeReadyError(processId, command, conditionStr, 0);
|
|
4208
4303
|
};
|
|
4209
4304
|
if (timeoutPromise) return await Promise.race([streamProcessor(), timeoutPromise]);
|