sandboxedjs 0.1.48 → 0.1.50
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/agent.d.cts +2 -1
- package/dist/agent.d.ts +2 -1
- package/dist/{container-DyRF-bY0.d.cts → container-DBMPLbUu.d.ts} +103 -410
- package/dist/{container-DyRF-bY0.d.ts → container-Dg8NwBc7.d.cts} +103 -410
- package/dist/index.cjs +2483 -306
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -65
- package/dist/index.d.ts +20 -65
- package/dist/index.js +2479 -305
- package/dist/index.js.map +1 -1
- package/dist/memory-volume-CTOXNJ6n.d.ts +66 -0
- package/dist/memory-volume-DCzGZFJb.d.cts +66 -0
- package/dist/python/python.data +16021 -66
- package/dist/python/python.js +2 -0
- package/dist/python/python.wasm +0 -0
- package/dist/python/python.worker.js +87 -0
- package/dist/python/runtime.json +34 -0
- package/dist/python-abi.cjs +2892 -0
- package/dist/python-abi.cjs.map +1 -0
- package/dist/python-abi.d.cts +645 -0
- package/dist/python-abi.d.ts +645 -0
- package/dist/python-abi.js +2839 -0
- package/dist/python-abi.js.map +1 -0
- package/dist/python-worker.js +865 -0
- package/dist/python-worker.js.map +1 -0
- package/dist/rolldown-wasi-worker.js +5 -1
- package/dist/rolldown-wasi-worker.js.map +1 -1
- package/dist/vfs-DzEcPbMY.d.cts +427 -0
- package/dist/vfs-DzEcPbMY.d.ts +427 -0
- package/package.json +8 -3
package/dist/index.cjs
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var index_js = require('buffer/index.js');
|
|
6
5
|
var pako = require('pako');
|
|
6
|
+
var index_js = require('buffer/index.js');
|
|
7
7
|
var sha256 = require('@noble/hashes/sha256');
|
|
8
8
|
var sha512 = require('@noble/hashes/sha512');
|
|
9
9
|
var sha1 = require('@noble/hashes/sha1');
|
|
@@ -21,10 +21,6 @@ var timersModule = require('timers-browserify');
|
|
|
21
21
|
var legacyUrl = require('url/url.js');
|
|
22
22
|
var legacy$1 = require('@noble/hashes/legacy');
|
|
23
23
|
var hmac = require('@noble/hashes/hmac');
|
|
24
|
-
var module$1 = require('module');
|
|
25
|
-
var fs = require('fs');
|
|
26
|
-
var path = require('path');
|
|
27
|
-
var url = require('url');
|
|
28
24
|
|
|
29
25
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
30
26
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -3611,10 +3607,10 @@ function builtinType({ shell, argv, io }) {
|
|
|
3611
3607
|
}
|
|
3612
3608
|
async function builtinCommand({ shell, argv, io }) {
|
|
3613
3609
|
const args = argv.slice(1);
|
|
3614
|
-
const
|
|
3610
|
+
const describe3 = args.includes("-v") || args.includes("-V");
|
|
3615
3611
|
const verbose = args.includes("-V");
|
|
3616
3612
|
const rest = args.filter((a) => a !== "-v" && a !== "-V" && a !== "-p");
|
|
3617
|
-
if (
|
|
3613
|
+
if (describe3) {
|
|
3618
3614
|
let status = 0;
|
|
3619
3615
|
for (const name of rest) {
|
|
3620
3616
|
if (isBuiltinName(name)) {
|
|
@@ -13927,15 +13923,15 @@ var sort = defineCommand({
|
|
|
13927
13923
|
const slice = fields.slice(start2, end === void 0 ? void 0 : end);
|
|
13928
13924
|
return slice.join(separator ?? " ");
|
|
13929
13925
|
};
|
|
13930
|
-
const
|
|
13926
|
+
const normalize4 = (line) => {
|
|
13931
13927
|
let value = keys.length ? fieldOf(line, keys[0]) : line;
|
|
13932
13928
|
if (args.has("ignore-leading-blanks")) value = value.replace(/^\s+/, "");
|
|
13933
13929
|
if (args.has("ignore-case")) value = value.toLowerCase();
|
|
13934
13930
|
return value;
|
|
13935
13931
|
};
|
|
13936
13932
|
const compare = (a, b) => {
|
|
13937
|
-
const x =
|
|
13938
|
-
const y =
|
|
13933
|
+
const x = normalize4(a);
|
|
13934
|
+
const y = normalize4(b);
|
|
13939
13935
|
if (args.has("numeric-sort") || args.has("general-numeric-sort")) {
|
|
13940
13936
|
const nx = parseFloat(x) || 0;
|
|
13941
13937
|
const ny = parseFloat(y) || 0;
|
|
@@ -15176,7 +15172,7 @@ var diff = defineCommand({
|
|
|
15176
15172
|
if (a === void 0 || b === void 0) return ctx.fail("missing operand", 2);
|
|
15177
15173
|
const { sources, ok: ok2 } = await readInputs(ctx, [a, b]);
|
|
15178
15174
|
if (!ok2 || sources.length < 2) return 2;
|
|
15179
|
-
const
|
|
15175
|
+
const normalize4 = (line) => {
|
|
15180
15176
|
let value = line;
|
|
15181
15177
|
if (args.has("ignore-all-space")) value = value.replace(/\s+/g, "");
|
|
15182
15178
|
else if (args.has("ignore-space-change")) value = value.replace(/\s+/g, " ").trim();
|
|
@@ -15185,7 +15181,7 @@ var diff = defineCommand({
|
|
|
15185
15181
|
};
|
|
15186
15182
|
const left = splitLines(sources[0].bytes).lines;
|
|
15187
15183
|
const right = splitLines(sources[1].bytes).lines;
|
|
15188
|
-
const script = diffLines(left.map(
|
|
15184
|
+
const script = diffLines(left.map(normalize4), right.map(normalize4));
|
|
15189
15185
|
if (script.length === 0) return 0;
|
|
15190
15186
|
if (args.has("brief")) {
|
|
15191
15187
|
ctx.line(`Files ${a} and ${b} differ`);
|
|
@@ -17685,150 +17681,2315 @@ function nodeCommands() {
|
|
|
17685
17681
|
// src/runtime/python.ts
|
|
17686
17682
|
init_path();
|
|
17687
17683
|
|
|
17688
|
-
// src/runtime/
|
|
17689
|
-
|
|
17690
|
-
|
|
17691
|
-
var
|
|
17692
|
-
|
|
17693
|
-
|
|
17694
|
-
|
|
17695
|
-
|
|
17696
|
-
|
|
17697
|
-
|
|
17698
|
-
|
|
17699
|
-
|
|
17700
|
-
|
|
17701
|
-
|
|
17702
|
-
|
|
17703
|
-
|
|
17704
|
-
|
|
17705
|
-
|
|
17706
|
-
|
|
17707
|
-
|
|
17708
|
-
|
|
17709
|
-
|
|
17710
|
-
|
|
17711
|
-
|
|
17684
|
+
// src/runtime/python/host-abi.ts
|
|
17685
|
+
var SBX_HOST_ABI_VERSION = 1;
|
|
17686
|
+
var SBX_REQUEST_HEADER_BYTES = 16;
|
|
17687
|
+
var SBX_RESPONSE_HEADER_BYTES = 20;
|
|
17688
|
+
var Op = {
|
|
17689
|
+
handshake: 0,
|
|
17690
|
+
openat: 1,
|
|
17691
|
+
close: 2,
|
|
17692
|
+
read: 3,
|
|
17693
|
+
write: 4,
|
|
17694
|
+
pread: 5,
|
|
17695
|
+
pwrite: 6,
|
|
17696
|
+
lseek: 7,
|
|
17697
|
+
fstat: 8,
|
|
17698
|
+
statat: 9,
|
|
17699
|
+
ftruncate: 10,
|
|
17700
|
+
renameat: 11,
|
|
17701
|
+
unlinkat: 12,
|
|
17702
|
+
mkdirat: 13,
|
|
17703
|
+
readlinkat: 14,
|
|
17704
|
+
symlinkat: 15,
|
|
17705
|
+
getdents: 16,
|
|
17706
|
+
fsync: 17,
|
|
17707
|
+
dup: 256,
|
|
17708
|
+
dup2: 257,
|
|
17709
|
+
get_flags: 258,
|
|
17710
|
+
set_flags: 259,
|
|
17711
|
+
pipe: 512,
|
|
17712
|
+
poll: 768,
|
|
17713
|
+
clock_gettime: 1024,
|
|
17714
|
+
sleep: 1025,
|
|
17715
|
+
getpid: 1280,
|
|
17716
|
+
getcwd: 1281,
|
|
17717
|
+
chdir: 1282,
|
|
17718
|
+
environ: 1283,
|
|
17719
|
+
getrandom: 1536
|
|
17712
17720
|
};
|
|
17713
|
-
|
|
17714
|
-
|
|
17721
|
+
var Errno = {
|
|
17722
|
+
EPERM: 1,
|
|
17723
|
+
ENOENT: 2,
|
|
17724
|
+
ESRCH: 3,
|
|
17725
|
+
EINTR: 4,
|
|
17726
|
+
EIO: 5,
|
|
17727
|
+
ENXIO: 6,
|
|
17728
|
+
E2BIG: 7,
|
|
17729
|
+
EBADF: 9,
|
|
17730
|
+
EAGAIN: 11,
|
|
17731
|
+
ENOMEM: 12,
|
|
17732
|
+
EACCES: 13,
|
|
17733
|
+
EFAULT: 14,
|
|
17734
|
+
EBUSY: 16,
|
|
17735
|
+
EEXIST: 17,
|
|
17736
|
+
EXDEV: 18,
|
|
17737
|
+
ENODEV: 19,
|
|
17738
|
+
ENOTDIR: 20,
|
|
17739
|
+
EISDIR: 21,
|
|
17740
|
+
EINVAL: 22,
|
|
17741
|
+
ENFILE: 23,
|
|
17742
|
+
EMFILE: 24,
|
|
17743
|
+
ENOTTY: 25,
|
|
17744
|
+
EFBIG: 27,
|
|
17745
|
+
ENOSPC: 28,
|
|
17746
|
+
ESPIPE: 29,
|
|
17747
|
+
EROFS: 30,
|
|
17748
|
+
EMLINK: 31,
|
|
17749
|
+
EPIPE: 32,
|
|
17750
|
+
ERANGE: 34,
|
|
17751
|
+
ENAMETOOLONG: 36,
|
|
17752
|
+
ENOSYS: 38,
|
|
17753
|
+
ENOTEMPTY: 39,
|
|
17754
|
+
ELOOP: 40,
|
|
17755
|
+
ENODATA: 61,
|
|
17756
|
+
EPROTO: 71,
|
|
17757
|
+
EOVERFLOW: 75,
|
|
17758
|
+
ETIMEDOUT: 110,
|
|
17759
|
+
ECANCELED: 125,
|
|
17760
|
+
EDQUOT: 122
|
|
17761
|
+
};
|
|
17762
|
+
var CAPABILITIES = ["files", "descriptors", "pipes", "readiness", "time", "identity", "entropy", "sockets", "processes", "signals", "storage", "services", "threads"];
|
|
17763
|
+
var OP_NAMES = Object.fromEntries(
|
|
17764
|
+
Object.entries(Op).map(([name, code]) => [code, name])
|
|
17765
|
+
);
|
|
17766
|
+
Object.fromEntries(
|
|
17767
|
+
Object.entries(Errno).map(([name, code]) => [code, name])
|
|
17768
|
+
);
|
|
17769
|
+
|
|
17770
|
+
// src/runtime/python/manifest.ts
|
|
17771
|
+
var MANIFEST_FORMAT = "sandboxedjs-python-runtime";
|
|
17772
|
+
var MANIFEST_SCHEMA_VERSION = 1;
|
|
17773
|
+
var ManifestError = class extends Error {
|
|
17774
|
+
code = "ERR_SBX_PYTHON_MANIFEST";
|
|
17775
|
+
};
|
|
17776
|
+
function validateManifest(value) {
|
|
17777
|
+
const manifest = value;
|
|
17778
|
+
if (!manifest || typeof manifest !== "object") throw new ManifestError("the Python runtime manifest is not an object");
|
|
17779
|
+
if (manifest.format !== MANIFEST_FORMAT) {
|
|
17780
|
+
throw new ManifestError(`not a ${MANIFEST_FORMAT} manifest (format: ${String(manifest.format)})`);
|
|
17781
|
+
}
|
|
17782
|
+
if (manifest.schemaVersion !== MANIFEST_SCHEMA_VERSION) {
|
|
17783
|
+
throw new ManifestError(
|
|
17784
|
+
`manifest schema version ${String(manifest.schemaVersion)}, this build understands ${MANIFEST_SCHEMA_VERSION}`
|
|
17785
|
+
);
|
|
17786
|
+
}
|
|
17787
|
+
if (manifest.engine !== "cpython-wasm") {
|
|
17788
|
+
throw new ManifestError(`unknown Python engine ${String(manifest.engine)}`);
|
|
17789
|
+
}
|
|
17790
|
+
if (!manifest.runtimeId) throw new ManifestError("the manifest has no runtimeId");
|
|
17791
|
+
if (!manifest.artifacts?.moduleUrl) throw new ManifestError("the manifest names no module artifact");
|
|
17792
|
+
const abi = manifest.hostAbi;
|
|
17793
|
+
if (!abi || abi.name !== "sbx_host_v1") {
|
|
17794
|
+
throw new ManifestError(`the runtime was built against host ABI ${String(abi?.name)}, not sbx_host_v1`);
|
|
17795
|
+
}
|
|
17796
|
+
if (abi.version !== SBX_HOST_ABI_VERSION) {
|
|
17797
|
+
throw new ManifestError(
|
|
17798
|
+
`the runtime was built against host ABI version ${abi.version}; this kernel speaks ${SBX_HOST_ABI_VERSION}`
|
|
17799
|
+
);
|
|
17800
|
+
}
|
|
17801
|
+
if (!manifest.capabilities) throw new ManifestError("the manifest declares no capabilities");
|
|
17802
|
+
return manifest;
|
|
17715
17803
|
}
|
|
17716
|
-
|
|
17717
|
-
|
|
17718
|
-
|
|
17719
|
-
|
|
17720
|
-
|
|
17721
|
-
|
|
17722
|
-
|
|
17723
|
-
|
|
17724
|
-
|
|
17725
|
-
|
|
17726
|
-
|
|
17727
|
-
|
|
17728
|
-
|
|
17729
|
-
|
|
17730
|
-
|
|
17731
|
-
|
|
17732
|
-
|
|
17733
|
-
|
|
17734
|
-
|
|
17735
|
-
|
|
17736
|
-
|
|
17737
|
-
|
|
17738
|
-
|
|
17739
|
-
|
|
17740
|
-
|
|
17741
|
-
|
|
17742
|
-
|
|
17743
|
-
|
|
17744
|
-
|
|
17745
|
-
|
|
17746
|
-
|
|
17804
|
+
|
|
17805
|
+
// src/runtime/python/config.ts
|
|
17806
|
+
var bundledManifest = {
|
|
17807
|
+
format: "sandboxedjs-python-runtime",
|
|
17808
|
+
schemaVersion: 1,
|
|
17809
|
+
runtimeId: "sbx-cpython-3.13.5-threaded-fixed",
|
|
17810
|
+
engine: "cpython-wasm",
|
|
17811
|
+
pythonVersion: "3.13.5",
|
|
17812
|
+
profile: "threaded-fixed",
|
|
17813
|
+
hostAbi: { name: "sbx_host_v1", version: 1 },
|
|
17814
|
+
artifacts: {
|
|
17815
|
+
moduleUrl: new URL(
|
|
17816
|
+
(typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)).includes("/src/runtime/python/") ? "../../../dist/python/python.js" : "./python/python.js",
|
|
17817
|
+
(typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))
|
|
17818
|
+
).href
|
|
17819
|
+
},
|
|
17820
|
+
capabilities: {
|
|
17821
|
+
threads: true,
|
|
17822
|
+
nativeExtensions: "fixed",
|
|
17823
|
+
networking: "none",
|
|
17824
|
+
processes: "none",
|
|
17825
|
+
persistence: "memory"
|
|
17826
|
+
}
|
|
17827
|
+
};
|
|
17828
|
+
var config = { backend: "sbx-cpython-wasm", manifest: bundledManifest };
|
|
17829
|
+
function setPythonBackend(options) {
|
|
17830
|
+
if (options.manifest !== void 0) config.manifest = validateManifest(options.manifest);
|
|
17831
|
+
if (options.workerUrl !== void 0) config.workerUrl = options.workerUrl;
|
|
17832
|
+
if (options.backend !== void 0) {
|
|
17833
|
+
if (options.backend === "sbx-cpython-wasm" && !config.manifest) {
|
|
17834
|
+
throw new Error(
|
|
17835
|
+
"the sbx-cpython-wasm backend needs a runtime manifest; pass one to configurePython({ manifest })"
|
|
17836
|
+
);
|
|
17747
17837
|
}
|
|
17748
|
-
|
|
17749
|
-
|
|
17750
|
-
|
|
17751
|
-
|
|
17752
|
-
|
|
17753
|
-
|
|
17754
|
-
|
|
17755
|
-
|
|
17756
|
-
|
|
17757
|
-
|
|
17758
|
-
|
|
17759
|
-
|
|
17760
|
-
|
|
17761
|
-
|
|
17762
|
-
|
|
17763
|
-
|
|
17764
|
-
|
|
17765
|
-
|
|
17766
|
-
|
|
17767
|
-
|
|
17768
|
-
|
|
17769
|
-
|
|
17770
|
-
|
|
17771
|
-
|
|
17772
|
-
|
|
17773
|
-
|
|
17774
|
-
|
|
17775
|
-
|
|
17776
|
-
|
|
17777
|
-
|
|
17778
|
-
|
|
17779
|
-
|
|
17780
|
-
|
|
17781
|
-
|
|
17782
|
-
|
|
17783
|
-
|
|
17784
|
-
|
|
17785
|
-
|
|
17786
|
-
|
|
17787
|
-
|
|
17788
|
-
|
|
17789
|
-
|
|
17790
|
-
|
|
17791
|
-
|
|
17792
|
-
|
|
17793
|
-
|
|
17794
|
-
|
|
17795
|
-
|
|
17796
|
-
|
|
17797
|
-
|
|
17798
|
-
}
|
|
17799
|
-
|
|
17800
|
-
|
|
17801
|
-
|
|
17802
|
-
|
|
17803
|
-
|
|
17804
|
-
|
|
17805
|
-
|
|
17806
|
-
|
|
17807
|
-
|
|
17808
|
-
|
|
17809
|
-
|
|
17810
|
-
|
|
17811
|
-
|
|
17812
|
-
|
|
17813
|
-
|
|
17814
|
-
|
|
17815
|
-
|
|
17816
|
-
|
|
17817
|
-
|
|
17838
|
+
config.backend = options.backend;
|
|
17839
|
+
}
|
|
17840
|
+
}
|
|
17841
|
+
function pythonBackend() {
|
|
17842
|
+
return config;
|
|
17843
|
+
}
|
|
17844
|
+
|
|
17845
|
+
// src/kernel/open-file.ts
|
|
17846
|
+
var PosixError = class extends Error {
|
|
17847
|
+
constructor(errno, message) {
|
|
17848
|
+
super(message ?? `errno ${errno}`);
|
|
17849
|
+
this.errno = errno;
|
|
17850
|
+
this.name = "PosixError";
|
|
17851
|
+
}
|
|
17852
|
+
errno;
|
|
17853
|
+
};
|
|
17854
|
+
var O_RDONLY = 0;
|
|
17855
|
+
var O_WRONLY = 1;
|
|
17856
|
+
var O_CREAT2 = 64;
|
|
17857
|
+
var O_EXCL2 = 128;
|
|
17858
|
+
var O_TRUNC2 = 512;
|
|
17859
|
+
var O_APPEND = 1024;
|
|
17860
|
+
var O_NONBLOCK = 2048;
|
|
17861
|
+
var O_DIRECTORY2 = 65536;
|
|
17862
|
+
var O_CLOEXEC = 524288;
|
|
17863
|
+
function accessMode(flags) {
|
|
17864
|
+
return flags & 3;
|
|
17865
|
+
}
|
|
17866
|
+
var SEEK_SET = 0;
|
|
17867
|
+
var SEEK_CUR = 1;
|
|
17868
|
+
var Inode = class {
|
|
17869
|
+
constructor(ino, path, vfs, cred) {
|
|
17870
|
+
this.ino = ino;
|
|
17871
|
+
this.path = path;
|
|
17872
|
+
this.vfs = vfs;
|
|
17873
|
+
this.cred = cred;
|
|
17874
|
+
}
|
|
17875
|
+
ino;
|
|
17876
|
+
path;
|
|
17877
|
+
vfs;
|
|
17878
|
+
cred;
|
|
17879
|
+
detached = null;
|
|
17880
|
+
refs = 0;
|
|
17881
|
+
/** Read the whole file, wherever it currently lives. */
|
|
17882
|
+
contents() {
|
|
17883
|
+
if (this.detached) return this.detached;
|
|
17884
|
+
try {
|
|
17885
|
+
return this.vfs.readFile(this.path, this.cred);
|
|
17886
|
+
} catch (error) {
|
|
17887
|
+
throw toPosixError(error);
|
|
17888
|
+
}
|
|
17889
|
+
}
|
|
17890
|
+
replace(data) {
|
|
17891
|
+
if (this.detached) {
|
|
17892
|
+
this.detached = data;
|
|
17893
|
+
return;
|
|
17894
|
+
}
|
|
17895
|
+
try {
|
|
17896
|
+
this.vfs.writeFile(this.path, data, { cred: this.cred });
|
|
17897
|
+
} catch (error) {
|
|
17898
|
+
throw toPosixError(error);
|
|
17899
|
+
}
|
|
17900
|
+
}
|
|
17901
|
+
/** Called when the last name is about to be removed. */
|
|
17902
|
+
detach() {
|
|
17903
|
+
if (this.detached) return;
|
|
17904
|
+
try {
|
|
17905
|
+
this.detached = this.vfs.readFile(this.path, this.cred);
|
|
17906
|
+
} catch {
|
|
17907
|
+
this.detached = new Uint8Array();
|
|
17908
|
+
}
|
|
17909
|
+
}
|
|
17910
|
+
size() {
|
|
17911
|
+
return this.contents().length;
|
|
17912
|
+
}
|
|
17913
|
+
stat() {
|
|
17914
|
+
if (this.detached) {
|
|
17915
|
+
return {
|
|
17916
|
+
ino: this.ino,
|
|
17917
|
+
mode: 33188,
|
|
17918
|
+
size: this.detached.length,
|
|
17919
|
+
uid: this.cred.uid,
|
|
17920
|
+
gid: this.cred.gid,
|
|
17921
|
+
nlink: 0,
|
|
17922
|
+
atimeMs: Date.now(),
|
|
17923
|
+
mtimeMs: Date.now(),
|
|
17924
|
+
ctimeMs: Date.now()
|
|
17925
|
+
};
|
|
17926
|
+
}
|
|
17927
|
+
try {
|
|
17928
|
+
const st = this.vfs.stat(this.path, { cred: this.cred });
|
|
17929
|
+
return {
|
|
17930
|
+
ino: st.ino,
|
|
17931
|
+
mode: st.mode,
|
|
17932
|
+
size: st.size,
|
|
17933
|
+
uid: st.uid,
|
|
17934
|
+
gid: st.gid,
|
|
17935
|
+
nlink: st.nlink ?? 1,
|
|
17936
|
+
atimeMs: st.atimeMs,
|
|
17937
|
+
mtimeMs: st.mtimeMs,
|
|
17938
|
+
ctimeMs: st.ctimeMs
|
|
17939
|
+
};
|
|
17940
|
+
} catch (error) {
|
|
17941
|
+
throw toPosixError(error);
|
|
17942
|
+
}
|
|
17943
|
+
}
|
|
17944
|
+
};
|
|
17945
|
+
var FileDescription = class {
|
|
17946
|
+
constructor(inode, flags) {
|
|
17947
|
+
this.inode = inode;
|
|
17948
|
+
this.flags = flags;
|
|
17949
|
+
inode.refs += 1;
|
|
17950
|
+
}
|
|
17951
|
+
inode;
|
|
17952
|
+
flags;
|
|
17953
|
+
kind = "file";
|
|
17954
|
+
offset = 0;
|
|
17955
|
+
read(length) {
|
|
17956
|
+
if (accessMode(this.flags) === O_WRONLY) throw new PosixError(Errno.EBADF);
|
|
17957
|
+
const data = this.inode.contents();
|
|
17958
|
+
const start2 = Math.min(this.offset, data.length);
|
|
17959
|
+
const end = Math.min(start2 + length, data.length);
|
|
17960
|
+
this.offset = end;
|
|
17961
|
+
return data.slice(start2, end);
|
|
17962
|
+
}
|
|
17963
|
+
pread(length, offset) {
|
|
17964
|
+
if (accessMode(this.flags) === O_WRONLY) throw new PosixError(Errno.EBADF);
|
|
17965
|
+
const data = this.inode.contents();
|
|
17966
|
+
const start2 = Math.min(offset, data.length);
|
|
17967
|
+
return data.slice(start2, Math.min(start2 + length, data.length));
|
|
17968
|
+
}
|
|
17969
|
+
write(data) {
|
|
17970
|
+
if (accessMode(this.flags) === O_RDONLY) throw new PosixError(Errno.EBADF);
|
|
17971
|
+
const at = this.flags & O_APPEND ? this.inode.size() : this.offset;
|
|
17972
|
+
const written = this.writeAt(data, at);
|
|
17973
|
+
this.offset = at + written;
|
|
17974
|
+
return written;
|
|
17975
|
+
}
|
|
17976
|
+
pwrite(data, offset) {
|
|
17977
|
+
if (accessMode(this.flags) === O_RDONLY) throw new PosixError(Errno.EBADF);
|
|
17978
|
+
return this.writeAt(data, offset);
|
|
17979
|
+
}
|
|
17980
|
+
writeAt(data, offset) {
|
|
17981
|
+
const current = this.inode.contents();
|
|
17982
|
+
const end = offset + data.length;
|
|
17983
|
+
const next = new Uint8Array(Math.max(current.length, end));
|
|
17984
|
+
next.set(current, 0);
|
|
17985
|
+
next.set(data, offset);
|
|
17986
|
+
this.inode.replace(next);
|
|
17987
|
+
return data.length;
|
|
17988
|
+
}
|
|
17989
|
+
seek(offset, whence) {
|
|
17990
|
+
const base2 = whence === SEEK_SET ? 0 : whence === SEEK_CUR ? this.offset : this.inode.size();
|
|
17991
|
+
const next = base2 + offset;
|
|
17992
|
+
if (next < 0) throw new PosixError(Errno.EINVAL);
|
|
17993
|
+
this.offset = next;
|
|
17994
|
+
return next;
|
|
17995
|
+
}
|
|
17996
|
+
truncate(length) {
|
|
17997
|
+
const current = this.inode.contents();
|
|
17998
|
+
const next = new Uint8Array(length);
|
|
17999
|
+
next.set(current.subarray(0, Math.min(length, current.length)), 0);
|
|
18000
|
+
this.inode.replace(next);
|
|
18001
|
+
}
|
|
18002
|
+
stat() {
|
|
18003
|
+
return this.inode.stat();
|
|
18004
|
+
}
|
|
18005
|
+
readable() {
|
|
18006
|
+
return true;
|
|
18007
|
+
}
|
|
18008
|
+
writable() {
|
|
18009
|
+
return true;
|
|
18010
|
+
}
|
|
18011
|
+
whenReady() {
|
|
18012
|
+
return Promise.resolve();
|
|
18013
|
+
}
|
|
18014
|
+
close() {
|
|
18015
|
+
this.inode.refs -= 1;
|
|
18016
|
+
if (this.inode.refs <= 0) this.inode.detached = null;
|
|
18017
|
+
}
|
|
18018
|
+
};
|
|
18019
|
+
var DirectoryDescription = class {
|
|
18020
|
+
constructor(path, flags, vfs, cred) {
|
|
18021
|
+
this.path = path;
|
|
18022
|
+
this.flags = flags;
|
|
18023
|
+
this.vfs = vfs;
|
|
18024
|
+
this.cred = cred;
|
|
18025
|
+
}
|
|
18026
|
+
path;
|
|
18027
|
+
flags;
|
|
18028
|
+
vfs;
|
|
18029
|
+
cred;
|
|
18030
|
+
kind = "dir";
|
|
18031
|
+
entries = null;
|
|
18032
|
+
index = 0;
|
|
18033
|
+
/** Entry names, NUL-terminated, as many as fit in `length`. */
|
|
18034
|
+
read(length) {
|
|
18035
|
+
if (!this.entries) {
|
|
17818
18036
|
try {
|
|
17819
|
-
vfs.
|
|
17820
|
-
|
|
17821
|
-
|
|
17822
|
-
translate(e);
|
|
18037
|
+
this.entries = [".", "..", ...this.vfs.readdir(this.path, this.cred)];
|
|
18038
|
+
} catch (error) {
|
|
18039
|
+
throw toPosixError(error);
|
|
17823
18040
|
}
|
|
17824
|
-
|
|
17825
|
-
|
|
17826
|
-
|
|
17827
|
-
|
|
17828
|
-
|
|
17829
|
-
|
|
17830
|
-
|
|
17831
|
-
|
|
18041
|
+
}
|
|
18042
|
+
const encoder9 = new TextEncoder();
|
|
18043
|
+
const parts = [];
|
|
18044
|
+
let total = 0;
|
|
18045
|
+
while (this.index < this.entries.length) {
|
|
18046
|
+
const encoded = encoder9.encode(this.entries[this.index] + "\0");
|
|
18047
|
+
if (total + encoded.length > length) break;
|
|
18048
|
+
parts.push(encoded);
|
|
18049
|
+
total += encoded.length;
|
|
18050
|
+
this.index += 1;
|
|
18051
|
+
}
|
|
18052
|
+
const joined = new Uint8Array(total);
|
|
18053
|
+
let at = 0;
|
|
18054
|
+
for (const part of parts) {
|
|
18055
|
+
joined.set(part, at);
|
|
18056
|
+
at += part.length;
|
|
18057
|
+
}
|
|
18058
|
+
return joined;
|
|
18059
|
+
}
|
|
18060
|
+
write() {
|
|
18061
|
+
throw new PosixError(Errno.EISDIR);
|
|
18062
|
+
}
|
|
18063
|
+
seek(offset, whence) {
|
|
18064
|
+
if (whence === SEEK_SET && offset === 0) {
|
|
18065
|
+
this.index = 0;
|
|
18066
|
+
return 0;
|
|
18067
|
+
}
|
|
18068
|
+
throw new PosixError(Errno.EINVAL);
|
|
18069
|
+
}
|
|
18070
|
+
stat() {
|
|
18071
|
+
try {
|
|
18072
|
+
const st = this.vfs.stat(this.path, { cred: this.cred });
|
|
18073
|
+
return {
|
|
18074
|
+
ino: st.ino,
|
|
18075
|
+
mode: st.mode,
|
|
18076
|
+
size: st.size,
|
|
18077
|
+
uid: st.uid,
|
|
18078
|
+
gid: st.gid,
|
|
18079
|
+
nlink: st.nlink ?? 2,
|
|
18080
|
+
atimeMs: st.atimeMs,
|
|
18081
|
+
mtimeMs: st.mtimeMs,
|
|
18082
|
+
ctimeMs: st.ctimeMs
|
|
18083
|
+
};
|
|
18084
|
+
} catch (error) {
|
|
18085
|
+
throw toPosixError(error);
|
|
18086
|
+
}
|
|
18087
|
+
}
|
|
18088
|
+
readable() {
|
|
18089
|
+
return true;
|
|
18090
|
+
}
|
|
18091
|
+
writable() {
|
|
18092
|
+
return false;
|
|
18093
|
+
}
|
|
18094
|
+
whenReady() {
|
|
18095
|
+
return Promise.resolve();
|
|
18096
|
+
}
|
|
18097
|
+
close() {
|
|
18098
|
+
}
|
|
18099
|
+
};
|
|
18100
|
+
var PIPE_CAPACITY = 64 * 1024;
|
|
18101
|
+
var PipeBuffer = class {
|
|
18102
|
+
chunks = [];
|
|
18103
|
+
queued = 0;
|
|
18104
|
+
readers = 0;
|
|
18105
|
+
writers = 0;
|
|
18106
|
+
waiters = [];
|
|
18107
|
+
get available() {
|
|
18108
|
+
return this.queued;
|
|
18109
|
+
}
|
|
18110
|
+
get space() {
|
|
18111
|
+
return Math.max(0, PIPE_CAPACITY - this.queued);
|
|
18112
|
+
}
|
|
18113
|
+
push(data) {
|
|
18114
|
+
this.chunks.push(data);
|
|
18115
|
+
this.queued += data.length;
|
|
18116
|
+
this.wake();
|
|
18117
|
+
}
|
|
18118
|
+
take(length) {
|
|
18119
|
+
const out = new Uint8Array(Math.min(length, this.queued));
|
|
18120
|
+
let at = 0;
|
|
18121
|
+
while (at < out.length) {
|
|
18122
|
+
const head2 = this.chunks[0];
|
|
18123
|
+
const take = Math.min(head2.length, out.length - at);
|
|
18124
|
+
out.set(head2.subarray(0, take), at);
|
|
18125
|
+
at += take;
|
|
18126
|
+
if (take === head2.length) this.chunks.shift();
|
|
18127
|
+
else this.chunks[0] = head2.subarray(take);
|
|
18128
|
+
}
|
|
18129
|
+
this.queued -= out.length;
|
|
18130
|
+
this.wake();
|
|
18131
|
+
return out;
|
|
18132
|
+
}
|
|
18133
|
+
/** Anything that may have changed readiness for either end. */
|
|
18134
|
+
wake() {
|
|
18135
|
+
const waiting = this.waiters;
|
|
18136
|
+
this.waiters = [];
|
|
18137
|
+
for (const resolve2 of waiting) resolve2();
|
|
18138
|
+
}
|
|
18139
|
+
whenReady() {
|
|
18140
|
+
return new Promise((resolve2) => this.waiters.push(resolve2));
|
|
18141
|
+
}
|
|
18142
|
+
};
|
|
18143
|
+
var PipeReadEnd = class {
|
|
18144
|
+
constructor(buffer, flags) {
|
|
18145
|
+
this.buffer = buffer;
|
|
18146
|
+
this.flags = flags;
|
|
18147
|
+
buffer.readers += 1;
|
|
18148
|
+
}
|
|
18149
|
+
buffer;
|
|
18150
|
+
flags;
|
|
18151
|
+
kind = "pipe";
|
|
18152
|
+
read(length) {
|
|
18153
|
+
if (this.buffer.available === 0) {
|
|
18154
|
+
if (this.buffer.writers === 0) return new Uint8Array();
|
|
18155
|
+
throw new PosixError(Errno.EAGAIN);
|
|
18156
|
+
}
|
|
18157
|
+
return this.buffer.take(length);
|
|
18158
|
+
}
|
|
18159
|
+
write() {
|
|
18160
|
+
throw new PosixError(Errno.EBADF);
|
|
18161
|
+
}
|
|
18162
|
+
stat() {
|
|
18163
|
+
return pipeStat();
|
|
18164
|
+
}
|
|
18165
|
+
readable() {
|
|
18166
|
+
return this.buffer.available > 0 || this.buffer.writers === 0;
|
|
18167
|
+
}
|
|
18168
|
+
writable() {
|
|
18169
|
+
return false;
|
|
18170
|
+
}
|
|
18171
|
+
whenReady() {
|
|
18172
|
+
return this.buffer.whenReady();
|
|
18173
|
+
}
|
|
18174
|
+
close() {
|
|
18175
|
+
this.buffer.readers -= 1;
|
|
18176
|
+
this.buffer.wake();
|
|
18177
|
+
}
|
|
18178
|
+
};
|
|
18179
|
+
var PipeWriteEnd = class {
|
|
18180
|
+
constructor(buffer, flags) {
|
|
18181
|
+
this.buffer = buffer;
|
|
18182
|
+
this.flags = flags;
|
|
18183
|
+
buffer.writers += 1;
|
|
18184
|
+
}
|
|
18185
|
+
buffer;
|
|
18186
|
+
flags;
|
|
18187
|
+
kind = "pipe";
|
|
18188
|
+
read() {
|
|
18189
|
+
throw new PosixError(Errno.EBADF);
|
|
18190
|
+
}
|
|
18191
|
+
write(data) {
|
|
18192
|
+
if (this.buffer.readers === 0) throw new PosixError(Errno.EPIPE);
|
|
18193
|
+
const space = this.buffer.space;
|
|
18194
|
+
if (space === 0) throw new PosixError(Errno.EAGAIN);
|
|
18195
|
+
const accepted = data.subarray(0, space);
|
|
18196
|
+
this.buffer.push(accepted.slice());
|
|
18197
|
+
return accepted.length;
|
|
18198
|
+
}
|
|
18199
|
+
stat() {
|
|
18200
|
+
return pipeStat();
|
|
18201
|
+
}
|
|
18202
|
+
readable() {
|
|
18203
|
+
return false;
|
|
18204
|
+
}
|
|
18205
|
+
writable() {
|
|
18206
|
+
return this.buffer.space > 0 || this.buffer.readers === 0;
|
|
18207
|
+
}
|
|
18208
|
+
whenReady() {
|
|
18209
|
+
return this.buffer.whenReady();
|
|
18210
|
+
}
|
|
18211
|
+
close() {
|
|
18212
|
+
this.buffer.writers -= 1;
|
|
18213
|
+
this.buffer.wake();
|
|
18214
|
+
}
|
|
18215
|
+
};
|
|
18216
|
+
function pipeStat() {
|
|
18217
|
+
const now = Date.now();
|
|
18218
|
+
return { ino: 0, mode: 4480, size: 0, uid: 0, gid: 0, nlink: 1, atimeMs: now, mtimeMs: now, ctimeMs: now };
|
|
18219
|
+
}
|
|
18220
|
+
function createPipe(flags = 0) {
|
|
18221
|
+
const buffer = new PipeBuffer();
|
|
18222
|
+
return [new PipeReadEnd(buffer, flags | O_RDONLY), new PipeWriteEnd(buffer, flags | O_WRONLY)];
|
|
18223
|
+
}
|
|
18224
|
+
var StreamDescription = class {
|
|
18225
|
+
constructor(flags, sink, isTty = false) {
|
|
18226
|
+
this.flags = flags;
|
|
18227
|
+
this.sink = sink;
|
|
18228
|
+
this.isTty = isTty;
|
|
18229
|
+
}
|
|
18230
|
+
flags;
|
|
18231
|
+
sink;
|
|
18232
|
+
isTty;
|
|
18233
|
+
kind = "stream";
|
|
18234
|
+
queue = [];
|
|
18235
|
+
queued = 0;
|
|
18236
|
+
ended = false;
|
|
18237
|
+
waiters = [];
|
|
18238
|
+
/** Host side: give the guest more input. */
|
|
18239
|
+
push(data) {
|
|
18240
|
+
if (data.length === 0) return;
|
|
18241
|
+
this.queue.push(data);
|
|
18242
|
+
this.queued += data.length;
|
|
18243
|
+
this.wake();
|
|
18244
|
+
}
|
|
18245
|
+
/** Host side: no more input will arrive. */
|
|
18246
|
+
end() {
|
|
18247
|
+
this.ended = true;
|
|
18248
|
+
this.wake();
|
|
18249
|
+
}
|
|
18250
|
+
read(length) {
|
|
18251
|
+
if (this.queued === 0) {
|
|
18252
|
+
if (this.ended) return new Uint8Array();
|
|
18253
|
+
throw new PosixError(Errno.EAGAIN);
|
|
18254
|
+
}
|
|
18255
|
+
const out = new Uint8Array(Math.min(length, this.queued));
|
|
18256
|
+
let at = 0;
|
|
18257
|
+
while (at < out.length) {
|
|
18258
|
+
const head2 = this.queue[0];
|
|
18259
|
+
const take = Math.min(head2.length, out.length - at);
|
|
18260
|
+
out.set(head2.subarray(0, take), at);
|
|
18261
|
+
at += take;
|
|
18262
|
+
if (take === head2.length) this.queue.shift();
|
|
18263
|
+
else this.queue[0] = head2.subarray(take);
|
|
18264
|
+
}
|
|
18265
|
+
this.queued -= out.length;
|
|
18266
|
+
return out;
|
|
18267
|
+
}
|
|
18268
|
+
write(data) {
|
|
18269
|
+
if (!this.sink) throw new PosixError(Errno.EBADF);
|
|
18270
|
+
this.sink(data);
|
|
18271
|
+
return data.length;
|
|
18272
|
+
}
|
|
18273
|
+
stat() {
|
|
18274
|
+
const now = Date.now();
|
|
18275
|
+
return {
|
|
18276
|
+
ino: 0,
|
|
18277
|
+
mode: this.isTty ? 8592 : 4480,
|
|
18278
|
+
size: 0,
|
|
18279
|
+
uid: 0,
|
|
18280
|
+
gid: 0,
|
|
18281
|
+
nlink: 1,
|
|
18282
|
+
atimeMs: now,
|
|
18283
|
+
mtimeMs: now,
|
|
18284
|
+
ctimeMs: now
|
|
18285
|
+
};
|
|
18286
|
+
}
|
|
18287
|
+
readable() {
|
|
18288
|
+
return this.queued > 0 || this.ended;
|
|
18289
|
+
}
|
|
18290
|
+
writable() {
|
|
18291
|
+
return true;
|
|
18292
|
+
}
|
|
18293
|
+
whenReady() {
|
|
18294
|
+
return new Promise((resolve2) => this.waiters.push(resolve2));
|
|
18295
|
+
}
|
|
18296
|
+
close() {
|
|
18297
|
+
this.wake();
|
|
18298
|
+
}
|
|
18299
|
+
wake() {
|
|
18300
|
+
const waiting = this.waiters;
|
|
18301
|
+
this.waiters = [];
|
|
18302
|
+
for (const resolve2 of waiting) resolve2();
|
|
18303
|
+
}
|
|
18304
|
+
};
|
|
18305
|
+
function toPosixError(error) {
|
|
18306
|
+
if (error instanceof PosixError) return error;
|
|
18307
|
+
const code = error?.code;
|
|
18308
|
+
const message = error?.message;
|
|
18309
|
+
const mapped = {
|
|
18310
|
+
ENOENT: Errno.ENOENT,
|
|
18311
|
+
EEXIST: Errno.EEXIST,
|
|
18312
|
+
ENOTDIR: Errno.ENOTDIR,
|
|
18313
|
+
EISDIR: Errno.EISDIR,
|
|
18314
|
+
EACCES: Errno.EACCES,
|
|
18315
|
+
EPERM: Errno.EPERM,
|
|
18316
|
+
ENOTEMPTY: Errno.ENOTEMPTY,
|
|
18317
|
+
EINVAL: Errno.EINVAL,
|
|
18318
|
+
ELOOP: Errno.ELOOP,
|
|
18319
|
+
EXDEV: Errno.EXDEV,
|
|
18320
|
+
ENOSPC: Errno.ENOSPC,
|
|
18321
|
+
EMFILE: Errno.EMFILE,
|
|
18322
|
+
ENAMETOOLONG: Errno.ENAMETOOLONG,
|
|
18323
|
+
EBADF: Errno.EBADF,
|
|
18324
|
+
EPIPE: Errno.EPIPE
|
|
18325
|
+
};
|
|
18326
|
+
return new PosixError(code && mapped[code] ? mapped[code] : Errno.EIO, message);
|
|
18327
|
+
}
|
|
18328
|
+
var DescriptorTable = class _DescriptorTable {
|
|
18329
|
+
slots = /* @__PURE__ */ new Map();
|
|
18330
|
+
/** Descriptions this table shares with others, so close counts correctly. */
|
|
18331
|
+
static refs = /* @__PURE__ */ new WeakMap();
|
|
18332
|
+
/** Install at a chosen number, closing whatever was there. */
|
|
18333
|
+
set(fd, description, cloexec = false) {
|
|
18334
|
+
if (fd < 0) throw new PosixError(Errno.EBADF);
|
|
18335
|
+
const existing = this.slots.get(fd);
|
|
18336
|
+
if (existing) this.release(existing.description);
|
|
18337
|
+
this.slots.set(fd, { description, cloexec });
|
|
18338
|
+
_DescriptorTable.refs.set(description, (_DescriptorTable.refs.get(description) ?? 0) + 1);
|
|
18339
|
+
return fd;
|
|
18340
|
+
}
|
|
18341
|
+
/** Install at the lowest free number at or above `from`. */
|
|
18342
|
+
add(description, cloexec = false, from = 0) {
|
|
18343
|
+
let fd = from;
|
|
18344
|
+
while (this.slots.has(fd)) fd += 1;
|
|
18345
|
+
return this.set(fd, description, cloexec);
|
|
18346
|
+
}
|
|
18347
|
+
get(fd) {
|
|
18348
|
+
const slot = this.slots.get(fd);
|
|
18349
|
+
if (!slot) throw new PosixError(Errno.EBADF);
|
|
18350
|
+
return slot.description;
|
|
18351
|
+
}
|
|
18352
|
+
has(fd) {
|
|
18353
|
+
return this.slots.has(fd);
|
|
18354
|
+
}
|
|
18355
|
+
cloexec(fd) {
|
|
18356
|
+
const slot = this.slots.get(fd);
|
|
18357
|
+
if (!slot) throw new PosixError(Errno.EBADF);
|
|
18358
|
+
return slot.cloexec;
|
|
18359
|
+
}
|
|
18360
|
+
setCloexec(fd, value) {
|
|
18361
|
+
const slot = this.slots.get(fd);
|
|
18362
|
+
if (!slot) throw new PosixError(Errno.EBADF);
|
|
18363
|
+
slot.cloexec = value;
|
|
18364
|
+
}
|
|
18365
|
+
/** `dup`: a second name for one description, so the offset is shared. */
|
|
18366
|
+
dup(fd, from = 0) {
|
|
18367
|
+
return this.add(this.get(fd), false, from);
|
|
18368
|
+
}
|
|
18369
|
+
dup2(fd, target) {
|
|
18370
|
+
const description = this.get(fd);
|
|
18371
|
+
if (fd === target) return target;
|
|
18372
|
+
return this.set(target, description, false);
|
|
18373
|
+
}
|
|
18374
|
+
close(fd) {
|
|
18375
|
+
const slot = this.slots.get(fd);
|
|
18376
|
+
if (!slot) throw new PosixError(Errno.EBADF);
|
|
18377
|
+
this.slots.delete(fd);
|
|
18378
|
+
this.release(slot.description);
|
|
18379
|
+
}
|
|
18380
|
+
/** Everything a child inherits: a spawn keeps all but the close-on-exec ones. */
|
|
18381
|
+
inherit() {
|
|
18382
|
+
const child = new _DescriptorTable();
|
|
18383
|
+
for (const [fd, slot] of this.slots) {
|
|
18384
|
+
if (slot.cloexec) continue;
|
|
18385
|
+
child.set(fd, slot.description, false);
|
|
18386
|
+
}
|
|
18387
|
+
return child;
|
|
18388
|
+
}
|
|
18389
|
+
/** Drop every descriptor. Every resource has an owner and a cleanup path. */
|
|
18390
|
+
closeAll() {
|
|
18391
|
+
for (const fd of [...this.slots.keys()]) {
|
|
18392
|
+
try {
|
|
18393
|
+
this.close(fd);
|
|
18394
|
+
} catch {
|
|
18395
|
+
}
|
|
18396
|
+
}
|
|
18397
|
+
}
|
|
18398
|
+
get openCount() {
|
|
18399
|
+
return this.slots.size;
|
|
18400
|
+
}
|
|
18401
|
+
release(description) {
|
|
18402
|
+
const refs = (_DescriptorTable.refs.get(description) ?? 1) - 1;
|
|
18403
|
+
if (refs <= 0) {
|
|
18404
|
+
_DescriptorTable.refs.delete(description);
|
|
18405
|
+
description.close();
|
|
18406
|
+
} else {
|
|
18407
|
+
_DescriptorTable.refs.set(description, refs);
|
|
18408
|
+
}
|
|
18409
|
+
}
|
|
18410
|
+
};
|
|
18411
|
+
var FileService = class {
|
|
18412
|
+
constructor(vfs, cred) {
|
|
18413
|
+
this.vfs = vfs;
|
|
18414
|
+
this.cred = cred;
|
|
18415
|
+
}
|
|
18416
|
+
vfs;
|
|
18417
|
+
cred;
|
|
18418
|
+
openInodes = /* @__PURE__ */ new Map();
|
|
18419
|
+
open(path, flags, mode = 438) {
|
|
18420
|
+
const exists = this.vfs.lexists(path);
|
|
18421
|
+
if (flags & O_CREAT2 && flags & O_EXCL2 && exists) throw new PosixError(Errno.EEXIST);
|
|
18422
|
+
if (!exists) {
|
|
18423
|
+
if (!(flags & O_CREAT2)) throw new PosixError(Errno.ENOENT);
|
|
18424
|
+
if (accessMode(flags) === O_RDONLY) throw new PosixError(Errno.EACCES);
|
|
18425
|
+
try {
|
|
18426
|
+
this.vfs.writeFile(path, new Uint8Array(), { cred: this.cred, mode });
|
|
18427
|
+
} catch (error) {
|
|
18428
|
+
throw toPosixError(error);
|
|
18429
|
+
}
|
|
18430
|
+
}
|
|
18431
|
+
let stat2;
|
|
18432
|
+
try {
|
|
18433
|
+
stat2 = this.vfs.stat(path, { cred: this.cred });
|
|
18434
|
+
} catch (error) {
|
|
18435
|
+
throw toPosixError(error);
|
|
18436
|
+
}
|
|
18437
|
+
if (stat2.isDirectory()) {
|
|
18438
|
+
if (accessMode(flags) !== O_RDONLY) throw new PosixError(Errno.EISDIR);
|
|
18439
|
+
return new DirectoryDescription(path, flags, this.vfs, this.cred);
|
|
18440
|
+
}
|
|
18441
|
+
if (flags & O_DIRECTORY2) throw new PosixError(Errno.ENOTDIR);
|
|
18442
|
+
const inode = this.inodeFor(stat2.ino, path);
|
|
18443
|
+
const description = new FileDescription(inode, flags);
|
|
18444
|
+
if (flags & O_TRUNC2 && accessMode(flags) !== O_RDONLY) description.truncate(0);
|
|
18445
|
+
return description;
|
|
18446
|
+
}
|
|
18447
|
+
/**
|
|
18448
|
+
* Remove a name.
|
|
18449
|
+
*
|
|
18450
|
+
* If something still has the file open, its contents move into the open
|
|
18451
|
+
* description first: POSIX guarantees a reader keeps reading, and a volume
|
|
18452
|
+
* that only knows about paths cannot provide that on its own.
|
|
18453
|
+
*/
|
|
18454
|
+
unlink(path) {
|
|
18455
|
+
let ino = null;
|
|
18456
|
+
try {
|
|
18457
|
+
ino = this.vfs.lstat(path).ino;
|
|
18458
|
+
} catch (error) {
|
|
18459
|
+
throw toPosixError(error);
|
|
18460
|
+
}
|
|
18461
|
+
const inode = ino === null ? void 0 : this.openInodes.get(ino);
|
|
18462
|
+
if (inode && inode.refs > 0 && inode.path === path) inode.detach();
|
|
18463
|
+
try {
|
|
18464
|
+
this.vfs.unlink(path, this.cred);
|
|
18465
|
+
} catch (error) {
|
|
18466
|
+
throw toPosixError(error);
|
|
18467
|
+
}
|
|
18468
|
+
if (inode && inode.refs <= 0) this.openInodes.delete(ino);
|
|
18469
|
+
}
|
|
18470
|
+
/** Rename a name. Anything already open follows the file to its new name. */
|
|
18471
|
+
rename(from, to) {
|
|
18472
|
+
let ino = null;
|
|
18473
|
+
try {
|
|
18474
|
+
ino = this.vfs.lstat(from).ino;
|
|
18475
|
+
} catch {
|
|
18476
|
+
}
|
|
18477
|
+
try {
|
|
18478
|
+
this.vfs.rename(from, to, this.cred);
|
|
18479
|
+
} catch (error) {
|
|
18480
|
+
throw toPosixError(error);
|
|
18481
|
+
}
|
|
18482
|
+
if (ino === null) return;
|
|
18483
|
+
const inode = this.openInodes.get(ino);
|
|
18484
|
+
if (inode) inode.path = to;
|
|
18485
|
+
}
|
|
18486
|
+
/** One {@link Inode} per file identity, shared by every open description. */
|
|
18487
|
+
inodeFor(ino, path) {
|
|
18488
|
+
const existing = this.openInodes.get(ino);
|
|
18489
|
+
if (existing) {
|
|
18490
|
+
existing.path = path;
|
|
18491
|
+
return existing;
|
|
18492
|
+
}
|
|
18493
|
+
const created = new Inode(ino, path, this.vfs, this.cred);
|
|
18494
|
+
this.openInodes.set(ino, created);
|
|
18495
|
+
return created;
|
|
18496
|
+
}
|
|
18497
|
+
};
|
|
18498
|
+
|
|
18499
|
+
// src/runtime/python/protocol.ts
|
|
18500
|
+
var ProtocolError = class extends Error {
|
|
18501
|
+
code = "ERR_SBX_ABI_PROTOCOL";
|
|
18502
|
+
};
|
|
18503
|
+
function decodeRequest(frame) {
|
|
18504
|
+
if (frame.length < SBX_REQUEST_HEADER_BYTES) throw new ProtocolError("short request frame");
|
|
18505
|
+
const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
|
|
18506
|
+
const header = {
|
|
18507
|
+
version: view.getUint16(0, true),
|
|
18508
|
+
op: view.getUint16(2, true),
|
|
18509
|
+
requestId: view.getUint32(4, true),
|
|
18510
|
+
generation: view.getUint32(8, true)
|
|
18511
|
+
};
|
|
18512
|
+
const length = view.getUint32(12, true);
|
|
18513
|
+
if (frame.length - SBX_REQUEST_HEADER_BYTES < length) {
|
|
18514
|
+
throw new ProtocolError(`truncated payload for ${OP_NAMES[header.op] ?? header.op}`);
|
|
18515
|
+
}
|
|
18516
|
+
return {
|
|
18517
|
+
header,
|
|
18518
|
+
payload: frame.subarray(SBX_REQUEST_HEADER_BYTES, SBX_REQUEST_HEADER_BYTES + length)
|
|
18519
|
+
};
|
|
18520
|
+
}
|
|
18521
|
+
function encodeResponse(header, status, payload) {
|
|
18522
|
+
const frame = new Uint8Array(SBX_RESPONSE_HEADER_BYTES + payload.length);
|
|
18523
|
+
const view = new DataView(frame.buffer);
|
|
18524
|
+
view.setUint16(0, header.version, true);
|
|
18525
|
+
view.setUint16(2, header.op, true);
|
|
18526
|
+
view.setUint32(4, header.requestId, true);
|
|
18527
|
+
view.setUint32(8, header.generation, true);
|
|
18528
|
+
view.setInt32(12, status, true);
|
|
18529
|
+
view.setUint32(16, payload.length, true);
|
|
18530
|
+
frame.set(payload, SBX_RESPONSE_HEADER_BYTES);
|
|
18531
|
+
return frame;
|
|
18532
|
+
}
|
|
18533
|
+
var Reader = class {
|
|
18534
|
+
at = 0;
|
|
18535
|
+
view;
|
|
18536
|
+
bytes;
|
|
18537
|
+
constructor(bytes2) {
|
|
18538
|
+
this.bytes = bytes2;
|
|
18539
|
+
this.view = new DataView(bytes2.buffer, bytes2.byteOffset, bytes2.byteLength);
|
|
18540
|
+
}
|
|
18541
|
+
need(count) {
|
|
18542
|
+
if (this.at + count > this.bytes.length) throw new ProtocolError("payload underrun");
|
|
18543
|
+
const offset = this.at;
|
|
18544
|
+
this.at += count;
|
|
18545
|
+
return offset;
|
|
18546
|
+
}
|
|
18547
|
+
i32() {
|
|
18548
|
+
return this.view.getInt32(this.need(4), true);
|
|
18549
|
+
}
|
|
18550
|
+
u32() {
|
|
18551
|
+
return this.view.getUint32(this.need(4), true);
|
|
18552
|
+
}
|
|
18553
|
+
i64() {
|
|
18554
|
+
return Number(this.view.getBigInt64(this.need(8), true));
|
|
18555
|
+
}
|
|
18556
|
+
u64() {
|
|
18557
|
+
return Number(this.view.getBigUint64(this.need(8), true));
|
|
18558
|
+
}
|
|
18559
|
+
bytes32() {
|
|
18560
|
+
const length = this.u32();
|
|
18561
|
+
const offset = this.need(length);
|
|
18562
|
+
return this.bytes.subarray(offset, offset + length);
|
|
18563
|
+
}
|
|
18564
|
+
string() {
|
|
18565
|
+
return new TextDecoder().decode(this.bytes32());
|
|
18566
|
+
}
|
|
18567
|
+
get remaining() {
|
|
18568
|
+
return this.bytes.length - this.at;
|
|
18569
|
+
}
|
|
18570
|
+
};
|
|
18571
|
+
var Writer = class {
|
|
18572
|
+
parts = [];
|
|
18573
|
+
i32(value) {
|
|
18574
|
+
const b = new Uint8Array(4);
|
|
18575
|
+
new DataView(b.buffer).setInt32(0, value, true);
|
|
18576
|
+
this.parts.push(b);
|
|
18577
|
+
return this;
|
|
18578
|
+
}
|
|
18579
|
+
u32(value) {
|
|
18580
|
+
const b = new Uint8Array(4);
|
|
18581
|
+
new DataView(b.buffer).setUint32(0, value >>> 0, true);
|
|
18582
|
+
this.parts.push(b);
|
|
18583
|
+
return this;
|
|
18584
|
+
}
|
|
18585
|
+
i64(value) {
|
|
18586
|
+
const b = new Uint8Array(8);
|
|
18587
|
+
new DataView(b.buffer).setBigInt64(0, BigInt(Math.trunc(value)), true);
|
|
18588
|
+
this.parts.push(b);
|
|
18589
|
+
return this;
|
|
18590
|
+
}
|
|
18591
|
+
u64(value) {
|
|
18592
|
+
const b = new Uint8Array(8);
|
|
18593
|
+
new DataView(b.buffer).setBigUint64(0, BigInt(Math.trunc(value)), true);
|
|
18594
|
+
this.parts.push(b);
|
|
18595
|
+
return this;
|
|
18596
|
+
}
|
|
18597
|
+
bytes32(value) {
|
|
18598
|
+
this.u32(value.length);
|
|
18599
|
+
this.parts.push(value);
|
|
18600
|
+
return this;
|
|
18601
|
+
}
|
|
18602
|
+
string(value) {
|
|
18603
|
+
return this.bytes32(new TextEncoder().encode(value));
|
|
18604
|
+
}
|
|
18605
|
+
finish() {
|
|
18606
|
+
const total = this.parts.reduce((sum, part) => sum + part.length, 0);
|
|
18607
|
+
const out = new Uint8Array(total);
|
|
18608
|
+
let at = 0;
|
|
18609
|
+
for (const part of this.parts) {
|
|
18610
|
+
out.set(part, at);
|
|
18611
|
+
at += part.length;
|
|
18612
|
+
}
|
|
18613
|
+
return out;
|
|
18614
|
+
}
|
|
18615
|
+
};
|
|
18616
|
+
function failure(errno) {
|
|
18617
|
+
return -Math.abs(errno);
|
|
18618
|
+
}
|
|
18619
|
+
|
|
18620
|
+
// src/runtime/python/syscall-server.ts
|
|
18621
|
+
var MAX_TRANSFER = 8 * 1024 * 1024;
|
|
18622
|
+
function createHostAbiServer(proc) {
|
|
18623
|
+
const files = new FileService(proc.vfs, proc.cred);
|
|
18624
|
+
const started = Date.now();
|
|
18625
|
+
const monotonicBase = typeof performance === "object" ? performance.now() : 0;
|
|
18626
|
+
return async (frame) => {
|
|
18627
|
+
const { header, payload } = decodeRequest(frame);
|
|
18628
|
+
if (header.version !== SBX_HOST_ABI_VERSION) {
|
|
18629
|
+
return encodeResponse(header, failure(Errno.EPROTO), new Uint8Array());
|
|
18630
|
+
}
|
|
18631
|
+
if (header.generation !== proc.generation) {
|
|
18632
|
+
return encodeResponse(header, failure(Errno.ESRCH), new Uint8Array());
|
|
18633
|
+
}
|
|
18634
|
+
try {
|
|
18635
|
+
const { status, payload: out } = await dispatch(header, new Reader(payload));
|
|
18636
|
+
return encodeResponse(header, status, out ?? new Uint8Array());
|
|
18637
|
+
} catch (error) {
|
|
18638
|
+
const posix = toPosixError(error);
|
|
18639
|
+
return encodeResponse(header, failure(posix.errno), new Uint8Array());
|
|
18640
|
+
}
|
|
18641
|
+
};
|
|
18642
|
+
async function dispatch(header, r) {
|
|
18643
|
+
switch (header.op) {
|
|
18644
|
+
case Op.handshake: {
|
|
18645
|
+
const w = new Writer().u32(SBX_HOST_ABI_VERSION).u32(CAPABILITIES.length);
|
|
18646
|
+
for (const capability of CAPABILITIES) {
|
|
18647
|
+
w.string(capability).u32(implemented(capability) ? 1 : 0);
|
|
18648
|
+
}
|
|
18649
|
+
return { status: 0, payload: w.finish() };
|
|
18650
|
+
}
|
|
18651
|
+
/* ------------------------------------------------------------ files */
|
|
18652
|
+
case Op.openat: {
|
|
18653
|
+
const path = resolve2(r.string());
|
|
18654
|
+
const flags = r.u32();
|
|
18655
|
+
const mode = r.u32();
|
|
18656
|
+
const description = files.open(path, flags, mode);
|
|
18657
|
+
return { status: proc.table.add(description, (flags & O_CLOEXEC) !== 0) };
|
|
18658
|
+
}
|
|
18659
|
+
case Op.close: {
|
|
18660
|
+
proc.table.close(r.i32());
|
|
18661
|
+
return { status: 0 };
|
|
18662
|
+
}
|
|
18663
|
+
case Op.read: {
|
|
18664
|
+
const description = proc.table.get(r.i32());
|
|
18665
|
+
const length = clamp(r.u32());
|
|
18666
|
+
const data = await readBlocking(description, length);
|
|
18667
|
+
return { status: data.length, payload: data };
|
|
18668
|
+
}
|
|
18669
|
+
case Op.write: {
|
|
18670
|
+
const description = proc.table.get(r.i32());
|
|
18671
|
+
const data = r.bytes32();
|
|
18672
|
+
const written = await writeBlocking(description, data);
|
|
18673
|
+
return { status: written };
|
|
18674
|
+
}
|
|
18675
|
+
case Op.pread: {
|
|
18676
|
+
const description = proc.table.get(r.i32());
|
|
18677
|
+
const length = clamp(r.u32());
|
|
18678
|
+
const offset = r.u64();
|
|
18679
|
+
if (!description.pread) throw new PosixError(Errno.ESPIPE);
|
|
18680
|
+
const data = description.pread(length, offset);
|
|
18681
|
+
return { status: data.length, payload: data };
|
|
18682
|
+
}
|
|
18683
|
+
case Op.pwrite: {
|
|
18684
|
+
const description = proc.table.get(r.i32());
|
|
18685
|
+
const data = r.bytes32();
|
|
18686
|
+
const offset = r.u64();
|
|
18687
|
+
if (!description.pwrite) throw new PosixError(Errno.ESPIPE);
|
|
18688
|
+
return { status: description.pwrite(data, offset) };
|
|
18689
|
+
}
|
|
18690
|
+
case Op.lseek: {
|
|
18691
|
+
const description = proc.table.get(r.i32());
|
|
18692
|
+
const offset = r.i64();
|
|
18693
|
+
const whence = r.u32();
|
|
18694
|
+
if (!description.seek) throw new PosixError(Errno.ESPIPE);
|
|
18695
|
+
return { status: 0, payload: new Writer().i64(description.seek(offset, whence)).finish() };
|
|
18696
|
+
}
|
|
18697
|
+
case Op.fstat: {
|
|
18698
|
+
return { status: 0, payload: encodeStat(proc.table.get(r.i32()).stat()) };
|
|
18699
|
+
}
|
|
18700
|
+
case Op.statat: {
|
|
18701
|
+
const path = resolve2(r.string());
|
|
18702
|
+
const followLinks = r.u32() !== 0;
|
|
18703
|
+
try {
|
|
18704
|
+
const st = followLinks ? proc.vfs.stat(path, { cred: proc.cred }) : proc.vfs.lstat(path);
|
|
18705
|
+
return {
|
|
18706
|
+
status: 0,
|
|
18707
|
+
payload: encodeStat({
|
|
18708
|
+
ino: st.ino,
|
|
18709
|
+
mode: st.mode,
|
|
18710
|
+
size: st.size,
|
|
18711
|
+
uid: st.uid,
|
|
18712
|
+
gid: st.gid,
|
|
18713
|
+
nlink: st.nlink ?? 1,
|
|
18714
|
+
atimeMs: st.atimeMs,
|
|
18715
|
+
mtimeMs: st.mtimeMs,
|
|
18716
|
+
ctimeMs: st.ctimeMs
|
|
18717
|
+
})
|
|
18718
|
+
};
|
|
18719
|
+
} catch (error) {
|
|
18720
|
+
throw toPosixError(error);
|
|
18721
|
+
}
|
|
18722
|
+
}
|
|
18723
|
+
case Op.ftruncate: {
|
|
18724
|
+
const description = proc.table.get(r.i32());
|
|
18725
|
+
const length = r.u64();
|
|
18726
|
+
if (!description.truncate) throw new PosixError(Errno.EINVAL);
|
|
18727
|
+
description.truncate(length);
|
|
18728
|
+
return { status: 0 };
|
|
18729
|
+
}
|
|
18730
|
+
case Op.renameat: {
|
|
18731
|
+
files.rename(resolve2(r.string()), resolve2(r.string()));
|
|
18732
|
+
return { status: 0 };
|
|
18733
|
+
}
|
|
18734
|
+
case Op.unlinkat: {
|
|
18735
|
+
const path = resolve2(r.string());
|
|
18736
|
+
const removeDirectory = r.u32() !== 0;
|
|
18737
|
+
if (removeDirectory) {
|
|
18738
|
+
try {
|
|
18739
|
+
proc.vfs.rmdir(path, proc.cred);
|
|
18740
|
+
} catch (error) {
|
|
18741
|
+
throw toPosixError(error);
|
|
18742
|
+
}
|
|
18743
|
+
} else {
|
|
18744
|
+
files.unlink(path);
|
|
18745
|
+
}
|
|
18746
|
+
return { status: 0 };
|
|
18747
|
+
}
|
|
18748
|
+
case Op.mkdirat: {
|
|
18749
|
+
const path = resolve2(r.string());
|
|
18750
|
+
const mode = r.u32();
|
|
18751
|
+
try {
|
|
18752
|
+
proc.vfs.mkdir(path, { mode, cred: proc.cred });
|
|
18753
|
+
} catch (error) {
|
|
18754
|
+
throw toPosixError(error);
|
|
18755
|
+
}
|
|
18756
|
+
return { status: 0 };
|
|
18757
|
+
}
|
|
18758
|
+
case Op.readlinkat: {
|
|
18759
|
+
try {
|
|
18760
|
+
const target = proc.vfs.readlink(resolve2(r.string()), proc.cred);
|
|
18761
|
+
return { status: 0, payload: new Writer().string(target).finish() };
|
|
18762
|
+
} catch (error) {
|
|
18763
|
+
throw toPosixError(error);
|
|
18764
|
+
}
|
|
18765
|
+
}
|
|
18766
|
+
case Op.symlinkat: {
|
|
18767
|
+
const target = r.string();
|
|
18768
|
+
try {
|
|
18769
|
+
proc.vfs.symlink(target, resolve2(r.string()), proc.cred);
|
|
18770
|
+
} catch (error) {
|
|
18771
|
+
throw toPosixError(error);
|
|
18772
|
+
}
|
|
18773
|
+
return { status: 0 };
|
|
18774
|
+
}
|
|
18775
|
+
case Op.getdents: {
|
|
18776
|
+
const description = proc.table.get(r.i32());
|
|
18777
|
+
if (description.kind !== "dir") throw new PosixError(Errno.ENOTDIR);
|
|
18778
|
+
const data = description.read(clamp(r.u32()));
|
|
18779
|
+
return { status: data.length, payload: data };
|
|
18780
|
+
}
|
|
18781
|
+
case Op.fsync: {
|
|
18782
|
+
proc.table.get(r.i32());
|
|
18783
|
+
return { status: 0 };
|
|
18784
|
+
}
|
|
18785
|
+
/* ------------------------------------------------------ descriptors */
|
|
18786
|
+
case Op.dup:
|
|
18787
|
+
return { status: proc.table.dup(r.i32(), r.u32()) };
|
|
18788
|
+
case Op.dup2:
|
|
18789
|
+
return { status: proc.table.dup2(r.i32(), r.i32()) };
|
|
18790
|
+
case Op.get_flags: {
|
|
18791
|
+
const fd = r.i32();
|
|
18792
|
+
const description = proc.table.get(fd);
|
|
18793
|
+
return { status: 0, payload: new Writer().u32(description.flags).u32(proc.table.cloexec(fd) ? 1 : 0).finish() };
|
|
18794
|
+
}
|
|
18795
|
+
case Op.set_flags: {
|
|
18796
|
+
const fd = r.i32();
|
|
18797
|
+
const flags = r.u32();
|
|
18798
|
+
const cloexec = r.u32();
|
|
18799
|
+
const description = proc.table.get(fd);
|
|
18800
|
+
description.flags = accessMode(description.flags) | flags & -4;
|
|
18801
|
+
proc.table.setCloexec(fd, cloexec !== 0);
|
|
18802
|
+
return { status: 0 };
|
|
18803
|
+
}
|
|
18804
|
+
/* ------------------------------------------------------------ pipes */
|
|
18805
|
+
case Op.pipe: {
|
|
18806
|
+
const flags = r.u32();
|
|
18807
|
+
const [readEnd, writeEnd] = createPipe(flags & O_NONBLOCK);
|
|
18808
|
+
const cloexec = (flags & O_CLOEXEC) !== 0;
|
|
18809
|
+
const readFd = proc.table.add(readEnd, cloexec);
|
|
18810
|
+
const writeFd = proc.table.add(writeEnd, cloexec);
|
|
18811
|
+
return { status: 0, payload: new Writer().i32(readFd).i32(writeFd).finish() };
|
|
18812
|
+
}
|
|
18813
|
+
/* -------------------------------------------------------- readiness */
|
|
18814
|
+
case Op.poll: {
|
|
18815
|
+
const count = r.u32();
|
|
18816
|
+
const requests = [];
|
|
18817
|
+
for (let i = 0; i < count; i += 1) requests.push({ fd: r.i32(), events: r.u32() });
|
|
18818
|
+
const timeoutMs = r.i64();
|
|
18819
|
+
const ready = await poll(requests, timeoutMs);
|
|
18820
|
+
const w = new Writer().u32(ready.length);
|
|
18821
|
+
for (const entry of ready) w.i32(entry.fd).u32(entry.revents);
|
|
18822
|
+
return { status: ready.length, payload: w.finish() };
|
|
18823
|
+
}
|
|
18824
|
+
/* ------------------------------------------------------------- time */
|
|
18825
|
+
case Op.clock_gettime: {
|
|
18826
|
+
const monotonic = r.u32() !== 0;
|
|
18827
|
+
const now = monotonic ? (typeof performance === "object" ? performance.now() : Date.now() - started) - monotonicBase : Date.now();
|
|
18828
|
+
const nanos = Math.round(now * 1e6);
|
|
18829
|
+
return { status: 0, payload: new Writer().i64(Math.floor(nanos / 1e9)).u32(nanos % 1e9).finish() };
|
|
18830
|
+
}
|
|
18831
|
+
case Op.sleep: {
|
|
18832
|
+
const nanos = r.u64();
|
|
18833
|
+
await sleep(nanos / 1e6);
|
|
18834
|
+
return { status: proc.signal.aborted ? failure(Errno.EINTR) : 0 };
|
|
18835
|
+
}
|
|
18836
|
+
/* --------------------------------------------------------- identity */
|
|
18837
|
+
case Op.getpid: {
|
|
18838
|
+
const w = new Writer().i32(proc.pid).i32(proc.ppid).u32(proc.cred.uid).u32(proc.cred.gid).u32(proc.cred.umask ?? 18);
|
|
18839
|
+
return { status: 0, payload: w.finish() };
|
|
18840
|
+
}
|
|
18841
|
+
case Op.getcwd:
|
|
18842
|
+
return { status: 0, payload: new Writer().string(proc.cwd).finish() };
|
|
18843
|
+
case Op.chdir: {
|
|
18844
|
+
const path = resolve2(r.string());
|
|
18845
|
+
let st;
|
|
18846
|
+
try {
|
|
18847
|
+
st = proc.vfs.stat(path, { cred: proc.cred });
|
|
18848
|
+
} catch (error) {
|
|
18849
|
+
throw toPosixError(error);
|
|
18850
|
+
}
|
|
18851
|
+
if (!st.isDirectory()) throw new PosixError(Errno.ENOTDIR);
|
|
18852
|
+
proc.cwd = path;
|
|
18853
|
+
return { status: 0 };
|
|
18854
|
+
}
|
|
18855
|
+
case Op.environ: {
|
|
18856
|
+
const joined = Object.entries(proc.env).map(([key, value]) => `${key}=${value}`).join("\0");
|
|
18857
|
+
return { status: 0, payload: new Writer().string(joined).finish() };
|
|
18858
|
+
}
|
|
18859
|
+
/* ---------------------------------------------------------- entropy */
|
|
18860
|
+
case Op.getrandom: {
|
|
18861
|
+
const length = Math.min(r.u32(), 65536);
|
|
18862
|
+
const bytes2 = new Uint8Array(length);
|
|
18863
|
+
crypto.getRandomValues(bytes2);
|
|
18864
|
+
return { status: length, payload: bytes2 };
|
|
18865
|
+
}
|
|
18866
|
+
default:
|
|
18867
|
+
return { status: failure(Errno.ENOSYS) };
|
|
18868
|
+
}
|
|
18869
|
+
}
|
|
18870
|
+
function implemented(capability) {
|
|
18871
|
+
return ["files", "descriptors", "pipes", "readiness", "time", "identity", "entropy"].includes(capability);
|
|
18872
|
+
}
|
|
18873
|
+
function resolve2(path) {
|
|
18874
|
+
if (path.startsWith("/")) return proc.vfs.resolvePath(path);
|
|
18875
|
+
return proc.vfs.resolvePath(`${proc.cwd.replace(/\/$/, "")}/${path}`);
|
|
18876
|
+
}
|
|
18877
|
+
function clamp(length) {
|
|
18878
|
+
return Math.min(length, MAX_TRANSFER);
|
|
18879
|
+
}
|
|
18880
|
+
async function readBlocking(description, length) {
|
|
18881
|
+
for (; ; ) {
|
|
18882
|
+
try {
|
|
18883
|
+
return description.read(length);
|
|
18884
|
+
} catch (error) {
|
|
18885
|
+
const posix = toPosixError(error);
|
|
18886
|
+
if (posix.errno !== Errno.EAGAIN || description.flags & O_NONBLOCK) throw posix;
|
|
18887
|
+
}
|
|
18888
|
+
await Promise.race([description.whenReady(), aborted()]);
|
|
18889
|
+
if (proc.signal.aborted) throw new PosixError(Errno.EINTR);
|
|
18890
|
+
}
|
|
18891
|
+
}
|
|
18892
|
+
async function writeBlocking(description, data) {
|
|
18893
|
+
for (; ; ) {
|
|
18894
|
+
try {
|
|
18895
|
+
return description.write(data);
|
|
18896
|
+
} catch (error) {
|
|
18897
|
+
const posix = toPosixError(error);
|
|
18898
|
+
if (posix.errno !== Errno.EAGAIN || description.flags & O_NONBLOCK) throw posix;
|
|
18899
|
+
}
|
|
18900
|
+
await Promise.race([description.whenReady(), aborted()]);
|
|
18901
|
+
if (proc.signal.aborted) throw new PosixError(Errno.EINTR);
|
|
18902
|
+
}
|
|
18903
|
+
}
|
|
18904
|
+
const POLLIN = 1;
|
|
18905
|
+
const POLLOUT = 4;
|
|
18906
|
+
const POLLHUP = 16;
|
|
18907
|
+
async function poll(requests, timeoutMs) {
|
|
18908
|
+
const deadline = timeoutMs < 0 ? Infinity : Date.now() + timeoutMs;
|
|
18909
|
+
for (; ; ) {
|
|
18910
|
+
const ready = [];
|
|
18911
|
+
const waits = [];
|
|
18912
|
+
for (const { fd, events } of requests) {
|
|
18913
|
+
let description;
|
|
18914
|
+
try {
|
|
18915
|
+
description = proc.table.get(fd);
|
|
18916
|
+
} catch {
|
|
18917
|
+
ready.push({ fd, revents: POLLHUP });
|
|
18918
|
+
continue;
|
|
18919
|
+
}
|
|
18920
|
+
let revents = 0;
|
|
18921
|
+
if (events & POLLIN && description.readable()) revents |= POLLIN;
|
|
18922
|
+
if (events & POLLOUT && description.writable()) revents |= POLLOUT;
|
|
18923
|
+
if (revents) ready.push({ fd, revents });
|
|
18924
|
+
else waits.push(description.whenReady());
|
|
18925
|
+
}
|
|
18926
|
+
if (ready.length > 0) return ready;
|
|
18927
|
+
const remaining = deadline - Date.now();
|
|
18928
|
+
if (remaining <= 0) return [];
|
|
18929
|
+
await Promise.race([...waits, sleep(Math.min(remaining, 50)), aborted()]);
|
|
18930
|
+
if (proc.signal.aborted) throw new PosixError(Errno.EINTR);
|
|
18931
|
+
}
|
|
18932
|
+
}
|
|
18933
|
+
function aborted() {
|
|
18934
|
+
if (proc.signal.aborted) return Promise.resolve();
|
|
18935
|
+
return new Promise((resolve3) => proc.signal.addEventListener("abort", () => resolve3(), { once: true }));
|
|
18936
|
+
}
|
|
18937
|
+
}
|
|
18938
|
+
function sleep(ms) {
|
|
18939
|
+
return new Promise((resolve2) => setTimeout(resolve2, Math.max(0, ms)));
|
|
18940
|
+
}
|
|
18941
|
+
function encodeStat(st) {
|
|
18942
|
+
return new Writer().u64(st.ino).u32(st.mode).u64(st.size).u32(st.uid).u32(st.gid).u32(st.nlink).i64(Math.round(st.atimeMs * 1e6)).i64(Math.round(st.mtimeMs * 1e6)).i64(Math.round(st.ctimeMs * 1e6)).finish();
|
|
18943
|
+
}
|
|
18944
|
+
|
|
18945
|
+
// src/runtime/python/sync-transport.ts
|
|
18946
|
+
var STATE = 0;
|
|
18947
|
+
var LENGTH = 1;
|
|
18948
|
+
var MORE = 2;
|
|
18949
|
+
var CONTROL_WORDS = 4;
|
|
18950
|
+
var STATE_REQUEST = 1;
|
|
18951
|
+
var STATE_RESPONSE = 2;
|
|
18952
|
+
var STATE_CONTINUE = 3;
|
|
18953
|
+
var STATE_CLOSED = 4;
|
|
18954
|
+
function createHostTransportBuffers(windowBytes = 1 << 20) {
|
|
18955
|
+
return {
|
|
18956
|
+
control: new SharedArrayBuffer(CONTROL_WORDS * Int32Array.BYTES_PER_ELEMENT),
|
|
18957
|
+
data: new SharedArrayBuffer(windowBytes)
|
|
18958
|
+
};
|
|
18959
|
+
}
|
|
18960
|
+
function syncTransportUnavailableReason() {
|
|
18961
|
+
if (typeof globalThis.crossOriginIsolated === "boolean" && !globalThis.crossOriginIsolated) {
|
|
18962
|
+
return "the page is not cross-origin isolated. Serve it with Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp.";
|
|
18963
|
+
}
|
|
18964
|
+
if (typeof SharedArrayBuffer !== "function") return "SharedArrayBuffer is unavailable in this host.";
|
|
18965
|
+
if (typeof Atomics !== "object" || typeof Atomics.wait !== "function") return "Atomics.wait is unavailable in this host.";
|
|
18966
|
+
return null;
|
|
18967
|
+
}
|
|
18968
|
+
var HostCallServer = class {
|
|
18969
|
+
control;
|
|
18970
|
+
data;
|
|
18971
|
+
capacity;
|
|
18972
|
+
handle;
|
|
18973
|
+
onFault;
|
|
18974
|
+
incoming = [];
|
|
18975
|
+
outgoing = null;
|
|
18976
|
+
sent = 0;
|
|
18977
|
+
closed = false;
|
|
18978
|
+
constructor(buffers, handle, onFault = () => {
|
|
18979
|
+
}) {
|
|
18980
|
+
this.control = new Int32Array(buffers.control);
|
|
18981
|
+
this.data = new Uint8Array(buffers.data);
|
|
18982
|
+
this.capacity = this.data.length;
|
|
18983
|
+
this.handle = handle;
|
|
18984
|
+
this.onFault = onFault;
|
|
18985
|
+
}
|
|
18986
|
+
/** Call on each wake message from the client. */
|
|
18987
|
+
async pump() {
|
|
18988
|
+
if (this.closed) return;
|
|
18989
|
+
const state = Atomics.load(this.control, STATE);
|
|
18990
|
+
if (state === STATE_REQUEST) {
|
|
18991
|
+
const size = Atomics.load(this.control, LENGTH);
|
|
18992
|
+
this.incoming.push(this.data.slice(0, size));
|
|
18993
|
+
if (Atomics.load(this.control, MORE) === 1) {
|
|
18994
|
+
this.publish(STATE_CONTINUE);
|
|
18995
|
+
return;
|
|
18996
|
+
}
|
|
18997
|
+
const request = concat3(this.incoming);
|
|
18998
|
+
this.incoming = [];
|
|
18999
|
+
let response;
|
|
19000
|
+
try {
|
|
19001
|
+
response = await this.handle(request);
|
|
19002
|
+
} catch (error) {
|
|
19003
|
+
this.onFault(error);
|
|
19004
|
+
this.close();
|
|
19005
|
+
return;
|
|
19006
|
+
}
|
|
19007
|
+
if (this.closed) return;
|
|
19008
|
+
this.outgoing = response;
|
|
19009
|
+
this.sent = 0;
|
|
19010
|
+
this.sendWindow();
|
|
19011
|
+
return;
|
|
19012
|
+
}
|
|
19013
|
+
if (state === STATE_CONTINUE) this.sendWindow();
|
|
19014
|
+
}
|
|
19015
|
+
/** Release a blocked client — container teardown, or the worker being killed. */
|
|
19016
|
+
close() {
|
|
19017
|
+
if (this.closed) return;
|
|
19018
|
+
this.closed = true;
|
|
19019
|
+
Atomics.store(this.control, STATE, STATE_CLOSED);
|
|
19020
|
+
Atomics.notify(this.control, STATE);
|
|
19021
|
+
}
|
|
19022
|
+
sendWindow() {
|
|
19023
|
+
const payload = this.outgoing ?? new Uint8Array();
|
|
19024
|
+
const size = Math.min(this.capacity, payload.length - this.sent);
|
|
19025
|
+
this.data.set(payload.subarray(this.sent, this.sent + size), 0);
|
|
19026
|
+
this.sent += size;
|
|
19027
|
+
Atomics.store(this.control, LENGTH, size);
|
|
19028
|
+
Atomics.store(this.control, MORE, this.sent < payload.length ? 1 : 0);
|
|
19029
|
+
this.publish(STATE_RESPONSE);
|
|
19030
|
+
}
|
|
19031
|
+
publish(state) {
|
|
19032
|
+
Atomics.store(this.control, STATE, state);
|
|
19033
|
+
Atomics.notify(this.control, STATE);
|
|
19034
|
+
}
|
|
19035
|
+
};
|
|
19036
|
+
function concat3(parts) {
|
|
19037
|
+
if (parts.length === 1) return parts[0];
|
|
19038
|
+
const total = parts.reduce((sum, part) => sum + part.length, 0);
|
|
19039
|
+
const joined = new Uint8Array(total);
|
|
19040
|
+
let at = 0;
|
|
19041
|
+
for (const part of parts) {
|
|
19042
|
+
joined.set(part, at);
|
|
19043
|
+
at += part.length;
|
|
19044
|
+
}
|
|
19045
|
+
return joined;
|
|
19046
|
+
}
|
|
19047
|
+
|
|
19048
|
+
// src/runtime/worker-host.ts
|
|
19049
|
+
function defaultWorkerUrl() {
|
|
19050
|
+
return new URL("./worker-entry.js", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
19051
|
+
}
|
|
19052
|
+
function hasDomWorker() {
|
|
19053
|
+
return typeof Worker === "function";
|
|
19054
|
+
}
|
|
19055
|
+
async function startRuntimeWorker(options = {}) {
|
|
19056
|
+
const url = options.url ?? defaultWorkerUrl();
|
|
19057
|
+
const worker = hasDomWorker() ? await startDomWorker(url) : await startNodeWorker(url, options.workerData ?? {});
|
|
19058
|
+
try {
|
|
19059
|
+
await new Promise((resolve2, reject) => {
|
|
19060
|
+
const timer = setTimeout(() => reject(new Error("the runtime worker did not start in time")), options.timeoutMs ?? 1e4);
|
|
19061
|
+
worker.onMessage((message) => {
|
|
19062
|
+
if (message?.type === "sandboxedjs:ready") {
|
|
19063
|
+
clearTimeout(timer);
|
|
19064
|
+
resolve2();
|
|
19065
|
+
}
|
|
19066
|
+
});
|
|
19067
|
+
worker.onError((error) => {
|
|
19068
|
+
clearTimeout(timer);
|
|
19069
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
19070
|
+
});
|
|
19071
|
+
});
|
|
19072
|
+
} catch (error) {
|
|
19073
|
+
try {
|
|
19074
|
+
await worker.terminate();
|
|
19075
|
+
} catch {
|
|
19076
|
+
}
|
|
19077
|
+
throw error;
|
|
19078
|
+
}
|
|
19079
|
+
return worker;
|
|
19080
|
+
}
|
|
19081
|
+
async function startDomWorker(url) {
|
|
19082
|
+
const worker = new Worker(url, { type: "module" });
|
|
19083
|
+
const listeners = [];
|
|
19084
|
+
const errors = [];
|
|
19085
|
+
worker.addEventListener("message", (event) => {
|
|
19086
|
+
for (const listener of listeners) listener(event.data);
|
|
19087
|
+
});
|
|
19088
|
+
worker.addEventListener("error", (event) => {
|
|
19089
|
+
const detail = event.message || "the runtime worker failed to load";
|
|
19090
|
+
for (const listener of errors) listener(new Error(detail));
|
|
19091
|
+
});
|
|
19092
|
+
return {
|
|
19093
|
+
postMessage: (message) => worker.postMessage(message),
|
|
19094
|
+
onMessage: (listener) => {
|
|
19095
|
+
listeners.push(listener);
|
|
19096
|
+
},
|
|
19097
|
+
onError: (listener) => {
|
|
19098
|
+
errors.push(listener);
|
|
19099
|
+
},
|
|
19100
|
+
terminate: () => worker.terminate()
|
|
19101
|
+
};
|
|
19102
|
+
}
|
|
19103
|
+
async function startNodeWorker(url, workerData) {
|
|
19104
|
+
const specifier = ["node", "worker_threads"].join(":");
|
|
19105
|
+
const { Worker: NodeWorker } = await import(
|
|
19106
|
+
/* @vite-ignore */
|
|
19107
|
+
/* webpackIgnore: true */
|
|
19108
|
+
specifier
|
|
19109
|
+
);
|
|
19110
|
+
const worker = new NodeWorker(url, { workerData });
|
|
19111
|
+
return {
|
|
19112
|
+
postMessage: (message) => worker.postMessage(message),
|
|
19113
|
+
onMessage: (listener) => worker.on("message", listener),
|
|
19114
|
+
onError: (listener) => worker.on("error", listener),
|
|
19115
|
+
terminate: () => worker.terminate()
|
|
19116
|
+
};
|
|
19117
|
+
}
|
|
19118
|
+
|
|
19119
|
+
// src/runtime/python/supervisor.ts
|
|
19120
|
+
var nextGeneration = 1;
|
|
19121
|
+
async function startPythonProcess(options) {
|
|
19122
|
+
const unavailable2 = syncTransportUnavailableReason();
|
|
19123
|
+
if (unavailable2) {
|
|
19124
|
+
throw new Error(`The SandboxedJs Python runtime needs blocking worker calls: ${unavailable2}`);
|
|
19125
|
+
}
|
|
19126
|
+
const generation = nextGeneration++;
|
|
19127
|
+
const stdin = new StreamDescription(O_RDONLY, null, options.isTty);
|
|
19128
|
+
const stdout = new StreamDescription(O_WRONLY, options.onStdout, options.isTty);
|
|
19129
|
+
const stderr = new StreamDescription(O_WRONLY, options.onStderr, options.isTty);
|
|
19130
|
+
const table = new DescriptorTable();
|
|
19131
|
+
table.set(0, stdin);
|
|
19132
|
+
table.set(1, stdout);
|
|
19133
|
+
table.set(2, stderr);
|
|
19134
|
+
const controller = new AbortController();
|
|
19135
|
+
const abort = () => controller.abort();
|
|
19136
|
+
options.signal.addEventListener("abort", abort, { once: true });
|
|
19137
|
+
const handle = createHostAbiServer({
|
|
19138
|
+
pid: options.pid,
|
|
19139
|
+
ppid: options.ppid,
|
|
19140
|
+
generation,
|
|
19141
|
+
vfs: options.vfs,
|
|
19142
|
+
cred: options.cred,
|
|
19143
|
+
table,
|
|
19144
|
+
env: options.env,
|
|
19145
|
+
cwd: options.cwd,
|
|
19146
|
+
signal: controller.signal
|
|
19147
|
+
});
|
|
19148
|
+
const buffers = createHostTransportBuffers();
|
|
19149
|
+
let fault = null;
|
|
19150
|
+
const server = new HostCallServer(buffers, handle, (error) => {
|
|
19151
|
+
fault = error;
|
|
19152
|
+
});
|
|
19153
|
+
let worker = null;
|
|
19154
|
+
let settle = () => {
|
|
19155
|
+
};
|
|
19156
|
+
let blame = () => {
|
|
19157
|
+
};
|
|
19158
|
+
const finished = new Promise((resolve2, reject) => {
|
|
19159
|
+
settle = resolve2;
|
|
19160
|
+
blame = reject;
|
|
19161
|
+
});
|
|
19162
|
+
let done = false;
|
|
19163
|
+
const cleanup = () => {
|
|
19164
|
+
if (done) return;
|
|
19165
|
+
done = true;
|
|
19166
|
+
options.signal.removeEventListener("abort", abort);
|
|
19167
|
+
server.close();
|
|
19168
|
+
table.closeAll();
|
|
19169
|
+
try {
|
|
19170
|
+
worker?.terminate();
|
|
19171
|
+
} catch {
|
|
19172
|
+
}
|
|
19173
|
+
};
|
|
19174
|
+
worker = await startRuntimeWorker({ url: options.workerUrl });
|
|
19175
|
+
worker.onMessage((message) => {
|
|
19176
|
+
const detail = message;
|
|
19177
|
+
if (detail?.type === "wake") {
|
|
19178
|
+
void server.pump();
|
|
19179
|
+
return;
|
|
19180
|
+
}
|
|
19181
|
+
if (detail?.type === "exit") {
|
|
19182
|
+
cleanup();
|
|
19183
|
+
settle(detail.code ?? 0);
|
|
19184
|
+
return;
|
|
19185
|
+
}
|
|
19186
|
+
if (detail?.type === "failed") {
|
|
19187
|
+
cleanup();
|
|
19188
|
+
blame(new Error(detail.message ?? "the Python process failed to start"));
|
|
19189
|
+
}
|
|
19190
|
+
});
|
|
19191
|
+
worker.onError((error) => {
|
|
19192
|
+
cleanup();
|
|
19193
|
+
blame(error instanceof Error ? error : new Error(String(error)));
|
|
19194
|
+
});
|
|
19195
|
+
controller.signal.addEventListener("abort", () => {
|
|
19196
|
+
if (done) return;
|
|
19197
|
+
cleanup();
|
|
19198
|
+
settle(130);
|
|
19199
|
+
});
|
|
19200
|
+
worker.postMessage({
|
|
19201
|
+
type: "start",
|
|
19202
|
+
buffers,
|
|
19203
|
+
generation,
|
|
19204
|
+
moduleUrl: options.manifest.artifacts.moduleUrl,
|
|
19205
|
+
argv: options.argv,
|
|
19206
|
+
env: options.env,
|
|
19207
|
+
cwd: options.cwd,
|
|
19208
|
+
pid: options.pid,
|
|
19209
|
+
ppid: options.ppid,
|
|
19210
|
+
mounts: options.mounts,
|
|
19211
|
+
isTty: options.isTty
|
|
19212
|
+
});
|
|
19213
|
+
return {
|
|
19214
|
+
write: (data) => stdin.push(data),
|
|
19215
|
+
endInput: () => stdin.end(),
|
|
19216
|
+
kill: () => controller.abort(),
|
|
19217
|
+
wait: async () => {
|
|
19218
|
+
const code = await finished;
|
|
19219
|
+
if (fault) throw fault;
|
|
19220
|
+
return code;
|
|
19221
|
+
}
|
|
19222
|
+
};
|
|
19223
|
+
}
|
|
19224
|
+
var END_OF_CENTRAL_DIRECTORY = 101010256;
|
|
19225
|
+
var CENTRAL_FILE_HEADER = 33639248;
|
|
19226
|
+
var ZIP64_END_LOCATOR = 117853008;
|
|
19227
|
+
var ZIP64_END_OF_CENTRAL_DIRECTORY = 101075792;
|
|
19228
|
+
var ZipError = class extends Error {
|
|
19229
|
+
code = "ERR_ZIP";
|
|
19230
|
+
};
|
|
19231
|
+
function readZip(archive) {
|
|
19232
|
+
const view = new DataView(archive.buffer, archive.byteOffset, archive.byteLength);
|
|
19233
|
+
const end = findEndOfCentralDirectory(archive);
|
|
19234
|
+
let entryCount = view.getUint16(end + 10, true);
|
|
19235
|
+
let directoryOffset = view.getUint32(end + 16, true);
|
|
19236
|
+
if (entryCount === 65535 || directoryOffset === 4294967295) {
|
|
19237
|
+
const locator = findSignature(archive, ZIP64_END_LOCATOR, end);
|
|
19238
|
+
if (locator < 0) throw new ZipError("zip64 archive without an end locator");
|
|
19239
|
+
const zip64End = Number(view.getBigUint64(locator + 8, true));
|
|
19240
|
+
if (view.getUint32(zip64End, true) !== ZIP64_END_OF_CENTRAL_DIRECTORY) {
|
|
19241
|
+
throw new ZipError("zip64 end record not found where the locator says");
|
|
19242
|
+
}
|
|
19243
|
+
entryCount = Number(view.getBigUint64(zip64End + 32, true));
|
|
19244
|
+
directoryOffset = Number(view.getBigUint64(zip64End + 48, true));
|
|
19245
|
+
}
|
|
19246
|
+
const entries = [];
|
|
19247
|
+
let at = directoryOffset;
|
|
19248
|
+
for (let i = 0; i < entryCount; i += 1) {
|
|
19249
|
+
if (view.getUint32(at, true) !== CENTRAL_FILE_HEADER) {
|
|
19250
|
+
throw new ZipError(`central directory entry ${i} has a bad signature`);
|
|
19251
|
+
}
|
|
19252
|
+
const flags = view.getUint16(at + 8, true);
|
|
19253
|
+
if (flags & 1) throw new ZipError("encrypted archives are not supported");
|
|
19254
|
+
const method = view.getUint16(at + 10, true);
|
|
19255
|
+
const compressedSize = view.getUint32(at + 20, true);
|
|
19256
|
+
const uncompressedSize = view.getUint32(at + 24, true);
|
|
19257
|
+
const nameLength = view.getUint16(at + 28, true);
|
|
19258
|
+
const extraLength = view.getUint16(at + 30, true);
|
|
19259
|
+
const commentLength = view.getUint16(at + 32, true);
|
|
19260
|
+
const externalAttributes = view.getUint32(at + 38, true);
|
|
19261
|
+
const localOffset = view.getUint32(at + 42, true);
|
|
19262
|
+
const name = new TextDecoder().decode(archive.subarray(at + 46, at + 46 + nameLength));
|
|
19263
|
+
entries.push({
|
|
19264
|
+
name,
|
|
19265
|
+
/* The high 16 bits are the Unix mode when the archive was made on Unix.
|
|
19266
|
+
* pip relies on it for console scripts, which have to stay executable. */
|
|
19267
|
+
mode: externalAttributes >>> 16,
|
|
19268
|
+
isDirectory: name.endsWith("/"),
|
|
19269
|
+
data: () => extract(archive, view, localOffset, method, compressedSize, uncompressedSize, name)
|
|
19270
|
+
});
|
|
19271
|
+
at += 46 + nameLength + extraLength + commentLength;
|
|
19272
|
+
}
|
|
19273
|
+
return entries;
|
|
19274
|
+
}
|
|
19275
|
+
function extract(archive, view, localOffset, method, compressedSize, uncompressedSize, name) {
|
|
19276
|
+
const nameLength = view.getUint16(localOffset + 26, true);
|
|
19277
|
+
const extraLength = view.getUint16(localOffset + 28, true);
|
|
19278
|
+
const start2 = localOffset + 30 + nameLength + extraLength;
|
|
19279
|
+
const body = archive.subarray(start2, start2 + compressedSize);
|
|
19280
|
+
if (method === 0) return body.slice();
|
|
19281
|
+
if (method !== 8) throw new ZipError(`${name}: unsupported compression method ${method}`);
|
|
19282
|
+
const inflated = pako.inflateRaw(body);
|
|
19283
|
+
if (inflated.length !== uncompressedSize) {
|
|
19284
|
+
throw new ZipError(`${name}: inflated to ${inflated.length} bytes, the directory says ${uncompressedSize}`);
|
|
19285
|
+
}
|
|
19286
|
+
return inflated;
|
|
19287
|
+
}
|
|
19288
|
+
function findEndOfCentralDirectory(archive, view) {
|
|
19289
|
+
const at = findSignature(archive, END_OF_CENTRAL_DIRECTORY, archive.length);
|
|
19290
|
+
if (at < 0) throw new ZipError("not a zip archive: no end-of-central-directory record");
|
|
19291
|
+
return at;
|
|
19292
|
+
}
|
|
19293
|
+
function findSignature(archive, signature, before) {
|
|
19294
|
+
const view = new DataView(archive.buffer, archive.byteOffset, archive.byteLength);
|
|
19295
|
+
for (let at = Math.min(before, archive.length) - 4; at >= 0; at -= 1) {
|
|
19296
|
+
if (view.getUint32(at, true) === signature) return at;
|
|
19297
|
+
}
|
|
19298
|
+
return -1;
|
|
19299
|
+
}
|
|
19300
|
+
|
|
19301
|
+
// src/runtime/python/pypi.ts
|
|
19302
|
+
var ACCEPTED_TAGS = ["py3-none-any", "py2.py3-none-any", "py3-none-emscripten"];
|
|
19303
|
+
function parseRequirement(text2) {
|
|
19304
|
+
const cleaned = text2.replace(/#.*$/, "").trim();
|
|
19305
|
+
if (!cleaned) return null;
|
|
19306
|
+
const [head2, marker = null] = splitOnce(cleaned, ";");
|
|
19307
|
+
const match2 = /^([A-Za-z0-9._-]+)\s*(\[[^\]]*\])?\s*(.*)$/.exec(head2.trim());
|
|
19308
|
+
if (!match2) return null;
|
|
19309
|
+
const [, name, extrasGroup = "", rest = ""] = match2;
|
|
19310
|
+
const specifiers = [];
|
|
19311
|
+
for (const part of rest.split(",")) {
|
|
19312
|
+
const spec = /^\s*(===|==|>=|<=|!=|~=|>|<)\s*([A-Za-z0-9.*+!-]+)\s*$/.exec(part);
|
|
19313
|
+
if (spec) specifiers.push({ op: spec[1], version: spec[2] });
|
|
19314
|
+
}
|
|
19315
|
+
return {
|
|
19316
|
+
name: normalize2(name),
|
|
19317
|
+
specifiers,
|
|
19318
|
+
extras: extrasGroup.slice(1, -1).split(",").map((e) => e.trim()).filter(Boolean),
|
|
19319
|
+
marker: marker?.trim() ?? null
|
|
19320
|
+
};
|
|
19321
|
+
}
|
|
19322
|
+
function normalize2(name) {
|
|
19323
|
+
return name.toLowerCase().replace(/[-_.]+/g, "-");
|
|
19324
|
+
}
|
|
19325
|
+
function markerApplies(marker, environment, extras) {
|
|
19326
|
+
if (!marker) return true;
|
|
19327
|
+
const evaluateClause = (clause) => {
|
|
19328
|
+
const match2 = /^\s*([A-Za-z_]+)\s*(===|==|!=|>=|<=|>|<|not in|in)\s*(.+?)\s*$/.exec(clause);
|
|
19329
|
+
if (!match2) return false;
|
|
19330
|
+
const [, variable, op, rawValue] = match2;
|
|
19331
|
+
const value = rawValue.replace(/^['"]|['"]$/g, "");
|
|
19332
|
+
if (variable === "extra") {
|
|
19333
|
+
const wanted = extras.includes(value);
|
|
19334
|
+
return op === "==" ? wanted : op === "!=" ? !wanted : false;
|
|
19335
|
+
}
|
|
19336
|
+
const actual = environment[variable];
|
|
19337
|
+
if (actual === void 0) return false;
|
|
19338
|
+
if (op === "in") return value.includes(actual);
|
|
19339
|
+
if (op === "not in") return !value.includes(actual);
|
|
19340
|
+
if (variable === "python_version" || variable === "python_full_version") {
|
|
19341
|
+
return compareVersions(actual, value, op);
|
|
19342
|
+
}
|
|
19343
|
+
return op === "==" || op === "===" ? actual === value : op === "!=" ? actual !== value : false;
|
|
19344
|
+
};
|
|
19345
|
+
if (marker.includes("(")) return false;
|
|
19346
|
+
return marker.split(/\s+or\s+/).some((group) => group.split(/\s+and\s+/).every(evaluateClause));
|
|
19347
|
+
}
|
|
19348
|
+
function compareVersions(left, right, op) {
|
|
19349
|
+
if (op === "==" || op === "===") {
|
|
19350
|
+
if (right.endsWith(".*")) return left.startsWith(right.slice(0, -1));
|
|
19351
|
+
return releaseOf(left).join(".") === releaseOf(right).join(".");
|
|
19352
|
+
}
|
|
19353
|
+
if (op === "!=") return !compareVersions(left, right, "==");
|
|
19354
|
+
const order = compareRelease(releaseOf(left), releaseOf(right));
|
|
19355
|
+
if (op === ">=") return order >= 0;
|
|
19356
|
+
if (op === "<=") return order <= 0;
|
|
19357
|
+
if (op === ">") return order > 0;
|
|
19358
|
+
if (op === "<") return order < 0;
|
|
19359
|
+
if (op === "~=") {
|
|
19360
|
+
const bound = releaseOf(right).slice(0, -1);
|
|
19361
|
+
return order >= 0 && compareRelease(releaseOf(left).slice(0, bound.length), bound) === 0;
|
|
19362
|
+
}
|
|
19363
|
+
return false;
|
|
19364
|
+
}
|
|
19365
|
+
function releaseOf(version) {
|
|
19366
|
+
const release = /^\s*v?(\d+(?:\.\d+)*)/.exec(version.trim());
|
|
19367
|
+
return release ? release[1].split(".").map(Number) : [0];
|
|
19368
|
+
}
|
|
19369
|
+
function compareRelease(left, right) {
|
|
19370
|
+
for (let i = 0; i < Math.max(left.length, right.length); i += 1) {
|
|
19371
|
+
const difference = (left[i] ?? 0) - (right[i] ?? 0);
|
|
19372
|
+
if (difference !== 0) return difference > 0 ? 1 : -1;
|
|
19373
|
+
}
|
|
19374
|
+
return 0;
|
|
19375
|
+
}
|
|
19376
|
+
function isPreRelease(version) {
|
|
19377
|
+
return /(a|b|rc|dev|post)\d*$/i.test(version.replace(/^\d+(\.\d+)*/, ""));
|
|
19378
|
+
}
|
|
19379
|
+
async function resolvePackageCandidates(client, requirement, environment) {
|
|
19380
|
+
const index = await client.json(`https://pypi.org/pypi/${requirement.name}/json`);
|
|
19381
|
+
const candidates = Object.keys(index.releases).filter((version) => requirement.specifiers.every((s) => compareVersions(version, s.version, s.op))).sort((a, b) => compareRelease(releaseOf(a), releaseOf(b)));
|
|
19382
|
+
const stable = candidates.filter((version) => !isPreRelease(version));
|
|
19383
|
+
const ordered = (stable.length > 0 ? stable : candidates).reverse();
|
|
19384
|
+
let sawSourceOnly = false;
|
|
19385
|
+
const resolved = [];
|
|
19386
|
+
for (const version of ordered) {
|
|
19387
|
+
const files = (index.releases[version] ?? []).filter((file3) => !file3.yanked);
|
|
19388
|
+
const wheel = pickWheel(files);
|
|
19389
|
+
if (wheel) {
|
|
19390
|
+
resolved.push({
|
|
19391
|
+
name: requirement.name,
|
|
19392
|
+
version,
|
|
19393
|
+
url: wheel.url,
|
|
19394
|
+
filename: wheel.filename,
|
|
19395
|
+
sha256: wheel.digests?.sha256 ?? "",
|
|
19396
|
+
requires: []
|
|
19397
|
+
});
|
|
19398
|
+
continue;
|
|
19399
|
+
}
|
|
19400
|
+
if (files.some((file3) => file3.packagetype === "sdist")) sawSourceOnly = true;
|
|
19401
|
+
}
|
|
19402
|
+
if (resolved.length > 0) return resolved;
|
|
19403
|
+
if (ordered.length === 0) {
|
|
19404
|
+
throw new Error(
|
|
19405
|
+
`no version of ${requirement.name} matches ${describe(requirement)}`
|
|
19406
|
+
);
|
|
19407
|
+
}
|
|
19408
|
+
throw new Error(
|
|
19409
|
+
sawSourceOnly ? `${requirement.name} ${ordered[0]} publishes only a source distribution, and this runtime cannot build one yet (source builds are a later milestone)` : `${requirement.name} ${ordered[0]} has no wheel this runtime can use; it needs one tagged ` + ACCEPTED_TAGS.join(" or ")
|
|
19410
|
+
);
|
|
19411
|
+
}
|
|
19412
|
+
function pickWheel(files) {
|
|
19413
|
+
const wheels = files.filter((file3) => file3.packagetype === "bdist_wheel");
|
|
19414
|
+
for (const tag2 of ACCEPTED_TAGS) {
|
|
19415
|
+
const match2 = wheels.find((file3) => file3.filename.endsWith(`-${tag2}.whl`));
|
|
19416
|
+
if (match2) return match2;
|
|
19417
|
+
}
|
|
19418
|
+
return null;
|
|
19419
|
+
}
|
|
19420
|
+
function describe(requirement) {
|
|
19421
|
+
return requirement.specifiers.length === 0 ? "any version" : requirement.specifiers.map((s) => `${s.op}${s.version}`).join(", ");
|
|
19422
|
+
}
|
|
19423
|
+
function splitOnce(text2, separator) {
|
|
19424
|
+
const at = text2.indexOf(separator);
|
|
19425
|
+
return at < 0 ? [text2] : [text2.slice(0, at), text2.slice(at + 1)];
|
|
19426
|
+
}
|
|
19427
|
+
|
|
19428
|
+
// src/runtime/python/install.ts
|
|
19429
|
+
var SITE_PACKAGES = "/usr/lib/python3.13/site-packages";
|
|
19430
|
+
var SCRIPTS = "/usr/local/bin";
|
|
19431
|
+
function markerEnvironment(pythonVersion) {
|
|
19432
|
+
const [major = "3", minor = "13"] = pythonVersion.split(".");
|
|
19433
|
+
return {
|
|
19434
|
+
python_version: `${major}.${minor}`,
|
|
19435
|
+
python_full_version: pythonVersion,
|
|
19436
|
+
sys_platform: "emscripten",
|
|
19437
|
+
platform_system: "Emscripten",
|
|
19438
|
+
platform_machine: "wasm32",
|
|
19439
|
+
implementation_name: "cpython",
|
|
19440
|
+
os_name: "posix"
|
|
19441
|
+
};
|
|
19442
|
+
}
|
|
19443
|
+
async function installRequirements(options) {
|
|
19444
|
+
const environment = markerEnvironment(options.pythonVersion);
|
|
19445
|
+
const report = { installed: [], skipped: [] };
|
|
19446
|
+
const queue = [];
|
|
19447
|
+
for (const text2 of options.requirements) {
|
|
19448
|
+
const requirement = parseRequirement(text2);
|
|
19449
|
+
if (requirement) queue.push({ requirement, extras: requirement.extras });
|
|
19450
|
+
}
|
|
19451
|
+
const archives = /* @__PURE__ */ new Map();
|
|
19452
|
+
const unavailable2 = /* @__PURE__ */ new Set();
|
|
19453
|
+
const candidateCache = /* @__PURE__ */ new Map();
|
|
19454
|
+
const solve = async (pending, state) => {
|
|
19455
|
+
if (pending.length === 0) return state;
|
|
19456
|
+
const [first, ...tail2] = pending;
|
|
19457
|
+
let { requirement, extras } = first;
|
|
19458
|
+
const rest = [];
|
|
19459
|
+
const mergedSpecifiers = [...requirement.specifiers];
|
|
19460
|
+
const mergedExtras = new Set(extras);
|
|
19461
|
+
for (const item of tail2) {
|
|
19462
|
+
if (item.requirement.name === requirement.name && markerApplies(item.requirement.marker, environment, item.extras)) {
|
|
19463
|
+
mergedSpecifiers.push(...item.requirement.specifiers);
|
|
19464
|
+
for (const extra of item.extras) mergedExtras.add(extra);
|
|
19465
|
+
} else {
|
|
19466
|
+
rest.push(item);
|
|
19467
|
+
}
|
|
19468
|
+
}
|
|
19469
|
+
requirement = { ...requirement, specifiers: mergedSpecifiers };
|
|
19470
|
+
extras = [...mergedExtras];
|
|
19471
|
+
if (!markerApplies(requirement.marker, environment, extras)) {
|
|
19472
|
+
return solve(rest, {
|
|
19473
|
+
...state,
|
|
19474
|
+
skipped: [...state.skipped, { name: requirement.name, marker: requirement.marker ?? "" }]
|
|
19475
|
+
});
|
|
19476
|
+
}
|
|
19477
|
+
const already = state.chosen.get(requirement.name);
|
|
19478
|
+
if (already) {
|
|
19479
|
+
const satisfied = requirement.specifiers.every(
|
|
19480
|
+
(s) => compareVersions(already.version, s.version, s.op)
|
|
19481
|
+
);
|
|
19482
|
+
if (!satisfied) {
|
|
19483
|
+
throw new Error(
|
|
19484
|
+
`${requirement.name} ${already.version} is already selected but another dependency needs ` + requirement.specifiers.map((s) => `${s.op}${s.version}`).join(", ")
|
|
19485
|
+
);
|
|
19486
|
+
}
|
|
19487
|
+
return solve(rest, state);
|
|
19488
|
+
}
|
|
19489
|
+
options.progress.collecting(requirement.name);
|
|
19490
|
+
if (unavailable2.has(requirement.name)) {
|
|
19491
|
+
throw new Error(`${requirement.name} has no wheel this runtime can use`);
|
|
19492
|
+
}
|
|
19493
|
+
const candidateKey = `${requirement.name}:${requirement.specifiers.map((s) => `${s.op}${s.version}`).join(",")}`;
|
|
19494
|
+
let candidatePromise = candidateCache.get(candidateKey);
|
|
19495
|
+
if (!candidatePromise) {
|
|
19496
|
+
candidatePromise = resolvePackageCandidates(options.client, requirement);
|
|
19497
|
+
candidateCache.set(candidateKey, candidatePromise);
|
|
19498
|
+
}
|
|
19499
|
+
let candidates;
|
|
19500
|
+
try {
|
|
19501
|
+
candidates = await candidatePromise;
|
|
19502
|
+
} catch (error) {
|
|
19503
|
+
const anyKey = `${requirement.name}:`;
|
|
19504
|
+
let anyPromise = candidateCache.get(anyKey);
|
|
19505
|
+
if (!anyPromise) {
|
|
19506
|
+
anyPromise = resolvePackageCandidates(
|
|
19507
|
+
options.client,
|
|
19508
|
+
{ ...requirement, specifiers: [] });
|
|
19509
|
+
candidateCache.set(anyKey, anyPromise);
|
|
19510
|
+
}
|
|
19511
|
+
try {
|
|
19512
|
+
await anyPromise;
|
|
19513
|
+
} catch {
|
|
19514
|
+
unavailable2.add(requirement.name);
|
|
19515
|
+
}
|
|
19516
|
+
throw error;
|
|
19517
|
+
}
|
|
19518
|
+
let failure2;
|
|
19519
|
+
for (const resolved of candidates) {
|
|
19520
|
+
try {
|
|
19521
|
+
let entries = archives.get(resolved.url);
|
|
19522
|
+
if (!entries) {
|
|
19523
|
+
options.progress.downloading(resolved.name, resolved.version);
|
|
19524
|
+
entries = readZip(await options.client.bytes(resolved.url));
|
|
19525
|
+
archives.set(resolved.url, entries);
|
|
19526
|
+
}
|
|
19527
|
+
const dependencies = [];
|
|
19528
|
+
const metadata = entries.find((entry) => /\.dist-info\/METADATA$/.test(entry.name));
|
|
19529
|
+
if (metadata) {
|
|
19530
|
+
for (const line of new TextDecoder().decode(metadata.data()).split(/\r?\n/)) {
|
|
19531
|
+
if (!line.startsWith("Requires-Dist:")) continue;
|
|
19532
|
+
const dependency = parseRequirement(line.slice("Requires-Dist:".length));
|
|
19533
|
+
if (dependency && markerApplies(dependency.marker, environment, extras)) {
|
|
19534
|
+
dependencies.push({ requirement: dependency, extras: dependency.extras });
|
|
19535
|
+
}
|
|
19536
|
+
}
|
|
19537
|
+
}
|
|
19538
|
+
const chosen = new Map(state.chosen);
|
|
19539
|
+
chosen.set(requirement.name, resolved);
|
|
19540
|
+
return await solve([...dependencies, ...rest], {
|
|
19541
|
+
chosen,
|
|
19542
|
+
staged: [...state.staged, ...stageWheel(entries, resolved)],
|
|
19543
|
+
installed: [...state.installed, { name: resolved.name, version: resolved.version }],
|
|
19544
|
+
skipped: state.skipped
|
|
19545
|
+
});
|
|
19546
|
+
} catch (error) {
|
|
19547
|
+
failure2 = error;
|
|
19548
|
+
}
|
|
19549
|
+
}
|
|
19550
|
+
throw failure2 instanceof Error ? failure2 : new Error(`could not resolve ${requirement.name}`);
|
|
19551
|
+
};
|
|
19552
|
+
const solved = await solve(queue, {
|
|
19553
|
+
chosen: /* @__PURE__ */ new Map(),
|
|
19554
|
+
staged: [],
|
|
19555
|
+
installed: [],
|
|
19556
|
+
skipped: []
|
|
19557
|
+
});
|
|
19558
|
+
report.installed = solved.installed;
|
|
19559
|
+
report.skipped = solved.skipped;
|
|
19560
|
+
commit(options.vfs, options.cred, solved.staged);
|
|
19561
|
+
return report;
|
|
19562
|
+
}
|
|
19563
|
+
function stageWheel(entries, resolved) {
|
|
19564
|
+
const staged = [];
|
|
19565
|
+
for (const entry of entries) {
|
|
19566
|
+
if (entry.isDirectory) continue;
|
|
19567
|
+
const dataPath = /^[^/]+\.data\/(purelib|platlib|scripts)\/(.+)$/.exec(entry.name);
|
|
19568
|
+
if (dataPath) {
|
|
19569
|
+
const [, scheme, relative2] = dataPath;
|
|
19570
|
+
staged.push({
|
|
19571
|
+
path: scheme === "scripts" ? `${SCRIPTS}/${relative2}` : `${SITE_PACKAGES}/${relative2}`,
|
|
19572
|
+
data: entry.data(),
|
|
19573
|
+
...scheme === "scripts" ? { mode: 493 } : {}
|
|
19574
|
+
});
|
|
19575
|
+
continue;
|
|
19576
|
+
}
|
|
19577
|
+
if (/^[^/]+\.data\//.test(entry.name)) continue;
|
|
19578
|
+
staged.push({ path: `${SITE_PACKAGES}/${entry.name}`, data: entry.data() });
|
|
19579
|
+
}
|
|
19580
|
+
const entryPoints = entries.find((entry) => /\.dist-info\/entry_points\.txt$/.test(entry.name));
|
|
19581
|
+
if (entryPoints) {
|
|
19582
|
+
for (const [name, target] of consoleScripts(new TextDecoder().decode(entryPoints.data()))) {
|
|
19583
|
+
staged.push({ path: `${SCRIPTS}/${name}`, data: new TextEncoder().encode(consoleLauncher(target)), mode: 493 });
|
|
19584
|
+
}
|
|
19585
|
+
}
|
|
19586
|
+
return staged;
|
|
19587
|
+
}
|
|
19588
|
+
function commit(vfs, cred, staged) {
|
|
19589
|
+
const directories = /* @__PURE__ */ new Set();
|
|
19590
|
+
for (const file3 of staged) directories.add(file3.path.slice(0, file3.path.lastIndexOf("/")));
|
|
19591
|
+
for (const directory2 of directories) vfs.mkdir(directory2, { recursive: true, cred });
|
|
19592
|
+
for (const file3 of staged) {
|
|
19593
|
+
vfs.writeFile(file3.path, file3.data, { cred, ...file3.mode === void 0 ? {} : { mode: file3.mode } });
|
|
19594
|
+
if (file3.mode !== void 0) vfs.chmod(file3.path, file3.mode, cred);
|
|
19595
|
+
}
|
|
19596
|
+
}
|
|
19597
|
+
function consoleScripts(text2) {
|
|
19598
|
+
const result = [];
|
|
19599
|
+
let section = "";
|
|
19600
|
+
for (const raw of text2.split(/\r?\n/)) {
|
|
19601
|
+
const line = raw.trim();
|
|
19602
|
+
const heading = /^\[([^\]]+)\]$/.exec(line);
|
|
19603
|
+
if (heading) {
|
|
19604
|
+
section = heading[1];
|
|
19605
|
+
continue;
|
|
19606
|
+
}
|
|
19607
|
+
if (section !== "console_scripts" || line === "" || line.startsWith("#")) continue;
|
|
19608
|
+
const assignment = /^([^=\s]+)\s*=\s*([^\s;]+)(?:\s*;.*)?$/.exec(line);
|
|
19609
|
+
if (assignment) result.push([assignment[1], assignment[2].replace(/\s*\[.*\]$/, "")]);
|
|
19610
|
+
}
|
|
19611
|
+
return result;
|
|
19612
|
+
}
|
|
19613
|
+
function consoleLauncher(target) {
|
|
19614
|
+
const [module, attribute = ""] = target.split(":", 2);
|
|
19615
|
+
return `#!/usr/bin/python3
|
|
19616
|
+
import sys
|
|
19617
|
+
from importlib import import_module
|
|
19618
|
+
entry = import_module(${JSON.stringify(module)})
|
|
19619
|
+
for part in ${JSON.stringify(attribute)}.split('.'):
|
|
19620
|
+
if part:
|
|
19621
|
+
entry = getattr(entry, part)
|
|
19622
|
+
raise SystemExit(entry())
|
|
19623
|
+
`;
|
|
19624
|
+
}
|
|
19625
|
+
|
|
19626
|
+
// src/runtime/python/backend.ts
|
|
19627
|
+
function withSitePackages(env2) {
|
|
19628
|
+
const existing = env2.PYTHONPATH;
|
|
19629
|
+
return {
|
|
19630
|
+
...env2,
|
|
19631
|
+
PYTHONPATH: existing ? `${SITE_PACKAGES}:${existing}` : SITE_PACKAGES,
|
|
19632
|
+
/* Installed packages live on a host-mounted VFS. Rewriting hundreds of
|
|
19633
|
+
* cache files on every short-lived WASM process is wasted work and can
|
|
19634
|
+
* exhaust the synchronous host-call bridge during large import graphs. */
|
|
19635
|
+
PYTHONDONTWRITEBYTECODE: env2.PYTHONDONTWRITEBYTECODE ?? "1"
|
|
19636
|
+
};
|
|
19637
|
+
}
|
|
19638
|
+
var INTERPRETER_OWNED = /* @__PURE__ */ new Set(["lib", "dev", "proc", "usr"]);
|
|
19639
|
+
async function resolveWorkerUrl(explicit) {
|
|
19640
|
+
if (explicit) {
|
|
19641
|
+
try {
|
|
19642
|
+
return new URL(explicit);
|
|
19643
|
+
} catch {
|
|
19644
|
+
return explicit;
|
|
19645
|
+
}
|
|
19646
|
+
}
|
|
19647
|
+
const beside = new URL("./python-worker.js", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
19648
|
+
if (beside.protocol !== "file:") return beside;
|
|
19649
|
+
const [{ existsSync }, { fileURLToPath: fileURLToPath2, pathToFileURL: pathToFileURL2 }] = await Promise.all([
|
|
19650
|
+
nodeBuiltin("fs"),
|
|
19651
|
+
nodeBuiltin("url")
|
|
19652
|
+
]);
|
|
19653
|
+
if (existsSync(fileURLToPath2(beside))) return beside;
|
|
19654
|
+
const built = new URL("../../../dist/python-worker.js", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
19655
|
+
if (existsSync(fileURLToPath2(built))) return pathToFileURL2(fileURLToPath2(built));
|
|
19656
|
+
throw new Error(
|
|
19657
|
+
"the SandboxedJs Python process worker has not been built; run `npm run build` in the package, or pass configurePython({ workerUrl })."
|
|
19658
|
+
);
|
|
19659
|
+
}
|
|
19660
|
+
function usingOwnedPython() {
|
|
19661
|
+
return pythonBackend().backend === "sbx-cpython-wasm";
|
|
19662
|
+
}
|
|
19663
|
+
async function runOwnedPython(ctx, argv) {
|
|
19664
|
+
const { manifest, workerUrl } = pythonBackend();
|
|
19665
|
+
if (!manifest) throw new Error("no Python runtime manifest is configured");
|
|
19666
|
+
const mounts = containerMounts(ctx);
|
|
19667
|
+
const process2 = await startPythonProcess({
|
|
19668
|
+
manifest,
|
|
19669
|
+
workerUrl: await resolveWorkerUrl(workerUrl),
|
|
19670
|
+
vfs: ctx.vfs,
|
|
19671
|
+
cred: ctx.cred,
|
|
19672
|
+
pid: ctx.proc.pid,
|
|
19673
|
+
ppid: ctx.proc.ppid ?? 1,
|
|
19674
|
+
argv,
|
|
19675
|
+
env: withSitePackages(ctx.env),
|
|
19676
|
+
cwd: ctx.cwd,
|
|
19677
|
+
isTty: isTerminal(ctx),
|
|
19678
|
+
mounts,
|
|
19679
|
+
onStdout: (data) => ctx.stdout.write(data),
|
|
19680
|
+
onStderr: (data) => ctx.stderr.write(data),
|
|
19681
|
+
signal: ctx.signal
|
|
19682
|
+
});
|
|
19683
|
+
void pumpStdin(ctx, process2);
|
|
19684
|
+
return process2.wait();
|
|
19685
|
+
}
|
|
19686
|
+
async function pumpStdin(ctx, proc) {
|
|
19687
|
+
const stdin = ctx.stdin;
|
|
19688
|
+
try {
|
|
19689
|
+
for (; ; ) {
|
|
19690
|
+
const chunk = await stdin.read(65536);
|
|
19691
|
+
if (chunk === null || chunk.length === 0) break;
|
|
19692
|
+
proc.write(chunk);
|
|
19693
|
+
}
|
|
19694
|
+
} catch {
|
|
19695
|
+
}
|
|
19696
|
+
proc.endInput();
|
|
19697
|
+
}
|
|
19698
|
+
function isTerminal(ctx) {
|
|
19699
|
+
const stdin = ctx.stdin;
|
|
19700
|
+
return Boolean(stdin.isTTY || stdin.interactive);
|
|
19701
|
+
}
|
|
19702
|
+
function containerMounts(ctx) {
|
|
19703
|
+
const mounts = [];
|
|
19704
|
+
let entries;
|
|
19705
|
+
try {
|
|
19706
|
+
entries = ctx.vfs.readdir("/", ctx.cred);
|
|
19707
|
+
} catch {
|
|
19708
|
+
return mounts;
|
|
19709
|
+
}
|
|
19710
|
+
for (const name of entries) {
|
|
19711
|
+
if (INTERPRETER_OWNED.has(name)) continue;
|
|
19712
|
+
try {
|
|
19713
|
+
if (!ctx.vfs.stat(`/${name}`, { cred: ctx.cred }).isDirectory()) continue;
|
|
19714
|
+
} catch {
|
|
19715
|
+
continue;
|
|
19716
|
+
}
|
|
19717
|
+
mounts.push({ guest: `/${name}`, container: `/${name}` });
|
|
19718
|
+
}
|
|
19719
|
+
try {
|
|
19720
|
+
if (ctx.vfs.stat(SITE_PACKAGES, { cred: ctx.cred }).isDirectory()) {
|
|
19721
|
+
mounts.push({ guest: SITE_PACKAGES, container: SITE_PACKAGES });
|
|
19722
|
+
}
|
|
19723
|
+
} catch {
|
|
19724
|
+
}
|
|
19725
|
+
try {
|
|
19726
|
+
if (ctx.vfs.stat(SCRIPTS, { cred: ctx.cred }).isDirectory()) {
|
|
19727
|
+
mounts.push({ guest: SCRIPTS, container: SCRIPTS });
|
|
19728
|
+
}
|
|
19729
|
+
} catch {
|
|
19730
|
+
}
|
|
19731
|
+
return mounts;
|
|
19732
|
+
}
|
|
19733
|
+
|
|
19734
|
+
// src/runtime/python/pip-command.ts
|
|
19735
|
+
var pipCommand = defineCommand({
|
|
19736
|
+
name: "pip",
|
|
19737
|
+
path: "/usr/bin/pip",
|
|
19738
|
+
aliases: ["pip3"],
|
|
19739
|
+
summary: "install Python wheels into the container's site-packages",
|
|
19740
|
+
usage: "pip install [-r requirements.txt] <package>...",
|
|
19741
|
+
manual: `Resolves wheels from PyPI and unpacks them into ${SITE_PACKAGES}, which
|
|
19742
|
+
the interpreter has on sys.path.
|
|
19743
|
+
|
|
19744
|
+
This is not pip. It installs published wheels only: there are no source builds,
|
|
19745
|
+
no editable installs, no uninstall, and one site-packages rather than virtual
|
|
19746
|
+
environments. A package with no usable wheel is an error, never a silent skip.`,
|
|
19747
|
+
async run(ctx) {
|
|
19748
|
+
const [action, ...args] = ctx.args;
|
|
19749
|
+
if (action === "--version" || action === "-V") {
|
|
19750
|
+
ctx.line(`pip (sandboxedjs wheel installer, not pip) targeting ${SITE_PACKAGES}`);
|
|
19751
|
+
return 0;
|
|
19752
|
+
}
|
|
19753
|
+
if (action === "list") {
|
|
19754
|
+
return listInstalled(ctx);
|
|
19755
|
+
}
|
|
19756
|
+
if (action !== "install") {
|
|
19757
|
+
ctx.line("usage: pip install [-r requirements.txt] <package>...");
|
|
19758
|
+
return action === void 0 ? 1 : 0;
|
|
19759
|
+
}
|
|
19760
|
+
const requirements = [];
|
|
19761
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
19762
|
+
const arg = args[i];
|
|
19763
|
+
if (arg === "-r" || arg === "--requirement") {
|
|
19764
|
+
const file3 = args[++i];
|
|
19765
|
+
if (!file3) return ctx.fail("option -r requires a file", 2);
|
|
19766
|
+
try {
|
|
19767
|
+
requirements.push(
|
|
19768
|
+
...ctx.vfs.readText(ctx.path(file3), ctx.cred).split(/\r?\n/).map((line) => line.replace(/#.*$/, "").trim()).filter(Boolean)
|
|
19769
|
+
);
|
|
19770
|
+
} catch {
|
|
19771
|
+
return ctx.fail(`could not open requirements file '${file3}'`);
|
|
19772
|
+
}
|
|
19773
|
+
continue;
|
|
19774
|
+
}
|
|
19775
|
+
if (arg.startsWith("-")) continue;
|
|
19776
|
+
requirements.push(arg);
|
|
19777
|
+
}
|
|
19778
|
+
if (requirements.length === 0) return ctx.fail("no packages specified");
|
|
19779
|
+
if (!ctx.kernel.net.outboundAllowed("https://pypi.org")) {
|
|
19780
|
+
return ctx.fail(
|
|
19781
|
+
"outbound network access is disabled for this container (enable with network: { allowOutbound: true })"
|
|
19782
|
+
);
|
|
19783
|
+
}
|
|
19784
|
+
const jsonCache = /* @__PURE__ */ new Map();
|
|
19785
|
+
const bytesCache = /* @__PURE__ */ new Map();
|
|
19786
|
+
const client = {
|
|
19787
|
+
async json(url) {
|
|
19788
|
+
let pending = jsonCache.get(url);
|
|
19789
|
+
if (!pending) {
|
|
19790
|
+
pending = fetch(url).then((response) => {
|
|
19791
|
+
if (!response.ok) throw new Error(`${url} answered ${response.status}`);
|
|
19792
|
+
return response.json();
|
|
19793
|
+
});
|
|
19794
|
+
jsonCache.set(url, pending);
|
|
19795
|
+
}
|
|
19796
|
+
return pending;
|
|
19797
|
+
},
|
|
19798
|
+
async bytes(url) {
|
|
19799
|
+
let pending = bytesCache.get(url);
|
|
19800
|
+
if (!pending) {
|
|
19801
|
+
pending = fetch(url).then(async (response) => {
|
|
19802
|
+
if (!response.ok) throw new Error(`${url} answered ${response.status}`);
|
|
19803
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
19804
|
+
});
|
|
19805
|
+
bytesCache.set(url, pending);
|
|
19806
|
+
}
|
|
19807
|
+
return pending;
|
|
19808
|
+
}
|
|
19809
|
+
};
|
|
19810
|
+
try {
|
|
19811
|
+
const report = await installRequirements({
|
|
19812
|
+
client,
|
|
19813
|
+
vfs: ctx.vfs,
|
|
19814
|
+
cred: ctx.cred,
|
|
19815
|
+
requirements,
|
|
19816
|
+
pythonVersion: pythonBackend().manifest?.pythonVersion ?? "3.13.5",
|
|
19817
|
+
progress: {
|
|
19818
|
+
collecting: (name) => ctx.line(`Collecting ${name}`),
|
|
19819
|
+
downloading: () => {
|
|
19820
|
+
}
|
|
19821
|
+
}
|
|
19822
|
+
});
|
|
19823
|
+
for (const skipped of report.skipped) {
|
|
19824
|
+
ctx.line(` Skipping ${skipped.name} (marker: ${skipped.marker})`);
|
|
19825
|
+
}
|
|
19826
|
+
ctx.line(
|
|
19827
|
+
`Successfully installed ${report.installed.map((p) => `${p.name}-${p.version}`).join(" ")}`
|
|
19828
|
+
);
|
|
19829
|
+
return 0;
|
|
19830
|
+
} catch (error) {
|
|
19831
|
+
return ctx.fail(error.message ?? String(error));
|
|
19832
|
+
}
|
|
19833
|
+
}
|
|
19834
|
+
});
|
|
19835
|
+
function listInstalled(ctx) {
|
|
19836
|
+
let entries;
|
|
19837
|
+
try {
|
|
19838
|
+
entries = ctx.vfs.readdir(SITE_PACKAGES, ctx.cred);
|
|
19839
|
+
} catch {
|
|
19840
|
+
return 0;
|
|
19841
|
+
}
|
|
19842
|
+
for (const entry of entries) {
|
|
19843
|
+
const match2 = /^(.+)-(.+)\.dist-info$/.exec(entry);
|
|
19844
|
+
if (match2) ctx.line(`${match2[1]} ${match2[2]}`);
|
|
19845
|
+
}
|
|
19846
|
+
return 0;
|
|
19847
|
+
}
|
|
19848
|
+
|
|
19849
|
+
// src/runtime/emscripten-fs.ts
|
|
19850
|
+
init_errno();
|
|
19851
|
+
init_path();
|
|
19852
|
+
var EM_ERRNO = {
|
|
19853
|
+
EPERM: 63,
|
|
19854
|
+
ENOENT: 44,
|
|
19855
|
+
EIO: 29,
|
|
19856
|
+
EBADF: 8,
|
|
19857
|
+
EACCES: 2,
|
|
19858
|
+
EBUSY: 10,
|
|
19859
|
+
EEXIST: 20,
|
|
19860
|
+
EXDEV: 75,
|
|
19861
|
+
ENODEV: 43,
|
|
19862
|
+
ENOTDIR: 54,
|
|
19863
|
+
EISDIR: 31,
|
|
19864
|
+
EINVAL: 28,
|
|
19865
|
+
ENFILE: 41,
|
|
19866
|
+
EMFILE: 33,
|
|
19867
|
+
ENOSPC: 51,
|
|
19868
|
+
EROFS: 57,
|
|
19869
|
+
ENOTEMPTY: 55,
|
|
19870
|
+
ELOOP: 32,
|
|
19871
|
+
ENOSYS: 52,
|
|
19872
|
+
ENOTSUP: 138
|
|
19873
|
+
};
|
|
19874
|
+
function emErrno(code) {
|
|
19875
|
+
return EM_ERRNO[code] ?? EM_ERRNO.EIO;
|
|
19876
|
+
}
|
|
19877
|
+
function mountContainerFs(FS, opts) {
|
|
19878
|
+
const { vfs, cred } = opts;
|
|
19879
|
+
const throwErrno = (code) => {
|
|
19880
|
+
throw new FS.ErrnoError(emErrno(code));
|
|
19881
|
+
};
|
|
19882
|
+
const translate = (e) => {
|
|
19883
|
+
if (isSysError(e)) return throwErrno(e.code);
|
|
19884
|
+
throw new FS.ErrnoError(emErrno("EIO"));
|
|
19885
|
+
};
|
|
19886
|
+
const mountRoot = opts.mountAt ? normalize(opts.mountAt) : "/";
|
|
19887
|
+
const backend = {
|
|
19888
|
+
/** Absolute container path for a node. */
|
|
19889
|
+
realPath(node2) {
|
|
19890
|
+
const parts = [];
|
|
19891
|
+
let current = node2;
|
|
19892
|
+
while (current && current.parent !== current) {
|
|
19893
|
+
parts.unshift(current.name);
|
|
19894
|
+
current = current.parent;
|
|
19895
|
+
}
|
|
19896
|
+
const relative2 = parts.join("/");
|
|
19897
|
+
if (mountRoot === "/") return "/" + relative2;
|
|
19898
|
+
return relative2 ? join(mountRoot, relative2) : mountRoot;
|
|
19899
|
+
},
|
|
19900
|
+
mount(_mount) {
|
|
19901
|
+
return backend.createNode(null, "/", 16877 | 0, 0);
|
|
19902
|
+
},
|
|
19903
|
+
createNode(parent, name, mode, rdev) {
|
|
19904
|
+
const node2 = FS.createNode(parent, name, mode, rdev);
|
|
19905
|
+
node2.node_ops = nodeOps;
|
|
19906
|
+
node2.stream_ops = streamOps;
|
|
19907
|
+
return node2;
|
|
19908
|
+
}
|
|
19909
|
+
};
|
|
19910
|
+
const nodeOps = {
|
|
19911
|
+
getattr(node2) {
|
|
19912
|
+
const path = backend.realPath(node2);
|
|
19913
|
+
try {
|
|
19914
|
+
const st = vfs.lstat(path);
|
|
19915
|
+
return {
|
|
19916
|
+
dev: st.dev,
|
|
19917
|
+
ino: st.ino,
|
|
19918
|
+
mode: st.mode,
|
|
19919
|
+
nlink: st.nlink,
|
|
19920
|
+
uid: st.uid,
|
|
19921
|
+
gid: st.gid,
|
|
19922
|
+
rdev: st.rdev,
|
|
19923
|
+
size: st.size,
|
|
19924
|
+
atime: new Date(st.atimeMs),
|
|
19925
|
+
mtime: new Date(st.mtimeMs),
|
|
19926
|
+
ctime: new Date(st.ctimeMs),
|
|
19927
|
+
blksize: 4096,
|
|
19928
|
+
blocks: Math.ceil(st.size / 512)
|
|
19929
|
+
};
|
|
19930
|
+
} catch (e) {
|
|
19931
|
+
return translate(e);
|
|
19932
|
+
}
|
|
19933
|
+
},
|
|
19934
|
+
setattr(node2, attr) {
|
|
19935
|
+
const path = backend.realPath(node2);
|
|
19936
|
+
try {
|
|
19937
|
+
if (attr.mode !== void 0) {
|
|
19938
|
+
vfs.chmod(path, attr.mode & 4095, cred);
|
|
19939
|
+
node2.mode = attr.mode;
|
|
19940
|
+
}
|
|
19941
|
+
if (attr.timestamp !== void 0) vfs.utimes(path, attr.timestamp, attr.timestamp, cred);
|
|
19942
|
+
if (attr.size !== void 0) {
|
|
19943
|
+
vfs.truncate(path, attr.size, cred);
|
|
19944
|
+
opts.onWrite?.(path);
|
|
19945
|
+
}
|
|
19946
|
+
} catch (e) {
|
|
19947
|
+
translate(e);
|
|
19948
|
+
}
|
|
19949
|
+
},
|
|
19950
|
+
lookup(parent, name) {
|
|
19951
|
+
const path = join(backend.realPath(parent), name);
|
|
19952
|
+
let mode;
|
|
19953
|
+
try {
|
|
19954
|
+
mode = vfs.lstat(path).mode;
|
|
19955
|
+
} catch {
|
|
19956
|
+
throw new FS.ErrnoError(EM_ERRNO.ENOENT);
|
|
19957
|
+
}
|
|
19958
|
+
return backend.createNode(parent, name, mode, 0);
|
|
19959
|
+
},
|
|
19960
|
+
mknod(parent, name, mode, dev) {
|
|
19961
|
+
const path = join(backend.realPath(parent), name);
|
|
19962
|
+
try {
|
|
19963
|
+
if (FS.isDir(mode)) {
|
|
19964
|
+
vfs.mkdir(path, { cred, mode: mode & 4095 });
|
|
19965
|
+
} else if (FS.isFile(mode)) {
|
|
19966
|
+
vfs.writeFile(path, new Uint8Array(0), { cred, mode: mode & 4095 });
|
|
19967
|
+
} else {
|
|
19968
|
+
return throwErrno("ENOTSUP");
|
|
19969
|
+
}
|
|
19970
|
+
opts.onWrite?.(path);
|
|
19971
|
+
} catch (e) {
|
|
19972
|
+
translate(e);
|
|
19973
|
+
}
|
|
19974
|
+
return backend.createNode(parent, name, mode, dev);
|
|
19975
|
+
},
|
|
19976
|
+
rename(oldNode, newDir, newName) {
|
|
19977
|
+
const from = backend.realPath(oldNode);
|
|
19978
|
+
const to = join(backend.realPath(newDir), newName);
|
|
19979
|
+
try {
|
|
19980
|
+
vfs.rename(from, to, cred);
|
|
19981
|
+
opts.onWrite?.(to);
|
|
19982
|
+
} catch (e) {
|
|
19983
|
+
translate(e);
|
|
19984
|
+
}
|
|
19985
|
+
oldNode.name = newName;
|
|
19986
|
+
oldNode.parent = newDir;
|
|
19987
|
+
},
|
|
19988
|
+
unlink(parent, name) {
|
|
19989
|
+
const path = join(backend.realPath(parent), name);
|
|
19990
|
+
try {
|
|
19991
|
+
vfs.unlink(path, cred);
|
|
19992
|
+
opts.onWrite?.(path);
|
|
17832
19993
|
} catch (e) {
|
|
17833
19994
|
translate(e);
|
|
17834
19995
|
}
|
|
@@ -18715,9 +20876,9 @@ async function resolveIndexUrl() {
|
|
|
18715
20876
|
if (indexUrl) return indexUrl;
|
|
18716
20877
|
if (!isNode2) return DEFAULT_BROWSER_INDEX_URL;
|
|
18717
20878
|
try {
|
|
18718
|
-
const { createRequire
|
|
20879
|
+
const { createRequire } = await nodeBuiltin("module");
|
|
18719
20880
|
const path = await nodeBuiltin("path");
|
|
18720
|
-
const require2 =
|
|
20881
|
+
const require2 = createRequire(path.join(process.cwd(), "index.js"));
|
|
18721
20882
|
return `${path.dirname(require2.resolve("pyodide/package.json"))}/`;
|
|
18722
20883
|
} catch {
|
|
18723
20884
|
return void 0;
|
|
@@ -18997,6 +21158,12 @@ var micropip = defineCommand({
|
|
|
18997
21158
|
summary: "install Python packages into the running interpreter",
|
|
18998
21159
|
usage: "micropip install <package>...",
|
|
18999
21160
|
async run(ctx) {
|
|
21161
|
+
if (usingOwnedPython()) {
|
|
21162
|
+
ctx.warn(
|
|
21163
|
+
"pip here is micropip, which installs into the Pyodide interpreter \u2014 not the source-built CPython this container is running, so the packages would not be importable.\nRun the container with the pyodide backend if you need micropip, or wait for venv and pip support on the owned runtime (see docs/python/release-gates.md, M4)."
|
|
21164
|
+
);
|
|
21165
|
+
return 1;
|
|
21166
|
+
}
|
|
19000
21167
|
const [action, ...args] = ctx.args;
|
|
19001
21168
|
if (action === "--version" || action === "-V") {
|
|
19002
21169
|
ctx.line("pip (micropip, Pyodide)");
|
|
@@ -19083,6 +21250,11 @@ var micropip = defineCommand({
|
|
|
19083
21250
|
var PYTHON_VERSION = "3.13";
|
|
19084
21251
|
function configurePython(options = {}) {
|
|
19085
21252
|
configureCPython({ indexURL: options.indexURL, moduleURL: options.pyodideURL });
|
|
21253
|
+
setPythonBackend({
|
|
21254
|
+
...options.backend !== void 0 ? { backend: options.backend } : {},
|
|
21255
|
+
...options.manifest !== void 0 ? { manifest: options.manifest } : {},
|
|
21256
|
+
...options.workerUrl !== void 0 ? { workerUrl: options.workerUrl } : {}
|
|
21257
|
+
});
|
|
19086
21258
|
}
|
|
19087
21259
|
var isPythonAvailable = isCPythonAvailable;
|
|
19088
21260
|
var python = defineCommand({
|
|
@@ -19095,6 +21267,13 @@ var python = defineCommand({
|
|
|
19095
21267
|
the container's virtual filesystem, modules in /workspace are importable, and
|
|
19096
21268
|
compatible packages can be installed with pip (micropip).`,
|
|
19097
21269
|
async run(ctx) {
|
|
21270
|
+
if (usingOwnedPython()) {
|
|
21271
|
+
try {
|
|
21272
|
+
return await runOwnedPython(ctx, ctx.args);
|
|
21273
|
+
} catch (error) {
|
|
21274
|
+
return ctx.fail(error.message ?? String(error));
|
|
21275
|
+
}
|
|
21276
|
+
}
|
|
19098
21277
|
const argv = ctx.args;
|
|
19099
21278
|
let i = 0;
|
|
19100
21279
|
let command;
|
|
@@ -19175,22 +21354,22 @@ function printHelp2(ctx) {
|
|
|
19175
21354
|
ctx.line("-V : print the Python version and exit");
|
|
19176
21355
|
}
|
|
19177
21356
|
function pythonCommands() {
|
|
19178
|
-
return [python, micropip];
|
|
21357
|
+
return usingOwnedPython() ? [python, pipCommand] : [python, micropip];
|
|
19179
21358
|
}
|
|
19180
21359
|
|
|
19181
21360
|
// src/runtime/ffmpeg.ts
|
|
19182
21361
|
var INSTALL_HINT = "ffmpeg is not installed in this container.\nThe FFmpeg runtime ships separately because it is a ~31MB WebAssembly build:\n npm install @ffmpeg/core";
|
|
19183
21362
|
var compiled = null;
|
|
19184
21363
|
async function loadFactory() {
|
|
19185
|
-
const { createRequire
|
|
21364
|
+
const { createRequire } = await nodeBuiltin("module");
|
|
19186
21365
|
const fs = await nodeBuiltin("fs/promises");
|
|
19187
21366
|
const path = await nodeBuiltin("path");
|
|
19188
|
-
const packageRequire =
|
|
21367
|
+
const packageRequire = createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
19189
21368
|
let require2 = packageRequire;
|
|
19190
21369
|
try {
|
|
19191
21370
|
require2.resolve("@ffmpeg/core/wasm");
|
|
19192
21371
|
} catch {
|
|
19193
|
-
require2 =
|
|
21372
|
+
require2 = createRequire(path.join(process.cwd(), "index.js"));
|
|
19194
21373
|
}
|
|
19195
21374
|
const wasmPath = require2.resolve("@ffmpeg/core/wasm");
|
|
19196
21375
|
const wasm = await fs.readFile(wasmPath);
|
|
@@ -21719,19 +23898,19 @@ var KernelChildProcess = class {
|
|
|
21719
23898
|
process;
|
|
21720
23899
|
started = false;
|
|
21721
23900
|
cancelled = false;
|
|
21722
|
-
constructor(kernel, cred,
|
|
23901
|
+
constructor(kernel, cred, config2, pid) {
|
|
21723
23902
|
this.stdin.interactive = true;
|
|
21724
|
-
if (
|
|
21725
|
-
if (
|
|
23903
|
+
if (config2.inheritStdio) this.stdin.isTTY = true;
|
|
23904
|
+
if (config2.stdinIgnored) this.stdin.end();
|
|
21726
23905
|
this.stdin.onRawMode = (enabled) => this.emit("rawmode", enabled);
|
|
21727
23906
|
this.kernel = kernel;
|
|
21728
23907
|
this.cred = cred;
|
|
21729
23908
|
this.pid = pid;
|
|
21730
|
-
this.command =
|
|
21731
|
-
this.args =
|
|
21732
|
-
this.parentPid =
|
|
21733
|
-
this.cwd =
|
|
21734
|
-
this.env = { ...
|
|
23909
|
+
this.command = config2.command;
|
|
23910
|
+
this.args = config2.args?.slice() ?? [];
|
|
23911
|
+
this.parentPid = config2.parentPid;
|
|
23912
|
+
this.cwd = config2.cwd ?? "/";
|
|
23913
|
+
this.env = { ...config2.env };
|
|
21735
23914
|
}
|
|
21736
23915
|
on(event, listener) {
|
|
21737
23916
|
let listeners = this.listeners.get(event);
|
|
@@ -21838,12 +24017,12 @@ var nextBridgePid = 1073741824;
|
|
|
21838
24017
|
function installNodeChildProcessBridge(pod, kernel, cred) {
|
|
21839
24018
|
const manager = pod.processManager;
|
|
21840
24019
|
const originalSpawn = manager.spawn;
|
|
21841
|
-
manager.spawn = (
|
|
21842
|
-
const resolved = kernel.resolveExecutable(
|
|
24020
|
+
manager.spawn = (config2) => {
|
|
24021
|
+
const resolved = kernel.resolveExecutable(config2.command, config2.cwd ?? "/", config2.env ?? {}, cred);
|
|
21843
24022
|
if (resolved?.kind === "builtin") {
|
|
21844
|
-
return new KernelChildProcess(kernel, cred,
|
|
24023
|
+
return new KernelChildProcess(kernel, cred, config2, nextBridgePid++);
|
|
21845
24024
|
}
|
|
21846
|
-
return originalSpawn.call(manager,
|
|
24025
|
+
return originalSpawn.call(manager, config2);
|
|
21847
24026
|
};
|
|
21848
24027
|
return () => {
|
|
21849
24028
|
if (manager.spawn === originalSpawn) return;
|
|
@@ -23205,14 +25384,14 @@ var AssertionError = class extends Error {
|
|
|
23205
25384
|
code = "ERR_ASSERTION";
|
|
23206
25385
|
constructor(options) {
|
|
23207
25386
|
const generated = options.message === void 0;
|
|
23208
|
-
super(options.message ??
|
|
25387
|
+
super(options.message ?? describe2(options.actual, options.expected, options.operator));
|
|
23209
25388
|
this.actual = options.actual;
|
|
23210
25389
|
this.expected = options.expected;
|
|
23211
25390
|
this.operator = options.operator;
|
|
23212
25391
|
this.generatedMessage = generated;
|
|
23213
25392
|
}
|
|
23214
25393
|
};
|
|
23215
|
-
function
|
|
25394
|
+
function describe2(actual, expected, operator) {
|
|
23216
25395
|
if (operator === "fail") return "Failed";
|
|
23217
25396
|
const rendered = (value) => inspect(value, { depth: 2 });
|
|
23218
25397
|
return `${rendered(actual)} ${operator} ${rendered(expected)}`;
|
|
@@ -24050,9 +26229,9 @@ var VirtualClientRequest = class extends streamModule4__default.default.Writable
|
|
|
24050
26229
|
} catch (error) {
|
|
24051
26230
|
clearTimeout(this.timer);
|
|
24052
26231
|
if (this.destroyedByUser) return;
|
|
24053
|
-
const
|
|
24054
|
-
if (!("code" in
|
|
24055
|
-
this.emit("error",
|
|
26232
|
+
const failure2 = error instanceof Error ? error : new Error(String(error));
|
|
26233
|
+
if (!("code" in failure2)) Object.assign(failure2, { code: "ECONNREFUSED" });
|
|
26234
|
+
this.emit("error", failure2);
|
|
24056
26235
|
} finally {
|
|
24057
26236
|
if (!settled) untrack();
|
|
24058
26237
|
}
|
|
@@ -24250,17 +26429,17 @@ function toBytes2(data, encoding) {
|
|
|
24250
26429
|
}
|
|
24251
26430
|
|
|
24252
26431
|
// src/runtime/sync-channel.ts
|
|
24253
|
-
var
|
|
24254
|
-
var
|
|
24255
|
-
var
|
|
24256
|
-
var
|
|
24257
|
-
var
|
|
24258
|
-
var
|
|
24259
|
-
var
|
|
24260
|
-
var
|
|
26432
|
+
var STATE2 = 0;
|
|
26433
|
+
var LENGTH2 = 1;
|
|
26434
|
+
var MORE2 = 2;
|
|
26435
|
+
var CONTROL_WORDS2 = 4;
|
|
26436
|
+
var STATE_REQUEST2 = 1;
|
|
26437
|
+
var STATE_RESPONSE2 = 2;
|
|
26438
|
+
var STATE_CONTINUE2 = 3;
|
|
26439
|
+
var STATE_CLOSED2 = 4;
|
|
24261
26440
|
function createSyncChannelBuffers(capacityBytes = 1 << 20) {
|
|
24262
26441
|
return {
|
|
24263
|
-
control: new SharedArrayBuffer(
|
|
26442
|
+
control: new SharedArrayBuffer(CONTROL_WORDS2 * Int32Array.BYTES_PER_ELEMENT),
|
|
24264
26443
|
data: new SharedArrayBuffer(capacityBytes)
|
|
24265
26444
|
};
|
|
24266
26445
|
}
|
|
@@ -24294,15 +26473,15 @@ var SyncChannelServer = class {
|
|
|
24294
26473
|
/** Call from the wake message the client sends after each chunk. */
|
|
24295
26474
|
async pump() {
|
|
24296
26475
|
if (this.closed) return;
|
|
24297
|
-
const state = Atomics.load(this.control,
|
|
24298
|
-
if (state ===
|
|
24299
|
-
const size = Atomics.load(this.control,
|
|
26476
|
+
const state = Atomics.load(this.control, STATE2);
|
|
26477
|
+
if (state === STATE_REQUEST2) {
|
|
26478
|
+
const size = Atomics.load(this.control, LENGTH2);
|
|
24300
26479
|
this.incoming.push(this.data.slice(0, size));
|
|
24301
|
-
if (Atomics.load(this.control,
|
|
24302
|
-
this.publish(
|
|
26480
|
+
if (Atomics.load(this.control, MORE2) === 1) {
|
|
26481
|
+
this.publish(STATE_CONTINUE2);
|
|
24303
26482
|
return;
|
|
24304
26483
|
}
|
|
24305
|
-
const request =
|
|
26484
|
+
const request = concat4(this.incoming);
|
|
24306
26485
|
this.incoming = [];
|
|
24307
26486
|
let response;
|
|
24308
26487
|
try {
|
|
@@ -24316,30 +26495,30 @@ var SyncChannelServer = class {
|
|
|
24316
26495
|
this.sendChunk();
|
|
24317
26496
|
return;
|
|
24318
26497
|
}
|
|
24319
|
-
if (state ===
|
|
26498
|
+
if (state === STATE_CONTINUE2) this.sendChunk();
|
|
24320
26499
|
}
|
|
24321
26500
|
/** Release a blocked client, e.g. when the container is torn down. */
|
|
24322
26501
|
close() {
|
|
24323
26502
|
if (this.closed) return;
|
|
24324
26503
|
this.closed = true;
|
|
24325
|
-
Atomics.store(this.control,
|
|
24326
|
-
Atomics.notify(this.control,
|
|
26504
|
+
Atomics.store(this.control, STATE2, STATE_CLOSED2);
|
|
26505
|
+
Atomics.notify(this.control, STATE2);
|
|
24327
26506
|
}
|
|
24328
26507
|
sendChunk() {
|
|
24329
26508
|
const payload = this.outgoing ?? new Uint8Array();
|
|
24330
26509
|
const size = Math.min(this.capacity, payload.length - this.sent);
|
|
24331
26510
|
this.data.set(payload.subarray(this.sent, this.sent + size), 0);
|
|
24332
26511
|
this.sent += size;
|
|
24333
|
-
Atomics.store(this.control,
|
|
24334
|
-
Atomics.store(this.control,
|
|
24335
|
-
this.publish(
|
|
26512
|
+
Atomics.store(this.control, LENGTH2, size);
|
|
26513
|
+
Atomics.store(this.control, MORE2, this.sent < payload.length ? 1 : 0);
|
|
26514
|
+
this.publish(STATE_RESPONSE2);
|
|
24336
26515
|
}
|
|
24337
26516
|
publish(state) {
|
|
24338
|
-
Atomics.store(this.control,
|
|
24339
|
-
Atomics.notify(this.control,
|
|
26517
|
+
Atomics.store(this.control, STATE2, state);
|
|
26518
|
+
Atomics.notify(this.control, STATE2);
|
|
24340
26519
|
}
|
|
24341
26520
|
};
|
|
24342
|
-
function
|
|
26521
|
+
function concat4(parts) {
|
|
24343
26522
|
if (parts.length === 1) return parts[0];
|
|
24344
26523
|
const total = parts.reduce((sum, part) => sum + part.length, 0);
|
|
24345
26524
|
const joined = new Uint8Array(total);
|
|
@@ -24472,13 +26651,13 @@ ${err.join("")}`),
|
|
|
24472
26651
|
return child;
|
|
24473
26652
|
};
|
|
24474
26653
|
const exec = (command, options = {}, callback) => {
|
|
24475
|
-
const [opts, cb] =
|
|
26654
|
+
const [opts, cb] = normalize3(options, callback);
|
|
24476
26655
|
const { file: file3, args } = throughShell(command, opts);
|
|
24477
26656
|
return collect(start2(file3, args, { ...opts, shell: false }), opts, cb);
|
|
24478
26657
|
};
|
|
24479
26658
|
const execFile = (file3, args = [], options = {}, callback) => {
|
|
24480
26659
|
const list = Array.isArray(args) ? args : [];
|
|
24481
|
-
const [opts, cb] = Array.isArray(args) ?
|
|
26660
|
+
const [opts, cb] = Array.isArray(args) ? normalize3(options, callback) : normalize3(args, options);
|
|
24482
26661
|
return collect(start2(file3, list, opts), opts, cb);
|
|
24483
26662
|
};
|
|
24484
26663
|
return {
|
|
@@ -24550,7 +26729,7 @@ ${result.stderr}`), {
|
|
|
24550
26729
|
const execSync = (command, options = {}) => orThrow(run(command, [], { ...options, shell: options.shell ?? true }), command, options);
|
|
24551
26730
|
return { spawnSync, execFileSync, execSync };
|
|
24552
26731
|
}
|
|
24553
|
-
function
|
|
26732
|
+
function normalize3(options, callback) {
|
|
24554
26733
|
if (typeof options === "function") return [{}, options];
|
|
24555
26734
|
return [options ?? {}, callback];
|
|
24556
26735
|
}
|
|
@@ -24942,7 +27121,7 @@ function createReadlineModule(defaultInput, defaultOutput = () => void 0) {
|
|
|
24942
27121
|
}
|
|
24943
27122
|
}
|
|
24944
27123
|
}
|
|
24945
|
-
const
|
|
27124
|
+
const isTerminal2 = (options, output) => {
|
|
24946
27125
|
if (typeof options?.terminal === "boolean") return options.terminal;
|
|
24947
27126
|
return Boolean(output?.isTTY);
|
|
24948
27127
|
};
|
|
@@ -24952,13 +27131,13 @@ function createReadlineModule(defaultInput, defaultOutput = () => void 0) {
|
|
|
24952
27131
|
const instance = new Interface(
|
|
24953
27132
|
options.input ?? defaultInput(),
|
|
24954
27133
|
resolvedOutput2,
|
|
24955
|
-
|
|
27134
|
+
isTerminal2(options, resolvedOutput2)
|
|
24956
27135
|
);
|
|
24957
27136
|
if (typeof options.prompt === "string") instance.setPrompt(options.prompt);
|
|
24958
27137
|
return instance;
|
|
24959
27138
|
}
|
|
24960
27139
|
const resolvedOutput = output;
|
|
24961
|
-
return new Interface(options ?? defaultInput(), resolvedOutput,
|
|
27140
|
+
return new Interface(options ?? defaultInput(), resolvedOutput, isTerminal2(void 0, resolvedOutput));
|
|
24962
27141
|
};
|
|
24963
27142
|
const noop = () => {
|
|
24964
27143
|
};
|
|
@@ -26925,44 +29104,69 @@ function ensureProcessGlobal() {
|
|
|
26925
29104
|
configurable: true
|
|
26926
29105
|
});
|
|
26927
29106
|
}
|
|
29107
|
+
|
|
29108
|
+
// src/runtime/rolldown-node-binding.ts
|
|
29109
|
+
async function loadNodeApi() {
|
|
29110
|
+
const [moduleApi, fsApi, pathApi, urlApi] = await Promise.all([
|
|
29111
|
+
nodeBuiltin("module"),
|
|
29112
|
+
nodeBuiltin("fs"),
|
|
29113
|
+
nodeBuiltin("path"),
|
|
29114
|
+
nodeBuiltin("url")
|
|
29115
|
+
]);
|
|
29116
|
+
return {
|
|
29117
|
+
createRequire: moduleApi.createRequire,
|
|
29118
|
+
existsSync: fsApi.existsSync,
|
|
29119
|
+
readFileSync: fsApi.readFileSync,
|
|
29120
|
+
dirname: pathApi.dirname,
|
|
29121
|
+
join: pathApi.join,
|
|
29122
|
+
fileURLToPath: urlApi.fileURLToPath,
|
|
29123
|
+
pathToFileURL: urlApi.pathToFileURL
|
|
29124
|
+
};
|
|
29125
|
+
}
|
|
26928
29126
|
var BINDING_PACKAGE = "@rolldown/binding-wasm32-wasi";
|
|
26929
29127
|
var ASYNC_WORK_POOL_SIZE = 4;
|
|
26930
29128
|
var WORKER_FILE = "rolldown-wasi-worker.js";
|
|
26931
29129
|
async function loadNodeRolldownMemfsBinding() {
|
|
26932
|
-
const
|
|
29130
|
+
const node2 = await loadNodeApi();
|
|
29131
|
+
const { createRequire, existsSync, readFileSync, dirname: dirname3, join: join3, fileURLToPath: fileURLToPath2, pathToFileURL: pathToFileURL2 } = node2;
|
|
29132
|
+
const require2 = createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
26933
29133
|
let packageDir;
|
|
26934
29134
|
try {
|
|
26935
|
-
packageDir =
|
|
29135
|
+
packageDir = dirname3(require2.resolve(`${BINDING_PACKAGE}/package.json`));
|
|
26936
29136
|
} catch {
|
|
26937
29137
|
return null;
|
|
26938
29138
|
}
|
|
26939
|
-
const fromBinding =
|
|
29139
|
+
const fromBinding = createRequire(join3(packageDir, "package.json"));
|
|
26940
29140
|
let runtime;
|
|
26941
29141
|
let fsModuleUrl;
|
|
26942
29142
|
let createContext2;
|
|
26943
29143
|
try {
|
|
26944
29144
|
runtime = fromBinding("@napi-rs/wasm-runtime");
|
|
26945
|
-
fsModuleUrl = resolveSubpath(fromBinding, "@napi-rs/wasm-runtime", "./fs");
|
|
29145
|
+
fsModuleUrl = resolveSubpath(node2, fromBinding, "@napi-rs/wasm-runtime", "./fs");
|
|
26946
29146
|
({ createContext: createContext2 } = fromBinding("@emnapi/runtime"));
|
|
26947
29147
|
} catch {
|
|
26948
29148
|
return null;
|
|
26949
29149
|
}
|
|
26950
|
-
const { memfs } = await import(
|
|
26951
|
-
|
|
29150
|
+
const { memfs } = await import(
|
|
29151
|
+
/* @vite-ignore */
|
|
29152
|
+
/* webpackIgnore: true */
|
|
29153
|
+
fsModuleUrl
|
|
29154
|
+
);
|
|
29155
|
+
const { Worker: Worker2 } = await nodeBuiltin("worker_threads");
|
|
26952
29156
|
const { fs: memoryFs, vol } = memfs();
|
|
26953
29157
|
const wasi2 = new runtime.WASI({
|
|
26954
29158
|
version: "preview1",
|
|
26955
29159
|
fs: memoryFs,
|
|
26956
29160
|
preopens: { "/": "/" }
|
|
26957
29161
|
});
|
|
26958
|
-
const wasmFile =
|
|
29162
|
+
const wasmFile = readFileSync(join3(packageDir, "rolldown-binding.wasm32-wasi.wasm"));
|
|
26959
29163
|
const sharedMemory = new WebAssembly.Memory({ initial: 16384, maximum: 65536, shared: true });
|
|
26960
29164
|
const workerPoolSize = Math.max(2, cpuCount());
|
|
26961
29165
|
const context = createContext2({ autoDestroy: false });
|
|
26962
29166
|
context.suppressDestroy();
|
|
26963
|
-
const workerPath = resolveWorkerPath();
|
|
29167
|
+
const workerPath = resolveWorkerPath(node2);
|
|
26964
29168
|
if (!workerPath) return null;
|
|
26965
|
-
const runtimeAnchor =
|
|
29169
|
+
const runtimeAnchor = pathToFileURL2(join3(packageDir, "package.json")).href;
|
|
26966
29170
|
const workers = /* @__PURE__ */ new Set();
|
|
26967
29171
|
let started = false;
|
|
26968
29172
|
const { napiModule } = await runtime.instantiateNapiModule(wasmFile, {
|
|
@@ -27014,24 +29218,26 @@ async function loadNodeRolldownMemfsBinding() {
|
|
|
27014
29218
|
for (const worker of workers) unreferenceWorker(worker);
|
|
27015
29219
|
return { ...napiModule.exports, __fs: memoryFs, __volume: vol };
|
|
27016
29220
|
}
|
|
27017
|
-
function resolveWorkerPath() {
|
|
27018
|
-
const
|
|
29221
|
+
function resolveWorkerPath(node2) {
|
|
29222
|
+
const { dirname: dirname3, existsSync, fileURLToPath: fileURLToPath2, join: join3 } = node2;
|
|
29223
|
+
const here = dirname3(fileURLToPath2((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
|
|
27019
29224
|
const candidates = [
|
|
27020
|
-
|
|
29225
|
+
join3(here, WORKER_FILE),
|
|
27021
29226
|
/* src/runtime → dist, for a checkout that has been built. */
|
|
27022
|
-
|
|
29227
|
+
join3(here, "..", "..", "dist", WORKER_FILE)
|
|
27023
29228
|
];
|
|
27024
|
-
return candidates.find((candidate) =>
|
|
29229
|
+
return candidates.find((candidate) => existsSync(candidate)) ?? null;
|
|
27025
29230
|
}
|
|
27026
|
-
function resolveSubpath(require2, packageName, subpath) {
|
|
27027
|
-
const
|
|
27028
|
-
const
|
|
29231
|
+
function resolveSubpath(node2, require2, packageName, subpath) {
|
|
29232
|
+
const { dirname: dirname3, join: join3, pathToFileURL: pathToFileURL2, readFileSync } = node2;
|
|
29233
|
+
const packageDir = dirname3(require2.resolve(packageName));
|
|
29234
|
+
const manifest = JSON.parse(readFileSync(join3(packageDir, "package.json"), "utf8"));
|
|
27029
29235
|
const entry = manifest?.exports?.[subpath];
|
|
27030
29236
|
const target = typeof entry === "string" ? entry : entry?.import ?? entry?.default;
|
|
27031
29237
|
if (typeof target !== "string") {
|
|
27032
29238
|
throw new Error(`${packageName} does not export ${subpath}`);
|
|
27033
29239
|
}
|
|
27034
|
-
return
|
|
29240
|
+
return pathToFileURL2(join3(packageDir, target)).href;
|
|
27035
29241
|
}
|
|
27036
29242
|
function cpuCount() {
|
|
27037
29243
|
try {
|
|
@@ -27210,9 +29416,9 @@ var LocalProcess = class extends EventEmitter4__default.default {
|
|
|
27210
29416
|
}
|
|
27211
29417
|
};
|
|
27212
29418
|
var PodChildProcess = class {
|
|
27213
|
-
constructor(pid,
|
|
29419
|
+
constructor(pid, config2, launch) {
|
|
27214
29420
|
this.pid = pid;
|
|
27215
|
-
this.config =
|
|
29421
|
+
this.config = config2;
|
|
27216
29422
|
this.launch = launch;
|
|
27217
29423
|
}
|
|
27218
29424
|
pid;
|
|
@@ -27350,15 +29556,54 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
27350
29556
|
instanceId = `sbx-${Math.random().toString(36).slice(2)}`;
|
|
27351
29557
|
router = new VirtualHttpRouter();
|
|
27352
29558
|
proxy = { activePorts: (_instanceId) => this.router.activePorts() };
|
|
29559
|
+
/**
|
|
29560
|
+
* Bind a port to a server that is not a JavaScript one.
|
|
29561
|
+
*
|
|
29562
|
+
* The request is flattened to bytes and headers before it crosses the
|
|
29563
|
+
* boundary, because the far side is a different language and a Node stream
|
|
29564
|
+
* object cannot go there. What comes back is a complete response; streaming
|
|
29565
|
+
* is a later protocol, and pretending to stream over a buffered path would
|
|
29566
|
+
* only move the surprise.
|
|
29567
|
+
*/
|
|
29568
|
+
serveExternal(port, owner, handler) {
|
|
29569
|
+
const server = new VirtualHttpServer(this.router, owner);
|
|
29570
|
+
server.on("request", (request, response) => {
|
|
29571
|
+
void (async () => {
|
|
29572
|
+
const chunks = [];
|
|
29573
|
+
for await (const chunk of request) chunks.push(chunk);
|
|
29574
|
+
const body = new Uint8Array(chunks.reduce((n, c) => n + c.length, 0));
|
|
29575
|
+
let at = 0;
|
|
29576
|
+
for (const chunk of chunks) {
|
|
29577
|
+
body.set(chunk, at);
|
|
29578
|
+
at += chunk.length;
|
|
29579
|
+
}
|
|
29580
|
+
try {
|
|
29581
|
+
const answer = await handler({
|
|
29582
|
+
method: request.method,
|
|
29583
|
+
path: request.url,
|
|
29584
|
+
headers: request.headers,
|
|
29585
|
+
body
|
|
29586
|
+
});
|
|
29587
|
+
response.writeHead(answer.statusCode, answer.headers ?? {});
|
|
29588
|
+
response.end(answer.body ?? "");
|
|
29589
|
+
} catch (error) {
|
|
29590
|
+
response.writeHead(500, { "content-type": "text/plain" });
|
|
29591
|
+
response.end(error instanceof Error ? error.message : String(error));
|
|
29592
|
+
}
|
|
29593
|
+
})();
|
|
29594
|
+
});
|
|
29595
|
+
server.listen(port);
|
|
29596
|
+
return () => server.close();
|
|
29597
|
+
}
|
|
27353
29598
|
/**
|
|
27354
29599
|
* Mutable on purpose: a container replaces `spawn` so that children resolve
|
|
27355
29600
|
* against the kernel's PATH. Left alone, it runs `node` and reports anything
|
|
27356
29601
|
* else as not found, which is the correct answer for a bare pod.
|
|
27357
29602
|
*/
|
|
27358
29603
|
processManager = {
|
|
27359
|
-
spawn: (
|
|
29604
|
+
spawn: (config2) => new PodChildProcess(
|
|
27360
29605
|
nextChildPid++,
|
|
27361
|
-
|
|
29606
|
+
config2,
|
|
27362
29607
|
(child) => this.spawn(child.command, child.args ?? [], {
|
|
27363
29608
|
...child.cwd ? { cwd: child.cwd } : {},
|
|
27364
29609
|
...child.env ? { env: child.env } : {}
|
|
@@ -27431,7 +29676,7 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
27431
29676
|
if (engine?.isEvaluating) throw new ProcessExit(code);
|
|
27432
29677
|
},
|
|
27433
29678
|
http: { router: this.router, owner, ...this.fetch ? { fetch: this.fetch } : {} },
|
|
27434
|
-
spawnChild: (
|
|
29679
|
+
spawnChild: (config2) => this.processManager.spawn(config2),
|
|
27435
29680
|
...typeof options.stdinPath === "string" ? { stdinPath: options.stdinPath } : {},
|
|
27436
29681
|
...options.interactiveStdin ? { interactiveStdin: true } : {},
|
|
27437
29682
|
...options.tty ? { tty: true } : {},
|
|
@@ -27652,10 +29897,10 @@ function serveVolume(volume) {
|
|
|
27652
29897
|
}
|
|
27653
29898
|
return encodeFrame({ ok: true, value: result });
|
|
27654
29899
|
} catch (error) {
|
|
27655
|
-
const
|
|
29900
|
+
const failure2 = error;
|
|
27656
29901
|
return encodeFrame({
|
|
27657
29902
|
ok: false,
|
|
27658
|
-
error: { ...
|
|
29903
|
+
error: { ...failure2.code ? { code: failure2.code } : {}, message: failure2.message ?? String(error) }
|
|
27659
29904
|
});
|
|
27660
29905
|
}
|
|
27661
29906
|
};
|
|
@@ -27672,7 +29917,7 @@ function serveSyncSyscalls(options) {
|
|
|
27672
29917
|
const result = await options.spawnChild(header.args[0]);
|
|
27673
29918
|
return encodeFrame({ ok: true, value: result });
|
|
27674
29919
|
} catch (error) {
|
|
27675
|
-
const
|
|
29920
|
+
const failure2 = error;
|
|
27676
29921
|
return encodeFrame({
|
|
27677
29922
|
ok: true,
|
|
27678
29923
|
value: {
|
|
@@ -27680,81 +29925,10 @@ function serveSyncSyscalls(options) {
|
|
|
27680
29925
|
stdout: "",
|
|
27681
29926
|
stderr: "",
|
|
27682
29927
|
signal: null,
|
|
27683
|
-
error: { ...
|
|
27684
|
-
}
|
|
27685
|
-
});
|
|
27686
|
-
}
|
|
27687
|
-
};
|
|
27688
|
-
}
|
|
27689
|
-
|
|
27690
|
-
// src/runtime/worker-host.ts
|
|
27691
|
-
function defaultWorkerUrl() {
|
|
27692
|
-
return new URL("./worker-entry.js", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
27693
|
-
}
|
|
27694
|
-
function hasDomWorker() {
|
|
27695
|
-
return typeof Worker === "function";
|
|
27696
|
-
}
|
|
27697
|
-
async function startRuntimeWorker(options = {}) {
|
|
27698
|
-
const url = options.url ?? defaultWorkerUrl();
|
|
27699
|
-
const worker = hasDomWorker() ? await startDomWorker(url) : await startNodeWorker(url, options.workerData ?? {});
|
|
27700
|
-
try {
|
|
27701
|
-
await new Promise((resolve2, reject) => {
|
|
27702
|
-
const timer = setTimeout(() => reject(new Error("the runtime worker did not start in time")), options.timeoutMs ?? 1e4);
|
|
27703
|
-
worker.onMessage((message) => {
|
|
27704
|
-
if (message?.type === "sandboxedjs:ready") {
|
|
27705
|
-
clearTimeout(timer);
|
|
27706
|
-
resolve2();
|
|
29928
|
+
error: { ...failure2.code ? { code: failure2.code } : {}, message: failure2.message ?? String(error) }
|
|
27707
29929
|
}
|
|
27708
29930
|
});
|
|
27709
|
-
worker.onError((error) => {
|
|
27710
|
-
clearTimeout(timer);
|
|
27711
|
-
reject(error instanceof Error ? error : new Error(String(error)));
|
|
27712
|
-
});
|
|
27713
|
-
});
|
|
27714
|
-
} catch (error) {
|
|
27715
|
-
try {
|
|
27716
|
-
await worker.terminate();
|
|
27717
|
-
} catch {
|
|
27718
29931
|
}
|
|
27719
|
-
throw error;
|
|
27720
|
-
}
|
|
27721
|
-
return worker;
|
|
27722
|
-
}
|
|
27723
|
-
async function startDomWorker(url) {
|
|
27724
|
-
const worker = new Worker(url, { type: "module" });
|
|
27725
|
-
const listeners = [];
|
|
27726
|
-
const errors = [];
|
|
27727
|
-
worker.addEventListener("message", (event) => {
|
|
27728
|
-
for (const listener of listeners) listener(event.data);
|
|
27729
|
-
});
|
|
27730
|
-
worker.addEventListener("error", (event) => {
|
|
27731
|
-
const detail = event.message || "the runtime worker failed to load";
|
|
27732
|
-
for (const listener of errors) listener(new Error(detail));
|
|
27733
|
-
});
|
|
27734
|
-
return {
|
|
27735
|
-
postMessage: (message) => worker.postMessage(message),
|
|
27736
|
-
onMessage: (listener) => {
|
|
27737
|
-
listeners.push(listener);
|
|
27738
|
-
},
|
|
27739
|
-
onError: (listener) => {
|
|
27740
|
-
errors.push(listener);
|
|
27741
|
-
},
|
|
27742
|
-
terminate: () => worker.terminate()
|
|
27743
|
-
};
|
|
27744
|
-
}
|
|
27745
|
-
async function startNodeWorker(url, workerData) {
|
|
27746
|
-
const specifier = ["node", "worker_threads"].join(":");
|
|
27747
|
-
const { Worker: NodeWorker } = await import(
|
|
27748
|
-
/* @vite-ignore */
|
|
27749
|
-
/* webpackIgnore: true */
|
|
27750
|
-
specifier
|
|
27751
|
-
);
|
|
27752
|
-
const worker = new NodeWorker(url, { workerData });
|
|
27753
|
-
return {
|
|
27754
|
-
postMessage: (message) => worker.postMessage(message),
|
|
27755
|
-
onMessage: (listener) => worker.on("message", listener),
|
|
27756
|
-
onError: (listener) => worker.on("error", listener),
|
|
27757
|
-
terminate: () => worker.terminate()
|
|
27758
29932
|
};
|
|
27759
29933
|
}
|
|
27760
29934
|
var WorkerProcess = class extends EventEmitter4__default.default {
|
|
@@ -28018,8 +30192,8 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
28018
30192
|
...request.inheritStdio ? { inheritStdio: true } : {}
|
|
28019
30193
|
});
|
|
28020
30194
|
} catch (error) {
|
|
28021
|
-
const
|
|
28022
|
-
resolve2({ status: null, stdout: "", stderr: "", signal: null, error: { ...
|
|
30195
|
+
const failure2 = error;
|
|
30196
|
+
resolve2({ status: null, stdout: "", stderr: "", signal: null, error: { ...failure2.code ? { code: failure2.code } : {}, message: failure2.message } });
|
|
28023
30197
|
return;
|
|
28024
30198
|
}
|
|
28025
30199
|
owned.add(handle);
|
|
@@ -28074,7 +30248,7 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
28074
30248
|
async forward(worker, port, request, response) {
|
|
28075
30249
|
const chunks = [];
|
|
28076
30250
|
for await (const chunk of request) chunks.push(chunk);
|
|
28077
|
-
const body =
|
|
30251
|
+
const body = concat5(chunks);
|
|
28078
30252
|
const id = this.nextRequestId++;
|
|
28079
30253
|
const answered = new Promise((resolve2) => this.waiting.set(id, resolve2));
|
|
28080
30254
|
worker.postMessage({
|
|
@@ -28155,7 +30329,7 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
28155
30329
|
function isRecord2(value) {
|
|
28156
30330
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28157
30331
|
}
|
|
28158
|
-
function
|
|
30332
|
+
function concat5(parts) {
|
|
28159
30333
|
if (parts.length === 0) return new Uint8Array();
|
|
28160
30334
|
if (parts.length === 1) return parts[0];
|
|
28161
30335
|
const total = parts.reduce((sum, part) => sum + part.length, 0);
|
|
@@ -29306,6 +31480,8 @@ exports.KERNEL_NAME = KERNEL_NAME;
|
|
|
29306
31480
|
exports.KERNEL_RELEASE = KERNEL_RELEASE;
|
|
29307
31481
|
exports.Kernel = Kernel;
|
|
29308
31482
|
exports.LocalRuntimePod = LocalRuntimePod;
|
|
31483
|
+
exports.MANIFEST_FORMAT = MANIFEST_FORMAT;
|
|
31484
|
+
exports.MANIFEST_SCHEMA_VERSION = MANIFEST_SCHEMA_VERSION;
|
|
29309
31485
|
exports.MemoryVolume = MemoryVolume;
|
|
29310
31486
|
exports.NODE_VERSION = NODE_VERSION;
|
|
29311
31487
|
exports.NPM_VERSION = NPM_VERSION;
|
|
@@ -29387,6 +31563,7 @@ exports.strerror = strerror;
|
|
|
29387
31563
|
exports.syncChannelSupported = syncChannelSupported;
|
|
29388
31564
|
exports.transformEsm = transformEsm;
|
|
29389
31565
|
exports.unameInfo = unameInfo;
|
|
31566
|
+
exports.validateManifest = validateManifest;
|
|
29390
31567
|
exports.wasiCommand = wasi;
|
|
29391
31568
|
//# sourceMappingURL=index.cjs.map
|
|
29392
31569
|
//# sourceMappingURL=index.cjs.map
|