@cloudflare/sandbox 0.13.0-next.769.1 → 1.0.0-rc.0

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.
Files changed (63) hide show
  1. package/README.md +62 -219
  2. package/dist/index.d.mts +548 -0
  3. package/dist/index.mjs +2452 -0
  4. package/package.json +17 -118
  5. package/Dockerfile +0 -327
  6. package/dist/bridge/index.d.ts +0 -181
  7. package/dist/bridge/index.d.ts.map +0 -1
  8. package/dist/bridge/index.js +0 -3053
  9. package/dist/bridge/index.js.map +0 -1
  10. package/dist/contexts-1EsLHByO.d.ts +0 -463
  11. package/dist/contexts-1EsLHByO.d.ts.map +0 -1
  12. package/dist/dist-Duor5GbS.js +0 -752
  13. package/dist/dist-Duor5GbS.js.map +0 -1
  14. package/dist/errors/index.d.ts +0 -4
  15. package/dist/errors/index.js +0 -4
  16. package/dist/errors-CXR0xBpw.js +0 -285
  17. package/dist/errors-CXR0xBpw.js.map +0 -1
  18. package/dist/errors-QYlSkVGz.js +0 -893
  19. package/dist/errors-QYlSkVGz.js.map +0 -1
  20. package/dist/extensions/index.d.ts +0 -4
  21. package/dist/extensions/index.js +0 -6
  22. package/dist/extensions-CFB2xHqY.js +0 -1023
  23. package/dist/extensions-CFB2xHqY.js.map +0 -1
  24. package/dist/filesystem-BWAZCZER.d.ts +0 -732
  25. package/dist/filesystem-BWAZCZER.d.ts.map +0 -1
  26. package/dist/git/index.d.ts +0 -63
  27. package/dist/git/index.d.ts.map +0 -1
  28. package/dist/git/index.js +0 -338
  29. package/dist/git/index.js.map +0 -1
  30. package/dist/index-Bs4bqXDR.d.ts +0 -438
  31. package/dist/index-Bs4bqXDR.d.ts.map +0 -1
  32. package/dist/index-HNYBk-az.d.ts +0 -444
  33. package/dist/index-HNYBk-az.d.ts.map +0 -1
  34. package/dist/index.d.ts +0 -576
  35. package/dist/index.d.ts.map +0 -1
  36. package/dist/index.js +0 -33
  37. package/dist/index.js.map +0 -1
  38. package/dist/interpreter/index.d.ts +0 -311
  39. package/dist/interpreter/index.d.ts.map +0 -1
  40. package/dist/interpreter/index.js +0 -292
  41. package/dist/interpreter/index.js.map +0 -1
  42. package/dist/openai/index.d.ts +0 -68
  43. package/dist/openai/index.d.ts.map +0 -1
  44. package/dist/openai/index.js +0 -367
  45. package/dist/openai/index.js.map +0 -1
  46. package/dist/opencode/index.d.ts +0 -182
  47. package/dist/opencode/index.d.ts.map +0 -1
  48. package/dist/opencode/index.js +0 -454
  49. package/dist/opencode/index.js.map +0 -1
  50. package/dist/process-types-GStiZ8f8.d.ts +0 -73
  51. package/dist/process-types-GStiZ8f8.d.ts.map +0 -1
  52. package/dist/sandbox-BbAabq93.d.ts +0 -42
  53. package/dist/sandbox-BbAabq93.d.ts.map +0 -1
  54. package/dist/sandbox-cmlgGVYX.js +0 -10056
  55. package/dist/sandbox-cmlgGVYX.js.map +0 -1
  56. package/dist/sidecar/index.d.ts +0 -77
  57. package/dist/sidecar/index.d.ts.map +0 -1
  58. package/dist/sidecar/index.js +0 -201
  59. package/dist/sidecar/index.js.map +0 -1
  60. package/dist/xterm/index.d.ts +0 -93
  61. package/dist/xterm/index.d.ts.map +0 -1
  62. package/dist/xterm/index.js +0 -220
  63. package/dist/xterm/index.js.map +0 -1
package/package.json CHANGED
@@ -1,129 +1,28 @@
1
1
  {
2
2
  "name": "@cloudflare/sandbox",
3
- "version": "0.13.0-next.769.1",
3
+ "version": "1.0.0-rc.0",
4
+ "description": "Structured workspace file operations for Cloudflare sandboxes",
5
+ "license": "Apache-2.0",
4
6
  "repository": {
5
7
  "type": "git",
6
- "url": "https://github.com/cloudflare/sandbox-sdk"
7
- },
8
- "description": "A sandboxed environment for running commands",
9
- "type": "module",
10
- "dependencies": {
11
- "@cloudflare/containers": "^0.3.7",
12
- "aws4fetch": "^1.0.20",
13
- "capnweb": "^0.8.0",
14
- "hono": "^4.12.26"
15
- },
16
- "devDependencies": {
17
- "@openai/agents": "^0.3.3",
18
- "@opencode-ai/sdk": "^1.1.40",
19
- "@repo/shared": "^0.0.0",
20
- "@types/acorn": "^4.0.6",
21
- "@types/bun": "^1.3.14",
22
- "@types/tar-stream": "^3.1.4",
23
- "@xterm/xterm": "^6.0.0",
24
- "acorn": "^8.14.0",
25
- "async-mutex": "^0.5.0",
26
- "tar-stream": "^3.2.0",
27
- "wrangler": "^4.102.0"
28
- },
29
- "peerDependencies": {
30
- "@openai/agents": "^0.3.3",
31
- "@opencode-ai/sdk": "^1.1.40",
32
- "@xterm/xterm": ">=5.0.0"
33
- },
34
- "peerDependenciesMeta": {
35
- "@openai/agents": {
36
- "optional": true
37
- },
38
- "@opencode-ai/sdk": {
39
- "optional": true
40
- },
41
- "@xterm/xterm": {
42
- "optional": true
43
- }
8
+ "url": "git+https://github.com/cloudflare/sandbox-sdk.git"
44
9
  },
45
- "tags": [
46
- "sandbox",
47
- "codegen",
48
- "containers",
49
- "cloudflare",
50
- "durable objects"
10
+ "files": [
11
+ "dist"
51
12
  ],
52
- "scripts": {
53
- "build": "rm -rf dist && npm run build:sidecar && tsdown --config tsdown.config.ts",
54
- "build:sidecar": "bun run ../../extensions/interpreter/build.ts",
55
- "check": "biome check && npm run typecheck",
56
- "fix": "biome check --fix && npm run typecheck",
57
- "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.sidecar.json",
58
- "docker:local": "scripts/docker-local.sh",
59
- "test": "vitest run --config vitest.config.ts \"$@\"",
60
- "test:harness": "vitest run --config vitest.harness.config.ts \"$@\"",
61
- "test:sidecar": "bun test ../../extensions/interpreter/src/sidecar",
62
- "test:e2e": "npm run test:e2e:vitest && npm run test:e2e:browser",
63
- "test:e2e:vitest": "cd ../../tests/e2e/test-worker && ./generate-config.sh && cd ../../.. && vitest run --config vitest.e2e.config.ts \"$@\"",
64
- "test:e2e:browser": "cd ../../tests/e2e/test-worker && ./generate-config.sh && cd ../../.. && npx playwright install chromium && playwright test --config tests/e2e/browser/playwright.config.ts",
65
- "test:perf": "cd ../.. && vitest run --config vitest.perf.config.ts \"$@\""
66
- },
13
+ "type": "module",
14
+ "sideEffects": false,
67
15
  "exports": {
68
16
  ".": {
69
- "types": "./dist/index.d.ts",
70
- "import": "./dist/index.js",
71
- "require": "./dist/index.js"
72
- },
73
- "./extensions": {
74
- "types": "./dist/extensions/index.d.ts",
75
- "import": "./dist/extensions/index.js",
76
- "require": "./dist/extensions/index.js"
77
- },
78
- "./errors": {
79
- "types": "./dist/errors/index.d.ts",
80
- "import": "./dist/errors/index.js",
81
- "require": "./dist/errors/index.js"
82
- },
83
- "./sidecar": {
84
- "types": "./dist/sidecar/index.d.ts",
85
- "import": "./dist/sidecar/index.js",
86
- "require": "./dist/sidecar/index.js"
87
- },
88
- "./interpreter": {
89
- "types": "./dist/interpreter/index.d.ts",
90
- "import": "./dist/interpreter/index.js",
91
- "require": "./dist/interpreter/index.js"
92
- },
93
- "./git": {
94
- "types": "./dist/git/index.d.ts",
95
- "import": "./dist/git/index.js",
96
- "require": "./dist/git/index.js"
97
- },
98
- "./openai": {
99
- "types": "./dist/openai/index.d.ts",
100
- "import": "./dist/openai/index.js",
101
- "require": "./dist/openai/index.js"
102
- },
103
- "./opencode": {
104
- "types": "./dist/opencode/index.d.ts",
105
- "import": "./dist/opencode/index.js",
106
- "require": "./dist/opencode/index.js"
107
- },
108
- "./xterm": {
109
- "types": "./dist/xterm/index.d.ts",
110
- "import": "./dist/xterm/index.js",
111
- "require": "./dist/xterm/index.js"
112
- },
113
- "./bridge": {
114
- "types": "./dist/bridge/index.d.ts",
115
- "import": "./dist/bridge/index.js",
116
- "require": "./dist/bridge/index.js"
17
+ "types": "./dist/index.d.mts",
18
+ "import": "./dist/index.mjs"
117
19
  }
118
20
  },
119
- "keywords": [],
120
- "author": "",
121
- "license": "Apache-2.0",
122
- "files": [
123
- "dist",
124
- "Dockerfile",
125
- "startup.sh",
126
- "README.md",
127
- "LICENSE"
128
- ]
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "dependencies": {
25
+ "aws4fetch": "1.0.20",
26
+ "zod": "4.5.4"
27
+ }
129
28
  }
package/Dockerfile DELETED
@@ -1,327 +0,0 @@
1
- # Bun version — override via --build-arg BUN_VERSION=$(cat .bun-version)
2
- ARG BUN_VERSION=1.3.14
3
- # Node version — override via --build-arg NODE_VERSION=24
4
- ARG NODE_VERSION=24
5
- # cloudflared release — shared across glibc and musl image variants.
6
- # Bump this together with the architecture-specific checksums below.
7
- ARG CLOUDFLARED_VERSION=2026.3.0
8
- FROM oven/bun:${BUN_VERSION} AS bun-binary
9
- FROM node:${NODE_VERSION}-slim AS node-runtime
10
-
11
- # ============================================================================
12
- # cloudflared (Cloudflare Tunnel daemon) — enables sandbox.tunnels.*
13
- # Version pin lives at the top of this Dockerfile as a global ARG, shared
14
- # by every image variant so they ship the same release.
15
- # ============================================================================
16
- FROM alpine:3.21 AS cloudflared-binary
17
-
18
- ARG TARGETARCH
19
- ARG CLOUDFLARED_VERSION
20
- ARG CLOUDFLARED_SHA256_AMD64=4a9e50e6d6d798e90fcd01933151a90bf7edd99a0a55c28ad18f2e16263a5c30
21
- ARG CLOUDFLARED_SHA256_ARM64=0755ba4cbab59980e6148367fcf53a8f3ec85a97deefd63c2420cf7850769bee
22
-
23
- # Inject the host's extra CA bundle when downloading behind a TLS-intercepting
24
- # proxy (e.g. Cloudflare WARP / Zero Trust). No-op when the secret isn't passed.
25
- RUN --mount=type=secret,id=wrangler_ca \
26
- if [ -f /run/secrets/wrangler_ca ] && [ -s /run/secrets/wrangler_ca ]; then \
27
- cat /run/secrets/wrangler_ca >> /etc/ssl/certs/ca-certificates.crt; \
28
- mkdir -p /usr/local/share/ca-certificates && \
29
- cp /run/secrets/wrangler_ca /usr/local/share/ca-certificates/wrangler-dev-ca.crt; \
30
- fi && \
31
- apk add --no-cache ca-certificates curl && \
32
- if [ -f /usr/local/share/ca-certificates/wrangler-dev-ca.crt ]; then \
33
- update-ca-certificates; \
34
- fi
35
-
36
- RUN set -eux; \
37
- arch="${TARGETARCH:-}"; \
38
- if [ -z "$arch" ]; then \
39
- arch="$(apk --print-arch)"; \
40
- fi; \
41
- case "$arch" in \
42
- amd64|x86_64) suffix=amd64; sha="${CLOUDFLARED_SHA256_AMD64}" ;; \
43
- arm64|aarch64) suffix=arm64; sha="${CLOUDFLARED_SHA256_ARM64}" ;; \
44
- *) echo "Unsupported arch for cloudflared: $arch" >&2; exit 1 ;; \
45
- esac; \
46
- url="https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-${suffix}"; \
47
- curl -fsSL -o /cloudflared "$url"; \
48
- echo "$sha /cloudflared" | sha256sum -c -; \
49
- chmod +x /cloudflared; \
50
- /cloudflared --version
51
-
52
- # Sandbox container images (default and python variants)
53
- # Multi-stage build optimized for Turborepo monorepo
54
-
55
- # ============================================================================
56
- # Stage 1: Prune monorepo to only include necessary packages
57
- # ============================================================================
58
- FROM node-runtime AS pruner
59
-
60
- WORKDIR /app
61
-
62
- RUN npm install -g turbo
63
-
64
- COPY . .
65
-
66
- # Prune to only @repo/sandbox-container and its dependencies (@repo/shared)
67
- # The --docker flag generates out/json and out/full directories
68
- RUN turbo prune @repo/sandbox-container --docker
69
-
70
- # ============================================================================
71
- # Stage 2: Install dependencies and build packages
72
- # Using glibc-based images (not Alpine) so the standalone binary works on
73
- # standard Linux distributions (Debian, Ubuntu, RHEL, etc.)
74
- # ============================================================================
75
- FROM node-runtime AS builder
76
-
77
- WORKDIR /app
78
-
79
- # Install Bun runtime (glibc version for glibc-compatible standalone binary)
80
- COPY --from=bun-binary /usr/local/bin/bun /usr/local/bin/bun
81
-
82
- # Copy pruned lockfile and package.json files (for Docker layer caching)
83
- COPY --from=pruner /app/out/json/ .
84
- COPY --from=pruner /app/out/package-lock.json ./package-lock.json
85
-
86
- # Install ALL dependencies with cache mount for npm packages
87
- RUN --mount=type=cache,target=/root/.npm \
88
- CI=true npm ci
89
-
90
- COPY --from=pruner /app/out/full/ .
91
-
92
- # Build all packages (Turborepo handles dependency order automatically)
93
- # This builds @repo/shared first, then @repo/sandbox-container (including standalone binary)
94
- RUN npx turbo run build
95
-
96
- # ============================================================================
97
- # Stage 3: Download pre-built Python 3.11.14
98
- # ============================================================================
99
- FROM ubuntu:22.04 AS python-builder
100
-
101
- # Prevent interactive prompts during package installation
102
- ENV DEBIAN_FRONTEND=noninteractive
103
-
104
- # Accept architecture from Docker BuildKit (for multi-arch builds)
105
- ARG TARGETARCH
106
-
107
- # Install minimal dependencies for downloading
108
- RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
109
- --mount=type=cache,target=/var/lib/apt,sharing=locked \
110
- rm -f /etc/apt/apt.conf.d/docker-clean && \
111
- echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' >/etc/apt/apt.conf.d/keep-cache && \
112
- apt-get update && apt-get install -y --no-install-recommends \
113
- wget ca-certificates
114
-
115
- # Download and extract pre-built Python 3.11.14 from python-build-standalone
116
- # Using PGO+LTO optimized builds for better performance
117
- # Supports multi-arch: amd64 (x86_64) and arm64 (aarch64)
118
- RUN --mount=type=cache,target=/tmp/python-cache \
119
- # Map Docker TARGETARCH to python-build-standalone arch naming
120
- if [ "$TARGETARCH" = "amd64" ]; then \
121
- PYTHON_ARCH="x86_64-unknown-linux-gnu"; \
122
- EXPECTED_SHA256="edd8d11aa538953d12822fab418359a692fd1ee4ca2675579fbf0fa31e3688f1"; \
123
- elif [ "$TARGETARCH" = "arm64" ]; then \
124
- PYTHON_ARCH="aarch64-unknown-linux-gnu"; \
125
- EXPECTED_SHA256="08141d31f95d86a23f23e4c741b726de0055f12f83200d1d4867b4e8e6e967c5"; \
126
- else \
127
- echo "Unsupported architecture: $TARGETARCH" && exit 1; \
128
- fi && \
129
- cd /tmp/python-cache && \
130
- wget -nc https://github.com/indygreg/python-build-standalone/releases/download/20251028/cpython-3.11.14+20251028-${PYTHON_ARCH}-install_only.tar.gz && \
131
- # Verify SHA256 checksum for security
132
- echo "${EXPECTED_SHA256} cpython-3.11.14+20251028-${PYTHON_ARCH}-install_only.tar.gz" | sha256sum -c - && \
133
- cd /tmp && \
134
- tar -xzf /tmp/python-cache/cpython-3.11.14+20251028-${PYTHON_ARCH}-install_only.tar.gz && \
135
- mv python /usr/local/ && \
136
- rm -rf /tmp/cpython-*
137
-
138
- # ============================================================================
139
- # Stage 4: Runtime base - Ubuntu 22.04 with Node.js and Bun (no Python)
140
- # ============================================================================
141
- FROM ubuntu:22.04 AS runtime-base
142
-
143
- # Accept version as build argument (passed from npm_package_version)
144
- ARG SANDBOX_VERSION=unknown
145
-
146
- # Prevent interactive prompts during package installation
147
- ENV DEBIAN_FRONTEND=noninteractive
148
-
149
- ENV SANDBOX_VERSION=${SANDBOX_VERSION}
150
-
151
- # Install runtime packages, S3FS-FUSE for bucket mounting, and snapshot tools
152
- # - fuse3: FUSE filesystem support (replaces legacy fuse, needed by s3fs/squashfuse/fuse-overlayfs)
153
- # - squashfs-tools: create squashfs archives (mksquashfs)
154
- # - squashfuse: mount squashfs in userspace (FUSE)
155
- # - fuse-overlayfs: userspace overlayfs for copy-on-write snapshots
156
- # Cache-bust: 2 - Clear apt cache to force fresh package list
157
- RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
158
- --mount=type=cache,target=/var/lib/apt,sharing=locked \
159
- rm -f /etc/apt/apt.conf.d/docker-clean && \
160
- echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' >/etc/apt/apt.conf.d/keep-cache && \
161
- rm -rf /var/cache/apt/* /var/lib/apt/lists/* && \
162
- apt-get update && apt-get install -y --no-install-recommends \
163
- s3fs fuse3 squashfs-tools squashfuse fuse-overlayfs \
164
- ca-certificates curl wget procps git unzip zip jq file tini \
165
- inotify-tools \
166
- libssl3 zlib1g libbz2-1.0 libreadline8 libsqlite3-0 \
167
- libncursesw6 libtinfo6 libxml2 libxmlsec1 libffi8 liblzma5 libtk8.6 && \
168
- update-ca-certificates
169
-
170
- # Enable FUSE in container - allow non-root users to use FUSE
171
- RUN sed -i 's/#user_allow_other/user_allow_other/' /etc/fuse.conf
172
-
173
- # fusermount requires /etc/mtab to locate active mounts
174
- RUN ln -sf /proc/mounts /etc/mtab
175
-
176
- # Install Node.js from official Node image (defaults to 24 LTS,
177
- # override via --build-arg NODE_VERSION=<version>)
178
- COPY --from=node-runtime /usr/local/bin/node /usr/local/bin/node
179
- COPY --from=node-runtime /usr/local/lib/node_modules /usr/local/lib/node_modules
180
- RUN ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm && \
181
- ln -s /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx
182
-
183
- # Install Bun runtime from official image
184
- COPY --from=bun-binary /usr/local/bin/bun /usr/local/bin/bun
185
-
186
- # Copy standalone binary
187
- COPY --from=builder /app/packages/sandbox-container/dist/sandbox /container-server/sandbox
188
-
189
- # Set up container server directory
190
- WORKDIR /container-server
191
-
192
- # Copy legacy JS bundle for backwards compatibility
193
- # Users with custom startup scripts that call `bun /container-server/dist/index.js` need this
194
- COPY --from=builder /app/packages/sandbox-container/dist/index.js ./dist/
195
-
196
- COPY --from=cloudflared-binary /cloudflared /usr/local/bin/cloudflared
197
- RUN cloudflared --version
198
-
199
- # Inject the host's extra CA bundle when running locally behind a TLS-
200
- # intercepting proxy (e.g. Cloudflare WARP / Zero Trust). See
201
- # DOCKER_README.md for the local-dev setup. No-op when the secret
202
- # isn't passed.
203
- RUN --mount=type=secret,id=wrangler_ca \
204
- if [ -f /run/secrets/wrangler_ca ] && [ -s /run/secrets/wrangler_ca ]; then \
205
- cp /run/secrets/wrangler_ca /usr/local/share/ca-certificates/wrangler-dev-ca.crt && \
206
- cat /run/secrets/wrangler_ca >> /etc/ssl/certs/ca-certificates.crt && \
207
- update-ca-certificates; \
208
- fi
209
-
210
- RUN mkdir -p /workspace
211
-
212
- # Expose the application port (3000 for control)
213
- EXPOSE 3000
214
-
215
- # ============================================================================
216
- # Stage 5a: Default image - lean, no Python
217
- # ============================================================================
218
- FROM runtime-base AS default
219
-
220
- # Disable Python pool (Python not available in this image)
221
- ENV PYTHON_POOL_MIN_SIZE=0
222
- ENV JAVASCRIPT_POOL_MIN_SIZE=3
223
- ENV TYPESCRIPT_POOL_MIN_SIZE=3
224
-
225
- ENTRYPOINT ["/usr/bin/tini", "--", "/container-server/sandbox"]
226
-
227
- # ============================================================================
228
- # Stage 5b: Python image - full, with Python + data science packages
229
- # ============================================================================
230
- FROM runtime-base AS python
231
-
232
- # Copy pre-built Python from python-builder stage
233
- COPY --from=python-builder /usr/local/python /usr/local/python
234
-
235
- # Create symlinks and update shared library cache
236
- RUN ln -s /usr/local/python/bin/python3.11 /usr/local/bin/python3.11 && \
237
- ln -s /usr/local/python/bin/python3 /usr/local/bin/python3 && \
238
- ln -s /usr/local/python/bin/pip3 /usr/local/bin/pip3 && \
239
- echo "/usr/local/python/lib" > /etc/ld.so.conf.d/python.conf && \
240
- ldconfig
241
-
242
- # Set Python 3.11 as default python3
243
- RUN update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.11 1
244
-
245
- # Install Python packages for data science and the code interpreter extension.
246
- # The interpreter runtime itself is provisioned by the @cloudflare/sandbox/interpreter
247
- # extension; this image only provides the Python toolchain it relies on.
248
- RUN --mount=type=cache,target=/root/.cache/pip \
249
- pip3 install --no-cache-dir matplotlib numpy pandas ipython
250
-
251
- # Pre-warm pool sizes consumed by the interpreter extension sidecar
252
- ENV PYTHON_POOL_MIN_SIZE=3
253
- ENV JAVASCRIPT_POOL_MIN_SIZE=3
254
- ENV TYPESCRIPT_POOL_MIN_SIZE=3
255
-
256
- ENTRYPOINT ["/usr/bin/tini", "--", "/container-server/sandbox"]
257
-
258
- # ============================================================================
259
- # Stage 5c: OpenCode image - with OpenCode CLI for AI coding agent
260
- # ============================================================================
261
- FROM runtime-base AS opencode
262
-
263
- RUN --mount=type=secret,id=wrangler_ca \
264
- if [ -f /run/secrets/wrangler_ca ] && [ -s /run/secrets/wrangler_ca ]; then \
265
- cp /run/secrets/wrangler_ca /usr/local/share/ca-certificates/wrangler-dev-ca.crt && \
266
- update-ca-certificates; \
267
- fi
268
-
269
- # Install OpenCode CLI via npm (avoids GitHub API rate limits)
270
- RUN npm i -g opencode-ai \
271
- && opencode --version
272
-
273
- # Disable Python pool (Python not available in this image)
274
- ENV PYTHON_POOL_MIN_SIZE=0
275
- ENV JAVASCRIPT_POOL_MIN_SIZE=3
276
- ENV TYPESCRIPT_POOL_MIN_SIZE=3
277
-
278
- # Expose OpenCode server port (in addition to 3000 from runtime-base)
279
- EXPOSE 4096
280
-
281
- ENTRYPOINT ["/usr/bin/tini", "--", "/container-server/sandbox"]
282
-
283
- # ============================================================================
284
- # Stage 5d: Musl image - Alpine-based with musl-linked binary
285
- # ============================================================================
286
- FROM alpine:3.21 AS musl
287
-
288
- ARG SANDBOX_VERSION=unknown
289
-
290
- ENV SANDBOX_VERSION=${SANDBOX_VERSION}
291
-
292
- # CA certificate installation
293
- RUN mkdir -p /usr/local/share/ca-certificates
294
- RUN --mount=type=secret,id=wrangler_ca \
295
- if [ -f /run/secrets/wrangler_ca ] && [ -s /run/secrets/wrangler_ca ]; then \
296
- cp /run/secrets/wrangler_ca /usr/local/share/ca-certificates/wrangler-dev-ca.crt && \
297
- cat /run/secrets/wrangler_ca >> /etc/ssl/certs/ca-certificates.crt && \
298
- apk add --no-cache ca-certificates && \
299
- update-ca-certificates; \
300
- else \
301
- apk add --no-cache ca-certificates; \
302
- fi
303
-
304
- RUN apk add --no-cache bash file git curl libstdc++ libgcc s3fs-fuse fuse tini
305
-
306
- RUN sed -i 's/#user_allow_other/user_allow_other/' /etc/fuse.conf
307
-
308
- # The Alpine variant uses the same cloudflared release asset as the glibc
309
- # variants. It is a static binary that runs on musl without gcompat.
310
- COPY --from=cloudflared-binary /cloudflared /usr/local/bin/cloudflared
311
- RUN cloudflared --version
312
-
313
- COPY --from=builder /app/packages/sandbox-container/dist/sandbox-musl /container-server/sandbox
314
-
315
- WORKDIR /container-server
316
-
317
- COPY --from=builder /app/packages/sandbox-container/dist/index.js ./dist/
318
-
319
- RUN mkdir -p /workspace
320
-
321
- EXPOSE 3000
322
-
323
- ENV PYTHON_POOL_MIN_SIZE=0
324
- ENV JAVASCRIPT_POOL_MIN_SIZE=0
325
- ENV TYPESCRIPT_POOL_MIN_SIZE=0
326
-
327
- ENTRYPOINT ["/sbin/tini", "--", "/container-server/sandbox"]
@@ -1,181 +0,0 @@
1
- import { DurableObject } from "cloudflare:workers";
2
-
3
- //#region src/bridge/types.d.ts
4
-
5
- /**
6
- * Configuration options for the bridge() factory.
7
- */
8
- interface BridgeConfig {
9
- /**
10
- * Override the default binding names used to look up Durable Objects.
11
- *
12
- * @default { sandbox: "Sandbox", warmPool: "WarmPool" }
13
- */
14
- bindings?: {
15
- /** Name of the Sandbox Durable Object binding. @default "Sandbox" */
16
- sandbox?: string;
17
- /** Name of the WarmPool Durable Object binding. @default "WarmPool" */
18
- warmPool?: string;
19
- };
20
- /**
21
- * URL prefix for all bridge API routes.
22
- *
23
- * @default "/v1"
24
- */
25
- apiRoutePrefix?: string;
26
- /**
27
- * Path for the health-check endpoint.
28
- *
29
- * @default "/health"
30
- */
31
- healthRoute?: string;
32
- }
33
- /**
34
- * The user-provided worker handlers that bridge() wraps.
35
- *
36
- * The bridge wraps `fetch` and `scheduled` with its own logic;
37
- * all other properties are passed through unchanged.
38
- */
39
- interface WorkerHandlers {
40
- fetch?(request: Request, env: any, ctx: ExecutionContext): Response | Promise<Response>;
41
- scheduled?(controller: ScheduledController, env: any, ctx: ExecutionContext): void | Promise<void>;
42
- [key: string]: unknown;
43
- }
44
- /**
45
- * Minimum environment shape required by the bridge.
46
- * The actual bindings are looked up dynamically by name.
47
- */
48
- interface BridgeEnv {
49
- SANDBOX_API_KEY?: string;
50
- WARM_POOL_TARGET?: string;
51
- WARM_POOL_REFRESH_INTERVAL?: string;
52
- [key: string]: unknown;
53
- }
54
- //#endregion
55
- //#region src/bridge/helpers.d.ts
56
- /**
57
- * Shell-quote a single argv token so it is safe to embed in a sh command
58
- * string. Tokens that contain only safe characters are returned unchanged
59
- * for readability. All others are wrapped in ANSI-C $'...' quoting which
60
- * can represent newlines, tabs, and other control characters as escape
61
- * sequences — unlike plain single quotes which pass content literally and
62
- * break when the value contains a real newline.
63
- */
64
- declare function shellQuote(arg: string): string;
65
- /**
66
- * POSIX-normalise a path (resolve `.` / `..` segments) and verify it lives
67
- * under /workspace. Returns the resolved absolute path on success, or null
68
- * if the path escapes the workspace.
69
- */
70
- declare function resolveWorkspacePath(userPath: string): string | null;
71
- //#endregion
72
- //#region src/bridge/warm-pool.d.ts
73
- interface WarmPoolConfig {
74
- /** Target number of warm (unassigned) containers to maintain. @default 0 */
75
- warmTarget?: number;
76
- /** How often to check and replenish warm containers (ms). @default 10000 */
77
- refreshInterval?: number;
78
- }
79
- interface PoolStats {
80
- /** Number of warm (unassigned) containers ready for use */
81
- warm: number;
82
- /** Number of containers assigned to sandbox IDs */
83
- assigned: number;
84
- /** Total containers tracked by the pool */
85
- total: number;
86
- /** Current pool configuration */
87
- config: Required<WarmPoolConfig>;
88
- /** Inferred max_instances limit, or null if not yet known */
89
- maxInstances: number | null;
90
- }
91
- /**
92
- * The WarmPool expects an environment with a `Sandbox` Durable Object binding.
93
- * This interface describes the minimum shape; the actual binding name is
94
- * configurable via the bridge, but defaults to "Sandbox".
95
- */
96
- interface WarmPoolEnv {
97
- Sandbox: DurableObjectNamespace;
98
- [key: string]: unknown;
99
- }
100
- declare class WarmPool extends DurableObject<WarmPoolEnv> {
101
- private config;
102
- /** Container UUIDs that are warm and available for assignment */
103
- private warmContainers;
104
- /** Maps caller-provided sandbox IDs to container UUIDs (1:1, no sharing) */
105
- private assignments;
106
- /** Containers currently starting — excluded from health checks */
107
- private startingContainers;
108
- /** Inferred max_instances limit learned from Cloudflare errors, or null */
109
- private knownMaxInstances;
110
- private capacityExhausted;
111
- private initialized;
112
- /**
113
- * Get a container UUID for the given sandbox ID.
114
- * - If this ID already has an assigned container that's still running, return it.
115
- * - Otherwise assign a warm container (or start a new one).
116
- */
117
- getContainer(sandboxId: string): Promise<string>;
118
- /**
119
- * Look up an existing container assignment without allocating.
120
- * Returns the container UUID if the sandbox ID has an active assignment, null otherwise.
121
- * Used by DELETE to avoid starting a container just to destroy it.
122
- */
123
- lookupContainer(sandboxId: string): Promise<string | null>;
124
- /**
125
- * Report that a container has stopped — removes it from tracking.
126
- */
127
- reportStopped(containerUUID: string): Promise<void>;
128
- /**
129
- * Get current pool statistics.
130
- */
131
- getStats(): Promise<PoolStats>;
132
- /**
133
- * Update pool configuration. Idempotent — called on every request to keep
134
- * config in sync with wrangler vars across deploys.
135
- */
136
- configure(config: WarmPoolConfig): Promise<void>;
137
- /**
138
- * Shutdown all pre-warmed (unassigned) containers.
139
- * Does not affect containers that are assigned to sandbox IDs.
140
- */
141
- shutdownPrewarmed(): Promise<void>;
142
- alarm(): Promise<void>;
143
- private init;
144
- private persist;
145
- private scheduleRefresh;
146
- private startContainer;
147
- private isContainerRunning;
148
- private checkContainerHealth;
149
- /**
150
- * Renew activity timeout on all warm containers to prevent them from sleeping.
151
- */
152
- private keepWarmContainersAlive;
153
- /**
154
- * Scale the warm pool towards warmTarget, respecting inferred max_instances.
155
- */
156
- private adjustPool;
157
- private removeContainer;
158
- private remainingCapacity;
159
- private isMaxInstancesError;
160
- private recordCapacityLimit;
161
- private throwCapacityError;
162
- private getSandboxStub;
163
- }
164
- //#endregion
165
- //#region src/bridge/index.d.ts
166
- /**
167
- * Create a Worker export that wraps user handlers with bridge functionality.
168
- *
169
- * The bridge:
170
- * 1. Checks that required Durable Object bindings exist (logs errors if missing).
171
- * 2. Wraps `fetch()` to serve bridge API routes first, then falls through to the user handler.
172
- * 3. Wraps `scheduled()` to prime the warm pool, then calls the user handler.
173
- * 4. Passes through all other properties unchanged.
174
- *
175
- * @param worker - The user's worker handlers (fetch, scheduled, and any others).
176
- * @param config - Optional configuration for binding names and route paths.
177
- */
178
- declare function bridge(worker: WorkerHandlers, config?: BridgeConfig): ExportedHandler<BridgeEnv>;
179
- //#endregion
180
- export { type BridgeConfig, type BridgeEnv, type PoolStats, WarmPool, type WarmPoolConfig, type WorkerHandlers, bridge, resolveWorkspacePath, shellQuote };
181
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/bridge/types.ts","../../src/bridge/helpers.ts","../../src/bridge/warm-pool.ts","../../src/bridge/index.ts"],"sourcesContent":[],"mappings":";;;;;;;AA6DgB,UAvCC,YAAA,CAuCD;EAEP;;;AAaT;;;;ICJgB,OAAA,CAAA,EAAU,MAAA;IAyBV;;;;AChFhB;AAOA;AAWC;AA6CD;EAA4C,cAAA,CAAA,EAAA,MAAA;EA2BH;;;;;EAiFf,WAAA,CAAA,EAAA,MAAA;;;;;;;;UFtIT,cAAA;EGgCD,KAAA,EAAA,OAAM,EH9BT,OG8BS,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EH5Bb,gBG4Ba,CAAA,EH3BjB,QG2BiB,GH3BN,OG2BM,CH3BE,QG2BF,CAAA;EACZ,SAAA,EAAA,UAAA,EH1BM,mBG0BN,EAAA,GAAA,EAAA,GAAA,EAAA,GAAA,EHxBD,gBGwBC,CAAA,EAAA,IAAA,GHvBE,OGuBF,CAAA,IAAA,CAAA;EACC,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;;;;;;UHZM,SAAA;;;;;;;;;;;AAAjB;;;;ACJA;AAyBgB,iBAzBA,UAAA,CAyBoB,GAAA,EAAA,MAAA,CAAA,EAAA,MAAA;;;;AChFpC;AAOA;AAmDU,iBDsBM,oBAAA,CCrBL,QAAsB,EAAA,MAAA,CAAA,EAAA,MAAA,GAAA,IAAA;;;AFbxB,UE9CQ,cAAA,CF8CR;EACG;EAAO,UAAA,CAAA,EAAA,MAAA;EAYF;;;UEpDA,SAAA;EDgDD;EAyBA,IAAA,EAAA,MAAA;;;;EChFC,KAAA,EAAA,MAAA;EAOA;EAmDP,MAAA,EA3CA,QA2CW,CA3CF,cA4CR,CAAA;EAIE;EAA+B,YAAA,EAAA,MAAA,GAAA,IAAA;;;;;;;UALlC,WAAA,CAiHiC;EAUd,OAAA,EA1HlB,sBA0HkB;EAyBZ,CAAA,GAAA,EAAA,MAAA,CAAA,EAAA,OAAA;;AA/I0B,cAA9B,QAAA,SAAiB,aAAa,CAAC,WAAD,CAAA,CAAA;;;;ECM3B;EACN,QAAA,WAAA;EACC;EACQ,QAAA,kBAAA;EAAhB;EAAe,QAAA,iBAAA;;;;;;;;mCDkBuB;;;;;;sCA6CG;;;;wCAYE;;;;cAS1B,QAAQ;;;;;oBAeF,iBAAiB;;;;;uBAUd;WAyBZ;;;;;;;;;;;;;;;;;;;;;;;;AAvMjB;AAWC;AA6CD;;;;;;;;;;AA+IiB,iBCzID,MAAA,CDyIC,MAAA,ECxIP,cDwIO,EAAA,MAAA,CAAA,ECvIN,YDuIM,CAAA,ECtId,eDsIc,CCtIE,SDsIF,CAAA"}