@ai-ecoverse/slicc-kernel 1.82.0 → 1.84.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 +26 -4
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +1025 -218
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +27 -5
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +1163 -250
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +27 -5
- package/dist/process-worker.js.map +3 -3
- package/package.json +3 -2
package/dist/kernel-worker.js
CHANGED
|
@@ -131,8 +131,8 @@ function descendants(path) {
|
|
|
131
131
|
return IDBKeyRange.bound(`${path}/`, `${path}0`, false, true);
|
|
132
132
|
}
|
|
133
133
|
function settle(transaction, value) {
|
|
134
|
-
return new Promise((
|
|
135
|
-
transaction.oncomplete = () =>
|
|
134
|
+
return new Promise((resolve2, reject) => {
|
|
135
|
+
transaction.oncomplete = () => resolve2(value());
|
|
136
136
|
transaction.onabort = () => reject(transaction.error ?? new Error("metadata transaction aborted"));
|
|
137
137
|
});
|
|
138
138
|
}
|
|
@@ -249,14 +249,14 @@ var IndexedDbMeta = class {
|
|
|
249
249
|
}
|
|
250
250
|
};
|
|
251
251
|
function openMeta(name2, factory) {
|
|
252
|
-
return new Promise((
|
|
252
|
+
return new Promise((resolve2, reject) => {
|
|
253
253
|
const request2 = factory.open(name2, META_VERSION);
|
|
254
254
|
request2.onupgradeneeded = (event) => {
|
|
255
255
|
if (event.oldVersion < 1) {
|
|
256
256
|
request2.result.createObjectStore(META_STORE, { keyPath: "path" }).createIndex("dir", "dir");
|
|
257
257
|
}
|
|
258
258
|
};
|
|
259
|
-
request2.onsuccess = () =>
|
|
259
|
+
request2.onsuccess = () => resolve2(new IndexedDbMeta(request2.result));
|
|
260
260
|
request2.onerror = () => reject(request2.error);
|
|
261
261
|
});
|
|
262
262
|
}
|
|
@@ -740,11 +740,11 @@ var RemoteWatch = class {
|
|
|
740
740
|
const seq2 = ++this.seq;
|
|
741
741
|
this.channel.postMessage({ tab: this.tab, paths: this.mine, seq: seq2 });
|
|
742
742
|
if (this.peers.size === 0) return Promise.resolve();
|
|
743
|
-
return new Promise((
|
|
743
|
+
return new Promise((resolve2) => {
|
|
744
744
|
const done4 = () => {
|
|
745
745
|
clearTimeout(timer);
|
|
746
746
|
this.waiting.delete(seq2);
|
|
747
|
-
|
|
747
|
+
resolve2();
|
|
748
748
|
};
|
|
749
749
|
const timer = setTimeout(() => {
|
|
750
750
|
done4();
|
|
@@ -840,7 +840,7 @@ async function openSync(handle) {
|
|
|
840
840
|
const delay = SYNC_BACKOFF_MS[attempt];
|
|
841
841
|
if (!LOCKED.has(err?.name)) throw err;
|
|
842
842
|
if (delay === void 0) return void 0;
|
|
843
|
-
await new Promise((
|
|
843
|
+
await new Promise((resolve2) => setTimeout(resolve2, delay));
|
|
844
844
|
}
|
|
845
845
|
}
|
|
846
846
|
}
|
|
@@ -1297,7 +1297,7 @@ var OpfsFs = class {
|
|
|
1297
1297
|
const again = name2 === "NotReadableError" || locks && LOCKED.has(name2);
|
|
1298
1298
|
if (!again || attempt >= READ_ATTEMPTS)
|
|
1299
1299
|
throw translate(err, path, locks ? "write" : "read");
|
|
1300
|
-
await new Promise((
|
|
1300
|
+
await new Promise((resolve2) => setTimeout(resolve2, attempt * 10));
|
|
1301
1301
|
}
|
|
1302
1302
|
}
|
|
1303
1303
|
}
|
|
@@ -1354,8 +1354,8 @@ var OpfsFs = class {
|
|
|
1354
1354
|
}
|
|
1355
1355
|
async truncate(path, size) {
|
|
1356
1356
|
const handle = await this.existing(path, true);
|
|
1357
|
-
const
|
|
1358
|
-
const target =
|
|
1357
|
+
const resolve2 = this.ranged || this.remote?.watched();
|
|
1358
|
+
const target = resolve2 ? (await this.locate(path, true)).path : path;
|
|
1359
1359
|
await this.retrying(path, () => positioned(handle, (io) => io.truncate(size)), true);
|
|
1360
1360
|
this.written(target);
|
|
1361
1361
|
}
|
|
@@ -1779,8 +1779,8 @@ function memoryMedia() {
|
|
|
1779
1779
|
};
|
|
1780
1780
|
}
|
|
1781
1781
|
function settle2(request2, value) {
|
|
1782
|
-
return new Promise((
|
|
1783
|
-
request2.onsuccess = () =>
|
|
1782
|
+
return new Promise((resolve2, reject) => {
|
|
1783
|
+
request2.onsuccess = () => resolve2(value());
|
|
1784
1784
|
request2.onerror = () => reject(request2.error);
|
|
1785
1785
|
});
|
|
1786
1786
|
}
|
|
@@ -1818,7 +1818,7 @@ function pinScript(url) {
|
|
|
1818
1818
|
|
|
1819
1819
|
// src/cdp/port.ts
|
|
1820
1820
|
function portCdpHook(ask, gone) {
|
|
1821
|
-
return (request2) => new Promise((
|
|
1821
|
+
return (request2) => new Promise((resolve2, reject) => {
|
|
1822
1822
|
const { port1, port2 } = new MessageChannel();
|
|
1823
1823
|
let closed = false;
|
|
1824
1824
|
const conn = {
|
|
@@ -1836,7 +1836,7 @@ function portCdpHook(ask, gone) {
|
|
|
1836
1836
|
};
|
|
1837
1837
|
port1.addEventListener("message", ({ data }) => {
|
|
1838
1838
|
if ("m" in data) conn.onmessage?.(data.m);
|
|
1839
|
-
else if ("open" in data)
|
|
1839
|
+
else if ("open" in data) resolve2(conn);
|
|
1840
1840
|
else if ("error" in data) {
|
|
1841
1841
|
closed = true;
|
|
1842
1842
|
port1.close();
|
|
@@ -2370,9 +2370,9 @@ var KernelPipe = class {
|
|
|
2370
2370
|
let filled = 0;
|
|
2371
2371
|
for (const chunk2 of this.chunks) {
|
|
2372
2372
|
if (filled === out.length) break;
|
|
2373
|
-
const
|
|
2374
|
-
out.set(chunk2.subarray(0,
|
|
2375
|
-
filled +=
|
|
2373
|
+
const count2 = Math.min(chunk2.length, out.length - filled);
|
|
2374
|
+
out.set(chunk2.subarray(0, count2), filled);
|
|
2375
|
+
filled += count2;
|
|
2376
2376
|
}
|
|
2377
2377
|
return out;
|
|
2378
2378
|
}
|
|
@@ -2403,25 +2403,25 @@ var KernelPipe = class {
|
|
|
2403
2403
|
let filled = 0;
|
|
2404
2404
|
while (filled < n) {
|
|
2405
2405
|
const head = this.chunks[0];
|
|
2406
|
-
const
|
|
2407
|
-
out.set(head.subarray(0,
|
|
2408
|
-
filled +=
|
|
2409
|
-
if (
|
|
2410
|
-
else this.chunks[0] = head.subarray(
|
|
2406
|
+
const count2 = Math.min(head.length, n - filled);
|
|
2407
|
+
out.set(head.subarray(0, count2), filled);
|
|
2408
|
+
filled += count2;
|
|
2409
|
+
if (count2 === head.length) this.chunks.shift();
|
|
2410
|
+
else this.chunks[0] = head.subarray(count2);
|
|
2411
2411
|
}
|
|
2412
2412
|
this.size -= n;
|
|
2413
2413
|
return out;
|
|
2414
2414
|
}
|
|
2415
2415
|
changed(signal) {
|
|
2416
2416
|
if (signal?.aborted) return Promise.reject(new PipeError("EINTR"));
|
|
2417
|
-
return new Promise((
|
|
2417
|
+
return new Promise((resolve2, reject) => {
|
|
2418
2418
|
const onAbort = () => {
|
|
2419
2419
|
this.waiters = this.waiters.filter((w) => w !== waiter);
|
|
2420
2420
|
reject(new PipeError("EINTR"));
|
|
2421
2421
|
};
|
|
2422
2422
|
const waiter = () => {
|
|
2423
2423
|
signal?.removeEventListener("abort", onAbort);
|
|
2424
|
-
|
|
2424
|
+
resolve2();
|
|
2425
2425
|
};
|
|
2426
2426
|
this.waiters.push(waiter);
|
|
2427
2427
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
@@ -2430,7 +2430,7 @@ var KernelPipe = class {
|
|
|
2430
2430
|
wake() {
|
|
2431
2431
|
const waiters = this.waiters;
|
|
2432
2432
|
this.waiters = [];
|
|
2433
|
-
for (const
|
|
2433
|
+
for (const resolve2 of waiters) resolve2();
|
|
2434
2434
|
}
|
|
2435
2435
|
};
|
|
2436
2436
|
|
|
@@ -2891,14 +2891,14 @@ var Changes = class {
|
|
|
2891
2891
|
waiters = [];
|
|
2892
2892
|
wait(signal) {
|
|
2893
2893
|
if (signal?.aborted) return Promise.reject(new KernelError("EINTR"));
|
|
2894
|
-
return new Promise((
|
|
2894
|
+
return new Promise((resolve2, reject) => {
|
|
2895
2895
|
const onAbort = () => {
|
|
2896
2896
|
this.waiters = this.waiters.filter((w) => w !== waiter);
|
|
2897
2897
|
reject(new KernelError("EINTR"));
|
|
2898
2898
|
};
|
|
2899
2899
|
const waiter = () => {
|
|
2900
2900
|
signal?.removeEventListener("abort", onAbort);
|
|
2901
|
-
|
|
2901
|
+
resolve2();
|
|
2902
2902
|
};
|
|
2903
2903
|
this.waiters.push(waiter);
|
|
2904
2904
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
@@ -2907,7 +2907,7 @@ var Changes = class {
|
|
|
2907
2907
|
wake() {
|
|
2908
2908
|
const waiters = this.waiters;
|
|
2909
2909
|
this.waiters = [];
|
|
2910
|
-
for (const
|
|
2910
|
+
for (const resolve2 of waiters) resolve2();
|
|
2911
2911
|
}
|
|
2912
2912
|
};
|
|
2913
2913
|
function link(a, b) {
|
|
@@ -3075,7 +3075,7 @@ var KernelSocket = class _KernelSocket {
|
|
|
3075
3075
|
});
|
|
3076
3076
|
const { host, port } = addr;
|
|
3077
3077
|
const dialled = new Promise(
|
|
3078
|
-
(
|
|
3078
|
+
(resolve2) => resolve2(route.uplink.dial({ network: "tcp", host, port, signal: abort.signal }))
|
|
3079
3079
|
);
|
|
3080
3080
|
dialled.then(
|
|
3081
3081
|
(conn) => abort.signal.aborted && conn.close(),
|
|
@@ -3425,8 +3425,8 @@ var MessageQueue = class {
|
|
|
3425
3425
|
this.overflow = overflow;
|
|
3426
3426
|
this.limit = limit;
|
|
3427
3427
|
this.taken = taken;
|
|
3428
|
-
this.closed = new Promise((
|
|
3429
|
-
this.settle =
|
|
3428
|
+
this.closed = new Promise((resolve2) => {
|
|
3429
|
+
this.settle = resolve2;
|
|
3430
3430
|
});
|
|
3431
3431
|
}
|
|
3432
3432
|
push(message3) {
|
|
@@ -3465,8 +3465,8 @@ var MessageQueue = class {
|
|
|
3465
3465
|
continue;
|
|
3466
3466
|
}
|
|
3467
3467
|
if (this.ended) return;
|
|
3468
|
-
await new Promise((
|
|
3469
|
-
this.waiter =
|
|
3468
|
+
await new Promise((resolve2) => {
|
|
3469
|
+
this.waiter = resolve2;
|
|
3470
3470
|
});
|
|
3471
3471
|
}
|
|
3472
3472
|
}
|
|
@@ -3557,8 +3557,8 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS } = {}) {
|
|
|
3557
3557
|
const relay = async (nid, socket) => {
|
|
3558
3558
|
let ending;
|
|
3559
3559
|
let late;
|
|
3560
|
-
const unanswered = new Promise((
|
|
3561
|
-
late = () =>
|
|
3560
|
+
const unanswered = new Promise((resolve2) => {
|
|
3561
|
+
late = () => resolve2("late");
|
|
3562
3562
|
});
|
|
3563
3563
|
const flow = {
|
|
3564
3564
|
inflight: 0,
|
|
@@ -3586,8 +3586,8 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS } = {}) {
|
|
|
3586
3586
|
}
|
|
3587
3587
|
flow.inflight += payloadSize(data);
|
|
3588
3588
|
while (flow.inflight > INBOUND_LIMIT && !flow.closing) {
|
|
3589
|
-
await new Promise((
|
|
3590
|
-
flow.wake =
|
|
3589
|
+
await new Promise((resolve2) => {
|
|
3590
|
+
flow.wake = resolve2;
|
|
3591
3591
|
});
|
|
3592
3592
|
}
|
|
3593
3593
|
}
|
|
@@ -3606,7 +3606,7 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS } = {}) {
|
|
|
3606
3606
|
if (!socket) return;
|
|
3607
3607
|
socket.send(call.data);
|
|
3608
3608
|
while (socket.buffered > SEND_BUFFER && sockets.has(call.nid)) {
|
|
3609
|
-
await new Promise((
|
|
3609
|
+
await new Promise((resolve2) => setTimeout(resolve2, 10));
|
|
3610
3610
|
}
|
|
3611
3611
|
peer.postMessage({ net: "ws-acked", nid: call.nid, n: payloadSize(call.data) });
|
|
3612
3612
|
};
|
|
@@ -5113,10 +5113,10 @@ var Budget = class {
|
|
|
5113
5113
|
async acquire(n, signal) {
|
|
5114
5114
|
while (this.free < n) {
|
|
5115
5115
|
signal.throwIfAborted();
|
|
5116
|
-
await new Promise((
|
|
5116
|
+
await new Promise((resolve2) => {
|
|
5117
5117
|
const done4 = () => {
|
|
5118
5118
|
signal.removeEventListener("abort", done4);
|
|
5119
|
-
|
|
5119
|
+
resolve2();
|
|
5120
5120
|
};
|
|
5121
5121
|
this.waiters.push(done4);
|
|
5122
5122
|
signal.addEventListener("abort", done4, { once: true });
|
|
@@ -5258,14 +5258,14 @@ async function watchHangup(conn, abort, until) {
|
|
|
5258
5258
|
}
|
|
5259
5259
|
}
|
|
5260
5260
|
function untilAborted(response, signal) {
|
|
5261
|
-
return new Promise((
|
|
5261
|
+
return new Promise((resolve2, reject) => {
|
|
5262
5262
|
const onAbort = () => {
|
|
5263
5263
|
reject(signal.reason ?? new KernelError("EINTR"));
|
|
5264
5264
|
response.then((late) => late.cancel()).catch(() => void 0);
|
|
5265
5265
|
};
|
|
5266
5266
|
if (signal.aborted) return onAbort();
|
|
5267
5267
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
5268
|
-
response.then(
|
|
5268
|
+
response.then(resolve2, reject).finally(() => signal.removeEventListener("abort", onAbort));
|
|
5269
5269
|
});
|
|
5270
5270
|
}
|
|
5271
5271
|
function plainResponse(status, message3) {
|
|
@@ -5298,8 +5298,8 @@ function wireCode(code) {
|
|
|
5298
5298
|
return sendableCode(code) ? code : 1011;
|
|
5299
5299
|
}
|
|
5300
5300
|
function quietly(ms) {
|
|
5301
|
-
return new Promise((
|
|
5302
|
-
AbortSignal.timeout(ms).addEventListener("abort", () =>
|
|
5301
|
+
return new Promise((resolve2) => {
|
|
5302
|
+
AbortSignal.timeout(ms).addEventListener("abort", () => resolve2(), { once: true });
|
|
5303
5303
|
});
|
|
5304
5304
|
}
|
|
5305
5305
|
var RealmProxy = class {
|
|
@@ -5397,7 +5397,7 @@ var RealmProxy = class {
|
|
|
5397
5397
|
return false;
|
|
5398
5398
|
}
|
|
5399
5399
|
const url = ctx.origin ? tunnelRequestUrl(req, ctx.origin) : requestUrl(req);
|
|
5400
|
-
const
|
|
5400
|
+
const keep2 = keepsAlive(req);
|
|
5401
5401
|
const framing = requestFraming(req.headers);
|
|
5402
5402
|
const reserve = framing.kind === "length" ? framing.length : framing.kind === "chunked" ? this.cap() : 0;
|
|
5403
5403
|
if (reserve > this.cap()) throw new HttpError(413, `request body over ${this.cap()} bytes`);
|
|
@@ -5420,7 +5420,7 @@ var RealmProxy = class {
|
|
|
5420
5420
|
} finally {
|
|
5421
5421
|
this.bodies.release(reserve);
|
|
5422
5422
|
}
|
|
5423
|
-
return await this.relay(conn, req.method, req.minor, response,
|
|
5423
|
+
return await this.relay(conn, req.method, req.minor, response, keep2);
|
|
5424
5424
|
} finally {
|
|
5425
5425
|
this.stop.signal.removeEventListener("abort", stopExchange);
|
|
5426
5426
|
abort.abort();
|
|
@@ -5468,8 +5468,8 @@ var RealmProxy = class {
|
|
|
5468
5468
|
bodiless: bodiless2
|
|
5469
5469
|
});
|
|
5470
5470
|
const chunked = !bodiless2 && minor >= 1;
|
|
5471
|
-
const
|
|
5472
|
-
headers.push(["Connection",
|
|
5471
|
+
const keep2 = keepAlive && (bodiless2 || chunked);
|
|
5472
|
+
headers.push(["Connection", keep2 ? "keep-alive" : "close"]);
|
|
5473
5473
|
if (chunked) headers.push(["Transfer-Encoding", "chunked"]);
|
|
5474
5474
|
const signal = this.stop.signal;
|
|
5475
5475
|
await conn.write(
|
|
@@ -5478,7 +5478,7 @@ var RealmProxy = class {
|
|
|
5478
5478
|
);
|
|
5479
5479
|
if (bodiless2) {
|
|
5480
5480
|
await response.cancel();
|
|
5481
|
-
return
|
|
5481
|
+
return keep2;
|
|
5482
5482
|
}
|
|
5483
5483
|
try {
|
|
5484
5484
|
for await (const piece of response.body) {
|
|
@@ -5489,7 +5489,7 @@ var RealmProxy = class {
|
|
|
5489
5489
|
return false;
|
|
5490
5490
|
}
|
|
5491
5491
|
if (chunked) await conn.write(LAST_CHUNK, signal);
|
|
5492
|
-
return
|
|
5492
|
+
return keep2;
|
|
5493
5493
|
}
|
|
5494
5494
|
async connect(conn, incoming, req, idle) {
|
|
5495
5495
|
const target = tunnelTarget(req);
|
|
@@ -5712,10 +5712,10 @@ function header(der, at) {
|
|
|
5712
5712
|
let len = der[at + 1];
|
|
5713
5713
|
let start2 = at + 2;
|
|
5714
5714
|
if (len & 128) {
|
|
5715
|
-
const
|
|
5715
|
+
const count2 = len & 127;
|
|
5716
5716
|
len = 0;
|
|
5717
|
-
for (let i = 0; i <
|
|
5718
|
-
start2 +=
|
|
5717
|
+
for (let i = 0; i < count2; i++) len = len * 256 + der[start2 + i];
|
|
5718
|
+
start2 += count2;
|
|
5719
5719
|
}
|
|
5720
5720
|
if (start2 + len > der.length) throw new Error("truncated DER");
|
|
5721
5721
|
return [tag, start2, start2 + len];
|
|
@@ -5833,18 +5833,18 @@ var LEAF_LIFETIME = 7 * DAY;
|
|
|
5833
5833
|
var ECDSA = { name: "ECDSA", namedCurve: "P-256" };
|
|
5834
5834
|
var SIGN = { name: "ECDSA", hash: "SHA-256" };
|
|
5835
5835
|
function request(req) {
|
|
5836
|
-
return new Promise((
|
|
5837
|
-
req.onsuccess = () =>
|
|
5836
|
+
return new Promise((resolve2, reject) => {
|
|
5837
|
+
req.onsuccess = () => resolve2(req.result);
|
|
5838
5838
|
req.onerror = () => reject(req.error);
|
|
5839
5839
|
});
|
|
5840
5840
|
}
|
|
5841
5841
|
function indexedDbCaStore(dbName = "slicc-realm-ca") {
|
|
5842
5842
|
let db;
|
|
5843
5843
|
const open = () => {
|
|
5844
|
-
db ??= new Promise((
|
|
5844
|
+
db ??= new Promise((resolve2, reject) => {
|
|
5845
5845
|
const req = indexedDB.open(dbName, 1);
|
|
5846
5846
|
req.onupgradeneeded = () => req.result.createObjectStore("ca");
|
|
5847
|
-
req.onsuccess = () =>
|
|
5847
|
+
req.onsuccess = () => resolve2(req.result);
|
|
5848
5848
|
req.onerror = () => reject(req.error);
|
|
5849
5849
|
});
|
|
5850
5850
|
db.catch(() => {
|
|
@@ -5868,8 +5868,8 @@ function indexedDbCaStore(dbName = "slicc-realm-ca") {
|
|
|
5868
5868
|
if (kept === record) store.put(record, owner);
|
|
5869
5869
|
else stored = kept;
|
|
5870
5870
|
};
|
|
5871
|
-
await new Promise((
|
|
5872
|
-
tx.oncomplete = () =>
|
|
5871
|
+
await new Promise((resolve2, reject) => {
|
|
5872
|
+
tx.oncomplete = () => resolve2();
|
|
5873
5873
|
tx.onerror = () => reject(tx.error);
|
|
5874
5874
|
});
|
|
5875
5875
|
return stored;
|
|
@@ -6398,8 +6398,8 @@ var RemoteTransport = class {
|
|
|
6398
6398
|
}
|
|
6399
6399
|
ask(call) {
|
|
6400
6400
|
if (this.failure) return Promise.reject(this.failure);
|
|
6401
|
-
return new Promise((
|
|
6402
|
-
this.waiting.set(call.nid, { resolve, reject });
|
|
6401
|
+
return new Promise((resolve2, reject) => {
|
|
6402
|
+
this.waiting.set(call.nid, { resolve: resolve2, reject });
|
|
6403
6403
|
this.port.postMessage(call);
|
|
6404
6404
|
});
|
|
6405
6405
|
}
|
|
@@ -6804,7 +6804,7 @@ var CdpFacade = class {
|
|
|
6804
6804
|
const conn = await this.host(runtime);
|
|
6805
6805
|
try {
|
|
6806
6806
|
const reply = await new Promise(
|
|
6807
|
-
(
|
|
6807
|
+
(resolve2, reject) => {
|
|
6808
6808
|
const timer = setTimeout(
|
|
6809
6809
|
() => reject(new HttpError(504, "the CDP host did not answer Target.getTargets")),
|
|
6810
6810
|
this.options.listTimeout ?? LIST_TIMEOUT
|
|
@@ -6817,7 +6817,7 @@ var CdpFacade = class {
|
|
|
6817
6817
|
const parsed2 = JSON.parse(message3);
|
|
6818
6818
|
if (parsed2.id !== 1) return;
|
|
6819
6819
|
clearTimeout(timer);
|
|
6820
|
-
|
|
6820
|
+
resolve2(parsed2);
|
|
6821
6821
|
};
|
|
6822
6822
|
conn.send(JSON.stringify({ id: 1, method: "Target.getTargets" }));
|
|
6823
6823
|
}
|
|
@@ -6877,9 +6877,9 @@ var Relay = class {
|
|
|
6877
6877
|
}
|
|
6878
6878
|
async start(head) {
|
|
6879
6879
|
await this.send(head);
|
|
6880
|
-
const hostGone = new Promise((
|
|
6880
|
+
const hostGone = new Promise((resolve2) => {
|
|
6881
6881
|
this.host.onclose = (reason) => {
|
|
6882
|
-
void this.end(reason ? CLOSE.error : CLOSE.normal, reason ?? "").then(() =>
|
|
6882
|
+
void this.end(reason ? CLOSE.error : CLOSE.normal, reason ?? "").then(() => resolve2());
|
|
6883
6883
|
};
|
|
6884
6884
|
});
|
|
6885
6885
|
this.host.onmessage = (message3) => {
|
|
@@ -6893,8 +6893,8 @@ var Relay = class {
|
|
|
6893
6893
|
await Promise.race([pumping, hostGone]);
|
|
6894
6894
|
await this.writes;
|
|
6895
6895
|
let timer;
|
|
6896
|
-
const waited = new Promise((
|
|
6897
|
-
timer = setTimeout(
|
|
6896
|
+
const waited = new Promise((resolve2) => {
|
|
6897
|
+
timer = setTimeout(resolve2, this.closeWaitMs);
|
|
6898
6898
|
});
|
|
6899
6899
|
await Promise.race([pumping, waited]);
|
|
6900
6900
|
clearTimeout(timer);
|
|
@@ -7487,9 +7487,13 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
|
|
|
7487
7487
|
// src/fs/fresh-modules.ts
|
|
7488
7488
|
var MAGIC = [0, 97, 115, 109];
|
|
7489
7489
|
var MAX_FRESH = 65536;
|
|
7490
|
+
var DEFAULT_UMASK = 18;
|
|
7490
7491
|
function isModule(bytes) {
|
|
7491
7492
|
return MAGIC.every((b, i) => bytes[i] === b);
|
|
7492
7493
|
}
|
|
7494
|
+
function within4(path, dir) {
|
|
7495
|
+
return path.startsWith(dir === "/" ? "/" : `${dir}/`);
|
|
7496
|
+
}
|
|
7493
7497
|
var FreshModules = class {
|
|
7494
7498
|
fresh = /* @__PURE__ */ new Map();
|
|
7495
7499
|
add(path, umask, pid) {
|
|
@@ -7497,17 +7501,40 @@ var FreshModules = class {
|
|
|
7497
7501
|
this.fresh.delete(key);
|
|
7498
7502
|
const oldest = this.fresh.size >= MAX_FRESH ? this.fresh.keys().next().value : void 0;
|
|
7499
7503
|
if (oldest !== void 0) this.fresh.delete(oldest);
|
|
7500
|
-
|
|
7504
|
+
const mask = umask & 511;
|
|
7505
|
+
this.fresh.set(key, { umask: mask, pid, added: 0, setup: mask !== DEFAULT_UMASK });
|
|
7501
7506
|
}
|
|
7502
7507
|
forget(pid) {
|
|
7503
7508
|
for (const [path, fresh2] of this.fresh) if (fresh2.pid === pid) this.fresh.delete(path);
|
|
7504
7509
|
}
|
|
7510
|
+
drop(fresh2) {
|
|
7511
|
+
for (const [key, note] of [...this.fresh]) if (note === fresh2) this.fresh.delete(key);
|
|
7512
|
+
}
|
|
7513
|
+
moved(from, to) {
|
|
7514
|
+
const source = normalizePath(from);
|
|
7515
|
+
const target = normalizePath(to);
|
|
7516
|
+
if (source === target) return;
|
|
7517
|
+
for (const key of [...this.fresh.keys()]) {
|
|
7518
|
+
if (key === target || within4(key, target)) this.fresh.delete(key);
|
|
7519
|
+
}
|
|
7520
|
+
for (const [key, fresh2] of [...this.fresh]) {
|
|
7521
|
+
if (key !== source && !within4(key, source)) continue;
|
|
7522
|
+
this.fresh.delete(key);
|
|
7523
|
+
this.fresh.set(target + key.slice(source.length), fresh2);
|
|
7524
|
+
}
|
|
7525
|
+
}
|
|
7505
7526
|
wrap(fs) {
|
|
7506
|
-
const
|
|
7527
|
+
const head = async (path) => {
|
|
7528
|
+
if (fs.pread) return fs.pread(path, 0, MAGIC.length);
|
|
7529
|
+
return (await fs.readFileBuffer(path)).subarray(0, MAGIC.length);
|
|
7530
|
+
};
|
|
7531
|
+
const decide = async (given, known) => {
|
|
7507
7532
|
const path = normalizePath(given);
|
|
7508
7533
|
const fresh2 = this.fresh.get(path);
|
|
7509
|
-
if (!fresh2
|
|
7534
|
+
if (!fresh2) return;
|
|
7535
|
+
const bytes = known && known.length >= MAGIC.length ? known : await head(path);
|
|
7510
7536
|
const want = isModule(bytes) ? 73 & ~fresh2.umask : 0;
|
|
7537
|
+
fresh2.setup = false;
|
|
7511
7538
|
if (want === fresh2.added) return;
|
|
7512
7539
|
const mode = (await fs.stat(path)).mode & 4095;
|
|
7513
7540
|
await fs.chmod(path, mode & ~fresh2.added | want);
|
|
@@ -7516,44 +7543,59 @@ var FreshModules = class {
|
|
|
7516
7543
|
const overrides = {
|
|
7517
7544
|
writeFile: async (path, content, owner) => {
|
|
7518
7545
|
await fs.writeFile(path, content, owner);
|
|
7519
|
-
|
|
7546
|
+
if (this.fresh.has(normalizePath(path))) {
|
|
7547
|
+
await decide(
|
|
7548
|
+
path,
|
|
7549
|
+
typeof content === "string" ? new TextEncoder().encode(content) : content
|
|
7550
|
+
);
|
|
7551
|
+
}
|
|
7520
7552
|
},
|
|
7521
7553
|
chmod: async (path, mode) => {
|
|
7522
7554
|
const fresh2 = this.fresh.get(normalizePath(path));
|
|
7523
|
-
|
|
7524
|
-
if (
|
|
7555
|
+
if (fresh2?.setup && (mode & 4095) === (438 & ~fresh2.umask)) fresh2.setup = false;
|
|
7556
|
+
else if (fresh2) this.drop(fresh2);
|
|
7525
7557
|
await fs.chmod(path, mode);
|
|
7526
7558
|
},
|
|
7527
7559
|
rm: async (path, options) => {
|
|
7528
|
-
this.fresh.delete(normalizePath(path));
|
|
7529
7560
|
await fs.rm(path, options);
|
|
7561
|
+
const at = normalizePath(path);
|
|
7562
|
+
for (const key of [...this.fresh.keys()]) {
|
|
7563
|
+
if (key === at || within4(key, at)) this.fresh.delete(key);
|
|
7564
|
+
}
|
|
7530
7565
|
},
|
|
7531
7566
|
rename: async (from, to) => {
|
|
7532
7567
|
await fs.rename(from, to);
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7568
|
+
this.moved(from, to);
|
|
7569
|
+
},
|
|
7570
|
+
link: async (from, to, follow2) => {
|
|
7571
|
+
await fs.link(from, to, follow2);
|
|
7572
|
+
const source = follow2 && fs.realpath ? await fs.realpath(from, true) : from;
|
|
7573
|
+
const fresh2 = this.fresh.get(normalizePath(source));
|
|
7536
7574
|
if (fresh2) this.fresh.set(normalizePath(to), fresh2);
|
|
7537
7575
|
}
|
|
7538
7576
|
};
|
|
7539
7577
|
const ranged2 = rangedOps(fs);
|
|
7540
7578
|
if (ranged2) {
|
|
7541
7579
|
overrides.pwrite = async (path, at, bytes, transfer) => {
|
|
7542
|
-
const
|
|
7580
|
+
const touches2 = at < MAGIC.length && this.fresh.has(normalizePath(path));
|
|
7543
7581
|
await ranged2.pwrite(path, at, bytes, transfer);
|
|
7544
|
-
if (
|
|
7582
|
+
if (touches2) await decide(path);
|
|
7583
|
+
};
|
|
7584
|
+
overrides.truncate = async (path, size) => {
|
|
7585
|
+
await ranged2.truncate(path, size);
|
|
7586
|
+
if (size < MAGIC.length && this.fresh.has(normalizePath(path))) await decide(path);
|
|
7545
7587
|
};
|
|
7546
7588
|
}
|
|
7547
|
-
const
|
|
7589
|
+
const bound2 = /* @__PURE__ */ new WeakMap();
|
|
7548
7590
|
return new Proxy(fs, {
|
|
7549
7591
|
get(target, key, receiver) {
|
|
7550
7592
|
if (Object.hasOwn(overrides, key)) return overrides[key];
|
|
7551
7593
|
const value = Reflect.get(target, key, receiver);
|
|
7552
7594
|
if (typeof value !== "function") return value;
|
|
7553
|
-
let method =
|
|
7595
|
+
let method = bound2.get(value);
|
|
7554
7596
|
if (method === void 0) {
|
|
7555
7597
|
method = value.bind(target);
|
|
7556
|
-
|
|
7598
|
+
bound2.set(value, method);
|
|
7557
7599
|
}
|
|
7558
7600
|
return method;
|
|
7559
7601
|
}
|
|
@@ -7613,7 +7655,7 @@ var UNLINKED_DIR = ".slicc-unlinked";
|
|
|
7613
7655
|
function webLocks() {
|
|
7614
7656
|
return globalThis.navigator?.locks;
|
|
7615
7657
|
}
|
|
7616
|
-
var
|
|
7658
|
+
var within5 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
|
|
7617
7659
|
var parentOf5 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
7618
7660
|
var lockName = (instance) => `slicc-unlinked:${instance}`;
|
|
7619
7661
|
var dirOf = (root) => root === "/" ? `/${UNLINKED_DIR}` : `${root}/${UNLINKED_DIR}`;
|
|
@@ -7621,12 +7663,12 @@ var PathGate = class {
|
|
|
7621
7663
|
tails = /* @__PURE__ */ new Map();
|
|
7622
7664
|
async acquire(path) {
|
|
7623
7665
|
const prev = this.tails.get(path) ?? Promise.resolve();
|
|
7624
|
-
const { promise, resolve } = Promise.withResolvers();
|
|
7666
|
+
const { promise, resolve: resolve2 } = Promise.withResolvers();
|
|
7625
7667
|
const tail = prev.then(() => promise);
|
|
7626
7668
|
this.tails.set(path, tail);
|
|
7627
7669
|
await prev;
|
|
7628
7670
|
return () => {
|
|
7629
|
-
|
|
7671
|
+
resolve2();
|
|
7630
7672
|
if (this.tails.get(path) === tail) this.tails.delete(path);
|
|
7631
7673
|
};
|
|
7632
7674
|
}
|
|
@@ -7713,7 +7755,7 @@ var UnlinkedKeeper = class {
|
|
|
7713
7755
|
for (const holder of this.holders) {
|
|
7714
7756
|
if (holder.owns(target)) continue;
|
|
7715
7757
|
for (const path of holder.held()) {
|
|
7716
|
-
if (!
|
|
7758
|
+
if (!within5(path, target) || holder.isKept(path)) continue;
|
|
7717
7759
|
held.set(path, [...held.get(path) ?? [], holder]);
|
|
7718
7760
|
}
|
|
7719
7761
|
}
|
|
@@ -8104,7 +8146,7 @@ var ChildTable = class {
|
|
|
8104
8146
|
}
|
|
8105
8147
|
async nextChange(candidates, flags2, interrupt) {
|
|
8106
8148
|
let wake;
|
|
8107
|
-
const stateChange = new Promise((
|
|
8149
|
+
const stateChange = new Promise((resolve2) => wake = resolve2);
|
|
8108
8150
|
const watching = flags2.untraced || flags2.continued;
|
|
8109
8151
|
if (watching && wake) this.stateChanged.push(wake);
|
|
8110
8152
|
try {
|
|
@@ -8151,6 +8193,65 @@ var ChildTable = class {
|
|
|
8151
8193
|
}
|
|
8152
8194
|
};
|
|
8153
8195
|
|
|
8196
|
+
// src/kernel/exec-ticket.ts
|
|
8197
|
+
var TICKET_ENV = "SLICC_SEALED_TICKET";
|
|
8198
|
+
var TICKET_TTL_MS = 3e4;
|
|
8199
|
+
var MAX_TICKETS = 256;
|
|
8200
|
+
var TICKET = /^[0-9a-f]{32}$/;
|
|
8201
|
+
async function argvDigest(argv) {
|
|
8202
|
+
const bytes = new TextEncoder().encode(JSON.stringify(argv));
|
|
8203
|
+
const hash = new Uint8Array(await crypto.subtle.digest("SHA-256", bytes));
|
|
8204
|
+
return [...hash].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
8205
|
+
}
|
|
8206
|
+
function isStrings(value) {
|
|
8207
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
8208
|
+
}
|
|
8209
|
+
function stringRecord(value) {
|
|
8210
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
8211
|
+
const entries = Object.entries(value);
|
|
8212
|
+
return entries.every(([, v]) => typeof v === "string") ? Object.fromEntries(entries) : void 0;
|
|
8213
|
+
}
|
|
8214
|
+
var TicketBook = class {
|
|
8215
|
+
booked = /* @__PURE__ */ new Map();
|
|
8216
|
+
now;
|
|
8217
|
+
normalise = async (path) => path;
|
|
8218
|
+
constructor(now = Date.now) {
|
|
8219
|
+
this.now = now;
|
|
8220
|
+
}
|
|
8221
|
+
get size() {
|
|
8222
|
+
return this.booked.size;
|
|
8223
|
+
}
|
|
8224
|
+
async record(req, reply, pid) {
|
|
8225
|
+
const { ticket, error } = reply;
|
|
8226
|
+
if (error !== void 0 || typeof ticket !== "string" || !TICKET.test(ticket)) return;
|
|
8227
|
+
const { path, argv, cwd } = req;
|
|
8228
|
+
const entry = {
|
|
8229
|
+
pid,
|
|
8230
|
+
path: await this.normalise(path),
|
|
8231
|
+
requested: path,
|
|
8232
|
+
requestedCwd: cwd,
|
|
8233
|
+
argv: await argvDigest(argv),
|
|
8234
|
+
cwd: await this.normalise(cwd),
|
|
8235
|
+
at: this.now()
|
|
8236
|
+
};
|
|
8237
|
+
this.prune();
|
|
8238
|
+
while (this.booked.size >= MAX_TICKETS)
|
|
8239
|
+
this.booked.delete(this.booked.keys().next().value);
|
|
8240
|
+
this.booked.set(ticket, entry);
|
|
8241
|
+
}
|
|
8242
|
+
take(ticket) {
|
|
8243
|
+
const booked = this.booked.get(ticket);
|
|
8244
|
+
this.booked.delete(ticket);
|
|
8245
|
+
return booked && this.now() - booked.at < TICKET_TTL_MS ? booked : void 0;
|
|
8246
|
+
}
|
|
8247
|
+
prune() {
|
|
8248
|
+
const now = this.now();
|
|
8249
|
+
for (const [ticket, booked] of this.booked) {
|
|
8250
|
+
if (now - booked.at >= TICKET_TTL_MS) this.booked.delete(ticket);
|
|
8251
|
+
}
|
|
8252
|
+
}
|
|
8253
|
+
};
|
|
8254
|
+
|
|
8154
8255
|
// src/mount/protocol.ts
|
|
8155
8256
|
var DRIVER_PROTOCOL = [1, 2];
|
|
8156
8257
|
function driverVersionError(theirs) {
|
|
@@ -8221,7 +8322,7 @@ var DriverConnection = class _DriverConnection {
|
|
|
8221
8322
|
call(call, transfer = []) {
|
|
8222
8323
|
if (this.failure) return Promise.reject(this.failure);
|
|
8223
8324
|
const id2 = ++this.nextId;
|
|
8224
|
-
return new Promise((
|
|
8325
|
+
return new Promise((resolve2, reject) => {
|
|
8225
8326
|
const timer = unref(
|
|
8226
8327
|
setTimeout(() => {
|
|
8227
8328
|
this.waiting.delete(id2);
|
|
@@ -8234,7 +8335,7 @@ var DriverConnection = class _DriverConnection {
|
|
|
8234
8335
|
this.onFail?.(error);
|
|
8235
8336
|
}, this.timeoutMs)
|
|
8236
8337
|
);
|
|
8237
|
-
this.waiting.set(id2, { resolve, reject, timer });
|
|
8338
|
+
this.waiting.set(id2, { resolve: resolve2, reject, timer });
|
|
8238
8339
|
this.port.postMessage({ ...call, id: id2 }, transfer);
|
|
8239
8340
|
});
|
|
8240
8341
|
}
|
|
@@ -8277,7 +8378,7 @@ function parseSize(text) {
|
|
|
8277
8378
|
if (!match) throw errnoError("EINVAL", `not a size: ${text}`);
|
|
8278
8379
|
return Math.floor(Number(match[1]) * UNITS[match[2].toLowerCase()]);
|
|
8279
8380
|
}
|
|
8280
|
-
var
|
|
8381
|
+
var within6 = (path, target) => path === target || target === "/" || path.startsWith(`${target}/`);
|
|
8281
8382
|
var HeldSet = class extends Set {
|
|
8282
8383
|
idle;
|
|
8283
8384
|
constructor(idle) {
|
|
@@ -8296,7 +8397,7 @@ var HeldSet = class extends Set {
|
|
|
8296
8397
|
}
|
|
8297
8398
|
};
|
|
8298
8399
|
function heldUnder(held, target) {
|
|
8299
|
-
for (const paths of held) for (const path of paths.keys()) if (
|
|
8400
|
+
for (const paths of held) for (const path of paths.keys()) if (within6(path, target)) return true;
|
|
8300
8401
|
return false;
|
|
8301
8402
|
}
|
|
8302
8403
|
var HeldPaths = class extends Map {
|
|
@@ -8377,8 +8478,8 @@ var HeldPaths = class extends Map {
|
|
|
8377
8478
|
this.keptHandles.delete(handle);
|
|
8378
8479
|
if (kept) this.letGo(kept);
|
|
8379
8480
|
}
|
|
8380
|
-
const
|
|
8381
|
-
if (
|
|
8481
|
+
const count2 = (this.opens.get(key) ?? 0) + (on ? 1 : -1);
|
|
8482
|
+
if (count2 > 0) this.opens.set(key, count2);
|
|
8382
8483
|
else {
|
|
8383
8484
|
this.opens.delete(key);
|
|
8384
8485
|
for (const id2 of this.handlesAt(key)) this.handles.delete(id2);
|
|
@@ -8392,8 +8493,8 @@ var HeldPaths = class extends Map {
|
|
|
8392
8493
|
return this.lastHandle;
|
|
8393
8494
|
}
|
|
8394
8495
|
holdWrite(path, on) {
|
|
8395
|
-
const
|
|
8396
|
-
if (
|
|
8496
|
+
const count2 = (this.get(path) ?? 0) + (on ? 1 : -1);
|
|
8497
|
+
if (count2 > 0) this.set(path, count2);
|
|
8397
8498
|
else {
|
|
8398
8499
|
this.delete(path);
|
|
8399
8500
|
this.revoked.delete(path);
|
|
@@ -8412,24 +8513,24 @@ var HeldPaths = class extends Map {
|
|
|
8412
8513
|
return this.owning === path;
|
|
8413
8514
|
}
|
|
8414
8515
|
revoke(prefix) {
|
|
8415
|
-
for (const path of this.keys()) if (
|
|
8516
|
+
for (const path of this.keys()) if (within6(path, prefix)) this.revoked.add(path);
|
|
8416
8517
|
}
|
|
8417
8518
|
renamed(from, to) {
|
|
8418
|
-
for (const [path,
|
|
8419
|
-
if (!
|
|
8519
|
+
for (const [path, count2] of [...this]) {
|
|
8520
|
+
if (!within6(path, from)) continue;
|
|
8420
8521
|
const moved2 = to + path.slice(from.length);
|
|
8421
8522
|
this.delete(path);
|
|
8422
|
-
this.set(moved2, (this.get(moved2) ?? 0) +
|
|
8523
|
+
this.set(moved2, (this.get(moved2) ?? 0) + count2);
|
|
8423
8524
|
if (this.revoked.delete(path)) this.revoked.add(moved2);
|
|
8424
8525
|
}
|
|
8425
|
-
for (const [path,
|
|
8426
|
-
if (!
|
|
8526
|
+
for (const [path, count2] of [...this.opens]) {
|
|
8527
|
+
if (!within6(path, from)) continue;
|
|
8427
8528
|
const moved2 = to + path.slice(from.length);
|
|
8428
8529
|
this.opens.delete(path);
|
|
8429
|
-
this.opens.set(moved2, (this.opens.get(moved2) ?? 0) +
|
|
8530
|
+
this.opens.set(moved2, (this.opens.get(moved2) ?? 0) + count2);
|
|
8430
8531
|
}
|
|
8431
8532
|
for (const [id2, key] of this.handles) {
|
|
8432
|
-
if (
|
|
8533
|
+
if (within6(key, from)) this.handles.set(id2, to + key.slice(from.length));
|
|
8433
8534
|
}
|
|
8434
8535
|
}
|
|
8435
8536
|
isRevoked(path) {
|
|
@@ -8536,7 +8637,7 @@ var MountTable = class {
|
|
|
8536
8637
|
locate(path) {
|
|
8537
8638
|
let best;
|
|
8538
8639
|
for (const mount of this.mounts.values()) {
|
|
8539
|
-
if (
|
|
8640
|
+
if (within6(path, mount.target) && (!best || mount.target.length > best.target.length))
|
|
8540
8641
|
best = mount;
|
|
8541
8642
|
}
|
|
8542
8643
|
if (!best) return void 0;
|
|
@@ -8679,7 +8780,7 @@ var MountTable = class {
|
|
|
8679
8780
|
async commitUnder(prefix) {
|
|
8680
8781
|
const at = normalizePath(prefix);
|
|
8681
8782
|
await Promise.all(
|
|
8682
|
-
[...this.sessions.keys()].filter((p) =>
|
|
8783
|
+
[...this.sessions.keys()].filter((p) => within6(p, at)).map((p) => this.commit(p))
|
|
8683
8784
|
);
|
|
8684
8785
|
}
|
|
8685
8786
|
async commitOverlapping(real, offset, length2) {
|
|
@@ -8714,10 +8815,10 @@ var MountTable = class {
|
|
|
8714
8815
|
}
|
|
8715
8816
|
forget(mount, path) {
|
|
8716
8817
|
mount.epoch++;
|
|
8717
|
-
for (const key of [...mount.attrs.keys()]) if (
|
|
8818
|
+
for (const key of [...mount.attrs.keys()]) if (within6(key, path)) mount.attrs.delete(key);
|
|
8718
8819
|
mount.lists.delete(path);
|
|
8719
8820
|
mount.lists.delete(parentOf7(path));
|
|
8720
|
-
for (const key of [...mount.lists.keys()]) if (
|
|
8821
|
+
for (const key of [...mount.lists.keys()]) if (within6(key, path)) mount.lists.delete(key);
|
|
8721
8822
|
}
|
|
8722
8823
|
async getattr(mount, path, rel2, settled = false) {
|
|
8723
8824
|
for (let round = 1; ; round++) {
|
|
@@ -9352,6 +9453,11 @@ function statJson(s) {
|
|
|
9352
9453
|
async function readdirStat(fs, dir) {
|
|
9353
9454
|
return (await fs.readdirStat(dir)).map(([name2, stat]) => [name2, stat && statJson(stat)]);
|
|
9354
9455
|
}
|
|
9456
|
+
async function usageAt(entry, path) {
|
|
9457
|
+
if (!entry.statfs) return void 0;
|
|
9458
|
+
const real = await realTarget(entry.fs, path).catch(() => path);
|
|
9459
|
+
return entry.statfs(real);
|
|
9460
|
+
}
|
|
9355
9461
|
async function storageUsage() {
|
|
9356
9462
|
const estimate = await globalThis.navigator?.storage?.estimate?.();
|
|
9357
9463
|
if (typeof estimate?.quota !== "number") return null;
|
|
@@ -9668,7 +9774,7 @@ async function dispatchOne(entry, req) {
|
|
|
9668
9774
|
if (req.op === "hold") return await holdOp(entry, path, req);
|
|
9669
9775
|
const refused2 = await guarded(entry, path, req);
|
|
9670
9776
|
if (refused2) return refused2;
|
|
9671
|
-
if (req.op === "statfs") return json2(await entry
|
|
9777
|
+
if (req.op === "statfs") return json2(await usageAt(entry, path) ?? await storageUsage());
|
|
9672
9778
|
if (entry.revoked?.(path)) return { ok: false, errno: "EIO", message: `${path} was unmounted` };
|
|
9673
9779
|
if (req.op === "write" && req.mode === 1 || UNLINKED_OPS.has(req.op)) {
|
|
9674
9780
|
const serve = async () => run(entry, await keptOr(entry, path, req.handle), req);
|
|
@@ -10720,7 +10826,7 @@ var AsyncOps = class {
|
|
|
10720
10826
|
this.wake();
|
|
10721
10827
|
}
|
|
10722
10828
|
sleep(timeoutMs, signal) {
|
|
10723
|
-
return new Promise((
|
|
10829
|
+
return new Promise((resolve2, reject) => {
|
|
10724
10830
|
let timer;
|
|
10725
10831
|
const cleanup = () => {
|
|
10726
10832
|
clearTimeout(timer);
|
|
@@ -10729,7 +10835,7 @@ var AsyncOps = class {
|
|
|
10729
10835
|
};
|
|
10730
10836
|
const wake = () => {
|
|
10731
10837
|
cleanup();
|
|
10732
|
-
|
|
10838
|
+
resolve2(true);
|
|
10733
10839
|
};
|
|
10734
10840
|
const abort = () => {
|
|
10735
10841
|
cleanup();
|
|
@@ -10740,7 +10846,7 @@ var AsyncOps = class {
|
|
|
10740
10846
|
if (timeoutMs !== void 0) {
|
|
10741
10847
|
timer = setTimeout(() => {
|
|
10742
10848
|
cleanup();
|
|
10743
|
-
|
|
10849
|
+
resolve2(false);
|
|
10744
10850
|
}, timeoutMs);
|
|
10745
10851
|
}
|
|
10746
10852
|
});
|
|
@@ -11162,7 +11268,7 @@ var Resolver = class {
|
|
|
11162
11268
|
};
|
|
11163
11269
|
function waitFor(lookup, signal) {
|
|
11164
11270
|
lookup.waiters++;
|
|
11165
|
-
return new Promise((
|
|
11271
|
+
return new Promise((resolve2, reject) => {
|
|
11166
11272
|
const abort = () => {
|
|
11167
11273
|
if (--lookup.waiters === 0) lookup.abort.abort(new KernelError("EINTR"));
|
|
11168
11274
|
reject(new KernelError("EINTR"));
|
|
@@ -11172,7 +11278,7 @@ function waitFor(lookup, signal) {
|
|
|
11172
11278
|
if (signal?.aborted) return;
|
|
11173
11279
|
lookup.waiters--;
|
|
11174
11280
|
signal?.removeEventListener("abort", abort);
|
|
11175
|
-
|
|
11281
|
+
resolve2(value);
|
|
11176
11282
|
});
|
|
11177
11283
|
});
|
|
11178
11284
|
}
|
|
@@ -11353,8 +11459,8 @@ var KernelTty = class {
|
|
|
11353
11459
|
}
|
|
11354
11460
|
rubOut(n) {
|
|
11355
11461
|
const dropped2 = this.line.splice(this.line.length - n, n);
|
|
11356
|
-
const
|
|
11357
|
-
const cells =
|
|
11462
|
+
const utf83 = (this.termios.c_iflag & IUTF8) !== 0;
|
|
11463
|
+
const cells = utf83 ? dropped2.filter((b) => !isContinuation(b)).length : dropped2.length;
|
|
11358
11464
|
if (cells > 0 && this.termios.c_lflag & ECHO) {
|
|
11359
11465
|
this.output(encoder3.encode("\b \b".repeat(cells)), false);
|
|
11360
11466
|
}
|
|
@@ -11424,14 +11530,14 @@ var KernelTty = class {
|
|
|
11424
11530
|
}
|
|
11425
11531
|
changed(signal) {
|
|
11426
11532
|
if (signal?.aborted) return Promise.reject(new KernelError("EINTR"));
|
|
11427
|
-
return new Promise((
|
|
11533
|
+
return new Promise((resolve2, reject) => {
|
|
11428
11534
|
const onAbort = () => {
|
|
11429
11535
|
this.waiters = this.waiters.filter((w) => w !== waiter);
|
|
11430
11536
|
reject(new KernelError("EINTR"));
|
|
11431
11537
|
};
|
|
11432
11538
|
const waiter = () => {
|
|
11433
11539
|
signal?.removeEventListener("abort", onAbort);
|
|
11434
|
-
|
|
11540
|
+
resolve2();
|
|
11435
11541
|
};
|
|
11436
11542
|
this.waiters.push(waiter);
|
|
11437
11543
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
@@ -11440,7 +11546,7 @@ var KernelTty = class {
|
|
|
11440
11546
|
wake() {
|
|
11441
11547
|
const waiters = this.waiters;
|
|
11442
11548
|
this.waiters = [];
|
|
11443
|
-
for (const
|
|
11549
|
+
for (const resolve2 of waiters) resolve2();
|
|
11444
11550
|
}
|
|
11445
11551
|
};
|
|
11446
11552
|
|
|
@@ -11539,14 +11645,14 @@ var PtyPair = class {
|
|
|
11539
11645
|
}
|
|
11540
11646
|
changed(signal) {
|
|
11541
11647
|
if (signal?.aborted) return Promise.reject(new KernelError("EINTR"));
|
|
11542
|
-
return new Promise((
|
|
11648
|
+
return new Promise((resolve2, reject) => {
|
|
11543
11649
|
const onAbort = () => {
|
|
11544
11650
|
this.waiters = this.waiters.filter((w) => w !== waiter);
|
|
11545
11651
|
reject(new KernelError("EINTR"));
|
|
11546
11652
|
};
|
|
11547
11653
|
const waiter = () => {
|
|
11548
11654
|
signal?.removeEventListener("abort", onAbort);
|
|
11549
|
-
|
|
11655
|
+
resolve2();
|
|
11550
11656
|
};
|
|
11551
11657
|
this.waiters.push(waiter);
|
|
11552
11658
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
@@ -11555,7 +11661,7 @@ var PtyPair = class {
|
|
|
11555
11661
|
wake() {
|
|
11556
11662
|
const waiters = this.waiters;
|
|
11557
11663
|
this.waiters = [];
|
|
11558
|
-
for (const
|
|
11664
|
+
for (const resolve2 of waiters) resolve2();
|
|
11559
11665
|
}
|
|
11560
11666
|
};
|
|
11561
11667
|
var PtyTable = class {
|
|
@@ -11620,7 +11726,8 @@ function ptySyscall(req, ctx) {
|
|
|
11620
11726
|
if (!ctx.ptys) throw new KernelError("ENOENT");
|
|
11621
11727
|
const pair = ctx.ptys.get(req.n);
|
|
11622
11728
|
ttyOpenable(ctx.guard, pair.slave);
|
|
11623
|
-
const
|
|
11729
|
+
const slave = pair.openSlave();
|
|
11730
|
+
const fd = ctx.fds.install(ctx.ttyFilter?.(slave) ?? slave, 3);
|
|
11624
11731
|
if (!req.noctty) ctx.jobs?.acquireTerminal(ctx.pid, pair.slave);
|
|
11625
11732
|
return json4(fd);
|
|
11626
11733
|
}
|
|
@@ -11693,8 +11800,8 @@ async function runChild(req, deps) {
|
|
|
11693
11800
|
};
|
|
11694
11801
|
const controls = [];
|
|
11695
11802
|
const capture = () => {
|
|
11696
|
-
const { promise, resolve } = Promise.withResolvers();
|
|
11697
|
-
const control = { shut: false, ended:
|
|
11803
|
+
const { promise, resolve: resolve2 } = Promise.withResolvers();
|
|
11804
|
+
const control = { shut: false, ended: resolve2, eof: promise };
|
|
11698
11805
|
controls.push(control);
|
|
11699
11806
|
return { capture: true, max, overflow: () => stop("ENOBUFS"), control };
|
|
11700
11807
|
};
|
|
@@ -11787,7 +11894,7 @@ async function waitReady(fds, read, write, deadline, interrupted2) {
|
|
|
11787
11894
|
return file.changed === void 0 ? [] : [file.changed(round.signal).catch(() => void 0)];
|
|
11788
11895
|
});
|
|
11789
11896
|
let timer;
|
|
11790
|
-
const expiry = deadline === Number.POSITIVE_INFINITY ? [] : [new Promise((
|
|
11897
|
+
const expiry = deadline === Number.POSITIVE_INFINITY ? [] : [new Promise((resolve2) => timer = setTimeout(resolve2, deadline - Date.now()))];
|
|
11791
11898
|
try {
|
|
11792
11899
|
await Promise.race([...changes, ...expiry, interrupted2]);
|
|
11793
11900
|
} finally {
|
|
@@ -11871,10 +11978,10 @@ async function socketSyscall(req, proc) {
|
|
|
11871
11978
|
}
|
|
11872
11979
|
}
|
|
11873
11980
|
function interruptible2(dialing, signal) {
|
|
11874
|
-
return new Promise((
|
|
11981
|
+
return new Promise((resolve2, reject) => {
|
|
11875
11982
|
const abort = () => reject(new KernelError("EINTR"));
|
|
11876
11983
|
signal.addEventListener("abort", abort, { once: true });
|
|
11877
|
-
dialing.then(
|
|
11984
|
+
dialing.then(resolve2, reject).finally(() => signal.removeEventListener("abort", abort));
|
|
11878
11985
|
});
|
|
11879
11986
|
}
|
|
11880
11987
|
function unnamed(domain) {
|
|
@@ -11901,7 +12008,7 @@ function isMissing(err) {
|
|
|
11901
12008
|
if (err?.code === "ENOENT") return true;
|
|
11902
12009
|
return err instanceof Error && err.message.startsWith("ENOENT");
|
|
11903
12010
|
}
|
|
11904
|
-
function
|
|
12011
|
+
function within7(path, root) {
|
|
11905
12012
|
return path === root || path.startsWith(root.endsWith("/") ? root : `${root}/`);
|
|
11906
12013
|
}
|
|
11907
12014
|
var VfsNode = class {
|
|
@@ -12222,12 +12329,12 @@ var VfsNodes = class {
|
|
|
12222
12329
|
return node;
|
|
12223
12330
|
}
|
|
12224
12331
|
holds(prefix) {
|
|
12225
|
-
for (const path of this.byPath.keys()) if (
|
|
12332
|
+
for (const path of this.byPath.keys()) if (within7(path, prefix)) return true;
|
|
12226
12333
|
return false;
|
|
12227
12334
|
}
|
|
12228
12335
|
writes(prefix) {
|
|
12229
12336
|
for (const [path, node] of this.byPath)
|
|
12230
|
-
if (node.writers > 0 &&
|
|
12337
|
+
if (node.writers > 0 && within7(path, prefix)) return true;
|
|
12231
12338
|
return false;
|
|
12232
12339
|
}
|
|
12233
12340
|
closed(node, writable2 = false) {
|
|
@@ -12271,11 +12378,11 @@ var VfsNodes = class {
|
|
|
12271
12378
|
this.kept.delete(node);
|
|
12272
12379
|
}
|
|
12273
12380
|
async flush(path) {
|
|
12274
|
-
for (const [p, node] of this.byPath) if (
|
|
12381
|
+
for (const [p, node] of this.byPath) if (within7(p, path)) await node.serial(() => node.flush());
|
|
12275
12382
|
}
|
|
12276
12383
|
async unlinking(path) {
|
|
12277
12384
|
for (const [held, node] of [...this.byPath]) {
|
|
12278
|
-
if (!
|
|
12385
|
+
if (!within7(held, path)) continue;
|
|
12279
12386
|
await node.serial(async () => {
|
|
12280
12387
|
await Promise.all([this.keepsOnDisk || node.keep(), node.limit()]);
|
|
12281
12388
|
});
|
|
@@ -12283,14 +12390,14 @@ var VfsNodes = class {
|
|
|
12283
12390
|
}
|
|
12284
12391
|
revoke(prefix) {
|
|
12285
12392
|
for (const [path, node] of [...this.byPath]) {
|
|
12286
|
-
if (!
|
|
12393
|
+
if (!within7(path, prefix)) continue;
|
|
12287
12394
|
node.revoke();
|
|
12288
12395
|
this.forget(node);
|
|
12289
12396
|
}
|
|
12290
12397
|
}
|
|
12291
12398
|
unlinked(path) {
|
|
12292
12399
|
for (const [held, node] of [...this.byPath]) {
|
|
12293
|
-
if (!
|
|
12400
|
+
if (!within7(held, path) || this.byPath.get(held) !== node) continue;
|
|
12294
12401
|
if (!this.dropName(held, node)) this.orphan(node);
|
|
12295
12402
|
}
|
|
12296
12403
|
}
|
|
@@ -12298,8 +12405,8 @@ var VfsNodes = class {
|
|
|
12298
12405
|
if (from === to) return;
|
|
12299
12406
|
const moved2 = [];
|
|
12300
12407
|
for (const [p, node] of [...this.byPath]) {
|
|
12301
|
-
if (
|
|
12302
|
-
else if (
|
|
12408
|
+
if (within7(p, from)) moved2.push([p, node]);
|
|
12409
|
+
else if (within7(p, to) && this.byPath.get(p) === node && !this.dropName(p, node)) {
|
|
12303
12410
|
this.orphan(node);
|
|
12304
12411
|
}
|
|
12305
12412
|
}
|
|
@@ -12578,7 +12685,7 @@ function isWasmSyscall(req) {
|
|
|
12578
12685
|
var MAX_READ = 1024 * 1024;
|
|
12579
12686
|
var WRITE_ACCESS = 3;
|
|
12580
12687
|
var KEYBOARD = /* @__PURE__ */ new Set([SIG.INT, SIG.QUIT, SIG.TSTP]);
|
|
12581
|
-
var
|
|
12688
|
+
var DEFAULT_UMASK2 = 18;
|
|
12582
12689
|
function words(value) {
|
|
12583
12690
|
if (!Array.isArray(value) || !value.every((w) => typeof w === "string")) {
|
|
12584
12691
|
throw new KernelError("EINVAL");
|
|
@@ -12606,7 +12713,7 @@ var WasmProcess = class {
|
|
|
12606
12713
|
interrupt = new AbortController();
|
|
12607
12714
|
gone = new AbortController();
|
|
12608
12715
|
dying = false;
|
|
12609
|
-
umask =
|
|
12716
|
+
umask = DEFAULT_UMASK2;
|
|
12610
12717
|
cred;
|
|
12611
12718
|
execChild;
|
|
12612
12719
|
killed = false;
|
|
@@ -12628,7 +12735,7 @@ var WasmProcess = class {
|
|
|
12628
12735
|
this.fds = fds;
|
|
12629
12736
|
this.options = options;
|
|
12630
12737
|
this.inherited = options.ignored ?? 0;
|
|
12631
|
-
this.umask = options.umask ??
|
|
12738
|
+
this.umask = options.umask ?? DEFAULT_UMASK2;
|
|
12632
12739
|
this.cred = copyCred(options.cred ?? ROOT);
|
|
12633
12740
|
this.children = new ChildTable(fds, options.spawner, options.forker);
|
|
12634
12741
|
this.nodes = options.nodes ?? new VfsNodes(options.fs);
|
|
@@ -12721,7 +12828,7 @@ var WasmProcess = class {
|
|
|
12721
12828
|
if (this.stopped) return "stop";
|
|
12722
12829
|
this.stopped = sig;
|
|
12723
12830
|
this.stops++;
|
|
12724
|
-
this.resumed = new Promise((
|
|
12831
|
+
this.resumed = new Promise((resolve2) => this.wake = resolve2);
|
|
12725
12832
|
const blocked = this.interrupt;
|
|
12726
12833
|
this.interrupt = new AbortController();
|
|
12727
12834
|
blocked.abort();
|
|
@@ -12786,7 +12893,9 @@ var WasmProcess = class {
|
|
|
12786
12893
|
const { ptys, jobs } = this.options;
|
|
12787
12894
|
const owner = this.options.owners ? this.ttyOwner() : void 0;
|
|
12788
12895
|
const guard2 = this.guarded();
|
|
12789
|
-
|
|
12896
|
+
const { ttyFilter } = this.options;
|
|
12897
|
+
const ctx = { pid: this.pid, fds: this.fds, ptys, jobs, guard: guard2, owner, ttyFilter };
|
|
12898
|
+
return ptySyscall(req, ctx);
|
|
12790
12899
|
}
|
|
12791
12900
|
return await this.procSyscall(req, cancelled);
|
|
12792
12901
|
} catch (e) {
|
|
@@ -12961,7 +13070,8 @@ var WasmProcess = class {
|
|
|
12961
13070
|
const tty = name2 === void 0 ? this.controllingTerminal() : this.options.jobs?.terminalNamed(name2);
|
|
12962
13071
|
if (!tty) throw new KernelError("ENXIO");
|
|
12963
13072
|
if (name2 !== void 0) ttyOpenable(this.guarded(), tty);
|
|
12964
|
-
|
|
13073
|
+
const file = tty.file();
|
|
13074
|
+
return this.fds.install(this.options.ttyFilter?.(file) ?? file, 3);
|
|
12965
13075
|
}
|
|
12966
13076
|
openSealed() {
|
|
12967
13077
|
const broker = this.options.sealed;
|
|
@@ -13001,15 +13111,8 @@ var WasmProcess = class {
|
|
|
13001
13111
|
async sealedCaller() {
|
|
13002
13112
|
const shown = await this.options.identity?.();
|
|
13003
13113
|
const broker = this.options.sealed;
|
|
13004
|
-
const
|
|
13005
|
-
return
|
|
13006
|
-
pid: shown?.pid ?? this.pid,
|
|
13007
|
-
ppid: shown?.ppid ?? 0,
|
|
13008
|
-
uid: this.cred.euid,
|
|
13009
|
-
gid: this.cred.egid,
|
|
13010
|
-
...tag !== void 0 ? { tag } : {},
|
|
13011
|
-
users: broker.users
|
|
13012
|
-
};
|
|
13114
|
+
const ids = { pid: shown?.pid ?? this.pid, ppid: shown?.ppid ?? 0 };
|
|
13115
|
+
return broker.stamp(ids, this.cred, broker.tagOf(this.pid));
|
|
13013
13116
|
}
|
|
13014
13117
|
guarded() {
|
|
13015
13118
|
const { guard: guard2 } = this.options;
|
|
@@ -13517,13 +13620,13 @@ var WasmProcess = class {
|
|
|
13517
13620
|
while (this.dlLock.depth > 0 && this.dlLock.owner !== owner) {
|
|
13518
13621
|
if (this.dying) throw new KernelError("EINTR");
|
|
13519
13622
|
const interrupt = this.interrupt.signal;
|
|
13520
|
-
const gone = await new Promise((
|
|
13623
|
+
const gone = await new Promise((resolve2) => {
|
|
13521
13624
|
const waiter = {
|
|
13522
13625
|
owner,
|
|
13523
13626
|
wake: (ended) => {
|
|
13524
13627
|
this.dlLock.waiters.delete(waiter);
|
|
13525
13628
|
interrupt.removeEventListener("abort", recheck);
|
|
13526
|
-
|
|
13629
|
+
resolve2(ended);
|
|
13527
13630
|
}
|
|
13528
13631
|
};
|
|
13529
13632
|
const recheck = () => waiter.wake(false);
|
|
@@ -13779,6 +13882,7 @@ function processOptions(opts, header3, hooks, created3) {
|
|
|
13779
13882
|
...inherited(opts),
|
|
13780
13883
|
...opts.owners ? { owners: true } : {},
|
|
13781
13884
|
...opts.sealed ? { sealed: opts.sealed } : {},
|
|
13885
|
+
...opts.ttyFilter ? { ttyFilter: opts.ttyFilter } : {},
|
|
13782
13886
|
...opts.clipboard ? { clipboard: opts.clipboard, ...clipboardName(opts) } : {},
|
|
13783
13887
|
...opts.readonlyAt ? { readonlyAt: opts.readonlyAt } : {},
|
|
13784
13888
|
...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3 } } : {},
|
|
@@ -14273,6 +14377,523 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
14273
14377
|
};
|
|
14274
14378
|
}
|
|
14275
14379
|
|
|
14380
|
+
// node_modules/@ai-ecoverse/slicc-scrub/dist/index.js
|
|
14381
|
+
var FRAGMENT = 16;
|
|
14382
|
+
var MIN_VALUE = 8;
|
|
14383
|
+
var MIN_BASE64 = 8;
|
|
14384
|
+
var encoder4 = new TextEncoder();
|
|
14385
|
+
var STD = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
14386
|
+
function utf82(text) {
|
|
14387
|
+
return encoder4.encode(text);
|
|
14388
|
+
}
|
|
14389
|
+
function base642(bytes, padded = true) {
|
|
14390
|
+
let out = "";
|
|
14391
|
+
for (let i = 0; i < bytes.length; i += 3) {
|
|
14392
|
+
const a = bytes[i];
|
|
14393
|
+
const b = i + 1 < bytes.length ? bytes[i + 1] : 0;
|
|
14394
|
+
const c = i + 2 < bytes.length ? bytes[i + 2] : 0;
|
|
14395
|
+
const triple = a << 16 | b << 8 | c;
|
|
14396
|
+
const left = bytes.length - i;
|
|
14397
|
+
out += STD[triple >> 18 & 63] + STD[triple >> 12 & 63];
|
|
14398
|
+
out += left > 1 ? STD[triple >> 6 & 63] : padded ? "=" : "";
|
|
14399
|
+
out += left > 2 ? STD[triple & 63] : padded ? "=" : "";
|
|
14400
|
+
}
|
|
14401
|
+
return out;
|
|
14402
|
+
}
|
|
14403
|
+
function urlSafe(text) {
|
|
14404
|
+
return text.replace(/\+/g, "-").replace(/\//g, "_");
|
|
14405
|
+
}
|
|
14406
|
+
function hex2(bytes) {
|
|
14407
|
+
let out = "";
|
|
14408
|
+
for (const byte of bytes) out += byte.toString(16).padStart(2, "0");
|
|
14409
|
+
return out;
|
|
14410
|
+
}
|
|
14411
|
+
function embedded(bytes, offset) {
|
|
14412
|
+
const shifted = new Uint8Array(offset + bytes.length);
|
|
14413
|
+
shifted.set(bytes, offset);
|
|
14414
|
+
const encoded = base642(shifted);
|
|
14415
|
+
const first = Math.ceil(8 * offset / 6);
|
|
14416
|
+
const last = Math.floor(8 * (offset + bytes.length) / 6);
|
|
14417
|
+
return encoded.slice(first, last);
|
|
14418
|
+
}
|
|
14419
|
+
function unicode(value, upper) {
|
|
14420
|
+
let out = "";
|
|
14421
|
+
for (let i = 0; i < value.length; i++) {
|
|
14422
|
+
const unit = value.charCodeAt(i);
|
|
14423
|
+
if (unit === 34) out += '\\"';
|
|
14424
|
+
else if (unit === 92) out += "\\\\";
|
|
14425
|
+
else if (unit < 32 || unit > 126) {
|
|
14426
|
+
const code = unit.toString(16).padStart(4, "0");
|
|
14427
|
+
out += `\\u${upper ? code.toUpperCase() : code}`;
|
|
14428
|
+
} else out += value[i];
|
|
14429
|
+
}
|
|
14430
|
+
return out;
|
|
14431
|
+
}
|
|
14432
|
+
function percent(value) {
|
|
14433
|
+
let component;
|
|
14434
|
+
try {
|
|
14435
|
+
component = encodeURIComponent(value);
|
|
14436
|
+
} catch {
|
|
14437
|
+
return [];
|
|
14438
|
+
}
|
|
14439
|
+
const lower = component.replace(/%[0-9A-F]{2}/g, (escape) => escape.toLowerCase());
|
|
14440
|
+
const plus = component.replace(/%20/g, "+");
|
|
14441
|
+
let form = "";
|
|
14442
|
+
for (const byte of utf82(value)) {
|
|
14443
|
+
const char = String.fromCharCode(byte);
|
|
14444
|
+
if (/[A-Za-z0-9*\-._]/.test(char)) form += char;
|
|
14445
|
+
else if (byte === 32) form += "+";
|
|
14446
|
+
else form += `%${byte.toString(16).toUpperCase().padStart(2, "0")}`;
|
|
14447
|
+
}
|
|
14448
|
+
return [component, lower, plus, form];
|
|
14449
|
+
}
|
|
14450
|
+
function html(value, apostrophe) {
|
|
14451
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, apostrophe);
|
|
14452
|
+
}
|
|
14453
|
+
function encodings(bytes) {
|
|
14454
|
+
const standard = [base642(bytes), base642(bytes, false)];
|
|
14455
|
+
for (const offset of [0, 1, 2]) {
|
|
14456
|
+
const run2 = embedded(bytes, offset);
|
|
14457
|
+
if (run2.length >= MIN_BASE64) standard.push(run2);
|
|
14458
|
+
}
|
|
14459
|
+
return [...standard, ...standard.map(urlSafe)];
|
|
14460
|
+
}
|
|
14461
|
+
function shapes(value) {
|
|
14462
|
+
const raw = utf82(value);
|
|
14463
|
+
const seen = /* @__PURE__ */ new Set([value]);
|
|
14464
|
+
const out = [];
|
|
14465
|
+
if (raw.length < FRAGMENT) out.push({ bytes: raw, form: "raw" });
|
|
14466
|
+
for (let offset = 0; raw.length >= FRAGMENT && offset + FRAGMENT <= raw.length; offset++) {
|
|
14467
|
+
out.push({ bytes: raw.subarray(offset, offset + FRAGMENT), form: "fragment", offset });
|
|
14468
|
+
}
|
|
14469
|
+
const add = (text, form) => {
|
|
14470
|
+
if (seen.has(text)) return;
|
|
14471
|
+
seen.add(text);
|
|
14472
|
+
out.push({ bytes: utf82(text), form });
|
|
14473
|
+
};
|
|
14474
|
+
const json5 = JSON.stringify(value).slice(1, -1);
|
|
14475
|
+
for (const text of [
|
|
14476
|
+
json5,
|
|
14477
|
+
json5.replace(/\//g, "\\/"),
|
|
14478
|
+
unicode(value, false),
|
|
14479
|
+
unicode(value, true)
|
|
14480
|
+
]) {
|
|
14481
|
+
add(text, "json");
|
|
14482
|
+
}
|
|
14483
|
+
for (const text of percent(value)) add(text, "percent");
|
|
14484
|
+
for (const text of [html(value, "'"), html(value, "'")]) add(text, "html");
|
|
14485
|
+
for (const text of encodings(raw)) add(text, "base64");
|
|
14486
|
+
add(hex2(raw), "hex");
|
|
14487
|
+
add(hex2(raw).toUpperCase(), "hex");
|
|
14488
|
+
return out;
|
|
14489
|
+
}
|
|
14490
|
+
function wrappable(form) {
|
|
14491
|
+
return form === "base64" || form === "hex";
|
|
14492
|
+
}
|
|
14493
|
+
var Automaton = class {
|
|
14494
|
+
edges = /* @__PURE__ */ new Map();
|
|
14495
|
+
fail = [0];
|
|
14496
|
+
depth = [0];
|
|
14497
|
+
children = [0];
|
|
14498
|
+
out = [[]];
|
|
14499
|
+
dict = [-1];
|
|
14500
|
+
lengths = [];
|
|
14501
|
+
add(bytes) {
|
|
14502
|
+
let node = 0;
|
|
14503
|
+
for (const byte of bytes) {
|
|
14504
|
+
const key = node * 256 + byte;
|
|
14505
|
+
let next2 = this.edges.get(key);
|
|
14506
|
+
if (next2 === void 0) {
|
|
14507
|
+
next2 = this.depth.length;
|
|
14508
|
+
this.edges.set(key, next2);
|
|
14509
|
+
this.fail.push(0);
|
|
14510
|
+
this.depth.push(this.depth[node] + 1);
|
|
14511
|
+
this.children.push(0);
|
|
14512
|
+
this.children[node] += 1;
|
|
14513
|
+
this.out.push([]);
|
|
14514
|
+
this.dict.push(-1);
|
|
14515
|
+
}
|
|
14516
|
+
node = next2;
|
|
14517
|
+
}
|
|
14518
|
+
const id2 = this.lengths.length;
|
|
14519
|
+
this.lengths.push(bytes.length);
|
|
14520
|
+
this.out[node].push(id2);
|
|
14521
|
+
return id2;
|
|
14522
|
+
}
|
|
14523
|
+
build() {
|
|
14524
|
+
const queue = [];
|
|
14525
|
+
const byNode = /* @__PURE__ */ new Map();
|
|
14526
|
+
for (const [key, child] of this.edges) {
|
|
14527
|
+
const parent = Math.floor(key / 256);
|
|
14528
|
+
const list = byNode.get(parent) ?? [];
|
|
14529
|
+
list.push([key % 256, child]);
|
|
14530
|
+
byNode.set(parent, list);
|
|
14531
|
+
}
|
|
14532
|
+
for (const [, child] of byNode.get(0) ?? []) queue.push(child);
|
|
14533
|
+
for (let head = 0; head < queue.length; head++) {
|
|
14534
|
+
const node = queue[head];
|
|
14535
|
+
const fallback = this.fail[node];
|
|
14536
|
+
this.dict[node] = this.out[fallback].length > 0 ? fallback : this.dict[fallback];
|
|
14537
|
+
for (const [byte, child] of byNode.get(node) ?? []) {
|
|
14538
|
+
let state = fallback;
|
|
14539
|
+
let target = this.edges.get(state * 256 + byte);
|
|
14540
|
+
while (target === void 0 && state > 0) {
|
|
14541
|
+
state = this.fail[state];
|
|
14542
|
+
target = this.edges.get(state * 256 + byte);
|
|
14543
|
+
}
|
|
14544
|
+
this.fail[child] = target ?? 0;
|
|
14545
|
+
queue.push(child);
|
|
14546
|
+
}
|
|
14547
|
+
}
|
|
14548
|
+
}
|
|
14549
|
+
step(state, byte) {
|
|
14550
|
+
let current = state;
|
|
14551
|
+
for (; ; ) {
|
|
14552
|
+
const next2 = this.edges.get(current * 256 + byte);
|
|
14553
|
+
if (next2 !== void 0) return next2;
|
|
14554
|
+
if (current === 0) return 0;
|
|
14555
|
+
current = this.fail[current];
|
|
14556
|
+
}
|
|
14557
|
+
}
|
|
14558
|
+
matches(state, visit) {
|
|
14559
|
+
for (let node = state; node > 0; node = this.dict[node]) {
|
|
14560
|
+
for (const id2 of this.out[node]) visit(id2);
|
|
14561
|
+
}
|
|
14562
|
+
}
|
|
14563
|
+
partials(state, length2, visit) {
|
|
14564
|
+
for (let node = state; node > 0; node = this.fail[node]) {
|
|
14565
|
+
if (this.children[node] > 0) visit(length2 - this.depth[node]);
|
|
14566
|
+
}
|
|
14567
|
+
}
|
|
14568
|
+
};
|
|
14569
|
+
var RANK = {
|
|
14570
|
+
raw: 0,
|
|
14571
|
+
fragment: 1,
|
|
14572
|
+
json: 2,
|
|
14573
|
+
percent: 3,
|
|
14574
|
+
html: 4,
|
|
14575
|
+
base64: 5,
|
|
14576
|
+
hex: 6,
|
|
14577
|
+
wrapped: 7
|
|
14578
|
+
};
|
|
14579
|
+
var CR2 = 13;
|
|
14580
|
+
var LF2 = 10;
|
|
14581
|
+
var EMPTY2 = new Uint8Array(0);
|
|
14582
|
+
function register(automaton, sources, ids, bytes, source) {
|
|
14583
|
+
const key = Array.from(bytes).join(",");
|
|
14584
|
+
let id2 = ids.get(key);
|
|
14585
|
+
if (id2 === void 0) {
|
|
14586
|
+
id2 = automaton.add(bytes);
|
|
14587
|
+
ids.set(key, id2);
|
|
14588
|
+
sources[id2] = [];
|
|
14589
|
+
}
|
|
14590
|
+
sources[id2].push(source);
|
|
14591
|
+
}
|
|
14592
|
+
function prepare(secrets) {
|
|
14593
|
+
const main = new Automaton();
|
|
14594
|
+
const wrap = new Automaton();
|
|
14595
|
+
const sources = [];
|
|
14596
|
+
const wrapSources = [];
|
|
14597
|
+
const ids = /* @__PURE__ */ new Map();
|
|
14598
|
+
const wrapIds = /* @__PURE__ */ new Map();
|
|
14599
|
+
const values = secrets.map((secret) => utf82(secret.value));
|
|
14600
|
+
secrets.forEach((secret, index) => {
|
|
14601
|
+
if (typeof secret.value !== "string" || values[index].length < MIN_VALUE) {
|
|
14602
|
+
throw new RangeError(`the value of ${secret.name} is shorter than ${MIN_VALUE} bytes`);
|
|
14603
|
+
}
|
|
14604
|
+
for (const shape of shapes(secret.value)) {
|
|
14605
|
+
const source = { secret: index, form: shape.form, offset: shape.offset };
|
|
14606
|
+
register(main, sources, ids, shape.bytes, source);
|
|
14607
|
+
if (wrappable(shape.form)) register(wrap, wrapSources, wrapIds, shape.bytes, source);
|
|
14608
|
+
}
|
|
14609
|
+
});
|
|
14610
|
+
main.build();
|
|
14611
|
+
wrap.build();
|
|
14612
|
+
const replacements = secrets.map((secret) => [
|
|
14613
|
+
utf82(secret.placeholder),
|
|
14614
|
+
utf82(`[redacted:${secret.name}]`)
|
|
14615
|
+
]);
|
|
14616
|
+
return { secrets, values, main, wrap, sources, wrapSources, replacements };
|
|
14617
|
+
}
|
|
14618
|
+
function better(a, b) {
|
|
14619
|
+
if (!b) return true;
|
|
14620
|
+
if (a.end !== b.end) return a.end > b.end;
|
|
14621
|
+
if (a.rank !== b.rank) return a.rank < b.rank;
|
|
14622
|
+
return a.secret < b.secret;
|
|
14623
|
+
}
|
|
14624
|
+
function resolve(c, input, start2, end, source) {
|
|
14625
|
+
if (source.form !== "fragment") {
|
|
14626
|
+
return {
|
|
14627
|
+
start: start2,
|
|
14628
|
+
end,
|
|
14629
|
+
secret: source.secret,
|
|
14630
|
+
form: source.form,
|
|
14631
|
+
rank: RANK[source.form],
|
|
14632
|
+
growing: false
|
|
14633
|
+
};
|
|
14634
|
+
}
|
|
14635
|
+
const value = c.values[source.secret];
|
|
14636
|
+
let stop = end;
|
|
14637
|
+
let at = source.offset + FRAGMENT;
|
|
14638
|
+
while (stop < input.length && at < value.length && input[stop] === value[at]) {
|
|
14639
|
+
stop++;
|
|
14640
|
+
at++;
|
|
14641
|
+
}
|
|
14642
|
+
const form = source.offset === 0 && at === value.length ? "raw" : "fragment";
|
|
14643
|
+
const growing = stop === input.length && at < value.length;
|
|
14644
|
+
return { start: start2, end: stop, secret: source.secret, form, rank: RANK[form], growing };
|
|
14645
|
+
}
|
|
14646
|
+
function keep(best, candidate) {
|
|
14647
|
+
if (better(candidate, best.get(candidate.start))) best.set(candidate.start, candidate);
|
|
14648
|
+
}
|
|
14649
|
+
function scanMain(c, input, best, partials) {
|
|
14650
|
+
let state = 0;
|
|
14651
|
+
for (let i = 0; i < input.length; i++) {
|
|
14652
|
+
state = c.main.step(state, input[i]);
|
|
14653
|
+
c.main.matches(state, (id2) => {
|
|
14654
|
+
const start2 = i + 1 - c.main.lengths[id2];
|
|
14655
|
+
for (const source of c.sources[id2]) {
|
|
14656
|
+
const candidate = resolve(c, input, start2, i + 1, source);
|
|
14657
|
+
if (candidate.growing) partials.push(candidate.start);
|
|
14658
|
+
keep(best, candidate);
|
|
14659
|
+
}
|
|
14660
|
+
});
|
|
14661
|
+
}
|
|
14662
|
+
c.main.partials(state, input.length, (start2) => partials.push(start2));
|
|
14663
|
+
}
|
|
14664
|
+
function scanWrapped(c, input, best, partials) {
|
|
14665
|
+
const map = [];
|
|
14666
|
+
for (let i = 0; i < input.length; i++) if (input[i] !== CR2 && input[i] !== LF2) map.push(i);
|
|
14667
|
+
if (map.length === input.length) return;
|
|
14668
|
+
let state = 0;
|
|
14669
|
+
for (let v = 0; v < map.length; v++) {
|
|
14670
|
+
state = c.wrap.step(state, input[map[v]]);
|
|
14671
|
+
c.wrap.matches(state, (id2) => {
|
|
14672
|
+
const first = v + 1 - c.wrap.lengths[id2];
|
|
14673
|
+
const start2 = map[first];
|
|
14674
|
+
const end = map[v] + 1;
|
|
14675
|
+
const wrapped = end - start2 !== c.wrap.lengths[id2];
|
|
14676
|
+
for (const source of c.wrapSources[id2]) {
|
|
14677
|
+
const form = wrapped ? "wrapped" : source.form;
|
|
14678
|
+
keep(best, { start: start2, end, secret: source.secret, form, rank: RANK[form], growing: false });
|
|
14679
|
+
}
|
|
14680
|
+
});
|
|
14681
|
+
}
|
|
14682
|
+
c.wrap.partials(state, map.length, (start2) => partials.push(map[start2]));
|
|
14683
|
+
}
|
|
14684
|
+
function count(c, hits, candidate) {
|
|
14685
|
+
const name2 = c.secrets[candidate.secret].name;
|
|
14686
|
+
const key = `${name2}\0${candidate.form}`;
|
|
14687
|
+
const hit = hits.get(key) ?? { name: name2, form: candidate.form, count: 0 };
|
|
14688
|
+
hit.count += 1;
|
|
14689
|
+
hits.set(key, hit);
|
|
14690
|
+
}
|
|
14691
|
+
function concat5(parts2) {
|
|
14692
|
+
let length2 = 0;
|
|
14693
|
+
for (const part of parts2) length2 += part.length;
|
|
14694
|
+
const out = new Uint8Array(length2);
|
|
14695
|
+
let at = 0;
|
|
14696
|
+
for (const part of parts2) {
|
|
14697
|
+
out.set(part, at);
|
|
14698
|
+
at += part.length;
|
|
14699
|
+
}
|
|
14700
|
+
return out;
|
|
14701
|
+
}
|
|
14702
|
+
function pass(c, input, final) {
|
|
14703
|
+
const best = /* @__PURE__ */ new Map();
|
|
14704
|
+
const partials = [];
|
|
14705
|
+
scanMain(c, input, best, partials);
|
|
14706
|
+
scanWrapped(c, input, best, partials);
|
|
14707
|
+
const holds = final ? [] : [...new Set(partials)].sort((a, b) => a - b);
|
|
14708
|
+
const starts = [...best.keys()].sort((a, b) => a - b);
|
|
14709
|
+
const parts2 = [];
|
|
14710
|
+
const hits = /* @__PURE__ */ new Map();
|
|
14711
|
+
let pos = 0;
|
|
14712
|
+
let cut = input.length;
|
|
14713
|
+
let s = 0;
|
|
14714
|
+
let h = 0;
|
|
14715
|
+
for (; ; ) {
|
|
14716
|
+
while (s < starts.length && starts[s] < pos) s++;
|
|
14717
|
+
while (h < holds.length && holds[h] < pos) h++;
|
|
14718
|
+
const hold = h < holds.length ? holds[h] : Infinity;
|
|
14719
|
+
const next2 = s < starts.length ? starts[s] : Infinity;
|
|
14720
|
+
if (hold <= next2) {
|
|
14721
|
+
cut = Math.min(hold, input.length);
|
|
14722
|
+
break;
|
|
14723
|
+
}
|
|
14724
|
+
const candidate = best.get(next2);
|
|
14725
|
+
parts2.push(
|
|
14726
|
+
input.subarray(pos, next2),
|
|
14727
|
+
c.replacements[candidate.secret][candidate.form === "raw" ? 0 : 1]
|
|
14728
|
+
);
|
|
14729
|
+
count(c, hits, candidate);
|
|
14730
|
+
pos = candidate.end;
|
|
14731
|
+
}
|
|
14732
|
+
parts2.push(input.subarray(pos, cut));
|
|
14733
|
+
return { output: concat5(parts2), cut, hits };
|
|
14734
|
+
}
|
|
14735
|
+
function merge(into, from) {
|
|
14736
|
+
for (const [key, hit] of from) {
|
|
14737
|
+
const known = into.get(key);
|
|
14738
|
+
if (known) known.count += hit.count;
|
|
14739
|
+
else into.set(key, { ...hit });
|
|
14740
|
+
}
|
|
14741
|
+
}
|
|
14742
|
+
function compile(secrets, options = {}) {
|
|
14743
|
+
const c = prepare(secrets.map((secret) => ({ ...secret })));
|
|
14744
|
+
const decoder4 = new TextDecoder();
|
|
14745
|
+
const idleMs = options.idleMs ?? 250;
|
|
14746
|
+
const scrubBytes = (input) => {
|
|
14747
|
+
if (c.secrets.length === 0) return { bytes: input.slice(), hits: [] };
|
|
14748
|
+
const result = pass(c, input, true);
|
|
14749
|
+
return { bytes: result.output, hits: [...result.hits.values()] };
|
|
14750
|
+
};
|
|
14751
|
+
return {
|
|
14752
|
+
version: options.version ?? 0,
|
|
14753
|
+
idleMs,
|
|
14754
|
+
size: c.main.lengths.length,
|
|
14755
|
+
bytes: scrubBytes,
|
|
14756
|
+
text(input) {
|
|
14757
|
+
const { bytes, hits } = scrubBytes(utf82(input));
|
|
14758
|
+
return { text: decoder4.decode(bytes), hits };
|
|
14759
|
+
},
|
|
14760
|
+
stream() {
|
|
14761
|
+
let pending = EMPTY2;
|
|
14762
|
+
const hits = /* @__PURE__ */ new Map();
|
|
14763
|
+
const run2 = (final) => {
|
|
14764
|
+
if (c.secrets.length === 0 || pending.length === 0) {
|
|
14765
|
+
const out = pending;
|
|
14766
|
+
pending = EMPTY2;
|
|
14767
|
+
return out;
|
|
14768
|
+
}
|
|
14769
|
+
const result = pass(c, pending, final);
|
|
14770
|
+
merge(hits, result.hits);
|
|
14771
|
+
pending = pending.slice(result.cut);
|
|
14772
|
+
return result.output;
|
|
14773
|
+
};
|
|
14774
|
+
return {
|
|
14775
|
+
push(chunk2) {
|
|
14776
|
+
pending = concat5([pending, chunk2]);
|
|
14777
|
+
return run2(false);
|
|
14778
|
+
},
|
|
14779
|
+
idle() {
|
|
14780
|
+
return pending.length < FRAGMENT ? run2(true) : EMPTY2;
|
|
14781
|
+
},
|
|
14782
|
+
end() {
|
|
14783
|
+
return run2(true);
|
|
14784
|
+
},
|
|
14785
|
+
get hits() {
|
|
14786
|
+
return [...hits.values()];
|
|
14787
|
+
}
|
|
14788
|
+
};
|
|
14789
|
+
}
|
|
14790
|
+
};
|
|
14791
|
+
}
|
|
14792
|
+
|
|
14793
|
+
// src/kernel/scrub-file.ts
|
|
14794
|
+
var SCRUB_IDLE_MS = 50;
|
|
14795
|
+
var encoder5 = new TextEncoder();
|
|
14796
|
+
function scrubberOf(secrets) {
|
|
14797
|
+
const usable = secrets.filter((s) => encoder5.encode(s.value).length >= MIN_VALUE);
|
|
14798
|
+
return usable.length > 0 ? compile(usable, { idleMs: SCRUB_IDLE_MS }) : void 0;
|
|
14799
|
+
}
|
|
14800
|
+
async function writeAll2(file, bytes, signal) {
|
|
14801
|
+
const write = file.write;
|
|
14802
|
+
for (let at = 0; at < bytes.length; ) {
|
|
14803
|
+
at += await write.call(file, bytes.subarray(at), at === 0 ? signal : void 0);
|
|
14804
|
+
}
|
|
14805
|
+
}
|
|
14806
|
+
function bound(file, key) {
|
|
14807
|
+
const method = file[key];
|
|
14808
|
+
return typeof method === "function" ? { [key]: method.bind(file) } : {};
|
|
14809
|
+
}
|
|
14810
|
+
function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
14811
|
+
const file = inner.file;
|
|
14812
|
+
const stream = scrubber.stream();
|
|
14813
|
+
let queue = Promise.resolve();
|
|
14814
|
+
let timer;
|
|
14815
|
+
let failed3;
|
|
14816
|
+
const raise = () => {
|
|
14817
|
+
if (failed3 === void 0) return;
|
|
14818
|
+
const err = failed3;
|
|
14819
|
+
failed3 = void 0;
|
|
14820
|
+
throw err;
|
|
14821
|
+
};
|
|
14822
|
+
const enqueue = (bytes, signal) => {
|
|
14823
|
+
const next2 = queue.then(() => bytes.length > 0 ? writeAll2(file, bytes, signal) : void 0);
|
|
14824
|
+
queue = next2.catch(() => void 0);
|
|
14825
|
+
return next2;
|
|
14826
|
+
};
|
|
14827
|
+
const release = () => {
|
|
14828
|
+
timer = void 0;
|
|
14829
|
+
enqueue(stream.idle()).catch((err) => {
|
|
14830
|
+
failed3 = err;
|
|
14831
|
+
});
|
|
14832
|
+
};
|
|
14833
|
+
return new OpenFile({
|
|
14834
|
+
...bound(file, "read"),
|
|
14835
|
+
...bound(file, "peek"),
|
|
14836
|
+
...bound(file, "poll"),
|
|
14837
|
+
...bound(file, "changed"),
|
|
14838
|
+
...bound(file, "stat"),
|
|
14839
|
+
...file.tty ? { tty: file.tty } : {},
|
|
14840
|
+
...file.clipboard ? { clipboard: file.clipboard } : {},
|
|
14841
|
+
...file.write ? {
|
|
14842
|
+
write: async (bytes, signal) => {
|
|
14843
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
14844
|
+
raise();
|
|
14845
|
+
await enqueue(stream.push(bytes), signal);
|
|
14846
|
+
timer = setTimeout(release, idleMs);
|
|
14847
|
+
return bytes.length;
|
|
14848
|
+
}
|
|
14849
|
+
} : {},
|
|
14850
|
+
flush: async () => {
|
|
14851
|
+
await queue;
|
|
14852
|
+
raise();
|
|
14853
|
+
await file.flush?.();
|
|
14854
|
+
},
|
|
14855
|
+
close: async () => {
|
|
14856
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
14857
|
+
let failure2;
|
|
14858
|
+
try {
|
|
14859
|
+
await enqueue(stream.end());
|
|
14860
|
+
raise();
|
|
14861
|
+
} catch (err) {
|
|
14862
|
+
failure2 = { err };
|
|
14863
|
+
}
|
|
14864
|
+
await inner.release();
|
|
14865
|
+
if (failure2) throw failure2.err;
|
|
14866
|
+
}
|
|
14867
|
+
});
|
|
14868
|
+
}
|
|
14869
|
+
function scrubbedAll(file, scrubbers) {
|
|
14870
|
+
return scrubbers.reduce((inner, scrubber) => scrubbed(inner, scrubber), file);
|
|
14871
|
+
}
|
|
14872
|
+
function stdioFiles(fds) {
|
|
14873
|
+
const files = /* @__PURE__ */ new Set();
|
|
14874
|
+
for (const fd of [1, 2]) {
|
|
14875
|
+
try {
|
|
14876
|
+
files.add(fds.get(fd));
|
|
14877
|
+
} catch {
|
|
14878
|
+
}
|
|
14879
|
+
}
|
|
14880
|
+
return files;
|
|
14881
|
+
}
|
|
14882
|
+
function scrubStdio(fds, scrubber) {
|
|
14883
|
+
const wrapped = /* @__PURE__ */ new Map();
|
|
14884
|
+
const stdio = stdioFiles(fds);
|
|
14885
|
+
for (const fd of fds.numbers()) {
|
|
14886
|
+
const original = fds.get(fd);
|
|
14887
|
+
if (!stdio.has(original) && !original.file.tty) continue;
|
|
14888
|
+
const known = wrapped.get(original);
|
|
14889
|
+
const flags2 = fds.statusFlags(fd);
|
|
14890
|
+
const wrapper = known ? known.retain() : scrubbed(original.retain(), scrubber);
|
|
14891
|
+
wrapped.set(original, wrapper);
|
|
14892
|
+
fds.installAt(fd, wrapper);
|
|
14893
|
+
if (flags2 !== void 0) fds.setStatusFlags(fd, flags2);
|
|
14894
|
+
}
|
|
14895
|
+
}
|
|
14896
|
+
|
|
14276
14897
|
// src/kernel/sealed.ts
|
|
14277
14898
|
var SEALED_MAX_BYTES = 64 * 1024;
|
|
14278
14899
|
var SEALED_TIMEOUT_MS = 1e4;
|
|
@@ -14286,7 +14907,7 @@ var SEALED_OPS = /* @__PURE__ */ new Set([
|
|
|
14286
14907
|
"cancel",
|
|
14287
14908
|
"materialize"
|
|
14288
14909
|
]);
|
|
14289
|
-
var
|
|
14910
|
+
var encoder6 = new TextEncoder();
|
|
14290
14911
|
var decoder3 = new TextDecoder("utf-8", { fatal: true });
|
|
14291
14912
|
function parseSealed(bytes) {
|
|
14292
14913
|
try {
|
|
@@ -14302,11 +14923,16 @@ function parseSealed(bytes) {
|
|
|
14302
14923
|
const req = parsed2;
|
|
14303
14924
|
if (req.v !== 1 || typeof req.op !== "string" || !SEALED_OPS.has(req.op))
|
|
14304
14925
|
throw new KernelError("EINVAL");
|
|
14926
|
+
if (req.op === "materialize" && !materializable(req)) throw new KernelError("EINVAL");
|
|
14305
14927
|
return req;
|
|
14306
14928
|
} finally {
|
|
14307
14929
|
bytes.fill(0);
|
|
14308
14930
|
}
|
|
14309
14931
|
}
|
|
14932
|
+
function materializable(req) {
|
|
14933
|
+
if (req.shellGrants !== true && !isStrings(req.names)) return false;
|
|
14934
|
+
return isStrings(req.argv) && typeof req.path === "string" && typeof req.cwd === "string";
|
|
14935
|
+
}
|
|
14310
14936
|
function errorReply(code, message3) {
|
|
14311
14937
|
return { v: 1, error: { code, message: message3 } };
|
|
14312
14938
|
}
|
|
@@ -14350,12 +14976,14 @@ var SealedChannel = class {
|
|
|
14350
14976
|
const timer = setTimeout(() => control.abort("timeout"), this.broker.timeoutMs);
|
|
14351
14977
|
const req = { ...fields, v: 1, op: fields.op, caller };
|
|
14352
14978
|
const flight = { control, done: Promise.resolve() };
|
|
14353
|
-
flight.done = this.answer(req, control.signal).then((reply) => {
|
|
14979
|
+
flight.done = this.answer(req, control.signal).then(async (reply) => {
|
|
14354
14980
|
clearTimeout(timer);
|
|
14355
14981
|
gone.removeEventListener("abort", withdraw);
|
|
14982
|
+
if (reply && req.op === "materialize")
|
|
14983
|
+
await this.broker.tickets.record(req, reply, caller.pid);
|
|
14356
14984
|
if (this.inflight !== flight) return;
|
|
14357
14985
|
this.inflight = void 0;
|
|
14358
|
-
if (reply) this.reply =
|
|
14986
|
+
if (reply) this.reply = encoder6.encode(serialized(reply));
|
|
14359
14987
|
});
|
|
14360
14988
|
this.inflight = flight;
|
|
14361
14989
|
return length2;
|
|
@@ -14363,8 +14991,8 @@ var SealedChannel = class {
|
|
|
14363
14991
|
async answer(req, signal) {
|
|
14364
14992
|
const hook = this.broker.hook;
|
|
14365
14993
|
if (!hook) return errorReply("ENOTCONN", "no vault is connected");
|
|
14366
|
-
const stopped = new Promise((
|
|
14367
|
-
signal.addEventListener("abort", () =>
|
|
14994
|
+
const stopped = new Promise((resolve2) => {
|
|
14995
|
+
signal.addEventListener("abort", () => resolve2(void 0), { once: true });
|
|
14368
14996
|
});
|
|
14369
14997
|
if (signal.aborted) return void 0;
|
|
14370
14998
|
const asked = Promise.resolve().then(() => hook(req, { signal })).then(
|
|
@@ -14419,17 +15047,60 @@ var SealedChannel = class {
|
|
|
14419
15047
|
this.reply = void 0;
|
|
14420
15048
|
}
|
|
14421
15049
|
};
|
|
15050
|
+
function swapOf(reply) {
|
|
15051
|
+
if (!isRecord(reply) || reply.error !== void 0) return void 0;
|
|
15052
|
+
const values = stringRecord(reply.values);
|
|
15053
|
+
const placeholders = stringRecord(reply.placeholders);
|
|
15054
|
+
return values && placeholders ? { values, placeholders } : void 0;
|
|
15055
|
+
}
|
|
14422
15056
|
var SealedBroker = class {
|
|
14423
15057
|
hook;
|
|
14424
15058
|
users;
|
|
14425
15059
|
timeoutMs;
|
|
14426
15060
|
tagOf;
|
|
15061
|
+
tickets = new TicketBook();
|
|
15062
|
+
userOf = async () => void 0;
|
|
14427
15063
|
constructor(hook, users, timeoutMs = SEALED_TIMEOUT_MS, tagOf = () => void 0) {
|
|
14428
15064
|
this.hook = hook;
|
|
14429
15065
|
this.users = users;
|
|
14430
15066
|
this.timeoutMs = timeoutMs;
|
|
14431
15067
|
this.tagOf = tagOf;
|
|
14432
15068
|
}
|
|
15069
|
+
async stamp(ids, cred, tag) {
|
|
15070
|
+
const user = await this.userOf(cred.euid).catch(() => void 0);
|
|
15071
|
+
return {
|
|
15072
|
+
pid: ids.pid,
|
|
15073
|
+
ppid: ids.ppid,
|
|
15074
|
+
uid: cred.euid,
|
|
15075
|
+
gid: cred.egid,
|
|
15076
|
+
...user !== void 0 ? { user } : {},
|
|
15077
|
+
groups: [...cred.groups],
|
|
15078
|
+
users: this.users,
|
|
15079
|
+
...tag !== void 0 ? { tag } : {}
|
|
15080
|
+
};
|
|
15081
|
+
}
|
|
15082
|
+
async consume(fields) {
|
|
15083
|
+
const { hook } = this;
|
|
15084
|
+
if (!hook) return void 0;
|
|
15085
|
+
const control = new AbortController();
|
|
15086
|
+
const timer = setTimeout(() => control.abort("timeout"), this.timeoutMs);
|
|
15087
|
+
const stopped = new Promise((resolve2) => {
|
|
15088
|
+
control.signal.addEventListener("abort", () => resolve2(void 0), { once: true });
|
|
15089
|
+
});
|
|
15090
|
+
const req = {
|
|
15091
|
+
...fields,
|
|
15092
|
+
v: 1,
|
|
15093
|
+
op: "materializeConsume",
|
|
15094
|
+
caller: fields.stamp
|
|
15095
|
+
};
|
|
15096
|
+
try {
|
|
15097
|
+
const asked = Promise.resolve().then(() => hook(req, { signal: control.signal })).then(swapOf, () => void 0);
|
|
15098
|
+
return await Promise.race([asked, stopped]);
|
|
15099
|
+
} finally {
|
|
15100
|
+
clearTimeout(timer);
|
|
15101
|
+
control.abort("done");
|
|
15102
|
+
}
|
|
15103
|
+
}
|
|
14433
15104
|
open() {
|
|
14434
15105
|
const channel = new SealedChannel(this);
|
|
14435
15106
|
return new OpenFile({
|
|
@@ -14928,11 +15599,11 @@ function codeOf3(err) {
|
|
|
14928
15599
|
}
|
|
14929
15600
|
function wait(ms, signal) {
|
|
14930
15601
|
if (signal.aborted) return Promise.resolve();
|
|
14931
|
-
return new Promise((
|
|
15602
|
+
return new Promise((resolve2) => {
|
|
14932
15603
|
const done4 = () => {
|
|
14933
15604
|
clearTimeout(timer);
|
|
14934
15605
|
signal.removeEventListener("abort", done4);
|
|
14935
|
-
|
|
15606
|
+
resolve2();
|
|
14936
15607
|
};
|
|
14937
15608
|
const timer = setTimeout(done4, ms);
|
|
14938
15609
|
signal.addEventListener("abort", done4, { once: true });
|
|
@@ -15259,11 +15930,11 @@ async function resize(h, path, size) {
|
|
|
15259
15930
|
}
|
|
15260
15931
|
}
|
|
15261
15932
|
function sleep(ms, signal) {
|
|
15262
|
-
return new Promise((
|
|
15933
|
+
return new Promise((resolve2) => {
|
|
15263
15934
|
const done4 = () => {
|
|
15264
15935
|
clearTimeout(timer);
|
|
15265
15936
|
signal.removeEventListener("abort", done4);
|
|
15266
|
-
|
|
15937
|
+
resolve2();
|
|
15267
15938
|
};
|
|
15268
15939
|
const timer = setTimeout(done4, ms);
|
|
15269
15940
|
signal.addEventListener("abort", done4);
|
|
@@ -15346,7 +16017,7 @@ var PORT_DEAD_MS = 1e4;
|
|
|
15346
16017
|
var PORT_LINGER_MS = 1e3;
|
|
15347
16018
|
function timed(transport, ms) {
|
|
15348
16019
|
const inflight = /* @__PURE__ */ new Set();
|
|
15349
|
-
const guard2 = (name2, run2, late, expire) => new Promise((
|
|
16020
|
+
const guard2 = (name2, run2, late, expire) => new Promise((resolve2, reject) => {
|
|
15350
16021
|
let expired = false;
|
|
15351
16022
|
const running = run2();
|
|
15352
16023
|
inflight.add(running);
|
|
@@ -15363,7 +16034,7 @@ function timed(transport, ms) {
|
|
|
15363
16034
|
(value) => {
|
|
15364
16035
|
clearTimeout(timer);
|
|
15365
16036
|
if (expired) late?.(value);
|
|
15366
|
-
|
|
16037
|
+
resolve2(value);
|
|
15367
16038
|
},
|
|
15368
16039
|
(err) => {
|
|
15369
16040
|
clearTimeout(timer);
|
|
@@ -15498,7 +16169,7 @@ var PortTransport = class {
|
|
|
15498
16169
|
ask(message3, bytes = 0, transfer = []) {
|
|
15499
16170
|
const id2 = ++this.next;
|
|
15500
16171
|
if (this.dead) return Promise.reject(fsError2("ENOTCONN", this.dead));
|
|
15501
|
-
return new Promise((
|
|
16172
|
+
return new Promise((resolve2, reject) => {
|
|
15502
16173
|
const timer = setTimeout(
|
|
15503
16174
|
() => {
|
|
15504
16175
|
this.waiting.delete(id2);
|
|
@@ -15512,7 +16183,7 @@ var PortTransport = class {
|
|
|
15512
16183
|
clearTimeout(timer);
|
|
15513
16184
|
this.waiting.delete(id2);
|
|
15514
16185
|
if (reply.error) reject(fsError2(reply.error.code ?? "EIO", reply.error.message ?? ""));
|
|
15515
|
-
else
|
|
16186
|
+
else resolve2(reply);
|
|
15516
16187
|
});
|
|
15517
16188
|
try {
|
|
15518
16189
|
this.port.postMessage({ id: id2, ...message3 }, transfer);
|
|
@@ -15541,7 +16212,7 @@ var PortTransport = class {
|
|
|
15541
16212
|
this.fail("the folder's watch ended");
|
|
15542
16213
|
return Promise.resolve();
|
|
15543
16214
|
}
|
|
15544
|
-
return new Promise((
|
|
16215
|
+
return new Promise((resolve2, reject) => {
|
|
15545
16216
|
const finish = () => {
|
|
15546
16217
|
this.waiting.delete(id2);
|
|
15547
16218
|
signal.removeEventListener("abort", stop);
|
|
@@ -15552,7 +16223,7 @@ var PortTransport = class {
|
|
|
15552
16223
|
this.port.postMessage({ id: id2, op: "unwatch" });
|
|
15553
16224
|
} catch {
|
|
15554
16225
|
}
|
|
15555
|
-
|
|
16226
|
+
resolve2();
|
|
15556
16227
|
};
|
|
15557
16228
|
this.watchBeat();
|
|
15558
16229
|
this.waiting.set(id2, (reply) => {
|
|
@@ -15560,7 +16231,7 @@ var PortTransport = class {
|
|
|
15560
16231
|
if (reply.event) return onEvent(reply.event);
|
|
15561
16232
|
finish();
|
|
15562
16233
|
if (reply.error) reject(fsError2(reply.error.code ?? "ENOTCONN", reply.error.message ?? ""));
|
|
15563
|
-
else
|
|
16234
|
+
else resolve2();
|
|
15564
16235
|
});
|
|
15565
16236
|
signal.addEventListener("abort", stop, { once: true });
|
|
15566
16237
|
try {
|
|
@@ -15673,10 +16344,10 @@ var ChunkedBytes = class {
|
|
|
15673
16344
|
}
|
|
15674
16345
|
truncate(size) {
|
|
15675
16346
|
if (size < this.size) {
|
|
15676
|
-
const
|
|
15677
|
-
this.chunks.length = Math.min(this.chunks.length,
|
|
15678
|
-
const tail = this.chunks[
|
|
15679
|
-
const from = size - (
|
|
16347
|
+
const keep2 = Math.ceil(size / CHUNK3);
|
|
16348
|
+
this.chunks.length = Math.min(this.chunks.length, keep2);
|
|
16349
|
+
const tail = this.chunks[keep2 - 1];
|
|
16350
|
+
const from = size - (keep2 - 1) * CHUNK3;
|
|
15680
16351
|
if (tail && from < tail.length) tail.fill(0, from);
|
|
15681
16352
|
}
|
|
15682
16353
|
this.size = size;
|
|
@@ -15921,8 +16592,8 @@ function importedMemory(bytes) {
|
|
|
15921
16592
|
at = end;
|
|
15922
16593
|
continue;
|
|
15923
16594
|
}
|
|
15924
|
-
const
|
|
15925
|
-
for (let i = 0; i <
|
|
16595
|
+
const count2 = u32();
|
|
16596
|
+
for (let i = 0; i < count2; i++) {
|
|
15926
16597
|
const module = name2();
|
|
15927
16598
|
const field3 = name2();
|
|
15928
16599
|
const kind = bytes[at++];
|
|
@@ -16351,7 +17022,7 @@ ${lines2}
|
|
|
16351
17022
|
const withdraw = () => control.abort("withdrawn");
|
|
16352
17023
|
requester.addEventListener("abort", withdraw, { once: true });
|
|
16353
17024
|
const aborted2 = new Promise(
|
|
16354
|
-
(
|
|
17025
|
+
(resolve2) => control.signal.addEventListener("abort", () => resolve2("aborted"), { once: true })
|
|
16355
17026
|
);
|
|
16356
17027
|
try {
|
|
16357
17028
|
const answered2 = Promise.resolve().then(() => approve(req, { signal: control.signal })).catch(() => "deny");
|
|
@@ -16477,7 +17148,7 @@ var LAYOUT = [
|
|
|
16477
17148
|
];
|
|
16478
17149
|
var LOAD_SAMPLE_MS = 5e3;
|
|
16479
17150
|
var LOAD_WINDOWS_MS = [6e4, 3e5, 9e5];
|
|
16480
|
-
var
|
|
17151
|
+
var encoder7 = new TextEncoder();
|
|
16481
17152
|
var USERS_MODES = ["off", "report", "enforce"];
|
|
16482
17153
|
function usersMode(mode = "off") {
|
|
16483
17154
|
if (USERS_MODES.includes(mode)) return mode;
|
|
@@ -16508,6 +17179,30 @@ function shebang(head) {
|
|
|
16508
17179
|
if (head[0] !== 35 || head[1] !== 33) return void 0;
|
|
16509
17180
|
return new TextDecoder().decode(head.subarray(0, SHEBANG_MAX)).slice(2).split("\n")[0].trim().split(/[ \t]+/);
|
|
16510
17181
|
}
|
|
17182
|
+
async function rootOnly(fs, path) {
|
|
17183
|
+
const names = chain(path);
|
|
17184
|
+
for (const [i, at] of names.entries()) {
|
|
17185
|
+
const st = await fs.lstat(at).catch(() => void 0);
|
|
17186
|
+
const kind = i === names.length - 1 ? st?.isFile : st?.isDirectory;
|
|
17187
|
+
if (!kind || st?.uid !== 0 || (st.mode & 18) !== 0) return false;
|
|
17188
|
+
}
|
|
17189
|
+
return true;
|
|
17190
|
+
}
|
|
17191
|
+
function plainEnv(words2) {
|
|
17192
|
+
const next2 = words2[1];
|
|
17193
|
+
if (baseName(words2[0] ?? "") !== "env" || next2 === void 0) return false;
|
|
17194
|
+
return next2 === "-S" || !next2.startsWith("-") && !next2.includes("=");
|
|
17195
|
+
}
|
|
17196
|
+
function shebangCommand(words2) {
|
|
17197
|
+
if (!plainEnv(words2)) {
|
|
17198
|
+
const arg2 = words2.slice(1).join(" ");
|
|
17199
|
+
return { interp: words2[0], args: arg2 ? [arg2] : [] };
|
|
17200
|
+
}
|
|
17201
|
+
const split2 = words2[1] === "-S";
|
|
17202
|
+
const [interp, ...rest2] = words2.slice(split2 ? 2 : 1);
|
|
17203
|
+
const arg = rest2.join(" ");
|
|
17204
|
+
return { interp, args: split2 ? rest2 : arg ? [arg] : [] };
|
|
17205
|
+
}
|
|
16511
17206
|
function interpreter(head) {
|
|
16512
17207
|
const words2 = shebang(head);
|
|
16513
17208
|
if (!words2) return "node";
|
|
@@ -16561,7 +17256,7 @@ function childHandle(handle) {
|
|
|
16561
17256
|
onState: (listener) => handle.onState(listener)
|
|
16562
17257
|
};
|
|
16563
17258
|
}
|
|
16564
|
-
function
|
|
17259
|
+
function concat6(chunks) {
|
|
16565
17260
|
const out = new Uint8Array(chunks.reduce((n, chunk2) => n + chunk2.length, 0));
|
|
16566
17261
|
let offset = 0;
|
|
16567
17262
|
for (const chunk2 of chunks) {
|
|
@@ -16647,6 +17342,7 @@ var Launcher = class {
|
|
|
16647
17342
|
usersMode;
|
|
16648
17343
|
dac;
|
|
16649
17344
|
sealed;
|
|
17345
|
+
scrubs = /* @__PURE__ */ new Map();
|
|
16650
17346
|
clipboard;
|
|
16651
17347
|
rootFs;
|
|
16652
17348
|
fileWatches;
|
|
@@ -16670,6 +17366,8 @@ var Launcher = class {
|
|
|
16670
17366
|
void 0,
|
|
16671
17367
|
(pid) => this.tagOf(pid)
|
|
16672
17368
|
);
|
|
17369
|
+
this.sealed.tickets.normalise = (path) => physicalPathAsync(this.base, path);
|
|
17370
|
+
this.sealed.userOf = async (uid) => (await this.users.lookup(uid))?.name;
|
|
16673
17371
|
if (this.owners) options.fs.trackOwners?.();
|
|
16674
17372
|
this.mounts = new MountTable({
|
|
16675
17373
|
open: (type, spec) => this.driver(type, spec),
|
|
@@ -16918,13 +17616,12 @@ var Launcher = class {
|
|
|
16918
17616
|
const binfmt = isWasm(head) ? void 0 : binfmtOf(await this.interpreters(scope), script);
|
|
16919
17617
|
const words2 = shebang(head) ?? (binfmt ? [binfmt] : void 0);
|
|
16920
17618
|
if (!words2) return void 0;
|
|
16921
|
-
|
|
16922
|
-
const [
|
|
16923
|
-
|
|
16924
|
-
const
|
|
16925
|
-
const found = interp ? await this.resolve(interp, interp, cwd, scope) : void 0;
|
|
17619
|
+
const { interp, args } = shebangCommand(words2);
|
|
17620
|
+
const passed = [...args, command ? script : file, ...argv.slice(1)];
|
|
17621
|
+
if (!interp) return void 0;
|
|
17622
|
+
const found = await this.resolve(interp, interp, cwd, scope);
|
|
16926
17623
|
if (!found) {
|
|
16927
|
-
if (
|
|
17624
|
+
if (depth >= MAX_INTERPRETERS || !await this.scriptCommand(interp, cwd, scope)) {
|
|
16928
17625
|
return void 0;
|
|
16929
17626
|
}
|
|
16930
17627
|
const inner = await this.interpreted(interp, [interp, ...passed], cwd, scope, depth + 1);
|
|
@@ -16964,6 +17661,99 @@ var Launcher = class {
|
|
|
16964
17661
|
await need(g, "exec", this.fs.resolvePath(req.cwd, file), want);
|
|
16965
17662
|
}
|
|
16966
17663
|
}
|
|
17664
|
+
async checkedPlan(req, { ppid, cred, scope }, fds) {
|
|
17665
|
+
const planned = await this.plan(req.file, req.argv, req.cwd, scope, req.argv0);
|
|
17666
|
+
try {
|
|
17667
|
+
await this.mayExec(cred, { ...req, pid: ppid }, planned);
|
|
17668
|
+
} catch (err) {
|
|
17669
|
+
await fds.closeAll();
|
|
17670
|
+
throw err.code === "EACCES" ? new SpawnError("EACCES") : err;
|
|
17671
|
+
}
|
|
17672
|
+
if (planned) return planned;
|
|
17673
|
+
await fds.closeAll();
|
|
17674
|
+
throw new SpawnError(await this.unrunnable(req.file, req.cwd, scope));
|
|
17675
|
+
}
|
|
17676
|
+
async ticketFile(req, fds) {
|
|
17677
|
+
if (req.file.startsWith("/")) return physicalPathAsync(this.base, req.file);
|
|
17678
|
+
await fds.closeAll();
|
|
17679
|
+
throw new SpawnError("EACCES");
|
|
17680
|
+
}
|
|
17681
|
+
takeTicket(req) {
|
|
17682
|
+
if (!(TICKET_ENV in req.env)) return void 0;
|
|
17683
|
+
return this.sealed.tickets.take(req.env[TICKET_ENV] ?? "") ?? null;
|
|
17684
|
+
}
|
|
17685
|
+
async redeemed(req, who, planned, fds) {
|
|
17686
|
+
if (who.booked === void 0) return { env: req.env };
|
|
17687
|
+
try {
|
|
17688
|
+
const redeemed = await this.redeem(req, who, planned);
|
|
17689
|
+
if (redeemed.scrub) scrubStdio(fds, redeemed.scrub);
|
|
17690
|
+
return redeemed;
|
|
17691
|
+
} catch {
|
|
17692
|
+
await fds.closeAll();
|
|
17693
|
+
throw new SpawnError("EACCES");
|
|
17694
|
+
}
|
|
17695
|
+
}
|
|
17696
|
+
async redeem(req, { ppid, cred, scope, booked }, planned) {
|
|
17697
|
+
const { [TICKET_ENV]: ticket = "", ...env } = req.env;
|
|
17698
|
+
const caller = this.jobs.shown(ppid);
|
|
17699
|
+
const named = typeof req.argv0 === "string" && !planned.script && !planned.target.fixed;
|
|
17700
|
+
const argv = named ? [req.argv0, ...req.argv.slice(1)] : req.argv;
|
|
17701
|
+
const exact = booked?.pid === caller && req.file === booked.path && await physicalPathAsync(this.base, req.cwd) === booked.cwd && await argvDigest(argv) === booked.argv;
|
|
17702
|
+
if (!exact) throw new SpawnError("EACCES");
|
|
17703
|
+
const { requested: path, requestedCwd: cwd, path: resolved2 } = booked;
|
|
17704
|
+
const pid = this.nextPid++;
|
|
17705
|
+
const ids = { pid: req.exec ? caller : pid, ppid: caller };
|
|
17706
|
+
const stamp = await this.sealed.stamp(ids, cred, this.tagOf(ppid));
|
|
17707
|
+
const interpreters = await this.interpreterChain(planned, booked.cwd, scope);
|
|
17708
|
+
const trusted = this.usersMode === "enforce" && await this.trustedFiles(planned, req.file, booked.cwd, scope);
|
|
17709
|
+
const swap = await this.sealed.consume({
|
|
17710
|
+
ticket,
|
|
17711
|
+
stamp,
|
|
17712
|
+
path,
|
|
17713
|
+
resolved: resolved2,
|
|
17714
|
+
argv,
|
|
17715
|
+
cwd,
|
|
17716
|
+
interpreters,
|
|
17717
|
+
trusted
|
|
17718
|
+
});
|
|
17719
|
+
if (!swap) throw new SpawnError("EACCES");
|
|
17720
|
+
const secrets = [];
|
|
17721
|
+
for (const [name2, placeholder] of Object.entries(swap.placeholders)) {
|
|
17722
|
+
const value = swap.values[name2];
|
|
17723
|
+
if (value === void 0 || env[name2] !== placeholder) continue;
|
|
17724
|
+
env[name2] = value;
|
|
17725
|
+
secrets.push({ name: name2, value, placeholder });
|
|
17726
|
+
}
|
|
17727
|
+
const scrub = scrubberOf(secrets);
|
|
17728
|
+
return { env, pid, cwd: booked.cwd, ...scrub ? { scrub } : {} };
|
|
17729
|
+
}
|
|
17730
|
+
async interpreterChain(planned, cwd, scope) {
|
|
17731
|
+
const out = [];
|
|
17732
|
+
for (const entry of planned.via ?? []) {
|
|
17733
|
+
if (entry.includes("/")) {
|
|
17734
|
+
out.push(await physicalPathAsync(this.base, this.fs.resolvePath(cwd, entry)));
|
|
17735
|
+
continue;
|
|
17736
|
+
}
|
|
17737
|
+
const script = (await this.scriptCommand(entry, cwd, scope))?.script;
|
|
17738
|
+
out.push(
|
|
17739
|
+
await physicalPathAsync(this.base, script ?? await this.commandFile(entry, cwd, scope))
|
|
17740
|
+
);
|
|
17741
|
+
}
|
|
17742
|
+
return out;
|
|
17743
|
+
}
|
|
17744
|
+
async commandFile(name2, cwd, scope) {
|
|
17745
|
+
const scoped = await this.resolve(name2, name2, cwd, scope);
|
|
17746
|
+
const system = scope === "" ? scoped : await this.resolve(name2, name2, cwd, "");
|
|
17747
|
+
if (!scoped || system?.glue === scoped.glue) return `/usr/bin/${name2}`;
|
|
17748
|
+
return scoped.glue;
|
|
17749
|
+
}
|
|
17750
|
+
async trustedFiles(planned, file, cwd, scope) {
|
|
17751
|
+
const files = await this.backingOf(planned, file, cwd, scope);
|
|
17752
|
+
for (const at of files) {
|
|
17753
|
+
if (!await rootOnly(this.base, await physicalPathAsync(this.base, at))) return false;
|
|
17754
|
+
}
|
|
17755
|
+
return true;
|
|
17756
|
+
}
|
|
16967
17757
|
async grantedCwd(caller, cwd) {
|
|
16968
17758
|
const real = await physicalPathAsync(this.base, cwd).catch(() => void 0);
|
|
16969
17759
|
return real === cwd && await this.sudoer.reachable(caller, cwd);
|
|
@@ -16982,13 +17772,15 @@ var Launcher = class {
|
|
|
16982
17772
|
}
|
|
16983
17773
|
async backing(file, cwd) {
|
|
16984
17774
|
const planned = await this.plan(file, [file], cwd, "");
|
|
16985
|
-
|
|
17775
|
+
return planned && this.backingOf(planned, file, cwd, "");
|
|
17776
|
+
}
|
|
17777
|
+
async backingOf(planned, file, cwd, scope) {
|
|
16986
17778
|
const { glue, wasm, imports } = planned.target;
|
|
16987
17779
|
const files = [glue, wasm, ...imports ? [imports] : []];
|
|
16988
17780
|
const scripts = [];
|
|
16989
17781
|
for (const name2 of [file, ...planned.via ?? []]) {
|
|
16990
17782
|
if (name2.includes("/") && !COMMAND2.test(name2)) scripts.push(this.fs.resolvePath(cwd, name2));
|
|
16991
|
-
const script = (await this.scriptCommand(name2, cwd,
|
|
17783
|
+
const script = (await this.scriptCommand(name2, cwd, scope))?.script;
|
|
16992
17784
|
if (script) scripts.push(script);
|
|
16993
17785
|
}
|
|
16994
17786
|
files.push(...scripts, ...await this.binfmtManifests(scripts));
|
|
@@ -17117,6 +17909,7 @@ var Launcher = class {
|
|
|
17117
17909
|
const seen = { ...req.env, HOSTNAME: this.hostname, cwd };
|
|
17118
17910
|
const env = { ...expandDefaults(target.env, seen), ...req.env };
|
|
17119
17911
|
for (const key of target.unset ?? []) delete env[key];
|
|
17912
|
+
delete env[TICKET_ENV];
|
|
17120
17913
|
env.HOSTNAME = this.hostname;
|
|
17121
17914
|
let program;
|
|
17122
17915
|
try {
|
|
@@ -17132,16 +17925,23 @@ var Launcher = class {
|
|
|
17132
17925
|
groupSession(pgid) {
|
|
17133
17926
|
return this.jobs.sessionOf(pgid);
|
|
17134
17927
|
}
|
|
17928
|
+
treeScrubs(pid, req) {
|
|
17929
|
+
const inherited2 = req.ppid !== void 0 ? this.scrubs.get(req.ppid) : void 0;
|
|
17930
|
+
const scrubs = req.scrub ? [...inherited2 ?? [], req.scrub] : inherited2;
|
|
17931
|
+
if (scrubs) this.scrubs.set(pid, scrubs);
|
|
17932
|
+
return scrubs;
|
|
17933
|
+
}
|
|
17135
17934
|
start(req) {
|
|
17136
17935
|
this.sampling();
|
|
17137
17936
|
if (req.pgid !== void 0 && this.jobs.sessionOf(req.pgid) === void 0) {
|
|
17138
17937
|
throw new SpawnError("ESRCH");
|
|
17139
17938
|
}
|
|
17140
|
-
const pid = this.nextPid++;
|
|
17939
|
+
const pid = req.pid ?? this.nextPid++;
|
|
17940
|
+
const scrubs = this.treeScrubs(pid, req);
|
|
17141
17941
|
const stack = this.stackFor(req.tag);
|
|
17142
17942
|
const terminal = req.fds.stdioTerminal();
|
|
17143
17943
|
const decided = req.decided ?? Promise.resolve(true);
|
|
17144
|
-
const
|
|
17944
|
+
const count2 = (byParent) => {
|
|
17145
17945
|
this.identities.asked++;
|
|
17146
17946
|
if (!byParent) this.identities.timedOut++;
|
|
17147
17947
|
};
|
|
@@ -17149,7 +17949,7 @@ var Launcher = class {
|
|
|
17149
17949
|
const handle = spawnWasmProcess({
|
|
17150
17950
|
pid,
|
|
17151
17951
|
identity: async () => {
|
|
17152
|
-
await (asked ??= decided.then(
|
|
17952
|
+
await (asked ??= decided.then(count2));
|
|
17153
17953
|
return this.identityOf(pid);
|
|
17154
17954
|
},
|
|
17155
17955
|
onSyscall: (call) => {
|
|
@@ -17163,6 +17963,7 @@ var Launcher = class {
|
|
|
17163
17963
|
...this.owners && req.program.abi === "wasi" ? { fresh: (path, umask) => this.freshModules.add(path, umask, pid) } : {},
|
|
17164
17964
|
...this.owners ? { owners: true } : {},
|
|
17165
17965
|
sealed: this.sealed,
|
|
17966
|
+
...scrubs ? { ttyFilter: (file) => scrubbedAll(file, scrubs) } : {},
|
|
17166
17967
|
clipboard: this.clipboard,
|
|
17167
17968
|
...this.dac ? { dac: this.dac } : {},
|
|
17168
17969
|
program: req.program,
|
|
@@ -17229,6 +18030,7 @@ var Launcher = class {
|
|
|
17229
18030
|
if (spent) addTimes(this.imageTimes, this.jobs.shown(pid), spent);
|
|
17230
18031
|
this.stopped.delete(pid);
|
|
17231
18032
|
this.processes.delete(pid);
|
|
18033
|
+
this.scrubs.delete(pid);
|
|
17232
18034
|
if (this.processes.size === 0) {
|
|
17233
18035
|
clearInterval(this.sampler);
|
|
17234
18036
|
this.sampler = void 0;
|
|
@@ -17400,6 +18202,7 @@ var Launcher = class {
|
|
|
17400
18202
|
}
|
|
17401
18203
|
spawner(ppid, report) {
|
|
17402
18204
|
return async (req, fds, grant) => {
|
|
18205
|
+
const booked = this.takeTicket(req);
|
|
17403
18206
|
if (grant && !await this.grantedCwd(grant.caller, req.cwd)) {
|
|
17404
18207
|
await fds.closeAll();
|
|
17405
18208
|
throw new SpawnError("EACCES");
|
|
@@ -17411,23 +18214,20 @@ var Launcher = class {
|
|
|
17411
18214
|
}
|
|
17412
18215
|
const cred = grant ? grant.cred : this.credOf(ppid);
|
|
17413
18216
|
const scope = grant ? "" : await this.scopeOf(cred.euid);
|
|
17414
|
-
const
|
|
17415
|
-
|
|
17416
|
-
|
|
17417
|
-
|
|
17418
|
-
|
|
17419
|
-
|
|
17420
|
-
|
|
17421
|
-
|
|
17422
|
-
await fds.closeAll();
|
|
17423
|
-
throw new SpawnError(await this.unrunnable(req.file, req.cwd, scope));
|
|
17424
|
-
}
|
|
18217
|
+
const file = booked === void 0 ? req.file : await this.ticketFile(req, fds);
|
|
18218
|
+
const planned = await this.checkedPlan({ ...req, file }, { ppid, cred, scope }, fds);
|
|
18219
|
+
const redeemed = await this.redeemed(
|
|
18220
|
+
{ ...req, file },
|
|
18221
|
+
{ ppid, cred, scope, booked },
|
|
18222
|
+
planned,
|
|
18223
|
+
fds
|
|
18224
|
+
);
|
|
17425
18225
|
const exec = req.exec ? { exec: true } : {};
|
|
17426
18226
|
const deciding = req.exec ? void 0 : this.undecided(ppid);
|
|
17427
18227
|
const handle = await this.launch(planned, {
|
|
17428
18228
|
...deciding ? { decided: deciding.promise } : {},
|
|
17429
|
-
env: req.env,
|
|
17430
18229
|
cwd: req.cwd,
|
|
18230
|
+
...redeemed,
|
|
17431
18231
|
fds,
|
|
17432
18232
|
report,
|
|
17433
18233
|
ppid,
|
|
@@ -17480,11 +18280,11 @@ var Launcher = class {
|
|
|
17480
18280
|
if (!waiting) return;
|
|
17481
18281
|
this.deciding.delete(ppid);
|
|
17482
18282
|
setTimeout(() => {
|
|
17483
|
-
for (const
|
|
18283
|
+
for (const resolve2 of waiting) resolve2(true);
|
|
17484
18284
|
}, 0);
|
|
17485
18285
|
}
|
|
17486
18286
|
forker(ppid, parent) {
|
|
17487
|
-
const { exec: _exec, pgid: _pgid, group: _group, ...image } = parent;
|
|
18287
|
+
const { exec: _exec, pgid: _pgid, group: _group, pid: _pid, scrub: _scrub, ...image } = parent;
|
|
17488
18288
|
return async (state, fds) => childHandle(
|
|
17489
18289
|
this.start({
|
|
17490
18290
|
...image,
|
|
@@ -17518,7 +18318,7 @@ var Launcher = class {
|
|
|
17518
18318
|
}
|
|
17519
18319
|
}
|
|
17520
18320
|
umaskOf(pid) {
|
|
17521
|
-
return this.processes.get(pid)?.umask?.() ??
|
|
18321
|
+
return this.processes.get(pid)?.umask?.() ?? DEFAULT_UMASK2;
|
|
17522
18322
|
}
|
|
17523
18323
|
imageOf(pid) {
|
|
17524
18324
|
const members = this.jobs.list();
|
|
@@ -17861,7 +18661,14 @@ var Launcher = class {
|
|
|
17861
18661
|
);
|
|
17862
18662
|
}
|
|
17863
18663
|
environment(cwd, extra, account) {
|
|
17864
|
-
|
|
18664
|
+
const env = {
|
|
18665
|
+
...this.env,
|
|
18666
|
+
...userEnv(account, this.pnpmHome),
|
|
18667
|
+
PWD: cwd,
|
|
18668
|
+
...extra
|
|
18669
|
+
};
|
|
18670
|
+
delete env[TICKET_ENV];
|
|
18671
|
+
return env;
|
|
17865
18672
|
}
|
|
17866
18673
|
async account(user) {
|
|
17867
18674
|
if (typeof user === "object") return user;
|
|
@@ -17957,7 +18764,7 @@ var Launcher = class {
|
|
|
17957
18764
|
},
|
|
17958
18765
|
account
|
|
17959
18766
|
);
|
|
17960
|
-
const report = (message3) => options.onData(
|
|
18767
|
+
const report = (message3) => options.onData(encoder7.encode(`${message3}\r
|
|
17961
18768
|
`));
|
|
17962
18769
|
const handle = await this.launch(planned, {
|
|
17963
18770
|
env,
|
|
@@ -17988,18 +18795,18 @@ var Launcher = class {
|
|
|
17988
18795
|
const env = this.environment(cwd, options.env, account);
|
|
17989
18796
|
const out = [];
|
|
17990
18797
|
const err = [];
|
|
17991
|
-
const
|
|
18798
|
+
const keep2 = options.collect !== false;
|
|
17992
18799
|
const collect = (chunks, tee) => (bytes) => {
|
|
17993
|
-
if (
|
|
18800
|
+
if (keep2) chunks.push(bytes);
|
|
17994
18801
|
tee?.(bytes);
|
|
17995
18802
|
};
|
|
17996
18803
|
const stdout = collect(out, options.onStdout);
|
|
17997
18804
|
const stderr = collect(err, options.onStderr);
|
|
17998
|
-
const report = (message3) => stderr(
|
|
18805
|
+
const report = (message3) => stderr(encoder7.encode(`${message3}
|
|
17999
18806
|
`));
|
|
18000
18807
|
if (!planned) {
|
|
18001
18808
|
report(`${file}: command not found`);
|
|
18002
|
-
return { status: NOT_FOUND, stdout:
|
|
18809
|
+
return { status: NOT_FOUND, stdout: concat6(out), stderr: concat6(err) };
|
|
18003
18810
|
}
|
|
18004
18811
|
const fds = new FdTable();
|
|
18005
18812
|
fds.installAt(0, options.stdin ? bytesSource(options.stdin) : deviceFile("null"));
|
|
@@ -18017,7 +18824,7 @@ var Launcher = class {
|
|
|
18017
18824
|
options.onStarted?.(handle.pid);
|
|
18018
18825
|
const status = await handle.exited;
|
|
18019
18826
|
const signal = handle.termsig();
|
|
18020
|
-
return { status, ...signal ? { signal } : {}, stdout:
|
|
18827
|
+
return { status, ...signal ? { signal } : {}, stdout: concat6(out), stderr: concat6(err) };
|
|
18021
18828
|
}
|
|
18022
18829
|
};
|
|
18023
18830
|
|
|
@@ -18118,14 +18925,14 @@ function dial(l, req) {
|
|
|
18118
18925
|
function sudoApprovals(port) {
|
|
18119
18926
|
const waiting = /* @__PURE__ */ new Map();
|
|
18120
18927
|
return {
|
|
18121
|
-
ask: (req, { signal }) => new Promise((
|
|
18122
|
-
waiting.set(req.id,
|
|
18928
|
+
ask: (req, { signal }) => new Promise((resolve2) => {
|
|
18929
|
+
waiting.set(req.id, resolve2);
|
|
18123
18930
|
signal.addEventListener(
|
|
18124
18931
|
"abort",
|
|
18125
18932
|
() => {
|
|
18126
18933
|
waiting.delete(req.id);
|
|
18127
18934
|
port.postMessage({ sudoAbort: { id: req.id, reason: String(signal.reason) } });
|
|
18128
|
-
|
|
18935
|
+
resolve2("deny");
|
|
18129
18936
|
},
|
|
18130
18937
|
{ once: true }
|
|
18131
18938
|
);
|
|
@@ -18209,9 +19016,9 @@ function hostProtect(init, lookup) {
|
|
|
18209
19016
|
function policyAsker(port) {
|
|
18210
19017
|
const policies = /* @__PURE__ */ new Map();
|
|
18211
19018
|
let nextPolicy = 0;
|
|
18212
|
-
const askPolicy = (req) => new Promise((
|
|
19019
|
+
const askPolicy = (req) => new Promise((resolve2) => {
|
|
18213
19020
|
const id2 = ++nextPolicy;
|
|
18214
|
-
policies.set(id2,
|
|
19021
|
+
policies.set(id2, resolve2);
|
|
18215
19022
|
port.postMessage({ mountPolicy: { id: id2, req } });
|
|
18216
19023
|
});
|
|
18217
19024
|
return {
|
|
@@ -18239,10 +19046,10 @@ function serveKernel(port, deps) {
|
|
|
18239
19046
|
const locks = deps.locks === null ? void 0 : deps.locks ?? locksOf();
|
|
18240
19047
|
let holding;
|
|
18241
19048
|
function holdLock(locks2) {
|
|
18242
|
-
holding ??= new Promise((
|
|
19049
|
+
holding ??= new Promise((resolve2) => {
|
|
18243
19050
|
const name2 = `slicc-kernel:${crypto.randomUUID()}`;
|
|
18244
19051
|
void locks2.request(name2, () => {
|
|
18245
|
-
|
|
19052
|
+
resolve2(name2);
|
|
18246
19053
|
return new Promise(() => {
|
|
18247
19054
|
});
|
|
18248
19055
|
});
|