sandboxedjs 0.1.16 → 0.1.18
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 +28 -20
- package/dist/index.cjs +300 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -2
- package/dist/index.d.ts +50 -2
- package/dist/index.js +299 -12
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@ Node 18.17+. Everything is pure JavaScript and WebAssembly — no compilation st
|
|
|
44
44
|
| **Shell** | POSIX `sh` (54 builtins) — pipelines, redirection, here-docs, globbing, brace/parameter/arithmetic/command expansion, functions, `if`/`for`/`while`/`case`/`select`, job control, traps, arrays, `[[ ]]`, `(( ))` |
|
|
45
45
|
| **Coreutils** | 154 programs — `ls cat cp mv rm mkdir grep sed awk find head tail sort uniq wc cut tr tee xargs chmod chown ln du df ps tar gzip base64 sha256sum diff curl wget` and the rest — plus 54 shell builtins |
|
|
46
46
|
| **Node.js** | Real Node semantics via Nodepod — `require`, npm packages, `http`, `fs`, streams, `worker_threads` |
|
|
47
|
-
| **Python** |
|
|
47
|
+
| **Python** | CPython 3.13 (Pyodide) on the *same* filesystem, with the real standard library |
|
|
48
48
|
| **FFmpeg** | `ffmpeg` and `ffprobe` (FFmpeg 5.1) reading and writing container files directly — [optional install](#video-and-audio) |
|
|
49
49
|
| **`/proc`** | Live and synthesised — `ps`, `top`, `free` and `uptime` all read the same source |
|
|
50
50
|
| **Networking** | Virtual interfaces, `/etc/hosts` resolution, in-container HTTP servers, an optional bridge to a real host port |
|
|
@@ -404,7 +404,7 @@ your disk.
|
|
|
404
404
|
|
|
405
405
|
### Python
|
|
406
406
|
|
|
407
|
-
Python is
|
|
407
|
+
Python is CPython 3.13, via Pyodide, mounted on the container's filesystem:
|
|
408
408
|
|
|
409
409
|
```ts
|
|
410
410
|
await box.exec("python3 -c \"print(open('/etc/hostname').read())\"");
|
|
@@ -414,7 +414,7 @@ await box.exec("echo '1 2 3' | python3 -c \"import sys; print(sum(map(int, sys.s
|
|
|
414
414
|
|
|
415
415
|
The bundled standard library includes `json`, `re`, `os`, `sys`, `math`, `random`, `hashlib`,
|
|
416
416
|
`binascii`, `struct`, `time`, `collections`, `itertools`, `functools`, `asyncio` and more. It is
|
|
417
|
-
|
|
417
|
+
Real CPython, so `sqlite3`, `dataclasses`, `decimal` and `typing` all work. Packages must be built for WebAssembly: `micropip` installs pure-Python wheels, and Pyodide's own distribution covers the rest
|
|
418
418
|
(and only with outbound networking enabled).
|
|
419
419
|
|
|
420
420
|
### Filesystem from the host
|
|
@@ -478,7 +478,7 @@ line is measured on the spot rather than claimed, so a runtime that is missing s
|
|
|
478
478
|
sandboxedjs — a Linux-like container inside Node.js
|
|
479
479
|
|
|
480
480
|
node v22.12.0 npm, require, http servers
|
|
481
|
-
python3
|
|
481
|
+
python3 CPython 3.13 only WebAssembly-built C extensions
|
|
482
482
|
ffmpeg 5.1.4 video and audio
|
|
483
483
|
network on npm install reaches the real registry
|
|
484
484
|
```
|
|
@@ -633,33 +633,35 @@ Those use dynamic imports, so they only fail if you call them.
|
|
|
633
633
|
|
|
634
634
|
### Python in a browser
|
|
635
635
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
The first is ours and is fixed: Emscripten resolves `micropython.wasm` against the loader's own
|
|
639
|
-
directory, which is right in Node and wrong once a bundler has rewritten the loader into a hashed
|
|
640
|
-
chunk — the guess lands on a path the dev server answers with `index.html`, and instantiation
|
|
641
|
-
dies on `expected magic word 00 61 73 6d, found 3c 21 64 6f` (the first bytes of `<!doctype`).
|
|
642
|
-
Pass the real URL and that goes away:
|
|
636
|
+
Node resolves Pyodide from the installed package. A browser cannot resolve it by name, so tell it
|
|
637
|
+
where the module and the assets are — a CDN is fine:
|
|
643
638
|
|
|
644
639
|
```ts
|
|
645
|
-
import
|
|
640
|
+
import { configurePython, createContainer } from "sandboxedjs";
|
|
641
|
+
|
|
642
|
+
configurePython({
|
|
643
|
+
engine: "cpython",
|
|
644
|
+
pyodideURL: "https://cdn.jsdelivr.net/pyodide/v0.28.3/full/pyodide.mjs",
|
|
645
|
+
indexURL: "https://cdn.jsdelivr.net/pyodide/v0.28.3/full/",
|
|
646
|
+
});
|
|
646
647
|
|
|
647
|
-
await createContainer(
|
|
648
|
+
const box = await createContainer();
|
|
649
|
+
await box.exec("python3 -c 'import sqlite3; print(sqlite3.sqlite_version)'");
|
|
648
650
|
```
|
|
649
651
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
+
Without that, `engine: "auto"` finds no interpreter and falls back to MicroPython, which is why a
|
|
653
|
+
browser build of this package carries no Python runtime it was not asked for.
|
|
652
654
|
|
|
653
|
-
|
|
655
|
+
**MicroPython in a browser still does not start**, and that part is upstream. With the correct
|
|
656
|
+
`.wasm` loaded — see `configurePython({ wasmUrl })` — instantiation fails on
|
|
654
657
|
|
|
655
658
|
```
|
|
656
659
|
LinkError: Import #45 "env" "__syscall_poll_nonblocking": function import requires a callable
|
|
657
660
|
```
|
|
658
661
|
|
|
659
662
|
The symbol appears nowhere in the shipped `micropython.mjs`, so the published glue and `.wasm`
|
|
660
|
-
disagree about their import table. Node is unaffected
|
|
661
|
-
|
|
662
|
-
the upstream package ships a matching pair.
|
|
663
|
+
disagree about their import table. Node is unaffected. Since CPython is now the default engine,
|
|
664
|
+
this only matters if you have deliberately pinned `engine: "micropython"` in a browser.
|
|
663
665
|
|
|
664
666
|
## Uploading files
|
|
665
667
|
|
|
@@ -744,7 +746,13 @@ Honest list of what does not work:
|
|
|
744
746
|
This affects older toolchains — Vite 4 and its contemporaries. Current Vite ships its Rust
|
|
745
747
|
pipeline as WebAssembly and runs fine, dev server included, as do Express, Koa, Fastify-style
|
|
746
748
|
apps and plain `http` servers.
|
|
747
|
-
- **Python is
|
|
749
|
+
- **Python is CPython via Pyodide.** The standard library is the real one. A C
|
|
750
|
+
extension works only if it has been built for WebAssembly — Pyodide ships
|
|
751
|
+
many, including `numpy`, but an arbitrary wheel from PyPI will not install.
|
|
752
|
+
Starting an interpreter costs about a second and a half; one is kept per
|
|
753
|
+
container, and each program runs in its own namespace.
|
|
754
|
+
- **MicroPython is still there** for hosts that would rather not carry a 13 MB
|
|
755
|
+
interpreter: `configurePython({ engine: "micropython" })`.
|
|
748
756
|
- **No real sockets.** HTTP servers work through the request proxy; raw TCP/UDP does not.
|
|
749
757
|
- **No real processes.** Processes are cooperative async tasks: `kill -9` cannot interrupt a
|
|
750
758
|
tight synchronous loop, and `SIGSTOP` only marks state.
|
package/dist/index.cjs
CHANGED
|
@@ -21941,6 +21941,7 @@ function mountContainerFs(FS, opts) {
|
|
|
21941
21941
|
if (isSysError(e)) return throwErrno(e.code);
|
|
21942
21942
|
throw new FS.ErrnoError(emErrno("EIO"));
|
|
21943
21943
|
};
|
|
21944
|
+
const mountRoot = opts.mountAt ? normalize(opts.mountAt) : "/";
|
|
21944
21945
|
const backend = {
|
|
21945
21946
|
/** Absolute container path for a node. */
|
|
21946
21947
|
realPath(node2) {
|
|
@@ -21950,7 +21951,9 @@ function mountContainerFs(FS, opts) {
|
|
|
21950
21951
|
parts.unshift(current.name);
|
|
21951
21952
|
current = current.parent;
|
|
21952
21953
|
}
|
|
21953
|
-
|
|
21954
|
+
const relative2 = parts.join("/");
|
|
21955
|
+
if (mountRoot === "/") return "/" + relative2;
|
|
21956
|
+
return relative2 ? join(mountRoot, relative2) : mountRoot;
|
|
21954
21957
|
},
|
|
21955
21958
|
mount(_mount) {
|
|
21956
21959
|
return backend.createNode(null, "/", 16877 | 0, 0);
|
|
@@ -22140,6 +22143,14 @@ function mountContainerFs(FS, opts) {
|
|
|
22140
22143
|
return position;
|
|
22141
22144
|
}
|
|
22142
22145
|
};
|
|
22146
|
+
if (opts.mountAt) {
|
|
22147
|
+
try {
|
|
22148
|
+
FS.mkdir(mountRoot);
|
|
22149
|
+
} catch {
|
|
22150
|
+
}
|
|
22151
|
+
FS.mount(backend, {}, mountRoot);
|
|
22152
|
+
return;
|
|
22153
|
+
}
|
|
22143
22154
|
FS.root = null;
|
|
22144
22155
|
FS.mount(backend, {}, "/");
|
|
22145
22156
|
try {
|
|
@@ -22148,13 +22159,286 @@ function mountContainerFs(FS, opts) {
|
|
|
22148
22159
|
}
|
|
22149
22160
|
}
|
|
22150
22161
|
|
|
22162
|
+
// src/runtime/cpython.ts
|
|
22163
|
+
var RESERVED_FOR_INTERPRETER = /* @__PURE__ */ new Set(["lib", "dev", "proc"]);
|
|
22164
|
+
var pyodideModule = null;
|
|
22165
|
+
var indexUrl;
|
|
22166
|
+
var moduleUrl;
|
|
22167
|
+
function configureCPython(options = {}) {
|
|
22168
|
+
if (options.indexURL !== void 0) indexUrl = options.indexURL;
|
|
22169
|
+
if (options.moduleURL !== void 0) {
|
|
22170
|
+
moduleUrl = options.moduleURL;
|
|
22171
|
+
pyodideModule = null;
|
|
22172
|
+
}
|
|
22173
|
+
}
|
|
22174
|
+
function importPyodide() {
|
|
22175
|
+
if (!pyodideModule) {
|
|
22176
|
+
const specifier = moduleUrl ?? ["py", "odide"].join("");
|
|
22177
|
+
pyodideModule = import(
|
|
22178
|
+
/* @vite-ignore */
|
|
22179
|
+
/* webpackIgnore: true */
|
|
22180
|
+
specifier
|
|
22181
|
+
);
|
|
22182
|
+
}
|
|
22183
|
+
return pyodideModule;
|
|
22184
|
+
}
|
|
22185
|
+
var isNode2 = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
|
|
22186
|
+
async function resolveIndexUrl() {
|
|
22187
|
+
if (indexUrl) return indexUrl;
|
|
22188
|
+
if (!isNode2) return void 0;
|
|
22189
|
+
try {
|
|
22190
|
+
const { createRequire } = await nodeBuiltin("module");
|
|
22191
|
+
const path = await nodeBuiltin("path");
|
|
22192
|
+
const require2 = createRequire(path.join(process.cwd(), "index.js"));
|
|
22193
|
+
return `${path.dirname(require2.resolve("pyodide/package.json"))}/`;
|
|
22194
|
+
} catch {
|
|
22195
|
+
return void 0;
|
|
22196
|
+
}
|
|
22197
|
+
}
|
|
22198
|
+
async function isCPythonAvailable() {
|
|
22199
|
+
try {
|
|
22200
|
+
await importPyodide();
|
|
22201
|
+
return true;
|
|
22202
|
+
} catch {
|
|
22203
|
+
return false;
|
|
22204
|
+
}
|
|
22205
|
+
}
|
|
22206
|
+
var interpreters = /* @__PURE__ */ new WeakMap();
|
|
22207
|
+
async function interpreterFor(ctx) {
|
|
22208
|
+
const existing = interpreters.get(ctx.vfs);
|
|
22209
|
+
if (existing) return existing;
|
|
22210
|
+
const starting = (async () => {
|
|
22211
|
+
const { loadPyodide } = await importPyodide();
|
|
22212
|
+
const resolved = await resolveIndexUrl();
|
|
22213
|
+
const py = await loadPyodide({
|
|
22214
|
+
...resolved ? { indexURL: resolved } : {},
|
|
22215
|
+
/* Output is rebound per program; these only catch anything printed
|
|
22216
|
+
* while the interpreter is still starting. */
|
|
22217
|
+
stdout: () => {
|
|
22218
|
+
},
|
|
22219
|
+
stderr: () => {
|
|
22220
|
+
}
|
|
22221
|
+
});
|
|
22222
|
+
mountContainerDirs(py, ctx);
|
|
22223
|
+
installRunner(py);
|
|
22224
|
+
return py;
|
|
22225
|
+
})();
|
|
22226
|
+
interpreters.set(ctx.vfs, starting);
|
|
22227
|
+
try {
|
|
22228
|
+
return await starting;
|
|
22229
|
+
} catch (error) {
|
|
22230
|
+
interpreters.delete(ctx.vfs);
|
|
22231
|
+
throw error;
|
|
22232
|
+
}
|
|
22233
|
+
}
|
|
22234
|
+
function installRunner(py) {
|
|
22235
|
+
py.__sbxRun = py.runPython(`
|
|
22236
|
+
from pyodide.code import eval_code_async
|
|
22237
|
+
|
|
22238
|
+
async def __sbx_run(source, scope):
|
|
22239
|
+
try:
|
|
22240
|
+
await eval_code_async(source, globals=scope)
|
|
22241
|
+
return 0
|
|
22242
|
+
except SystemExit as exit:
|
|
22243
|
+
code = exit.code
|
|
22244
|
+
if code is None:
|
|
22245
|
+
return 0
|
|
22246
|
+
return code if isinstance(code, int) else 1
|
|
22247
|
+
|
|
22248
|
+
__sbx_run
|
|
22249
|
+
`);
|
|
22250
|
+
}
|
|
22251
|
+
function mountContainerDirs(py, ctx) {
|
|
22252
|
+
const mounted = py.__sbxMounted ??= /* @__PURE__ */ new Set();
|
|
22253
|
+
let entries;
|
|
22254
|
+
try {
|
|
22255
|
+
entries = ctx.vfs.readdirWithTypes("/", ctx.cred);
|
|
22256
|
+
} catch {
|
|
22257
|
+
return;
|
|
22258
|
+
}
|
|
22259
|
+
for (const entry of entries) {
|
|
22260
|
+
if (entry.kind !== "directory") continue;
|
|
22261
|
+
if (RESERVED_FOR_INTERPRETER.has(entry.name)) continue;
|
|
22262
|
+
if (mounted.has(entry.name)) continue;
|
|
22263
|
+
try {
|
|
22264
|
+
mountContainerFs(py.FS, {
|
|
22265
|
+
vfs: ctx.vfs,
|
|
22266
|
+
cred: ctx.cred,
|
|
22267
|
+
mountAt: `/${entry.name}`
|
|
22268
|
+
});
|
|
22269
|
+
mounted.add(entry.name);
|
|
22270
|
+
} catch {
|
|
22271
|
+
}
|
|
22272
|
+
}
|
|
22273
|
+
}
|
|
22274
|
+
function bootstrap(py, ctx, argv, scriptDir) {
|
|
22275
|
+
const paths = [
|
|
22276
|
+
...scriptDir ? [scriptDir] : [""],
|
|
22277
|
+
"/usr/lib/python3",
|
|
22278
|
+
"/usr/lib/python3/site-packages",
|
|
22279
|
+
"/usr/local/lib/python3/site-packages"
|
|
22280
|
+
];
|
|
22281
|
+
py.runPython(`
|
|
22282
|
+
import sys, os
|
|
22283
|
+
sys.argv[:] = ${JSON.stringify(argv)}
|
|
22284
|
+
for __p in reversed(${JSON.stringify(paths)}):
|
|
22285
|
+
if __p and __p not in sys.path:
|
|
22286
|
+
sys.path.insert(0, __p)
|
|
22287
|
+
elif __p == "" and "" not in sys.path:
|
|
22288
|
+
sys.path.insert(0, "")
|
|
22289
|
+
try:
|
|
22290
|
+
del __p
|
|
22291
|
+
except NameError:
|
|
22292
|
+
pass
|
|
22293
|
+
os.environ.clear()
|
|
22294
|
+
os.environ.update(${JSON.stringify(ctx.env)})
|
|
22295
|
+
`);
|
|
22296
|
+
try {
|
|
22297
|
+
py.FS.chdir(ctx.cwd);
|
|
22298
|
+
} catch {
|
|
22299
|
+
}
|
|
22300
|
+
}
|
|
22301
|
+
function reportError(ctx, error) {
|
|
22302
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
22303
|
+
const systemExit = /SystemExit:?\s*(-?\d+)?/.exec(message);
|
|
22304
|
+
if (systemExit) {
|
|
22305
|
+
return systemExit[1] !== void 0 ? Number(systemExit[1]) & 255 : 0;
|
|
22306
|
+
}
|
|
22307
|
+
if (/KeyboardInterrupt/.test(message)) {
|
|
22308
|
+
ctx.stderr.write("KeyboardInterrupt\n");
|
|
22309
|
+
return 130;
|
|
22310
|
+
}
|
|
22311
|
+
const text = message.replace(/^PythonError:\s*/, "");
|
|
22312
|
+
ctx.stderr.write(text.endsWith("\n") ? text : `${text}
|
|
22313
|
+
`);
|
|
22314
|
+
return 1;
|
|
22315
|
+
}
|
|
22316
|
+
async function runCPythonProgram(ctx, source, argv, scriptDir, stdinText) {
|
|
22317
|
+
let py;
|
|
22318
|
+
try {
|
|
22319
|
+
py = await interpreterFor(ctx);
|
|
22320
|
+
} catch (error) {
|
|
22321
|
+
ctx.stderr.write(
|
|
22322
|
+
`python3: CPython is unavailable in this host (${error instanceof Error ? error.message : String(error)})
|
|
22323
|
+
`
|
|
22324
|
+
);
|
|
22325
|
+
return { exitCode: 127 };
|
|
22326
|
+
}
|
|
22327
|
+
mountContainerDirs(py, ctx);
|
|
22328
|
+
try {
|
|
22329
|
+
await py.loadPackagesFromImports(source, {
|
|
22330
|
+
messageCallback: () => {
|
|
22331
|
+
},
|
|
22332
|
+
errorCallback: () => {
|
|
22333
|
+
}
|
|
22334
|
+
});
|
|
22335
|
+
} catch {
|
|
22336
|
+
}
|
|
22337
|
+
const encoder6 = new TextEncoder();
|
|
22338
|
+
const decoder7 = new TextDecoder();
|
|
22339
|
+
py.setStdout({
|
|
22340
|
+
write: (buffer) => {
|
|
22341
|
+
ctx.write(decoder7.decode(buffer));
|
|
22342
|
+
return buffer.length;
|
|
22343
|
+
}
|
|
22344
|
+
});
|
|
22345
|
+
py.setStderr({
|
|
22346
|
+
write: (buffer) => {
|
|
22347
|
+
ctx.stderr.write(decoder7.decode(buffer));
|
|
22348
|
+
return buffer.length;
|
|
22349
|
+
}
|
|
22350
|
+
});
|
|
22351
|
+
if (stdinText !== null) {
|
|
22352
|
+
const bytes = encoder6.encode(stdinText);
|
|
22353
|
+
let offset = 0;
|
|
22354
|
+
py.setStdin({
|
|
22355
|
+
read: (buffer) => {
|
|
22356
|
+
const take = Math.min(buffer.length, bytes.length - offset);
|
|
22357
|
+
buffer.set(bytes.subarray(offset, offset + take));
|
|
22358
|
+
offset += take;
|
|
22359
|
+
return take;
|
|
22360
|
+
}
|
|
22361
|
+
});
|
|
22362
|
+
} else {
|
|
22363
|
+
py.setStdin({ read: () => 0 });
|
|
22364
|
+
}
|
|
22365
|
+
try {
|
|
22366
|
+
bootstrap(py, ctx, argv, scriptDir);
|
|
22367
|
+
} catch (error) {
|
|
22368
|
+
return { exitCode: reportError(ctx, error) };
|
|
22369
|
+
}
|
|
22370
|
+
const globals = py.globals.get("dict")();
|
|
22371
|
+
try {
|
|
22372
|
+
globals.set("__name__", "__main__");
|
|
22373
|
+
const exitCode = await py.__sbxRun(source, globals);
|
|
22374
|
+
return { exitCode: Number(exitCode) & 255 };
|
|
22375
|
+
} catch (error) {
|
|
22376
|
+
return { exitCode: reportError(ctx, error) };
|
|
22377
|
+
} finally {
|
|
22378
|
+
try {
|
|
22379
|
+
globals.destroy();
|
|
22380
|
+
} catch {
|
|
22381
|
+
}
|
|
22382
|
+
}
|
|
22383
|
+
}
|
|
22384
|
+
var micropip = defineCommand({
|
|
22385
|
+
name: "micropip",
|
|
22386
|
+
path: "/usr/bin/micropip",
|
|
22387
|
+
summary: "install Python packages into the running interpreter",
|
|
22388
|
+
usage: "micropip install <package>...",
|
|
22389
|
+
async run(ctx) {
|
|
22390
|
+
const [action, ...packages] = ctx.args;
|
|
22391
|
+
if (action !== "install" || packages.length === 0) {
|
|
22392
|
+
ctx.line("usage: micropip install <package>...");
|
|
22393
|
+
return action === void 0 ? 1 : 0;
|
|
22394
|
+
}
|
|
22395
|
+
let py;
|
|
22396
|
+
try {
|
|
22397
|
+
py = await interpreterFor(ctx);
|
|
22398
|
+
} catch {
|
|
22399
|
+
ctx.stderr.write("micropip: CPython is unavailable in this host\n");
|
|
22400
|
+
return 127;
|
|
22401
|
+
}
|
|
22402
|
+
try {
|
|
22403
|
+
await py.loadPackage("micropip");
|
|
22404
|
+
const micropipModule = py.pyimport("micropip");
|
|
22405
|
+
for (const name of packages) {
|
|
22406
|
+
ctx.line(`Collecting ${name}`);
|
|
22407
|
+
await micropipModule.install(name);
|
|
22408
|
+
ctx.line(`Successfully installed ${name}`);
|
|
22409
|
+
}
|
|
22410
|
+
return 0;
|
|
22411
|
+
} catch (error) {
|
|
22412
|
+
ctx.stderr.write(
|
|
22413
|
+
`micropip: ${error instanceof Error ? error.message : String(error)}
|
|
22414
|
+
`
|
|
22415
|
+
);
|
|
22416
|
+
return 1;
|
|
22417
|
+
}
|
|
22418
|
+
}
|
|
22419
|
+
});
|
|
22420
|
+
|
|
22151
22421
|
// src/runtime/python.ts
|
|
22152
22422
|
init_path();
|
|
22153
22423
|
var PYTHON_VERSION = "3.4.0";
|
|
22154
22424
|
var MICROPYTHON_BANNER = "MicroPython v1.28.0 on 2026-04-06; SandboxedJS with Emscripten";
|
|
22155
22425
|
var loaderPromise = null;
|
|
22156
22426
|
var wasmUrl;
|
|
22427
|
+
var engine = "auto";
|
|
22428
|
+
var cpythonUsable = null;
|
|
22429
|
+
async function useCPython() {
|
|
22430
|
+
if (engine === "micropython") return false;
|
|
22431
|
+
if (engine === "cpython") return true;
|
|
22432
|
+
cpythonUsable ??= isCPythonAvailable();
|
|
22433
|
+
return cpythonUsable;
|
|
22434
|
+
}
|
|
22157
22435
|
function configurePython(options = {}) {
|
|
22436
|
+
if (options.engine !== void 0) {
|
|
22437
|
+
engine = options.engine;
|
|
22438
|
+
cpythonUsable = null;
|
|
22439
|
+
}
|
|
22440
|
+
if (options.indexURL !== void 0) configureCPython({ indexURL: options.indexURL });
|
|
22441
|
+
if (options.pyodideURL !== void 0) configureCPython({ moduleURL: options.pyodideURL });
|
|
22158
22442
|
if (options.wasmUrl !== void 0) wasmUrl = options.wasmUrl;
|
|
22159
22443
|
}
|
|
22160
22444
|
async function getLoader() {
|
|
@@ -22229,6 +22513,9 @@ function reportPythonError(ctx, e) {
|
|
|
22229
22513
|
return 1;
|
|
22230
22514
|
}
|
|
22231
22515
|
async function runProgram(ctx, source, argv, scriptDir, stdinText) {
|
|
22516
|
+
if (await useCPython()) {
|
|
22517
|
+
return runCPythonProgram(ctx, source, argv, scriptDir, stdinText);
|
|
22518
|
+
}
|
|
22232
22519
|
let stdinOffset = 0;
|
|
22233
22520
|
const stdinBytes = stdinText === null ? new Uint8Array(0) : new TextEncoder().encode(stdinText);
|
|
22234
22521
|
const mp = await createInterpreter(ctx, {
|
|
@@ -22551,7 +22838,7 @@ async function readZip(data) {
|
|
|
22551
22838
|
return entries;
|
|
22552
22839
|
}
|
|
22553
22840
|
function pythonCommands() {
|
|
22554
|
-
return [python, pip];
|
|
22841
|
+
return [python, pip, micropip];
|
|
22555
22842
|
}
|
|
22556
22843
|
|
|
22557
22844
|
// src/runtime/ffmpeg.ts
|
|
@@ -22780,8 +23067,8 @@ function renameShadowedExports(source) {
|
|
|
22780
23067
|
for (const [key, value] of Object.entries(node2)) {
|
|
22781
23068
|
if (key === "type" || key === "start" || key === "end" || skip.includes(key)) continue;
|
|
22782
23069
|
if (Array.isArray(value)) {
|
|
22783
|
-
for (const item of value) if (
|
|
22784
|
-
} else if (
|
|
23070
|
+
for (const item of value) if (isNode3(item)) visit(item, childScope);
|
|
23071
|
+
} else if (isNode3(value)) {
|
|
22785
23072
|
visit(value, childScope);
|
|
22786
23073
|
}
|
|
22787
23074
|
}
|
|
@@ -22805,9 +23092,9 @@ function blockNames(body) {
|
|
|
22805
23092
|
for (const declarator of node2.declarations) {
|
|
22806
23093
|
collectPattern(declarator.id, names);
|
|
22807
23094
|
}
|
|
22808
|
-
} else if (node2.type === "ClassDeclaration" &&
|
|
23095
|
+
} else if (node2.type === "ClassDeclaration" && isNode3(node2.id)) {
|
|
22809
23096
|
names.add(node2.id.name);
|
|
22810
|
-
} else if (node2.type === "FunctionDeclaration" &&
|
|
23097
|
+
} else if (node2.type === "FunctionDeclaration" && isNode3(node2.id)) {
|
|
22811
23098
|
names.add(node2.id.name);
|
|
22812
23099
|
}
|
|
22813
23100
|
}
|
|
@@ -22818,10 +23105,10 @@ function collectVars(nodes, names) {
|
|
|
22818
23105
|
for (const item of nodes) collectVars(item, names);
|
|
22819
23106
|
return;
|
|
22820
23107
|
}
|
|
22821
|
-
if (!
|
|
23108
|
+
if (!isNode3(nodes)) return;
|
|
22822
23109
|
const node2 = nodes;
|
|
22823
23110
|
if (node2.type === "FunctionDeclaration" || node2.type === "FunctionExpression" || node2.type === "ArrowFunctionExpression") {
|
|
22824
|
-
if (
|
|
23111
|
+
if (isNode3(node2.id)) names.add(node2.id.name);
|
|
22825
23112
|
return;
|
|
22826
23113
|
}
|
|
22827
23114
|
if (node2.type === "VariableDeclaration" && node2.kind === "var") {
|
|
@@ -22835,7 +23122,7 @@ function collectVars(nodes, names) {
|
|
|
22835
23122
|
}
|
|
22836
23123
|
}
|
|
22837
23124
|
function collectPattern(node2, names) {
|
|
22838
|
-
if (!
|
|
23125
|
+
if (!isNode3(node2)) return;
|
|
22839
23126
|
switch (node2.type) {
|
|
22840
23127
|
case "Identifier":
|
|
22841
23128
|
names.add(node2.name);
|
|
@@ -22859,7 +23146,7 @@ function collectPattern(node2, names) {
|
|
|
22859
23146
|
}
|
|
22860
23147
|
}
|
|
22861
23148
|
function isExports(value) {
|
|
22862
|
-
return
|
|
23149
|
+
return isNode3(value) && value.type === "Identifier" && value.name === NAME;
|
|
22863
23150
|
}
|
|
22864
23151
|
function freshName(source) {
|
|
22865
23152
|
let name = "__sandboxedjs_exports";
|
|
@@ -22867,7 +23154,7 @@ function freshName(source) {
|
|
|
22867
23154
|
while (source.includes(name)) name = `__sandboxedjs_exports${++suffix}`;
|
|
22868
23155
|
return name;
|
|
22869
23156
|
}
|
|
22870
|
-
function
|
|
23157
|
+
function isNode3(value) {
|
|
22871
23158
|
return typeof value === "object" && value !== null && typeof value.type === "string";
|
|
22872
23159
|
}
|
|
22873
23160
|
var NOTHING = [];
|
|
@@ -24818,6 +25105,7 @@ exports.braceExpand = braceExpand;
|
|
|
24818
25105
|
exports.buildRootfs = buildRootfs;
|
|
24819
25106
|
exports.builtinNames = builtinNames;
|
|
24820
25107
|
exports.captureStdio = captureStdio;
|
|
25108
|
+
exports.configureCPython = configureCPython;
|
|
24821
25109
|
exports.configurePython = configurePython;
|
|
24822
25110
|
exports.createContainer = createContainer;
|
|
24823
25111
|
exports.createContext = createContext;
|
|
@@ -24836,6 +25124,7 @@ exports.globToRegex = globToRegex;
|
|
|
24836
25124
|
exports.hasMagic = hasMagic;
|
|
24837
25125
|
exports.installUserland = installUserland;
|
|
24838
25126
|
exports.isBuiltinName = isBuiltinName;
|
|
25127
|
+
exports.isCPythonAvailable = isCPythonAvailable;
|
|
24839
25128
|
exports.isPythonAvailable = isPythonAvailable;
|
|
24840
25129
|
exports.isSysError = isSysError;
|
|
24841
25130
|
exports.makeCred = makeCred;
|