@cloudflare/sandbox 0.7.12 → 0.7.13
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 +123 -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-B2OybvGn.d.ts} +14 -1
- package/dist/{sandbox-Buy5jfCP.d.ts.map → sandbox-B2OybvGn.d.ts.map} +1 -1
- package/package.json +1 -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-B2OybvGn.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();
|
|
@@ -3328,7 +3348,7 @@ function buildS3fsSource(bucket, prefix) {
|
|
|
3328
3348
|
* This file is auto-updated by .github/changeset-version.ts during releases
|
|
3329
3349
|
* DO NOT EDIT MANUALLY - Changes will be overwritten on the next version bump
|
|
3330
3350
|
*/
|
|
3331
|
-
const SDK_VERSION = "0.7.
|
|
3351
|
+
const SDK_VERSION = "0.7.13";
|
|
3332
3352
|
|
|
3333
3353
|
//#endregion
|
|
3334
3354
|
//#region src/sandbox.ts
|
|
@@ -3848,22 +3868,84 @@ var Sandbox = class Sandbox extends Container {
|
|
|
3848
3868
|
}
|
|
3849
3869
|
});
|
|
3850
3870
|
} catch (e) {
|
|
3851
|
-
if (this.isNoInstanceError(e))
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3871
|
+
if (this.isNoInstanceError(e)) {
|
|
3872
|
+
const errorBody$1 = {
|
|
3873
|
+
code: ErrorCode.INTERNAL_ERROR,
|
|
3874
|
+
message: "Container is currently provisioning. This can take several minutes on first deployment.",
|
|
3875
|
+
context: { phase: "provisioning" },
|
|
3876
|
+
httpStatus: 503,
|
|
3877
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3878
|
+
suggestion: "This is expected during first deployment. The SDK will retry automatically."
|
|
3879
|
+
};
|
|
3880
|
+
return new Response(JSON.stringify(errorBody$1), {
|
|
3881
|
+
status: 503,
|
|
3882
|
+
headers: {
|
|
3883
|
+
"Content-Type": "application/json",
|
|
3884
|
+
"Retry-After": "10"
|
|
3885
|
+
}
|
|
3886
|
+
});
|
|
3887
|
+
}
|
|
3888
|
+
if (this.isPermanentStartupError(e)) {
|
|
3889
|
+
this.logger.error("Permanent container startup error, returning 500", e instanceof Error ? e : new Error(String(e)));
|
|
3890
|
+
const errorBody$1 = {
|
|
3891
|
+
code: ErrorCode.INTERNAL_ERROR,
|
|
3892
|
+
message: "Container failed to start due to a permanent error. Check your container configuration.",
|
|
3893
|
+
context: {
|
|
3894
|
+
phase: "startup",
|
|
3895
|
+
error: e instanceof Error ? e.message : String(e)
|
|
3896
|
+
},
|
|
3897
|
+
httpStatus: 500,
|
|
3898
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3899
|
+
suggestion: "This error will not resolve with retries. Check container logs, image name, and resource limits."
|
|
3900
|
+
};
|
|
3901
|
+
return new Response(JSON.stringify(errorBody$1), {
|
|
3902
|
+
status: 500,
|
|
3903
|
+
headers: { "Content-Type": "application/json" }
|
|
3904
|
+
});
|
|
3905
|
+
}
|
|
3855
3906
|
if (this.isTransientStartupError(e)) {
|
|
3856
3907
|
if (staleStateDetected) {
|
|
3857
3908
|
this.logger.warn("Container startup failed after stale state detection, aborting DO for recovery", { error: e instanceof Error ? e.message : String(e) });
|
|
3858
3909
|
this.ctx.abort();
|
|
3859
3910
|
} else this.logger.debug("Transient container startup error, returning 503", { error: e instanceof Error ? e.message : String(e) });
|
|
3860
|
-
|
|
3911
|
+
const errorBody$1 = {
|
|
3912
|
+
code: ErrorCode.INTERNAL_ERROR,
|
|
3913
|
+
message: "Container is starting. Please retry in a moment.",
|
|
3914
|
+
context: {
|
|
3915
|
+
phase: "startup",
|
|
3916
|
+
error: e instanceof Error ? e.message : String(e)
|
|
3917
|
+
},
|
|
3918
|
+
httpStatus: 503,
|
|
3919
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3920
|
+
suggestion: "The container is booting. The SDK will retry automatically."
|
|
3921
|
+
};
|
|
3922
|
+
return new Response(JSON.stringify(errorBody$1), {
|
|
3861
3923
|
status: 503,
|
|
3862
|
-
headers: {
|
|
3924
|
+
headers: {
|
|
3925
|
+
"Content-Type": "application/json",
|
|
3926
|
+
"Retry-After": "3"
|
|
3927
|
+
}
|
|
3863
3928
|
});
|
|
3864
3929
|
}
|
|
3865
|
-
this.logger.
|
|
3866
|
-
|
|
3930
|
+
this.logger.warn("Unrecognized container startup error, returning 503 for retry", { error: e instanceof Error ? e.message : String(e) });
|
|
3931
|
+
const errorBody = {
|
|
3932
|
+
code: ErrorCode.INTERNAL_ERROR,
|
|
3933
|
+
message: "Container is starting. Please retry in a moment.",
|
|
3934
|
+
context: {
|
|
3935
|
+
phase: "startup",
|
|
3936
|
+
error: e instanceof Error ? e.message : String(e)
|
|
3937
|
+
},
|
|
3938
|
+
httpStatus: 503,
|
|
3939
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3940
|
+
suggestion: "The SDK will retry automatically. If this persists, the container may need redeployment."
|
|
3941
|
+
};
|
|
3942
|
+
return new Response(JSON.stringify(errorBody), {
|
|
3943
|
+
status: 503,
|
|
3944
|
+
headers: {
|
|
3945
|
+
"Content-Type": "application/json",
|
|
3946
|
+
"Retry-After": "5"
|
|
3947
|
+
}
|
|
3948
|
+
});
|
|
3867
3949
|
}
|
|
3868
3950
|
}
|
|
3869
3951
|
return await super.containerFetch(requestOrUrl, portOrInit, portParam);
|
|
@@ -3909,6 +3991,30 @@ var Sandbox = class Sandbox extends Container {
|
|
|
3909
3991
|
].some((pattern) => msg.includes(pattern));
|
|
3910
3992
|
}
|
|
3911
3993
|
/**
|
|
3994
|
+
* Helper: Check if error is a permanent startup failure that will never recover
|
|
3995
|
+
*
|
|
3996
|
+
* These errors indicate resource exhaustion, misconfiguration, or missing images.
|
|
3997
|
+
* Retrying will never succeed, so the SDK should fail fast with HTTP 500.
|
|
3998
|
+
*
|
|
3999
|
+
* Error sources (traced from platform internals):
|
|
4000
|
+
* - Container runtime: OOM, PID limit
|
|
4001
|
+
* - Scheduling/provisioning: no matching app, no namespace configured
|
|
4002
|
+
* - workerd container-client.c++: no such image
|
|
4003
|
+
* - @cloudflare/containers: did not call start
|
|
4004
|
+
*/
|
|
4005
|
+
isPermanentStartupError(error) {
|
|
4006
|
+
if (!(error instanceof Error)) return false;
|
|
4007
|
+
const msg = error.message.toLowerCase();
|
|
4008
|
+
return [
|
|
4009
|
+
"ran out of memory",
|
|
4010
|
+
"too many subprocesses",
|
|
4011
|
+
"no application that matches",
|
|
4012
|
+
"no container application assigned",
|
|
4013
|
+
"no such image",
|
|
4014
|
+
"did not call start"
|
|
4015
|
+
].some((pattern) => msg.includes(pattern));
|
|
4016
|
+
}
|
|
4017
|
+
/**
|
|
3912
4018
|
* Helper: Parse containerFetch arguments (supports multiple signatures)
|
|
3913
4019
|
*/
|
|
3914
4020
|
parseContainerFetchArgs(requestOrUrl, portOrInit, portParam) {
|
|
@@ -4168,9 +4274,6 @@ var Sandbox = class Sandbox extends Container {
|
|
|
4168
4274
|
}
|
|
4169
4275
|
try {
|
|
4170
4276
|
const streamProcessor = async () => {
|
|
4171
|
-
const DEBOUNCE_MS = 50;
|
|
4172
|
-
let lastCheckTime = 0;
|
|
4173
|
-
let pendingCheck = false;
|
|
4174
4277
|
const checkPattern = () => {
|
|
4175
4278
|
const stdoutResult = this.matchPattern(collectedStdout, pattern);
|
|
4176
4279
|
if (stdoutResult) return stdoutResult;
|
|
@@ -4183,27 +4286,17 @@ var Sandbox = class Sandbox extends Container {
|
|
|
4183
4286
|
const data = event.data || "";
|
|
4184
4287
|
if (event.type === "stdout") collectedStdout += data;
|
|
4185
4288
|
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
|
-
}
|
|
4289
|
+
const result = checkPattern();
|
|
4290
|
+
if (result) return result;
|
|
4194
4291
|
}
|
|
4195
4292
|
if (event.type === "exit") {
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
if (result) return result;
|
|
4199
|
-
}
|
|
4293
|
+
const result = checkPattern();
|
|
4294
|
+
if (result) return result;
|
|
4200
4295
|
throw this.createExitedBeforeReadyError(processId, command, conditionStr, event.exitCode ?? 1);
|
|
4201
4296
|
}
|
|
4202
4297
|
}
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
if (result) return result;
|
|
4206
|
-
}
|
|
4298
|
+
const finalResult = checkPattern();
|
|
4299
|
+
if (finalResult) return finalResult;
|
|
4207
4300
|
throw this.createExitedBeforeReadyError(processId, command, conditionStr, 0);
|
|
4208
4301
|
};
|
|
4209
4302
|
if (timeoutPromise) return await Promise.race([streamProcessor(), timeoutPromise]);
|