@cloudflare/sandbox 0.13.0-next.649.1 → 0.13.0-next.681.1
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 +6 -11
- package/README.md +2 -2
- package/dist/bridge/index.d.ts.map +1 -1
- package/dist/bridge/index.js +68 -49
- package/dist/bridge/index.js.map +1 -1
- package/dist/codes-y-U76vnQ.d.ts +79 -0
- package/dist/codes-y-U76vnQ.d.ts.map +1 -0
- package/dist/contexts-DY1LHU1v.d.ts +327 -0
- package/dist/contexts-DY1LHU1v.d.ts.map +1 -0
- package/dist/{dist-mAH_7Ui7.js → dist-BStBkGIC.js} +50 -93
- package/dist/dist-BStBkGIC.js.map +1 -0
- package/dist/errors/index.d.ts +4 -0
- package/dist/errors/index.js +4 -0
- package/dist/errors-ewgSNicb.js +741 -0
- package/dist/errors-ewgSNicb.js.map +1 -0
- package/dist/{errors-CpoDEfUZ.js → errors-k3B8orjH.js} +41 -4
- package/dist/errors-k3B8orjH.js.map +1 -0
- package/dist/extensions/index.d.ts +2 -0
- package/dist/extensions/index.js +4 -0
- package/dist/extensions-CepYdzro.js +191 -0
- package/dist/extensions-CepYdzro.js.map +1 -0
- package/dist/git/index.d.ts +74 -0
- package/dist/git/index.d.ts.map +1 -0
- package/dist/git/index.js +345 -0
- package/dist/git/index.js.map +1 -0
- package/dist/index-B7QgIs0N.d.ts +1841 -0
- package/dist/index-B7QgIs0N.d.ts.map +1 -0
- package/dist/index-Dy6u9r60.d.ts +390 -0
- package/dist/index-Dy6u9r60.d.ts.map +1 -0
- package/dist/index.d.ts +27 -189
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -43
- package/dist/index.js.map +1 -1
- package/dist/interpreter/index.d.ts +309 -0
- package/dist/interpreter/index.d.ts.map +1 -0
- package/dist/interpreter/index.js +264 -0
- package/dist/interpreter/index.js.map +1 -0
- package/dist/openai/index.d.ts +3 -2
- package/dist/openai/index.d.ts.map +1 -1
- package/dist/openai/index.js +2 -2
- package/dist/openai/index.js.map +1 -1
- package/dist/opencode/index.d.ts +137 -160
- package/dist/opencode/index.d.ts.map +1 -1
- package/dist/opencode/index.js +269 -159
- package/dist/opencode/index.js.map +1 -1
- package/dist/sandbox-DHNO89IF.d.ts +828 -0
- package/dist/sandbox-DHNO89IF.d.ts.map +1 -0
- package/dist/{sandbox-B-FLGbkP.js → sandbox-boKWPIcd.js} +8214 -7267
- package/dist/sandbox-boKWPIcd.js.map +1 -0
- package/dist/sidecar/index.d.ts +77 -0
- package/dist/sidecar/index.d.ts.map +1 -0
- package/dist/sidecar/index.js +201 -0
- package/dist/sidecar/index.js.map +1 -0
- package/dist/xterm/index.d.ts +6 -6
- package/dist/xterm/index.d.ts.map +1 -1
- package/dist/xterm/index.js +6 -6
- package/dist/xterm/index.js.map +1 -1
- package/package.json +36 -3
- package/dist/contexts-DPFhc2nR.d.ts +0 -238
- package/dist/contexts-DPFhc2nR.d.ts.map +0 -1
- package/dist/dist-mAH_7Ui7.js.map +0 -1
- package/dist/errors-CpoDEfUZ.js.map +0 -1
- package/dist/sandbox-44kEJjAc.d.ts +0 -2652
- package/dist/sandbox-44kEJjAc.d.ts.map +0 -1
- package/dist/sandbox-B-FLGbkP.js.map +0 -1
package/Dockerfile
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Bun version — override via --build-arg BUN_VERSION=$(cat .bun-version)
|
|
2
|
-
ARG BUN_VERSION=1
|
|
2
|
+
ARG BUN_VERSION=1.3.14
|
|
3
3
|
# Node version — override via --build-arg NODE_VERSION=24
|
|
4
4
|
ARG NODE_VERSION=24
|
|
5
5
|
# cloudflared release — shared across glibc and musl image variants.
|
|
@@ -186,12 +186,9 @@ COPY --from=bun-binary /usr/local/bin/bun /usr/local/bin/bun
|
|
|
186
186
|
# Copy standalone binary
|
|
187
187
|
COPY --from=builder /app/packages/sandbox-container/dist/sandbox /container-server/sandbox
|
|
188
188
|
|
|
189
|
-
# Set up container server directory
|
|
189
|
+
# Set up container server directory
|
|
190
190
|
WORKDIR /container-server
|
|
191
191
|
|
|
192
|
-
# Copy bundled JavaScript executor (runs on Node or Bun for code interpreter)
|
|
193
|
-
COPY --from=builder /app/packages/sandbox-container/dist/runtime/executors/javascript/node_executor.js ./dist/runtime/executors/javascript/
|
|
194
|
-
|
|
195
192
|
# Copy legacy JS bundle for backwards compatibility
|
|
196
193
|
# Users with custom startup scripts that call `bun /container-server/dist/index.js` need this
|
|
197
194
|
COPY --from=builder /app/packages/sandbox-container/dist/index.js ./dist/
|
|
@@ -245,14 +242,13 @@ RUN ln -s /usr/local/python/bin/python3.11 /usr/local/bin/python3.11 && \
|
|
|
245
242
|
# Set Python 3.11 as default python3
|
|
246
243
|
RUN update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.11 1
|
|
247
244
|
|
|
248
|
-
# Install Python packages for data science and code interpreter
|
|
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.
|
|
249
248
|
RUN --mount=type=cache,target=/root/.cache/pip \
|
|
250
249
|
pip3 install --no-cache-dir matplotlib numpy pandas ipython
|
|
251
250
|
|
|
252
|
-
#
|
|
253
|
-
COPY --from=builder /app/packages/sandbox-container/src/runtime/executors/python/ipython_executor.py ./dist/runtime/executors/python/
|
|
254
|
-
|
|
255
|
-
# Enable all interpreter pools
|
|
251
|
+
# Pre-warm pool sizes consumed by the interpreter extension sidecar
|
|
256
252
|
ENV PYTHON_POOL_MIN_SIZE=3
|
|
257
253
|
ENV JAVASCRIPT_POOL_MIN_SIZE=3
|
|
258
254
|
ENV TYPESCRIPT_POOL_MIN_SIZE=3
|
|
@@ -318,7 +314,6 @@ COPY --from=builder /app/packages/sandbox-container/dist/sandbox-musl /container
|
|
|
318
314
|
|
|
319
315
|
WORKDIR /container-server
|
|
320
316
|
|
|
321
|
-
COPY --from=builder /app/packages/sandbox-container/dist/runtime/executors/javascript/node_executor.js ./dist/runtime/executors/javascript/
|
|
322
317
|
COPY --from=builder /app/packages/sandbox-container/dist/index.js ./dist/
|
|
323
318
|
|
|
324
319
|
RUN mkdir -p /workspace
|
package/README.md
CHANGED
|
@@ -82,7 +82,7 @@ export default {
|
|
|
82
82
|
|
|
83
83
|
// Execute Python code
|
|
84
84
|
if (url.pathname === '/run') {
|
|
85
|
-
const result = await sandbox.exec('python3 -c "print(2 + 2)"');
|
|
85
|
+
const result = await sandbox.exec('python3 -c "print(2 + 2)"').output();
|
|
86
86
|
return Response.json({ output: result.stdout, success: result.success });
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -154,7 +154,7 @@ Notes:
|
|
|
154
154
|
- **Edge-Native** - Runs on Cloudflare's global network
|
|
155
155
|
- **Code Interpreter** - Execute Python and JavaScript with rich outputs
|
|
156
156
|
- **File System Access** - Read, write, and manage files
|
|
157
|
-
- **Command Execution** - Run
|
|
157
|
+
- **Command Execution** - Run commands with a Containers-style process handle, streaming output, stdin, and background process control
|
|
158
158
|
- **Preview URLs** - Expose services with public URLs
|
|
159
159
|
- **Quick tunnels** - Zero-config `*.trycloudflare.com` URLs via `sandbox.tunnels.get(port)`
|
|
160
160
|
- **Git Integration** - Clone repositories directly
|
|
@@ -1 +1 @@
|
|
|
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;;;;AC7EhB;AAOA;AAWC;AA6CD;EAA4C,cAAA,CAAA,EAAA,MAAA;EA2BH;;;;;EAiFf,WAAA,CAAA,EAAA,MAAA;;;;;;;;UFzIT,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;;;;AC7EpC;AAOA;AAmDU,iBDmBM,oBAAA,CClBL,
|
|
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;;;;AC7EhB;AAOA;AAWC;AA6CD;EAA4C,cAAA,CAAA,EAAA,MAAA;EA2BH;;;;;EAiFf,WAAA,CAAA,EAAA,MAAA;;;;;;;;UFzIT,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;;;;AC7EpC;AAOA;AAmDU,iBDmBM,oBAAA,CClBL,QAAA,EAAsB,MAAA,CAAA,EAAA,MAAA,GAAA,IAAA;;;AFHhB,UExDA,cAAA,CFwDS;;;;ECJV,eAAU,CAAA,EAAA,MAAA;AAyB1B;UCtEiB,SAAA;;;EAPA;EAOA,QAAA,EAAA,MAAS;EAmDhB;EAKG,KAAA,EAAA,MAAS;EAAsB;EA2BH,MAAA,EA3E/B,QA2E+B,CA3EtB,cA2EsB,CAAA;EA6CG;EAYE,YAAA,EAAA,MAAA,GAAA,IAAA;;;;;;;UAzFpC,WAAA,CAKoB;EAAa,OAAA,EAJhC,sBAIgC;;;cAA9B,QAAA,SAAiB,cAAc;ECG5B,QAAA,MAAM;EACZ;EACC,QAAA,cAAA;EACQ;EAAhB,QAAA,WAAA;EAAe;;;;;;;;;;;mCDqBuB;;;;;;sCA6CG;;;;wCAYE;;;;cAS1B,QAAQ;;;;;oBAeF,iBAAiB;;;;;uBAUd;WAyBZ;;;;;;;;;;;;;;;;;;;;;;;;AAvMjB;AAWC;AA6CD;;;;;;;;;;AA+IiB,iBC5ID,MAAA,CD4IC,MAAA,EC3IP,cD2IO,EAAA,MAAA,CAAA,EC1IN,YD0IM,CAAA,ECzId,eDyIc,CCzIE,SDyIF,CAAA"}
|
package/dist/bridge/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import "../dist-
|
|
2
|
-
import "../errors-
|
|
3
|
-
import
|
|
1
|
+
import "../dist-BStBkGIC.js";
|
|
2
|
+
import "../errors-k3B8orjH.js";
|
|
3
|
+
import "../errors-ewgSNicb.js";
|
|
4
|
+
import { S as streamFile, g as validateTunnelName, h as validatePort, m as SandboxSecurityError, n as getSandbox } from "../sandbox-boKWPIcd.js";
|
|
5
|
+
import "../extensions-CepYdzro.js";
|
|
4
6
|
import { DurableObject, env } from "cloudflare:workers";
|
|
5
7
|
import { Hono } from "hono";
|
|
6
8
|
|
|
@@ -454,7 +456,7 @@ const OPENAPI_SCHEMA = {
|
|
|
454
456
|
type: "string",
|
|
455
457
|
pattern: "^[a-zA-Z0-9._-]{1,128}$"
|
|
456
458
|
},
|
|
457
|
-
description: "Scope this operation to
|
|
459
|
+
description: "Scope this operation to an explicit session. If omitted, the operation uses top-level sandbox behavior."
|
|
458
460
|
}],
|
|
459
461
|
requestBody: {
|
|
460
462
|
required: true,
|
|
@@ -618,7 +620,7 @@ const OPENAPI_SCHEMA = {
|
|
|
618
620
|
type: "string",
|
|
619
621
|
pattern: "^[a-zA-Z0-9._-]{1,128}$"
|
|
620
622
|
},
|
|
621
|
-
description: "Scope this operation to
|
|
623
|
+
description: "Scope this operation to an explicit session. If omitted, the operation uses top-level sandbox behavior."
|
|
622
624
|
}
|
|
623
625
|
],
|
|
624
626
|
responses: {
|
|
@@ -694,7 +696,7 @@ const OPENAPI_SCHEMA = {
|
|
|
694
696
|
type: "string",
|
|
695
697
|
pattern: "^[a-zA-Z0-9._-]{1,128}$"
|
|
696
698
|
},
|
|
697
|
-
description: "Scope this operation to
|
|
699
|
+
description: "Scope this operation to an explicit session. If omitted, the operation uses top-level sandbox behavior."
|
|
698
700
|
}
|
|
699
701
|
],
|
|
700
702
|
requestBody: {
|
|
@@ -737,12 +739,12 @@ const OPENAPI_SCHEMA = {
|
|
|
737
739
|
},
|
|
738
740
|
"/v1/sandbox/{id}/pty": { get: {
|
|
739
741
|
operationId: "ptyTerminal",
|
|
740
|
-
summary: "Open a
|
|
741
|
-
description: "Upgrades the HTTP connection to a WebSocket and proxies it to a PTY shell inside the sandbox.\n\n**WebSocket frame protocol:**\n\n| Direction | Frame type | Content |\n|-----------|------------|--------------------------------------------------|\n| Client → Server | Binary | UTF-8 encoded keystrokes / input |\n| Server → Client | Binary | Terminal output (including ANSI escape sequences) |\n| Client → Server | Text (JSON) | Control messages, e.g. `{\"type\":\"resize\",\"cols\":120,\"rows\":30}` |\n| Server → Client | Text (JSON) | Status messages: `ready`, `exit`, `error` |\n\n**Status messages (server → client):**\n- `{\"type\":\"ready\"}` — PTY is accepting input\n- `{\"type\":\"exit\",\"code\":0,\"signal\":\"SIGTERM\"}` — PTY exited\n- `{\"type\":\"error\",\"message\":\"...\"}` — error occurred\n\nIf the client disconnects, the
|
|
742
|
+
summary: "Open a terminal via WebSocket",
|
|
743
|
+
description: "Upgrades the HTTP connection to a WebSocket and proxies it to a PTY shell inside the sandbox.\n\n**A terminal ID is required**, supplied via either the `terminalId` query parameter or the `Terminal-Id` header (header takes precedence). The terminal ID is a stable resource name: reconnecting with the same ID reattaches to the same live PTY while the sandbox container is alive. If the sandbox container restarts (for example after it sleeps), connecting with the same ID creates a fresh shell — prior PTY state and process history are not preserved.\n\n**WebSocket frame protocol:**\n\n| Direction | Frame type | Content |\n|-----------|------------|--------------------------------------------------|\n| Client → Server | Binary | UTF-8 encoded keystrokes / input |\n| Server → Client | Binary | Terminal output (including ANSI escape sequences) |\n| Client → Server | Text (JSON) | Control messages, e.g. `{\"type\":\"resize\",\"cols\":120,\"rows\":30}` |\n| Server → Client | Text (JSON) | Status messages: `ready`, `exit`, `error` |\n\n**Status messages (server → client):**\n- `{\"type\":\"ready\"}` — PTY is accepting input\n- `{\"type\":\"exit\",\"code\":0,\"signal\":\"SIGTERM\"}` — PTY exited\n- `{\"type\":\"error\",\"message\":\"...\"}` — error occurred\n\nIf the client disconnects, the terminal stays alive while the sandbox container is alive; reconnect with the same terminal ID to reattach.",
|
|
742
744
|
"x-codeSamples": [{
|
|
743
745
|
lang: "JavaScript",
|
|
744
746
|
label: "WebSocket",
|
|
745
|
-
source: "const ws = new WebSocket(\"wss://$HOST/v1/sandbox/my-sandbox/pty?cols=120&rows=30\");\nws.binaryType = \"arraybuffer\";\nws.onmessage = (e) => { /* handle binary output or JSON status */ };"
|
|
747
|
+
source: "const ws = new WebSocket(\"wss://$HOST/v1/sandbox/my-sandbox/pty?terminalId=term-1&cols=120&rows=30\");\nws.binaryType = \"arraybuffer\";\nws.onmessage = (e) => { /* handle binary output or JSON status */ };"
|
|
746
748
|
}],
|
|
747
749
|
parameters: [
|
|
748
750
|
{
|
|
@@ -780,21 +782,31 @@ const OPENAPI_SCHEMA = {
|
|
|
780
782
|
description: "Shell binary to run (e.g. `/bin/bash`). Uses the container default if omitted."
|
|
781
783
|
},
|
|
782
784
|
{
|
|
783
|
-
name: "
|
|
785
|
+
name: "cwd",
|
|
784
786
|
in: "query",
|
|
785
787
|
required: false,
|
|
786
788
|
schema: { type: "string" },
|
|
787
|
-
description: "
|
|
789
|
+
description: "Initial working directory for newly created terminal resources."
|
|
788
790
|
},
|
|
789
791
|
{
|
|
790
|
-
name: "
|
|
792
|
+
name: "terminalId",
|
|
793
|
+
in: "query",
|
|
794
|
+
required: false,
|
|
795
|
+
schema: {
|
|
796
|
+
type: "string",
|
|
797
|
+
pattern: "^[a-zA-Z0-9._-]{1,128}$"
|
|
798
|
+
},
|
|
799
|
+
description: "Terminal resource ID. Required unless the `Terminal-Id` request header is supplied. Stable name for this terminal resource: reuse the same ID across reconnects to reattach to the same live PTY. After the sandbox container restarts, the same ID creates a new shell. Ignored when `Terminal-Id` header is also present (header takes precedence)."
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
name: "Terminal-Id",
|
|
791
803
|
in: "header",
|
|
792
804
|
required: false,
|
|
793
805
|
schema: {
|
|
794
806
|
type: "string",
|
|
795
807
|
pattern: "^[a-zA-Z0-9._-]{1,128}$"
|
|
796
808
|
},
|
|
797
|
-
description: "
|
|
809
|
+
description: "Terminal resource ID. Required unless the `terminalId` query parameter is supplied. Takes precedence over the `terminalId` query parameter when both are present. Same stable-ID semantics apply: same ID reattaches to the live PTY; after the sandbox container restarts a new shell is created."
|
|
798
810
|
}
|
|
799
811
|
],
|
|
800
812
|
responses: {
|
|
@@ -1045,7 +1057,7 @@ const OPENAPI_SCHEMA = {
|
|
|
1045
1057
|
"/v1/sandbox/{id}/session": { post: {
|
|
1046
1058
|
operationId: "createSession",
|
|
1047
1059
|
summary: "Create an execution session",
|
|
1048
|
-
description: "Sessions isolate working directory and environment variables across commands. The returned session ID is used with the `Session-Id` header on exec
|
|
1060
|
+
description: "Sessions isolate working directory and environment variables across commands. The returned session ID is used with the `Session-Id` header on exec and file endpoints.",
|
|
1049
1061
|
parameters: [{
|
|
1050
1062
|
name: "id",
|
|
1051
1063
|
in: "path",
|
|
@@ -1102,7 +1114,7 @@ const OPENAPI_SCHEMA = {
|
|
|
1102
1114
|
"/v1/sandbox/{id}/session/{sid}": { delete: {
|
|
1103
1115
|
operationId: "deleteSession",
|
|
1104
1116
|
summary: "Delete an execution session",
|
|
1105
|
-
description: "Removes
|
|
1117
|
+
description: "Removes an explicit execution session.",
|
|
1106
1118
|
parameters: [{
|
|
1107
1119
|
name: "id",
|
|
1108
1120
|
in: "path",
|
|
@@ -1136,11 +1148,11 @@ const OPENAPI_SCHEMA = {
|
|
|
1136
1148
|
},
|
|
1137
1149
|
"401": { $ref: "#/components/responses/Unauthorized" },
|
|
1138
1150
|
"502": {
|
|
1139
|
-
description: "Session deletion failed
|
|
1151
|
+
description: "Session deletion failed.",
|
|
1140
1152
|
content: { "application/json": {
|
|
1141
1153
|
schema: { $ref: "#/components/schemas/ErrorResponse" },
|
|
1142
1154
|
example: {
|
|
1143
|
-
error: "
|
|
1155
|
+
error: "session deletion failed",
|
|
1144
1156
|
code: "session_error"
|
|
1145
1157
|
}
|
|
1146
1158
|
} }
|
|
@@ -1942,31 +1954,36 @@ function createBridgeApp(config) {
|
|
|
1942
1954
|
closed = true;
|
|
1943
1955
|
lastWrite.then(() => writer.close()).catch(() => {});
|
|
1944
1956
|
}
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1957
|
+
(async () => {
|
|
1958
|
+
try {
|
|
1959
|
+
const proc = await executor.exec(command, opts);
|
|
1960
|
+
const decoder = new TextDecoder();
|
|
1961
|
+
const pump = async (stream, name) => {
|
|
1962
|
+
if (!stream) return;
|
|
1963
|
+
const reader = stream.getReader();
|
|
1964
|
+
try {
|
|
1965
|
+
for (;;) {
|
|
1966
|
+
const { value, done } = await reader.read();
|
|
1967
|
+
if (done) break;
|
|
1968
|
+
if (value && value.byteLength > 0) writeSSE(name, toBase64(decoder.decode(value)));
|
|
1969
|
+
}
|
|
1970
|
+
} finally {
|
|
1971
|
+
reader.releaseLock();
|
|
1972
|
+
}
|
|
1973
|
+
};
|
|
1974
|
+
await Promise.all([pump(proc.stdout, "stdout"), pump(proc.stderr, "stderr")]);
|
|
1975
|
+
const exitCode = await proc.exitCode;
|
|
1976
|
+
writeSSE("exit", JSON.stringify({ exit_code: exitCode }));
|
|
1977
|
+
} catch (err) {
|
|
1978
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1956
1979
|
writeSSE("error", JSON.stringify({
|
|
1957
|
-
error:
|
|
1958
|
-
code: "
|
|
1980
|
+
error: `exec failed: ${msg}`,
|
|
1981
|
+
code: "exec_transport_error"
|
|
1959
1982
|
}));
|
|
1983
|
+
} finally {
|
|
1960
1984
|
closeStream();
|
|
1961
1985
|
}
|
|
1962
|
-
})
|
|
1963
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1964
|
-
writeSSE("error", JSON.stringify({
|
|
1965
|
-
error: `exec failed: ${msg}`,
|
|
1966
|
-
code: "exec_transport_error"
|
|
1967
|
-
}));
|
|
1968
|
-
closeStream();
|
|
1969
|
-
});
|
|
1986
|
+
})();
|
|
1970
1987
|
return new Response(readable, {
|
|
1971
1988
|
status: 200,
|
|
1972
1989
|
headers: {
|
|
@@ -2072,22 +2089,24 @@ function createBridgeApp(config) {
|
|
|
2072
2089
|
const colsParam = c.req.query("cols");
|
|
2073
2090
|
const rowsParam = c.req.query("rows");
|
|
2074
2091
|
const shell = c.req.query("shell");
|
|
2075
|
-
const
|
|
2092
|
+
const cwd = c.req.query("cwd");
|
|
2093
|
+
const terminalId = c.req.header("Terminal-Id") ?? c.req.query("terminalId") ?? c.req.query("terminal");
|
|
2076
2094
|
const cols = colsParam ? Number(colsParam) : 80;
|
|
2077
2095
|
const rows = rowsParam ? Number(rowsParam) : 24;
|
|
2078
2096
|
if (Number.isNaN(cols) || Number.isNaN(rows)) return errorJson("cols and rows must be valid numbers", "invalid_request", 400);
|
|
2079
|
-
const
|
|
2097
|
+
const terminalOptions = {};
|
|
2098
|
+
const connectOptions = {
|
|
2080
2099
|
cols,
|
|
2081
2100
|
rows
|
|
2082
2101
|
};
|
|
2083
|
-
if (shell)
|
|
2102
|
+
if (shell) terminalOptions.shell = shell;
|
|
2103
|
+
if (cwd) terminalOptions.cwd = cwd;
|
|
2104
|
+
if (!terminalId) return errorJson("terminalId query parameter or Terminal-Id header required", "invalid_request", 400);
|
|
2105
|
+
const validatedId = validateSessionId(terminalId);
|
|
2106
|
+
if (!validatedId) return errorJson("Invalid terminal ID format", "invalid_request", 400);
|
|
2107
|
+
terminalOptions.id = validatedId;
|
|
2084
2108
|
try {
|
|
2085
|
-
|
|
2086
|
-
const validatedId = validateSessionId(sessionId);
|
|
2087
|
-
if (!validatedId) return errorJson("Invalid session ID format", "invalid_request", 400);
|
|
2088
|
-
return await (await sandbox.getSession(validatedId)).terminal(c.req.raw, opts);
|
|
2089
|
-
}
|
|
2090
|
-
return await sandbox.terminal(c.req.raw, opts);
|
|
2109
|
+
return await sandbox.terminal(terminalOptions).connect(c.req.raw, connectOptions);
|
|
2091
2110
|
} catch (err) {
|
|
2092
2111
|
return errorJson(`terminal failed: ${err instanceof Error ? err.message : String(err)}`, "exec_transport_error", 502);
|
|
2093
2112
|
}
|
|
@@ -2102,7 +2121,7 @@ function createBridgeApp(config) {
|
|
|
2102
2121
|
const excludeArgs = excludes.map((rel) => `--exclude ${shellQuote(`./${rel.replace(/^\.\//, "")}`)}`).join(" ");
|
|
2103
2122
|
const tarCmd = excludeArgs ? `tar cf ${shellQuote(tmpPath)} ${excludeArgs} -C ${shellQuote(root)} .` : `tar cf ${shellQuote(tmpPath)} -C ${shellQuote(root)} .`;
|
|
2104
2123
|
try {
|
|
2105
|
-
const result = await sandbox.exec(tarCmd);
|
|
2124
|
+
const result = await sandbox.exec(tarCmd).output({ encoding: "utf8" });
|
|
2106
2125
|
if (result.exitCode !== 0) return errorJson(`tar failed (exit ${result.exitCode}): ${result.stderr}`, "workspace_archive_read_error", 502);
|
|
2107
2126
|
const stream = await sandbox.readFileStream(tmpPath);
|
|
2108
2127
|
sandbox.exec(`rm -f ${shellQuote(tmpPath)}`).catch(() => {});
|
|
@@ -2134,7 +2153,7 @@ function createBridgeApp(config) {
|
|
|
2134
2153
|
const CHUNK = 6144;
|
|
2135
2154
|
for (let i = 0; i < tarBytes.length; i += CHUNK) b64 += btoa(String.fromCharCode(...tarBytes.subarray(i, i + CHUNK)));
|
|
2136
2155
|
await sandbox.writeFile(tmpPath, b64, { encoding: "base64" });
|
|
2137
|
-
const extractResult = await sandbox.exec(`tar xf ${shellQuote(tmpPath)} -C ${shellQuote(root)} && rm -f ${shellQuote(tmpPath)}`);
|
|
2156
|
+
const extractResult = await sandbox.exec(`tar xf ${shellQuote(tmpPath)} -C ${shellQuote(root)} && rm -f ${shellQuote(tmpPath)}`).output({ encoding: "utf8" });
|
|
2138
2157
|
if (extractResult.exitCode !== 0) return errorJson(`tar extract failed (exit ${extractResult.exitCode}): ${extractResult.stderr}`, "workspace_archive_write_error", 502);
|
|
2139
2158
|
return c.json({ ok: true });
|
|
2140
2159
|
} catch (err) {
|