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.js
CHANGED
|
@@ -8841,7 +8841,7 @@ async function runShell(ctxName, ctx) {
|
|
|
8841
8841
|
const args = ctx.args.slice();
|
|
8842
8842
|
let command;
|
|
8843
8843
|
let scriptPath;
|
|
8844
|
-
let
|
|
8844
|
+
let readStdin = false;
|
|
8845
8845
|
let interactive = false;
|
|
8846
8846
|
let login = ctxName.startsWith("-");
|
|
8847
8847
|
const options = {};
|
|
@@ -8854,7 +8854,7 @@ async function runShell(ctxName, ctx) {
|
|
|
8854
8854
|
break;
|
|
8855
8855
|
}
|
|
8856
8856
|
if (arg === "-s") {
|
|
8857
|
-
|
|
8857
|
+
readStdin = true;
|
|
8858
8858
|
continue;
|
|
8859
8859
|
}
|
|
8860
8860
|
if (arg === "-i") {
|
|
@@ -8891,7 +8891,7 @@ async function runShell(ctxName, ctx) {
|
|
|
8891
8891
|
break;
|
|
8892
8892
|
}
|
|
8893
8893
|
const rest = args.slice(i);
|
|
8894
|
-
if (command === void 0 && !
|
|
8894
|
+
if (command === void 0 && !readStdin && rest.length > 0) {
|
|
8895
8895
|
scriptPath = rest[0];
|
|
8896
8896
|
}
|
|
8897
8897
|
const positional = command !== void 0 ? rest.slice(1) : scriptPath !== void 0 ? rest.slice(1) : rest;
|
|
@@ -17786,6 +17786,143 @@ function mountContainerFs(FS, opts) {
|
|
|
17786
17786
|
}
|
|
17787
17787
|
}
|
|
17788
17788
|
|
|
17789
|
+
// src/runtime/python-syscalls.ts
|
|
17790
|
+
var EMPTY = new Uint8Array(0);
|
|
17791
|
+
function createStdinHost(ctx) {
|
|
17792
|
+
let pending = EMPTY;
|
|
17793
|
+
let eof = false;
|
|
17794
|
+
const take = (size) => {
|
|
17795
|
+
const n = Math.min(size, pending.length);
|
|
17796
|
+
const out = pending.subarray(0, n);
|
|
17797
|
+
pending = pending.subarray(n);
|
|
17798
|
+
return out;
|
|
17799
|
+
};
|
|
17800
|
+
return {
|
|
17801
|
+
/**
|
|
17802
|
+
* Drain a non-interactive stdin up front.
|
|
17803
|
+
*
|
|
17804
|
+
* A pipe ends, so reading it eagerly costs nothing and leaves every read
|
|
17805
|
+
* answerable without suspending — which is what keeps piped input working
|
|
17806
|
+
* on hosts with no stack-switching. A terminal never ends, so priming one
|
|
17807
|
+
* would hang before the program had printed its prompt.
|
|
17808
|
+
*/
|
|
17809
|
+
async prime() {
|
|
17810
|
+
if (ctx.stdin.isTTY || ctx.stdin.interactive) return;
|
|
17811
|
+
try {
|
|
17812
|
+
pending = await ctx.stdin.readAll();
|
|
17813
|
+
} catch {
|
|
17814
|
+
pending = EMPTY;
|
|
17815
|
+
}
|
|
17816
|
+
eof = true;
|
|
17817
|
+
},
|
|
17818
|
+
buffered(size) {
|
|
17819
|
+
if (pending.length > 0) return take(size);
|
|
17820
|
+
return eof ? EMPTY : void 0;
|
|
17821
|
+
},
|
|
17822
|
+
async read(size) {
|
|
17823
|
+
if (pending.length > 0) return take(size);
|
|
17824
|
+
if (eof) return EMPTY;
|
|
17825
|
+
const chunk = await ctx.stdin.read(size);
|
|
17826
|
+
if (chunk === null || chunk.length === 0) {
|
|
17827
|
+
eof = true;
|
|
17828
|
+
return EMPTY;
|
|
17829
|
+
}
|
|
17830
|
+
pending = chunk;
|
|
17831
|
+
return take(size);
|
|
17832
|
+
},
|
|
17833
|
+
isatty() {
|
|
17834
|
+
return Boolean(ctx.stdin.isTTY);
|
|
17835
|
+
}
|
|
17836
|
+
};
|
|
17837
|
+
}
|
|
17838
|
+
var BRIDGE_PY = `
|
|
17839
|
+
import builtins, io, sys
|
|
17840
|
+
import _sbx_host as _host
|
|
17841
|
+
from pyodide.ffi import can_run_sync, run_sync
|
|
17842
|
+
|
|
17843
|
+
|
|
17844
|
+
def _to_bytes(value):
|
|
17845
|
+
if value is None:
|
|
17846
|
+
return b""
|
|
17847
|
+
to_bytes = getattr(value, "to_bytes", None)
|
|
17848
|
+
if to_bytes is not None:
|
|
17849
|
+
return to_bytes()
|
|
17850
|
+
return bytes(value.to_py())
|
|
17851
|
+
|
|
17852
|
+
|
|
17853
|
+
class _SbxStdin(io.RawIOBase):
|
|
17854
|
+
"""The container's standard input, as a blocking raw stream."""
|
|
17855
|
+
|
|
17856
|
+
def readable(self):
|
|
17857
|
+
return True
|
|
17858
|
+
|
|
17859
|
+
def fileno(self):
|
|
17860
|
+
return 0
|
|
17861
|
+
|
|
17862
|
+
def isatty(self):
|
|
17863
|
+
return bool(_host.isatty())
|
|
17864
|
+
|
|
17865
|
+
def readinto(self, target):
|
|
17866
|
+
want = len(target)
|
|
17867
|
+
if want == 0:
|
|
17868
|
+
return 0
|
|
17869
|
+
ready = _host.buffered(want)
|
|
17870
|
+
if ready is None:
|
|
17871
|
+
if not can_run_sync():
|
|
17872
|
+
raise OSError(
|
|
17873
|
+
"this host cannot wait for interactive input: WebAssembly "
|
|
17874
|
+
"stack switching (JSPI) is unavailable. Pipe the input in, "
|
|
17875
|
+
"or use a browser or Node build that supports it."
|
|
17876
|
+
)
|
|
17877
|
+
ready = run_sync(_host.read(want))
|
|
17878
|
+
data = _to_bytes(ready)
|
|
17879
|
+
target[: len(data)] = data
|
|
17880
|
+
return len(data)
|
|
17881
|
+
|
|
17882
|
+
|
|
17883
|
+
def _install():
|
|
17884
|
+
stdin = io.TextIOWrapper(
|
|
17885
|
+
io.BufferedReader(_SbxStdin()), encoding="utf-8", errors="replace", line_buffering=True
|
|
17886
|
+
)
|
|
17887
|
+
sys.stdin = stdin
|
|
17888
|
+
sys.__stdin__ = stdin
|
|
17889
|
+
|
|
17890
|
+
def input(prompt=""):
|
|
17891
|
+
# CPython writes the prompt to stdout and strips exactly one trailing
|
|
17892
|
+
# newline; anything else changes what a program reads back.
|
|
17893
|
+
if prompt != "":
|
|
17894
|
+
sys.stdout.write(str(prompt))
|
|
17895
|
+
sys.stdout.flush()
|
|
17896
|
+
line = sys.stdin.readline()
|
|
17897
|
+
if not line:
|
|
17898
|
+
raise EOFError("EOF when reading a line")
|
|
17899
|
+
if line.endswith("\\n"):
|
|
17900
|
+
line = line[:-1]
|
|
17901
|
+
if line.endswith("\\r"):
|
|
17902
|
+
line = line[:-1]
|
|
17903
|
+
return line
|
|
17904
|
+
|
|
17905
|
+
builtins.input = input
|
|
17906
|
+
|
|
17907
|
+
|
|
17908
|
+
_install()
|
|
17909
|
+
`;
|
|
17910
|
+
function installSyscallBridge(py) {
|
|
17911
|
+
const slot = py.__sbxStdin ??= { active: null };
|
|
17912
|
+
py.registerJsModule("_sbx_host", {
|
|
17913
|
+
/* Not `?.` and `??`: `buffered` returns undefined to mean "you will have
|
|
17914
|
+
* to wait", and a nullish default would quietly turn that into end-of-file —
|
|
17915
|
+
* which is exactly the silent EOF this bridge exists to remove. */
|
|
17916
|
+
buffered: (size) => slot.active ? slot.active.buffered(size) : EMPTY,
|
|
17917
|
+
read: (size) => slot.active ? slot.active.read(size) : Promise.resolve(EMPTY),
|
|
17918
|
+
isatty: () => slot.active?.isatty() ?? false
|
|
17919
|
+
});
|
|
17920
|
+
py.runPython(BRIDGE_PY);
|
|
17921
|
+
}
|
|
17922
|
+
function bindStdin(py, host2) {
|
|
17923
|
+
py.__sbxStdin.active = host2;
|
|
17924
|
+
}
|
|
17925
|
+
|
|
17789
17926
|
// src/runtime/cpython.ts
|
|
17790
17927
|
var RESERVED_FOR_INTERPRETER = /* @__PURE__ */ new Set(["lib", "dev", "proc"]);
|
|
17791
17928
|
var pyodideModule = null;
|
|
@@ -17858,6 +17995,7 @@ async function interpreterFor(ctx) {
|
|
|
17858
17995
|
});
|
|
17859
17996
|
mountContainerDirs(py, ctx);
|
|
17860
17997
|
installRunner(py);
|
|
17998
|
+
installSyscallBridge(py);
|
|
17861
17999
|
return py;
|
|
17862
18000
|
})();
|
|
17863
18001
|
interpreters.set(ctx.vfs, starting);
|
|
@@ -17952,7 +18090,7 @@ function reportError(ctx, error) {
|
|
|
17952
18090
|
`);
|
|
17953
18091
|
return 1;
|
|
17954
18092
|
}
|
|
17955
|
-
async function runCPythonProgram(ctx, source, argv, scriptDir
|
|
18093
|
+
async function runCPythonProgram(ctx, source, argv, scriptDir = null) {
|
|
17956
18094
|
let py;
|
|
17957
18095
|
try {
|
|
17958
18096
|
py = await interpreterFor(ctx);
|
|
@@ -17973,7 +18111,6 @@ async function runCPythonProgram(ctx, source, argv, scriptDir, stdinText) {
|
|
|
17973
18111
|
});
|
|
17974
18112
|
} catch {
|
|
17975
18113
|
}
|
|
17976
|
-
const encoder8 = new TextEncoder();
|
|
17977
18114
|
const decoder8 = new TextDecoder();
|
|
17978
18115
|
py.setStdout({
|
|
17979
18116
|
write: (buffer) => {
|
|
@@ -17987,20 +18124,17 @@ async function runCPythonProgram(ctx, source, argv, scriptDir, stdinText) {
|
|
|
17987
18124
|
return buffer.length;
|
|
17988
18125
|
}
|
|
17989
18126
|
});
|
|
17990
|
-
|
|
17991
|
-
|
|
17992
|
-
|
|
17993
|
-
|
|
17994
|
-
|
|
17995
|
-
|
|
17996
|
-
|
|
17997
|
-
|
|
17998
|
-
|
|
17999
|
-
|
|
18000
|
-
|
|
18001
|
-
} else {
|
|
18002
|
-
py.setStdin({ read: () => 0 });
|
|
18003
|
-
}
|
|
18127
|
+
const stdinHost = createStdinHost(ctx);
|
|
18128
|
+
await stdinHost.prime();
|
|
18129
|
+
bindStdin(py, stdinHost);
|
|
18130
|
+
py.setStdin({
|
|
18131
|
+
read: (buffer) => {
|
|
18132
|
+
const ready = stdinHost.buffered(buffer.length);
|
|
18133
|
+
if (!ready || ready.length === 0) return 0;
|
|
18134
|
+
buffer.set(ready);
|
|
18135
|
+
return ready.length;
|
|
18136
|
+
}
|
|
18137
|
+
});
|
|
18004
18138
|
try {
|
|
18005
18139
|
bootstrap(py, ctx, argv, scriptDir);
|
|
18006
18140
|
} catch (error) {
|
|
@@ -18133,11 +18267,6 @@ function configurePython(options = {}) {
|
|
|
18133
18267
|
configureCPython({ indexURL: options.indexURL, moduleURL: options.pyodideURL });
|
|
18134
18268
|
}
|
|
18135
18269
|
var isPythonAvailable = isCPythonAvailable;
|
|
18136
|
-
async function readStdin(ctx) {
|
|
18137
|
-
if (ctx.stdin.isTTY || ctx.stdin.interactive) return null;
|
|
18138
|
-
const bytes2 = await ctx.stdin.readAll();
|
|
18139
|
-
return bytes2.length ? new TextDecoder().decode(bytes2) : null;
|
|
18140
|
-
}
|
|
18141
18270
|
var python = defineCommand({
|
|
18142
18271
|
name: "python3",
|
|
18143
18272
|
path: "/usr/bin/python3",
|
|
@@ -18186,7 +18315,7 @@ compatible packages can be installed with pip (micropip).`,
|
|
|
18186
18315
|
}
|
|
18187
18316
|
const rest = argv.slice(i);
|
|
18188
18317
|
if (command !== void 0) {
|
|
18189
|
-
return (await runCPythonProgram(ctx, command, ["-c", ...rest], null
|
|
18318
|
+
return (await runCPythonProgram(ctx, command, ["-c", ...rest], null)).exitCode;
|
|
18190
18319
|
}
|
|
18191
18320
|
if (moduleName !== void 0) {
|
|
18192
18321
|
const program = `
|
|
@@ -18198,16 +18327,16 @@ except ImportError:
|
|
|
18198
18327
|
print("/usr/bin/python3: No module named " + ${JSON.stringify(moduleName)}, file=sys.stderr)
|
|
18199
18328
|
raise SystemExit(1)
|
|
18200
18329
|
`;
|
|
18201
|
-
return (await runCPythonProgram(ctx, program, [moduleName, ...rest], null
|
|
18330
|
+
return (await runCPythonProgram(ctx, program, [moduleName, ...rest], null)).exitCode;
|
|
18202
18331
|
}
|
|
18203
18332
|
if (script === void 0) {
|
|
18204
18333
|
if (ctx.stdin.isTTY) return runCPythonRepl(ctx);
|
|
18205
18334
|
const source2 = new TextDecoder().decode(await ctx.stdin.readAll());
|
|
18206
|
-
return source2.trim() ? (await runCPythonProgram(ctx, source2, ["", ...rest]
|
|
18335
|
+
return source2.trim() ? (await runCPythonProgram(ctx, source2, ["", ...rest])).exitCode : 0;
|
|
18207
18336
|
}
|
|
18208
18337
|
if (script === "-") {
|
|
18209
18338
|
const source2 = new TextDecoder().decode(await ctx.stdin.readAll());
|
|
18210
|
-
return (await runCPythonProgram(ctx, source2, ["-", ...rest]
|
|
18339
|
+
return (await runCPythonProgram(ctx, source2, ["-", ...rest])).exitCode;
|
|
18211
18340
|
}
|
|
18212
18341
|
const abs = ctx.path(script);
|
|
18213
18342
|
let source;
|
|
@@ -18218,7 +18347,7 @@ except ImportError:
|
|
|
18218
18347
|
`);
|
|
18219
18348
|
return 2;
|
|
18220
18349
|
}
|
|
18221
|
-
return (await runCPythonProgram(ctx, source, [abs, ...rest], dirname(abs)
|
|
18350
|
+
return (await runCPythonProgram(ctx, source, [abs, ...rest], dirname(abs))).exitCode;
|
|
18222
18351
|
}
|
|
18223
18352
|
});
|
|
18224
18353
|
function printHelp2(ctx) {
|