@ai-ecoverse/slicc-kernel 1.170.3 → 1.171.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 +10 -3
- package/dist/driver-worker.js +32 -10
- package/dist/driver-worker.js.map +3 -3
- package/dist/index.js +49 -19
- package/dist/index.js.map +3 -3
- package/dist/kernel-worker.js +394 -284
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-driver-worker.js +36 -14
- package/dist/node-driver-worker.js.map +3 -3
- package/dist/node-process-worker.cjs +3 -3
- package/dist/node-process-worker.cjs.map +2 -2
- package/dist/node-process-worker.js +3 -3
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +491 -324
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +3 -3
- package/dist/process-worker.js.map +2 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/kernel/net/http-syscalls.d.ts +1 -0
- package/dist/types/kernel/net/placeholder-floor.d.ts +8 -0
- package/dist/types/kernel/net/remote-transport.d.ts +4 -1
- package/dist/types/kernel/net/transport.d.ts +4 -0
- package/dist/types/node/follow.d.ts +4 -0
- package/dist/types/node.d.ts +1 -0
- package/dist/types/realm/sync-fs-wire.d.ts +1 -1
- package/dist/types/transport.d.ts +2 -2
- package/package.json +2 -2
package/dist/kernel-worker.js
CHANGED
|
@@ -7310,6 +7310,19 @@ function uploadsFor(peer) {
|
|
|
7310
7310
|
});
|
|
7311
7311
|
return { of, answer: (call) => pulls.get(call.nid)?.(call) };
|
|
7312
7312
|
}
|
|
7313
|
+
function headOf(nid, response) {
|
|
7314
|
+
return {
|
|
7315
|
+
net: "head",
|
|
7316
|
+
nid,
|
|
7317
|
+
...response.url !== void 0 ? { url: response.url } : {},
|
|
7318
|
+
...response.redirected !== void 0 ? { redirected: response.redirected } : {},
|
|
7319
|
+
...response.redirects ? { redirects: response.redirects } : {},
|
|
7320
|
+
...response.opaqueRedirect ? { opaqueRedirect: true } : {},
|
|
7321
|
+
status: response.status,
|
|
7322
|
+
statusText: response.statusText,
|
|
7323
|
+
headers: response.headers
|
|
7324
|
+
};
|
|
7325
|
+
}
|
|
7313
7326
|
function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS2 } = {}) {
|
|
7314
7327
|
const open2 = /* @__PURE__ */ new Map();
|
|
7315
7328
|
const fail2 = (nid, e) => {
|
|
@@ -7335,6 +7348,7 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS2 } = {})
|
|
|
7335
7348
|
method: call.method,
|
|
7336
7349
|
headers: call.headers,
|
|
7337
7350
|
...call.streamed ? { bodyStream: uploads.of(call.nid, abort.signal) } : call.body ? { body: call.body } : {},
|
|
7351
|
+
...call.redirect !== void 0 ? { redirect: call.redirect } : {},
|
|
7338
7352
|
signal: abort.signal
|
|
7339
7353
|
});
|
|
7340
7354
|
if (!open2.has(call.nid)) {
|
|
@@ -7342,15 +7356,7 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS2 } = {})
|
|
|
7342
7356
|
return;
|
|
7343
7357
|
}
|
|
7344
7358
|
open2.set(call.nid, { abort, body: response.body[Symbol.asyncIterator](), response });
|
|
7345
|
-
peer.postMessage(
|
|
7346
|
-
net: "head",
|
|
7347
|
-
nid: call.nid,
|
|
7348
|
-
...response.redirected ? { url: response.url, redirected: true } : {},
|
|
7349
|
-
...response.redirects ? { redirects: response.redirects } : {},
|
|
7350
|
-
status: response.status,
|
|
7351
|
-
statusText: response.statusText,
|
|
7352
|
-
headers: response.headers
|
|
7353
|
-
});
|
|
7359
|
+
peer.postMessage(headOf(call.nid, response));
|
|
7354
7360
|
} catch (e) {
|
|
7355
7361
|
fail2(call.nid, e);
|
|
7356
7362
|
}
|
|
@@ -8206,9 +8212,9 @@ function serveClient(port, host) {
|
|
|
8206
8212
|
ended.resolve();
|
|
8207
8213
|
}
|
|
8208
8214
|
async function hello(message3) {
|
|
8209
|
-
const
|
|
8210
|
-
if (
|
|
8211
|
-
send2({ hello: { protocol: PROTOCOL, error:
|
|
8215
|
+
const refused4 = versionError(message3.protocol) ?? await hosts.requests.accept(host, message3);
|
|
8216
|
+
if (refused4) {
|
|
8217
|
+
send2({ hello: { protocol: PROTOCOL, error: refused4 } });
|
|
8212
8218
|
detach();
|
|
8213
8219
|
return;
|
|
8214
8220
|
}
|
|
@@ -8498,7 +8504,7 @@ function satisfies(version, range2) {
|
|
|
8498
8504
|
}
|
|
8499
8505
|
|
|
8500
8506
|
// src/version.ts
|
|
8501
|
-
var KERNEL_VERSION = true ? "1.
|
|
8507
|
+
var KERNEL_VERSION = true ? "1.171.0" : "0.0.0-dev";
|
|
8502
8508
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8503
8509
|
function procVersion() {
|
|
8504
8510
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -8790,10 +8796,10 @@ async function tierPackages(fs, physical, roots, bins, kernel, global) {
|
|
|
8790
8796
|
const own = commandsOf(pkg, manifest);
|
|
8791
8797
|
const named = new Set(own.map((command) => command.name));
|
|
8792
8798
|
const extra = bins ? await binCommandsOf(physical, pkg, manifest, named) : [];
|
|
8793
|
-
const
|
|
8799
|
+
const refused4 = engineRefusal(manifest, kernel);
|
|
8794
8800
|
const name2 = pkg.slice(root.length + 1);
|
|
8795
8801
|
const dependency = direct?.has(name2) === false;
|
|
8796
|
-
const marks = { ...
|
|
8802
|
+
const marks = { ...refused4 ? { refused: refused4 } : {}, ...dependency ? { dependency } : {} };
|
|
8797
8803
|
out.push({
|
|
8798
8804
|
name: name2,
|
|
8799
8805
|
pkg,
|
|
@@ -8825,7 +8831,7 @@ function winners(tier) {
|
|
|
8825
8831
|
}
|
|
8826
8832
|
return out;
|
|
8827
8833
|
}
|
|
8828
|
-
async function scanCommands(fs, modules, binsFrom = Number.POSITIVE_INFINITY, kernel = KERNEL_VERSION,
|
|
8834
|
+
async function scanCommands(fs, modules, binsFrom = Number.POSITIVE_INFINITY, kernel = KERNEL_VERSION, refused4, global = /* @__PURE__ */ new Set()) {
|
|
8829
8835
|
const found = /* @__PURE__ */ new Map();
|
|
8830
8836
|
const physical = physicalResolver(fs);
|
|
8831
8837
|
const tiers = (typeof modules === "string" ? [modules] : modules).map(
|
|
@@ -8839,7 +8845,7 @@ async function scanCommands(fs, modules, binsFrom = Number.POSITIVE_INFINITY, ke
|
|
|
8839
8845
|
const dependencies = [];
|
|
8840
8846
|
for (const [index, roots] of tiers.entries()) {
|
|
8841
8847
|
const tier = await tierPackages(fs, physical, roots, index >= binsFrom, kernel, global);
|
|
8842
|
-
if (
|
|
8848
|
+
if (refused4) refused4.push(...tier.flatMap((entry) => entry.commands.filter((c) => c.refused)));
|
|
8843
8849
|
await take(tier.filter((entry) => !entry.dependency));
|
|
8844
8850
|
dependencies.push(tier.filter((entry) => entry.dependency));
|
|
8845
8851
|
}
|
|
@@ -10392,6 +10398,78 @@ var CronService = class {
|
|
|
10392
10398
|
}
|
|
10393
10399
|
};
|
|
10394
10400
|
|
|
10401
|
+
// src/kernel/net/placeholder-floor.ts
|
|
10402
|
+
var PLACEHOLDER = /fnox_proxy_[0-9a-f]{24}/;
|
|
10403
|
+
var ESCAPE = /%([0-9a-f]{2})/gi;
|
|
10404
|
+
var BASIC = /\bbasic\b(.*)/is;
|
|
10405
|
+
var PERCENT_LAYERS = 8;
|
|
10406
|
+
var BASE64_GROUP = 4;
|
|
10407
|
+
var PLACEHOLDER_REFUSED = "refused: this request has a sealed placeholder in its URL, a header or a Basic credential, and nothing fills it, so it was not sent";
|
|
10408
|
+
var PlaceholderRefused = class extends Error {
|
|
10409
|
+
status = 403;
|
|
10410
|
+
code = "EACCES";
|
|
10411
|
+
constructor() {
|
|
10412
|
+
super(PLACEHOLDER_REFUSED);
|
|
10413
|
+
}
|
|
10414
|
+
};
|
|
10415
|
+
function carries(text) {
|
|
10416
|
+
let layer = text;
|
|
10417
|
+
for (let i = 0; i < PERCENT_LAYERS; i++) {
|
|
10418
|
+
if (PLACEHOLDER.test(layer)) return true;
|
|
10419
|
+
const next3 = layer.replace(
|
|
10420
|
+
ESCAPE,
|
|
10421
|
+
(_, hex4) => String.fromCharCode(Number.parseInt(hex4, 16))
|
|
10422
|
+
);
|
|
10423
|
+
if (next3 === layer) return false;
|
|
10424
|
+
layer = next3;
|
|
10425
|
+
}
|
|
10426
|
+
return PLACEHOLDER.test(layer);
|
|
10427
|
+
}
|
|
10428
|
+
function basicCarries(value2) {
|
|
10429
|
+
const credential = BASIC.exec(value2)?.[1];
|
|
10430
|
+
if (credential === void 0) return false;
|
|
10431
|
+
const letters = credential.replace(/[^A-Za-z0-9+/_-]/g, "").replaceAll("-", "+").replaceAll("_", "/");
|
|
10432
|
+
for (let shift = 0; shift < BASE64_GROUP; shift++) {
|
|
10433
|
+
const part = letters.slice(shift);
|
|
10434
|
+
const whole = part.length % BASE64_GROUP === 1 ? part.slice(0, -1) : part;
|
|
10435
|
+
if (carries(atob(whole))) return true;
|
|
10436
|
+
}
|
|
10437
|
+
return false;
|
|
10438
|
+
}
|
|
10439
|
+
function headersCarry(headers) {
|
|
10440
|
+
return headers.some(
|
|
10441
|
+
([name2, value2]) => carries(name2.toLowerCase()) || carries(value2) || basicCarries(value2)
|
|
10442
|
+
);
|
|
10443
|
+
}
|
|
10444
|
+
function urlCarries(url) {
|
|
10445
|
+
return carries(url) || URL.canParse(url) && carries(new URL(url).href);
|
|
10446
|
+
}
|
|
10447
|
+
function refuse(request3) {
|
|
10448
|
+
if (urlCarries(request3.url) || headersCarry(request3.headers)) throw new PlaceholderRefused();
|
|
10449
|
+
}
|
|
10450
|
+
function refuseSocket(request3) {
|
|
10451
|
+
refuse(request3);
|
|
10452
|
+
if (request3.protocols.some(carries)) throw new PlaceholderRefused();
|
|
10453
|
+
}
|
|
10454
|
+
function placeholderFloor(inner) {
|
|
10455
|
+
const open2 = inner.websocket?.bind(inner);
|
|
10456
|
+
return {
|
|
10457
|
+
get traits() {
|
|
10458
|
+
return inner.traits;
|
|
10459
|
+
},
|
|
10460
|
+
...open2 ? {
|
|
10461
|
+
websocket: async (request3) => {
|
|
10462
|
+
refuseSocket(request3);
|
|
10463
|
+
return open2(request3);
|
|
10464
|
+
}
|
|
10465
|
+
} : {},
|
|
10466
|
+
async fetch(request3, owner) {
|
|
10467
|
+
refuse(request3);
|
|
10468
|
+
return inner.fetch(request3, owner);
|
|
10469
|
+
}
|
|
10470
|
+
};
|
|
10471
|
+
}
|
|
10472
|
+
|
|
10395
10473
|
// src/kernel/net/proxy-service.ts
|
|
10396
10474
|
var SEND_BUFFER2 = 1024 * 1024;
|
|
10397
10475
|
var TLS_HANDSHAKE = 22;
|
|
@@ -10840,8 +10918,8 @@ var RealmProxy = class {
|
|
|
10840
10918
|
}
|
|
10841
10919
|
async connect(conn, incoming, req, idle2) {
|
|
10842
10920
|
const target = tunnelTarget(req);
|
|
10843
|
-
const
|
|
10844
|
-
if (
|
|
10921
|
+
const refused4 = target.port === 443 ? await this.tunnelReady(target) : void 0;
|
|
10922
|
+
if (refused4) throw refused4;
|
|
10845
10923
|
await conn.write(latin1Bytes("HTTP/1.1 200 Connection Established\r\n\r\n"), this.stop.signal);
|
|
10846
10924
|
try {
|
|
10847
10925
|
const first = await incoming.peek(this.stop.signal);
|
|
@@ -10898,7 +10976,8 @@ var RealmProxy = class {
|
|
|
10898
10976
|
});
|
|
10899
10977
|
} catch (e) {
|
|
10900
10978
|
waiting.abort();
|
|
10901
|
-
|
|
10979
|
+
const status = e instanceof PlaceholderRefused ? e.status : 502;
|
|
10980
|
+
throw new HttpError(status, e instanceof Error ? e.message : String(e));
|
|
10902
10981
|
}
|
|
10903
10982
|
ctx.idle.ms = Number.POSITIVE_INFINITY;
|
|
10904
10983
|
try {
|
|
@@ -11112,7 +11191,7 @@ async function relay(socket, conn) {
|
|
|
11112
11191
|
// src/fs/attest.ts
|
|
11113
11192
|
var ATTEST_MAX = 1024 * 1024;
|
|
11114
11193
|
var UNOWNED = 1e3;
|
|
11115
|
-
function
|
|
11194
|
+
function refuse2(code, path, why) {
|
|
11116
11195
|
throw Object.assign(new Error(`attest ${path}: ${why}`), { code });
|
|
11117
11196
|
}
|
|
11118
11197
|
function chainOf(path) {
|
|
@@ -11154,11 +11233,11 @@ async function trustedParents(fs, path, o) {
|
|
|
11154
11233
|
const parents = [];
|
|
11155
11234
|
for (const dir of chainOf(path).slice(0, -1)) {
|
|
11156
11235
|
const st = await fs.lstat(dir);
|
|
11157
|
-
if (st.isSymbolicLink)
|
|
11158
|
-
if (!st.isDirectory)
|
|
11236
|
+
if (st.isSymbolicLink) refuse2("EACCES", path, `${dir} is a symlink`);
|
|
11237
|
+
if (!st.isDirectory) refuse2("ENOTDIR", path, `${dir} is not a directory`);
|
|
11159
11238
|
const perm = owned(dir, st);
|
|
11160
11239
|
if (o.users !== "off" && (perm.uid !== 0 || (perm.mode & 18) !== 0)) {
|
|
11161
|
-
|
|
11240
|
+
refuse2("EACCES", path, `${dir} is not root-owned or is writable by group or others`);
|
|
11162
11241
|
}
|
|
11163
11242
|
parents.push(perm);
|
|
11164
11243
|
}
|
|
@@ -11166,27 +11245,27 @@ async function trustedParents(fs, path, o) {
|
|
|
11166
11245
|
}
|
|
11167
11246
|
async function attest(fs, asked, o) {
|
|
11168
11247
|
if (typeof asked !== "string" || !asked.startsWith("/")) {
|
|
11169
|
-
|
|
11248
|
+
refuse2("EINVAL", String(asked), "not an absolute path");
|
|
11170
11249
|
}
|
|
11171
11250
|
const path = normalizePath(asked);
|
|
11172
11251
|
const mount = o.mounts.find((target) => {
|
|
11173
11252
|
const at = normalizePath(target);
|
|
11174
11253
|
return at === "/" || under2(path, at);
|
|
11175
11254
|
});
|
|
11176
|
-
if (mount !== void 0)
|
|
11255
|
+
if (mount !== void 0) refuse2("EACCES", path, `under the mount ${mount}`);
|
|
11177
11256
|
const parents = await trustedParents(fs, path, o);
|
|
11178
11257
|
for (let tries = 0; ; tries++) {
|
|
11179
11258
|
const before = await fs.lstat(path);
|
|
11180
|
-
if (before.isSymbolicLink)
|
|
11259
|
+
if (before.isSymbolicLink) refuse2("EACCES", path, "is a symlink");
|
|
11181
11260
|
if (!before.isFile)
|
|
11182
|
-
|
|
11183
|
-
if (before.size > ATTEST_MAX)
|
|
11261
|
+
refuse2(before.isDirectory ? "EISDIR" : "EINVAL", path, "is not a regular file");
|
|
11262
|
+
if (before.size > ATTEST_MAX) refuse2("EFBIG", path, `is over ${ATTEST_MAX} bytes`);
|
|
11184
11263
|
const bytes = (await fs.readFileBuffer(path)).slice();
|
|
11185
11264
|
const after = await fs.lstat(path);
|
|
11186
11265
|
if (unchanged(before, after, bytes)) {
|
|
11187
11266
|
return attested(path, after, bytes, await sha2562(bytes), o, parents);
|
|
11188
11267
|
}
|
|
11189
|
-
if (tries >= 1)
|
|
11268
|
+
if (tries >= 1) refuse2("EAGAIN", path, "changed while it was read");
|
|
11190
11269
|
}
|
|
11191
11270
|
}
|
|
11192
11271
|
var WATCH_DEBOUNCE_MS = 50;
|
|
@@ -13345,8 +13424,8 @@ var DriverConnection = class _DriverConnection {
|
|
|
13345
13424
|
} finally {
|
|
13346
13425
|
clearTimeout(timer);
|
|
13347
13426
|
}
|
|
13348
|
-
const
|
|
13349
|
-
if (
|
|
13427
|
+
const refused4 = driverVersionError(hello.protocol);
|
|
13428
|
+
if (refused4) throw errnoError("EPROTO", refused4);
|
|
13350
13429
|
if (hello.error) throw errnoError(hello.errno ?? "EIO", hello.error);
|
|
13351
13430
|
return new _DriverConnection(port, hello.capabilities ?? {}, waiting, timeoutMs, options);
|
|
13352
13431
|
}
|
|
@@ -15370,8 +15449,8 @@ async function guarded(entry, path, req) {
|
|
|
15370
15449
|
return { paths };
|
|
15371
15450
|
} catch (err) {
|
|
15372
15451
|
const refusal2 = err.code === "EACCES";
|
|
15373
|
-
const
|
|
15374
|
-
return { refused:
|
|
15452
|
+
const refused4 = req.op === "exists" && refusal2 ? json2(false) : toErrno(err);
|
|
15453
|
+
return { refused: refused4 };
|
|
15375
15454
|
}
|
|
15376
15455
|
}
|
|
15377
15456
|
async function copyOp(entry, path, req) {
|
|
@@ -15567,13 +15646,13 @@ async function created2(entry, req) {
|
|
|
15567
15646
|
return seen === void 0 ? looked : json2({ ...looked.json, seen });
|
|
15568
15647
|
}
|
|
15569
15648
|
var DENIED = /* @__PURE__ */ new Set(["EACCES", "EPERM"]);
|
|
15570
|
-
async function rmPermitted(entry, path, req,
|
|
15649
|
+
async function rmPermitted(entry, path, req, refused4) {
|
|
15571
15650
|
const st = await entry.fs.lstat(path).catch(() => void 0);
|
|
15572
|
-
if (!st?.isDirectory) return
|
|
15651
|
+
if (!st?.isDirectory) return refused4;
|
|
15573
15652
|
const unlisted = await guarded(entry, path, { ...req, op: "readdir" });
|
|
15574
15653
|
if ("refused" in unlisted) return unlisted.refused;
|
|
15575
15654
|
const names2 = await entry.fs.readdir(path).catch(() => void 0);
|
|
15576
|
-
if (!names2) return
|
|
15655
|
+
if (!names2) return refused4;
|
|
15577
15656
|
let first;
|
|
15578
15657
|
for (const name2 of names2) {
|
|
15579
15658
|
const child = await dispatchOne(entry, {
|
|
@@ -15624,14 +15703,14 @@ async function newDevName(entry, path, req) {
|
|
|
15624
15703
|
const named = NAMING.has(req.op);
|
|
15625
15704
|
if (!named && !CREATIONS.has(req.op)) return void 0;
|
|
15626
15705
|
const target = named ? entry.fs.resolvePath(entry.cwd, req.arg2 ?? "") : path;
|
|
15627
|
-
const
|
|
15628
|
-
if (!
|
|
15706
|
+
const refused4 = devCreation(target, entry.cred?.());
|
|
15707
|
+
if (!refused4) return void 0;
|
|
15629
15708
|
const there = await entry.fs.lstat(target).then(
|
|
15630
15709
|
() => true,
|
|
15631
15710
|
() => false
|
|
15632
15711
|
);
|
|
15633
15712
|
if (there) return void 0;
|
|
15634
|
-
return { ok: false, errno:
|
|
15713
|
+
return { ok: false, errno: refused4, message: `${target}: no new names in /dev or /proc` };
|
|
15635
15714
|
}
|
|
15636
15715
|
var MISS_OPS = /* @__PURE__ */ new Set(["stat", "lstat"]);
|
|
15637
15716
|
async function linkFree(fs, path) {
|
|
@@ -15754,7 +15833,7 @@ function encodeSabResult(result) {
|
|
|
15754
15833
|
message: result.message,
|
|
15755
15834
|
...result.direct ? { direct: true } : {},
|
|
15756
15835
|
...result.dev !== void 0 ? { dev: result.dev } : {},
|
|
15757
|
-
...result.detail
|
|
15836
|
+
...result.detail ? { detail: result.detail } : {}
|
|
15758
15837
|
})
|
|
15759
15838
|
)
|
|
15760
15839
|
};
|
|
@@ -17734,8 +17813,8 @@ var KernelLoopback = class {
|
|
|
17734
17813
|
);
|
|
17735
17814
|
} catch (err) {
|
|
17736
17815
|
socket.close();
|
|
17737
|
-
const
|
|
17738
|
-
throw
|
|
17816
|
+
const refused4 = err instanceof KernelError && err.code === "ECONNREFUSED";
|
|
17817
|
+
throw refused4 ? errno2("ECONNREFUSED", `nothing listens on the kernel's port ${port}`) : err;
|
|
17739
17818
|
}
|
|
17740
17819
|
signal.addEventListener("abort", () => socket.close(), { once: true });
|
|
17741
17820
|
return socket;
|
|
@@ -19216,22 +19295,28 @@ var HttpHandles = class {
|
|
|
19216
19295
|
return response.redirected ? { ...head, json: { ...head.json, redirected: true } } : head;
|
|
19217
19296
|
} catch (e) {
|
|
19218
19297
|
entry.upload?.cancel();
|
|
19219
|
-
|
|
19220
|
-
|
|
19221
|
-
|
|
19222
|
-
|
|
19223
|
-
|
|
19224
|
-
|
|
19225
|
-
|
|
19226
|
-
|
|
19227
|
-
}
|
|
19228
|
-
entry.body = once(new TextEncoder().encode(text))[Symbol.asyncIterator]();
|
|
19229
|
-
return this.headOf(handle, req.url, {
|
|
19230
|
-
status,
|
|
19231
|
-
statusText: "",
|
|
19232
|
-
headers: [["content-type", "text/plain; charset=utf-8"]]
|
|
19233
|
-
});
|
|
19298
|
+
if (port !== void 0) return { ok: false, errno: codeOf2(e), message: message2(e) };
|
|
19299
|
+
return this.failure(handle, req, e, entry);
|
|
19300
|
+
}
|
|
19301
|
+
}
|
|
19302
|
+
failure(handle, req, e, entry) {
|
|
19303
|
+
const text = message2(e);
|
|
19304
|
+
if (e instanceof PlaceholderRefused) {
|
|
19305
|
+
return { ok: false, errno: e.code, message: text, detail: "placeholder" };
|
|
19234
19306
|
}
|
|
19307
|
+
const status = e.status;
|
|
19308
|
+
if (text === NO_TRANSPORT || typeof status !== "number" || status === 502) {
|
|
19309
|
+
const code = codeOf2(e);
|
|
19310
|
+
const errno3 = text === NO_TRANSPORT ? "ENETUNREACH" : code !== "EIO" ? code : "ECONNREFUSED";
|
|
19311
|
+
const failed3 = e.detail === "transport";
|
|
19312
|
+
return { ok: false, errno: errno3, message: text, ...failed3 ? { detail: "transport" } : {} };
|
|
19313
|
+
}
|
|
19314
|
+
entry.body = once(new TextEncoder().encode(text))[Symbol.asyncIterator]();
|
|
19315
|
+
return this.headOf(handle, req.url, {
|
|
19316
|
+
status,
|
|
19317
|
+
statusText: "",
|
|
19318
|
+
headers: [["content-type", "text/plain; charset=utf-8"]]
|
|
19319
|
+
});
|
|
19235
19320
|
}
|
|
19236
19321
|
headOf(handle, url, response) {
|
|
19237
19322
|
const { status, statusText, headers } = response;
|
|
@@ -22442,7 +22527,7 @@ var HEAD_MAX = 16 * 1024;
|
|
|
22442
22527
|
var ANY_PLACEHOLDER = /fnox_proxy_[0-9a-f]{24}/g;
|
|
22443
22528
|
var REQUEST_LINE2 = /^([!#$%&'*+.^_`|~0-9A-Za-z-]+) ([\x21-\x7e]+) HTTP\/1\.[01]$/;
|
|
22444
22529
|
var HEADER_LINE = /^([!#$%&'*+.^_`|~0-9A-Za-z-]+):[ \t]*(.*?)[ \t]*$/;
|
|
22445
|
-
var
|
|
22530
|
+
var BASIC2 = /^(Basic[ \t]+)([A-Za-z0-9+/]+={0,2})$/i;
|
|
22446
22531
|
var encoder8 = new TextEncoder();
|
|
22447
22532
|
function binary(text) {
|
|
22448
22533
|
let out = "";
|
|
@@ -22458,7 +22543,7 @@ function sniffHttp1(start2) {
|
|
|
22458
22543
|
return "no";
|
|
22459
22544
|
}
|
|
22460
22545
|
function basicOf(value2) {
|
|
22461
|
-
const m =
|
|
22546
|
+
const m = BASIC2.exec(value2);
|
|
22462
22547
|
if (!m) return void 0;
|
|
22463
22548
|
try {
|
|
22464
22549
|
return { scheme: m[1], decoded: atob(m[2]) };
|
|
@@ -28956,6 +29041,234 @@ function enableDnsStub(net, stub) {
|
|
|
28956
29041
|
});
|
|
28957
29042
|
}
|
|
28958
29043
|
|
|
29044
|
+
// src/kernel/net/remote-transport.ts
|
|
29045
|
+
var TransportError = class extends Error {
|
|
29046
|
+
status;
|
|
29047
|
+
code;
|
|
29048
|
+
detail;
|
|
29049
|
+
constructor(message3, status, code, detail) {
|
|
29050
|
+
super(message3);
|
|
29051
|
+
this.status = status;
|
|
29052
|
+
this.code = code;
|
|
29053
|
+
this.detail = detail === "transport" ? detail : void 0;
|
|
29054
|
+
}
|
|
29055
|
+
};
|
|
29056
|
+
function unfollowed2(redirect) {
|
|
29057
|
+
return redirect !== void 0 && redirect !== "follow";
|
|
29058
|
+
}
|
|
29059
|
+
function honors(traits, redirect) {
|
|
29060
|
+
if (traits.redirectPolicy === true) return true;
|
|
29061
|
+
const hops = traits.redirectHops;
|
|
29062
|
+
const raw2 = traits.manualRedirects === true && (hops === void 0 || hops === false);
|
|
29063
|
+
return redirect === "manual" && raw2;
|
|
29064
|
+
}
|
|
29065
|
+
function refused3(message3) {
|
|
29066
|
+
return new TransportError(message3, 502, void 0, "transport");
|
|
29067
|
+
}
|
|
29068
|
+
var RemoteTransport = class {
|
|
29069
|
+
traits;
|
|
29070
|
+
port;
|
|
29071
|
+
waiting = /* @__PURE__ */ new Map();
|
|
29072
|
+
nextId = 0;
|
|
29073
|
+
sockets = /* @__PURE__ */ new Map();
|
|
29074
|
+
uploads = /* @__PURE__ */ new Map();
|
|
29075
|
+
failure;
|
|
29076
|
+
constructor(port, traits) {
|
|
29077
|
+
this.port = port;
|
|
29078
|
+
this.traits = traits;
|
|
29079
|
+
}
|
|
29080
|
+
receive(reply) {
|
|
29081
|
+
if (reply.net === "body-pull") {
|
|
29082
|
+
void this.pull(reply.nid);
|
|
29083
|
+
return;
|
|
29084
|
+
}
|
|
29085
|
+
const socket = this.sockets.get(reply.nid);
|
|
29086
|
+
if (socket && this.toSocket(reply, socket)) return;
|
|
29087
|
+
const waiter = this.waiting.get(reply.nid);
|
|
29088
|
+
if (!waiter) return;
|
|
29089
|
+
this.waiting.delete(reply.nid);
|
|
29090
|
+
if (reply.net === "error") {
|
|
29091
|
+
waiter.reject(new TransportError(reply.message, reply.status, reply.code, reply.detail));
|
|
29092
|
+
} else waiter.resolve(reply);
|
|
29093
|
+
}
|
|
29094
|
+
toSocket(reply, socket) {
|
|
29095
|
+
if (reply.net === "ws-message") socket.queue.push(reply.data);
|
|
29096
|
+
else if (reply.net === "ws-acked") socket.acked(reply.n);
|
|
29097
|
+
else if (reply.net === "ws-closed") {
|
|
29098
|
+
this.sockets.delete(reply.nid);
|
|
29099
|
+
socket.queue.end({ code: reply.code, reason: reply.reason });
|
|
29100
|
+
} else return false;
|
|
29101
|
+
return true;
|
|
29102
|
+
}
|
|
29103
|
+
async pull(nid) {
|
|
29104
|
+
const upload = this.uploads.get(nid);
|
|
29105
|
+
if (!upload) {
|
|
29106
|
+
this.port.postMessage({ net: "body-error", nid, message: "the request body is gone" });
|
|
29107
|
+
return;
|
|
29108
|
+
}
|
|
29109
|
+
try {
|
|
29110
|
+
const next3 = await upload.next();
|
|
29111
|
+
if (next3.done) {
|
|
29112
|
+
this.uploads.delete(nid);
|
|
29113
|
+
this.port.postMessage({ net: "body-end", nid });
|
|
29114
|
+
} else this.port.postMessage({ net: "body-chunk", nid, bytes: next3.value });
|
|
29115
|
+
} catch (e) {
|
|
29116
|
+
this.uploads.delete(nid);
|
|
29117
|
+
this.port.postMessage({
|
|
29118
|
+
net: "body-error",
|
|
29119
|
+
nid,
|
|
29120
|
+
message: e instanceof Error ? e.message : String(e)
|
|
29121
|
+
});
|
|
29122
|
+
}
|
|
29123
|
+
}
|
|
29124
|
+
dropUpload(nid) {
|
|
29125
|
+
const upload = this.uploads.get(nid);
|
|
29126
|
+
this.uploads.delete(nid);
|
|
29127
|
+
void upload?.return?.().catch(() => void 0);
|
|
29128
|
+
}
|
|
29129
|
+
fail(error) {
|
|
29130
|
+
this.failure = error;
|
|
29131
|
+
for (const nid of [...this.uploads.keys()]) this.dropUpload(nid);
|
|
29132
|
+
for (const waiter of this.waiting.values()) waiter.reject(error);
|
|
29133
|
+
this.waiting.clear();
|
|
29134
|
+
for (const socket of this.sockets.values())
|
|
29135
|
+
socket.queue.end({ code: 1011, reason: error.message });
|
|
29136
|
+
this.sockets.clear();
|
|
29137
|
+
}
|
|
29138
|
+
ask(call) {
|
|
29139
|
+
if (this.failure) return Promise.reject(this.failure);
|
|
29140
|
+
return new Promise((resolve2, reject) => {
|
|
29141
|
+
this.waiting.set(call.nid, { resolve: resolve2, reject });
|
|
29142
|
+
this.port.postMessage(call);
|
|
29143
|
+
});
|
|
29144
|
+
}
|
|
29145
|
+
cancel(nid) {
|
|
29146
|
+
const waiter = this.waiting.get(nid);
|
|
29147
|
+
this.waiting.delete(nid);
|
|
29148
|
+
waiter?.reject(new TransportError("the request was cancelled"));
|
|
29149
|
+
this.port.postMessage({ net: "cancel", nid });
|
|
29150
|
+
}
|
|
29151
|
+
async fetch(request3) {
|
|
29152
|
+
const nid = ++this.nextId;
|
|
29153
|
+
const { signal, redirect } = request3;
|
|
29154
|
+
signal.throwIfAborted();
|
|
29155
|
+
if (unfollowed2(redirect) && !honors(this.traits, redirect)) {
|
|
29156
|
+
throw refused3(`this transport cannot honor redirect: ${redirect}`);
|
|
29157
|
+
}
|
|
29158
|
+
let finished = false;
|
|
29159
|
+
const abort = () => {
|
|
29160
|
+
finished = true;
|
|
29161
|
+
this.dropUpload(nid);
|
|
29162
|
+
this.cancel(nid);
|
|
29163
|
+
};
|
|
29164
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
29165
|
+
const finish = () => {
|
|
29166
|
+
this.dropUpload(nid);
|
|
29167
|
+
if (finished) return;
|
|
29168
|
+
finished = true;
|
|
29169
|
+
signal.removeEventListener("abort", abort);
|
|
29170
|
+
};
|
|
29171
|
+
if (request3.bodyStream) this.uploads.set(nid, request3.bodyStream[Symbol.asyncIterator]());
|
|
29172
|
+
let head;
|
|
29173
|
+
try {
|
|
29174
|
+
head = await this.ask({
|
|
29175
|
+
net: "fetch",
|
|
29176
|
+
nid,
|
|
29177
|
+
url: request3.url,
|
|
29178
|
+
method: request3.method,
|
|
29179
|
+
headers: request3.headers,
|
|
29180
|
+
...request3.bodyStream ? { streamed: true } : request3.body ? { body: request3.body } : {},
|
|
29181
|
+
...redirect !== void 0 ? { redirect } : {}
|
|
29182
|
+
});
|
|
29183
|
+
} catch (e) {
|
|
29184
|
+
finish();
|
|
29185
|
+
throw e;
|
|
29186
|
+
}
|
|
29187
|
+
const { status, statusText, headers, url, redirected: redirected2, redirects, opaqueRedirect } = head;
|
|
29188
|
+
const read = async () => {
|
|
29189
|
+
if (finished) return void 0;
|
|
29190
|
+
const reply = await this.ask({ net: "read", nid }).catch((e) => {
|
|
29191
|
+
finish();
|
|
29192
|
+
throw e;
|
|
29193
|
+
});
|
|
29194
|
+
if (reply.net === "chunk") return reply.bytes;
|
|
29195
|
+
finish();
|
|
29196
|
+
return void 0;
|
|
29197
|
+
};
|
|
29198
|
+
const cancel = async () => {
|
|
29199
|
+
if (finished) return;
|
|
29200
|
+
finish();
|
|
29201
|
+
this.cancel(nid);
|
|
29202
|
+
};
|
|
29203
|
+
if (unfollowed2(redirect) && (redirected2 || redirects?.length)) {
|
|
29204
|
+
await cancel();
|
|
29205
|
+
throw refused3(`this transport followed a redirect despite redirect: ${redirect}`);
|
|
29206
|
+
}
|
|
29207
|
+
return {
|
|
29208
|
+
...url !== void 0 ? { url } : {},
|
|
29209
|
+
...redirected2 !== void 0 ? { redirected: redirected2 } : {},
|
|
29210
|
+
...redirects ? { redirects } : {},
|
|
29211
|
+
...opaqueRedirect ? { opaqueRedirect } : {},
|
|
29212
|
+
status,
|
|
29213
|
+
statusText,
|
|
29214
|
+
headers,
|
|
29215
|
+
cancel,
|
|
29216
|
+
body: {
|
|
29217
|
+
[Symbol.asyncIterator]: () => ({
|
|
29218
|
+
next: async () => {
|
|
29219
|
+
const bytes = await read();
|
|
29220
|
+
return bytes ? { value: bytes, done: false } : { value: void 0, done: true };
|
|
29221
|
+
},
|
|
29222
|
+
return: async () => {
|
|
29223
|
+
await cancel();
|
|
29224
|
+
return { value: void 0, done: true };
|
|
29225
|
+
}
|
|
29226
|
+
})
|
|
29227
|
+
}
|
|
29228
|
+
};
|
|
29229
|
+
}
|
|
29230
|
+
async websocket(request3) {
|
|
29231
|
+
const nid = ++this.nextId;
|
|
29232
|
+
const { signal } = request3;
|
|
29233
|
+
signal.throwIfAborted();
|
|
29234
|
+
const abort = () => this.cancel(nid);
|
|
29235
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
29236
|
+
let opened2;
|
|
29237
|
+
try {
|
|
29238
|
+
opened2 = await this.ask({
|
|
29239
|
+
net: "ws-open",
|
|
29240
|
+
nid,
|
|
29241
|
+
url: request3.url,
|
|
29242
|
+
protocols: request3.protocols,
|
|
29243
|
+
headers: request3.headers
|
|
29244
|
+
});
|
|
29245
|
+
} finally {
|
|
29246
|
+
signal.removeEventListener("abort", abort);
|
|
29247
|
+
}
|
|
29248
|
+
const close = (code, reason) => this.port.postMessage({ net: "ws-close", nid, code, reason });
|
|
29249
|
+
const queue = new MessageQueue(
|
|
29250
|
+
() => close(1e3, "a message is too big"),
|
|
29251
|
+
Number.POSITIVE_INFINITY,
|
|
29252
|
+
(n) => this.port.postMessage({ net: "ws-consumed", nid, n })
|
|
29253
|
+
);
|
|
29254
|
+
let unacked = 0;
|
|
29255
|
+
this.sockets.set(nid, { queue, acked: (n) => void (unacked -= n) });
|
|
29256
|
+
return {
|
|
29257
|
+
protocol: opened2.protocol,
|
|
29258
|
+
get buffered() {
|
|
29259
|
+
return unacked;
|
|
29260
|
+
},
|
|
29261
|
+
send: (data) => {
|
|
29262
|
+
unacked += payloadSize(data);
|
|
29263
|
+
this.port.postMessage({ net: "ws-send", nid, data });
|
|
29264
|
+
},
|
|
29265
|
+
messages: queue,
|
|
29266
|
+
close,
|
|
29267
|
+
closed: queue.closed
|
|
29268
|
+
};
|
|
29269
|
+
}
|
|
29270
|
+
};
|
|
29271
|
+
|
|
28959
29272
|
// src/kernel/net/redirect-hops.ts
|
|
28960
29273
|
var HELD_MS = 3e4;
|
|
28961
29274
|
var HELD_MAX2 = 64;
|
|
@@ -29031,7 +29344,10 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
29031
29344
|
return { ...inner.traits, manualRedirects: true };
|
|
29032
29345
|
},
|
|
29033
29346
|
...inner.websocket ? { websocket: inner.websocket.bind(inner) } : {},
|
|
29034
|
-
async fetch(request3,
|
|
29347
|
+
async fetch(request3, ...rest2) {
|
|
29348
|
+
if (unfollowed2(request3.redirect)) return inner.fetch(request3, ...rest2);
|
|
29349
|
+
const [caller] = rest2;
|
|
29350
|
+
const owner = caller ?? KERNEL;
|
|
29035
29351
|
const key = keyOf3(owner, request3.method, request3.url);
|
|
29036
29352
|
const waiting = held.get(key);
|
|
29037
29353
|
if (waiting && waiting.fingerprint === fingerprint(request3.headers)) {
|
|
@@ -29040,7 +29356,7 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
29040
29356
|
return replay(waiting);
|
|
29041
29357
|
}
|
|
29042
29358
|
if (waiting) drop(key);
|
|
29043
|
-
const response = await inner.fetch(request3);
|
|
29359
|
+
const response = await inner.fetch(request3, ...rest2);
|
|
29044
29360
|
if (!response.redirects?.length) return response;
|
|
29045
29361
|
return replay({
|
|
29046
29362
|
owner,
|
|
@@ -29479,9 +29795,9 @@ function serveFilesystem(port, handlers, capabilities = {}, options = {}) {
|
|
|
29479
29795
|
let open2 = false;
|
|
29480
29796
|
const reply = (message3, transfer = []) => port.postMessage(message3, transfer);
|
|
29481
29797
|
async function hello(message3) {
|
|
29482
|
-
const
|
|
29483
|
-
if (
|
|
29484
|
-
reply({ hello: { protocol: DRIVER_PROTOCOL, error:
|
|
29798
|
+
const refused4 = driverVersionError(message3.protocol);
|
|
29799
|
+
if (refused4) {
|
|
29800
|
+
reply({ hello: { protocol: DRIVER_PROTOCOL, error: refused4, errno: "EPROTO" } });
|
|
29485
29801
|
return;
|
|
29486
29802
|
}
|
|
29487
29803
|
try {
|
|
@@ -31883,7 +32199,7 @@ var Launcher = class {
|
|
|
31883
32199
|
...options.env
|
|
31884
32200
|
};
|
|
31885
32201
|
this.ca = kernelCa(options.caStore ?? memoryCaStore());
|
|
31886
|
-
this.transport = replayingHops(options.transport ?? missingTransport());
|
|
32202
|
+
this.transport = placeholderFloor(replayingHops(options.transport ?? missingTransport()));
|
|
31887
32203
|
this.announcedTraits = JSON.stringify(this.transport.traits);
|
|
31888
32204
|
this.uplink = options.uplink;
|
|
31889
32205
|
this.routes = new Routes(options.uplink?.traits.ipv6 === true);
|
|
@@ -32038,16 +32354,16 @@ var Launcher = class {
|
|
|
32038
32354
|
if (!found) {
|
|
32039
32355
|
found = this.swaps.settled().then(() => this.trustedAppended()).then(async (appended2) => {
|
|
32040
32356
|
const tiers = await this.tiers(scope, appended2);
|
|
32041
|
-
const
|
|
32357
|
+
const refused4 = [];
|
|
32042
32358
|
const commands = await scanCommands(
|
|
32043
32359
|
this.scanned,
|
|
32044
32360
|
tiers,
|
|
32045
32361
|
tiers.length - appended2.length,
|
|
32046
32362
|
void 0,
|
|
32047
|
-
|
|
32363
|
+
refused4,
|
|
32048
32364
|
await this.globalRoots(scope)
|
|
32049
32365
|
);
|
|
32050
|
-
this.refusedOf.set(commands,
|
|
32366
|
+
this.refusedOf.set(commands, refused4.map(refusing));
|
|
32051
32367
|
return commands;
|
|
32052
32368
|
}).then(
|
|
32053
32369
|
(commands) => this.refusals(commands).set(SUDO_COMMAND.name, SUDO_COMMAND).set(CRONTAB_COMMAND.name, CRONTAB_COMMAND)
|
|
@@ -32253,14 +32569,14 @@ var Launcher = class {
|
|
|
32253
32569
|
return await this.commandAt(path, scope) ?? await this.refusedAt(path, name2, scope);
|
|
32254
32570
|
}
|
|
32255
32571
|
async refusedAt(path, name2, scope) {
|
|
32256
|
-
const
|
|
32257
|
-
if (
|
|
32572
|
+
const refused4 = this.refusedOf.get(await this.commands(scope)) ?? [];
|
|
32573
|
+
if (refused4.length === 0) return void 0;
|
|
32258
32574
|
const st = await this.base.stat(path).catch(() => void 0);
|
|
32259
32575
|
if (!st?.isFile) return void 0;
|
|
32260
32576
|
const real = await physicalPathAsync(this.base, path).catch(() => path);
|
|
32261
32577
|
const same3 = async (own) => own === path || await physicalPathAsync(this.base, own).catch(() => own) === real;
|
|
32262
32578
|
const owners = [];
|
|
32263
|
-
for (const c of
|
|
32579
|
+
for (const c of refused4) {
|
|
32264
32580
|
const origin = c.origin;
|
|
32265
32581
|
for (const own of [origin.glue, origin.wasm, ...origin.variants ?? []]) {
|
|
32266
32582
|
if (!await same3(own)) continue;
|
|
@@ -32270,11 +32586,11 @@ var Launcher = class {
|
|
|
32270
32586
|
}
|
|
32271
32587
|
const stem = name2.replace(/\.wasm$/, "");
|
|
32272
32588
|
const named = owners.find((c) => c.name === name2) ?? owners.find((c) => c.name === stem);
|
|
32273
|
-
return named ?? owners[0] ?? await this.refusedCopy(real, name2,
|
|
32589
|
+
return named ?? owners[0] ?? await this.refusedCopy(real, name2, refused4);
|
|
32274
32590
|
}
|
|
32275
|
-
async refusedCopy(real, name2,
|
|
32591
|
+
async refusedCopy(real, name2, refused4) {
|
|
32276
32592
|
const dir = real.slice(0, real.lastIndexOf("/"));
|
|
32277
|
-
for (const c of
|
|
32593
|
+
for (const c of refused4) {
|
|
32278
32594
|
const origin = c.origin;
|
|
32279
32595
|
if (origin.abi !== "emscripten" || origin.script || c.name !== name2) continue;
|
|
32280
32596
|
const own = await physicalPathAsync(this.base, origin.glue).catch(() => origin.glue);
|
|
@@ -32482,12 +32798,12 @@ var Launcher = class {
|
|
|
32482
32798
|
return void 0;
|
|
32483
32799
|
}
|
|
32484
32800
|
async planOne(req, { ppid, cred, scope }, catalogOnly = false) {
|
|
32485
|
-
const
|
|
32801
|
+
const refused4 = (err) => {
|
|
32486
32802
|
throw codeOf8(err) === "EACCES" ? new SpawnError("EACCES") : err;
|
|
32487
32803
|
};
|
|
32488
|
-
const file = await this.execFile(req.file, req.cwd, this.execGuard(cred, ppid)).catch(
|
|
32804
|
+
const file = await this.execFile(req.file, req.cwd, this.execGuard(cred, ppid)).catch(refused4);
|
|
32489
32805
|
const planned = await this.plan(file, req.argv, req.cwd, scope, req.argv0, catalogOnly);
|
|
32490
|
-
await this.mayExec(cred, { ...req, file, pid: ppid }, planned).catch(
|
|
32806
|
+
await this.mayExec(cred, { ...req, file, pid: ppid }, planned).catch(refused4);
|
|
32491
32807
|
if (planned) return planned;
|
|
32492
32808
|
throw new SpawnError(catalogOnly ? "ENOENT" : await this.unrunnable(file, req.cwd, scope));
|
|
32493
32809
|
}
|
|
@@ -34467,212 +34783,6 @@ function integrityAsker(port) {
|
|
|
34467
34783
|
return { lookup: lookup2, answer: answer2 };
|
|
34468
34784
|
}
|
|
34469
34785
|
|
|
34470
|
-
// src/kernel/net/remote-transport.ts
|
|
34471
|
-
var TransportError = class extends Error {
|
|
34472
|
-
status;
|
|
34473
|
-
code;
|
|
34474
|
-
detail;
|
|
34475
|
-
constructor(message3, status, code, detail) {
|
|
34476
|
-
super(message3);
|
|
34477
|
-
this.status = status;
|
|
34478
|
-
this.code = code;
|
|
34479
|
-
this.detail = detail === "transport" ? detail : void 0;
|
|
34480
|
-
}
|
|
34481
|
-
};
|
|
34482
|
-
var RemoteTransport = class {
|
|
34483
|
-
traits;
|
|
34484
|
-
port;
|
|
34485
|
-
waiting = /* @__PURE__ */ new Map();
|
|
34486
|
-
nextId = 0;
|
|
34487
|
-
sockets = /* @__PURE__ */ new Map();
|
|
34488
|
-
uploads = /* @__PURE__ */ new Map();
|
|
34489
|
-
failure;
|
|
34490
|
-
constructor(port, traits) {
|
|
34491
|
-
this.port = port;
|
|
34492
|
-
this.traits = traits;
|
|
34493
|
-
}
|
|
34494
|
-
receive(reply) {
|
|
34495
|
-
if (reply.net === "body-pull") {
|
|
34496
|
-
void this.pull(reply.nid);
|
|
34497
|
-
return;
|
|
34498
|
-
}
|
|
34499
|
-
const socket = this.sockets.get(reply.nid);
|
|
34500
|
-
if (socket && this.toSocket(reply, socket)) return;
|
|
34501
|
-
const waiter = this.waiting.get(reply.nid);
|
|
34502
|
-
if (!waiter) return;
|
|
34503
|
-
this.waiting.delete(reply.nid);
|
|
34504
|
-
if (reply.net === "error") {
|
|
34505
|
-
waiter.reject(new TransportError(reply.message, reply.status, reply.code, reply.detail));
|
|
34506
|
-
} else waiter.resolve(reply);
|
|
34507
|
-
}
|
|
34508
|
-
toSocket(reply, socket) {
|
|
34509
|
-
if (reply.net === "ws-message") socket.queue.push(reply.data);
|
|
34510
|
-
else if (reply.net === "ws-acked") socket.acked(reply.n);
|
|
34511
|
-
else if (reply.net === "ws-closed") {
|
|
34512
|
-
this.sockets.delete(reply.nid);
|
|
34513
|
-
socket.queue.end({ code: reply.code, reason: reply.reason });
|
|
34514
|
-
} else return false;
|
|
34515
|
-
return true;
|
|
34516
|
-
}
|
|
34517
|
-
async pull(nid) {
|
|
34518
|
-
const upload = this.uploads.get(nid);
|
|
34519
|
-
if (!upload) {
|
|
34520
|
-
this.port.postMessage({ net: "body-error", nid, message: "the request body is gone" });
|
|
34521
|
-
return;
|
|
34522
|
-
}
|
|
34523
|
-
try {
|
|
34524
|
-
const next3 = await upload.next();
|
|
34525
|
-
if (next3.done) {
|
|
34526
|
-
this.uploads.delete(nid);
|
|
34527
|
-
this.port.postMessage({ net: "body-end", nid });
|
|
34528
|
-
} else this.port.postMessage({ net: "body-chunk", nid, bytes: next3.value });
|
|
34529
|
-
} catch (e) {
|
|
34530
|
-
this.uploads.delete(nid);
|
|
34531
|
-
this.port.postMessage({
|
|
34532
|
-
net: "body-error",
|
|
34533
|
-
nid,
|
|
34534
|
-
message: e instanceof Error ? e.message : String(e)
|
|
34535
|
-
});
|
|
34536
|
-
}
|
|
34537
|
-
}
|
|
34538
|
-
dropUpload(nid) {
|
|
34539
|
-
const upload = this.uploads.get(nid);
|
|
34540
|
-
this.uploads.delete(nid);
|
|
34541
|
-
void upload?.return?.().catch(() => void 0);
|
|
34542
|
-
}
|
|
34543
|
-
fail(error) {
|
|
34544
|
-
this.failure = error;
|
|
34545
|
-
for (const nid of [...this.uploads.keys()]) this.dropUpload(nid);
|
|
34546
|
-
for (const waiter of this.waiting.values()) waiter.reject(error);
|
|
34547
|
-
this.waiting.clear();
|
|
34548
|
-
for (const socket of this.sockets.values())
|
|
34549
|
-
socket.queue.end({ code: 1011, reason: error.message });
|
|
34550
|
-
this.sockets.clear();
|
|
34551
|
-
}
|
|
34552
|
-
ask(call) {
|
|
34553
|
-
if (this.failure) return Promise.reject(this.failure);
|
|
34554
|
-
return new Promise((resolve2, reject) => {
|
|
34555
|
-
this.waiting.set(call.nid, { resolve: resolve2, reject });
|
|
34556
|
-
this.port.postMessage(call);
|
|
34557
|
-
});
|
|
34558
|
-
}
|
|
34559
|
-
cancel(nid) {
|
|
34560
|
-
const waiter = this.waiting.get(nid);
|
|
34561
|
-
this.waiting.delete(nid);
|
|
34562
|
-
waiter?.reject(new TransportError("the request was cancelled"));
|
|
34563
|
-
this.port.postMessage({ net: "cancel", nid });
|
|
34564
|
-
}
|
|
34565
|
-
async fetch(request3) {
|
|
34566
|
-
const nid = ++this.nextId;
|
|
34567
|
-
const { signal } = request3;
|
|
34568
|
-
signal.throwIfAborted();
|
|
34569
|
-
let finished = false;
|
|
34570
|
-
const abort = () => {
|
|
34571
|
-
finished = true;
|
|
34572
|
-
this.dropUpload(nid);
|
|
34573
|
-
this.cancel(nid);
|
|
34574
|
-
};
|
|
34575
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
34576
|
-
const finish = () => {
|
|
34577
|
-
this.dropUpload(nid);
|
|
34578
|
-
if (finished) return;
|
|
34579
|
-
finished = true;
|
|
34580
|
-
signal.removeEventListener("abort", abort);
|
|
34581
|
-
};
|
|
34582
|
-
if (request3.bodyStream) this.uploads.set(nid, request3.bodyStream[Symbol.asyncIterator]());
|
|
34583
|
-
let head;
|
|
34584
|
-
try {
|
|
34585
|
-
head = await this.ask({
|
|
34586
|
-
net: "fetch",
|
|
34587
|
-
nid,
|
|
34588
|
-
url: request3.url,
|
|
34589
|
-
method: request3.method,
|
|
34590
|
-
headers: request3.headers,
|
|
34591
|
-
...request3.bodyStream ? { streamed: true } : request3.body ? { body: request3.body } : {}
|
|
34592
|
-
});
|
|
34593
|
-
} catch (e) {
|
|
34594
|
-
finish();
|
|
34595
|
-
throw e;
|
|
34596
|
-
}
|
|
34597
|
-
const { status, statusText, headers, url, redirected: redirected2, redirects } = head;
|
|
34598
|
-
const read = async () => {
|
|
34599
|
-
if (finished) return void 0;
|
|
34600
|
-
const reply = await this.ask({ net: "read", nid }).catch((e) => {
|
|
34601
|
-
finish();
|
|
34602
|
-
throw e;
|
|
34603
|
-
});
|
|
34604
|
-
if (reply.net === "chunk") return reply.bytes;
|
|
34605
|
-
finish();
|
|
34606
|
-
return void 0;
|
|
34607
|
-
};
|
|
34608
|
-
const cancel = async () => {
|
|
34609
|
-
if (finished) return;
|
|
34610
|
-
finish();
|
|
34611
|
-
this.cancel(nid);
|
|
34612
|
-
};
|
|
34613
|
-
return {
|
|
34614
|
-
...redirected2 ? { url, redirected: redirected2 } : {},
|
|
34615
|
-
...redirects ? { redirects } : {},
|
|
34616
|
-
status,
|
|
34617
|
-
statusText,
|
|
34618
|
-
headers,
|
|
34619
|
-
cancel,
|
|
34620
|
-
body: {
|
|
34621
|
-
[Symbol.asyncIterator]: () => ({
|
|
34622
|
-
next: async () => {
|
|
34623
|
-
const bytes = await read();
|
|
34624
|
-
return bytes ? { value: bytes, done: false } : { value: void 0, done: true };
|
|
34625
|
-
},
|
|
34626
|
-
return: async () => {
|
|
34627
|
-
await cancel();
|
|
34628
|
-
return { value: void 0, done: true };
|
|
34629
|
-
}
|
|
34630
|
-
})
|
|
34631
|
-
}
|
|
34632
|
-
};
|
|
34633
|
-
}
|
|
34634
|
-
async websocket(request3) {
|
|
34635
|
-
const nid = ++this.nextId;
|
|
34636
|
-
const { signal } = request3;
|
|
34637
|
-
signal.throwIfAborted();
|
|
34638
|
-
const abort = () => this.cancel(nid);
|
|
34639
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
34640
|
-
let opened2;
|
|
34641
|
-
try {
|
|
34642
|
-
opened2 = await this.ask({
|
|
34643
|
-
net: "ws-open",
|
|
34644
|
-
nid,
|
|
34645
|
-
url: request3.url,
|
|
34646
|
-
protocols: request3.protocols,
|
|
34647
|
-
headers: request3.headers
|
|
34648
|
-
});
|
|
34649
|
-
} finally {
|
|
34650
|
-
signal.removeEventListener("abort", abort);
|
|
34651
|
-
}
|
|
34652
|
-
const close = (code, reason) => this.port.postMessage({ net: "ws-close", nid, code, reason });
|
|
34653
|
-
const queue = new MessageQueue(
|
|
34654
|
-
() => close(1e3, "a message is too big"),
|
|
34655
|
-
Number.POSITIVE_INFINITY,
|
|
34656
|
-
(n) => this.port.postMessage({ net: "ws-consumed", nid, n })
|
|
34657
|
-
);
|
|
34658
|
-
let unacked = 0;
|
|
34659
|
-
this.sockets.set(nid, { queue, acked: (n) => void (unacked -= n) });
|
|
34660
|
-
return {
|
|
34661
|
-
protocol: opened2.protocol,
|
|
34662
|
-
get buffered() {
|
|
34663
|
-
return unacked;
|
|
34664
|
-
},
|
|
34665
|
-
send: (data) => {
|
|
34666
|
-
unacked += payloadSize(data);
|
|
34667
|
-
this.port.postMessage({ net: "ws-send", nid, data });
|
|
34668
|
-
},
|
|
34669
|
-
messages: queue,
|
|
34670
|
-
close,
|
|
34671
|
-
closed: queue.closed
|
|
34672
|
-
};
|
|
34673
|
-
}
|
|
34674
|
-
};
|
|
34675
|
-
|
|
34676
34786
|
// src/sealed-relay.ts
|
|
34677
34787
|
function sealedAsker(port) {
|
|
34678
34788
|
const asks = /* @__PURE__ */ new Map();
|