@cloudflare/sandbox 0.0.0-444d2da → 0.0.0-4aceb32
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 +94 -0
- package/Dockerfile +97 -11
- package/README.md +743 -24
- package/container_src/bun.lock +122 -0
- package/container_src/circuit-breaker.ts +121 -0
- package/container_src/handler/exec.ts +340 -0
- package/container_src/handler/file.ts +844 -0
- package/container_src/handler/git.ts +182 -0
- package/container_src/handler/ports.ts +314 -0
- package/container_src/handler/process.ts +640 -0
- package/container_src/index.ts +402 -2646
- package/container_src/jupyter-server.ts +579 -0
- package/container_src/jupyter-service.ts +448 -0
- package/container_src/mime-processor.ts +255 -0
- package/container_src/package.json +9 -0
- package/container_src/startup.sh +83 -0
- package/container_src/types.ts +108 -0
- package/package.json +6 -8
- package/src/client.ts +353 -1261
- package/src/errors.ts +218 -0
- package/src/index.ts +54 -129
- package/src/interpreter-types.ts +383 -0
- package/src/interpreter.ts +150 -0
- package/src/jupyter-client.ts +349 -0
- package/src/request-handler.ts +144 -0
- package/src/sandbox.ts +778 -0
- package/src/security.ts +113 -0
- package/src/sse-parser.ts +147 -0
- package/src/types.ts +401 -0
- package/tsconfig.json +1 -1
- package/tests/client.example.ts +0 -308
- package/tests/connection-test.ts +0 -81
- package/tests/simple-test.ts +0 -81
- package/tests/test1.ts +0 -281
- package/tests/test2.ts +0 -929
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Function to check if Jupyter is ready
|
|
4
|
+
check_jupyter_ready() {
|
|
5
|
+
curl -s http://localhost:8888/api > /dev/null 2>&1
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
# Function to notify Bun server that Jupyter is ready
|
|
9
|
+
notify_jupyter_ready() {
|
|
10
|
+
# Create a marker file that the Bun server can check
|
|
11
|
+
touch /tmp/jupyter-ready
|
|
12
|
+
echo "[Startup] Jupyter is ready, notified Bun server"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
# Start Jupyter notebook server in background
|
|
16
|
+
echo "[Startup] Starting Jupyter server..."
|
|
17
|
+
jupyter notebook \
|
|
18
|
+
--ip=0.0.0.0 \
|
|
19
|
+
--port=8888 \
|
|
20
|
+
--no-browser \
|
|
21
|
+
--allow-root \
|
|
22
|
+
--NotebookApp.token='' \
|
|
23
|
+
--NotebookApp.password='' \
|
|
24
|
+
--NotebookApp.allow_origin='*' \
|
|
25
|
+
--NotebookApp.disable_check_xsrf=True \
|
|
26
|
+
--NotebookApp.allow_remote_access=True \
|
|
27
|
+
--NotebookApp.allow_credentials=True \
|
|
28
|
+
> /tmp/jupyter.log 2>&1 &
|
|
29
|
+
|
|
30
|
+
JUPYTER_PID=$!
|
|
31
|
+
|
|
32
|
+
# Start Bun server immediately (parallel startup)
|
|
33
|
+
echo "[Startup] Starting Bun server..."
|
|
34
|
+
bun index.ts &
|
|
35
|
+
BUN_PID=$!
|
|
36
|
+
|
|
37
|
+
# Monitor Jupyter readiness in background
|
|
38
|
+
(
|
|
39
|
+
echo "[Startup] Monitoring Jupyter readiness in background..."
|
|
40
|
+
MAX_ATTEMPTS=30
|
|
41
|
+
ATTEMPT=0
|
|
42
|
+
DELAY=0.5
|
|
43
|
+
MAX_DELAY=5
|
|
44
|
+
|
|
45
|
+
while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
|
|
46
|
+
if check_jupyter_ready; then
|
|
47
|
+
notify_jupyter_ready
|
|
48
|
+
echo "[Startup] Jupyter server is ready after $ATTEMPT attempts"
|
|
49
|
+
break
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Check if Jupyter process is still running
|
|
53
|
+
if ! kill -0 $JUPYTER_PID 2>/dev/null; then
|
|
54
|
+
echo "[Startup] WARNING: Jupyter process died. Check /tmp/jupyter.log for details"
|
|
55
|
+
cat /tmp/jupyter.log
|
|
56
|
+
# Don't exit - let Bun server continue running in degraded mode
|
|
57
|
+
break
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
ATTEMPT=$((ATTEMPT + 1))
|
|
61
|
+
echo "[Startup] Jupyter not ready yet (attempt $ATTEMPT/$MAX_ATTEMPTS, delay ${DELAY}s)"
|
|
62
|
+
|
|
63
|
+
# Sleep with exponential backoff
|
|
64
|
+
sleep $DELAY
|
|
65
|
+
|
|
66
|
+
# Increase delay exponentially with jitter, cap at MAX_DELAY
|
|
67
|
+
DELAY=$(awk "BEGIN {printf \"%.2f\", $DELAY * 1.5 + (rand() * 0.5)}")
|
|
68
|
+
# Use awk for comparison since bc might not be available
|
|
69
|
+
if [ $(awk "BEGIN {print ($DELAY > $MAX_DELAY)}") -eq 1 ]; then
|
|
70
|
+
DELAY=$MAX_DELAY
|
|
71
|
+
fi
|
|
72
|
+
done
|
|
73
|
+
|
|
74
|
+
if [ $ATTEMPT -eq $MAX_ATTEMPTS ]; then
|
|
75
|
+
echo "[Startup] WARNING: Jupyter failed to become ready within attempts"
|
|
76
|
+
echo "[Startup] Jupyter logs:"
|
|
77
|
+
cat /tmp/jupyter.log
|
|
78
|
+
# Don't exit - let Bun server continue in degraded mode
|
|
79
|
+
fi
|
|
80
|
+
) &
|
|
81
|
+
|
|
82
|
+
# Wait for Bun server (main process)
|
|
83
|
+
wait $BUN_PID
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { ChildProcess } from "node:child_process";
|
|
2
|
+
|
|
3
|
+
// Process management types
|
|
4
|
+
export type ProcessStatus =
|
|
5
|
+
| 'starting'
|
|
6
|
+
| 'running'
|
|
7
|
+
| 'completed'
|
|
8
|
+
| 'failed'
|
|
9
|
+
| 'killed'
|
|
10
|
+
| 'error';
|
|
11
|
+
|
|
12
|
+
export interface ProcessRecord {
|
|
13
|
+
id: string;
|
|
14
|
+
pid?: number;
|
|
15
|
+
command: string;
|
|
16
|
+
status: ProcessStatus;
|
|
17
|
+
startTime: Date;
|
|
18
|
+
endTime?: Date;
|
|
19
|
+
exitCode?: number;
|
|
20
|
+
sessionId?: string;
|
|
21
|
+
childProcess?: ChildProcess;
|
|
22
|
+
stdout: string;
|
|
23
|
+
stderr: string;
|
|
24
|
+
outputListeners: Set<(stream: 'stdout' | 'stderr', data: string) => void>;
|
|
25
|
+
statusListeners: Set<(status: ProcessStatus) => void>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface StartProcessRequest {
|
|
29
|
+
command: string;
|
|
30
|
+
options?: {
|
|
31
|
+
processId?: string;
|
|
32
|
+
sessionId?: string;
|
|
33
|
+
timeout?: number;
|
|
34
|
+
env?: Record<string, string>;
|
|
35
|
+
cwd?: string;
|
|
36
|
+
encoding?: string;
|
|
37
|
+
autoCleanup?: boolean;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ExecuteOptions {
|
|
42
|
+
sessionId?: string | null;
|
|
43
|
+
background?: boolean;
|
|
44
|
+
cwd?: string | URL;
|
|
45
|
+
env?: Record<string, string>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface ExecuteRequest extends ExecuteOptions {
|
|
49
|
+
command: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface GitCheckoutRequest {
|
|
53
|
+
repoUrl: string;
|
|
54
|
+
branch?: string;
|
|
55
|
+
targetDir?: string;
|
|
56
|
+
sessionId?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface MkdirRequest {
|
|
60
|
+
path: string;
|
|
61
|
+
recursive?: boolean;
|
|
62
|
+
sessionId?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface WriteFileRequest {
|
|
66
|
+
path: string;
|
|
67
|
+
content: string;
|
|
68
|
+
encoding?: string;
|
|
69
|
+
sessionId?: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface ReadFileRequest {
|
|
73
|
+
path: string;
|
|
74
|
+
encoding?: string;
|
|
75
|
+
sessionId?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface DeleteFileRequest {
|
|
79
|
+
path: string;
|
|
80
|
+
sessionId?: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface RenameFileRequest {
|
|
84
|
+
oldPath: string;
|
|
85
|
+
newPath: string;
|
|
86
|
+
sessionId?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface MoveFileRequest {
|
|
90
|
+
sourcePath: string;
|
|
91
|
+
destinationPath: string;
|
|
92
|
+
sessionId?: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface ExposePortRequest {
|
|
96
|
+
port: number;
|
|
97
|
+
name?: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface UnexposePortRequest {
|
|
101
|
+
port: number;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface SessionData {
|
|
105
|
+
sessionId: string;
|
|
106
|
+
activeProcess: ChildProcess | null;
|
|
107
|
+
createdAt: Date;
|
|
108
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudflare/sandbox",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-4aceb32",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/cloudflare/sandbox-sdk"
|
|
7
7
|
},
|
|
8
8
|
"description": "A sandboxed environment for running commands",
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@cloudflare/containers": "^0.0.
|
|
10
|
+
"@cloudflare/containers": "^0.0.25"
|
|
11
11
|
},
|
|
12
12
|
"tags": [
|
|
13
13
|
"sandbox",
|
|
@@ -17,18 +17,16 @@
|
|
|
17
17
|
"durable objects"
|
|
18
18
|
],
|
|
19
19
|
"scripts": {
|
|
20
|
-
"build": "rm -rf dist && tsup src/*.ts --outDir dist --dts --sourcemap --format esm"
|
|
20
|
+
"build": "rm -rf dist && tsup src/*.ts --outDir dist --dts --sourcemap --format esm",
|
|
21
|
+
"docker:local": "docker build . -t cloudflare/sandbox-test:$npm_package_version",
|
|
22
|
+
"docker:publish": "docker buildx build --platform linux/amd64,linux/arm64 -t cloudflare/sandbox:$npm_package_version --push .",
|
|
23
|
+
"docker:publish:beta": "docker buildx build --platform linux/amd64,linux/arm64 -t cloudflare/sandbox:$npm_package_version-beta --push ."
|
|
21
24
|
},
|
|
22
25
|
"exports": {
|
|
23
26
|
".": {
|
|
24
27
|
"types": "./dist/index.d.ts",
|
|
25
28
|
"import": "./dist/index.js",
|
|
26
29
|
"require": "./dist/index.js"
|
|
27
|
-
},
|
|
28
|
-
"./client": {
|
|
29
|
-
"types": "./dist/client.d.ts",
|
|
30
|
-
"import": "./dist/client.js",
|
|
31
|
-
"require": "./dist/client.js"
|
|
32
30
|
}
|
|
33
31
|
},
|
|
34
32
|
"keywords": [],
|