sandboxedjs 0.1.31 → 0.1.32
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/dist/index.cjs +158 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +158 -29
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -8858,7 +8858,7 @@ async function runShell(ctxName, ctx) {
|
|
|
8858
8858
|
const args = ctx.args.slice();
|
|
8859
8859
|
let command;
|
|
8860
8860
|
let scriptPath;
|
|
8861
|
-
let
|
|
8861
|
+
let readStdin = false;
|
|
8862
8862
|
let interactive = false;
|
|
8863
8863
|
let login = ctxName.startsWith("-");
|
|
8864
8864
|
const options = {};
|
|
@@ -8871,7 +8871,7 @@ async function runShell(ctxName, ctx) {
|
|
|
8871
8871
|
break;
|
|
8872
8872
|
}
|
|
8873
8873
|
if (arg === "-s") {
|
|
8874
|
-
|
|
8874
|
+
readStdin = true;
|
|
8875
8875
|
continue;
|
|
8876
8876
|
}
|
|
8877
8877
|
if (arg === "-i") {
|
|
@@ -8908,7 +8908,7 @@ async function runShell(ctxName, ctx) {
|
|
|
8908
8908
|
break;
|
|
8909
8909
|
}
|
|
8910
8910
|
const rest = args.slice(i);
|
|
8911
|
-
if (command === void 0 && !
|
|
8911
|
+
if (command === void 0 && !readStdin && rest.length > 0) {
|
|
8912
8912
|
scriptPath = rest[0];
|
|
8913
8913
|
}
|
|
8914
8914
|
const positional = command !== void 0 ? rest.slice(1) : scriptPath !== void 0 ? rest.slice(1) : rest;
|
|
@@ -17803,6 +17803,143 @@ function mountContainerFs(FS, opts) {
|
|
|
17803
17803
|
}
|
|
17804
17804
|
}
|
|
17805
17805
|
|
|
17806
|
+
// src/runtime/python-syscalls.ts
|
|
17807
|
+
var EMPTY = new Uint8Array(0);
|
|
17808
|
+
function createStdinHost(ctx) {
|
|
17809
|
+
let pending = EMPTY;
|
|
17810
|
+
let eof = false;
|
|
17811
|
+
const take = (size) => {
|
|
17812
|
+
const n = Math.min(size, pending.length);
|
|
17813
|
+
const out = pending.subarray(0, n);
|
|
17814
|
+
pending = pending.subarray(n);
|
|
17815
|
+
return out;
|
|
17816
|
+
};
|
|
17817
|
+
return {
|
|
17818
|
+
/**
|
|
17819
|
+
* Drain a non-interactive stdin up front.
|
|
17820
|
+
*
|
|
17821
|
+
* A pipe ends, so reading it eagerly costs nothing and leaves every read
|
|
17822
|
+
* answerable without suspending — which is what keeps piped input working
|
|
17823
|
+
* on hosts with no stack-switching. A terminal never ends, so priming one
|
|
17824
|
+
* would hang before the program had printed its prompt.
|
|
17825
|
+
*/
|
|
17826
|
+
async prime() {
|
|
17827
|
+
if (ctx.stdin.isTTY || ctx.stdin.interactive) return;
|
|
17828
|
+
try {
|
|
17829
|
+
pending = await ctx.stdin.readAll();
|
|
17830
|
+
} catch {
|
|
17831
|
+
pending = EMPTY;
|
|
17832
|
+
}
|
|
17833
|
+
eof = true;
|
|
17834
|
+
},
|
|
17835
|
+
buffered(size) {
|
|
17836
|
+
if (pending.length > 0) return take(size);
|
|
17837
|
+
return eof ? EMPTY : void 0;
|
|
17838
|
+
},
|
|
17839
|
+
async read(size) {
|
|
17840
|
+
if (pending.length > 0) return take(size);
|
|
17841
|
+
if (eof) return EMPTY;
|
|
17842
|
+
const chunk = await ctx.stdin.read(size);
|
|
17843
|
+
if (chunk === null || chunk.length === 0) {
|
|
17844
|
+
eof = true;
|
|
17845
|
+
return EMPTY;
|
|
17846
|
+
}
|
|
17847
|
+
pending = chunk;
|
|
17848
|
+
return take(size);
|
|
17849
|
+
},
|
|
17850
|
+
isatty() {
|
|
17851
|
+
return Boolean(ctx.stdin.isTTY);
|
|
17852
|
+
}
|
|
17853
|
+
};
|
|
17854
|
+
}
|
|
17855
|
+
var BRIDGE_PY = `
|
|
17856
|
+
import builtins, io, sys
|
|
17857
|
+
import _sbx_host as _host
|
|
17858
|
+
from pyodide.ffi import can_run_sync, run_sync
|
|
17859
|
+
|
|
17860
|
+
|
|
17861
|
+
def _to_bytes(value):
|
|
17862
|
+
if value is None:
|
|
17863
|
+
return b""
|
|
17864
|
+
to_bytes = getattr(value, "to_bytes", None)
|
|
17865
|
+
if to_bytes is not None:
|
|
17866
|
+
return to_bytes()
|
|
17867
|
+
return bytes(value.to_py())
|
|
17868
|
+
|
|
17869
|
+
|
|
17870
|
+
class _SbxStdin(io.RawIOBase):
|
|
17871
|
+
"""The container's standard input, as a blocking raw stream."""
|
|
17872
|
+
|
|
17873
|
+
def readable(self):
|
|
17874
|
+
return True
|
|
17875
|
+
|
|
17876
|
+
def fileno(self):
|
|
17877
|
+
return 0
|
|
17878
|
+
|
|
17879
|
+
def isatty(self):
|
|
17880
|
+
return bool(_host.isatty())
|
|
17881
|
+
|
|
17882
|
+
def readinto(self, target):
|
|
17883
|
+
want = len(target)
|
|
17884
|
+
if want == 0:
|
|
17885
|
+
return 0
|
|
17886
|
+
ready = _host.buffered(want)
|
|
17887
|
+
if ready is None:
|
|
17888
|
+
if not can_run_sync():
|
|
17889
|
+
raise OSError(
|
|
17890
|
+
"this host cannot wait for interactive input: WebAssembly "
|
|
17891
|
+
"stack switching (JSPI) is unavailable. Pipe the input in, "
|
|
17892
|
+
"or use a browser or Node build that supports it."
|
|
17893
|
+
)
|
|
17894
|
+
ready = run_sync(_host.read(want))
|
|
17895
|
+
data = _to_bytes(ready)
|
|
17896
|
+
target[: len(data)] = data
|
|
17897
|
+
return len(data)
|
|
17898
|
+
|
|
17899
|
+
|
|
17900
|
+
def _install():
|
|
17901
|
+
stdin = io.TextIOWrapper(
|
|
17902
|
+
io.BufferedReader(_SbxStdin()), encoding="utf-8", errors="replace", line_buffering=True
|
|
17903
|
+
)
|
|
17904
|
+
sys.stdin = stdin
|
|
17905
|
+
sys.__stdin__ = stdin
|
|
17906
|
+
|
|
17907
|
+
def input(prompt=""):
|
|
17908
|
+
# CPython writes the prompt to stdout and strips exactly one trailing
|
|
17909
|
+
# newline; anything else changes what a program reads back.
|
|
17910
|
+
if prompt != "":
|
|
17911
|
+
sys.stdout.write(str(prompt))
|
|
17912
|
+
sys.stdout.flush()
|
|
17913
|
+
line = sys.stdin.readline()
|
|
17914
|
+
if not line:
|
|
17915
|
+
raise EOFError("EOF when reading a line")
|
|
17916
|
+
if line.endswith("\\n"):
|
|
17917
|
+
line = line[:-1]
|
|
17918
|
+
if line.endswith("\\r"):
|
|
17919
|
+
line = line[:-1]
|
|
17920
|
+
return line
|
|
17921
|
+
|
|
17922
|
+
builtins.input = input
|
|
17923
|
+
|
|
17924
|
+
|
|
17925
|
+
_install()
|
|
17926
|
+
`;
|
|
17927
|
+
function installSyscallBridge(py) {
|
|
17928
|
+
const slot = py.__sbxStdin ??= { active: null };
|
|
17929
|
+
py.registerJsModule("_sbx_host", {
|
|
17930
|
+
/* Not `?.` and `??`: `buffered` returns undefined to mean "you will have
|
|
17931
|
+
* to wait", and a nullish default would quietly turn that into end-of-file —
|
|
17932
|
+
* which is exactly the silent EOF this bridge exists to remove. */
|
|
17933
|
+
buffered: (size) => slot.active ? slot.active.buffered(size) : EMPTY,
|
|
17934
|
+
read: (size) => slot.active ? slot.active.read(size) : Promise.resolve(EMPTY),
|
|
17935
|
+
isatty: () => slot.active?.isatty() ?? false
|
|
17936
|
+
});
|
|
17937
|
+
py.runPython(BRIDGE_PY);
|
|
17938
|
+
}
|
|
17939
|
+
function bindStdin(py, host2) {
|
|
17940
|
+
py.__sbxStdin.active = host2;
|
|
17941
|
+
}
|
|
17942
|
+
|
|
17806
17943
|
// src/runtime/cpython.ts
|
|
17807
17944
|
var RESERVED_FOR_INTERPRETER = /* @__PURE__ */ new Set(["lib", "dev", "proc"]);
|
|
17808
17945
|
var pyodideModule = null;
|
|
@@ -17875,6 +18012,7 @@ async function interpreterFor(ctx) {
|
|
|
17875
18012
|
});
|
|
17876
18013
|
mountContainerDirs(py, ctx);
|
|
17877
18014
|
installRunner(py);
|
|
18015
|
+
installSyscallBridge(py);
|
|
17878
18016
|
return py;
|
|
17879
18017
|
})();
|
|
17880
18018
|
interpreters.set(ctx.vfs, starting);
|
|
@@ -17969,7 +18107,7 @@ function reportError(ctx, error) {
|
|
|
17969
18107
|
`);
|
|
17970
18108
|
return 1;
|
|
17971
18109
|
}
|
|
17972
|
-
async function runCPythonProgram(ctx, source, argv, scriptDir
|
|
18110
|
+
async function runCPythonProgram(ctx, source, argv, scriptDir = null) {
|
|
17973
18111
|
let py;
|
|
17974
18112
|
try {
|
|
17975
18113
|
py = await interpreterFor(ctx);
|
|
@@ -17990,7 +18128,6 @@ async function runCPythonProgram(ctx, source, argv, scriptDir, stdinText) {
|
|
|
17990
18128
|
});
|
|
17991
18129
|
} catch {
|
|
17992
18130
|
}
|
|
17993
|
-
const encoder8 = new TextEncoder();
|
|
17994
18131
|
const decoder8 = new TextDecoder();
|
|
17995
18132
|
py.setStdout({
|
|
17996
18133
|
write: (buffer) => {
|
|
@@ -18004,20 +18141,17 @@ async function runCPythonProgram(ctx, source, argv, scriptDir, stdinText) {
|
|
|
18004
18141
|
return buffer.length;
|
|
18005
18142
|
}
|
|
18006
18143
|
});
|
|
18007
|
-
|
|
18008
|
-
|
|
18009
|
-
|
|
18010
|
-
|
|
18011
|
-
|
|
18012
|
-
|
|
18013
|
-
|
|
18014
|
-
|
|
18015
|
-
|
|
18016
|
-
|
|
18017
|
-
|
|
18018
|
-
} else {
|
|
18019
|
-
py.setStdin({ read: () => 0 });
|
|
18020
|
-
}
|
|
18144
|
+
const stdinHost = createStdinHost(ctx);
|
|
18145
|
+
await stdinHost.prime();
|
|
18146
|
+
bindStdin(py, stdinHost);
|
|
18147
|
+
py.setStdin({
|
|
18148
|
+
read: (buffer) => {
|
|
18149
|
+
const ready = stdinHost.buffered(buffer.length);
|
|
18150
|
+
if (!ready || ready.length === 0) return 0;
|
|
18151
|
+
buffer.set(ready);
|
|
18152
|
+
return ready.length;
|
|
18153
|
+
}
|
|
18154
|
+
});
|
|
18021
18155
|
try {
|
|
18022
18156
|
bootstrap(py, ctx, argv, scriptDir);
|
|
18023
18157
|
} catch (error) {
|
|
@@ -18150,11 +18284,6 @@ function configurePython(options = {}) {
|
|
|
18150
18284
|
configureCPython({ indexURL: options.indexURL, moduleURL: options.pyodideURL });
|
|
18151
18285
|
}
|
|
18152
18286
|
var isPythonAvailable = isCPythonAvailable;
|
|
18153
|
-
async function readStdin(ctx) {
|
|
18154
|
-
if (ctx.stdin.isTTY || ctx.stdin.interactive) return null;
|
|
18155
|
-
const bytes2 = await ctx.stdin.readAll();
|
|
18156
|
-
return bytes2.length ? new TextDecoder().decode(bytes2) : null;
|
|
18157
|
-
}
|
|
18158
18287
|
var python = defineCommand({
|
|
18159
18288
|
name: "python3",
|
|
18160
18289
|
path: "/usr/bin/python3",
|
|
@@ -18203,7 +18332,7 @@ compatible packages can be installed with pip (micropip).`,
|
|
|
18203
18332
|
}
|
|
18204
18333
|
const rest = argv.slice(i);
|
|
18205
18334
|
if (command !== void 0) {
|
|
18206
|
-
return (await runCPythonProgram(ctx, command, ["-c", ...rest], null
|
|
18335
|
+
return (await runCPythonProgram(ctx, command, ["-c", ...rest], null)).exitCode;
|
|
18207
18336
|
}
|
|
18208
18337
|
if (moduleName !== void 0) {
|
|
18209
18338
|
const program = `
|
|
@@ -18215,16 +18344,16 @@ except ImportError:
|
|
|
18215
18344
|
print("/usr/bin/python3: No module named " + ${JSON.stringify(moduleName)}, file=sys.stderr)
|
|
18216
18345
|
raise SystemExit(1)
|
|
18217
18346
|
`;
|
|
18218
|
-
return (await runCPythonProgram(ctx, program, [moduleName, ...rest], null
|
|
18347
|
+
return (await runCPythonProgram(ctx, program, [moduleName, ...rest], null)).exitCode;
|
|
18219
18348
|
}
|
|
18220
18349
|
if (script === void 0) {
|
|
18221
18350
|
if (ctx.stdin.isTTY) return runCPythonRepl(ctx);
|
|
18222
18351
|
const source2 = new TextDecoder().decode(await ctx.stdin.readAll());
|
|
18223
|
-
return source2.trim() ? (await runCPythonProgram(ctx, source2, ["", ...rest]
|
|
18352
|
+
return source2.trim() ? (await runCPythonProgram(ctx, source2, ["", ...rest])).exitCode : 0;
|
|
18224
18353
|
}
|
|
18225
18354
|
if (script === "-") {
|
|
18226
18355
|
const source2 = new TextDecoder().decode(await ctx.stdin.readAll());
|
|
18227
|
-
return (await runCPythonProgram(ctx, source2, ["-", ...rest]
|
|
18356
|
+
return (await runCPythonProgram(ctx, source2, ["-", ...rest])).exitCode;
|
|
18228
18357
|
}
|
|
18229
18358
|
const abs = ctx.path(script);
|
|
18230
18359
|
let source;
|
|
@@ -18235,7 +18364,7 @@ except ImportError:
|
|
|
18235
18364
|
`);
|
|
18236
18365
|
return 2;
|
|
18237
18366
|
}
|
|
18238
|
-
return (await runCPythonProgram(ctx, source, [abs, ...rest], dirname(abs)
|
|
18367
|
+
return (await runCPythonProgram(ctx, source, [abs, ...rest], dirname(abs))).exitCode;
|
|
18239
18368
|
}
|
|
18240
18369
|
});
|
|
18241
18370
|
function printHelp2(ctx) {
|