sandboxedjs 0.1.53 → 0.1.55

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.
@@ -1,4 +1,4 @@
1
- import { R as RuntimeVolume, c as VolumeStat, d as VolumeStats } from './vfs-DzEcPbMY.js';
1
+ import { R as RuntimeVolume, d as VolumeStat, e as VolumeStats } from './contracts-CVgctitO.js';
2
2
 
3
3
  type NodeKind = "file" | "directory" | "symlink";
4
4
  interface MemoryVolumeSnapshotEntry {
@@ -1,4 +1,4 @@
1
- import { R as RuntimeVolume, c as VolumeStat, d as VolumeStats } from './vfs-DzEcPbMY.cjs';
1
+ import { R as RuntimeVolume, d as VolumeStat, e as VolumeStats } from './contracts-CVgctitO.cjs';
2
2
 
3
3
  type NodeKind = "file" | "directory" | "symlink";
4
4
  interface MemoryVolumeSnapshotEntry {
@@ -35,7 +35,20 @@ var Op = {
35
35
  getcwd: 1281,
36
36
  chdir: 1282,
37
37
  environ: 1283,
38
- getrandom: 1536
38
+ getrandom: 1536,
39
+ socket: 1792,
40
+ bind: 1793,
41
+ listen: 1794,
42
+ accept: 1795,
43
+ connect: 1796,
44
+ send: 1797,
45
+ recv: 1798,
46
+ shutdown: 1799,
47
+ getsockname: 1800,
48
+ getpeername: 1801,
49
+ setsockopt: 1802,
50
+ getsockopt: 1803,
51
+ socket_close: 1804
39
52
  };
40
53
  var Errno = {
41
54
  EPERM: 1,
@@ -72,6 +85,15 @@ var Errno = {
72
85
  ENOTEMPTY: 39,
73
86
  ELOOP: 40,
74
87
  ENODATA: 61,
88
+ ENOTSOCK: 88,
89
+ EAFNOSUPPORT: 97,
90
+ EADDRINUSE: 98,
91
+ EADDRNOTAVAIL: 99,
92
+ ENETUNREACH: 101,
93
+ ECONNRESET: 104,
94
+ EISCONN: 106,
95
+ ENOTCONN: 107,
96
+ ECONNREFUSED: 111,
75
97
  EPROTO: 71,
76
98
  EOVERFLOW: 75,
77
99
  ETIMEDOUT: 110,
@@ -1081,6 +1103,170 @@ var FileService = class {
1081
1103
  }
1082
1104
  };
1083
1105
 
1106
+ // src/net/virtual-socket.ts
1107
+ var VirtualTcpSocket = class _VirtualTcpSocket {
1108
+ constructor(network) {
1109
+ this.network = network;
1110
+ }
1111
+ network;
1112
+ listenerValue = null;
1113
+ connectionValue = null;
1114
+ boundPort = 0;
1115
+ boundAddress = "0.0.0.0";
1116
+ bind(address, port) {
1117
+ if (this.listenerValue || this.connectionValue || this.boundPort !== 0) {
1118
+ throw new PosixError(Errno.EINVAL, "socket is already bound");
1119
+ }
1120
+ this.boundAddress = address;
1121
+ this.boundPort = port;
1122
+ }
1123
+ listen(backlog) {
1124
+ if (this.listenerValue) return;
1125
+ if (this.boundPort === 0) {
1126
+ const port = this.findEphemeralPort();
1127
+ this.boundPort = port;
1128
+ }
1129
+ this.listenerValue = this.network.listen(this.boundPort, this.boundAddress, backlog);
1130
+ }
1131
+ connect(port, address = "127.0.0.1") {
1132
+ if (this.listenerValue || this.connectionValue) throw new PosixError(Errno.EISCONN);
1133
+ this.connectionValue = this.network.connect(port, this.boundPort, this.boundAddress);
1134
+ this.boundPort = this.connectionValue.local.port;
1135
+ this.boundAddress = this.connectionValue.local.address;
1136
+ }
1137
+ accept() {
1138
+ if (!this.listenerValue) throw new PosixError(Errno.EINVAL, "socket is not listening");
1139
+ const accepted = this.listenerValue.accept().connection;
1140
+ const socket = new _VirtualTcpSocket(this.network);
1141
+ socket.connectionValue = accepted;
1142
+ socket.boundPort = accepted.local.port;
1143
+ socket.boundAddress = accepted.local.address;
1144
+ return socket;
1145
+ }
1146
+ get listener() {
1147
+ return this.listenerValue;
1148
+ }
1149
+ get connection() {
1150
+ return this.connectionValue;
1151
+ }
1152
+ get local() {
1153
+ return { address: this.boundAddress, port: this.boundPort };
1154
+ }
1155
+ get remote() {
1156
+ return this.connectionValue?.remote ?? null;
1157
+ }
1158
+ get readable() {
1159
+ return this.listenerValue?.readable ?? this.connectionValue?.readable ?? false;
1160
+ }
1161
+ get writable() {
1162
+ return this.connectionValue?.writable ?? false;
1163
+ }
1164
+ waitForChange() {
1165
+ return (this.listenerValue ?? this.connectionValue)?.waitForChange() ?? Promise.resolve();
1166
+ }
1167
+ read(length) {
1168
+ if (!this.connectionValue) throw new PosixError(Errno.EINVAL);
1169
+ return this.connectionValue.read(length);
1170
+ }
1171
+ write(data) {
1172
+ if (!this.connectionValue) throw new PosixError(Errno.EINVAL);
1173
+ return this.connectionValue.write(data);
1174
+ }
1175
+ shutdown(read, write) {
1176
+ if (!this.connectionValue) throw new PosixError(Errno.ENOTCONN);
1177
+ this.connectionValue.shutdown(read, write);
1178
+ }
1179
+ close() {
1180
+ if (this.listenerValue) this.network.close(this.listenerValue);
1181
+ this.connectionValue?.close();
1182
+ this.listenerValue = null;
1183
+ this.connectionValue = null;
1184
+ }
1185
+ findEphemeralPort() {
1186
+ for (let port = 49152; port <= 65535; port += 1) if (!this.network.hasListener(port)) return port;
1187
+ throw new PosixError(Errno.EADDRINUSE, "no ephemeral ports available");
1188
+ }
1189
+ };
1190
+ var SocketDescription = class _SocketDescription {
1191
+ kind = "socket";
1192
+ flags;
1193
+ resource;
1194
+ closed = false;
1195
+ options = /* @__PURE__ */ new Map();
1196
+ constructor(resource, flags = 0) {
1197
+ this.resource = resource;
1198
+ this.flags = flags;
1199
+ }
1200
+ get listener() {
1201
+ return this.resource.listener;
1202
+ }
1203
+ get connection() {
1204
+ return this.resource.connection;
1205
+ }
1206
+ read(length) {
1207
+ return this.resource.read(length);
1208
+ }
1209
+ write(data) {
1210
+ return this.resource.write(data);
1211
+ }
1212
+ readable() {
1213
+ return this.resource.readable;
1214
+ }
1215
+ writable() {
1216
+ return this.resource.writable;
1217
+ }
1218
+ whenReady() {
1219
+ return this.resource.waitForChange();
1220
+ }
1221
+ stat() {
1222
+ return {
1223
+ ino: 0,
1224
+ mode: 49663,
1225
+ size: 0,
1226
+ uid: 0,
1227
+ gid: 0,
1228
+ nlink: 1,
1229
+ atimeMs: Date.now(),
1230
+ mtimeMs: Date.now(),
1231
+ ctimeMs: Date.now()
1232
+ };
1233
+ }
1234
+ close() {
1235
+ if (this.closed) return;
1236
+ this.closed = true;
1237
+ this.resource.close();
1238
+ }
1239
+ bind(address, port) {
1240
+ this.resource.bind(address, port);
1241
+ }
1242
+ listen(backlog) {
1243
+ this.resource.listen(backlog);
1244
+ }
1245
+ connect(address, port) {
1246
+ this.resource.connect(port, address);
1247
+ }
1248
+ accept() {
1249
+ return new _SocketDescription(this.resource.accept(), this.flags);
1250
+ }
1251
+ shutdown(read, write) {
1252
+ this.resource.shutdown(read, write);
1253
+ }
1254
+ setOption(level, option, value) {
1255
+ this.options.set(`${level}:${option}`, value.slice());
1256
+ }
1257
+ getOption(level, option) {
1258
+ return this.options.get(`${level}:${option}`)?.slice() ?? new Uint8Array(4);
1259
+ }
1260
+ localAddress() {
1261
+ return this.resource.local;
1262
+ }
1263
+ peerAddress() {
1264
+ const peer = this.resource.remote;
1265
+ if (!peer) throw new PosixError(Errno.ENOTCONN);
1266
+ return peer;
1267
+ }
1268
+ };
1269
+
1084
1270
  // src/runtime/python/syscall-server.ts
1085
1271
  var MAX_TRANSFER = 8 * 1024 * 1024;
1086
1272
  function createHostAbiServer(proc) {
@@ -1327,12 +1513,76 @@ function createHostAbiServer(proc) {
1327
1513
  crypto.getRandomValues(bytes);
1328
1514
  return { status: length, payload: bytes };
1329
1515
  }
1516
+ /* ----------------------------------------------------------- sockets */
1517
+ case Op.socket: {
1518
+ const family = r.u32();
1519
+ const type = r.u32();
1520
+ const protocol = r.i32();
1521
+ if (family !== 2 || (type & 15) !== 1 || protocol !== 0) throw new PosixError(Errno.EAFNOSUPPORT);
1522
+ if (!proc.sockets) throw new PosixError(Errno.ENOSYS);
1523
+ return { status: proc.table.add(new SocketDescription(new VirtualTcpSocket(proc.sockets))) };
1524
+ }
1525
+ case Op.bind: {
1526
+ const description = socketDescription(proc.table.get(r.i32()));
1527
+ description.bind(r.string(), r.u32());
1528
+ return { status: 0 };
1529
+ }
1530
+ case Op.listen: {
1531
+ const description = socketDescription(proc.table.get(r.i32()));
1532
+ description.listen(Math.max(1, Math.min(1024, r.u32())));
1533
+ return { status: 0 };
1534
+ }
1535
+ case Op.accept: {
1536
+ const description = socketDescription(proc.table.get(r.i32()));
1537
+ const accepted = await acceptBlocking(description);
1538
+ const fd = proc.table.add(accepted);
1539
+ const peer = accepted.peerAddress();
1540
+ return { status: fd, payload: new Writer().string(peer.address).u32(peer.port).finish() };
1541
+ }
1542
+ case Op.connect: {
1543
+ const description = socketDescription(proc.table.get(r.i32()));
1544
+ description.connect(r.string(), r.u32());
1545
+ return { status: 0 };
1546
+ }
1547
+ case Op.send: {
1548
+ const description = socketDescription(proc.table.get(r.i32()));
1549
+ return { status: await writeBlocking(description, r.bytes32()) };
1550
+ }
1551
+ case Op.recv: {
1552
+ const description = socketDescription(proc.table.get(r.i32()));
1553
+ const data = await readBlocking(description, clamp(r.u32()));
1554
+ return { status: data.length, payload: data };
1555
+ }
1556
+ case Op.shutdown: {
1557
+ const description = socketDescription(proc.table.get(r.i32()));
1558
+ const how = r.u32();
1559
+ if (how > 2) throw new PosixError(Errno.EINVAL);
1560
+ description.shutdown(how === 0 || how === 2, how === 1 || how === 2);
1561
+ return { status: 0 };
1562
+ }
1563
+ case Op.getsockname: {
1564
+ const address = socketDescription(proc.table.get(r.i32())).localAddress();
1565
+ return { status: 0, payload: new Writer().string(address.address).u32(address.port).finish() };
1566
+ }
1567
+ case Op.getpeername: {
1568
+ const address = socketDescription(proc.table.get(r.i32())).peerAddress();
1569
+ return { status: 0, payload: new Writer().string(address.address).u32(address.port).finish() };
1570
+ }
1571
+ case Op.setsockopt: {
1572
+ const description = socketDescription(proc.table.get(r.i32()));
1573
+ description.setOption(r.u32(), r.u32(), r.bytes32());
1574
+ return { status: 0 };
1575
+ }
1576
+ case Op.getsockopt: {
1577
+ const description = socketDescription(proc.table.get(r.i32()));
1578
+ return { status: 0, payload: new Writer().bytes32(description.getOption(r.u32(), r.u32())).finish() };
1579
+ }
1330
1580
  default:
1331
1581
  return { status: failure(Errno.ENOSYS) };
1332
1582
  }
1333
1583
  }
1334
1584
  function implemented(capability) {
1335
- return ["files", "descriptors", "pipes", "readiness", "time", "identity", "entropy"].includes(capability);
1585
+ return ["files", "descriptors", "pipes", "readiness", "time", "identity", "entropy"].includes(capability) || capability === "sockets" && proc.sockets !== void 0;
1336
1586
  }
1337
1587
  function resolve2(path) {
1338
1588
  if (path.startsWith("/")) return proc.vfs.resolvePath(path);
@@ -1341,6 +1591,22 @@ function createHostAbiServer(proc) {
1341
1591
  function clamp(length) {
1342
1592
  return Math.min(length, MAX_TRANSFER);
1343
1593
  }
1594
+ function socketDescription(description) {
1595
+ if (!(description instanceof SocketDescription)) throw new PosixError(Errno.ENOTSOCK, "descriptor is not a socket");
1596
+ return description;
1597
+ }
1598
+ async function acceptBlocking(description) {
1599
+ for (; ; ) {
1600
+ try {
1601
+ return description.accept();
1602
+ } catch (error) {
1603
+ const posix = toPosixError(error);
1604
+ if (posix.errno !== Errno.EAGAIN || description.flags & O_NONBLOCK) throw posix;
1605
+ }
1606
+ await Promise.race([description.whenReady(), aborted()]);
1607
+ if (proc.signal.aborted) throw new PosixError(Errno.EINTR);
1608
+ }
1609
+ }
1344
1610
  async function readBlocking(description, length) {
1345
1611
  for (; ; ) {
1346
1612
  try {
@@ -1561,6 +1827,37 @@ var HostAbiClient = class {
1561
1827
  getrandom(length) {
1562
1828
  return this.call(Op.getrandom, new Writer().u32(length).finish()).payload;
1563
1829
  }
1830
+ socket(family, type, protocol = 0) {
1831
+ return this.call(Op.socket, new Writer().u32(family).u32(type).i32(protocol).finish()).status;
1832
+ }
1833
+ bind(fd, address, port) {
1834
+ this.call(Op.bind, new Writer().i32(fd).string(address).u32(port).finish());
1835
+ }
1836
+ listen(fd, backlog = 128) {
1837
+ this.call(Op.listen, new Writer().i32(fd).u32(backlog).finish());
1838
+ }
1839
+ accept(fd) {
1840
+ const result = this.call(Op.accept, new Writer().i32(fd).finish());
1841
+ const r = new Reader(result.payload);
1842
+ return { fd: result.status, address: r.string(), port: r.u32() };
1843
+ }
1844
+ connect(fd, address, port) {
1845
+ this.call(Op.connect, new Writer().i32(fd).string(address).u32(port).finish());
1846
+ }
1847
+ send(fd, data) {
1848
+ return this.call(Op.send, new Writer().i32(fd).bytes32(data).finish()).status;
1849
+ }
1850
+ recv(fd, length) {
1851
+ return this.call(Op.recv, new Writer().i32(fd).u32(length).finish()).payload;
1852
+ }
1853
+ shutdown(fd, how) {
1854
+ this.call(Op.shutdown, new Writer().i32(fd).u32(how).finish());
1855
+ }
1856
+ socketName(fd, peer = false) {
1857
+ const payload = this.call(peer ? Op.getpeername : Op.getsockname, new Writer().i32(fd).finish()).payload;
1858
+ const r = new Reader(payload);
1859
+ return { address: r.string(), port: r.u32() };
1860
+ }
1564
1861
  };
1565
1862
  function decodeStat(payload) {
1566
1863
  const r = new Reader(payload);