sandboxedjs 0.1.50 → 0.1.52
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 +16 -14
- package/dist/agent.d.cts +1 -1
- package/dist/agent.d.ts +1 -1
- package/dist/{container-Dg8NwBc7.d.cts → container-B--ykWn3.d.cts} +57 -1
- package/dist/{container-DBMPLbUu.d.ts → container-BSW6jjlq.d.ts} +57 -1
- package/dist/index.cjs +513 -333
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +514 -334
- package/dist/index.js.map +1 -1
- package/dist/python/python.data +147 -136
- package/dist/python/python.js +1 -1
- package/dist/python/python.wasm +0 -0
- package/dist/python/runtime.json +13 -7
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -89,7 +89,7 @@ it alongside their model provider.
|
|
|
89
89
|
| **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, `[[ ]]`, `(( ))` |
|
|
90
90
|
| **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 |
|
|
91
91
|
| **Node.js** | Its own module engine — `require` *and* `import`, live bindings, `exports` maps, top-level `await`, npm packages, `http`, `fs`, streams, `child_process` |
|
|
92
|
-
| **Python** | CPython 3.13
|
|
92
|
+
| **Python** | Source-built CPython 3.13/WASM on the *same* filesystem, with the real standard library |
|
|
93
93
|
| **WebAssembly** | A WASI (`preview1`) host — run any `wasm32-wasi` binary from clang, Rust, Zig or TinyGo as an ordinary process, on the same filesystem |
|
|
94
94
|
| **FFmpeg** | `ffmpeg` and `ffprobe` (FFmpeg 5.1) reading and writing container files directly — [optional install](#video-and-audio) |
|
|
95
95
|
| **`/proc`** | Live and synthesised — `ps`, `top`, `free` and `uptime` all read the same source |
|
|
@@ -391,7 +391,7 @@ your disk.
|
|
|
391
391
|
|
|
392
392
|
### Python
|
|
393
393
|
|
|
394
|
-
Python is CPython 3.13
|
|
394
|
+
Python is the bundled, source-built CPython 3.13 WebAssembly runtime mounted on the container's filesystem:
|
|
395
395
|
|
|
396
396
|
```ts
|
|
397
397
|
await box.exec("python3 -c \"print(open('/etc/hostname').read())\"");
|
|
@@ -401,8 +401,10 @@ await box.exec("echo '1 2 3' | python3 -c \"import sys; print(sum(map(int, sys.s
|
|
|
401
401
|
|
|
402
402
|
The bundled standard library includes `json`, `re`, `os`, `sys`, `math`, `random`, `hashlib`,
|
|
403
403
|
`binascii`, `struct`, `time`, `collections`, `itertools`, `functools`, `asyncio` and more. It is
|
|
404
|
-
|
|
405
|
-
|
|
404
|
+
It is real CPython, so `sqlite3`, `dataclasses`, `decimal`, `typing`, `ssl`, and
|
|
405
|
+
`asyncio` work. `pip` installs compatible wheels into the same filesystem and
|
|
406
|
+
creates their `console_scripts` in `/usr/local/bin` (with outbound networking
|
|
407
|
+
enabled). Native extensions still need an Emscripten-compatible build.
|
|
406
408
|
|
|
407
409
|
### WebAssembly binaries
|
|
408
410
|
|
|
@@ -701,20 +703,21 @@ Those use dynamic imports, so they only fail if you call them.
|
|
|
701
703
|
|
|
702
704
|
### Python in a browser
|
|
703
705
|
|
|
704
|
-
Python works lazily in a browser without extra configuration.
|
|
705
|
-
|
|
706
|
+
Python works lazily in a browser without extra configuration. The owned CPython
|
|
707
|
+
runtime and its pthread worker are shipped with the npm package:
|
|
706
708
|
|
|
707
709
|
```ts
|
|
708
710
|
const box = await createContainer();
|
|
709
711
|
await box.exec("python3 -c 'import sqlite3; print(sqlite3.sqlite_version)'");
|
|
710
712
|
```
|
|
711
713
|
|
|
712
|
-
|
|
714
|
+
Pyodide remains available as an explicit compatibility backend:
|
|
713
715
|
|
|
714
716
|
```ts
|
|
715
717
|
import { configurePython, createContainer } from "sandboxedjs";
|
|
716
718
|
|
|
717
719
|
configurePython({
|
|
720
|
+
backend: "pyodide",
|
|
718
721
|
pyodideURL: "https://cdn.jsdelivr.net/pyodide/v0.28.3/full/pyodide.mjs",
|
|
719
722
|
indexURL: "https://cdn.jsdelivr.net/pyodide/v0.28.3/full/",
|
|
720
723
|
});
|
|
@@ -723,8 +726,8 @@ const box = await createContainer();
|
|
|
723
726
|
await box.exec("python3 -c 'import sqlite3; print(sqlite3.sqlite_version)'");
|
|
724
727
|
```
|
|
725
728
|
|
|
726
|
-
Python never falls back to a host interpreter
|
|
727
|
-
Pyodide module and
|
|
729
|
+
Python never falls back to a host interpreter. When selecting the optional
|
|
730
|
+
Pyodide backend, its module and asset directory must use the same version.
|
|
728
731
|
|
|
729
732
|
## Uploading files
|
|
730
733
|
|
|
@@ -972,11 +975,10 @@ Honest list of what does not work:
|
|
|
972
975
|
now?" and run `npm install && npm run dev` from the shell instead.
|
|
973
976
|
- **No `net`, `tls`, `worker_threads` or `vm`.** `http` and `https` are served by a virtual stack
|
|
974
977
|
that `request()` talks to directly, so servers work; raw sockets do not.
|
|
975
|
-
- **Python is CPython
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
container, and each program runs in its own namespace.
|
|
978
|
+
- **Python is source-built CPython/WASM.** Each program gets its own interpreter
|
|
979
|
+
process worker. Pure-Python wheels install normally; native extensions must
|
|
980
|
+
be linked or published for Emscripten. Pydantic 2's `pydantic-core` is not
|
|
981
|
+
currently available, so use a Pydantic 1 constraint for FastAPI deployments.
|
|
980
982
|
- **No real sockets.** HTTP servers work through the request proxy; raw TCP/UDP does not.
|
|
981
983
|
- **No real processes.** Processes are cooperative async tasks: `kill -9` cannot interrupt a
|
|
982
984
|
tight synchronous loop, and `SIGSTOP` only marks state.
|
package/dist/agent.d.cts
CHANGED
package/dist/agent.d.ts
CHANGED
|
@@ -1053,7 +1053,7 @@ declare class Shell {
|
|
|
1053
1053
|
declare const MANIFEST_FORMAT = "sandboxedjs-python-runtime";
|
|
1054
1054
|
declare const MANIFEST_SCHEMA_VERSION = 1;
|
|
1055
1055
|
/** Build profiles, as defined in docs/python/architecture.md. */
|
|
1056
|
-
type PythonProfile = "core" | "threaded-fixed" | "
|
|
1056
|
+
type PythonProfile = "core" | "threaded-fixed" | "dynamic";
|
|
1057
1057
|
interface PythonCapabilities {
|
|
1058
1058
|
/** Real Python threads. `core` builds have none, and must say so. */
|
|
1059
1059
|
threads: boolean;
|
|
@@ -1101,6 +1101,54 @@ interface PythonRuntimeManifest {
|
|
|
1101
1101
|
*/
|
|
1102
1102
|
declare function validateManifest(value: unknown): PythonRuntimeManifest;
|
|
1103
1103
|
|
|
1104
|
+
/**
|
|
1105
|
+
* Dependency resolution for the owned Python runtime.
|
|
1106
|
+
*
|
|
1107
|
+
* The installer this replaces walked candidate versions and downloaded a whole
|
|
1108
|
+
* wheel for each one just to read its `METADATA`. That is why it needed an
|
|
1109
|
+
* arbitrary cap on how many candidates it would try: without one, discovering
|
|
1110
|
+
* that a package's last forty releases all need the same unavailable native
|
|
1111
|
+
* extension cost forty multi-megabyte downloads, and the install looked hung
|
|
1112
|
+
* rather than failed. The cap made the symptom bearable and the cause worse --
|
|
1113
|
+
* a resolution that hit it reported a limit rather than the conflict, and a
|
|
1114
|
+
* legitimately deep graph failed for no reason.
|
|
1115
|
+
*
|
|
1116
|
+
* Three changes remove the need for it:
|
|
1117
|
+
*
|
|
1118
|
+
* * Dependency metadata is read from PEP 658 sidecars, so learning what a
|
|
1119
|
+
* release requires costs a few kilobytes rather than the wheel.
|
|
1120
|
+
* * Constraints propagate. A version excluded by an already-chosen package's
|
|
1121
|
+
* requirement is never fetched at all.
|
|
1122
|
+
* * Conflicts are learned. When a set of constraints proves unsatisfiable,
|
|
1123
|
+
* the proof is recorded, so the same subtree is not re-derived once per
|
|
1124
|
+
* parent version.
|
|
1125
|
+
*
|
|
1126
|
+
* What bounds the work now is a deadline and a cancellation signal, which are
|
|
1127
|
+
* honest limits: they say the search ran out of time, not that it ran out of
|
|
1128
|
+
* an arbitrary allowance.
|
|
1129
|
+
*/
|
|
1130
|
+
|
|
1131
|
+
/**
|
|
1132
|
+
* One prebuilt SandboxedJs wheel, as published in a wheel index.
|
|
1133
|
+
*
|
|
1134
|
+
* `abiId` travels with the entry rather than being implied by the index it
|
|
1135
|
+
* came from. An index served for a different interpreter build would otherwise
|
|
1136
|
+
* look usable, and the wheel would fail at import rather than at resolution.
|
|
1137
|
+
*/
|
|
1138
|
+
interface PrebuiltWheel {
|
|
1139
|
+
name: string;
|
|
1140
|
+
version: string;
|
|
1141
|
+
filename: string;
|
|
1142
|
+
sha256: string;
|
|
1143
|
+
abiId: string;
|
|
1144
|
+
requires: string[];
|
|
1145
|
+
}
|
|
1146
|
+
interface WheelIndex {
|
|
1147
|
+
/** Where `filename` is resolved against. */
|
|
1148
|
+
baseUrl: string;
|
|
1149
|
+
wheels: PrebuiltWheel[];
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1104
1152
|
/**
|
|
1105
1153
|
* Which Python backend a container uses.
|
|
1106
1154
|
*
|
|
@@ -1178,6 +1226,14 @@ interface PythonOptions {
|
|
|
1178
1226
|
manifest?: PythonRuntimeManifest;
|
|
1179
1227
|
/** Where the built process worker is served from, for hosts that must say. */
|
|
1180
1228
|
workerUrl?: string;
|
|
1229
|
+
/**
|
|
1230
|
+
* Prebuilt wheels for this runtime's native ABI, which PyPI does not carry.
|
|
1231
|
+
*
|
|
1232
|
+
* Either the index itself, or the base URL its `index.json` is served from.
|
|
1233
|
+
* A package with a compiled extension cannot resolve without one, because
|
|
1234
|
+
* no published wheel targets wasm32-emscripten.
|
|
1235
|
+
*/
|
|
1236
|
+
wheelIndex?: WheelIndex | string | null;
|
|
1181
1237
|
}
|
|
1182
1238
|
declare function configurePython(options?: PythonOptions): void;
|
|
1183
1239
|
declare const isPythonAvailable: typeof isCPythonAvailable;
|
|
@@ -1053,7 +1053,7 @@ declare class Shell {
|
|
|
1053
1053
|
declare const MANIFEST_FORMAT = "sandboxedjs-python-runtime";
|
|
1054
1054
|
declare const MANIFEST_SCHEMA_VERSION = 1;
|
|
1055
1055
|
/** Build profiles, as defined in docs/python/architecture.md. */
|
|
1056
|
-
type PythonProfile = "core" | "threaded-fixed" | "
|
|
1056
|
+
type PythonProfile = "core" | "threaded-fixed" | "dynamic";
|
|
1057
1057
|
interface PythonCapabilities {
|
|
1058
1058
|
/** Real Python threads. `core` builds have none, and must say so. */
|
|
1059
1059
|
threads: boolean;
|
|
@@ -1101,6 +1101,54 @@ interface PythonRuntimeManifest {
|
|
|
1101
1101
|
*/
|
|
1102
1102
|
declare function validateManifest(value: unknown): PythonRuntimeManifest;
|
|
1103
1103
|
|
|
1104
|
+
/**
|
|
1105
|
+
* Dependency resolution for the owned Python runtime.
|
|
1106
|
+
*
|
|
1107
|
+
* The installer this replaces walked candidate versions and downloaded a whole
|
|
1108
|
+
* wheel for each one just to read its `METADATA`. That is why it needed an
|
|
1109
|
+
* arbitrary cap on how many candidates it would try: without one, discovering
|
|
1110
|
+
* that a package's last forty releases all need the same unavailable native
|
|
1111
|
+
* extension cost forty multi-megabyte downloads, and the install looked hung
|
|
1112
|
+
* rather than failed. The cap made the symptom bearable and the cause worse --
|
|
1113
|
+
* a resolution that hit it reported a limit rather than the conflict, and a
|
|
1114
|
+
* legitimately deep graph failed for no reason.
|
|
1115
|
+
*
|
|
1116
|
+
* Three changes remove the need for it:
|
|
1117
|
+
*
|
|
1118
|
+
* * Dependency metadata is read from PEP 658 sidecars, so learning what a
|
|
1119
|
+
* release requires costs a few kilobytes rather than the wheel.
|
|
1120
|
+
* * Constraints propagate. A version excluded by an already-chosen package's
|
|
1121
|
+
* requirement is never fetched at all.
|
|
1122
|
+
* * Conflicts are learned. When a set of constraints proves unsatisfiable,
|
|
1123
|
+
* the proof is recorded, so the same subtree is not re-derived once per
|
|
1124
|
+
* parent version.
|
|
1125
|
+
*
|
|
1126
|
+
* What bounds the work now is a deadline and a cancellation signal, which are
|
|
1127
|
+
* honest limits: they say the search ran out of time, not that it ran out of
|
|
1128
|
+
* an arbitrary allowance.
|
|
1129
|
+
*/
|
|
1130
|
+
|
|
1131
|
+
/**
|
|
1132
|
+
* One prebuilt SandboxedJs wheel, as published in a wheel index.
|
|
1133
|
+
*
|
|
1134
|
+
* `abiId` travels with the entry rather than being implied by the index it
|
|
1135
|
+
* came from. An index served for a different interpreter build would otherwise
|
|
1136
|
+
* look usable, and the wheel would fail at import rather than at resolution.
|
|
1137
|
+
*/
|
|
1138
|
+
interface PrebuiltWheel {
|
|
1139
|
+
name: string;
|
|
1140
|
+
version: string;
|
|
1141
|
+
filename: string;
|
|
1142
|
+
sha256: string;
|
|
1143
|
+
abiId: string;
|
|
1144
|
+
requires: string[];
|
|
1145
|
+
}
|
|
1146
|
+
interface WheelIndex {
|
|
1147
|
+
/** Where `filename` is resolved against. */
|
|
1148
|
+
baseUrl: string;
|
|
1149
|
+
wheels: PrebuiltWheel[];
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1104
1152
|
/**
|
|
1105
1153
|
* Which Python backend a container uses.
|
|
1106
1154
|
*
|
|
@@ -1178,6 +1226,14 @@ interface PythonOptions {
|
|
|
1178
1226
|
manifest?: PythonRuntimeManifest;
|
|
1179
1227
|
/** Where the built process worker is served from, for hosts that must say. */
|
|
1180
1228
|
workerUrl?: string;
|
|
1229
|
+
/**
|
|
1230
|
+
* Prebuilt wheels for this runtime's native ABI, which PyPI does not carry.
|
|
1231
|
+
*
|
|
1232
|
+
* Either the index itself, or the base URL its `index.json` is served from.
|
|
1233
|
+
* A package with a compiled extension cannot resolve without one, because
|
|
1234
|
+
* no published wheel targets wasm32-emscripten.
|
|
1235
|
+
*/
|
|
1236
|
+
wheelIndex?: WheelIndex | string | null;
|
|
1181
1237
|
}
|
|
1182
1238
|
declare function configurePython(options?: PythonOptions): void;
|
|
1183
1239
|
declare const isPythonAvailable: typeof isCPythonAvailable;
|