@cloudflare/sandbox 0.0.0-104f455 → 0.0.0-153e416

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/CHANGELOG.md CHANGED
@@ -1,5 +1,58 @@
1
1
  # @cloudflare/sandbox
2
2
 
3
+ ## 0.4.11
4
+
5
+ ### Patch Changes
6
+
7
+ - [#159](https://github.com/cloudflare/sandbox-sdk/pull/159) [`e16659a`](https://github.com/cloudflare/sandbox-sdk/commit/e16659a1815923f1cd1176f51a052725d820ee16) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Use latest containers package version
8
+
9
+ ## 0.4.10
10
+
11
+ ### Patch Changes
12
+
13
+ - [#156](https://github.com/cloudflare/sandbox-sdk/pull/156) [`b61841c`](https://github.com/cloudflare/sandbox-sdk/commit/b61841cfb3248022ee8136311e54955ed9faa1ee) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Fix WebSocket upgrade requests through exposed ports
14
+
15
+ ## 0.4.9
16
+
17
+ ### Patch Changes
18
+
19
+ - [#152](https://github.com/cloudflare/sandbox-sdk/pull/152) [`8e7773e`](https://github.com/cloudflare/sandbox-sdk/commit/8e7773ec9571a5f968cbbc5f48e38e01d7d13b77) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Add exists() method to check if a file or directory exists
20
+
21
+ This adds a new `exists()` method to the SDK that checks whether a file or directory exists at a given path. The method returns a boolean indicating existence, similar to Python's `os.path.exists()` and JavaScript's `fs.existsSync()`.
22
+
23
+ The implementation is end-to-end:
24
+
25
+ - New `FileExistsResult` and `FileExistsRequest` types in shared package
26
+ - Handler endpoint at `/api/exists` in container layer
27
+ - Client method in `FileClient` and `Sandbox` classes
28
+ - Full test coverage (unit tests and E2E tests)
29
+
30
+ ## 0.4.8
31
+
32
+ ### Patch Changes
33
+
34
+ - [#153](https://github.com/cloudflare/sandbox-sdk/pull/153) [`f6a5c3e`](https://github.com/cloudflare/sandbox-sdk/commit/f6a5c3e1607fce5fc26f816e9206ae437898d5af) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Fix token extraction regex causing Invalid token errors
35
+
36
+ ## 0.4.7
37
+
38
+ ### Patch Changes
39
+
40
+ - [#141](https://github.com/cloudflare/sandbox-sdk/pull/141) [`c39674b`](https://github.com/cloudflare/sandbox-sdk/commit/c39674b8fe2e986e59a794b6bb3a5f51a87bae89) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Fix commands hanging when reading stdin by redirecting stdin to /dev/null
41
+
42
+ - [#143](https://github.com/cloudflare/sandbox-sdk/pull/143) [`276efc0`](https://github.com/cloudflare/sandbox-sdk/commit/276efc0ca8776bcc8de79e7e58dd24d9f418cc5c) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Remove unnecessary existing session check
43
+
44
+ ## 0.4.6
45
+
46
+ ### Patch Changes
47
+
48
+ - [#133](https://github.com/cloudflare/sandbox-sdk/pull/133) [`da2cfb8`](https://github.com/cloudflare/sandbox-sdk/commit/da2cfb876675eb3445970c90b4d70d00288a7c74) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - feat: Add version sync detection between npm package and Docker image
49
+
50
+ ## 0.4.5
51
+
52
+ ### Patch Changes
53
+
54
+ - [#127](https://github.com/cloudflare/sandbox-sdk/pull/127) [`e79ac80`](https://github.com/cloudflare/sandbox-sdk/commit/e79ac80bc855a3ec527d44cc14585794b23cb129) Thanks [@whoiskatrin](https://github.com/whoiskatrin)! - configurable sleepAfter
55
+
3
56
  ## 0.4.4
4
57
 
5
58
  ### Patch Changes
package/Dockerfile CHANGED
@@ -60,9 +60,15 @@ RUN npm ci --production
60
60
  # ============================================================================
61
61
  FROM ubuntu:22.04 AS runtime
62
62
 
63
+ # Accept version as build argument (passed from npm_package_version)
64
+ ARG SANDBOX_VERSION=unknown
65
+
63
66
  # Prevent interactive prompts during package installation
64
67
  ENV DEBIAN_FRONTEND=noninteractive
65
68
 
69
+ # Set the sandbox version as an environment variable for version checking
70
+ ENV SANDBOX_VERSION=${SANDBOX_VERSION}
71
+
66
72
  # Install essential runtime packages
67
73
  RUN apt-get update && apt-get install -y --no-install-recommends \
68
74
  curl \
@@ -0,0 +1,7 @@
1
+ // src/version.ts
2
+ var SDK_VERSION = "0.4.11";
3
+
4
+ export {
5
+ SDK_VERSION
6
+ };
7
+ //# sourceMappingURL=chunk-FE4PJSRB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/version.ts"],"sourcesContent":["/**\n * SDK version - automatically synchronized with package.json by Changesets\n * This file is auto-updated by .github/changeset-version.ts during releases\n * DO NOT EDIT MANUALLY - Changes will be overwritten on the next version bump\n */\nexport const SDK_VERSION = '0.4.11';\n"],"mappings":";AAKO,IAAM,cAAc;","names":[]}
@@ -14,6 +14,12 @@ import {
14
14
  import {
15
15
  parseSSEStream
16
16
  } from "./chunk-EKSWCBCA.js";
17
+ import {
18
+ SDK_VERSION
19
+ } from "./chunk-FE4PJSRB.js";
20
+
21
+ // src/request-handler.ts
22
+ import { switchPort } from "@cloudflare/containers";
17
23
 
18
24
  // src/sandbox.ts
19
25
  import { Container, getContainer } from "@cloudflare/containers";
@@ -1057,6 +1063,25 @@ var FileClient = class extends BaseHttpClient {
1057
1063
  throw error;
1058
1064
  }
1059
1065
  }
1066
+ /**
1067
+ * Check if a file or directory exists
1068
+ * @param path - Path to check
1069
+ * @param sessionId - The session ID for this operation
1070
+ */
1071
+ async exists(path, sessionId) {
1072
+ try {
1073
+ const data = {
1074
+ path,
1075
+ sessionId
1076
+ };
1077
+ const response = await this.post("/api/exists", data);
1078
+ this.logSuccess("Path existence checked", `${path} (exists: ${response.exists})`);
1079
+ return response;
1080
+ } catch (error) {
1081
+ this.logError("exists", error);
1082
+ throw error;
1083
+ }
1084
+ }
1060
1085
  };
1061
1086
 
1062
1087
  // src/clients/git-client.ts
@@ -1562,6 +1587,20 @@ var UtilityClient = class extends BaseHttpClient {
1562
1587
  throw error;
1563
1588
  }
1564
1589
  }
1590
+ /**
1591
+ * Get the container version
1592
+ * Returns the version embedded in the Docker image during build
1593
+ */
1594
+ async getVersion() {
1595
+ try {
1596
+ const response = await this.get("/api/version");
1597
+ this.logSuccess("Version retrieved", response.version);
1598
+ return response.version;
1599
+ } catch (error) {
1600
+ this.logger.debug("Failed to get container version (may be old container)", { error });
1601
+ return "unknown";
1602
+ }
1603
+ }
1565
1604
  };
1566
1605
 
1567
1606
  // src/clients/sandbox-client.ts
@@ -1595,12 +1634,15 @@ function getSandbox(ns, id, options) {
1595
1634
  if (options?.baseUrl) {
1596
1635
  stub.setBaseUrl(options.baseUrl);
1597
1636
  }
1637
+ if (options?.sleepAfter !== void 0) {
1638
+ stub.setSleepAfter(options.sleepAfter);
1639
+ }
1598
1640
  return stub;
1599
1641
  }
1600
1642
  var Sandbox = class extends Container {
1601
1643
  defaultPort = 3e3;
1602
1644
  // Default port for the container's Bun server
1603
- sleepAfter = "3m";
1645
+ sleepAfter = "10m";
1604
1646
  // Sleep the sandbox if no requests are made in this timeframe
1605
1647
  client;
1606
1648
  codeInterpreter;
@@ -1658,6 +1700,10 @@ var Sandbox = class extends Container {
1658
1700
  }
1659
1701
  }
1660
1702
  }
1703
+ // RPC method to set the sleep timeout
1704
+ async setSleepAfter(sleepAfter) {
1705
+ this.sleepAfter = sleepAfter;
1706
+ }
1661
1707
  // RPC method to set environment variables
1662
1708
  async setEnvVars(envVars) {
1663
1709
  this.envVars = { ...this.envVars, ...envVars };
@@ -1681,6 +1727,35 @@ var Sandbox = class extends Container {
1681
1727
  }
1682
1728
  onStart() {
1683
1729
  this.logger.debug("Sandbox started");
1730
+ this.checkVersionCompatibility().catch((error) => {
1731
+ this.logger.error("Version compatibility check failed", error instanceof Error ? error : new Error(String(error)));
1732
+ });
1733
+ }
1734
+ /**
1735
+ * Check if the container version matches the SDK version
1736
+ * Logs a warning if there's a mismatch
1737
+ */
1738
+ async checkVersionCompatibility() {
1739
+ try {
1740
+ const sdkVersion = SDK_VERSION;
1741
+ const containerVersion = await this.client.utils.getVersion();
1742
+ if (containerVersion === "unknown") {
1743
+ this.logger.warn(
1744
+ "Container version check: Container version could not be determined. This may indicate an outdated container image. Please update your container to match SDK version " + sdkVersion
1745
+ );
1746
+ return;
1747
+ }
1748
+ if (containerVersion !== sdkVersion) {
1749
+ const message = `Version mismatch detected! SDK version (${sdkVersion}) does not match container version (${containerVersion}). This may cause compatibility issues. Please update your container image to version ${sdkVersion}`;
1750
+ this.logger.warn(message);
1751
+ } else {
1752
+ this.logger.debug("Version check passed", { sdkVersion, containerVersion });
1753
+ }
1754
+ } catch (error) {
1755
+ this.logger.debug("Version compatibility check encountered an error", {
1756
+ error: error instanceof Error ? error.message : String(error)
1757
+ });
1758
+ }
1684
1759
  }
1685
1760
  onStop() {
1686
1761
  this.logger.debug("Sandbox stopped");
@@ -1699,6 +1774,11 @@ var Sandbox = class extends Container {
1699
1774
  this.sandboxName = name;
1700
1775
  await this.ctx.storage.put("sandboxName", name);
1701
1776
  }
1777
+ const upgradeHeader = request.headers.get("Upgrade");
1778
+ const isWebSocket = upgradeHeader?.toLowerCase() === "websocket";
1779
+ if (isWebSocket) {
1780
+ return await super.fetch(request);
1781
+ }
1702
1782
  const port = this.determinePort(url);
1703
1783
  return await this.containerFetch(request, port);
1704
1784
  });
@@ -1731,7 +1811,7 @@ var Sandbox = class extends Container {
1731
1811
  await this.ctx.storage.put("defaultSession", sessionId);
1732
1812
  this.logger.debug("Default session initialized", { sessionId });
1733
1813
  } catch (error) {
1734
- if (error?.message?.includes("already exists") || error?.message?.includes("Session")) {
1814
+ if (error?.message?.includes("already exists")) {
1735
1815
  this.logger.debug("Reusing existing session after reload", { sessionId });
1736
1816
  this.defaultSession = sessionId;
1737
1817
  await this.ctx.storage.put("defaultSession", sessionId);
@@ -2013,6 +2093,10 @@ var Sandbox = class extends Container {
2013
2093
  const session = await this.ensureDefaultSession();
2014
2094
  return this.client.files.listFiles(path, session, options);
2015
2095
  }
2096
+ async exists(path, sessionId) {
2097
+ const session = sessionId ?? await this.ensureDefaultSession();
2098
+ return this.client.files.exists(path, session);
2099
+ }
2016
2100
  async exposePort(port, options) {
2017
2101
  if (options.hostname.endsWith(".workers.dev")) {
2018
2102
  const errorResponse = {
@@ -2188,6 +2272,7 @@ var Sandbox = class extends Container {
2188
2272
  renameFile: (oldPath, newPath) => this.renameFile(oldPath, newPath, sessionId),
2189
2273
  moveFile: (sourcePath, destPath) => this.moveFile(sourcePath, destPath, sessionId),
2190
2274
  listFiles: (path, options) => this.client.files.listFiles(path, sessionId, options),
2275
+ exists: (path) => this.exists(path, sessionId),
2191
2276
  // Git operations
2192
2277
  gitCheckout: (repoUrl, options) => this.gitCheckout(repoUrl, { ...options, sessionId }),
2193
2278
  // Environment management - needs special handling
@@ -2280,6 +2365,10 @@ async function proxyToSandbox(request, env) {
2280
2365
  );
2281
2366
  }
2282
2367
  }
2368
+ const upgradeHeader = request.headers.get("Upgrade");
2369
+ if (upgradeHeader?.toLowerCase() === "websocket") {
2370
+ return await sandbox.fetch(switchPort(request, port));
2371
+ }
2283
2372
  let proxyUrl;
2284
2373
  if (port !== 3e3) {
2285
2374
  proxyUrl = `http://localhost:${port}${path}${url.search}`;
@@ -2300,14 +2389,14 @@ async function proxyToSandbox(request, env) {
2300
2389
  // @ts-expect-error - duplex required for body streaming in modern runtimes
2301
2390
  duplex: "half"
2302
2391
  });
2303
- return sandbox.containerFetch(proxyRequest, port);
2392
+ return await sandbox.containerFetch(proxyRequest, port);
2304
2393
  } catch (error) {
2305
2394
  logger.error("Proxy routing error", error instanceof Error ? error : new Error(String(error)));
2306
2395
  return new Response("Proxy routing error", { status: 500 });
2307
2396
  }
2308
2397
  }
2309
2398
  function extractSandboxRoute(url) {
2310
- const subdomainMatch = url.hostname.match(/^(\d{4,5})-([^.-][^.]*[^.-]|[^.-])-([a-zA-Z0-9_-]{12,20})\.(.+)$/);
2399
+ const subdomainMatch = url.hostname.match(/^(\d{4,5})-([^.-][^.]*?[^.-]|[^.-])-([a-z0-9_-]{16})\.(.+)$/);
2311
2400
  if (!subdomainMatch) {
2312
2401
  return null;
2313
2402
  }
@@ -2364,4 +2453,4 @@ export {
2364
2453
  getSandbox,
2365
2454
  Sandbox
2366
2455
  };
2367
- //# sourceMappingURL=chunk-2P3MDMNJ.js.map
2456
+ //# sourceMappingURL=chunk-SVWLTRHD.js.map