@cloudflare/sandbox 0.7.0 → 0.7.2
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 +32 -7
- package/dist/{contexts-CdrlvHWK.d.ts → contexts-uY_burk0.d.ts} +1 -1
- package/dist/{contexts-CdrlvHWK.d.ts.map → contexts-uY_burk0.d.ts.map} +1 -1
- package/dist/{dist-BpbdH8ry.js → dist-D9B_6gn_.js} +1 -1
- package/dist/{dist-BpbdH8ry.js.map → dist-D9B_6gn_.js.map} +1 -1
- package/dist/{errors-BCXUmJUn.js → errors-Bzl0ZNia.js} +1 -1
- package/dist/{errors-BCXUmJUn.js.map → errors-Bzl0ZNia.js.map} +1 -1
- package/dist/index.d.ts +8 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +64 -24
- package/dist/index.js.map +1 -1
- package/dist/openai/index.d.ts +1 -1
- package/dist/openai/index.js +1 -1
- package/dist/opencode/index.d.ts +2 -2
- package/dist/opencode/index.js +2 -2
- package/dist/opencode/index.js.map +1 -1
- package/dist/{sandbox-CEsJ1edi.d.ts → sandbox-CgjQQZGw.d.ts} +9 -6
- package/dist/sandbox-CgjQQZGw.d.ts.map +1 -0
- package/dist/xterm/index.d.ts +89 -0
- package/dist/xterm/index.d.ts.map +1 -0
- package/dist/xterm/index.js +177 -0
- package/dist/xterm/index.js.map +1 -0
- package/package.json +17 -5
- package/dist/sandbox-CEsJ1edi.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { _ as getEnvString, a as isExecResult, c as shellEscape, d as TraceContext, f as Execution, g as filterEnvVars, h as extractRepoName, i as isWSStreamChunk, l as createLogger, m as GitLogger, n as isWSError, o as isProcess, p as ResultImpl, r as isWSResponse, s as isProcessStatus, t as generateRequestId, u as createNoOpLogger, v as partitionEnvVars } from "./dist-
|
|
2
|
-
import { t as ErrorCode } from "./errors-
|
|
1
|
+
import { _ as getEnvString, a as isExecResult, c as shellEscape, d as TraceContext, f as Execution, g as filterEnvVars, h as extractRepoName, i as isWSStreamChunk, l as createLogger, m as GitLogger, n as isWSError, o as isProcess, p as ResultImpl, r as isWSResponse, s as isProcessStatus, t as generateRequestId, u as createNoOpLogger, v as partitionEnvVars } from "./dist-D9B_6gn_.js";
|
|
2
|
+
import { t as ErrorCode } from "./errors-Bzl0ZNia.js";
|
|
3
3
|
import { Container, getContainer, switchPort } from "@cloudflare/containers";
|
|
4
4
|
|
|
5
5
|
//#region src/errors/classes.ts
|
|
@@ -2089,13 +2089,16 @@ var SecurityError = class extends Error {
|
|
|
2089
2089
|
}
|
|
2090
2090
|
};
|
|
2091
2091
|
/**
|
|
2092
|
-
* Validates port numbers for sandbox services
|
|
2093
|
-
*
|
|
2092
|
+
* Validates port numbers for sandbox services.
|
|
2093
|
+
*
|
|
2094
|
+
* Rules:
|
|
2095
|
+
* - Range: 1024-65535 (privileged ports require root, which containers don't have)
|
|
2096
|
+
* - Reserved: 3000 (sandbox control plane)
|
|
2094
2097
|
*/
|
|
2095
2098
|
function validatePort(port) {
|
|
2096
2099
|
if (!Number.isInteger(port)) return false;
|
|
2097
2100
|
if (port < 1024 || port > 65535) return false;
|
|
2098
|
-
if ([3e3
|
|
2101
|
+
if ([3e3].includes(port)) return false;
|
|
2099
2102
|
return true;
|
|
2100
2103
|
}
|
|
2101
2104
|
/**
|
|
@@ -2216,6 +2219,19 @@ var CodeInterpreter = class {
|
|
|
2216
2219
|
}
|
|
2217
2220
|
};
|
|
2218
2221
|
|
|
2222
|
+
//#endregion
|
|
2223
|
+
//#region src/pty/proxy.ts
|
|
2224
|
+
async function proxyTerminal(stub, sessionId, request, options) {
|
|
2225
|
+
if (!sessionId || typeof sessionId !== "string") throw new Error("sessionId is required for terminal access");
|
|
2226
|
+
if (request.headers.get("Upgrade")?.toLowerCase() !== "websocket") throw new Error("terminal() requires a WebSocket upgrade request");
|
|
2227
|
+
const params = new URLSearchParams({ sessionId });
|
|
2228
|
+
if (options?.cols) params.set("cols", String(options.cols));
|
|
2229
|
+
if (options?.rows) params.set("rows", String(options.rows));
|
|
2230
|
+
const ptyUrl = `http://localhost/ws/pty?${params}`;
|
|
2231
|
+
const ptyRequest = new Request(ptyUrl, request);
|
|
2232
|
+
return stub.fetch(switchPort(ptyRequest, 3e3));
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2219
2235
|
//#endregion
|
|
2220
2236
|
//#region src/request-handler.ts
|
|
2221
2237
|
async function proxyToSandbox(request, env) {
|
|
@@ -2254,15 +2270,18 @@ async function proxyToSandbox(request, env) {
|
|
|
2254
2270
|
let proxyUrl;
|
|
2255
2271
|
if (port !== 3e3) proxyUrl = `http://localhost:${port}${path}${url.search}`;
|
|
2256
2272
|
else proxyUrl = `http://localhost:3000${path}${url.search}`;
|
|
2273
|
+
const headers = {
|
|
2274
|
+
"X-Original-URL": request.url,
|
|
2275
|
+
"X-Forwarded-Host": url.hostname,
|
|
2276
|
+
"X-Forwarded-Proto": url.protocol.replace(":", ""),
|
|
2277
|
+
"X-Sandbox-Name": sandboxId
|
|
2278
|
+
};
|
|
2279
|
+
request.headers.forEach((value, key) => {
|
|
2280
|
+
headers[key] = value;
|
|
2281
|
+
});
|
|
2257
2282
|
const proxyRequest = new Request(proxyUrl, {
|
|
2258
2283
|
method: request.method,
|
|
2259
|
-
headers
|
|
2260
|
-
...Object.fromEntries(request.headers),
|
|
2261
|
-
"X-Original-URL": request.url,
|
|
2262
|
-
"X-Forwarded-Host": url.hostname,
|
|
2263
|
-
"X-Forwarded-Proto": url.protocol.replace(":", ""),
|
|
2264
|
-
"X-Sandbox-Name": sandboxId
|
|
2265
|
-
},
|
|
2284
|
+
headers,
|
|
2266
2285
|
body: request.body,
|
|
2267
2286
|
duplex: "half"
|
|
2268
2287
|
});
|
|
@@ -2548,7 +2567,7 @@ function buildS3fsSource(bucket, prefix) {
|
|
|
2548
2567
|
* This file is auto-updated by .github/changeset-version.ts during releases
|
|
2549
2568
|
* DO NOT EDIT MANUALLY - Changes will be overwritten on the next version bump
|
|
2550
2569
|
*/
|
|
2551
|
-
const SDK_VERSION = "0.7.
|
|
2570
|
+
const SDK_VERSION = "0.7.2";
|
|
2552
2571
|
|
|
2553
2572
|
//#endregion
|
|
2554
2573
|
//#region src/sandbox.ts
|
|
@@ -2563,11 +2582,31 @@ function getSandbox(ns, id, options) {
|
|
|
2563
2582
|
if (options?.sleepAfter !== void 0) stub.setSleepAfter(options.sleepAfter);
|
|
2564
2583
|
if (options?.keepAlive !== void 0) stub.setKeepAlive(options.keepAlive);
|
|
2565
2584
|
if (options?.containerTimeouts) stub.setContainerTimeouts(options.containerTimeouts);
|
|
2566
|
-
|
|
2585
|
+
const defaultSessionId = `sandbox-${effectiveId}`;
|
|
2586
|
+
const enhancedMethods = {
|
|
2587
|
+
createSession: async (opts) => {
|
|
2588
|
+
return enhanceSession(stub, await stub.createSession(opts));
|
|
2589
|
+
},
|
|
2590
|
+
getSession: async (sessionId) => {
|
|
2591
|
+
return enhanceSession(stub, await stub.getSession(sessionId));
|
|
2592
|
+
},
|
|
2593
|
+
terminal: (request, opts) => proxyTerminal(stub, defaultSessionId, request, opts),
|
|
2594
|
+
wsConnect: connect(stub)
|
|
2595
|
+
};
|
|
2596
|
+
return new Proxy(stub, { get(target, prop) {
|
|
2597
|
+
if (typeof prop === "string" && prop in enhancedMethods) return enhancedMethods[prop];
|
|
2598
|
+
return target[prop];
|
|
2599
|
+
} });
|
|
2600
|
+
}
|
|
2601
|
+
function enhanceSession(stub, rpcSession) {
|
|
2602
|
+
return {
|
|
2603
|
+
...rpcSession,
|
|
2604
|
+
terminal: (request, opts) => proxyTerminal(stub, rpcSession.id, request, opts)
|
|
2605
|
+
};
|
|
2567
2606
|
}
|
|
2568
2607
|
function connect(stub) {
|
|
2569
2608
|
return async (request, port) => {
|
|
2570
|
-
if (!validatePort(port)) throw new SecurityError(`Invalid
|
|
2609
|
+
if (!validatePort(port)) throw new SecurityError(`Invalid port number: ${port}. Must be 1024-65535, excluding 3000 (sandbox control plane).`);
|
|
2571
2610
|
const portSwitchedRequest = switchPort(request, port);
|
|
2572
2611
|
return await stub.fetch(portSwitchedRequest);
|
|
2573
2612
|
};
|
|
@@ -3632,6 +3671,7 @@ var Sandbox = class extends Container {
|
|
|
3632
3671
|
* // url: https://8080-sandbox-id-my-token-v1.example.com
|
|
3633
3672
|
*/
|
|
3634
3673
|
async exposePort(port, options) {
|
|
3674
|
+
if (!validatePort(port)) throw new SecurityError(`Invalid port number: ${port}. Must be 1024-65535, excluding 3000 (sandbox control plane).`);
|
|
3635
3675
|
if (options.hostname.endsWith(".workers.dev")) throw new CustomDomainRequiredError({
|
|
3636
3676
|
code: ErrorCode.CUSTOM_DOMAIN_REQUIRED,
|
|
3637
3677
|
message: `Port exposure requires a custom domain. .workers.dev domains do not support wildcard subdomains required for port proxying.`,
|
|
@@ -3659,7 +3699,7 @@ var Sandbox = class extends Container {
|
|
|
3659
3699
|
};
|
|
3660
3700
|
}
|
|
3661
3701
|
async unexposePort(port) {
|
|
3662
|
-
if (!validatePort(port)) throw new SecurityError(`Invalid port number: ${port}. Must be
|
|
3702
|
+
if (!validatePort(port)) throw new SecurityError(`Invalid port number: ${port}. Must be 1024-65535, excluding 3000 (sandbox control plane).`);
|
|
3663
3703
|
const sessionId = await this.ensureDefaultSession();
|
|
3664
3704
|
await this.client.ports.unexposePort(port, sessionId);
|
|
3665
3705
|
const tokens = await this.ctx.storage.get("portTokens") || {};
|
|
@@ -3699,11 +3739,14 @@ var Sandbox = class extends Container {
|
|
|
3699
3739
|
this.logger.error("Port is exposed but has no token - bug detected", void 0, { port });
|
|
3700
3740
|
return false;
|
|
3701
3741
|
}
|
|
3702
|
-
if (storedToken.length !== token.length) return false;
|
|
3703
3742
|
const encoder = new TextEncoder();
|
|
3704
3743
|
const a = encoder.encode(storedToken);
|
|
3705
3744
|
const b = encoder.encode(token);
|
|
3706
|
-
|
|
3745
|
+
try {
|
|
3746
|
+
return crypto.subtle.timingSafeEqual(a, b);
|
|
3747
|
+
} catch {
|
|
3748
|
+
return false;
|
|
3749
|
+
}
|
|
3707
3750
|
}
|
|
3708
3751
|
validateCustomToken(token) {
|
|
3709
3752
|
if (token.length === 0) throw new SecurityError(`Custom token cannot be empty.`);
|
|
@@ -3716,7 +3759,7 @@ var Sandbox = class extends Container {
|
|
|
3716
3759
|
return btoa(String.fromCharCode(...array)).replace(/\+/g, "_").replace(/\//g, "_").replace(/=/g, "").toLowerCase();
|
|
3717
3760
|
}
|
|
3718
3761
|
constructPreviewUrl(port, sandboxId, hostname, token) {
|
|
3719
|
-
if (!validatePort(port)) throw new SecurityError(`Invalid port number: ${port}. Must be
|
|
3762
|
+
if (!validatePort(port)) throw new SecurityError(`Invalid port number: ${port}. Must be 1024-65535, excluding 3000 (sandbox control plane).`);
|
|
3720
3763
|
const effectiveId = this.sandboxName || sandboxId;
|
|
3721
3764
|
const hasUppercase = /[A-Z]/.test(effectiveId);
|
|
3722
3765
|
if (!this.normalizeId && hasUppercase) throw new SecurityError(`Preview URLs require lowercase sandbox IDs. Your ID "${effectiveId}" contains uppercase letters.\n\nTo fix this:\n1. Create a new sandbox with: getSandbox(ns, "${effectiveId}", { normalizeId: true })\n2. This will create a sandbox with ID: "${effectiveId.toLowerCase()}"\n\nNote: Due to DNS case-insensitivity, IDs with uppercase letters cannot be used with preview URLs.`);
|
|
@@ -3790,13 +3833,10 @@ var Sandbox = class extends Container {
|
|
|
3790
3833
|
timestamp: response.timestamp
|
|
3791
3834
|
};
|
|
3792
3835
|
}
|
|
3793
|
-
/**
|
|
3794
|
-
* Internal helper to create ExecutionSession wrapper for a given sessionId
|
|
3795
|
-
* Used by both createSession and getSession
|
|
3796
|
-
*/
|
|
3797
3836
|
getSessionWrapper(sessionId) {
|
|
3798
3837
|
return {
|
|
3799
3838
|
id: sessionId,
|
|
3839
|
+
terminal: null,
|
|
3800
3840
|
exec: (command, options) => this.execWithSession(command, sessionId, options),
|
|
3801
3841
|
execStream: (command, options) => this.execStreamWithSession(command, sessionId, options),
|
|
3802
3842
|
startProcess: (command, options) => this.startProcess(command, options, sessionId),
|
|
@@ -3995,5 +4035,5 @@ async function collectFile(stream) {
|
|
|
3995
4035
|
}
|
|
3996
4036
|
|
|
3997
4037
|
//#endregion
|
|
3998
|
-
export { BucketMountError, CodeInterpreter, CommandClient, FileClient, GitClient, InvalidMountConfigError, MissingCredentialsError, PortClient, ProcessClient, ProcessExitedBeforeReadyError, ProcessReadyTimeoutError, S3FSMountError, Sandbox, SandboxClient, UtilityClient, asyncIterableToSSEStream, collectFile, getSandbox, isExecResult, isProcess, isProcessStatus, parseSSEStream, proxyToSandbox, responseToAsyncIterable, streamFile };
|
|
4038
|
+
export { BucketMountError, CodeInterpreter, CommandClient, FileClient, GitClient, InvalidMountConfigError, MissingCredentialsError, PortClient, ProcessClient, ProcessExitedBeforeReadyError, ProcessReadyTimeoutError, S3FSMountError, Sandbox, SandboxClient, UtilityClient, asyncIterableToSSEStream, collectFile, getSandbox, isExecResult, isProcess, isProcessStatus, parseSSEStream, proxyTerminal, proxyToSandbox, responseToAsyncIterable, streamFile };
|
|
3999
4039
|
//# sourceMappingURL=index.js.map
|