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.js
CHANGED
|
@@ -17787,7 +17787,20 @@ var Op = {
|
|
|
17787
17787
|
getcwd: 1281,
|
|
17788
17788
|
chdir: 1282,
|
|
17789
17789
|
environ: 1283,
|
|
17790
|
-
getrandom: 1536
|
|
17790
|
+
getrandom: 1536,
|
|
17791
|
+
socket: 1792,
|
|
17792
|
+
bind: 1793,
|
|
17793
|
+
listen: 1794,
|
|
17794
|
+
accept: 1795,
|
|
17795
|
+
connect: 1796,
|
|
17796
|
+
send: 1797,
|
|
17797
|
+
recv: 1798,
|
|
17798
|
+
shutdown: 1799,
|
|
17799
|
+
getsockname: 1800,
|
|
17800
|
+
getpeername: 1801,
|
|
17801
|
+
setsockopt: 1802,
|
|
17802
|
+
getsockopt: 1803,
|
|
17803
|
+
socket_close: 1804
|
|
17791
17804
|
};
|
|
17792
17805
|
var Errno = {
|
|
17793
17806
|
EPERM: 1,
|
|
@@ -17824,6 +17837,15 @@ var Errno = {
|
|
|
17824
17837
|
ENOTEMPTY: 39,
|
|
17825
17838
|
ELOOP: 40,
|
|
17826
17839
|
ENODATA: 61,
|
|
17840
|
+
ENOTSOCK: 88,
|
|
17841
|
+
EAFNOSUPPORT: 97,
|
|
17842
|
+
EADDRINUSE: 98,
|
|
17843
|
+
EADDRNOTAVAIL: 99,
|
|
17844
|
+
ENETUNREACH: 101,
|
|
17845
|
+
ECONNRESET: 104,
|
|
17846
|
+
EISCONN: 106,
|
|
17847
|
+
ENOTCONN: 107,
|
|
17848
|
+
ECONNREFUSED: 111,
|
|
17827
17849
|
EPROTO: 71,
|
|
17828
17850
|
EOVERFLOW: 75,
|
|
17829
17851
|
ETIMEDOUT: 110,
|
|
@@ -17896,7 +17918,15 @@ var bundledManifest = {
|
|
|
17896
17918
|
persistence: "memory"
|
|
17897
17919
|
}
|
|
17898
17920
|
};
|
|
17899
|
-
var
|
|
17921
|
+
var bundledWheelIndex = new URL(
|
|
17922
|
+
import.meta.url.includes("/src/runtime/python/") ? "../../../dist/python/wheels/" : "./python/wheels/",
|
|
17923
|
+
import.meta.url
|
|
17924
|
+
).href;
|
|
17925
|
+
var config = {
|
|
17926
|
+
backend: "sbx-cpython-wasm",
|
|
17927
|
+
manifest: bundledManifest,
|
|
17928
|
+
wheelIndex: bundledWheelIndex
|
|
17929
|
+
};
|
|
17900
17930
|
function setPythonBackend(options) {
|
|
17901
17931
|
if (options.wheelIndex !== void 0) config.wheelIndex = options.wheelIndex;
|
|
17902
17932
|
if (options.manifest !== void 0) config.manifest = validateManifest(options.manifest);
|
|
@@ -18689,6 +18719,362 @@ function failure(errno) {
|
|
|
18689
18719
|
return -Math.abs(errno);
|
|
18690
18720
|
}
|
|
18691
18721
|
|
|
18722
|
+
// src/net/virtual-socket.ts
|
|
18723
|
+
var ByteQueue = class {
|
|
18724
|
+
chunks = [];
|
|
18725
|
+
length = 0;
|
|
18726
|
+
waiters = /* @__PURE__ */ new Set();
|
|
18727
|
+
push(bytes2) {
|
|
18728
|
+
if (bytes2.length === 0) return;
|
|
18729
|
+
const copy = bytes2.slice();
|
|
18730
|
+
this.chunks.push(copy);
|
|
18731
|
+
this.length += copy.length;
|
|
18732
|
+
this.wake();
|
|
18733
|
+
}
|
|
18734
|
+
take(max) {
|
|
18735
|
+
if (max <= 0 || this.length === 0) return new Uint8Array();
|
|
18736
|
+
const out = new Uint8Array(Math.min(max, this.length));
|
|
18737
|
+
let at = 0;
|
|
18738
|
+
while (at < out.length) {
|
|
18739
|
+
const chunk = this.chunks[0];
|
|
18740
|
+
const count = Math.min(chunk.length, out.length - at);
|
|
18741
|
+
out.set(chunk.subarray(0, count), at);
|
|
18742
|
+
at += count;
|
|
18743
|
+
this.length -= count;
|
|
18744
|
+
if (count === chunk.length) this.chunks.shift();
|
|
18745
|
+
else this.chunks[0] = chunk.subarray(count);
|
|
18746
|
+
}
|
|
18747
|
+
return out;
|
|
18748
|
+
}
|
|
18749
|
+
get size() {
|
|
18750
|
+
return this.length;
|
|
18751
|
+
}
|
|
18752
|
+
whenChanged() {
|
|
18753
|
+
return new Promise((resolve3) => this.waiters.add(resolve3));
|
|
18754
|
+
}
|
|
18755
|
+
wake() {
|
|
18756
|
+
for (const resolve3 of this.waiters) resolve3();
|
|
18757
|
+
this.waiters.clear();
|
|
18758
|
+
}
|
|
18759
|
+
};
|
|
18760
|
+
var VirtualTcpConnection = class {
|
|
18761
|
+
incoming = new ByteQueue();
|
|
18762
|
+
peer = null;
|
|
18763
|
+
readClosed = false;
|
|
18764
|
+
writeClosed = false;
|
|
18765
|
+
closed = false;
|
|
18766
|
+
local;
|
|
18767
|
+
remote;
|
|
18768
|
+
constructor(local, remote) {
|
|
18769
|
+
this.local = local;
|
|
18770
|
+
this.remote = remote;
|
|
18771
|
+
}
|
|
18772
|
+
pairWith(peer) {
|
|
18773
|
+
this.peer = peer;
|
|
18774
|
+
}
|
|
18775
|
+
get eof() {
|
|
18776
|
+
return this.readClosed || this.incoming.size === 0 && this.peer?.writeClosed === true;
|
|
18777
|
+
}
|
|
18778
|
+
get readable() {
|
|
18779
|
+
return this.incoming.size > 0 || this.eof;
|
|
18780
|
+
}
|
|
18781
|
+
get writable() {
|
|
18782
|
+
return !this.writeClosed && !this.closed && this.peer !== null && !this.peer.readClosed;
|
|
18783
|
+
}
|
|
18784
|
+
read(maxLength) {
|
|
18785
|
+
if (this.incoming.size > 0) return this.incoming.take(maxLength);
|
|
18786
|
+
if (this.eof) return new Uint8Array();
|
|
18787
|
+
throw new PosixError(Errno.EAGAIN, "socket read would block");
|
|
18788
|
+
}
|
|
18789
|
+
write(bytes2) {
|
|
18790
|
+
if (!this.writable) throw new PosixError(this.closed || this.writeClosed ? Errno.EPIPE : Errno.ECONNRESET);
|
|
18791
|
+
this.peer.incoming.push(bytes2);
|
|
18792
|
+
return bytes2.length;
|
|
18793
|
+
}
|
|
18794
|
+
async waitForChange() {
|
|
18795
|
+
if (this.readable || this.closed) return;
|
|
18796
|
+
await this.incoming.whenChanged();
|
|
18797
|
+
}
|
|
18798
|
+
shutdown(read, write) {
|
|
18799
|
+
if (read) this.readClosed = true;
|
|
18800
|
+
if (write) {
|
|
18801
|
+
this.writeClosed = true;
|
|
18802
|
+
if (this.peer) this.peer.incoming.wake();
|
|
18803
|
+
}
|
|
18804
|
+
this.incoming.wake();
|
|
18805
|
+
this.peer?.incoming.wake();
|
|
18806
|
+
}
|
|
18807
|
+
close() {
|
|
18808
|
+
if (this.closed) return;
|
|
18809
|
+
this.closed = true;
|
|
18810
|
+
this.readClosed = true;
|
|
18811
|
+
this.writeClosed = true;
|
|
18812
|
+
if (this.peer) {
|
|
18813
|
+
this.peer.readClosed = true;
|
|
18814
|
+
this.peer.incoming.wake();
|
|
18815
|
+
}
|
|
18816
|
+
this.incoming.wake();
|
|
18817
|
+
}
|
|
18818
|
+
};
|
|
18819
|
+
var VirtualTcpListener = class {
|
|
18820
|
+
constructor(port, address = "0.0.0.0", backlog = 128) {
|
|
18821
|
+
this.port = port;
|
|
18822
|
+
this.address = address;
|
|
18823
|
+
this.backlog = backlog;
|
|
18824
|
+
}
|
|
18825
|
+
port;
|
|
18826
|
+
address;
|
|
18827
|
+
backlog;
|
|
18828
|
+
pending = [];
|
|
18829
|
+
waiters = /* @__PURE__ */ new Set();
|
|
18830
|
+
closed = false;
|
|
18831
|
+
enqueue(connection) {
|
|
18832
|
+
if (this.closed) {
|
|
18833
|
+
connection.close();
|
|
18834
|
+
throw new PosixError(Errno.ECONNREFUSED, "listener is closed");
|
|
18835
|
+
}
|
|
18836
|
+
if (this.pending.length >= this.backlog) {
|
|
18837
|
+
connection.close();
|
|
18838
|
+
throw new PosixError(Errno.EAGAIN, "listener backlog is full");
|
|
18839
|
+
}
|
|
18840
|
+
this.pending.push(connection);
|
|
18841
|
+
this.wake();
|
|
18842
|
+
}
|
|
18843
|
+
accept() {
|
|
18844
|
+
const connection = this.pending.shift();
|
|
18845
|
+
if (!connection) {
|
|
18846
|
+
if (this.closed) throw new PosixError(Errno.EBADF, "listener is closed");
|
|
18847
|
+
throw new PosixError(Errno.EAGAIN, "listener accept would block");
|
|
18848
|
+
}
|
|
18849
|
+
return { connection, peer: connection.remote };
|
|
18850
|
+
}
|
|
18851
|
+
get readable() {
|
|
18852
|
+
return this.pending.length > 0 || this.closed;
|
|
18853
|
+
}
|
|
18854
|
+
get isClosed() {
|
|
18855
|
+
return this.closed;
|
|
18856
|
+
}
|
|
18857
|
+
async waitForChange() {
|
|
18858
|
+
if (this.readable) return;
|
|
18859
|
+
await new Promise((resolve3) => this.waiters.add(resolve3));
|
|
18860
|
+
}
|
|
18861
|
+
close() {
|
|
18862
|
+
if (this.closed) return;
|
|
18863
|
+
this.closed = true;
|
|
18864
|
+
for (const connection of this.pending.splice(0)) connection.close();
|
|
18865
|
+
this.wake();
|
|
18866
|
+
}
|
|
18867
|
+
wake() {
|
|
18868
|
+
for (const resolve3 of this.waiters) resolve3();
|
|
18869
|
+
this.waiters.clear();
|
|
18870
|
+
}
|
|
18871
|
+
};
|
|
18872
|
+
var VirtualTcpSocket = class _VirtualTcpSocket {
|
|
18873
|
+
constructor(network) {
|
|
18874
|
+
this.network = network;
|
|
18875
|
+
}
|
|
18876
|
+
network;
|
|
18877
|
+
listenerValue = null;
|
|
18878
|
+
connectionValue = null;
|
|
18879
|
+
boundPort = 0;
|
|
18880
|
+
boundAddress = "0.0.0.0";
|
|
18881
|
+
bind(address, port) {
|
|
18882
|
+
if (this.listenerValue || this.connectionValue || this.boundPort !== 0) {
|
|
18883
|
+
throw new PosixError(Errno.EINVAL, "socket is already bound");
|
|
18884
|
+
}
|
|
18885
|
+
this.boundAddress = address;
|
|
18886
|
+
this.boundPort = port;
|
|
18887
|
+
}
|
|
18888
|
+
listen(backlog) {
|
|
18889
|
+
if (this.listenerValue) return;
|
|
18890
|
+
if (this.boundPort === 0) {
|
|
18891
|
+
const port = this.findEphemeralPort();
|
|
18892
|
+
this.boundPort = port;
|
|
18893
|
+
}
|
|
18894
|
+
this.listenerValue = this.network.listen(this.boundPort, this.boundAddress, backlog);
|
|
18895
|
+
}
|
|
18896
|
+
connect(port, address = "127.0.0.1") {
|
|
18897
|
+
if (this.listenerValue || this.connectionValue) throw new PosixError(Errno.EISCONN);
|
|
18898
|
+
this.connectionValue = this.network.connect(port, this.boundPort, this.boundAddress);
|
|
18899
|
+
this.boundPort = this.connectionValue.local.port;
|
|
18900
|
+
this.boundAddress = this.connectionValue.local.address;
|
|
18901
|
+
}
|
|
18902
|
+
accept() {
|
|
18903
|
+
if (!this.listenerValue) throw new PosixError(Errno.EINVAL, "socket is not listening");
|
|
18904
|
+
const accepted = this.listenerValue.accept().connection;
|
|
18905
|
+
const socket = new _VirtualTcpSocket(this.network);
|
|
18906
|
+
socket.connectionValue = accepted;
|
|
18907
|
+
socket.boundPort = accepted.local.port;
|
|
18908
|
+
socket.boundAddress = accepted.local.address;
|
|
18909
|
+
return socket;
|
|
18910
|
+
}
|
|
18911
|
+
get listener() {
|
|
18912
|
+
return this.listenerValue;
|
|
18913
|
+
}
|
|
18914
|
+
get connection() {
|
|
18915
|
+
return this.connectionValue;
|
|
18916
|
+
}
|
|
18917
|
+
get local() {
|
|
18918
|
+
return { address: this.boundAddress, port: this.boundPort };
|
|
18919
|
+
}
|
|
18920
|
+
get remote() {
|
|
18921
|
+
return this.connectionValue?.remote ?? null;
|
|
18922
|
+
}
|
|
18923
|
+
get readable() {
|
|
18924
|
+
return this.listenerValue?.readable ?? this.connectionValue?.readable ?? false;
|
|
18925
|
+
}
|
|
18926
|
+
get writable() {
|
|
18927
|
+
return this.connectionValue?.writable ?? false;
|
|
18928
|
+
}
|
|
18929
|
+
waitForChange() {
|
|
18930
|
+
return (this.listenerValue ?? this.connectionValue)?.waitForChange() ?? Promise.resolve();
|
|
18931
|
+
}
|
|
18932
|
+
read(length) {
|
|
18933
|
+
if (!this.connectionValue) throw new PosixError(Errno.EINVAL);
|
|
18934
|
+
return this.connectionValue.read(length);
|
|
18935
|
+
}
|
|
18936
|
+
write(data) {
|
|
18937
|
+
if (!this.connectionValue) throw new PosixError(Errno.EINVAL);
|
|
18938
|
+
return this.connectionValue.write(data);
|
|
18939
|
+
}
|
|
18940
|
+
shutdown(read, write) {
|
|
18941
|
+
if (!this.connectionValue) throw new PosixError(Errno.ENOTCONN);
|
|
18942
|
+
this.connectionValue.shutdown(read, write);
|
|
18943
|
+
}
|
|
18944
|
+
close() {
|
|
18945
|
+
if (this.listenerValue) this.network.close(this.listenerValue);
|
|
18946
|
+
this.connectionValue?.close();
|
|
18947
|
+
this.listenerValue = null;
|
|
18948
|
+
this.connectionValue = null;
|
|
18949
|
+
}
|
|
18950
|
+
findEphemeralPort() {
|
|
18951
|
+
for (let port = 49152; port <= 65535; port += 1) if (!this.network.hasListener(port)) return port;
|
|
18952
|
+
throw new PosixError(Errno.EADDRINUSE, "no ephemeral ports available");
|
|
18953
|
+
}
|
|
18954
|
+
};
|
|
18955
|
+
var SocketDescription = class _SocketDescription {
|
|
18956
|
+
kind = "socket";
|
|
18957
|
+
flags;
|
|
18958
|
+
resource;
|
|
18959
|
+
closed = false;
|
|
18960
|
+
options = /* @__PURE__ */ new Map();
|
|
18961
|
+
constructor(resource, flags = 0) {
|
|
18962
|
+
this.resource = resource;
|
|
18963
|
+
this.flags = flags;
|
|
18964
|
+
}
|
|
18965
|
+
get listener() {
|
|
18966
|
+
return this.resource.listener;
|
|
18967
|
+
}
|
|
18968
|
+
get connection() {
|
|
18969
|
+
return this.resource.connection;
|
|
18970
|
+
}
|
|
18971
|
+
read(length) {
|
|
18972
|
+
return this.resource.read(length);
|
|
18973
|
+
}
|
|
18974
|
+
write(data) {
|
|
18975
|
+
return this.resource.write(data);
|
|
18976
|
+
}
|
|
18977
|
+
readable() {
|
|
18978
|
+
return this.resource.readable;
|
|
18979
|
+
}
|
|
18980
|
+
writable() {
|
|
18981
|
+
return this.resource.writable;
|
|
18982
|
+
}
|
|
18983
|
+
whenReady() {
|
|
18984
|
+
return this.resource.waitForChange();
|
|
18985
|
+
}
|
|
18986
|
+
stat() {
|
|
18987
|
+
return {
|
|
18988
|
+
ino: 0,
|
|
18989
|
+
mode: 49663,
|
|
18990
|
+
size: 0,
|
|
18991
|
+
uid: 0,
|
|
18992
|
+
gid: 0,
|
|
18993
|
+
nlink: 1,
|
|
18994
|
+
atimeMs: Date.now(),
|
|
18995
|
+
mtimeMs: Date.now(),
|
|
18996
|
+
ctimeMs: Date.now()
|
|
18997
|
+
};
|
|
18998
|
+
}
|
|
18999
|
+
close() {
|
|
19000
|
+
if (this.closed) return;
|
|
19001
|
+
this.closed = true;
|
|
19002
|
+
this.resource.close();
|
|
19003
|
+
}
|
|
19004
|
+
bind(address, port) {
|
|
19005
|
+
this.resource.bind(address, port);
|
|
19006
|
+
}
|
|
19007
|
+
listen(backlog) {
|
|
19008
|
+
this.resource.listen(backlog);
|
|
19009
|
+
}
|
|
19010
|
+
connect(address, port) {
|
|
19011
|
+
this.resource.connect(port, address);
|
|
19012
|
+
}
|
|
19013
|
+
accept() {
|
|
19014
|
+
return new _SocketDescription(this.resource.accept(), this.flags);
|
|
19015
|
+
}
|
|
19016
|
+
shutdown(read, write) {
|
|
19017
|
+
this.resource.shutdown(read, write);
|
|
19018
|
+
}
|
|
19019
|
+
setOption(level, option, value) {
|
|
19020
|
+
this.options.set(`${level}:${option}`, value.slice());
|
|
19021
|
+
}
|
|
19022
|
+
getOption(level, option) {
|
|
19023
|
+
return this.options.get(`${level}:${option}`)?.slice() ?? new Uint8Array(4);
|
|
19024
|
+
}
|
|
19025
|
+
localAddress() {
|
|
19026
|
+
return this.resource.local;
|
|
19027
|
+
}
|
|
19028
|
+
peerAddress() {
|
|
19029
|
+
const peer = this.resource.remote;
|
|
19030
|
+
if (!peer) throw new PosixError(Errno.ENOTCONN);
|
|
19031
|
+
return peer;
|
|
19032
|
+
}
|
|
19033
|
+
};
|
|
19034
|
+
var VirtualTcpNetwork = class {
|
|
19035
|
+
constructor(occupied) {
|
|
19036
|
+
this.occupied = occupied;
|
|
19037
|
+
}
|
|
19038
|
+
occupied;
|
|
19039
|
+
listeners = /* @__PURE__ */ new Map();
|
|
19040
|
+
listen(port, address = "0.0.0.0", backlog = 128) {
|
|
19041
|
+
if (this.listeners.has(port) || this.occupied?.(port)) throw new PosixError(Errno.EADDRINUSE, `port ${port} is already in use`);
|
|
19042
|
+
const listener = new VirtualTcpListener(port, address, backlog);
|
|
19043
|
+
this.listeners.set(port, listener);
|
|
19044
|
+
return listener;
|
|
19045
|
+
}
|
|
19046
|
+
close(listener) {
|
|
19047
|
+
if (this.listeners.get(listener.port) !== listener) return;
|
|
19048
|
+
this.listeners.delete(listener.port);
|
|
19049
|
+
listener.close();
|
|
19050
|
+
}
|
|
19051
|
+
connect(port, localPort = 0, localAddress = "127.0.0.1") {
|
|
19052
|
+
const listener = this.listeners.get(port);
|
|
19053
|
+
if (!listener || listener.isClosed) throw new PosixError(Errno.ECONNREFUSED, `port ${port} is not listening`);
|
|
19054
|
+
const client = new VirtualTcpConnection(
|
|
19055
|
+
{ address: localAddress, port: localPort },
|
|
19056
|
+
{ address: listener.address, port }
|
|
19057
|
+
);
|
|
19058
|
+
const server = new VirtualTcpConnection(
|
|
19059
|
+
{ address: listener.address, port },
|
|
19060
|
+
{ address: localAddress, port: localPort }
|
|
19061
|
+
);
|
|
19062
|
+
client.pairWith(server);
|
|
19063
|
+
server.pairWith(client);
|
|
19064
|
+
listener.enqueue(server);
|
|
19065
|
+
return client;
|
|
19066
|
+
}
|
|
19067
|
+
hasListener(port) {
|
|
19068
|
+
return this.listeners.has(port);
|
|
19069
|
+
}
|
|
19070
|
+
ports() {
|
|
19071
|
+
return [...this.listeners.keys()].sort((a, b) => a - b);
|
|
19072
|
+
}
|
|
19073
|
+
closeAll() {
|
|
19074
|
+
for (const listener of [...this.listeners.values()]) this.close(listener);
|
|
19075
|
+
}
|
|
19076
|
+
};
|
|
19077
|
+
|
|
18692
19078
|
// src/runtime/python/syscall-server.ts
|
|
18693
19079
|
var MAX_TRANSFER = 8 * 1024 * 1024;
|
|
18694
19080
|
function createHostAbiServer(proc) {
|
|
@@ -18935,12 +19321,76 @@ function createHostAbiServer(proc) {
|
|
|
18935
19321
|
crypto.getRandomValues(bytes2);
|
|
18936
19322
|
return { status: length, payload: bytes2 };
|
|
18937
19323
|
}
|
|
19324
|
+
/* ----------------------------------------------------------- sockets */
|
|
19325
|
+
case Op.socket: {
|
|
19326
|
+
const family = r.u32();
|
|
19327
|
+
const type = r.u32();
|
|
19328
|
+
const protocol = r.i32();
|
|
19329
|
+
if (family !== 2 || (type & 15) !== 1 || protocol !== 0) throw new PosixError(Errno.EAFNOSUPPORT);
|
|
19330
|
+
if (!proc.sockets) throw new PosixError(Errno.ENOSYS);
|
|
19331
|
+
return { status: proc.table.add(new SocketDescription(new VirtualTcpSocket(proc.sockets))) };
|
|
19332
|
+
}
|
|
19333
|
+
case Op.bind: {
|
|
19334
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19335
|
+
description.bind(r.string(), r.u32());
|
|
19336
|
+
return { status: 0 };
|
|
19337
|
+
}
|
|
19338
|
+
case Op.listen: {
|
|
19339
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19340
|
+
description.listen(Math.max(1, Math.min(1024, r.u32())));
|
|
19341
|
+
return { status: 0 };
|
|
19342
|
+
}
|
|
19343
|
+
case Op.accept: {
|
|
19344
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19345
|
+
const accepted = await acceptBlocking(description);
|
|
19346
|
+
const fd = proc.table.add(accepted);
|
|
19347
|
+
const peer = accepted.peerAddress();
|
|
19348
|
+
return { status: fd, payload: new Writer().string(peer.address).u32(peer.port).finish() };
|
|
19349
|
+
}
|
|
19350
|
+
case Op.connect: {
|
|
19351
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19352
|
+
description.connect(r.string(), r.u32());
|
|
19353
|
+
return { status: 0 };
|
|
19354
|
+
}
|
|
19355
|
+
case Op.send: {
|
|
19356
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19357
|
+
return { status: await writeBlocking(description, r.bytes32()) };
|
|
19358
|
+
}
|
|
19359
|
+
case Op.recv: {
|
|
19360
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19361
|
+
const data = await readBlocking(description, clamp(r.u32()));
|
|
19362
|
+
return { status: data.length, payload: data };
|
|
19363
|
+
}
|
|
19364
|
+
case Op.shutdown: {
|
|
19365
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19366
|
+
const how = r.u32();
|
|
19367
|
+
if (how > 2) throw new PosixError(Errno.EINVAL);
|
|
19368
|
+
description.shutdown(how === 0 || how === 2, how === 1 || how === 2);
|
|
19369
|
+
return { status: 0 };
|
|
19370
|
+
}
|
|
19371
|
+
case Op.getsockname: {
|
|
19372
|
+
const address = socketDescription(proc.table.get(r.i32())).localAddress();
|
|
19373
|
+
return { status: 0, payload: new Writer().string(address.address).u32(address.port).finish() };
|
|
19374
|
+
}
|
|
19375
|
+
case Op.getpeername: {
|
|
19376
|
+
const address = socketDescription(proc.table.get(r.i32())).peerAddress();
|
|
19377
|
+
return { status: 0, payload: new Writer().string(address.address).u32(address.port).finish() };
|
|
19378
|
+
}
|
|
19379
|
+
case Op.setsockopt: {
|
|
19380
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19381
|
+
description.setOption(r.u32(), r.u32(), r.bytes32());
|
|
19382
|
+
return { status: 0 };
|
|
19383
|
+
}
|
|
19384
|
+
case Op.getsockopt: {
|
|
19385
|
+
const description = socketDescription(proc.table.get(r.i32()));
|
|
19386
|
+
return { status: 0, payload: new Writer().bytes32(description.getOption(r.u32(), r.u32())).finish() };
|
|
19387
|
+
}
|
|
18938
19388
|
default:
|
|
18939
19389
|
return { status: failure(Errno.ENOSYS) };
|
|
18940
19390
|
}
|
|
18941
19391
|
}
|
|
18942
19392
|
function implemented(capability) {
|
|
18943
|
-
return ["files", "descriptors", "pipes", "readiness", "time", "identity", "entropy"].includes(capability);
|
|
19393
|
+
return ["files", "descriptors", "pipes", "readiness", "time", "identity", "entropy"].includes(capability) || capability === "sockets" && proc.sockets !== void 0;
|
|
18944
19394
|
}
|
|
18945
19395
|
function resolve3(path) {
|
|
18946
19396
|
if (path.startsWith("/")) return proc.vfs.resolvePath(path);
|
|
@@ -18949,6 +19399,22 @@ function createHostAbiServer(proc) {
|
|
|
18949
19399
|
function clamp(length) {
|
|
18950
19400
|
return Math.min(length, MAX_TRANSFER);
|
|
18951
19401
|
}
|
|
19402
|
+
function socketDescription(description) {
|
|
19403
|
+
if (!(description instanceof SocketDescription)) throw new PosixError(Errno.ENOTSOCK, "descriptor is not a socket");
|
|
19404
|
+
return description;
|
|
19405
|
+
}
|
|
19406
|
+
async function acceptBlocking(description) {
|
|
19407
|
+
for (; ; ) {
|
|
19408
|
+
try {
|
|
19409
|
+
return description.accept();
|
|
19410
|
+
} catch (error) {
|
|
19411
|
+
const posix = toPosixError(error);
|
|
19412
|
+
if (posix.errno !== Errno.EAGAIN || description.flags & O_NONBLOCK) throw posix;
|
|
19413
|
+
}
|
|
19414
|
+
await Promise.race([description.whenReady(), aborted()]);
|
|
19415
|
+
if (proc.signal.aborted) throw new PosixError(Errno.EINTR);
|
|
19416
|
+
}
|
|
19417
|
+
}
|
|
18952
19418
|
async function readBlocking(description, length) {
|
|
18953
19419
|
for (; ; ) {
|
|
18954
19420
|
try {
|
|
@@ -19215,7 +19681,8 @@ async function startPythonProcess(options) {
|
|
|
19215
19681
|
table,
|
|
19216
19682
|
env: options.env,
|
|
19217
19683
|
cwd: options.cwd,
|
|
19218
|
-
signal: controller.signal
|
|
19684
|
+
signal: controller.signal,
|
|
19685
|
+
sockets: options.sockets
|
|
19219
19686
|
});
|
|
19220
19687
|
const buffers = createHostTransportBuffers();
|
|
19221
19688
|
let fault = null;
|
|
@@ -19822,7 +20289,8 @@ async function runOwnedPython(ctx, argv) {
|
|
|
19822
20289
|
mounts,
|
|
19823
20290
|
onStdout: (data) => ctx.stdout.write(data),
|
|
19824
20291
|
onStderr: (data) => ctx.stderr.write(data),
|
|
19825
|
-
signal: ctx.signal
|
|
20292
|
+
signal: ctx.signal,
|
|
20293
|
+
sockets: ctx.kernel.pod.sockets
|
|
19826
20294
|
});
|
|
19827
20295
|
void pumpStdin(ctx, process2);
|
|
19828
20296
|
return process2.wait();
|
|
@@ -19927,6 +20395,17 @@ environments. A package with no usable wheel is an error, never a silent skip.`,
|
|
|
19927
20395
|
}
|
|
19928
20396
|
const cache = /* @__PURE__ */ new Map();
|
|
19929
20397
|
const request = async (url, timeoutMs, read) => {
|
|
20398
|
+
if (url.startsWith("file:")) {
|
|
20399
|
+
try {
|
|
20400
|
+
const [{ readFile }, { fileURLToPath: fileURLToPath2 }] = await Promise.all([
|
|
20401
|
+
nodeBuiltin("fs/promises"),
|
|
20402
|
+
nodeBuiltin("url")
|
|
20403
|
+
]);
|
|
20404
|
+
return await read(new Response(await readFile(fileURLToPath2(url))));
|
|
20405
|
+
} catch (error) {
|
|
20406
|
+
throw new Error(`could not read bundled wheel asset ${url}: ${error.message}`);
|
|
20407
|
+
}
|
|
20408
|
+
}
|
|
19930
20409
|
const controller = new AbortController();
|
|
19931
20410
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
19932
20411
|
try {
|
|
@@ -26128,12 +26607,16 @@ var VirtualHttpServer = class extends EventEmitter4 {
|
|
|
26128
26607
|
}
|
|
26129
26608
|
};
|
|
26130
26609
|
var VirtualHttpRouter = class {
|
|
26610
|
+
constructor(sockets) {
|
|
26611
|
+
this.sockets = sockets;
|
|
26612
|
+
}
|
|
26613
|
+
sockets;
|
|
26131
26614
|
servers = /* @__PURE__ */ new Map();
|
|
26132
26615
|
/** Notified when a server begins listening, for `onServerReady`. */
|
|
26133
26616
|
onListen;
|
|
26134
26617
|
onClose;
|
|
26135
26618
|
register(port, server, owner) {
|
|
26136
|
-
if (this.servers.has(port)) throw Object.assign(new Error(`listen EADDRINUSE: address already in use 0.0.0.0:${port}`), { code: "EADDRINUSE", port });
|
|
26619
|
+
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 });
|
|
26137
26620
|
this.servers.set(port, { server, owner });
|
|
26138
26621
|
this.onListen?.(port);
|
|
26139
26622
|
}
|
|
@@ -29717,8 +30200,9 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
29717
30200
|
volume = new MirroringVolume(new MemoryVolume());
|
|
29718
30201
|
packages;
|
|
29719
30202
|
instanceId = `sbx-${Math.random().toString(36).slice(2)}`;
|
|
29720
|
-
router
|
|
29721
|
-
|
|
30203
|
+
router;
|
|
30204
|
+
sockets;
|
|
30205
|
+
proxy = { activePorts: (_instanceId) => [.../* @__PURE__ */ new Set([...this.router.activePorts(), ...this.sockets.ports()])].sort((a, b) => a - b) };
|
|
29722
30206
|
/**
|
|
29723
30207
|
* Bind a port to a server that is not a JavaScript one.
|
|
29724
30208
|
*
|
|
@@ -29785,6 +30269,8 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
29785
30269
|
fetch;
|
|
29786
30270
|
constructor(options) {
|
|
29787
30271
|
ensureProcessGlobal();
|
|
30272
|
+
this.sockets = new VirtualTcpNetwork((port) => this.router.activePortsIncludes(port));
|
|
30273
|
+
this.router = new VirtualHttpRouter(this.sockets);
|
|
29788
30274
|
this.workdir = options.workdir ?? "/";
|
|
29789
30275
|
this.env = { ...options.env };
|
|
29790
30276
|
this.aliases = { ...WASM_ALIASES, ...options.aliases };
|
|
@@ -29918,8 +30404,10 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
29918
30404
|
await new Promise((resolve3) => setTimeout(resolve3, busy ? 5 : 0));
|
|
29919
30405
|
}
|
|
29920
30406
|
}
|
|
29921
|
-
async request(
|
|
29922
|
-
return this.router.request(
|
|
30407
|
+
async request(port, init = {}) {
|
|
30408
|
+
if (this.router.activePortsIncludes(port)) return this.router.request(port, init);
|
|
30409
|
+
if (!this.sockets.hasListener(port)) return this.router.request(port, init);
|
|
30410
|
+
return this.requestTcp(port, init);
|
|
29923
30411
|
}
|
|
29924
30412
|
connect(port, init, peer) {
|
|
29925
30413
|
return this.router.connect(port, init, peer);
|
|
@@ -29938,8 +30426,46 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
29938
30426
|
for (const process2 of this.running) process2.kill();
|
|
29939
30427
|
this.running.clear();
|
|
29940
30428
|
this.router.closeAll();
|
|
30429
|
+
this.sockets.closeAll();
|
|
29941
30430
|
this.esbuild?.stop();
|
|
29942
30431
|
}
|
|
30432
|
+
/** HTTP/1.1 client path for a server implemented outside the JS runtime. */
|
|
30433
|
+
async requestTcp(port, init) {
|
|
30434
|
+
const connection = this.sockets.connect(port);
|
|
30435
|
+
const method = String(init.method ?? "GET").toUpperCase();
|
|
30436
|
+
const path = String(init.path ?? "/");
|
|
30437
|
+
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;
|
|
30438
|
+
const headers = Object.entries(init.headers ?? {}).map(([name, value]) => `${name}: ${String(value)}`);
|
|
30439
|
+
if (!headers.some((line) => line.toLowerCase().startsWith("host:"))) headers.push("Host: localhost");
|
|
30440
|
+
if (!headers.some((line) => line.toLowerCase().startsWith("connection:"))) headers.push("Connection: close");
|
|
30441
|
+
if (body.length && !headers.some((line) => line.toLowerCase().startsWith("content-length:"))) headers.push(`Content-Length: ${body.length}`);
|
|
30442
|
+
const request = new TextEncoder().encode(`${method} ${path} HTTP/1.1\r
|
|
30443
|
+
${headers.join("\r\n")}\r
|
|
30444
|
+
\r
|
|
30445
|
+
`);
|
|
30446
|
+
connection.write(request);
|
|
30447
|
+
if (body.length) connection.write(body);
|
|
30448
|
+
const bytes2 = [];
|
|
30449
|
+
let combined = new Uint8Array();
|
|
30450
|
+
for (; ; ) {
|
|
30451
|
+
try {
|
|
30452
|
+
const chunk = connection.read(64 * 1024);
|
|
30453
|
+
if (chunk.length === 0) break;
|
|
30454
|
+
bytes2.push(chunk);
|
|
30455
|
+
combined = joinBytes(bytes2);
|
|
30456
|
+
const headerEnd = findBytes(combined, new Uint8Array([13, 10, 13, 10]));
|
|
30457
|
+
if (headerEnd < 0) continue;
|
|
30458
|
+
const headerText = new TextDecoder().decode(combined.subarray(0, headerEnd));
|
|
30459
|
+
const contentLength = /^content-length:\s*(\d+)\s*$/im.exec(headerText)?.[1];
|
|
30460
|
+
if (contentLength !== void 0 && combined.length >= headerEnd + 4 + Number(contentLength)) break;
|
|
30461
|
+
} catch (error) {
|
|
30462
|
+
if (!(error instanceof PosixError) || error.errno !== Errno.EAGAIN) throw error;
|
|
30463
|
+
await connection.waitForChange();
|
|
30464
|
+
}
|
|
30465
|
+
}
|
|
30466
|
+
connection.close();
|
|
30467
|
+
return parseHttpResponse(combined);
|
|
30468
|
+
}
|
|
29943
30469
|
seed(files) {
|
|
29944
30470
|
for (const [path, data] of Object.entries(files)) {
|
|
29945
30471
|
const parts = path.split("/").filter(Boolean);
|
|
@@ -29971,6 +30497,43 @@ function formatError(error) {
|
|
|
29971
30497
|
function isRecord(value) {
|
|
29972
30498
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
29973
30499
|
}
|
|
30500
|
+
function joinBytes(parts) {
|
|
30501
|
+
const total = parts.reduce((sum, part) => sum + part.length, 0);
|
|
30502
|
+
const out = new Uint8Array(total);
|
|
30503
|
+
let at = 0;
|
|
30504
|
+
for (const part of parts) {
|
|
30505
|
+
out.set(part, at);
|
|
30506
|
+
at += part.length;
|
|
30507
|
+
}
|
|
30508
|
+
return out;
|
|
30509
|
+
}
|
|
30510
|
+
function findBytes(haystack, needle) {
|
|
30511
|
+
outer: for (let at = 0; at <= haystack.length - needle.length; at += 1) {
|
|
30512
|
+
for (let i = 0; i < needle.length; i += 1) if (haystack[at + i] !== needle[i]) continue outer;
|
|
30513
|
+
return at;
|
|
30514
|
+
}
|
|
30515
|
+
return -1;
|
|
30516
|
+
}
|
|
30517
|
+
function parseHttpResponse(bytes2) {
|
|
30518
|
+
const marker = new Uint8Array([13, 10, 13, 10]);
|
|
30519
|
+
const headerEnd = findBytes(bytes2, marker);
|
|
30520
|
+
if (headerEnd < 0) throw new Error("Python server returned an incomplete HTTP response");
|
|
30521
|
+
const text2 = new TextDecoder().decode(bytes2.subarray(0, headerEnd));
|
|
30522
|
+
const lines = text2.split("\r\n");
|
|
30523
|
+
const status = /HTTP\/\d\.\d\s+(\d+)(?:\s+(.*))?/.exec(lines.shift() ?? "");
|
|
30524
|
+
if (!status) throw new Error("Python server returned an invalid HTTP status line");
|
|
30525
|
+
const headers = {};
|
|
30526
|
+
for (const line of lines) {
|
|
30527
|
+
const separator = line.indexOf(":");
|
|
30528
|
+
if (separator > 0) headers[line.slice(0, separator).toLowerCase()] = line.slice(separator + 1).trim();
|
|
30529
|
+
}
|
|
30530
|
+
return {
|
|
30531
|
+
statusCode: Number(status[1]),
|
|
30532
|
+
statusMessage: status[2] ?? "",
|
|
30533
|
+
headers,
|
|
30534
|
+
body: bytes2.slice(headerEnd + marker.length)
|
|
30535
|
+
};
|
|
30536
|
+
}
|
|
29974
30537
|
function packageIsInstalled(volume, cwd, wanted) {
|
|
29975
30538
|
for (let dir3 = clean(cwd); ; dir3 = dirname(dir3)) {
|
|
29976
30539
|
if (packageTreeContains(volume, join(dir3, "node_modules"), wanted, /* @__PURE__ */ new Set())) return true;
|