@ai-ecoverse/slicc-kernel 1.2.0 → 1.3.0
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 +22 -1
- package/dist/index.js +150 -2
- package/dist/index.js.map +3 -3
- package/dist/kernel-worker.js +2400 -419
- package/dist/kernel-worker.js.map +4 -4
- package/dist/process-worker.js +249 -12
- package/dist/process-worker.js.map +4 -4
- package/package.json +6 -4
package/dist/process-worker.js
CHANGED
|
@@ -56,6 +56,15 @@ var SIGNAL_BY_NAME = {
|
|
|
56
56
|
};
|
|
57
57
|
|
|
58
58
|
// src/fs/types.ts
|
|
59
|
+
function normalizePath(path) {
|
|
60
|
+
const parts = [];
|
|
61
|
+
for (const part of path.split("/")) {
|
|
62
|
+
if (part === "" || part === ".") continue;
|
|
63
|
+
if (part === "..") parts.pop();
|
|
64
|
+
else parts.push(part);
|
|
65
|
+
}
|
|
66
|
+
return `/${parts.join("/")}`;
|
|
67
|
+
}
|
|
59
68
|
function inodeOf(path) {
|
|
60
69
|
let h1 = 3735928559;
|
|
61
70
|
let h2 = 1103547991;
|
|
@@ -104,8 +113,8 @@ function toErrno(Fs, err) {
|
|
|
104
113
|
return err;
|
|
105
114
|
}
|
|
106
115
|
const code = err?.code;
|
|
107
|
-
const
|
|
108
|
-
return new Fs.ErrnoError(
|
|
116
|
+
const errno2 = typeof code === "string" ? ERRNO_BY_CODE[code] ?? EIO : EIO;
|
|
117
|
+
return new Fs.ErrnoError(errno2);
|
|
109
118
|
}
|
|
110
119
|
function liveNodePath(node) {
|
|
111
120
|
const parts = [];
|
|
@@ -495,8 +504,8 @@ function outermostDirs(dirs) {
|
|
|
495
504
|
}
|
|
496
505
|
function describeMountError(err) {
|
|
497
506
|
if (err instanceof Error) return err.message;
|
|
498
|
-
const
|
|
499
|
-
return typeof
|
|
507
|
+
const errno2 = err?.errno;
|
|
508
|
+
return typeof errno2 === "number" ? `errno ${errno2}` : String(err);
|
|
500
509
|
}
|
|
501
510
|
function mountLiveVfsDirs(Fs, bridge, dirs, warn) {
|
|
502
511
|
if (typeof Fs.filesystems !== "object" || !Fs.filesystems) {
|
|
@@ -620,8 +629,8 @@ function decodeSabResult(status2, payload) {
|
|
|
620
629
|
case SAB_STATUS_ERRNO: {
|
|
621
630
|
try {
|
|
622
631
|
const parsed = JSON.parse(decoder.decode(payload));
|
|
623
|
-
const
|
|
624
|
-
return { ok: false, errno, message: String(parsed.message ??
|
|
632
|
+
const errno2 = typeof parsed.errno === "string" && /^E[A-Z]+$/.test(parsed.errno) ? parsed.errno : "EIO";
|
|
633
|
+
return { ok: false, errno: errno2, message: String(parsed.message ?? errno2) };
|
|
625
634
|
} catch {
|
|
626
635
|
return { ok: false, errno: "EIO", message: "sync-sab: malformed errno payload" };
|
|
627
636
|
}
|
|
@@ -797,6 +806,7 @@ var WASI_ERRNO = {
|
|
|
797
806
|
EAFNOSUPPORT: 5,
|
|
798
807
|
EAGAIN: 6,
|
|
799
808
|
ECONNREFUSED: 14,
|
|
809
|
+
EEXIST: 20,
|
|
800
810
|
EINPROGRESS: 26,
|
|
801
811
|
EISCONN: 30,
|
|
802
812
|
ENETUNREACH: 40,
|
|
@@ -834,6 +844,7 @@ var POLLHUP = 16;
|
|
|
834
844
|
var POLLRDNORM = 64;
|
|
835
845
|
var POLLWRNORM = 256;
|
|
836
846
|
var O_NONBLOCK = 2048;
|
|
847
|
+
var SOCKET_MODE = 49663;
|
|
837
848
|
var PTY_PATH = /^\/dev\/(?:ptmx|pts\/(\d+))$/;
|
|
838
849
|
function isPtyPath(path) {
|
|
839
850
|
return PTY_PATH.test(path);
|
|
@@ -881,6 +892,8 @@ function nonblocking(stream) {
|
|
|
881
892
|
}
|
|
882
893
|
var KernelStreams = class {
|
|
883
894
|
refs = /* @__PURE__ */ new Map();
|
|
895
|
+
socketRoot;
|
|
896
|
+
sockets = 0;
|
|
884
897
|
Fs;
|
|
885
898
|
sys;
|
|
886
899
|
options;
|
|
@@ -896,6 +909,27 @@ var KernelStreams = class {
|
|
|
896
909
|
if (terminal ?? this.sys.isatty?.(kfd) ?? false) stream.tty = this.ttyOps(kfd);
|
|
897
910
|
else delete stream.tty;
|
|
898
911
|
}
|
|
912
|
+
attachSocket(stream, kfd) {
|
|
913
|
+
this.attach(stream, kfd, false);
|
|
914
|
+
stream.sliccKernelSocket = true;
|
|
915
|
+
}
|
|
916
|
+
socketStream(flags) {
|
|
917
|
+
const fs = this.Fs;
|
|
918
|
+
if (!fs.mount || !fs.createNode || !fs.createStream) {
|
|
919
|
+
const stream = this.Fs.open("/dev/null", 2);
|
|
920
|
+
stream.flags = flags;
|
|
921
|
+
return stream;
|
|
922
|
+
}
|
|
923
|
+
const createNode = fs.createNode;
|
|
924
|
+
this.socketRoot ??= fs.mount({ mount: () => createNode(null, "/", 16895, 0) }, {}, null);
|
|
925
|
+
const ino = ++this.sockets;
|
|
926
|
+
const node = fs.createNode(this.socketRoot, `socket:${ino}`, SOCKET_MODE, 0);
|
|
927
|
+
const now = /* @__PURE__ */ new Date();
|
|
928
|
+
const stat = { dev: 0, ino, mode: SOCKET_MODE, nlink: 1, uid: 0, gid: 0, rdev: 0, size: 0 };
|
|
929
|
+
const times = { atime: now, mtime: now, ctime: now, blksize: 4096, blocks: 0 };
|
|
930
|
+
node.node_ops = { getattr: () => ({ ...stat, ...times }) };
|
|
931
|
+
return fs.createStream({ node, flags, seekable: false, position: 0, stream_ops: {} });
|
|
932
|
+
}
|
|
899
933
|
nameTerminal(stream) {
|
|
900
934
|
const kfd = stream.sliccKernelFd;
|
|
901
935
|
if (!stream.tty || kfd === void 0) return;
|
|
@@ -1660,6 +1694,9 @@ function describeForFork(Fs, sys, streams, livePath) {
|
|
|
1660
1694
|
}
|
|
1661
1695
|
function kernelEntry(stream, kernel) {
|
|
1662
1696
|
const cloexec = closesOnExec(stream) ? { cloexec: true } : {};
|
|
1697
|
+
if (stream.sliccKernelSocket) {
|
|
1698
|
+
return { fd: stream.fd, kernel, kind: "socket", flags: stream.flags, ...cloexec };
|
|
1699
|
+
}
|
|
1663
1700
|
const kind = stream.sliccKernelFile ? "file" : stream.tty ? "tty" : "stream";
|
|
1664
1701
|
return { fd: stream.fd, kernel, kind, ...cloexec };
|
|
1665
1702
|
}
|
|
@@ -1701,7 +1738,8 @@ function inheritedSlot(fd, stream) {
|
|
|
1701
1738
|
const access = ACCESS[stream.flags & O_ACCMODE];
|
|
1702
1739
|
return { fd, device, ...access ? { access } : {} };
|
|
1703
1740
|
}
|
|
1704
|
-
|
|
1741
|
+
const flags = stream.sliccKernelSocket ? { flags: stream.flags } : {};
|
|
1742
|
+
return { fd, kernel: stream.sliccKernelFd, ...flags };
|
|
1705
1743
|
}
|
|
1706
1744
|
function place(Fs, stream, fd) {
|
|
1707
1745
|
if (stream.fd === fd) return stream;
|
|
@@ -1709,7 +1747,8 @@ function place(Fs, stream, fd) {
|
|
|
1709
1747
|
Fs.closeStream(stream.fd);
|
|
1710
1748
|
return moved;
|
|
1711
1749
|
}
|
|
1712
|
-
function placeholder(Fs, entry) {
|
|
1750
|
+
function placeholder(Fs, streams, entry) {
|
|
1751
|
+
if (entry.kind === "socket") return streams.socketStream(entry.flags ?? O_RDWR);
|
|
1713
1752
|
if (entry.kind === "tty") return Fs.open("/dev/tty", O_RDWR);
|
|
1714
1753
|
if (entry.kind === "stream") return Fs.open("/dev/null", O_RDWR);
|
|
1715
1754
|
Fs.mkdirTree(PLACEHOLDER_DIR);
|
|
@@ -1730,8 +1769,9 @@ function asFifo(stream, streams, identity) {
|
|
|
1730
1769
|
};
|
|
1731
1770
|
}
|
|
1732
1771
|
function placeKernelStream(Fs, streams, entry) {
|
|
1733
|
-
const stream = place(Fs, placeholder(Fs, entry), entry.fd);
|
|
1772
|
+
const stream = place(Fs, placeholder(Fs, streams, entry), entry.fd);
|
|
1734
1773
|
if (entry.kind === "file") streams.attachFile(stream, entry.kernel);
|
|
1774
|
+
else if (entry.kind === "socket") streams.attachSocket(stream, entry.kernel);
|
|
1735
1775
|
else streams.attach(stream, entry.kernel, entry.kind === "tty");
|
|
1736
1776
|
if (entry.kind === "tty") streams.nameTerminal(stream);
|
|
1737
1777
|
if (entry.kind === "stream") {
|
|
@@ -1759,6 +1799,40 @@ function restoreForkedStreams(Fs, streams, table) {
|
|
|
1759
1799
|
}
|
|
1760
1800
|
}
|
|
1761
1801
|
|
|
1802
|
+
// src/process/process-http.ts
|
|
1803
|
+
var HttpError = class extends Error {
|
|
1804
|
+
code;
|
|
1805
|
+
constructor(code, message) {
|
|
1806
|
+
super(message);
|
|
1807
|
+
this.code = code;
|
|
1808
|
+
}
|
|
1809
|
+
};
|
|
1810
|
+
function createHttpKernel(transport) {
|
|
1811
|
+
const call = (req) => {
|
|
1812
|
+
const r = transport.call(req, Number.POSITIVE_INFINITY, req.op);
|
|
1813
|
+
if (!r.ok) throw new HttpError(r.errno, r.message);
|
|
1814
|
+
return r;
|
|
1815
|
+
};
|
|
1816
|
+
return {
|
|
1817
|
+
request(req) {
|
|
1818
|
+
const r = call({
|
|
1819
|
+
op: "net-request",
|
|
1820
|
+
url: req.url,
|
|
1821
|
+
method: (req.method ?? "GET").toUpperCase(),
|
|
1822
|
+
headers: req.headers ?? [],
|
|
1823
|
+
...req.body ? { body: req.body } : {}
|
|
1824
|
+
});
|
|
1825
|
+
return r.json;
|
|
1826
|
+
},
|
|
1827
|
+
read(handle, max) {
|
|
1828
|
+
return call({ op: "net-read", handle, max }).bytes;
|
|
1829
|
+
},
|
|
1830
|
+
close(handle) {
|
|
1831
|
+
call({ op: "net-close", handle });
|
|
1832
|
+
}
|
|
1833
|
+
};
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1762
1836
|
// src/process/process-signals.ts
|
|
1763
1837
|
var SignalGate = class {
|
|
1764
1838
|
reported = { caught: 0, ignored: 0 };
|
|
@@ -1821,6 +1895,160 @@ var SignalGate = class {
|
|
|
1821
1895
|
}
|
|
1822
1896
|
};
|
|
1823
1897
|
|
|
1898
|
+
// src/process/process-sockets.ts
|
|
1899
|
+
var O_RDWR2 = 2;
|
|
1900
|
+
var KILLED_BY_SIGPIPE2 = 128 + 13;
|
|
1901
|
+
function errno(e) {
|
|
1902
|
+
if (e instanceof SyscallError) return -wasiErrno(e.code);
|
|
1903
|
+
const code = e?.errno;
|
|
1904
|
+
if (typeof code === "number") return -code;
|
|
1905
|
+
throw e;
|
|
1906
|
+
}
|
|
1907
|
+
var O_WRONLY = 1;
|
|
1908
|
+
var O_CREAT3 = 64;
|
|
1909
|
+
var O_EXCL3 = 128;
|
|
1910
|
+
function resolved(Fs, addr) {
|
|
1911
|
+
if (addr.family !== "unix" || !addr.path || addr.path.startsWith("\0")) return addr;
|
|
1912
|
+
const path = addr.path.startsWith("/") ? addr.path : `${Fs.cwd()}/${addr.path}`;
|
|
1913
|
+
return { family: "unix", path: normalizePath(path) };
|
|
1914
|
+
}
|
|
1915
|
+
function socketNode(Fs, addr) {
|
|
1916
|
+
if (addr.family !== "unix" || !addr.path || addr.path.startsWith("\0")) return void 0;
|
|
1917
|
+
const fs = Fs;
|
|
1918
|
+
let stream;
|
|
1919
|
+
try {
|
|
1920
|
+
stream = Fs.open(addr.path, O_WRONLY | O_CREAT3 | O_EXCL3, 493);
|
|
1921
|
+
} catch (e) {
|
|
1922
|
+
if (e?.errno === wasiErrno("EEXIST")) {
|
|
1923
|
+
throw new SyscallError("EADDRINUSE");
|
|
1924
|
+
}
|
|
1925
|
+
throw e;
|
|
1926
|
+
}
|
|
1927
|
+
if (Fs.close) Fs.close(stream);
|
|
1928
|
+
else Fs.closeStream(stream.fd);
|
|
1929
|
+
return { remove: () => fs.unlink?.(addr.path) };
|
|
1930
|
+
}
|
|
1931
|
+
function createSocketKernel(deps) {
|
|
1932
|
+
const { transport, Fs, sys, streams } = deps;
|
|
1933
|
+
const call = (req) => {
|
|
1934
|
+
const r = transport.call(req, Number.POSITIVE_INFINITY, req.op);
|
|
1935
|
+
if (!r.ok) throw new SyscallError(r.errno);
|
|
1936
|
+
return r;
|
|
1937
|
+
};
|
|
1938
|
+
const json = (req) => {
|
|
1939
|
+
const r = call(req);
|
|
1940
|
+
return r.ok && r.kind === "json" ? r.json : void 0;
|
|
1941
|
+
};
|
|
1942
|
+
const done = (req) => {
|
|
1943
|
+
call(req);
|
|
1944
|
+
return 0;
|
|
1945
|
+
};
|
|
1946
|
+
const guard = (op) => {
|
|
1947
|
+
for (; ; ) {
|
|
1948
|
+
try {
|
|
1949
|
+
return op();
|
|
1950
|
+
} catch (e) {
|
|
1951
|
+
const restart = e instanceof SyscallError && e.code === "EINTR" && deps.restartable?.();
|
|
1952
|
+
if (!restart) return errno(e);
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
};
|
|
1956
|
+
const socketAt = (fd) => {
|
|
1957
|
+
const stream = Fs.getStream(fd);
|
|
1958
|
+
if (!stream) throw new SyscallError("EBADF");
|
|
1959
|
+
if (!stream.sliccKernelSocket || stream.sliccKernelFd === void 0) {
|
|
1960
|
+
throw new SyscallError("ENOTSOCK");
|
|
1961
|
+
}
|
|
1962
|
+
return stream;
|
|
1963
|
+
};
|
|
1964
|
+
const kfd = (fd) => socketAt(fd).sliccKernelFd;
|
|
1965
|
+
const install = (k, nonblock, cloexec = false) => {
|
|
1966
|
+
let stream;
|
|
1967
|
+
try {
|
|
1968
|
+
stream = streams.socketStream(O_RDWR2 | (nonblock ? O_NONBLOCK : 0));
|
|
1969
|
+
} catch (e) {
|
|
1970
|
+
sys.close(k);
|
|
1971
|
+
throw e;
|
|
1972
|
+
}
|
|
1973
|
+
streams.attachSocket(stream, k);
|
|
1974
|
+
setCloseOnExec(stream, cloexec);
|
|
1975
|
+
return stream.fd;
|
|
1976
|
+
};
|
|
1977
|
+
return {
|
|
1978
|
+
socket: (domain, nonblock, cloexec) => guard(() => install(json({ op: "sock-open", domain }), nonblock, cloexec)),
|
|
1979
|
+
socketpair: (domain, nonblock, cloexec) => guard(() => {
|
|
1980
|
+
const [a, b] = json({ op: "sock-pair", domain });
|
|
1981
|
+
let first;
|
|
1982
|
+
try {
|
|
1983
|
+
first = install(a, nonblock, cloexec);
|
|
1984
|
+
} catch (e) {
|
|
1985
|
+
sys.close(b);
|
|
1986
|
+
throw e;
|
|
1987
|
+
}
|
|
1988
|
+
try {
|
|
1989
|
+
return [first, install(b, nonblock, cloexec)];
|
|
1990
|
+
} catch (e) {
|
|
1991
|
+
const stream = Fs.getStream(first);
|
|
1992
|
+
if (stream) stream.stream_ops.close?.(stream);
|
|
1993
|
+
Fs.closeStream(first);
|
|
1994
|
+
throw e;
|
|
1995
|
+
}
|
|
1996
|
+
}),
|
|
1997
|
+
bind: (fd, given) => guard(() => {
|
|
1998
|
+
const addr = resolved(Fs, given);
|
|
1999
|
+
const node = socketNode(Fs, addr);
|
|
2000
|
+
try {
|
|
2001
|
+
return done({ op: "sock-bind", fd: kfd(fd), addr });
|
|
2002
|
+
} catch (e) {
|
|
2003
|
+
node?.remove();
|
|
2004
|
+
throw e;
|
|
2005
|
+
}
|
|
2006
|
+
}),
|
|
2007
|
+
listen: (fd, backlog) => guard(() => done({ op: "sock-listen", fd: kfd(fd), backlog })),
|
|
2008
|
+
accept: (fd, nonblock, cloexec) => guard(() => {
|
|
2009
|
+
const listener = socketAt(fd);
|
|
2010
|
+
const req = {
|
|
2011
|
+
op: "sock-accept",
|
|
2012
|
+
fd: listener.sliccKernelFd,
|
|
2013
|
+
nonblock: (listener.flags & O_NONBLOCK) !== 0
|
|
2014
|
+
};
|
|
2015
|
+
const got = json(req);
|
|
2016
|
+
return { fd: install(got.fd, nonblock, cloexec), peer: got.peer };
|
|
2017
|
+
}),
|
|
2018
|
+
connect: (fd, addr) => guard(() => {
|
|
2019
|
+
const stream = socketAt(fd);
|
|
2020
|
+
const nonblock = (stream.flags & O_NONBLOCK) !== 0;
|
|
2021
|
+
return done({
|
|
2022
|
+
op: "sock-connect",
|
|
2023
|
+
fd: stream.sliccKernelFd,
|
|
2024
|
+
addr: resolved(Fs, addr),
|
|
2025
|
+
nonblock
|
|
2026
|
+
});
|
|
2027
|
+
}),
|
|
2028
|
+
shutdown: (fd, how) => guard(() => done({ op: "sock-shutdown", fd: kfd(fd), how })),
|
|
2029
|
+
name: (fd, peer) => guard(() => json({ op: "sock-name", fd: kfd(fd), peer })),
|
|
2030
|
+
getopt: (fd, level, name) => guard(() => ({ value: json({ op: "sock-getopt", fd: kfd(fd), level, name }) })),
|
|
2031
|
+
setopt: (fd, level, name, value) => guard(() => done({ op: "sock-setopt", fd: kfd(fd), level, name, value })),
|
|
2032
|
+
send: (fd, bytes, flags) => guard(() => {
|
|
2033
|
+
const stream = socketAt(fd);
|
|
2034
|
+
const nonblock = flags.dontwait === true || (stream.flags & O_NONBLOCK) !== 0;
|
|
2035
|
+
try {
|
|
2036
|
+
return sys.write(stream.sliccKernelFd, bytes, { nonblock });
|
|
2037
|
+
} catch (e) {
|
|
2038
|
+
const broken = e instanceof SyscallError && e.code === "EPIPE";
|
|
2039
|
+
if (broken && !flags.nosignal && !deps.sigpipe?.())
|
|
2040
|
+
throw new ProcessExit(KILLED_BY_SIGPIPE2);
|
|
2041
|
+
throw e;
|
|
2042
|
+
}
|
|
2043
|
+
}),
|
|
2044
|
+
recv: (fd, max, flags) => guard(() => {
|
|
2045
|
+
const stream = socketAt(fd);
|
|
2046
|
+
const nonblock = flags.dontwait === true || (stream.flags & O_NONBLOCK) !== 0;
|
|
2047
|
+
return sys.read(stream.sliccKernelFd, max, { nonblock, peek: flags.peek === true });
|
|
2048
|
+
})
|
|
2049
|
+
};
|
|
2050
|
+
}
|
|
2051
|
+
|
|
1824
2052
|
// src/process/realm-user.ts
|
|
1825
2053
|
var REALM_UID = 1e3;
|
|
1826
2054
|
var REALM_GID = 1e3;
|
|
@@ -1950,10 +2178,10 @@ function wireKernelFd(Fs, streams, entry) {
|
|
|
1950
2178
|
});
|
|
1951
2179
|
}
|
|
1952
2180
|
var O_RDONLY = 0;
|
|
1953
|
-
var
|
|
1954
|
-
var
|
|
2181
|
+
var O_WRONLY2 = 1;
|
|
2182
|
+
var O_RDWR3 = 2;
|
|
1955
2183
|
function openDevice(Fs, fd, meta) {
|
|
1956
|
-
const flags = meta.access === "read" ? O_RDONLY : meta.access === "write" ?
|
|
2184
|
+
const flags = meta.access === "read" ? O_RDONLY : meta.access === "write" ? O_WRONLY2 : O_RDWR3;
|
|
1957
2185
|
let stream;
|
|
1958
2186
|
try {
|
|
1959
2187
|
stream = Fs.open(`/dev/${meta.device}`, flags);
|
|
@@ -2147,6 +2375,15 @@ async function runWasmProcess(init, port, deps = {}) {
|
|
|
2147
2375
|
inherit: (actions) => describeInherited(running.FS, sys, streams, livePath, actions),
|
|
2148
2376
|
stdioPromoter: () => vfsPromoter(running.FS, sys, streams, livePath)
|
|
2149
2377
|
});
|
|
2378
|
+
running.sliccKernel.http = createHttpKernel(transport);
|
|
2379
|
+
running.sliccKernel.net = createSocketKernel({
|
|
2380
|
+
transport,
|
|
2381
|
+
Fs: running.FS,
|
|
2382
|
+
sys,
|
|
2383
|
+
streams,
|
|
2384
|
+
sigpipe,
|
|
2385
|
+
restartable
|
|
2386
|
+
});
|
|
2150
2387
|
try {
|
|
2151
2388
|
return runMain(running, init);
|
|
2152
2389
|
} finally {
|