sandboxedjs 0.1.54 → 0.1.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/agent.d.cts +2 -2
- package/dist/agent.d.ts +2 -2
- package/dist/{container-B--ykWn3.d.cts → container-BAgb9I06.d.ts} +1 -1
- package/dist/{container-BSW6jjlq.d.ts → container-CY_hS650.d.cts} +1 -1
- package/dist/{vfs-DzEcPbMY.d.cts → contracts-CVgctitO.d.cts} +196 -136
- package/dist/{vfs-DzEcPbMY.d.ts → contracts-CVgctitO.d.ts} +196 -136
- package/dist/index.cjs +573 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -6
- package/dist/index.d.ts +11 -6
- package/dist/index.js +573 -10
- package/dist/index.js.map +1 -1
- package/dist/{memory-volume-CTOXNJ6n.d.ts → memory-volume-CWuWScIs.d.ts} +1 -1
- package/dist/{memory-volume-DCzGZFJb.d.cts → memory-volume-DlMSAh-K.d.cts} +1 -1
- package/dist/python/python.data +278 -268
- package/dist/python/python.js +1 -1
- package/dist/python/python.wasm +0 -0
- package/dist/python/runtime.json +3 -3
- package/dist/python/wheels/index.json +42 -0
- package/dist/python/wheels/pydantic_core-2.23.2-cp313-cp313-emscripten_5_0_6_wasm32.whl +0 -0
- package/dist/python/wheels/pydantic_core-2.46.5-cp313-cp313-emscripten_5_0_6_wasm32.whl +0 -0
- package/dist/python/wheels/sbx_c_probe-1.0.0-cp313-cp313-emscripten_5_0_6_wasm32.whl +0 -0
- package/dist/python/wheels/sbx_rust_probe-1.0.0-cp313-cp313-emscripten_5_0_6_wasm32.whl +0 -0
- package/dist/python-abi.cjs +305 -2
- package/dist/python-abi.cjs.map +1 -1
- package/dist/python-abi.d.cts +267 -226
- package/dist/python-abi.d.ts +267 -226
- package/dist/python-abi.js +305 -2
- package/dist/python-abi.js.map +1 -1
- package/dist/python-worker.js +136 -5
- package/dist/python-worker.js.map +1 -1
- package/dist/worker-entry.js +5 -1
- package/dist/worker-entry.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -17804,7 +17804,20 @@ var Op = {
|
|
|
17804
17804
|
getcwd: 1281,
|
|
17805
17805
|
chdir: 1282,
|
|
17806
17806
|
environ: 1283,
|
|
17807
|
-
getrandom: 1536
|
|
17807
|
+
getrandom: 1536,
|
|
17808
|
+
socket: 1792,
|
|
17809
|
+
bind: 1793,
|
|
17810
|
+
listen: 1794,
|
|
17811
|
+
accept: 1795,
|
|
17812
|
+
connect: 1796,
|
|
17813
|
+
send: 1797,
|
|
17814
|
+
recv: 1798,
|
|
17815
|
+
shutdown: 1799,
|
|
17816
|
+
getsockname: 1800,
|
|
17817
|
+
getpeername: 1801,
|
|
17818
|
+
setsockopt: 1802,
|
|
17819
|
+
getsockopt: 1803,
|
|
17820
|
+
socket_close: 1804
|
|
17808
17821
|
};
|
|
17809
17822
|
var Errno = {
|
|
17810
17823
|
EPERM: 1,
|
|
@@ -17841,6 +17854,15 @@ var Errno = {
|
|
|
17841
17854
|
ENOTEMPTY: 39,
|
|
17842
17855
|
ELOOP: 40,
|
|
17843
17856
|
ENODATA: 61,
|
|
17857
|
+
ENOTSOCK: 88,
|
|
17858
|
+
EAFNOSUPPORT: 97,
|
|
17859
|
+
EADDRINUSE: 98,
|
|
17860
|
+
EADDRNOTAVAIL: 99,
|
|
17861
|
+
ENETUNREACH: 101,
|
|
17862
|
+
ECONNRESET: 104,
|
|
17863
|
+
EISCONN: 106,
|
|
17864
|
+
ENOTCONN: 107,
|
|
17865
|
+
ECONNREFUSED: 111,
|
|
17844
17866
|
EPROTO: 71,
|
|
17845
17867
|
EOVERFLOW: 75,
|
|
17846
17868
|
ETIMEDOUT: 110,
|
|
@@ -17913,7 +17935,15 @@ var bundledManifest = {
|
|
|
17913
17935
|
persistence: "memory"
|
|
17914
17936
|
}
|
|
17915
17937
|
};
|
|
17916
|
-
var
|
|
17938
|
+
var bundledWheelIndex = new URL(
|
|
17939
|
+
(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/wheels/" : "./python/wheels/",
|
|
17940
|
+
(typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))
|
|
17941
|
+
).href;
|
|
17942
|
+
var config = {
|
|
17943
|
+
backend: "sbx-cpython-wasm",
|
|
17944
|
+
manifest: bundledManifest,
|
|
17945
|
+
wheelIndex: bundledWheelIndex
|
|
17946
|
+
};
|
|
17917
17947
|
function setPythonBackend(options) {
|
|
17918
17948
|
if (options.wheelIndex !== void 0) config.wheelIndex = options.wheelIndex;
|
|
17919
17949
|
if (options.manifest !== void 0) config.manifest = validateManifest(options.manifest);
|
|
@@ -18706,6 +18736,362 @@ function failure(errno) {
|
|
|
18706
18736
|
return -Math.abs(errno);
|
|
18707
18737
|
}
|
|
18708
18738
|
|
|
18739
|
+
// src/net/virtual-socket.ts
|
|
18740
|
+
var ByteQueue = class {
|
|
18741
|
+
chunks = [];
|
|
18742
|
+
length = 0;
|
|
18743
|
+
waiters = /* @__PURE__ */ new Set();
|
|
18744
|
+
push(bytes2) {
|
|
18745
|
+
if (bytes2.length === 0) return;
|
|
18746
|
+
const copy = bytes2.slice();
|
|
18747
|
+
this.chunks.push(copy);
|
|
18748
|
+
this.length += copy.length;
|
|
18749
|
+
this.wake();
|
|
18750
|
+
}
|
|
18751
|
+
take(max) {
|
|
18752
|
+
if (max <= 0 || this.length === 0) return new Uint8Array();
|
|
18753
|
+
const out = new Uint8Array(Math.min(max, this.length));
|
|
18754
|
+
let at = 0;
|
|
18755
|
+
while (at < out.length) {
|
|
18756
|
+
const chunk = this.chunks[0];
|
|
18757
|
+
const count = Math.min(chunk.length, out.length - at);
|
|
18758
|
+
out.set(chunk.subarray(0, count), at);
|
|
18759
|
+
at += count;
|
|
18760
|
+
this.length -= count;
|
|
18761
|
+
if (count === chunk.length) this.chunks.shift();
|
|
18762
|
+
else this.chunks[0] = chunk.subarray(count);
|
|
18763
|
+
}
|
|
18764
|
+
return out;
|
|
18765
|
+
}
|
|
18766
|
+
get size() {
|
|
18767
|
+
return this.length;
|
|
18768
|
+
}
|
|
18769
|
+
whenChanged() {
|
|
18770
|
+
return new Promise((resolve3) => this.waiters.add(resolve3));
|
|
18771
|
+
}
|
|
18772
|
+
wake() {
|
|
18773
|
+
for (const resolve3 of this.waiters) resolve3();
|
|
18774
|
+
this.waiters.clear();
|
|
18775
|
+
}
|
|
18776
|
+
};
|
|
18777
|
+
var VirtualTcpConnection = class {
|
|
18778
|
+
incoming = new ByteQueue();
|
|
18779
|
+
peer = null;
|
|
18780
|
+
readClosed = false;
|
|
18781
|
+
writeClosed = false;
|
|
18782
|
+
closed = false;
|
|
18783
|
+
local;
|
|
18784
|
+
remote;
|
|
18785
|
+
constructor(local, remote) {
|
|
18786
|
+
this.local = local;
|
|
18787
|
+
this.remote = remote;
|
|
18788
|
+
}
|
|
18789
|
+
pairWith(peer) {
|
|
18790
|
+
this.peer = peer;
|
|
18791
|
+
}
|
|
18792
|
+
get eof() {
|
|
18793
|
+
return this.readClosed || this.incoming.size === 0 && this.peer?.writeClosed === true;
|
|
18794
|
+
}
|
|
18795
|
+
get readable() {
|
|
18796
|
+
return this.incoming.size > 0 || this.eof;
|
|
18797
|
+
}
|
|
18798
|
+
get writable() {
|
|
18799
|
+
return !this.writeClosed && !this.closed && this.peer !== null && !this.peer.readClosed;
|
|
18800
|
+
}
|
|
18801
|
+
read(maxLength) {
|
|
18802
|
+
if (this.incoming.size > 0) return this.incoming.take(maxLength);
|
|
18803
|
+
if (this.eof) return new Uint8Array();
|
|
18804
|
+
throw new PosixError(Errno.EAGAIN, "socket read would block");
|
|
18805
|
+
}
|
|
18806
|
+
write(bytes2) {
|
|
18807
|
+
if (!this.writable) throw new PosixError(this.closed || this.writeClosed ? Errno.EPIPE : Errno.ECONNRESET);
|
|
18808
|
+
this.peer.incoming.push(bytes2);
|
|
18809
|
+
return bytes2.length;
|
|
18810
|
+
}
|
|
18811
|
+
async waitForChange() {
|
|
18812
|
+
if (this.readable || this.closed) return;
|
|
18813
|
+
await this.incoming.whenChanged();
|
|
18814
|
+
}
|
|
18815
|
+
shutdown(read, write) {
|
|
18816
|
+
if (read) this.readClosed = true;
|
|
18817
|
+
if (write) {
|
|
18818
|
+
this.writeClosed = true;
|
|
18819
|
+
if (this.peer) this.peer.incoming.wake();
|
|
18820
|
+
}
|
|
18821
|
+
this.incoming.wake();
|
|
18822
|
+
this.peer?.incoming.wake();
|
|
18823
|
+
}
|
|
18824
|
+
close() {
|
|
18825
|
+
if (this.closed) return;
|
|
18826
|
+
this.closed = true;
|
|
18827
|
+
this.readClosed = true;
|
|
18828
|
+
this.writeClosed = true;
|
|
18829
|
+
if (this.peer) {
|
|
18830
|
+
this.peer.readClosed = true;
|
|
18831
|
+
this.peer.incoming.wake();
|
|
18832
|
+
}
|
|
18833
|
+
this.incoming.wake();
|
|
18834
|
+
}
|
|
18835
|
+
};
|
|
18836
|
+
var VirtualTcpListener = class {
|
|
18837
|
+
constructor(port, address = "0.0.0.0", backlog = 128) {
|
|
18838
|
+
this.port = port;
|
|
18839
|
+
this.address = address;
|
|
18840
|
+
this.backlog = backlog;
|
|
18841
|
+
}
|
|
18842
|
+
port;
|
|
18843
|
+
address;
|
|
18844
|
+
backlog;
|
|
18845
|
+
pending = [];
|
|
18846
|
+
waiters = /* @__PURE__ */ new Set();
|
|
18847
|
+
closed = false;
|
|
18848
|
+
enqueue(connection) {
|
|
18849
|
+
if (this.closed) {
|
|
18850
|
+
connection.close();
|
|
18851
|
+
throw new PosixError(Errno.ECONNREFUSED, "listener is closed");
|
|
18852
|
+
}
|
|
18853
|
+
if (this.pending.length >= this.backlog) {
|
|
18854
|
+
connection.close();
|
|
18855
|
+
throw new PosixError(Errno.EAGAIN, "listener backlog is full");
|
|
18856
|
+
}
|
|
18857
|
+
this.pending.push(connection);
|
|
18858
|
+
this.wake();
|
|
18859
|
+
}
|
|
18860
|
+
accept() {
|
|
18861
|
+
const connection = this.pending.shift();
|
|
18862
|
+
if (!connection) {
|
|
18863
|
+
if (this.closed) throw new PosixError(Errno.EBADF, "listener is closed");
|
|
18864
|
+
throw new PosixError(Errno.EAGAIN, "listener accept would block");
|
|
18865
|
+
}
|
|
18866
|
+
return { connection, peer: connection.remote };
|
|
18867
|
+
}
|
|
18868
|
+
get readable() {
|
|
18869
|
+
return this.pending.length > 0 || this.closed;
|
|
18870
|
+
}
|
|
18871
|
+
get isClosed() {
|
|
18872
|
+
return this.closed;
|
|
18873
|
+
}
|
|
18874
|
+
async waitForChange() {
|
|
18875
|
+
if (this.readable) return;
|
|
18876
|
+
await new Promise((resolve3) => this.waiters.add(resolve3));
|
|
18877
|
+
}
|
|
18878
|
+
close() {
|
|
18879
|
+
if (this.closed) return;
|
|
18880
|
+
this.closed = true;
|
|
18881
|
+
for (const connection of this.pending.splice(0)) connection.close();
|
|
18882
|
+
this.wake();
|
|
18883
|
+
}
|
|
18884
|
+
wake() {
|
|
18885
|
+
for (const resolve3 of this.waiters) resolve3();
|
|
18886
|
+
this.waiters.clear();
|
|
18887
|
+
}
|
|
18888
|
+
};
|
|
18889
|
+
var VirtualTcpSocket = class _VirtualTcpSocket {
|
|
18890
|
+
constructor(network) {
|
|
18891
|
+
this.network = network;
|
|
18892
|
+
}
|
|
18893
|
+
network;
|
|
18894
|
+
listenerValue = null;
|
|
18895
|
+
connectionValue = null;
|
|
18896
|
+
boundPort = 0;
|
|
18897
|
+
boundAddress = "0.0.0.0";
|
|
18898
|
+
bind(address, port) {
|
|
18899
|
+
if (this.listenerValue || this.connectionValue || this.boundPort !== 0) {
|
|
18900
|
+
throw new PosixError(Errno.EINVAL, "socket is already bound");
|
|
18901
|
+
}
|
|
18902
|
+
this.boundAddress = address;
|
|
18903
|
+
this.boundPort = port;
|
|
18904
|
+
}
|
|
18905
|
+
listen(backlog) {
|
|
18906
|
+
if (this.listenerValue) return;
|
|
18907
|
+
if (this.boundPort === 0) {
|
|
18908
|
+
const port = this.findEphemeralPort();
|
|
18909
|
+
this.boundPort = port;
|
|
18910
|
+
}
|
|
18911
|
+
this.listenerValue = this.network.listen(this.boundPort, this.boundAddress, backlog);
|
|
18912
|
+
}
|
|
18913
|
+
connect(port, address = "127.0.0.1") {
|
|
18914
|
+
if (this.listenerValue || this.connectionValue) throw new PosixError(Errno.EISCONN);
|
|
18915
|
+
this.connectionValue = this.network.connect(port, this.boundPort, this.boundAddress);
|
|
18916
|
+
this.boundPort = this.connectionValue.local.port;
|
|
18917
|
+
this.boundAddress = this.connectionValue.local.address;
|
|
18918
|
+
}
|
|
18919
|
+
accept() {
|
|
18920
|
+
if (!this.listenerValue) throw new PosixError(Errno.EINVAL, "socket is not listening");
|
|
18921
|
+
const accepted = this.listenerValue.accept().connection;
|
|
18922
|
+
const socket = new _VirtualTcpSocket(this.network);
|
|
18923
|
+
socket.connectionValue = accepted;
|
|
18924
|
+
socket.boundPort = accepted.local.port;
|
|
18925
|
+
socket.boundAddress = accepted.local.address;
|
|
18926
|
+
return socket;
|
|
18927
|
+
}
|
|
18928
|
+
get listener() {
|
|
18929
|
+
return this.listenerValue;
|
|
18930
|
+
}
|
|
18931
|
+
get connection() {
|
|
18932
|
+
return this.connectionValue;
|
|
18933
|
+
}
|
|
18934
|
+
get local() {
|
|
18935
|
+
return { address: this.boundAddress, port: this.boundPort };
|
|
18936
|
+
}
|
|
18937
|
+
get remote() {
|
|
18938
|
+
return this.connectionValue?.remote ?? null;
|
|
18939
|
+
}
|
|
18940
|
+
get readable() {
|
|
18941
|
+
return this.listenerValue?.readable ?? this.connectionValue?.readable ?? false;
|
|
18942
|
+
}
|
|
18943
|
+
get writable() {
|
|
18944
|
+
return this.connectionValue?.writable ?? false;
|
|
18945
|
+
}
|
|
18946
|
+
waitForChange() {
|
|
18947
|
+
return (this.listenerValue ?? this.connectionValue)?.waitForChange() ?? Promise.resolve();
|
|
18948
|
+
}
|
|
18949
|
+
read(length) {
|
|
18950
|
+
if (!this.connectionValue) throw new PosixError(Errno.EINVAL);
|
|
18951
|
+
return this.connectionValue.read(length);
|
|
18952
|
+
}
|
|
18953
|
+
write(data) {
|
|
18954
|
+
if (!this.connectionValue) throw new PosixError(Errno.EINVAL);
|
|
18955
|
+
return this.connectionValue.write(data);
|
|
18956
|
+
}
|
|
18957
|
+
shutdown(read, write) {
|
|
18958
|
+
if (!this.connectionValue) throw new PosixError(Errno.ENOTCONN);
|
|
18959
|
+
this.connectionValue.shutdown(read, write);
|
|
18960
|
+
}
|
|
18961
|
+
close() {
|
|
18962
|
+
if (this.listenerValue) this.network.close(this.listenerValue);
|
|
18963
|
+
this.connectionValue?.close();
|
|
18964
|
+
this.listenerValue = null;
|
|
18965
|
+
this.connectionValue = null;
|
|
18966
|
+
}
|
|
18967
|
+
findEphemeralPort() {
|
|
18968
|
+
for (let port = 49152; port <= 65535; port += 1) if (!this.network.hasListener(port)) return port;
|
|
18969
|
+
throw new PosixError(Errno.EADDRINUSE, "no ephemeral ports available");
|
|
18970
|
+
}
|
|
18971
|
+
};
|
|
18972
|
+
var SocketDescription = class _SocketDescription {
|
|
18973
|
+
kind = "socket";
|
|
18974
|
+
flags;
|
|
18975
|
+
resource;
|
|
18976
|
+
closed = false;
|
|
18977
|
+
options = /* @__PURE__ */ new Map();
|
|
18978
|
+
constructor(resource, flags = 0) {
|
|
18979
|
+
this.resource = resource;
|
|
18980
|
+
this.flags = flags;
|
|
18981
|
+
}
|
|
18982
|
+
get listener() {
|
|
18983
|
+
return this.resource.listener;
|
|
18984
|
+
}
|
|
18985
|
+
get connection() {
|
|
18986
|
+
return this.resource.connection;
|
|
18987
|
+
}
|
|
18988
|
+
read(length) {
|
|
18989
|
+
return this.resource.read(length);
|
|
18990
|
+
}
|
|
18991
|
+
write(data) {
|
|
18992
|
+
return this.resource.write(data);
|
|
18993
|
+
}
|
|
18994
|
+
readable() {
|
|
18995
|
+
return this.resource.readable;
|
|
18996
|
+
}
|
|
18997
|
+
writable() {
|
|
18998
|
+
return this.resource.writable;
|
|
18999
|
+
}
|
|
19000
|
+
whenReady() {
|
|
19001
|
+
return this.resource.waitForChange();
|
|
19002
|
+
}
|
|
19003
|
+
stat() {
|
|
19004
|
+
return {
|
|
19005
|
+
ino: 0,
|
|
19006
|
+
mode: 49663,
|
|
19007
|
+
size: 0,
|
|
19008
|
+
uid: 0,
|
|
19009
|
+
gid: 0,
|
|
19010
|
+
nlink: 1,
|
|
19011
|
+
atimeMs: Date.now(),
|
|
19012
|
+
mtimeMs: Date.now(),
|
|
19013
|
+
ctimeMs: Date.now()
|
|
19014
|
+
};
|
|
19015
|
+
}
|
|
19016
|
+
close() {
|
|
19017
|
+
if (this.closed) return;
|
|
19018
|
+
this.closed = true;
|
|
19019
|
+
this.resource.close();
|
|
19020
|
+
}
|
|
19021
|
+
bind(address, port) {
|
|
19022
|
+
this.resource.bind(address, port);
|
|
19023
|
+
}
|
|
19024
|
+
listen(backlog) {
|
|
19025
|
+
this.resource.listen(backlog);
|
|
19026
|
+
}
|
|
19027
|
+
connect(address, port) {
|
|
19028
|
+
this.resource.connect(port, address);
|
|
19029
|
+
}
|
|
19030
|
+
accept() {
|
|
19031
|
+
return new _SocketDescription(this.resource.accept(), this.flags);
|
|
19032
|
+
}
|
|
19033
|
+
shutdown(read, write) {
|
|
19034
|
+
this.resource.shutdown(read, write);
|
|
19035
|
+
}
|
|
19036
|
+
setOption(level, option, value) {
|
|
19037
|
+
this.options.set(`${level}:${option}`, value.slice());
|
|
19038
|
+
}
|
|
19039
|
+
getOption(level, option) {
|
|
19040
|
+
return this.options.get(`${level}:${option}`)?.slice() ?? new Uint8Array(4);
|
|
19041
|
+
}
|
|
19042
|
+
localAddress() {
|
|
19043
|
+
return this.resource.local;
|
|
19044
|
+
}
|
|
19045
|
+
peerAddress() {
|
|
19046
|
+
const peer = this.resource.remote;
|
|
19047
|
+
if (!peer) throw new PosixError(Errno.ENOTCONN);
|
|
19048
|
+
return peer;
|
|
19049
|
+
}
|
|
19050
|
+
};
|
|
19051
|
+
var VirtualTcpNetwork = class {
|
|
19052
|
+
constructor(occupied) {
|
|
19053
|
+
this.occupied = occupied;
|
|
19054
|
+
}
|
|
19055
|
+
occupied;
|
|
19056
|
+
listeners = /* @__PURE__ */ new Map();
|
|
19057
|
+
listen(port, address = "0.0.0.0", backlog = 128) {
|
|
19058
|
+
if (this.listeners.has(port) || this.occupied?.(port)) throw new PosixError(Errno.EADDRINUSE, `port ${port} is already in use`);
|
|
19059
|
+
const listener = new VirtualTcpListener(port, address, backlog);
|
|
19060
|
+
this.listeners.set(port, listener);
|
|
19061
|
+
return listener;
|
|
19062
|
+
}
|
|
19063
|
+
close(listener) {
|
|
19064
|
+
if (this.listeners.get(listener.port) !== listener) return;
|
|
19065
|
+
this.listeners.delete(listener.port);
|
|
19066
|
+
listener.close();
|
|
19067
|
+
}
|
|
19068
|
+
connect(port, localPort = 0, localAddress = "127.0.0.1") {
|
|
19069
|
+
const listener = this.listeners.get(port);
|
|
19070
|
+
if (!listener || listener.isClosed) throw new PosixError(Errno.ECONNREFUSED, `port ${port} is not listening`);
|
|
19071
|
+
const client = new VirtualTcpConnection(
|
|
19072
|
+
{ address: localAddress, port: localPort },
|
|
19073
|
+
{ address: listener.address, port }
|
|
19074
|
+
);
|
|
19075
|
+
const server = new VirtualTcpConnection(
|
|
19076
|
+
{ address: listener.address, port },
|
|
19077
|
+
{ address: localAddress, port: localPort }
|
|
19078
|
+
);
|
|
19079
|
+
client.pairWith(server);
|
|
19080
|
+
server.pairWith(client);
|
|
19081
|
+
listener.enqueue(server);
|
|
19082
|
+
return client;
|
|
19083
|
+
}
|
|
19084
|
+
hasListener(port) {
|
|
19085
|
+
return this.listeners.has(port);
|
|
19086
|
+
}
|
|
19087
|
+
ports() {
|
|
19088
|
+
return [...this.listeners.keys()].sort((a, b) => a - b);
|
|
19089
|
+
}
|
|
19090
|
+
closeAll() {
|
|
19091
|
+
for (const listener of [...this.listeners.values()]) this.close(listener);
|
|
19092
|
+
}
|
|
19093
|
+
};
|
|
19094
|
+
|
|
18709
19095
|
// src/runtime/python/syscall-server.ts
|
|
18710
19096
|
var MAX_TRANSFER = 8 * 1024 * 1024;
|
|
18711
19097
|
function createHostAbiServer(proc) {
|
|
@@ -18952,12 +19338,76 @@ function createHostAbiServer(proc) {
|
|
|
18952
19338
|
crypto.getRandomValues(bytes2);
|
|
18953
19339
|
return { status: length, payload: bytes2 };
|
|
18954
19340
|
}
|
|
19341
|
+
/* ----------------------------------------------------------- sockets */
|
|
19342
|
+
case Op.socket: {
|
|
19343
|
+
const family = r.u32();
|
|
19344
|
+
const type = r.u32();
|
|
19345
|
+
const protocol = r.i32();
|
|
19346
|
+
if (family !== 2 || (type & 15) !== 1 || protocol !== 0) throw new PosixError(Errno.EAFNOSUPPORT);
|
|
19347
|
+
if (!proc.sockets) throw new PosixError(Errno.ENOSYS);
|
|
19348
|
+
return { status: proc.table.add(new SocketDescription(new VirtualTcpSocket(proc.sockets))) };
|
|
19349
|
+
}
|
|
19350
|
+
case Op.bind: {
|
|
19351
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19352
|
+
description.bind(r.string(), r.u32());
|
|
19353
|
+
return { status: 0 };
|
|
19354
|
+
}
|
|
19355
|
+
case Op.listen: {
|
|
19356
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19357
|
+
description.listen(Math.max(1, Math.min(1024, r.u32())));
|
|
19358
|
+
return { status: 0 };
|
|
19359
|
+
}
|
|
19360
|
+
case Op.accept: {
|
|
19361
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19362
|
+
const accepted = await acceptBlocking(description);
|
|
19363
|
+
const fd = proc.table.add(accepted);
|
|
19364
|
+
const peer = accepted.peerAddress();
|
|
19365
|
+
return { status: fd, payload: new Writer().string(peer.address).u32(peer.port).finish() };
|
|
19366
|
+
}
|
|
19367
|
+
case Op.connect: {
|
|
19368
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19369
|
+
description.connect(r.string(), r.u32());
|
|
19370
|
+
return { status: 0 };
|
|
19371
|
+
}
|
|
19372
|
+
case Op.send: {
|
|
19373
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19374
|
+
return { status: await writeBlocking(description, r.bytes32()) };
|
|
19375
|
+
}
|
|
19376
|
+
case Op.recv: {
|
|
19377
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19378
|
+
const data = await readBlocking(description, clamp(r.u32()));
|
|
19379
|
+
return { status: data.length, payload: data };
|
|
19380
|
+
}
|
|
19381
|
+
case Op.shutdown: {
|
|
19382
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19383
|
+
const how = r.u32();
|
|
19384
|
+
if (how > 2) throw new PosixError(Errno.EINVAL);
|
|
19385
|
+
description.shutdown(how === 0 || how === 2, how === 1 || how === 2);
|
|
19386
|
+
return { status: 0 };
|
|
19387
|
+
}
|
|
19388
|
+
case Op.getsockname: {
|
|
19389
|
+
const address = socketDescription(proc.table.get(r.i32())).localAddress();
|
|
19390
|
+
return { status: 0, payload: new Writer().string(address.address).u32(address.port).finish() };
|
|
19391
|
+
}
|
|
19392
|
+
case Op.getpeername: {
|
|
19393
|
+
const address = socketDescription(proc.table.get(r.i32())).peerAddress();
|
|
19394
|
+
return { status: 0, payload: new Writer().string(address.address).u32(address.port).finish() };
|
|
19395
|
+
}
|
|
19396
|
+
case Op.setsockopt: {
|
|
19397
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19398
|
+
description.setOption(r.u32(), r.u32(), r.bytes32());
|
|
19399
|
+
return { status: 0 };
|
|
19400
|
+
}
|
|
19401
|
+
case Op.getsockopt: {
|
|
19402
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19403
|
+
return { status: 0, payload: new Writer().bytes32(description.getOption(r.u32(), r.u32())).finish() };
|
|
19404
|
+
}
|
|
18955
19405
|
default:
|
|
18956
19406
|
return { status: failure(Errno.ENOSYS) };
|
|
18957
19407
|
}
|
|
18958
19408
|
}
|
|
18959
19409
|
function implemented(capability) {
|
|
18960
|
-
return ["files", "descriptors", "pipes", "readiness", "time", "identity", "entropy"].includes(capability);
|
|
19410
|
+
return ["files", "descriptors", "pipes", "readiness", "time", "identity", "entropy"].includes(capability) || capability === "sockets" && proc.sockets !== void 0;
|
|
18961
19411
|
}
|
|
18962
19412
|
function resolve3(path) {
|
|
18963
19413
|
if (path.startsWith("/")) return proc.vfs.resolvePath(path);
|
|
@@ -18966,6 +19416,22 @@ function createHostAbiServer(proc) {
|
|
|
18966
19416
|
function clamp(length) {
|
|
18967
19417
|
return Math.min(length, MAX_TRANSFER);
|
|
18968
19418
|
}
|
|
19419
|
+
function socketDescription(description) {
|
|
19420
|
+
if (!(description instanceof SocketDescription)) throw new PosixError(Errno.ENOTSOCK, "descriptor is not a socket");
|
|
19421
|
+
return description;
|
|
19422
|
+
}
|
|
19423
|
+
async function acceptBlocking(description) {
|
|
19424
|
+
for (; ; ) {
|
|
19425
|
+
try {
|
|
19426
|
+
return description.accept();
|
|
19427
|
+
} catch (error) {
|
|
19428
|
+
const posix = toPosixError(error);
|
|
19429
|
+
if (posix.errno !== Errno.EAGAIN || description.flags & O_NONBLOCK) throw posix;
|
|
19430
|
+
}
|
|
19431
|
+
await Promise.race([description.whenReady(), aborted()]);
|
|
19432
|
+
if (proc.signal.aborted) throw new PosixError(Errno.EINTR);
|
|
19433
|
+
}
|
|
19434
|
+
}
|
|
18969
19435
|
async function readBlocking(description, length) {
|
|
18970
19436
|
for (; ; ) {
|
|
18971
19437
|
try {
|
|
@@ -19232,7 +19698,8 @@ async function startPythonProcess(options) {
|
|
|
19232
19698
|
table,
|
|
19233
19699
|
env: options.env,
|
|
19234
19700
|
cwd: options.cwd,
|
|
19235
|
-
signal: controller.signal
|
|
19701
|
+
signal: controller.signal,
|
|
19702
|
+
sockets: options.sockets
|
|
19236
19703
|
});
|
|
19237
19704
|
const buffers = createHostTransportBuffers();
|
|
19238
19705
|
let fault = null;
|
|
@@ -19839,7 +20306,8 @@ async function runOwnedPython(ctx, argv) {
|
|
|
19839
20306
|
mounts,
|
|
19840
20307
|
onStdout: (data) => ctx.stdout.write(data),
|
|
19841
20308
|
onStderr: (data) => ctx.stderr.write(data),
|
|
19842
|
-
signal: ctx.signal
|
|
20309
|
+
signal: ctx.signal,
|
|
20310
|
+
sockets: ctx.kernel.pod.sockets
|
|
19843
20311
|
});
|
|
19844
20312
|
void pumpStdin(ctx, process2);
|
|
19845
20313
|
return process2.wait();
|
|
@@ -19944,6 +20412,17 @@ environments. A package with no usable wheel is an error, never a silent skip.`,
|
|
|
19944
20412
|
}
|
|
19945
20413
|
const cache = /* @__PURE__ */ new Map();
|
|
19946
20414
|
const request = async (url, timeoutMs, read) => {
|
|
20415
|
+
if (url.startsWith("file:")) {
|
|
20416
|
+
try {
|
|
20417
|
+
const [{ readFile }, { fileURLToPath: fileURLToPath2 }] = await Promise.all([
|
|
20418
|
+
nodeBuiltin("fs/promises"),
|
|
20419
|
+
nodeBuiltin("url")
|
|
20420
|
+
]);
|
|
20421
|
+
return await read(new Response(await readFile(fileURLToPath2(url))));
|
|
20422
|
+
} catch (error) {
|
|
20423
|
+
throw new Error(`could not read bundled wheel asset ${url}: ${error.message}`);
|
|
20424
|
+
}
|
|
20425
|
+
}
|
|
19947
20426
|
const controller = new AbortController();
|
|
19948
20427
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
19949
20428
|
try {
|
|
@@ -26145,12 +26624,16 @@ var VirtualHttpServer = class extends EventEmitter4__default.default {
|
|
|
26145
26624
|
}
|
|
26146
26625
|
};
|
|
26147
26626
|
var VirtualHttpRouter = class {
|
|
26627
|
+
constructor(sockets) {
|
|
26628
|
+
this.sockets = sockets;
|
|
26629
|
+
}
|
|
26630
|
+
sockets;
|
|
26148
26631
|
servers = /* @__PURE__ */ new Map();
|
|
26149
26632
|
/** Notified when a server begins listening, for `onServerReady`. */
|
|
26150
26633
|
onListen;
|
|
26151
26634
|
onClose;
|
|
26152
26635
|
register(port, server, owner) {
|
|
26153
|
-
if (this.servers.has(port)) throw Object.assign(new Error(`listen EADDRINUSE: address already in use 0.0.0.0:${port}`), { code: "EADDRINUSE", port });
|
|
26636
|
+
if (this.servers.has(port) || this.sockets?.hasListener(port)) throw Object.assign(new Error(`listen EADDRINUSE: address already in use 0.0.0.0:${port}`), { code: "EADDRINUSE", port });
|
|
26154
26637
|
this.servers.set(port, { server, owner });
|
|
26155
26638
|
this.onListen?.(port);
|
|
26156
26639
|
}
|
|
@@ -29734,8 +30217,9 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
29734
30217
|
volume = new MirroringVolume(new MemoryVolume());
|
|
29735
30218
|
packages;
|
|
29736
30219
|
instanceId = `sbx-${Math.random().toString(36).slice(2)}`;
|
|
29737
|
-
router
|
|
29738
|
-
|
|
30220
|
+
router;
|
|
30221
|
+
sockets;
|
|
30222
|
+
proxy = { activePorts: (_instanceId) => [.../* @__PURE__ */ new Set([...this.router.activePorts(), ...this.sockets.ports()])].sort((a, b) => a - b) };
|
|
29739
30223
|
/**
|
|
29740
30224
|
* Bind a port to a server that is not a JavaScript one.
|
|
29741
30225
|
*
|
|
@@ -29802,6 +30286,8 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
29802
30286
|
fetch;
|
|
29803
30287
|
constructor(options) {
|
|
29804
30288
|
ensureProcessGlobal();
|
|
30289
|
+
this.sockets = new VirtualTcpNetwork((port) => this.router.activePortsIncludes(port));
|
|
30290
|
+
this.router = new VirtualHttpRouter(this.sockets);
|
|
29805
30291
|
this.workdir = options.workdir ?? "/";
|
|
29806
30292
|
this.env = { ...options.env };
|
|
29807
30293
|
this.aliases = { ...WASM_ALIASES, ...options.aliases };
|
|
@@ -29935,8 +30421,10 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
29935
30421
|
await new Promise((resolve3) => setTimeout(resolve3, busy ? 5 : 0));
|
|
29936
30422
|
}
|
|
29937
30423
|
}
|
|
29938
|
-
async request(
|
|
29939
|
-
return this.router.request(
|
|
30424
|
+
async request(port, init = {}) {
|
|
30425
|
+
if (this.router.activePortsIncludes(port)) return this.router.request(port, init);
|
|
30426
|
+
if (!this.sockets.hasListener(port)) return this.router.request(port, init);
|
|
30427
|
+
return this.requestTcp(port, init);
|
|
29940
30428
|
}
|
|
29941
30429
|
connect(port, init, peer) {
|
|
29942
30430
|
return this.router.connect(port, init, peer);
|
|
@@ -29955,8 +30443,46 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
29955
30443
|
for (const process2 of this.running) process2.kill();
|
|
29956
30444
|
this.running.clear();
|
|
29957
30445
|
this.router.closeAll();
|
|
30446
|
+
this.sockets.closeAll();
|
|
29958
30447
|
this.esbuild?.stop();
|
|
29959
30448
|
}
|
|
30449
|
+
/** HTTP/1.1 client path for a server implemented outside the JS runtime. */
|
|
30450
|
+
async requestTcp(port, init) {
|
|
30451
|
+
const connection = this.sockets.connect(port);
|
|
30452
|
+
const method = String(init.method ?? "GET").toUpperCase();
|
|
30453
|
+
const path = String(init.path ?? "/");
|
|
30454
|
+
const body = init.body == null ? new Uint8Array() : typeof init.body === "string" ? new TextEncoder().encode(init.body) : init.body instanceof ArrayBuffer ? new Uint8Array(init.body) : init.body;
|
|
30455
|
+
const headers = Object.entries(init.headers ?? {}).map(([name, value]) => `${name}: ${String(value)}`);
|
|
30456
|
+
if (!headers.some((line) => line.toLowerCase().startsWith("host:"))) headers.push("Host: localhost");
|
|
30457
|
+
if (!headers.some((line) => line.toLowerCase().startsWith("connection:"))) headers.push("Connection: close");
|
|
30458
|
+
if (body.length && !headers.some((line) => line.toLowerCase().startsWith("content-length:"))) headers.push(`Content-Length: ${body.length}`);
|
|
30459
|
+
const request = new TextEncoder().encode(`${method} ${path} HTTP/1.1\r
|
|
30460
|
+
${headers.join("\r\n")}\r
|
|
30461
|
+
\r
|
|
30462
|
+
`);
|
|
30463
|
+
connection.write(request);
|
|
30464
|
+
if (body.length) connection.write(body);
|
|
30465
|
+
const bytes2 = [];
|
|
30466
|
+
let combined = new Uint8Array();
|
|
30467
|
+
for (; ; ) {
|
|
30468
|
+
try {
|
|
30469
|
+
const chunk = connection.read(64 * 1024);
|
|
30470
|
+
if (chunk.length === 0) break;
|
|
30471
|
+
bytes2.push(chunk);
|
|
30472
|
+
combined = joinBytes(bytes2);
|
|
30473
|
+
const headerEnd = findBytes(combined, new Uint8Array([13, 10, 13, 10]));
|
|
30474
|
+
if (headerEnd < 0) continue;
|
|
30475
|
+
const headerText = new TextDecoder().decode(combined.subarray(0, headerEnd));
|
|
30476
|
+
const contentLength = /^content-length:\s*(\d+)\s*$/im.exec(headerText)?.[1];
|
|
30477
|
+
if (contentLength !== void 0 && combined.length >= headerEnd + 4 + Number(contentLength)) break;
|
|
30478
|
+
} catch (error) {
|
|
30479
|
+
if (!(error instanceof PosixError) || error.errno !== Errno.EAGAIN) throw error;
|
|
30480
|
+
await connection.waitForChange();
|
|
30481
|
+
}
|
|
30482
|
+
}
|
|
30483
|
+
connection.close();
|
|
30484
|
+
return parseHttpResponse(combined);
|
|
30485
|
+
}
|
|
29960
30486
|
seed(files) {
|
|
29961
30487
|
for (const [path, data] of Object.entries(files)) {
|
|
29962
30488
|
const parts = path.split("/").filter(Boolean);
|
|
@@ -29988,6 +30514,43 @@ function formatError(error) {
|
|
|
29988
30514
|
function isRecord(value) {
|
|
29989
30515
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
29990
30516
|
}
|
|
30517
|
+
function joinBytes(parts) {
|
|
30518
|
+
const total = parts.reduce((sum, part) => sum + part.length, 0);
|
|
30519
|
+
const out = new Uint8Array(total);
|
|
30520
|
+
let at = 0;
|
|
30521
|
+
for (const part of parts) {
|
|
30522
|
+
out.set(part, at);
|
|
30523
|
+
at += part.length;
|
|
30524
|
+
}
|
|
30525
|
+
return out;
|
|
30526
|
+
}
|
|
30527
|
+
function findBytes(haystack, needle) {
|
|
30528
|
+
outer: for (let at = 0; at <= haystack.length - needle.length; at += 1) {
|
|
30529
|
+
for (let i = 0; i < needle.length; i += 1) if (haystack[at + i] !== needle[i]) continue outer;
|
|
30530
|
+
return at;
|
|
30531
|
+
}
|
|
30532
|
+
return -1;
|
|
30533
|
+
}
|
|
30534
|
+
function parseHttpResponse(bytes2) {
|
|
30535
|
+
const marker = new Uint8Array([13, 10, 13, 10]);
|
|
30536
|
+
const headerEnd = findBytes(bytes2, marker);
|
|
30537
|
+
if (headerEnd < 0) throw new Error("Python server returned an incomplete HTTP response");
|
|
30538
|
+
const text2 = new TextDecoder().decode(bytes2.subarray(0, headerEnd));
|
|
30539
|
+
const lines = text2.split("\r\n");
|
|
30540
|
+
const status = /HTTP\/\d\.\d\s+(\d+)(?:\s+(.*))?/.exec(lines.shift() ?? "");
|
|
30541
|
+
if (!status) throw new Error("Python server returned an invalid HTTP status line");
|
|
30542
|
+
const headers = {};
|
|
30543
|
+
for (const line of lines) {
|
|
30544
|
+
const separator = line.indexOf(":");
|
|
30545
|
+
if (separator > 0) headers[line.slice(0, separator).toLowerCase()] = line.slice(separator + 1).trim();
|
|
30546
|
+
}
|
|
30547
|
+
return {
|
|
30548
|
+
statusCode: Number(status[1]),
|
|
30549
|
+
statusMessage: status[2] ?? "",
|
|
30550
|
+
headers,
|
|
30551
|
+
body: bytes2.slice(headerEnd + marker.length)
|
|
30552
|
+
};
|
|
30553
|
+
}
|
|
29991
30554
|
function packageIsInstalled(volume, cwd, wanted) {
|
|
29992
30555
|
for (let dir3 = clean(cwd); ; dir3 = dirname(dir3)) {
|
|
29993
30556
|
if (packageTreeContains(volume, join(dir3, "node_modules"), wanted, /* @__PURE__ */ new Set())) return true;
|