@cloudflare/sandbox 1.0.1 → 1.0.3
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/README.md +1 -1
- package/dist/index.mjs +68 -12
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -99,7 +99,7 @@ npm run check
|
|
|
99
99
|
npm test
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
-
[Testing](docs/testing.md) explains what these commands check, how to build behind a TLS-inspecting proxy, and how to test in production. [Releasing](docs/releasing.md) explains how maintainers publish the package and its image.
|
|
102
|
+
[Testing](docs/testing.md) explains what these commands check, how to build behind a TLS-inspecting proxy, and how to test in production. [Releasing](docs/releasing.md) explains how to describe a change for the release notes, and how maintainers publish the package and its image.
|
|
103
103
|
|
|
104
104
|
## License
|
|
105
105
|
|
package/dist/index.mjs
CHANGED
|
@@ -968,7 +968,10 @@ function readBytes(payload, offset, length) {
|
|
|
968
968
|
}
|
|
969
969
|
function decodeText(bytes) {
|
|
970
970
|
try {
|
|
971
|
-
return new TextDecoder("utf-8", {
|
|
971
|
+
return new TextDecoder("utf-8", {
|
|
972
|
+
fatal: true,
|
|
973
|
+
ignoreBOM: true
|
|
974
|
+
}).decode(bytes);
|
|
972
975
|
} catch (cause) {
|
|
973
976
|
throw protocolError("sandbox-shim returned invalid UTF-8 in directory entry name", cause);
|
|
974
977
|
}
|
|
@@ -985,11 +988,12 @@ async function readFile(container, path, options) {
|
|
|
985
988
|
stderr: "pipe"
|
|
986
989
|
});
|
|
987
990
|
let control;
|
|
988
|
-
let
|
|
991
|
+
let stdout;
|
|
989
992
|
try {
|
|
990
993
|
control = session.openStderrControl();
|
|
991
|
-
|
|
994
|
+
stdout = new StdoutReader(session.openStdoutReader());
|
|
992
995
|
const opening = await control.readFrame();
|
|
996
|
+
stdout.stopReadingAhead();
|
|
993
997
|
if (opening.kind === "fileError") {
|
|
994
998
|
await control.expectEnd();
|
|
995
999
|
await session.settle();
|
|
@@ -1001,17 +1005,69 @@ async function readFile(container, path, options) {
|
|
|
1001
1005
|
if (opening.kind !== "success") throw protocolError("sandbox-shim returned data before file bytes");
|
|
1002
1006
|
const terminal = readTerminalControl(control);
|
|
1003
1007
|
terminal.catch(() => void 0);
|
|
1004
|
-
return new Response(responseBody(session, control,
|
|
1008
|
+
return new Response(responseBody(session, control, stdout, terminal, path));
|
|
1005
1009
|
} catch (error) {
|
|
1006
|
-
terminateRead(session, control,
|
|
1010
|
+
terminateRead(session, control, stdout, error);
|
|
1007
1011
|
throw error;
|
|
1008
1012
|
}
|
|
1009
1013
|
}
|
|
1010
|
-
|
|
1014
|
+
/**
|
|
1015
|
+
* Reads the shim's stdout, reading ahead until `readFile` has the opening frame from stderr.
|
|
1016
|
+
*
|
|
1017
|
+
* A container transport can carry stdout and stderr over one connection with shared backpressure,
|
|
1018
|
+
* and can deliver file bytes before the opening frame, or between its fragments. The rest of the
|
|
1019
|
+
* frame then arrives only after something reads stdout. The shim writes the whole opening frame
|
|
1020
|
+
* before any file byte, so the read-ahead stops once that frame is complete. After that, the
|
|
1021
|
+
* response body reads stdout on demand, so the caller's pace applies backpressure again.
|
|
1022
|
+
*
|
|
1023
|
+
* The read-ahead has no size limit, because stopping before the frame is complete would bring the
|
|
1024
|
+
* hang back. How much it holds depends on how far the transport lets stdout run ahead of stderr.
|
|
1025
|
+
*/
|
|
1026
|
+
var StdoutReader = class {
|
|
1027
|
+
#reader;
|
|
1028
|
+
#chunks = [];
|
|
1029
|
+
#pending;
|
|
1030
|
+
#readingAhead = true;
|
|
1031
|
+
constructor(reader) {
|
|
1032
|
+
this.#reader = reader;
|
|
1033
|
+
this.#readNext();
|
|
1034
|
+
}
|
|
1035
|
+
/** Stops reading ahead. Chunks already read stay queued for `read()`. */
|
|
1036
|
+
stopReadingAhead() {
|
|
1037
|
+
this.#readingAhead = false;
|
|
1038
|
+
}
|
|
1039
|
+
read() {
|
|
1040
|
+
const chunk = this.#chunks.shift();
|
|
1041
|
+
if (chunk !== void 0) return Promise.resolve({
|
|
1042
|
+
done: false,
|
|
1043
|
+
value: chunk
|
|
1044
|
+
});
|
|
1045
|
+
const pending = this.#pending ?? this.#reader.read();
|
|
1046
|
+
this.#pending = void 0;
|
|
1047
|
+
return pending;
|
|
1048
|
+
}
|
|
1049
|
+
discard(reason) {
|
|
1050
|
+
this.#reader.cancel(reason).then(() => this.#reader.releaseLock(), () => this.#reader.releaseLock());
|
|
1051
|
+
}
|
|
1052
|
+
releaseLock() {
|
|
1053
|
+
this.#reader.releaseLock();
|
|
1054
|
+
}
|
|
1055
|
+
#readNext() {
|
|
1056
|
+
const read = this.#reader.read();
|
|
1057
|
+
this.#pending = read;
|
|
1058
|
+
read.then((result) => {
|
|
1059
|
+
if (this.#pending !== read || result.done) return;
|
|
1060
|
+
this.#pending = void 0;
|
|
1061
|
+
this.#chunks.push(result.value);
|
|
1062
|
+
if (this.#readingAhead) this.#readNext();
|
|
1063
|
+
}, () => void 0);
|
|
1064
|
+
}
|
|
1065
|
+
};
|
|
1066
|
+
function responseBody(session, control, stdout, terminalFrame, path) {
|
|
1011
1067
|
return new ReadableStream({
|
|
1012
1068
|
pull: async (controller) => {
|
|
1013
1069
|
try {
|
|
1014
|
-
const next = await session.waitFor(
|
|
1070
|
+
const next = await session.waitFor(stdout.read());
|
|
1015
1071
|
if (!next.done) {
|
|
1016
1072
|
controller.enqueue(next.value);
|
|
1017
1073
|
return;
|
|
@@ -1025,16 +1081,16 @@ function responseBody(session, control, output, terminalFrame, path) {
|
|
|
1025
1081
|
}, terminal.errno, terminal.detail);
|
|
1026
1082
|
}
|
|
1027
1083
|
if (terminal.kind !== "success") throw protocolError("sandbox-shim returned data after file bytes");
|
|
1028
|
-
|
|
1084
|
+
stdout.releaseLock();
|
|
1029
1085
|
control.releaseLock();
|
|
1030
1086
|
session.finish();
|
|
1031
1087
|
controller.close();
|
|
1032
1088
|
} catch (error) {
|
|
1033
|
-
terminateRead(session, control,
|
|
1089
|
+
terminateRead(session, control, stdout, error);
|
|
1034
1090
|
controller.error(error);
|
|
1035
1091
|
}
|
|
1036
1092
|
},
|
|
1037
|
-
cancel: (reason) => terminateRead(session, control,
|
|
1093
|
+
cancel: (reason) => terminateRead(session, control, stdout, reason)
|
|
1038
1094
|
});
|
|
1039
1095
|
}
|
|
1040
1096
|
async function readTerminalControl(control) {
|
|
@@ -1042,10 +1098,10 @@ async function readTerminalControl(control) {
|
|
|
1042
1098
|
await control.expectEnd();
|
|
1043
1099
|
return frame;
|
|
1044
1100
|
}
|
|
1045
|
-
function terminateRead(session, control,
|
|
1101
|
+
function terminateRead(session, control, stdout, reason) {
|
|
1046
1102
|
session.terminate();
|
|
1047
1103
|
control?.discard(reason);
|
|
1048
|
-
|
|
1104
|
+
stdout?.discard(reason);
|
|
1049
1105
|
}
|
|
1050
1106
|
//#endregion
|
|
1051
1107
|
//#region src/files/stat-file.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudflare/sandbox",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Structured workspace file operations for Cloudflare sandboxes",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -23,6 +23,6 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"aws4fetch": "1.0.20",
|
|
26
|
-
"zod": "4.6.
|
|
26
|
+
"zod": "4.6.7"
|
|
27
27
|
}
|
|
28
28
|
}
|