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.cjs
CHANGED
|
@@ -18185,6 +18185,55 @@ def _install_processes():
|
|
|
18185
18185
|
|
|
18186
18186
|
_install_processes()
|
|
18187
18187
|
`;
|
|
18188
|
+
var ASYNCIO_PY = `
|
|
18189
|
+
import asyncio
|
|
18190
|
+
from pyodide.ffi import can_run_sync, run_sync
|
|
18191
|
+
|
|
18192
|
+
_orig_run = asyncio.run
|
|
18193
|
+
|
|
18194
|
+
|
|
18195
|
+
def _run(main, *, debug=None, loop_factory=None):
|
|
18196
|
+
if not asyncio.iscoroutine(main) and not asyncio.isfuture(main):
|
|
18197
|
+
raise ValueError("a coroutine was expected, got {!r}".format(main))
|
|
18198
|
+
if not can_run_sync():
|
|
18199
|
+
# No stack switching: the original at least raises a comprehensible
|
|
18200
|
+
# error rather than this shim inventing a new one.
|
|
18201
|
+
return _orig_run(main, debug=debug, loop_factory=loop_factory)
|
|
18202
|
+
return run_sync(main)
|
|
18203
|
+
|
|
18204
|
+
|
|
18205
|
+
def _run_until_complete(self, future):
|
|
18206
|
+
if not can_run_sync():
|
|
18207
|
+
raise RuntimeError(
|
|
18208
|
+
"cannot wait for a coroutine on this host: WebAssembly stack "
|
|
18209
|
+
"switching (JSPI) is unavailable."
|
|
18210
|
+
)
|
|
18211
|
+
return run_sync(future)
|
|
18212
|
+
|
|
18213
|
+
|
|
18214
|
+
async def _create_server(self, *args, **kwargs):
|
|
18215
|
+
# Pyodide's loop raises a bare NotImplementedError from deep inside
|
|
18216
|
+
# asyncio, which tells a reader nothing about why their server will not
|
|
18217
|
+
# start. Naming the limit is the least this can do until the container can
|
|
18218
|
+
# route connections to Python.
|
|
18219
|
+
raise NotImplementedError(
|
|
18220
|
+
"this container cannot yet accept network connections from Python: "
|
|
18221
|
+
"asyncio's create_server is not implemented on Pyodide's event loop, "
|
|
18222
|
+
"so an ASGI/WSGI server such as uvicorn will install and import but "
|
|
18223
|
+
"not bind a port. Outbound requests do work."
|
|
18224
|
+
)
|
|
18225
|
+
|
|
18226
|
+
|
|
18227
|
+
def _install_asyncio():
|
|
18228
|
+
asyncio.run = _run
|
|
18229
|
+
asyncio.runners.run = _run
|
|
18230
|
+
loop_type = type(asyncio.get_event_loop())
|
|
18231
|
+
loop_type.run_until_complete = _run_until_complete
|
|
18232
|
+
loop_type.create_server = _create_server
|
|
18233
|
+
|
|
18234
|
+
|
|
18235
|
+
_install_asyncio()
|
|
18236
|
+
`;
|
|
18188
18237
|
var NETWORK_PY = `
|
|
18189
18238
|
import builtins, email.message, io, sys, urllib.error, urllib.request, urllib.response
|
|
18190
18239
|
import _sbx_host as _host
|
|
@@ -18469,6 +18518,7 @@ function installSyscallBridge(py) {
|
|
|
18469
18518
|
py.runPython(BRIDGE_PY);
|
|
18470
18519
|
py.runPython(PROCESS_PY);
|
|
18471
18520
|
py.runPython(NETWORK_PY);
|
|
18521
|
+
py.runPython(ASYNCIO_PY);
|
|
18472
18522
|
}
|
|
18473
18523
|
function bindProgram(py, binding) {
|
|
18474
18524
|
py.__sbxSlot.current = binding;
|
|
@@ -18742,6 +18792,67 @@ async function runCPythonRepl(ctx) {
|
|
|
18742
18792
|
}
|
|
18743
18793
|
return 0;
|
|
18744
18794
|
}
|
|
18795
|
+
var PIP_PY = `
|
|
18796
|
+
import json, re
|
|
18797
|
+
|
|
18798
|
+
import micropip
|
|
18799
|
+
|
|
18800
|
+
_MISSING = re.compile(r"Can't find a pure Python 3 wheel for '([^']+)'")
|
|
18801
|
+
_EXTRAS = re.compile(r"^\\s*([A-Za-z0-9._-]+)\\s*\\[([^\\]]+)\\](.*)$")
|
|
18802
|
+
|
|
18803
|
+
|
|
18804
|
+
def _name_of(spec):
|
|
18805
|
+
return re.split(r"[\\[<>=!~;\\s]", spec.strip(), 1)[0]
|
|
18806
|
+
|
|
18807
|
+
|
|
18808
|
+
def _installed_version(name):
|
|
18809
|
+
try:
|
|
18810
|
+
found = micropip.list()[name.replace("_", "-").lower()]
|
|
18811
|
+
return getattr(found, "version", None)
|
|
18812
|
+
except Exception:
|
|
18813
|
+
return None
|
|
18814
|
+
|
|
18815
|
+
|
|
18816
|
+
async def _install_one(spec):
|
|
18817
|
+
"""Install one requirement, retrying without extras if they are impossible."""
|
|
18818
|
+
attempt = spec
|
|
18819
|
+
dropped = None
|
|
18820
|
+
while True:
|
|
18821
|
+
try:
|
|
18822
|
+
await micropip.install(attempt)
|
|
18823
|
+
except ValueError as error:
|
|
18824
|
+
message = str(error)
|
|
18825
|
+
missing = _MISSING.findall(message)
|
|
18826
|
+
extras = _EXTRAS.match(attempt)
|
|
18827
|
+
if missing and extras and dropped is None:
|
|
18828
|
+
dropped = [e.strip() for e in extras.group(2).split(",")]
|
|
18829
|
+
attempt = extras.group(1) + extras.group(3)
|
|
18830
|
+
continue
|
|
18831
|
+
return {
|
|
18832
|
+
"spec": spec, "ok": False, "missing": missing,
|
|
18833
|
+
"reason": message.strip().split("\\n")[0],
|
|
18834
|
+
}
|
|
18835
|
+
except Exception as error:
|
|
18836
|
+
return {"spec": spec, "ok": False, "missing": [], "reason": str(error).strip().split("\\n")[0]}
|
|
18837
|
+
|
|
18838
|
+
name = _name_of(attempt)
|
|
18839
|
+
return {
|
|
18840
|
+
"spec": spec, "ok": True, "name": name,
|
|
18841
|
+
"version": _installed_version(name), "dropped": dropped,
|
|
18842
|
+
}
|
|
18843
|
+
|
|
18844
|
+
|
|
18845
|
+
async def __sbx_pip(specs_json):
|
|
18846
|
+
results = []
|
|
18847
|
+
for spec in json.loads(specs_json):
|
|
18848
|
+
try:
|
|
18849
|
+
results.append(await _install_one(spec))
|
|
18850
|
+
except Exception as error:
|
|
18851
|
+
results.append({"spec": spec, "ok": False, "missing": [], "reason": str(error)})
|
|
18852
|
+
return json.dumps(results)
|
|
18853
|
+
|
|
18854
|
+
__sbx_pip
|
|
18855
|
+
`;
|
|
18745
18856
|
var micropip = defineCommand({
|
|
18746
18857
|
name: "micropip",
|
|
18747
18858
|
path: "/usr/bin/micropip",
|
|
@@ -18779,8 +18890,7 @@ var micropip = defineCommand({
|
|
|
18779
18890
|
ctx.stderr.write("pip: no packages specified\n");
|
|
18780
18891
|
return 1;
|
|
18781
18892
|
}
|
|
18782
|
-
|
|
18783
|
-
if (!ctx.kernel.net.outboundAllowed(index)) {
|
|
18893
|
+
if (!ctx.kernel.net.outboundAllowed("https://pypi.org")) {
|
|
18784
18894
|
ctx.stderr.write(
|
|
18785
18895
|
"pip: outbound network access is disabled for this container (enable with network: { allowOutbound: true })\n"
|
|
18786
18896
|
);
|
|
@@ -18793,22 +18903,42 @@ var micropip = defineCommand({
|
|
|
18793
18903
|
ctx.stderr.write("pip: Pyodide is unavailable in this host\n");
|
|
18794
18904
|
return 127;
|
|
18795
18905
|
}
|
|
18906
|
+
let outcomes;
|
|
18796
18907
|
try {
|
|
18797
18908
|
await py.loadPackage("micropip");
|
|
18798
|
-
const
|
|
18799
|
-
|
|
18800
|
-
|
|
18801
|
-
await micropipModule.install(name);
|
|
18802
|
-
ctx.line(`Successfully installed ${name}`);
|
|
18803
|
-
}
|
|
18804
|
-
return 0;
|
|
18909
|
+
for (const name of packages) ctx.line(`Collecting ${name}`);
|
|
18910
|
+
const install2 = py.runPython(PIP_PY);
|
|
18911
|
+
outcomes = JSON.parse(String(await install2(JSON.stringify(packages))));
|
|
18805
18912
|
} catch (error) {
|
|
18806
18913
|
ctx.stderr.write(
|
|
18807
|
-
`
|
|
18914
|
+
`pip: installation failed: ${error instanceof Error ? error.message : String(error)}
|
|
18808
18915
|
`
|
|
18809
18916
|
);
|
|
18810
18917
|
return 1;
|
|
18811
18918
|
}
|
|
18919
|
+
const installed2 = [];
|
|
18920
|
+
for (const outcome of outcomes) {
|
|
18921
|
+
if (outcome.ok) {
|
|
18922
|
+
installed2.push(
|
|
18923
|
+
outcome.version ? `${outcome.name}-${outcome.version}` : String(outcome.name)
|
|
18924
|
+
);
|
|
18925
|
+
if (outcome.dropped?.length) {
|
|
18926
|
+
ctx.stderr.write(
|
|
18927
|
+
` WARNING: ${outcome.name}: the ${outcome.dropped.map((extra) => `'${extra}'`).join(", ")} extra needs native code with no WebAssembly build; installed ${outcome.name} without it
|
|
18928
|
+
`
|
|
18929
|
+
);
|
|
18930
|
+
}
|
|
18931
|
+
continue;
|
|
18932
|
+
}
|
|
18933
|
+
const missing = outcome.missing ?? [];
|
|
18934
|
+
ctx.stderr.write(
|
|
18935
|
+
missing.length > 0 ? `ERROR: could not install ${outcome.spec}: no WebAssembly build exists for ${missing.map((name) => name.split(/[<>=!~;\s]/)[0]).join(", ")}
|
|
18936
|
+
` : `ERROR: could not install ${outcome.spec}: ${outcome.reason ?? "unknown error"}
|
|
18937
|
+
`
|
|
18938
|
+
);
|
|
18939
|
+
}
|
|
18940
|
+
if (installed2.length > 0) ctx.line(`Successfully installed ${installed2.join(" ")}`);
|
|
18941
|
+
return outcomes.every((outcome) => outcome.ok) ? 0 : 1;
|
|
18812
18942
|
}
|
|
18813
18943
|
});
|
|
18814
18944
|
|