@ai-ecoverse/slicc-kernel 1.26.6 → 1.28.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 +62 -4
- package/dist/driver-worker.js +1 -1
- package/dist/driver-worker.js.map +1 -1
- package/dist/index.js +221 -12
- package/dist/index.js.map +4 -4
- package/dist/kernel-worker.js +634 -51
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-driver-worker.js +1 -1
- package/dist/node-driver-worker.js.map +1 -1
- package/dist/node-process-worker.js +89 -20
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +547 -49
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +89 -20
- package/dist/process-worker.js.map +4 -4
- package/dist/testing.js +223 -0
- package/dist/testing.js.map +7 -0
- package/package.json +4 -3
package/dist/node.js
CHANGED
|
@@ -465,6 +465,170 @@ var FdTable = class _FdTable {
|
|
|
465
465
|
}
|
|
466
466
|
};
|
|
467
467
|
|
|
468
|
+
// src/process/wasi/wasi-abi.ts
|
|
469
|
+
var E = {
|
|
470
|
+
SUCCESS: 0,
|
|
471
|
+
"2BIG": 1,
|
|
472
|
+
ACCES: 2,
|
|
473
|
+
ADDRINUSE: 3,
|
|
474
|
+
ADDRNOTAVAIL: 4,
|
|
475
|
+
AFNOSUPPORT: 5,
|
|
476
|
+
AGAIN: 6,
|
|
477
|
+
ALREADY: 7,
|
|
478
|
+
BADF: 8,
|
|
479
|
+
BADMSG: 9,
|
|
480
|
+
BUSY: 10,
|
|
481
|
+
CANCELED: 11,
|
|
482
|
+
CHILD: 12,
|
|
483
|
+
CONNABORTED: 13,
|
|
484
|
+
CONNREFUSED: 14,
|
|
485
|
+
CONNRESET: 15,
|
|
486
|
+
DEADLK: 16,
|
|
487
|
+
DESTADDRREQ: 17,
|
|
488
|
+
DOM: 18,
|
|
489
|
+
DQUOT: 19,
|
|
490
|
+
EXIST: 20,
|
|
491
|
+
FAULT: 21,
|
|
492
|
+
FBIG: 22,
|
|
493
|
+
HOSTUNREACH: 23,
|
|
494
|
+
IDRM: 24,
|
|
495
|
+
ILSEQ: 25,
|
|
496
|
+
INPROGRESS: 26,
|
|
497
|
+
INTR: 27,
|
|
498
|
+
INVAL: 28,
|
|
499
|
+
IO: 29,
|
|
500
|
+
ISCONN: 30,
|
|
501
|
+
ISDIR: 31,
|
|
502
|
+
LOOP: 32,
|
|
503
|
+
MFILE: 33,
|
|
504
|
+
MLINK: 34,
|
|
505
|
+
MSGSIZE: 35,
|
|
506
|
+
MULTIHOP: 36,
|
|
507
|
+
NAMETOOLONG: 37,
|
|
508
|
+
NETDOWN: 38,
|
|
509
|
+
NETRESET: 39,
|
|
510
|
+
NETUNREACH: 40,
|
|
511
|
+
NFILE: 41,
|
|
512
|
+
NOBUFS: 42,
|
|
513
|
+
NODEV: 43,
|
|
514
|
+
NOENT: 44,
|
|
515
|
+
NOEXEC: 45,
|
|
516
|
+
NOLCK: 46,
|
|
517
|
+
NOLINK: 47,
|
|
518
|
+
NOMEM: 48,
|
|
519
|
+
NOMSG: 49,
|
|
520
|
+
NOPROTOOPT: 50,
|
|
521
|
+
NOSPC: 51,
|
|
522
|
+
NOSYS: 52,
|
|
523
|
+
NOTCONN: 53,
|
|
524
|
+
NOTDIR: 54,
|
|
525
|
+
NOTEMPTY: 55,
|
|
526
|
+
NOTRECOVERABLE: 56,
|
|
527
|
+
NOTSOCK: 57,
|
|
528
|
+
NOTSUP: 58,
|
|
529
|
+
NOTTY: 59,
|
|
530
|
+
NXIO: 60,
|
|
531
|
+
OVERFLOW: 61,
|
|
532
|
+
OWNERDEAD: 62,
|
|
533
|
+
PERM: 63,
|
|
534
|
+
PIPE: 64,
|
|
535
|
+
PROTO: 65,
|
|
536
|
+
PROTONOSUPPORT: 66,
|
|
537
|
+
PROTOTYPE: 67,
|
|
538
|
+
RANGE: 68,
|
|
539
|
+
ROFS: 69,
|
|
540
|
+
SPIPE: 70,
|
|
541
|
+
SRCH: 71,
|
|
542
|
+
STALE: 72,
|
|
543
|
+
TIMEDOUT: 73,
|
|
544
|
+
TXTBSY: 74,
|
|
545
|
+
XDEV: 75,
|
|
546
|
+
NOTCAPABLE: 76
|
|
547
|
+
};
|
|
548
|
+
var RIGHTS = {
|
|
549
|
+
FD_DATASYNC: 1n << 0n,
|
|
550
|
+
FD_READ: 1n << 1n,
|
|
551
|
+
FD_SEEK: 1n << 2n,
|
|
552
|
+
FD_FDSTAT_SET_FLAGS: 1n << 3n,
|
|
553
|
+
FD_SYNC: 1n << 4n,
|
|
554
|
+
FD_TELL: 1n << 5n,
|
|
555
|
+
FD_WRITE: 1n << 6n,
|
|
556
|
+
ALL: (1n << 30n) - 1n
|
|
557
|
+
};
|
|
558
|
+
var WASI_SIGNAL_TO_POSIX = Object.fromEntries(
|
|
559
|
+
Array.from({ length: 30 }, (_, i) => [i + 1, i + 1 < 16 ? i + 1 : i + 2])
|
|
560
|
+
);
|
|
561
|
+
|
|
562
|
+
// src/process/wasi-errno.ts
|
|
563
|
+
var WASI_ERRNO = {
|
|
564
|
+
...Object.fromEntries(Object.entries(E).map(([name2, errno]) => [`E${name2}`, errno])),
|
|
565
|
+
EWOULDBLOCK: E.AGAIN,
|
|
566
|
+
ENOTSUP: 138,
|
|
567
|
+
EOPNOTSUPP: 138,
|
|
568
|
+
ENOMEDIUM: 148
|
|
569
|
+
};
|
|
570
|
+
function wasiErrno(code) {
|
|
571
|
+
return WASI_ERRNO[code] ?? E.IO;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// src/kernel/net/uplink-socket.ts
|
|
575
|
+
var CHUNK = 64 * 1024;
|
|
576
|
+
function hostPort(text) {
|
|
577
|
+
const match = /^\[?([^\]]*?)\]?:(\d{1,5})$/.exec(text);
|
|
578
|
+
const port = Number(match?.[2]);
|
|
579
|
+
const host = match?.[1];
|
|
580
|
+
if (!host || port > 65535) return void 0;
|
|
581
|
+
return { host, port };
|
|
582
|
+
}
|
|
583
|
+
async function inbound(conn, rx) {
|
|
584
|
+
for (; ; ) {
|
|
585
|
+
while (!rx.writeReady) await rx.changed();
|
|
586
|
+
if (rx.readersGone) return;
|
|
587
|
+
const bytes = await conn.read();
|
|
588
|
+
if (!bytes) return;
|
|
589
|
+
await rx.write(bytes);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
async function outbound(conn, tx) {
|
|
593
|
+
for (; ; ) {
|
|
594
|
+
const bytes = await tx.read(CHUNK);
|
|
595
|
+
if (bytes.length === 0) {
|
|
596
|
+
conn.closeWrite();
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
for (let at = 0; at < bytes.length; ) {
|
|
600
|
+
const n = await conn.write(bytes.subarray(at));
|
|
601
|
+
if (!(n > 0)) throw new Error("the uplink wrote nothing");
|
|
602
|
+
at += n;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
async function released(rx, tx) {
|
|
607
|
+
while (!(rx.readersGone && tx.writersGone)) await Promise.race([rx.changed(), tx.changed()]);
|
|
608
|
+
}
|
|
609
|
+
function uplinkLink(conn, onReset) {
|
|
610
|
+
const rx = new KernelPipe();
|
|
611
|
+
const tx = new KernelPipe();
|
|
612
|
+
for (const pipe of [rx, tx]) {
|
|
613
|
+
pipe.openRead();
|
|
614
|
+
pipe.openWrite();
|
|
615
|
+
}
|
|
616
|
+
let open = true;
|
|
617
|
+
const close = () => {
|
|
618
|
+
if (!open) return;
|
|
619
|
+
open = false;
|
|
620
|
+
conn.close();
|
|
621
|
+
};
|
|
622
|
+
void inbound(conn, rx).catch(() => {
|
|
623
|
+
onReset();
|
|
624
|
+
close();
|
|
625
|
+
tx.closeRead();
|
|
626
|
+
}).finally(() => rx.closeWrite());
|
|
627
|
+
void outbound(conn, tx).catch(close).finally(() => tx.closeRead());
|
|
628
|
+
void released(rx, tx).then(close);
|
|
629
|
+
return { rx, tx };
|
|
630
|
+
}
|
|
631
|
+
|
|
468
632
|
// src/kernel/socket.ts
|
|
469
633
|
var SOMAXCONN = 4096;
|
|
470
634
|
var EPHEMERAL_FIRST = 32768;
|
|
@@ -482,6 +646,21 @@ var AF_INET = 2;
|
|
|
482
646
|
var SHUT_RD = 0;
|
|
483
647
|
var SHUT_WR = 1;
|
|
484
648
|
var SHUT_RDWR = 2;
|
|
649
|
+
var DIAL_TIMEOUT_MS = 3e4;
|
|
650
|
+
var DIAL_ERRORS = [
|
|
651
|
+
"ECONNREFUSED",
|
|
652
|
+
"ENETUNREACH",
|
|
653
|
+
"EHOSTUNREACH",
|
|
654
|
+
"ETIMEDOUT",
|
|
655
|
+
"ECONNRESET"
|
|
656
|
+
];
|
|
657
|
+
function dialError(e, timedOut, closed) {
|
|
658
|
+
if (timedOut) return new KernelError("ETIMEDOUT");
|
|
659
|
+
if (closed) return new KernelError("ECONNABORTED");
|
|
660
|
+
const code = e?.code;
|
|
661
|
+
const known = DIAL_ERRORS.find((errno) => errno === code);
|
|
662
|
+
return new KernelError(known ?? "EHOSTUNREACH");
|
|
663
|
+
}
|
|
485
664
|
function isLoopback(host) {
|
|
486
665
|
return /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(host);
|
|
487
666
|
}
|
|
@@ -530,6 +709,9 @@ var KernelSocket = class _KernelSocket {
|
|
|
530
709
|
net;
|
|
531
710
|
domain;
|
|
532
711
|
state = "open";
|
|
712
|
+
dialing;
|
|
713
|
+
failed;
|
|
714
|
+
reset = false;
|
|
533
715
|
local;
|
|
534
716
|
peer;
|
|
535
717
|
link;
|
|
@@ -537,7 +719,7 @@ var KernelSocket = class _KernelSocket {
|
|
|
537
719
|
writeShut = false;
|
|
538
720
|
queue = [];
|
|
539
721
|
backlog = 0;
|
|
540
|
-
|
|
722
|
+
boundAt;
|
|
541
723
|
changes = new Changes();
|
|
542
724
|
options = /* @__PURE__ */ new Map();
|
|
543
725
|
constructor(net, domain) {
|
|
@@ -559,12 +741,16 @@ var KernelSocket = class _KernelSocket {
|
|
|
559
741
|
async read(max, signal) {
|
|
560
742
|
const { rx } = this.connection();
|
|
561
743
|
if (this.readShut || max <= 0) return new Uint8Array(0);
|
|
562
|
-
|
|
744
|
+
const bytes = await pipeCall(() => rx.read(max, signal));
|
|
745
|
+
if (bytes.length === 0 && this.reset) throw new KernelError("ECONNRESET");
|
|
746
|
+
return bytes;
|
|
563
747
|
}
|
|
564
748
|
async peek(max, signal) {
|
|
565
749
|
const { rx } = this.connection();
|
|
566
750
|
if (this.readShut || max <= 0) return new Uint8Array(0);
|
|
567
|
-
|
|
751
|
+
const bytes = await pipeCall(() => rx.peek(max, signal));
|
|
752
|
+
if (bytes.length === 0 && this.reset) throw new KernelError("ECONNRESET");
|
|
753
|
+
return bytes;
|
|
568
754
|
}
|
|
569
755
|
async write(bytes, signal) {
|
|
570
756
|
const { tx } = this.connection();
|
|
@@ -575,6 +761,8 @@ var KernelSocket = class _KernelSocket {
|
|
|
575
761
|
if (this.state === "listening") {
|
|
576
762
|
return { readable: this.queue.length > 0, writable: false, hangup: false };
|
|
577
763
|
}
|
|
764
|
+
if (this.state === "connecting") return { readable: false, writable: false, hangup: false };
|
|
765
|
+
if (this.failed) return { readable: true, writable: true, hangup: true };
|
|
578
766
|
if (this.state !== "connected" || !this.link) {
|
|
579
767
|
return { readable: false, writable: false, hangup: true };
|
|
580
768
|
}
|
|
@@ -596,7 +784,7 @@ var KernelSocket = class _KernelSocket {
|
|
|
596
784
|
if (this.state !== "open" || this.local) throw new KernelError("EINVAL");
|
|
597
785
|
if (addr.family !== this.domain) throw new KernelError("EAFNOSUPPORT");
|
|
598
786
|
this.local = this.net.bind(this, addr);
|
|
599
|
-
this.
|
|
787
|
+
this.boundAt = this.local;
|
|
600
788
|
}
|
|
601
789
|
listen(backlog) {
|
|
602
790
|
if (this.state === "connected") throw new KernelError("EISCONN");
|
|
@@ -623,15 +811,19 @@ var KernelSocket = class _KernelSocket {
|
|
|
623
811
|
this.changes.wake();
|
|
624
812
|
return true;
|
|
625
813
|
}
|
|
626
|
-
connect(addr) {
|
|
814
|
+
connect(addr, viaUplink = true) {
|
|
627
815
|
if (this.state === "connected") throw new KernelError("EISCONN");
|
|
816
|
+
if (this.state === "connecting") throw new KernelError("EALREADY");
|
|
628
817
|
if (this.state !== "open") throw new KernelError("EINVAL");
|
|
629
818
|
if (addr.family !== this.domain) throw new KernelError("EAFNOSUPPORT");
|
|
819
|
+
this.failed = void 0;
|
|
820
|
+
const route = viaUplink && addr.family === "inet" ? this.net.uplinkFor(addr.host) : void 0;
|
|
821
|
+
if (route) return this.dial(addr, route);
|
|
630
822
|
const target = this.net.target(addr);
|
|
631
823
|
if (!this.local) {
|
|
632
824
|
if (addr.family === "inet") {
|
|
633
825
|
this.local = this.net.bind(this, { family: "inet", host: "127.0.0.1", port: 0 });
|
|
634
|
-
this.
|
|
826
|
+
this.boundAt = this.local;
|
|
635
827
|
} else this.local = { family: "unix", path: "" };
|
|
636
828
|
}
|
|
637
829
|
const server = new _KernelSocket(this.net, this.domain);
|
|
@@ -644,6 +836,52 @@ var KernelSocket = class _KernelSocket {
|
|
|
644
836
|
server.close();
|
|
645
837
|
throw new KernelError("ECONNREFUSED");
|
|
646
838
|
}
|
|
839
|
+
return void 0;
|
|
840
|
+
}
|
|
841
|
+
dial(addr, route) {
|
|
842
|
+
this.state = "connecting";
|
|
843
|
+
const abort = new AbortController();
|
|
844
|
+
this.dialing = abort;
|
|
845
|
+
let timedOut = false;
|
|
846
|
+
const timer = setTimeout(() => {
|
|
847
|
+
timedOut = true;
|
|
848
|
+
abort.abort(new KernelError("ETIMEDOUT"));
|
|
849
|
+
}, route.timeoutMs ?? DIAL_TIMEOUT_MS);
|
|
850
|
+
const abandoned = new Promise((_, reject) => {
|
|
851
|
+
abort.signal.addEventListener("abort", () => reject(abort.signal.reason), { once: true });
|
|
852
|
+
});
|
|
853
|
+
const { host, port } = addr;
|
|
854
|
+
const dialled = new Promise(
|
|
855
|
+
(resolve) => resolve(route.uplink.dial({ network: "tcp", host, port, signal: abort.signal }))
|
|
856
|
+
);
|
|
857
|
+
dialled.then(
|
|
858
|
+
(conn) => abort.signal.aborted && conn.close(),
|
|
859
|
+
() => void 0
|
|
860
|
+
);
|
|
861
|
+
return Promise.race([dialled, abandoned]).then(
|
|
862
|
+
(conn) => {
|
|
863
|
+
if (abort.signal.aborted) throw dialError(abort.signal.reason, timedOut, true);
|
|
864
|
+
this.local = { family: "inet", host: "0.0.0.0", port: 0, ...hostPort(conn.localAddr) };
|
|
865
|
+
this.peer = { ...addr, ...hostPort(conn.remoteAddr) };
|
|
866
|
+
this.dialing = void 0;
|
|
867
|
+
this.attach(
|
|
868
|
+
uplinkLink(conn, () => {
|
|
869
|
+
this.reset = true;
|
|
870
|
+
this.changes.wake();
|
|
871
|
+
})
|
|
872
|
+
);
|
|
873
|
+
},
|
|
874
|
+
(e) => {
|
|
875
|
+
const error = dialError(e, timedOut, abort.signal.aborted);
|
|
876
|
+
if (this.dialing === abort) {
|
|
877
|
+
this.dialing = void 0;
|
|
878
|
+
this.failed = error.code;
|
|
879
|
+
this.state = "open";
|
|
880
|
+
this.changes.wake();
|
|
881
|
+
}
|
|
882
|
+
throw error;
|
|
883
|
+
}
|
|
884
|
+
).finally(() => clearTimeout(timer));
|
|
647
885
|
}
|
|
648
886
|
unlink() {
|
|
649
887
|
const link2 = this.link;
|
|
@@ -673,8 +911,11 @@ var KernelSocket = class _KernelSocket {
|
|
|
673
911
|
switch (name2) {
|
|
674
912
|
case SO_TYPE:
|
|
675
913
|
return SOCK_STREAM;
|
|
676
|
-
case SO_ERROR:
|
|
677
|
-
|
|
914
|
+
case SO_ERROR: {
|
|
915
|
+
const failed = this.failed;
|
|
916
|
+
this.failed = void 0;
|
|
917
|
+
return failed ? wasiErrno(failed) : 0;
|
|
918
|
+
}
|
|
678
919
|
case SO_ACCEPTCONN:
|
|
679
920
|
return this.state === "listening" ? 1 : 0;
|
|
680
921
|
case SO_DOMAIN:
|
|
@@ -692,6 +933,8 @@ var KernelSocket = class _KernelSocket {
|
|
|
692
933
|
close() {
|
|
693
934
|
const was = this.state;
|
|
694
935
|
this.state = "closed";
|
|
936
|
+
this.dialing?.abort(new KernelError("ECONNABORTED"));
|
|
937
|
+
this.dialing = void 0;
|
|
695
938
|
if (was === "listening") {
|
|
696
939
|
for (const pending of this.queue.splice(0)) pending.close();
|
|
697
940
|
}
|
|
@@ -701,8 +944,8 @@ var KernelSocket = class _KernelSocket {
|
|
|
701
944
|
this.readShut = true;
|
|
702
945
|
this.writeShut = true;
|
|
703
946
|
}
|
|
704
|
-
if (this.
|
|
705
|
-
this.
|
|
947
|
+
if (this.boundAt) this.net.release(this.boundAt, this);
|
|
948
|
+
this.boundAt = void 0;
|
|
706
949
|
this.changes.wake();
|
|
707
950
|
}
|
|
708
951
|
static pair(net, domain) {
|
|
@@ -725,6 +968,15 @@ var LoopbackNet = class {
|
|
|
725
968
|
activators = /* @__PURE__ */ new Map();
|
|
726
969
|
internal = /* @__PURE__ */ new Set();
|
|
727
970
|
nextEphemeral = EPHEMERAL_FIRST;
|
|
971
|
+
route;
|
|
972
|
+
useUplink(route) {
|
|
973
|
+
this.route = route;
|
|
974
|
+
}
|
|
975
|
+
uplinkFor(host) {
|
|
976
|
+
const route = this.route;
|
|
977
|
+
if (!route) return void 0;
|
|
978
|
+
return route.routes.classify(host) === "uplink" ? route : void 0;
|
|
979
|
+
}
|
|
728
980
|
kernelOnly(port, reserve = false) {
|
|
729
981
|
if (reserve) this.internal.add(port);
|
|
730
982
|
return this.internal.has(port);
|
|
@@ -743,7 +995,7 @@ var LoopbackNet = class {
|
|
|
743
995
|
}
|
|
744
996
|
connect(addr) {
|
|
745
997
|
const socket = this.socket(addr.family);
|
|
746
|
-
socket.connect(addr);
|
|
998
|
+
void socket.connect(addr, false);
|
|
747
999
|
return socket;
|
|
748
1000
|
}
|
|
749
1001
|
bind(socket, addr) {
|
|
@@ -784,7 +1036,7 @@ var LoopbackNet = class {
|
|
|
784
1036
|
};
|
|
785
1037
|
|
|
786
1038
|
// src/kernel/dial.ts
|
|
787
|
-
var
|
|
1039
|
+
var CHUNK2 = 64 * 1024;
|
|
788
1040
|
var LOOPBACK_NAMES = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "::1", "[::1]"]);
|
|
789
1041
|
function dialSocket(net, port, host = "127.0.0.1") {
|
|
790
1042
|
if (!Number.isInteger(port) || port < 1 || port > 65535) throw new KernelError("EINVAL");
|
|
@@ -849,7 +1101,7 @@ function serveSocket(socket, port, onClose) {
|
|
|
849
1101
|
for (; ; ) {
|
|
850
1102
|
await turn();
|
|
851
1103
|
if (closed) return;
|
|
852
|
-
const chunk2 = await socket.read(
|
|
1104
|
+
const chunk2 = await socket.read(CHUNK2);
|
|
853
1105
|
if (chunk2.length === 0) break;
|
|
854
1106
|
credit--;
|
|
855
1107
|
send(chunk2, [chunk2.buffer]);
|
|
@@ -1084,7 +1336,7 @@ function serveTransport(peer, transport) {
|
|
|
1084
1336
|
}
|
|
1085
1337
|
|
|
1086
1338
|
// src/client/protocol.ts
|
|
1087
|
-
var PROTOCOL = [1,
|
|
1339
|
+
var PROTOCOL = [1, 7];
|
|
1088
1340
|
var FS_METHODS = [
|
|
1089
1341
|
"readFile",
|
|
1090
1342
|
"writeFile",
|
|
@@ -4491,6 +4743,7 @@ async function hostSyscall(req, ctx) {
|
|
|
4491
4743
|
|
|
4492
4744
|
// src/kernel/net/loopback-names.ts
|
|
4493
4745
|
var HOST_LOOPBACK = "host.slicc.internal";
|
|
4746
|
+
var HOST_LOOPBACK_ADDRESS = [10, 0, 2, 2];
|
|
4494
4747
|
var PAGE_LOOPBACK = "kernel.localhost";
|
|
4495
4748
|
var PAGE_LOOPBACK_URL = `http://{port}.${PAGE_LOOPBACK}`;
|
|
4496
4749
|
function toHostLoopback(href) {
|
|
@@ -5687,6 +5940,215 @@ var HttpHandles = class {
|
|
|
5687
5940
|
}
|
|
5688
5941
|
};
|
|
5689
5942
|
|
|
5943
|
+
// src/kernel/net/routes.ts
|
|
5944
|
+
var HOST_ADDRESS = HOST_LOOPBACK_ADDRESS.join(".");
|
|
5945
|
+
function ipv4Bytes(text) {
|
|
5946
|
+
const parts = text.split(".");
|
|
5947
|
+
if (parts.length !== 4 || !parts.every((p) => /^\d{1,3}$/.test(p))) return void 0;
|
|
5948
|
+
const bytes = parts.map(Number);
|
|
5949
|
+
return bytes.every((b) => b <= 255) ? bytes : void 0;
|
|
5950
|
+
}
|
|
5951
|
+
function ipv6Groups(text) {
|
|
5952
|
+
if (!text.includes(":")) return void 0;
|
|
5953
|
+
let canonical;
|
|
5954
|
+
try {
|
|
5955
|
+
canonical = new URL(`http://[${text}]/`).hostname.slice(1, -1);
|
|
5956
|
+
} catch {
|
|
5957
|
+
return void 0;
|
|
5958
|
+
}
|
|
5959
|
+
const [head, tail] = canonical.split("::");
|
|
5960
|
+
const part = (s) => s ? s.split(":").map((h) => Number.parseInt(h, 16)) : [];
|
|
5961
|
+
const front = part(head);
|
|
5962
|
+
const back = part(tail);
|
|
5963
|
+
return tail === void 0 ? front : [...front, ...new Array(8 - front.length - back.length).fill(0), ...back];
|
|
5964
|
+
}
|
|
5965
|
+
function toBits(values, width) {
|
|
5966
|
+
return values.reduce((acc, v) => acc << BigInt(width) | BigInt(v), 0n);
|
|
5967
|
+
}
|
|
5968
|
+
function addressBits(host) {
|
|
5969
|
+
const v4 = ipv4Bytes(host);
|
|
5970
|
+
if (v4) return { v6: false, bits: toBits(v4, 8) };
|
|
5971
|
+
const v6 = ipv6Groups(host);
|
|
5972
|
+
return v6 ? { v6: true, bits: toBits(v6, 16) } : void 0;
|
|
5973
|
+
}
|
|
5974
|
+
function parsePrefix(text) {
|
|
5975
|
+
const parts = text.trim().split("/");
|
|
5976
|
+
if (parts.length > 2) return void 0;
|
|
5977
|
+
const [address = "", size] = parts;
|
|
5978
|
+
const parsed = addressBits(address);
|
|
5979
|
+
if (!parsed) return void 0;
|
|
5980
|
+
const max = parsed.v6 ? 128 : 32;
|
|
5981
|
+
const length2 = size === void 0 ? max : /^\d{1,3}$/.test(size) ? Number(size) : -1;
|
|
5982
|
+
if (length2 < 0 || length2 > max) return void 0;
|
|
5983
|
+
return { ...parsed, length: length2 };
|
|
5984
|
+
}
|
|
5985
|
+
function within3(prefix, addr) {
|
|
5986
|
+
if (prefix.v6 !== addr.v6) return false;
|
|
5987
|
+
const shift = BigInt((prefix.v6 ? 128 : 32) - prefix.length);
|
|
5988
|
+
return addr.bits >> shift === prefix.bits >> shift;
|
|
5989
|
+
}
|
|
5990
|
+
var RESERVED = [
|
|
5991
|
+
"0.0.0.0/8",
|
|
5992
|
+
"127.0.0.0/8",
|
|
5993
|
+
"169.254.0.0/16",
|
|
5994
|
+
"224.0.0.0/4",
|
|
5995
|
+
"240.0.0.0/4",
|
|
5996
|
+
"::/96",
|
|
5997
|
+
"::ffff:0:0/96",
|
|
5998
|
+
"fe80::/10",
|
|
5999
|
+
"ff00::/8"
|
|
6000
|
+
].map((p) => parsePrefix(p));
|
|
6001
|
+
var Routes = class {
|
|
6002
|
+
table = [];
|
|
6003
|
+
exit = false;
|
|
6004
|
+
ipv6;
|
|
6005
|
+
constructor(ipv62 = false) {
|
|
6006
|
+
this.ipv6 = ipv62;
|
|
6007
|
+
}
|
|
6008
|
+
set(table) {
|
|
6009
|
+
const parsed = (table.prefixes ?? []).map(parsePrefix);
|
|
6010
|
+
const bad = (table.prefixes ?? []).find((_, i) => !parsed[i]);
|
|
6011
|
+
if (bad !== void 0) throw new Error(`not an address prefix: ${bad}`);
|
|
6012
|
+
this.table = parsed;
|
|
6013
|
+
this.exit = table.exit === true;
|
|
6014
|
+
}
|
|
6015
|
+
classify(host) {
|
|
6016
|
+
const name2 = host.toLowerCase().replace(/\.$/, "");
|
|
6017
|
+
if (name2 === "localhost" || name2.endsWith(".localhost") || name2 === "0.0.0.0") {
|
|
6018
|
+
return "loopback";
|
|
6019
|
+
}
|
|
6020
|
+
if (name2 === HOST_LOOPBACK || name2 === HOST_ADDRESS) return "host";
|
|
6021
|
+
const addr = addressBits(name2);
|
|
6022
|
+
if (!addr) return "unreachable";
|
|
6023
|
+
if (addr.v6 && addr.bits === 1n) return "loopback";
|
|
6024
|
+
if (!addr.v6 && addr.bits >> 24n === 127n) return "loopback";
|
|
6025
|
+
if (RESERVED.some((p) => within3(p, addr))) return "reserved";
|
|
6026
|
+
if (addr.v6 && !this.ipv6) return "unreachable";
|
|
6027
|
+
if (this.exit || this.table.some((p) => within3(p, addr))) return "uplink";
|
|
6028
|
+
return "unreachable";
|
|
6029
|
+
}
|
|
6030
|
+
};
|
|
6031
|
+
|
|
6032
|
+
// src/kernel/net/uplink.ts
|
|
6033
|
+
function answerOf(result) {
|
|
6034
|
+
const answer = Array.isArray(result) ? { addresses: result } : result;
|
|
6035
|
+
const addresses = Array.isArray(answer?.addresses) ? answer.addresses.filter((a) => typeof a === "string") : [];
|
|
6036
|
+
return {
|
|
6037
|
+
addresses,
|
|
6038
|
+
...typeof answer?.ttl === "number" && answer.ttl >= 0 ? { ttl: answer.ttl } : {}
|
|
6039
|
+
};
|
|
6040
|
+
}
|
|
6041
|
+
var NEVER = new Routes(true);
|
|
6042
|
+
|
|
6043
|
+
// src/kernel/net/resolver.ts
|
|
6044
|
+
var RESOLVE_TTL_MAX = 60;
|
|
6045
|
+
var RESOLVE_TIMEOUT_MS = 1e4;
|
|
6046
|
+
var RESOLVE_CACHE_MAX = 256;
|
|
6047
|
+
var LOOPBACK_NAMES2 = /* @__PURE__ */ new Set(["localhost", "localhost.localdomain", "ip6-localhost", "::1"]);
|
|
6048
|
+
function hostsEntry(name2) {
|
|
6049
|
+
if (LOOPBACK_NAMES2.has(name2) || name2.endsWith(".localhost")) return "127.0.0.1";
|
|
6050
|
+
if (name2 === HOST_LOOPBACK) return HOST_LOOPBACK_ADDRESS.join(".");
|
|
6051
|
+
return ipv4Bytes(name2) ? name2 : void 0;
|
|
6052
|
+
}
|
|
6053
|
+
var Resolver = class {
|
|
6054
|
+
uplink;
|
|
6055
|
+
routes;
|
|
6056
|
+
now;
|
|
6057
|
+
timeoutMs;
|
|
6058
|
+
log;
|
|
6059
|
+
cache = /* @__PURE__ */ new Map();
|
|
6060
|
+
pending = /* @__PURE__ */ new Map();
|
|
6061
|
+
constructor(options) {
|
|
6062
|
+
this.uplink = options.uplink;
|
|
6063
|
+
this.routes = options.routes;
|
|
6064
|
+
this.now = options.now ?? Date.now;
|
|
6065
|
+
this.timeoutMs = options.timeoutMs ?? RESOLVE_TIMEOUT_MS;
|
|
6066
|
+
this.log = options.log ?? ((message2) => console.warn(message2));
|
|
6067
|
+
}
|
|
6068
|
+
async resolve(name2, family, blocking) {
|
|
6069
|
+
const key = name2.toLowerCase().replace(/\.$/, "");
|
|
6070
|
+
const local = hostsEntry(key);
|
|
6071
|
+
if (ipv6Groups(key)) {
|
|
6072
|
+
const v4 = family !== 6 && local ? [local] : [];
|
|
6073
|
+
return family === 4 ? v4 : [...v4, key];
|
|
6074
|
+
}
|
|
6075
|
+
if (local) {
|
|
6076
|
+
const six = LOOPBACK_NAMES2.has(key) || key.endsWith(".localhost") ? ["::1"] : [];
|
|
6077
|
+
return family === 6 ? six : family === 4 ? [local] : [local, ...six];
|
|
6078
|
+
}
|
|
6079
|
+
if (!this.uplink || key === "") return [];
|
|
6080
|
+
const asked = this.uplink.traits.ipv6 ? family : 4;
|
|
6081
|
+
if (family === 6 && asked !== 6) return [];
|
|
6082
|
+
const id = `${asked}:${key}`;
|
|
6083
|
+
const hit = this.cache.get(id);
|
|
6084
|
+
if (hit && hit.expires > this.now()) return hit.addresses;
|
|
6085
|
+
const signal = blocking?.();
|
|
6086
|
+
if (signal?.aborted) throw new KernelError("EINTR");
|
|
6087
|
+
let lookup = this.pending.get(id);
|
|
6088
|
+
if (!lookup) {
|
|
6089
|
+
const abort = new AbortController();
|
|
6090
|
+
lookup = { work: this.lookup(key, asked, id, abort.signal), abort, waiters: 0 };
|
|
6091
|
+
this.pending.set(id, lookup);
|
|
6092
|
+
void lookup.work.then(() => this.pending.delete(id));
|
|
6093
|
+
}
|
|
6094
|
+
return waitFor(lookup, signal);
|
|
6095
|
+
}
|
|
6096
|
+
async lookup(name2, family, id, abandoned) {
|
|
6097
|
+
const uplink = this.uplink;
|
|
6098
|
+
const timeout = AbortSignal.any([AbortSignal.timeout(this.timeoutMs), abandoned]);
|
|
6099
|
+
let answer;
|
|
6100
|
+
try {
|
|
6101
|
+
answer = answerOf(
|
|
6102
|
+
await Promise.race([
|
|
6103
|
+
uplink.resolve(name2, family, timeout),
|
|
6104
|
+
new Promise(
|
|
6105
|
+
(_, reject) => timeout.addEventListener("abort", () => reject(timeout.reason), { once: true })
|
|
6106
|
+
)
|
|
6107
|
+
])
|
|
6108
|
+
);
|
|
6109
|
+
} catch {
|
|
6110
|
+
return [];
|
|
6111
|
+
}
|
|
6112
|
+
const addresses = answer.addresses.filter((a) => this.usable(name2, a, family));
|
|
6113
|
+
if (addresses.length > 0) this.remember(id, addresses, answer.ttl);
|
|
6114
|
+
return addresses;
|
|
6115
|
+
}
|
|
6116
|
+
usable(name2, address, family) {
|
|
6117
|
+
const v4 = ipv4Bytes(address) !== void 0;
|
|
6118
|
+
if (!v4 && (family === 4 || !ipv6Groups(address))) return false;
|
|
6119
|
+
if (v4 && family === 6) return false;
|
|
6120
|
+
const kind = this.routes.classify(address);
|
|
6121
|
+
if (kind !== "loopback" && kind !== "host" && kind !== "reserved") return true;
|
|
6122
|
+
this.log(`slicc-kernel: dropped the uplink's answer ${address} for ${name2}: it is ${kind}`);
|
|
6123
|
+
return false;
|
|
6124
|
+
}
|
|
6125
|
+
remember(id, addresses, ttl) {
|
|
6126
|
+
const seconds = Math.min(ttl ?? RESOLVE_TTL_MAX, RESOLVE_TTL_MAX);
|
|
6127
|
+
if (seconds <= 0) return;
|
|
6128
|
+
this.cache.delete(id);
|
|
6129
|
+
this.cache.set(id, { addresses, expires: this.now() + seconds * 1e3 });
|
|
6130
|
+
if (this.cache.size > RESOLVE_CACHE_MAX) {
|
|
6131
|
+
this.cache.delete(this.cache.keys().next().value);
|
|
6132
|
+
}
|
|
6133
|
+
}
|
|
6134
|
+
};
|
|
6135
|
+
function waitFor(lookup, signal) {
|
|
6136
|
+
lookup.waiters++;
|
|
6137
|
+
return new Promise((resolve, reject) => {
|
|
6138
|
+
const abort = () => {
|
|
6139
|
+
if (--lookup.waiters === 0) lookup.abort.abort(new KernelError("EINTR"));
|
|
6140
|
+
reject(new KernelError("EINTR"));
|
|
6141
|
+
};
|
|
6142
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
6143
|
+
void lookup.work.then((value) => {
|
|
6144
|
+
if (signal?.aborted) return;
|
|
6145
|
+
lookup.waiters--;
|
|
6146
|
+
signal?.removeEventListener("abort", abort);
|
|
6147
|
+
resolve(value);
|
|
6148
|
+
});
|
|
6149
|
+
});
|
|
6150
|
+
}
|
|
6151
|
+
|
|
5690
6152
|
// src/kernel/tty.ts
|
|
5691
6153
|
var ICRNL = 256;
|
|
5692
6154
|
var IUTF8 = 16384;
|
|
@@ -6190,7 +6652,8 @@ var SOCKET_OPS = [
|
|
|
6190
6652
|
"sock-shutdown",
|
|
6191
6653
|
"sock-name",
|
|
6192
6654
|
"sock-getopt",
|
|
6193
|
-
"sock-setopt"
|
|
6655
|
+
"sock-setopt",
|
|
6656
|
+
"sock-resolve"
|
|
6194
6657
|
];
|
|
6195
6658
|
function socketAt(fds, fd) {
|
|
6196
6659
|
const file = fds.get(fd).file;
|
|
@@ -6221,10 +6684,15 @@ async function socketSyscall(req, proc) {
|
|
|
6221
6684
|
return ok();
|
|
6222
6685
|
case "sock-accept":
|
|
6223
6686
|
return ok(await accept(proc, req.fd, req.nonblock));
|
|
6224
|
-
case "sock-connect":
|
|
6225
|
-
socketAt(fds, req.fd).connect(req.addr);
|
|
6226
|
-
if (req.nonblock)
|
|
6687
|
+
case "sock-connect": {
|
|
6688
|
+
const dialing = socketAt(fds, req.fd).connect(req.addr);
|
|
6689
|
+
if (req.nonblock) {
|
|
6690
|
+
dialing?.catch(() => void 0);
|
|
6691
|
+
throw new KernelError("EINPROGRESS");
|
|
6692
|
+
}
|
|
6693
|
+
if (dialing !== void 0) await interruptible(dialing, proc.blocking());
|
|
6227
6694
|
return ok();
|
|
6695
|
+
}
|
|
6228
6696
|
case "sock-shutdown":
|
|
6229
6697
|
socketAt(fds, req.fd).shutdown(req.how);
|
|
6230
6698
|
return ok();
|
|
@@ -6239,8 +6707,20 @@ async function socketSyscall(req, proc) {
|
|
|
6239
6707
|
case "sock-setopt":
|
|
6240
6708
|
socketAt(fds, req.fd).setOption(req.level, req.name, req.value);
|
|
6241
6709
|
return ok();
|
|
6710
|
+
case "sock-resolve": {
|
|
6711
|
+
const addresses = await proc.resolve(req.name, req.family, () => proc.blocking());
|
|
6712
|
+
if (addresses.length === 0) throw new KernelError("ENOENT");
|
|
6713
|
+
return ok(addresses);
|
|
6714
|
+
}
|
|
6242
6715
|
}
|
|
6243
6716
|
}
|
|
6717
|
+
function interruptible(dialing, signal) {
|
|
6718
|
+
return new Promise((resolve, reject) => {
|
|
6719
|
+
const abort = () => reject(new KernelError("EINTR"));
|
|
6720
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
6721
|
+
dialing.then(resolve, reject).finally(() => signal.removeEventListener("abort", abort));
|
|
6722
|
+
});
|
|
6723
|
+
}
|
|
6244
6724
|
function unnamed(domain) {
|
|
6245
6725
|
return domain === "inet" ? { family: "inet", host: "0.0.0.0", port: 0 } : { family: "unix", path: "" };
|
|
6246
6726
|
}
|
|
@@ -6490,7 +6970,7 @@ function isMissing(err) {
|
|
|
6490
6970
|
if (err?.code === "ENOENT") return true;
|
|
6491
6971
|
return err instanceof Error && err.message.startsWith("ENOENT");
|
|
6492
6972
|
}
|
|
6493
|
-
function
|
|
6973
|
+
function within4(path, root) {
|
|
6494
6974
|
return path === root || path.startsWith(root.endsWith("/") ? root : `${root}/`);
|
|
6495
6975
|
}
|
|
6496
6976
|
var VfsNode = class {
|
|
@@ -6698,7 +7178,7 @@ var VfsNodes = class {
|
|
|
6698
7178
|
return node;
|
|
6699
7179
|
}
|
|
6700
7180
|
holds(prefix) {
|
|
6701
|
-
for (const path of this.byPath.keys()) if (
|
|
7181
|
+
for (const path of this.byPath.keys()) if (within4(path, prefix)) return true;
|
|
6702
7182
|
return false;
|
|
6703
7183
|
}
|
|
6704
7184
|
closed(node) {
|
|
@@ -6706,24 +7186,24 @@ var VfsNodes = class {
|
|
|
6706
7186
|
if (node.opens === 0 && this.byPath.get(node.path) === node) this.byPath.delete(node.path);
|
|
6707
7187
|
}
|
|
6708
7188
|
async flush(path) {
|
|
6709
|
-
for (const [p, node] of this.byPath) if (
|
|
7189
|
+
for (const [p, node] of this.byPath) if (within4(p, path)) await node.serial(() => node.flush());
|
|
6710
7190
|
}
|
|
6711
7191
|
async unlinking(path) {
|
|
6712
7192
|
for (const [held, node] of [...this.byPath]) {
|
|
6713
|
-
if (!
|
|
7193
|
+
if (!within4(held, path)) continue;
|
|
6714
7194
|
await node.serial(async () => void await Promise.all([node.keep(), node.limit()]));
|
|
6715
7195
|
}
|
|
6716
7196
|
}
|
|
6717
7197
|
revoke(prefix) {
|
|
6718
7198
|
for (const [path, node] of this.byPath) {
|
|
6719
|
-
if (!
|
|
7199
|
+
if (!within4(path, prefix)) continue;
|
|
6720
7200
|
node.revoke();
|
|
6721
7201
|
this.byPath.delete(path);
|
|
6722
7202
|
}
|
|
6723
7203
|
}
|
|
6724
7204
|
unlinked(path) {
|
|
6725
7205
|
for (const [held, node] of [...this.byPath]) {
|
|
6726
|
-
if (!
|
|
7206
|
+
if (!within4(held, path)) continue;
|
|
6727
7207
|
node.orphaned = true;
|
|
6728
7208
|
this.byPath.delete(held);
|
|
6729
7209
|
}
|
|
@@ -6732,8 +7212,8 @@ var VfsNodes = class {
|
|
|
6732
7212
|
if (from === to) return;
|
|
6733
7213
|
const moved2 = [];
|
|
6734
7214
|
for (const [p, node] of this.byPath) {
|
|
6735
|
-
if (
|
|
6736
|
-
else if (
|
|
7215
|
+
if (within4(p, from)) moved2.push(node);
|
|
7216
|
+
else if (within4(p, to)) {
|
|
6737
7217
|
node.orphaned = true;
|
|
6738
7218
|
this.byPath.delete(p);
|
|
6739
7219
|
}
|
|
@@ -6987,6 +7467,7 @@ function isWasmSyscall(req) {
|
|
|
6987
7467
|
return typeof op === "string" && SYSCALL_OPS.has(op);
|
|
6988
7468
|
}
|
|
6989
7469
|
var MAX_READ = 1024 * 1024;
|
|
7470
|
+
var HOSTS_ONLY = new Resolver({ routes: new Routes() });
|
|
6990
7471
|
var WasmProcess = class {
|
|
6991
7472
|
exited = false;
|
|
6992
7473
|
children;
|
|
@@ -7378,10 +7859,12 @@ var WasmProcess = class {
|
|
|
7378
7859
|
}
|
|
7379
7860
|
socketSyscall(req) {
|
|
7380
7861
|
this.net ??= this.options.net ?? new LoopbackNet();
|
|
7862
|
+
const resolver = this.options.resolver ?? HOSTS_ONLY;
|
|
7381
7863
|
return socketSyscall(req, {
|
|
7382
7864
|
fds: this.fds,
|
|
7383
7865
|
net: this.net,
|
|
7384
|
-
blocking: () => this.blockingSignal()
|
|
7866
|
+
blocking: () => this.blockingSignal(),
|
|
7867
|
+
resolve: (name2, family, blocking) => resolver.resolve(name2, family, blocking)
|
|
7385
7868
|
});
|
|
7386
7869
|
}
|
|
7387
7870
|
tty(fd) {
|
|
@@ -7576,6 +8059,7 @@ function spawnWasmProcess(opts) {
|
|
|
7576
8059
|
http: opts.http,
|
|
7577
8060
|
locks: opts.locks,
|
|
7578
8061
|
onReap: opts.onReap,
|
|
8062
|
+
resolver: opts.resolver,
|
|
7579
8063
|
onPending: (sig) => void Atomics.or(header3, SAB_I_SIGNALS, sigbit(sig)),
|
|
7580
8064
|
onTimer: (which) => void Atomics.or(header3, SAB_I_TIMERS, 1 << which),
|
|
7581
8065
|
hasPending: () => Atomics.load(header3, SAB_I_SIGNALS) !== 0 || Atomics.load(header3, SAB_I_TIMERS) !== 0,
|
|
@@ -8666,7 +9150,7 @@ function memoryMedia() {
|
|
|
8666
9150
|
}
|
|
8667
9151
|
|
|
8668
9152
|
// src/mount/chunked.ts
|
|
8669
|
-
var
|
|
9153
|
+
var CHUNK3 = 1024 * 1024;
|
|
8670
9154
|
var ChunkedBytes = class {
|
|
8671
9155
|
chunks = [];
|
|
8672
9156
|
size = 0;
|
|
@@ -8675,9 +9159,9 @@ var ChunkedBytes = class {
|
|
|
8675
9159
|
if (end <= offset) return new Uint8Array(0);
|
|
8676
9160
|
const out = new Uint8Array(end - offset);
|
|
8677
9161
|
for (let at = offset; at < end; ) {
|
|
8678
|
-
const index = Math.floor(at /
|
|
8679
|
-
const from = at - index *
|
|
8680
|
-
const n = Math.min(
|
|
9162
|
+
const index = Math.floor(at / CHUNK3);
|
|
9163
|
+
const from = at - index * CHUNK3;
|
|
9164
|
+
const n = Math.min(CHUNK3 - from, end - at);
|
|
8681
9165
|
const chunk2 = this.chunks[index];
|
|
8682
9166
|
if (chunk2) out.set(chunk2.subarray(from, Math.min(from + n, chunk2.length)), at - offset);
|
|
8683
9167
|
at += n;
|
|
@@ -8688,10 +9172,10 @@ var ChunkedBytes = class {
|
|
|
8688
9172
|
const whole = owned && bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength;
|
|
8689
9173
|
for (let done4 = 0; done4 < bytes.length; ) {
|
|
8690
9174
|
const at = offset + done4;
|
|
8691
|
-
const index = Math.floor(at /
|
|
8692
|
-
const from = at - index *
|
|
8693
|
-
const n = Math.min(
|
|
8694
|
-
if (whole && n ===
|
|
9175
|
+
const index = Math.floor(at / CHUNK3);
|
|
9176
|
+
const from = at - index * CHUNK3;
|
|
9177
|
+
const n = Math.min(CHUNK3 - from, bytes.length - done4);
|
|
9178
|
+
if (whole && n === CHUNK3 && bytes.length === CHUNK3) this.chunks[index] = bytes;
|
|
8695
9179
|
else this.room(index, from + n).set(bytes.subarray(done4, done4 + n), from);
|
|
8696
9180
|
done4 += n;
|
|
8697
9181
|
}
|
|
@@ -8699,10 +9183,10 @@ var ChunkedBytes = class {
|
|
|
8699
9183
|
}
|
|
8700
9184
|
truncate(size) {
|
|
8701
9185
|
if (size < this.size) {
|
|
8702
|
-
const keep = Math.ceil(size /
|
|
9186
|
+
const keep = Math.ceil(size / CHUNK3);
|
|
8703
9187
|
this.chunks.length = Math.min(this.chunks.length, keep);
|
|
8704
9188
|
const tail = this.chunks[keep - 1];
|
|
8705
|
-
const from = size - (keep - 1) *
|
|
9189
|
+
const from = size - (keep - 1) * CHUNK3;
|
|
8706
9190
|
if (tail && from < tail.length) tail.fill(0, from);
|
|
8707
9191
|
}
|
|
8708
9192
|
this.size = size;
|
|
@@ -8710,7 +9194,7 @@ var ChunkedBytes = class {
|
|
|
8710
9194
|
room(index, need) {
|
|
8711
9195
|
const chunk2 = this.chunks[index];
|
|
8712
9196
|
if (chunk2 && chunk2.length >= need) return chunk2;
|
|
8713
|
-
const grown = new Uint8Array(Math.min(
|
|
9197
|
+
const grown = new Uint8Array(Math.min(CHUNK3, Math.max(need, (chunk2?.length ?? 0) * 2)));
|
|
8714
9198
|
if (chunk2) grown.set(chunk2);
|
|
8715
9199
|
this.chunks[index] = grown;
|
|
8716
9200
|
return grown;
|
|
@@ -9124,6 +9608,9 @@ var Launcher = class {
|
|
|
9124
9608
|
cdp;
|
|
9125
9609
|
ca;
|
|
9126
9610
|
transport;
|
|
9611
|
+
uplink;
|
|
9612
|
+
routes;
|
|
9613
|
+
resolver;
|
|
9127
9614
|
watchers = new FsWatchers();
|
|
9128
9615
|
pnpmHome;
|
|
9129
9616
|
mounts;
|
|
@@ -9163,6 +9650,11 @@ var Launcher = class {
|
|
|
9163
9650
|
this.env = { ...networkEnv(), SLICC_CDP_URL: this.cdp.url, ...options.env };
|
|
9164
9651
|
this.ca = kernelCa(options.caStore ?? memoryCaStore());
|
|
9165
9652
|
this.transport = options.transport ?? missingTransport();
|
|
9653
|
+
this.uplink = options.uplink;
|
|
9654
|
+
this.routes = new Routes(options.uplink?.traits.ipv6 === true);
|
|
9655
|
+
if (options.uplink?.routes) this.routes.set(options.uplink.routes);
|
|
9656
|
+
this.resolver = new Resolver({ uplink: options.uplink, routes: this.routes });
|
|
9657
|
+
if (options.uplink) this.net.useUplink({ uplink: options.uplink, routes: this.routes });
|
|
9166
9658
|
enableNetwork(this.net, {
|
|
9167
9659
|
transport: this.transport,
|
|
9168
9660
|
engine: kernelTlsEngine(packageTlsEngine(options.fs, this.modulesDir)),
|
|
@@ -9177,6 +9669,9 @@ var Launcher = class {
|
|
|
9177
9669
|
this.catalog = void 0;
|
|
9178
9670
|
});
|
|
9179
9671
|
}
|
|
9672
|
+
setRoutes(table) {
|
|
9673
|
+
this.routes.set(table);
|
|
9674
|
+
}
|
|
9180
9675
|
commands() {
|
|
9181
9676
|
this.catalog ??= this.roots().then((roots) => scanCommands(this.base, roots));
|
|
9182
9677
|
return this.catalog;
|
|
@@ -9356,6 +9851,7 @@ var Launcher = class {
|
|
|
9356
9851
|
net: this.net,
|
|
9357
9852
|
http: new HttpHandles(this.transport),
|
|
9358
9853
|
locks: this.locks,
|
|
9854
|
+
resolver: this.resolver,
|
|
9359
9855
|
onReap: (child) => this.reaped(child),
|
|
9360
9856
|
...req.fork ? { fork: req.fork } : {},
|
|
9361
9857
|
...this.shownIds(req)
|
|
@@ -9720,7 +10216,7 @@ function valid(name2) {
|
|
|
9720
10216
|
throw new TypeError(`invalid name: ${name2}`);
|
|
9721
10217
|
}
|
|
9722
10218
|
}
|
|
9723
|
-
var
|
|
10219
|
+
var CHUNK4 = 1024 * 1024;
|
|
9724
10220
|
function bytesOf(data) {
|
|
9725
10221
|
if (typeof data === "string") return new TextEncoder().encode(data);
|
|
9726
10222
|
if (data instanceof Blob) return data.arrayBuffer().then((buffer) => new Uint8Array(buffer));
|
|
@@ -9744,19 +10240,19 @@ var Chunks = class {
|
|
|
9744
10240
|
}
|
|
9745
10241
|
grow(end) {
|
|
9746
10242
|
if (end <= this.size) return;
|
|
9747
|
-
const last = Math.floor((end - 1) /
|
|
9748
|
-
for (let i = 0; i < last; i++) this.pad(i,
|
|
9749
|
-
this.pad(last, end - last *
|
|
10243
|
+
const last = Math.floor((end - 1) / CHUNK4);
|
|
10244
|
+
for (let i = 0; i < last; i++) this.pad(i, CHUNK4);
|
|
10245
|
+
this.pad(last, end - last * CHUNK4);
|
|
9750
10246
|
this.size = end;
|
|
9751
10247
|
}
|
|
9752
10248
|
async write(at, bytes) {
|
|
9753
10249
|
if (bytes.length === 0) return;
|
|
9754
|
-
const first = Math.floor(at /
|
|
9755
|
-
for (let i = 0; i < first; i++) this.pad(i,
|
|
10250
|
+
const first = Math.floor(at / CHUNK4);
|
|
10251
|
+
for (let i = 0; i < first; i++) this.pad(i, CHUNK4);
|
|
9756
10252
|
for (let done4 = 0; done4 < bytes.length; ) {
|
|
9757
|
-
const index = Math.floor((at + done4) /
|
|
9758
|
-
const from = at + done4 - index *
|
|
9759
|
-
const n = Math.min(
|
|
10253
|
+
const index = Math.floor((at + done4) / CHUNK4);
|
|
10254
|
+
const from = at + done4 - index * CHUNK4;
|
|
10255
|
+
const n = Math.min(CHUNK4 - from, bytes.length - done4);
|
|
9760
10256
|
const view = bytes.subarray(done4, done4 + n);
|
|
9761
10257
|
const part = view.buffer instanceof ArrayBuffer ? view : view.slice();
|
|
9762
10258
|
const old = this.blobs[index];
|
|
@@ -9776,10 +10272,10 @@ var Chunks = class {
|
|
|
9776
10272
|
this.grow(size);
|
|
9777
10273
|
return;
|
|
9778
10274
|
}
|
|
9779
|
-
const keep = Math.ceil(size /
|
|
10275
|
+
const keep = Math.ceil(size / CHUNK4);
|
|
9780
10276
|
this.blobs.length = keep;
|
|
9781
10277
|
if (keep > 0)
|
|
9782
|
-
this.blobs[keep - 1] = this.blobs[keep - 1].slice(0, size - (keep - 1) *
|
|
10278
|
+
this.blobs[keep - 1] = this.blobs[keep - 1].slice(0, size - (keep - 1) * CHUNK4);
|
|
9783
10279
|
this.size = size;
|
|
9784
10280
|
}
|
|
9785
10281
|
};
|
|
@@ -10705,6 +11201,7 @@ async function createNodeKernel(options = {}) {
|
|
|
10705
11201
|
...options.modules ? { modules: options.modules } : {},
|
|
10706
11202
|
...options.env ? { env: options.env } : {},
|
|
10707
11203
|
...transport ? { transport } : {},
|
|
11204
|
+
...options.network?.uplink ? { uplink: options.network.uplink } : {},
|
|
10708
11205
|
...options.processMounts !== void 0 ? { processMounts: options.processMounts } : {},
|
|
10709
11206
|
...options.fstabRetries ? { fstabRetries: options.fstabRetries } : {},
|
|
10710
11207
|
...options.hostfs ? { hostfs: options.hostfs } : {},
|
|
@@ -10772,6 +11269,7 @@ async function createNodeKernel(options = {}) {
|
|
|
10772
11269
|
mount: (spec) => guard(() => launcher.mount(spec)),
|
|
10773
11270
|
umount: (target) => guard(async () => launcher.umount(target)),
|
|
10774
11271
|
mounts: async () => launcher.mounts.list(),
|
|
11272
|
+
setRoutes: (routes) => guard(async () => launcher.setRoutes(routes)),
|
|
10775
11273
|
async connect() {
|
|
10776
11274
|
if (terminated) throw new Error(TERMINATED);
|
|
10777
11275
|
const { port1, port2 } = new MessageChannel2();
|