sandboxedjs 0.1.33 → 0.1.34
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 +140 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +140 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -18168,6 +18168,55 @@ def _install_processes():
|
|
|
18168
18168
|
|
|
18169
18169
|
_install_processes()
|
|
18170
18170
|
`;
|
|
18171
|
+
var ASYNCIO_PY = `
|
|
18172
|
+
import asyncio
|
|
18173
|
+
from pyodide.ffi import can_run_sync, run_sync
|
|
18174
|
+
|
|
18175
|
+
_orig_run = asyncio.run
|
|
18176
|
+
|
|
18177
|
+
|
|
18178
|
+
def _run(main, *, debug=None, loop_factory=None):
|
|
18179
|
+
if not asyncio.iscoroutine(main) and not asyncio.isfuture(main):
|
|
18180
|
+
raise ValueError("a coroutine was expected, got {!r}".format(main))
|
|
18181
|
+
if not can_run_sync():
|
|
18182
|
+
# No stack switching: the original at least raises a comprehensible
|
|
18183
|
+
# error rather than this shim inventing a new one.
|
|
18184
|
+
return _orig_run(main, debug=debug, loop_factory=loop_factory)
|
|
18185
|
+
return run_sync(main)
|
|
18186
|
+
|
|
18187
|
+
|
|
18188
|
+
def _run_until_complete(self, future):
|
|
18189
|
+
if not can_run_sync():
|
|
18190
|
+
raise RuntimeError(
|
|
18191
|
+
"cannot wait for a coroutine on this host: WebAssembly stack "
|
|
18192
|
+
"switching (JSPI) is unavailable."
|
|
18193
|
+
)
|
|
18194
|
+
return run_sync(future)
|
|
18195
|
+
|
|
18196
|
+
|
|
18197
|
+
async def _create_server(self, *args, **kwargs):
|
|
18198
|
+
# Pyodide's loop raises a bare NotImplementedError from deep inside
|
|
18199
|
+
# asyncio, which tells a reader nothing about why their server will not
|
|
18200
|
+
# start. Naming the limit is the least this can do until the container can
|
|
18201
|
+
# route connections to Python.
|
|
18202
|
+
raise NotImplementedError(
|
|
18203
|
+
"this container cannot yet accept network connections from Python: "
|
|
18204
|
+
"asyncio's create_server is not implemented on Pyodide's event loop, "
|
|
18205
|
+
"so an ASGI/WSGI server such as uvicorn will install and import but "
|
|
18206
|
+
"not bind a port. Outbound requests do work."
|
|
18207
|
+
)
|
|
18208
|
+
|
|
18209
|
+
|
|
18210
|
+
def _install_asyncio():
|
|
18211
|
+
asyncio.run = _run
|
|
18212
|
+
asyncio.runners.run = _run
|
|
18213
|
+
loop_type = type(asyncio.get_event_loop())
|
|
18214
|
+
loop_type.run_until_complete = _run_until_complete
|
|
18215
|
+
loop_type.create_server = _create_server
|
|
18216
|
+
|
|
18217
|
+
|
|
18218
|
+
_install_asyncio()
|
|
18219
|
+
`;
|
|
18171
18220
|
var NETWORK_PY = `
|
|
18172
18221
|
import builtins, email.message, io, sys, urllib.error, urllib.request, urllib.response
|
|
18173
18222
|
import _sbx_host as _host
|
|
@@ -18452,6 +18501,7 @@ function installSyscallBridge(py) {
|
|
|
18452
18501
|
py.runPython(BRIDGE_PY);
|
|
18453
18502
|
py.runPython(PROCESS_PY);
|
|
18454
18503
|
py.runPython(NETWORK_PY);
|
|
18504
|
+
py.runPython(ASYNCIO_PY);
|
|
18455
18505
|
}
|
|
18456
18506
|
function bindProgram(py, binding) {
|
|
18457
18507
|
py.__sbxSlot.current = binding;
|
|
@@ -18725,6 +18775,67 @@ async function runCPythonRepl(ctx) {
|
|
|
18725
18775
|
}
|
|
18726
18776
|
return 0;
|
|
18727
18777
|
}
|
|
18778
|
+
var PIP_PY = `
|
|
18779
|
+
import json, re
|
|
18780
|
+
|
|
18781
|
+
import micropip
|
|
18782
|
+
|
|
18783
|
+
_MISSING = re.compile(r"Can't find a pure Python 3 wheel for '([^']+)'")
|
|
18784
|
+
_EXTRAS = re.compile(r"^\\s*([A-Za-z0-9._-]+)\\s*\\[([^\\]]+)\\](.*)$")
|
|
18785
|
+
|
|
18786
|
+
|
|
18787
|
+
def _name_of(spec):
|
|
18788
|
+
return re.split(r"[\\[<>=!~;\\s]", spec.strip(), 1)[0]
|
|
18789
|
+
|
|
18790
|
+
|
|
18791
|
+
def _installed_version(name):
|
|
18792
|
+
try:
|
|
18793
|
+
found = micropip.list()[name.replace("_", "-").lower()]
|
|
18794
|
+
return getattr(found, "version", None)
|
|
18795
|
+
except Exception:
|
|
18796
|
+
return None
|
|
18797
|
+
|
|
18798
|
+
|
|
18799
|
+
async def _install_one(spec):
|
|
18800
|
+
"""Install one requirement, retrying without extras if they are impossible."""
|
|
18801
|
+
attempt = spec
|
|
18802
|
+
dropped = None
|
|
18803
|
+
while True:
|
|
18804
|
+
try:
|
|
18805
|
+
await micropip.install(attempt)
|
|
18806
|
+
except ValueError as error:
|
|
18807
|
+
message = str(error)
|
|
18808
|
+
missing = _MISSING.findall(message)
|
|
18809
|
+
extras = _EXTRAS.match(attempt)
|
|
18810
|
+
if missing and extras and dropped is None:
|
|
18811
|
+
dropped = [e.strip() for e in extras.group(2).split(",")]
|
|
18812
|
+
attempt = extras.group(1) + extras.group(3)
|
|
18813
|
+
continue
|
|
18814
|
+
return {
|
|
18815
|
+
"spec": spec, "ok": False, "missing": missing,
|
|
18816
|
+
"reason": message.strip().split("\\n")[0],
|
|
18817
|
+
}
|
|
18818
|
+
except Exception as error:
|
|
18819
|
+
return {"spec": spec, "ok": False, "missing": [], "reason": str(error).strip().split("\\n")[0]}
|
|
18820
|
+
|
|
18821
|
+
name = _name_of(attempt)
|
|
18822
|
+
return {
|
|
18823
|
+
"spec": spec, "ok": True, "name": name,
|
|
18824
|
+
"version": _installed_version(name), "dropped": dropped,
|
|
18825
|
+
}
|
|
18826
|
+
|
|
18827
|
+
|
|
18828
|
+
async def __sbx_pip(specs_json):
|
|
18829
|
+
results = []
|
|
18830
|
+
for spec in json.loads(specs_json):
|
|
18831
|
+
try:
|
|
18832
|
+
results.append(await _install_one(spec))
|
|
18833
|
+
except Exception as error:
|
|
18834
|
+
results.append({"spec": spec, "ok": False, "missing": [], "reason": str(error)})
|
|
18835
|
+
return json.dumps(results)
|
|
18836
|
+
|
|
18837
|
+
__sbx_pip
|
|
18838
|
+
`;
|
|
18728
18839
|
var micropip = defineCommand({
|
|
18729
18840
|
name: "micropip",
|
|
18730
18841
|
path: "/usr/bin/micropip",
|
|
@@ -18762,8 +18873,7 @@ var micropip = defineCommand({
|
|
|
18762
18873
|
ctx.stderr.write("pip: no packages specified\n");
|
|
18763
18874
|
return 1;
|
|
18764
18875
|
}
|
|
18765
|
-
|
|
18766
|
-
if (!ctx.kernel.net.outboundAllowed(index)) {
|
|
18876
|
+
if (!ctx.kernel.net.outboundAllowed("https://pypi.org")) {
|
|
18767
18877
|
ctx.stderr.write(
|
|
18768
18878
|
"pip: outbound network access is disabled for this container (enable with network: { allowOutbound: true })\n"
|
|
18769
18879
|
);
|
|
@@ -18776,22 +18886,42 @@ var micropip = defineCommand({
|
|
|
18776
18886
|
ctx.stderr.write("pip: Pyodide is unavailable in this host\n");
|
|
18777
18887
|
return 127;
|
|
18778
18888
|
}
|
|
18889
|
+
let outcomes;
|
|
18779
18890
|
try {
|
|
18780
18891
|
await py.loadPackage("micropip");
|
|
18781
|
-
const
|
|
18782
|
-
|
|
18783
|
-
|
|
18784
|
-
await micropipModule.install(name);
|
|
18785
|
-
ctx.line(`Successfully installed ${name}`);
|
|
18786
|
-
}
|
|
18787
|
-
return 0;
|
|
18892
|
+
for (const name of packages) ctx.line(`Collecting ${name}`);
|
|
18893
|
+
const install2 = py.runPython(PIP_PY);
|
|
18894
|
+
outcomes = JSON.parse(String(await install2(JSON.stringify(packages))));
|
|
18788
18895
|
} catch (error) {
|
|
18789
18896
|
ctx.stderr.write(
|
|
18790
|
-
`
|
|
18897
|
+
`pip: installation failed: ${error instanceof Error ? error.message : String(error)}
|
|
18791
18898
|
`
|
|
18792
18899
|
);
|
|
18793
18900
|
return 1;
|
|
18794
18901
|
}
|
|
18902
|
+
const installed2 = [];
|
|
18903
|
+
for (const outcome of outcomes) {
|
|
18904
|
+
if (outcome.ok) {
|
|
18905
|
+
installed2.push(
|
|
18906
|
+
outcome.version ? `${outcome.name}-${outcome.version}` : String(outcome.name)
|
|
18907
|
+
);
|
|
18908
|
+
if (outcome.dropped?.length) {
|
|
18909
|
+
ctx.stderr.write(
|
|
18910
|
+
` WARNING: ${outcome.name}: the ${outcome.dropped.map((extra) => `'${extra}'`).join(", ")} extra needs native code with no WebAssembly build; installed ${outcome.name} without it
|
|
18911
|
+
`
|
|
18912
|
+
);
|
|
18913
|
+
}
|
|
18914
|
+
continue;
|
|
18915
|
+
}
|
|
18916
|
+
const missing = outcome.missing ?? [];
|
|
18917
|
+
ctx.stderr.write(
|
|
18918
|
+
missing.length > 0 ? `ERROR: could not install ${outcome.spec}: no WebAssembly build exists for ${missing.map((name) => name.split(/[<>=!~;\s]/)[0]).join(", ")}
|
|
18919
|
+
` : `ERROR: could not install ${outcome.spec}: ${outcome.reason ?? "unknown error"}
|
|
18920
|
+
`
|
|
18921
|
+
);
|
|
18922
|
+
}
|
|
18923
|
+
if (installed2.length > 0) ctx.line(`Successfully installed ${installed2.join(" ")}`);
|
|
18924
|
+
return outcomes.every((outcome) => outcome.ok) ? 0 : 1;
|
|
18795
18925
|
}
|
|
18796
18926
|
});
|
|
18797
18927
|
|