Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/ten-areas-doubt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cloudflare/sandbox": patch
---

Make package ready for deployment
9 changes: 9 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,12 @@ jobs:
GITHUB_TOKEN: ${{ secrets.SANDBOX_GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
NPM_PUBLISH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}

- name: Build and push Docker image
if: steps.changesets.outputs.published == 'true'
run: |
cd packages/sandbox
npm run docker:build
npm run docker:publish
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,23 @@

> **⚠️ Experimental** - This library is currently experimental and we're actively seeking feedback. Please try it out and let us know what you think!

A library to spin up a sandboxed environment.
A library to spin up a sandboxed environment. **If you'd like to try one of our pre-made examples, take a look at [examples/basic](./examples/basic) ready to deploy to your Cloudflare account!**

First, create a Dockerfile at the root of your project, with the following content:

```Dockerfile
# If building your project on amd64, use:
FROM docker.io/ghostwriternr/cloudflare-sandbox:0.0.4
# If building your project on arm64, use:
# FROM docker.io/ghostwriternr/cloudflare-sandbox-arm:0.0.4

EXPOSE 3000

# Run the same command as the original image
CMD ["bun", "index.ts"]
```

> **NOTE**: In an upcoming release, this step will be removed entirely and you can reference a single Docker image published by us directly in your wrangler configuration below.

First, setup your wrangler.json to use the sandbox:

Expand All @@ -12,7 +28,7 @@ First, setup your wrangler.json to use the sandbox:
"containers": [
{
"class_name": "Sandbox",
"image": "./node_modules/@cloudflare/sandbox/Dockerfile",
"image": "./Dockerfile",
"name": "sandbox"
}
],
Expand Down
8 changes: 8 additions & 0 deletions examples/basic/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# syntax=docker/dockerfile:1

FROM docker.io/ghostwriternr/cloudflare-sandbox:0.0.4

EXPOSE 3000

# Run the same command as the original image
CMD ["bun", "index.ts"]
3 changes: 2 additions & 1 deletion examples/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"private": true,
"description": "An example of using the sandbox package",
"scripts": {
"start": "wrangler dev"
"start": "wrangler dev",
"deploy": "wrangler deploy"
},
"author": "",
"license": "MIT"
Expand Down
2 changes: 1 addition & 1 deletion examples/basic/wrangler.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"containers": [
{
"class_name": "Sandbox",
"image": "../../node_modules/@cloudflare/sandbox/Dockerfile",
"image": "./Dockerfile",
"name": "sandbox",
"max_instances": 1
}
Expand Down
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"tsup": "^8.5.0",
"tsx": "^4.20.3",
"typescript": "^5.8.3",
"wrangler": "^4.21.0"
"wrangler": "^4.21.2"
},
"private": true,
"packageManager": "npm@11.4.2"
Expand Down
10 changes: 8 additions & 2 deletions packages/sandbox/container_src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ const server = serve({
const url = new URL(req.url);
const pathname = url.pathname;

console.log(`[Container] Incoming ${req.method} request to ${pathname}`);

// Handle CORS
const corsHeaders = {
"Access-Control-Allow-Headers": "Content-Type, Authorization",
Expand All @@ -93,11 +95,13 @@ const server = serve({

// Handle preflight requests
if (req.method === "OPTIONS") {
console.log(`[Container] Handling CORS preflight for ${pathname}`);
return new Response(null, { headers: corsHeaders, status: 200 });
}

try {
// Handle different routes
console.log(`[Container] Processing ${req.method} ${pathname}`);
switch (pathname) {
case "/":
return new Response("Hello from Bun server! 🚀", {
Expand Down Expand Up @@ -352,13 +356,14 @@ const server = serve({
break;

default:
console.log(`[Container] Route not found: ${pathname}`);
return new Response("Not Found", {
headers: corsHeaders,
status: 404,
});
}
} catch (error) {
console.error("[Server] Error handling request:", error);
console.error(`[Container] Error handling ${req.method} ${pathname}:`, error);
return new Response(
JSON.stringify({
error: "Internal server error",
Expand All @@ -374,6 +379,7 @@ const server = serve({
);
}
},
hostname: "0.0.0.0",
port: 3000,
} as any);

Expand Down Expand Up @@ -2874,7 +2880,7 @@ function executeMoveFile(
});
}

console.log(`🚀 Bun server running on http://localhost:${server.port}`);
console.log(`🚀 Bun server running on http://0.0.0.0:${server.port}`);
console.log(`📡 HTTP API endpoints available:`);
console.log(` POST /api/session/create - Create a new session`);
console.log(` GET /api/session/list - List all sessions`);
Expand Down
4 changes: 3 additions & 1 deletion packages/sandbox/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
"durable objects"
],
"scripts": {
"build": "rm -rf dist && tsup src/*.ts --outDir dist --dts --sourcemap --format esm"
"build": "rm -rf dist && tsup src/*.ts --outDir dist --dts --sourcemap --format esm",
"docker:build": "docker build -t ghostwriternr/cloudflare-sandbox:$npm_package_version .",
"docker:publish": "docker push docker.io/ghostwriternr/cloudflare-sandbox:$npm_package_version"
},
"exports": {
".": {
Expand Down
27 changes: 24 additions & 3 deletions packages/sandbox/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,10 +203,31 @@ export class HttpClient {
path: string,
options?: RequestInit
): Promise<Response> {
if (this.options.stub) {
return this.options.stub.containerFetch(path, options, this.options.port);
const url = this.options.stub ? `stub:${path}` : `${this.baseUrl}${path}`;
const method = options?.method || "GET";

console.log(`[HTTP Client] Making ${method} request to ${url}`);

try {
let response: Response;

if (this.options.stub) {
response = await this.options.stub.containerFetch(path, options, this.options.port);
} else {
response = await fetch(this.baseUrl + path, options);
}

console.log(`[HTTP Client] Response: ${response.status} ${response.statusText}`);

if (!response.ok) {
console.error(`[HTTP Client] Request failed: ${method} ${url} - ${response.status} ${response.statusText}`);
}

return response;
} catch (error) {
console.error(`[HTTP Client] Request error: ${method} ${url}`, error);
throw error;
}
return fetch(this.baseUrl + path, options);
}
// Public methods to set event handlers
setOnOutput(
Expand Down