@ai-ecoverse/slicc-kernel 1.106.2 → 1.107.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 +19 -3
- package/dist/kernel-worker.js +1064 -446
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +43 -11
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +870 -246
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +43 -11
- package/dist/process-worker.js.map +3 -3
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +2 -2
- package/dist/types/cron/schedule.d.ts +25 -0
- package/dist/types/cron/service.d.ts +68 -0
- package/dist/types/cron/table.d.ts +23 -0
- package/dist/types/launcher.d.ts +11 -0
- package/dist/types/node.d.ts +4 -0
- package/dist/types/process/js/js-kernel.d.ts +2 -1
- package/package.json +1 -1
package/dist/node.js
CHANGED
|
@@ -699,12 +699,12 @@ function userCred(uid, gid, groups = [gid]) {
|
|
|
699
699
|
function copyCred(cred) {
|
|
700
700
|
return { ...cred, groups: [...cred.groups] };
|
|
701
701
|
}
|
|
702
|
-
function id(
|
|
703
|
-
if (
|
|
704
|
-
if (!Number.isInteger(
|
|
705
|
-
throw fsError("EINVAL", `not a user or group id: ${String(
|
|
702
|
+
function id(value2) {
|
|
703
|
+
if (value2 === void 0 || value2 === -1 || value2 === 4294967295) return void 0;
|
|
704
|
+
if (!Number.isInteger(value2) || value2 < 0 || value2 > MAX_ID) {
|
|
705
|
+
throw fsError("EINVAL", `not a user or group id: ${String(value2)}`);
|
|
706
706
|
}
|
|
707
|
-
return
|
|
707
|
+
return value2;
|
|
708
708
|
}
|
|
709
709
|
function changeCred(cur, change) {
|
|
710
710
|
if (typeof change !== "object" || change === null || Array.isArray(change)) {
|
|
@@ -715,10 +715,10 @@ function changeCred(cur, change) {
|
|
|
715
715
|
for (const keys of [UIDS, GIDS]) {
|
|
716
716
|
const own = keys.map((key) => cur[key]);
|
|
717
717
|
for (const key of keys) {
|
|
718
|
-
const
|
|
719
|
-
if (
|
|
720
|
-
if (!privileged && !own.includes(
|
|
721
|
-
next3[key] =
|
|
718
|
+
const value2 = id(change[key]);
|
|
719
|
+
if (value2 === void 0) continue;
|
|
720
|
+
if (!privileged && !own.includes(value2)) throw fsError("EPERM", `${key} ${value2}`);
|
|
721
|
+
next3[key] = value2;
|
|
722
722
|
}
|
|
723
723
|
}
|
|
724
724
|
if (change.groups !== void 0) {
|
|
@@ -1329,11 +1329,11 @@ function ipv6Groups(text) {
|
|
|
1329
1329
|
} catch {
|
|
1330
1330
|
return void 0;
|
|
1331
1331
|
}
|
|
1332
|
-
const [head,
|
|
1332
|
+
const [head, tail2] = canonical.split("::");
|
|
1333
1333
|
const part = (s) => s ? s.split(":").map((h) => Number.parseInt(h, 16)) : [];
|
|
1334
1334
|
const front = part(head);
|
|
1335
|
-
const back = part(
|
|
1336
|
-
return
|
|
1335
|
+
const back = part(tail2);
|
|
1336
|
+
return tail2 === void 0 ? front : [...front, ...new Array(8 - front.length - back.length).fill(0), ...back];
|
|
1337
1337
|
}
|
|
1338
1338
|
function toBits(values, width) {
|
|
1339
1339
|
return values.reduce((acc, v) => acc << BigInt(width) | BigInt(v), 0n);
|
|
@@ -1815,8 +1815,8 @@ var KernelSocket = class _KernelSocket {
|
|
|
1815
1815
|
}
|
|
1816
1816
|
return this.options.get(`${level}:${name2}`) ?? 0;
|
|
1817
1817
|
}
|
|
1818
|
-
setOption(level, name2,
|
|
1819
|
-
this.options.set(`${level}:${name2}`,
|
|
1818
|
+
setOption(level, name2, value2) {
|
|
1819
|
+
this.options.set(`${level}:${name2}`, value2);
|
|
1820
1820
|
}
|
|
1821
1821
|
close() {
|
|
1822
1822
|
const was = this.state;
|
|
@@ -2214,8 +2214,8 @@ var SENT_HEADERS_DROP = /* @__PURE__ */ new Set([
|
|
|
2214
2214
|
]);
|
|
2215
2215
|
function headerRecord(headers) {
|
|
2216
2216
|
const out = {};
|
|
2217
|
-
for (const [name2,
|
|
2218
|
-
if (!SENT_HEADERS_DROP.has(name2.toLowerCase())) out[name2] =
|
|
2217
|
+
for (const [name2, value2] of headers) {
|
|
2218
|
+
if (!SENT_HEADERS_DROP.has(name2.toLowerCase())) out[name2] = value2;
|
|
2219
2219
|
}
|
|
2220
2220
|
return out;
|
|
2221
2221
|
}
|
|
@@ -2306,9 +2306,9 @@ var NO_WEBSOCKET = "WebSocket not supported by this transport (fetchTransport ne
|
|
|
2306
2306
|
var MAX_REQUEST_BODY = 64 * 1024 * 1024;
|
|
2307
2307
|
function joinHeaders(headers) {
|
|
2308
2308
|
const out = new Headers();
|
|
2309
|
-
for (const [name2,
|
|
2309
|
+
for (const [name2, value2] of headers) {
|
|
2310
2310
|
try {
|
|
2311
|
-
out.append(name2,
|
|
2311
|
+
out.append(name2, value2);
|
|
2312
2312
|
} catch {
|
|
2313
2313
|
}
|
|
2314
2314
|
}
|
|
@@ -2387,8 +2387,8 @@ function fetchTransport(options = {}) {
|
|
|
2387
2387
|
);
|
|
2388
2388
|
}
|
|
2389
2389
|
const headers2 = [];
|
|
2390
|
-
response.headers.forEach((
|
|
2391
|
-
headers2.push([name2,
|
|
2390
|
+
response.headers.forEach((value2, name2) => {
|
|
2391
|
+
headers2.push([name2, value2]);
|
|
2392
2392
|
});
|
|
2393
2393
|
const body = chunks(response.body, options.bodyIdleMs ?? BODY_IDLE_MS);
|
|
2394
2394
|
return {
|
|
@@ -3449,9 +3449,9 @@ var PathMap = class {
|
|
|
3449
3449
|
keys() {
|
|
3450
3450
|
return this.values.keys();
|
|
3451
3451
|
}
|
|
3452
|
-
set(path,
|
|
3452
|
+
set(path, value2) {
|
|
3453
3453
|
if (!this.values.has(path)) this.link(path);
|
|
3454
|
-
this.values.set(path,
|
|
3454
|
+
this.values.set(path, value2);
|
|
3455
3455
|
return this;
|
|
3456
3456
|
}
|
|
3457
3457
|
delete(path) {
|
|
@@ -3933,8 +3933,8 @@ var ProtectedFs = class {
|
|
|
3933
3933
|
for (let at = fs; at && at !== Object.prototype; at = Object.getPrototypeOf(at)) {
|
|
3934
3934
|
for (const name2 of Object.getOwnPropertyNames(at)) {
|
|
3935
3935
|
if (name2 === "constructor" || Object.hasOwn(view2, name2)) continue;
|
|
3936
|
-
const
|
|
3937
|
-
view2[name2] = typeof
|
|
3936
|
+
const value2 = fs[name2];
|
|
3937
|
+
view2[name2] = typeof value2 === "function" ? value2.bind(fs) : value2;
|
|
3938
3938
|
}
|
|
3939
3939
|
}
|
|
3940
3940
|
return Object.assign(view2, own);
|
|
@@ -4064,8 +4064,8 @@ function view(target, overrides) {
|
|
|
4064
4064
|
if (keys.has(prop)) return overrides[prop];
|
|
4065
4065
|
return Reflect.get(t, prop, receiver);
|
|
4066
4066
|
},
|
|
4067
|
-
set(t, prop,
|
|
4068
|
-
return Reflect.set(t, prop,
|
|
4067
|
+
set(t, prop, value2) {
|
|
4068
|
+
return Reflect.set(t, prop, value2);
|
|
4069
4069
|
},
|
|
4070
4070
|
getPrototypeOf(t) {
|
|
4071
4071
|
return Reflect.getPrototypeOf(t);
|
|
@@ -5273,12 +5273,12 @@ var PathGate = class {
|
|
|
5273
5273
|
async acquire(path) {
|
|
5274
5274
|
const prev = this.tails.get(path) ?? Promise.resolve();
|
|
5275
5275
|
const { promise, resolve: resolve2 } = Promise.withResolvers();
|
|
5276
|
-
const
|
|
5277
|
-
this.tails.set(path,
|
|
5276
|
+
const tail2 = prev.then(() => promise);
|
|
5277
|
+
this.tails.set(path, tail2);
|
|
5278
5278
|
await prev;
|
|
5279
5279
|
return () => {
|
|
5280
5280
|
resolve2();
|
|
5281
|
-
if (this.tails.get(path) ===
|
|
5281
|
+
if (this.tails.get(path) === tail2) this.tails.delete(path);
|
|
5282
5282
|
};
|
|
5283
5283
|
}
|
|
5284
5284
|
async run(path, op) {
|
|
@@ -5726,15 +5726,15 @@ function concat(chunks2, total = chunks2.reduce((n, c) => n + c.length, 0)) {
|
|
|
5726
5726
|
}
|
|
5727
5727
|
return out;
|
|
5728
5728
|
}
|
|
5729
|
-
function safeValue(
|
|
5730
|
-
return !/[\r\n\0]/.test(
|
|
5729
|
+
function safeValue(value2) {
|
|
5730
|
+
return !/[\r\n\0]/.test(value2);
|
|
5731
5731
|
}
|
|
5732
5732
|
function responseHead(status, reason, headers) {
|
|
5733
5733
|
const phrase = /^[\t\x20-\x7e\x80-\xff]*$/.test(reason) ? reason : "";
|
|
5734
5734
|
let head = `HTTP/1.1 ${status} ${phrase}\r
|
|
5735
5735
|
`;
|
|
5736
|
-
for (const [name2,
|
|
5737
|
-
if (TOKEN.test(name2) && safeValue(
|
|
5736
|
+
for (const [name2, value2] of headers) {
|
|
5737
|
+
if (TOKEN.test(name2) && safeValue(value2)) head += `${name2}: ${value2}\r
|
|
5738
5738
|
`;
|
|
5739
5739
|
}
|
|
5740
5740
|
return latin1Bytes(`${head}\r
|
|
@@ -6006,8 +6006,8 @@ Connection: close\r
|
|
|
6006
6006
|
out.set(bytes, head.length);
|
|
6007
6007
|
return out;
|
|
6008
6008
|
}
|
|
6009
|
-
function json(
|
|
6010
|
-
return respond(200, `${JSON.stringify(
|
|
6009
|
+
function json(value2) {
|
|
6010
|
+
return respond(200, `${JSON.stringify(value2, null, 2)}
|
|
6011
6011
|
`, "application/json; charset=UTF-8");
|
|
6012
6012
|
}
|
|
6013
6013
|
var CdpFacade = class {
|
|
@@ -6405,9 +6405,9 @@ function comparator(token) {
|
|
|
6405
6405
|
function set(text) {
|
|
6406
6406
|
const trimmed = text.trim().replace(/(<=|>=|<|>|=|\^|~>?)\s+/g, "$1");
|
|
6407
6407
|
if (trimmed === "") return ANY;
|
|
6408
|
-
const
|
|
6409
|
-
if (
|
|
6410
|
-
const [from, to] = [partial(
|
|
6408
|
+
const range2 = /^(\S+)\s+-\s+(\S+)$/.exec(trimmed);
|
|
6409
|
+
if (range2) {
|
|
6410
|
+
const [from, to] = [partial(range2[1]), partial(range2[2])];
|
|
6411
6411
|
return from && to ? hyphen(from, to) : void 0;
|
|
6412
6412
|
}
|
|
6413
6413
|
const out = [];
|
|
@@ -6426,16 +6426,16 @@ function holds(v, [op, w]) {
|
|
|
6426
6426
|
if (op === ">=") return c >= 0;
|
|
6427
6427
|
return c === 0;
|
|
6428
6428
|
}
|
|
6429
|
-
function satisfies(version,
|
|
6429
|
+
function satisfies(version, range2) {
|
|
6430
6430
|
const v = parseVersion(version);
|
|
6431
6431
|
if (!v) return void 0;
|
|
6432
|
-
const sets =
|
|
6432
|
+
const sets = range2.split("||").map(set);
|
|
6433
6433
|
if (sets.some((s) => s === void 0)) return void 0;
|
|
6434
6434
|
return sets.some((s) => s.every((c) => holds(v, c)));
|
|
6435
6435
|
}
|
|
6436
6436
|
|
|
6437
6437
|
// src/version.ts
|
|
6438
|
-
var KERNEL_VERSION = true ? "1.
|
|
6438
|
+
var KERNEL_VERSION = true ? "1.107.0" : "0.0.0-dev";
|
|
6439
6439
|
var OS_RELEASE = "6.0.0-slicc";
|
|
6440
6440
|
function procVersion() {
|
|
6441
6441
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -6459,19 +6459,19 @@ function inside(pkg, rel2) {
|
|
|
6459
6459
|
function envOf(pkg, raw) {
|
|
6460
6460
|
const env = {};
|
|
6461
6461
|
if (!raw || typeof raw !== "object") return env;
|
|
6462
|
-
for (const [key,
|
|
6462
|
+
for (const [key, value2] of Object.entries(raw)) {
|
|
6463
6463
|
if (!ENV_KEY.test(key)) continue;
|
|
6464
|
-
if (typeof
|
|
6465
|
-
else if (
|
|
6464
|
+
if (typeof value2 === "string") env[key] = value2.replace(PACKAGE, pkg);
|
|
6465
|
+
else if (value2 === null) env[key] = null;
|
|
6466
6466
|
}
|
|
6467
6467
|
return env;
|
|
6468
6468
|
}
|
|
6469
6469
|
function envFields(merged2) {
|
|
6470
6470
|
const env = {};
|
|
6471
6471
|
const unset = [];
|
|
6472
|
-
for (const [key,
|
|
6473
|
-
if (
|
|
6474
|
-
else env[key] =
|
|
6472
|
+
for (const [key, value2] of Object.entries(merged2)) {
|
|
6473
|
+
if (value2 === null) unset.push(key);
|
|
6474
|
+
else env[key] = value2;
|
|
6475
6475
|
}
|
|
6476
6476
|
return {
|
|
6477
6477
|
...Object.keys(env).length > 0 ? { env } : {},
|
|
@@ -6550,9 +6550,9 @@ function commandsOf(pkg, manifest) {
|
|
|
6550
6550
|
async function withPackagePaths(fs, pkg, command) {
|
|
6551
6551
|
if (!command.env) return command;
|
|
6552
6552
|
const env = {};
|
|
6553
|
-
for (const [key,
|
|
6554
|
-
const path = !
|
|
6555
|
-
env[key] = path && await fs.exists(path) ? path :
|
|
6553
|
+
for (const [key, value2] of Object.entries(command.env)) {
|
|
6554
|
+
const path = !value2.startsWith("/") && value2.includes("/") && inside(pkg, value2);
|
|
6555
|
+
env[key] = path && await fs.exists(path) ? path : value2;
|
|
6556
6556
|
}
|
|
6557
6557
|
return { ...command, env };
|
|
6558
6558
|
}
|
|
@@ -6603,7 +6603,7 @@ function physicalResolver(fs) {
|
|
|
6603
6603
|
const known = /* @__PURE__ */ new Map();
|
|
6604
6604
|
const pending = /* @__PURE__ */ new Set();
|
|
6605
6605
|
let hops = 0;
|
|
6606
|
-
const
|
|
6606
|
+
const step2 = async (path) => {
|
|
6607
6607
|
if (path === "/") return { path, file: false };
|
|
6608
6608
|
const slash = path.lastIndexOf("/");
|
|
6609
6609
|
const parent = await resolve2(path.slice(0, slash) || "/");
|
|
@@ -6620,7 +6620,7 @@ function physicalResolver(fs) {
|
|
|
6620
6620
|
let found = known.get(path);
|
|
6621
6621
|
if (!found) {
|
|
6622
6622
|
pending.add(path);
|
|
6623
|
-
found =
|
|
6623
|
+
found = step2(path).finally(() => pending.delete(path));
|
|
6624
6624
|
known.set(path, found);
|
|
6625
6625
|
}
|
|
6626
6626
|
return found;
|
|
@@ -6655,15 +6655,15 @@ async function binCommandsOf(physical, pkg, manifest, taken) {
|
|
|
6655
6655
|
}
|
|
6656
6656
|
function engineRefusal(manifest, kernel) {
|
|
6657
6657
|
const engines = manifest.engines;
|
|
6658
|
-
const
|
|
6658
|
+
const range2 = engines && typeof engines === "object" ? engines["slicc-kernel"] : void 0;
|
|
6659
6659
|
const running = parseVersion(kernel);
|
|
6660
|
-
if (typeof
|
|
6660
|
+
if (typeof range2 !== "string" || !running || running.slice(0, 3).every((n) => n === 0)) {
|
|
6661
6661
|
return void 0;
|
|
6662
6662
|
}
|
|
6663
|
-
const fits = satisfies(kernel,
|
|
6663
|
+
const fits = satisfies(kernel, range2);
|
|
6664
6664
|
if (fits) return void 0;
|
|
6665
6665
|
const who = `${String(manifest.name ?? "?")}@${String(manifest.version ?? "?")}`;
|
|
6666
|
-
return fits === false ? `${who} needs slicc-kernel ${
|
|
6666
|
+
return fits === false ? `${who} needs slicc-kernel ${range2}; this kernel is ${kernel}` : `${who} has an engines.slicc-kernel range this kernel can't read: ${JSON.stringify(range2)}`;
|
|
6667
6667
|
}
|
|
6668
6668
|
var PACKAGE_NAME = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
|
|
6669
6669
|
function replacesOf(manifest) {
|
|
@@ -6794,6 +6794,573 @@ function binfmtOf(binfmts, path) {
|
|
|
6794
6794
|
return best === void 0 ? void 0 : binfmts.get(best);
|
|
6795
6795
|
}
|
|
6796
6796
|
|
|
6797
|
+
// src/cron/clock.ts
|
|
6798
|
+
var systemCronClock = {
|
|
6799
|
+
now: () => Date.now(),
|
|
6800
|
+
sleep(until, signal) {
|
|
6801
|
+
if (signal.aborted) return Promise.resolve();
|
|
6802
|
+
return new Promise((resolve2) => {
|
|
6803
|
+
const done4 = () => {
|
|
6804
|
+
clearTimeout(timer);
|
|
6805
|
+
signal.removeEventListener("abort", done4);
|
|
6806
|
+
resolve2();
|
|
6807
|
+
};
|
|
6808
|
+
const timer = setTimeout(done4, Math.max(0, until - Date.now()));
|
|
6809
|
+
timer.unref?.();
|
|
6810
|
+
signal.addEventListener("abort", done4, { once: true });
|
|
6811
|
+
});
|
|
6812
|
+
}
|
|
6813
|
+
};
|
|
6814
|
+
|
|
6815
|
+
// src/cron/schedule.ts
|
|
6816
|
+
var MISSED_CAP = 1e5;
|
|
6817
|
+
var MACROS = {
|
|
6818
|
+
"@yearly": "0 0 1 1 *",
|
|
6819
|
+
"@annually": "0 0 1 1 *",
|
|
6820
|
+
"@monthly": "0 0 1 * *",
|
|
6821
|
+
"@weekly": "0 0 * * 0",
|
|
6822
|
+
"@daily": "0 0 * * *",
|
|
6823
|
+
"@midnight": "0 0 * * *",
|
|
6824
|
+
"@hourly": "0 * * * *"
|
|
6825
|
+
};
|
|
6826
|
+
var MONTHS = ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"];
|
|
6827
|
+
var WEEKDAYS = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
|
|
6828
|
+
var FIELDS = [
|
|
6829
|
+
{ name: "minute", min: 0, max: 59 },
|
|
6830
|
+
{ name: "hour", min: 0, max: 23 },
|
|
6831
|
+
{ name: "day of month", min: 1, max: 31 },
|
|
6832
|
+
{ name: "month", min: 1, max: 12, names: MONTHS, offset: 1 },
|
|
6833
|
+
{ name: "day of week", min: 0, max: 7, names: WEEKDAYS }
|
|
6834
|
+
];
|
|
6835
|
+
function value(text, field4) {
|
|
6836
|
+
const named = field4.names?.indexOf(text.toLowerCase()) ?? -1;
|
|
6837
|
+
if (named >= 0) return named + (field4.offset ?? 0);
|
|
6838
|
+
if (!/^\d+$/.test(text)) throw new Error(`${field4.name}: "${text}" is not a number`);
|
|
6839
|
+
const number = Number(text);
|
|
6840
|
+
if (number < field4.min || number > field4.max)
|
|
6841
|
+
throw new Error(`${field4.name}: ${number} is outside ${field4.min}-${field4.max}`);
|
|
6842
|
+
return number;
|
|
6843
|
+
}
|
|
6844
|
+
function range(part, field4) {
|
|
6845
|
+
if (part === "*") return [field4.min, field4.max];
|
|
6846
|
+
const [from, to, extra] = part.split("-");
|
|
6847
|
+
if (extra !== void 0) throw new Error(`${field4.name}: "${part}" is not a range`);
|
|
6848
|
+
const start2 = value(from, field4);
|
|
6849
|
+
const end = to === void 0 ? start2 : value(to, field4);
|
|
6850
|
+
if (end < start2) throw new Error(`${field4.name}: range ${part} runs backwards`);
|
|
6851
|
+
return [start2, end];
|
|
6852
|
+
}
|
|
6853
|
+
function step(text, field4) {
|
|
6854
|
+
if (text === void 0) return 1;
|
|
6855
|
+
if (!/^\d+$/.test(text) || Number(text) === 0)
|
|
6856
|
+
throw new Error(`${field4.name}: step "${text}" must be a positive number`);
|
|
6857
|
+
return Number(text);
|
|
6858
|
+
}
|
|
6859
|
+
function field2(text, spec) {
|
|
6860
|
+
const out = /* @__PURE__ */ new Set();
|
|
6861
|
+
for (const part of text.split(",")) {
|
|
6862
|
+
if (part === "") throw new Error(`${spec.name}: empty list item`);
|
|
6863
|
+
const [base, every, extra] = part.split("/");
|
|
6864
|
+
if (extra !== void 0) throw new Error(`${spec.name}: "${part}" has two steps`);
|
|
6865
|
+
const [start2, end] = range(base, spec);
|
|
6866
|
+
const stride = step(every, spec);
|
|
6867
|
+
const last = every !== void 0 && !base.includes("-") ? spec.max : end;
|
|
6868
|
+
for (let n = start2; n <= last; n += stride) out.add(n);
|
|
6869
|
+
}
|
|
6870
|
+
return out;
|
|
6871
|
+
}
|
|
6872
|
+
function parseSchedule(expression) {
|
|
6873
|
+
const trimmed = expression.trim();
|
|
6874
|
+
const text = MACROS[trimmed.toLowerCase()] ?? trimmed;
|
|
6875
|
+
if (text.startsWith("@")) throw new Error(`unknown schedule ${trimmed}`);
|
|
6876
|
+
const parts2 = text.split(/\s+/);
|
|
6877
|
+
if (parts2.length !== 5)
|
|
6878
|
+
throw new Error(
|
|
6879
|
+
`"${trimmed}" needs 5 fields (minute hour day month weekday), not ${parts2.length}`
|
|
6880
|
+
);
|
|
6881
|
+
const [minutes, hours, days, months, weekdays] = parts2.map(
|
|
6882
|
+
(part, at) => field2(part, FIELDS[at])
|
|
6883
|
+
);
|
|
6884
|
+
if (weekdays.delete(7)) weekdays.add(0);
|
|
6885
|
+
return {
|
|
6886
|
+
minutes,
|
|
6887
|
+
hours,
|
|
6888
|
+
days,
|
|
6889
|
+
months,
|
|
6890
|
+
weekdays,
|
|
6891
|
+
anyDay: parts2[2].startsWith("*"),
|
|
6892
|
+
anyWeekday: parts2[4].startsWith("*")
|
|
6893
|
+
};
|
|
6894
|
+
}
|
|
6895
|
+
function parseWhen(expression) {
|
|
6896
|
+
if (expression.trim().toLowerCase() === "@reboot") return { reboot: true };
|
|
6897
|
+
return { reboot: false, schedule: parseSchedule(expression) };
|
|
6898
|
+
}
|
|
6899
|
+
var LOCAL = {
|
|
6900
|
+
year: (d) => d.getFullYear(),
|
|
6901
|
+
month: (d) => d.getMonth(),
|
|
6902
|
+
date: (d) => d.getDate(),
|
|
6903
|
+
day: (d) => d.getDay(),
|
|
6904
|
+
hours: (d) => d.getHours(),
|
|
6905
|
+
minutes: (d) => d.getMinutes(),
|
|
6906
|
+
setMonth: (d, month) => d.setMonth(month, 1),
|
|
6907
|
+
setDate: (d, date) => d.setDate(date),
|
|
6908
|
+
setHours: (d, hours) => d.setHours(hours, 0, 0, 0),
|
|
6909
|
+
setMinutes: (d, minutes) => d.setMinutes(minutes, 0, 0)
|
|
6910
|
+
};
|
|
6911
|
+
var UTC = {
|
|
6912
|
+
year: (d) => d.getUTCFullYear(),
|
|
6913
|
+
month: (d) => d.getUTCMonth(),
|
|
6914
|
+
date: (d) => d.getUTCDate(),
|
|
6915
|
+
day: (d) => d.getUTCDay(),
|
|
6916
|
+
hours: (d) => d.getUTCHours(),
|
|
6917
|
+
minutes: (d) => d.getUTCMinutes(),
|
|
6918
|
+
setMonth: (d, month) => d.setUTCMonth(month, 1),
|
|
6919
|
+
setDate: (d, date) => d.setUTCDate(date),
|
|
6920
|
+
setHours: (d, hours) => d.setUTCHours(hours, 0, 0, 0),
|
|
6921
|
+
setMinutes: (d, minutes) => d.setUTCMinutes(minutes, 0, 0)
|
|
6922
|
+
};
|
|
6923
|
+
function dayMatches(schedule, cal, date) {
|
|
6924
|
+
const day = schedule.days.has(cal.date(date));
|
|
6925
|
+
const weekday = schedule.weekdays.has(cal.day(date));
|
|
6926
|
+
if (schedule.anyDay || schedule.anyWeekday) return day && weekday;
|
|
6927
|
+
return day || weekday;
|
|
6928
|
+
}
|
|
6929
|
+
var LIMIT_YEARS = 8;
|
|
6930
|
+
function nextFire(schedule, after, utc = false) {
|
|
6931
|
+
const cal = utc ? UTC : LOCAL;
|
|
6932
|
+
const date = new Date(Math.floor(after / 6e4) * 6e4 + 6e4);
|
|
6933
|
+
const limit = cal.year(date) + LIMIT_YEARS;
|
|
6934
|
+
while (cal.year(date) <= limit) {
|
|
6935
|
+
if (!schedule.months.has(cal.month(date) + 1)) {
|
|
6936
|
+
cal.setMonth(date, cal.month(date) + 1);
|
|
6937
|
+
cal.setHours(date, 0);
|
|
6938
|
+
} else if (!dayMatches(schedule, cal, date)) {
|
|
6939
|
+
cal.setDate(date, cal.date(date) + 1);
|
|
6940
|
+
cal.setHours(date, 0);
|
|
6941
|
+
} else if (!schedule.hours.has(cal.hours(date))) {
|
|
6942
|
+
cal.setHours(date, cal.hours(date) + 1);
|
|
6943
|
+
} else if (!schedule.minutes.has(cal.minutes(date))) {
|
|
6944
|
+
cal.setMinutes(date, cal.minutes(date) + 1);
|
|
6945
|
+
} else return date.getTime();
|
|
6946
|
+
}
|
|
6947
|
+
return null;
|
|
6948
|
+
}
|
|
6949
|
+
function missedFires(schedule, from, until, utc = false, cap = MISSED_CAP) {
|
|
6950
|
+
let count2 = 0;
|
|
6951
|
+
let last = null;
|
|
6952
|
+
let at = from;
|
|
6953
|
+
while (count2 < cap) {
|
|
6954
|
+
at = nextFire(schedule, at, utc);
|
|
6955
|
+
if (at === null || at > until) return { count: count2, last, more: false };
|
|
6956
|
+
last = at;
|
|
6957
|
+
count2++;
|
|
6958
|
+
}
|
|
6959
|
+
const next3 = nextFire(schedule, last, utc);
|
|
6960
|
+
return { count: count2, last, more: next3 !== null && next3 <= until };
|
|
6961
|
+
}
|
|
6962
|
+
|
|
6963
|
+
// src/cron/table.ts
|
|
6964
|
+
var SYSTEM_CRONTAB = "/etc/crontab";
|
|
6965
|
+
var SPOOL_DIR = "/var/spool/cron/crontabs";
|
|
6966
|
+
var ENV_LINE = /^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/;
|
|
6967
|
+
var NAME_LINE = /^#\s*name:\s*(.*?)\s*$/;
|
|
6968
|
+
var JOB_NAME = /^[A-Za-z0-9_][A-Za-z0-9_.-]*$/;
|
|
6969
|
+
var USER_NAME = /^[a-z_][a-z0-9_.-]*$/;
|
|
6970
|
+
function unquote(text) {
|
|
6971
|
+
const trimmed = text.trim();
|
|
6972
|
+
const quote = trimmed[0];
|
|
6973
|
+
if ((quote === '"' || quote === "'") && trimmed.length > 1 && trimmed.endsWith(quote))
|
|
6974
|
+
return trimmed.slice(1, -1);
|
|
6975
|
+
return trimmed;
|
|
6976
|
+
}
|
|
6977
|
+
function hashId(text) {
|
|
6978
|
+
let a = 2166136261;
|
|
6979
|
+
let b = 16777619;
|
|
6980
|
+
for (let i = 0; i < text.length; i++) {
|
|
6981
|
+
const c = text.charCodeAt(i);
|
|
6982
|
+
a = Math.imul(a ^ c, 16777619);
|
|
6983
|
+
b = Math.imul(b ^ c, 1540483477);
|
|
6984
|
+
}
|
|
6985
|
+
const hex3 = (n) => (n >>> 0).toString(16).padStart(8, "0");
|
|
6986
|
+
return hex3(a) + hex3(b);
|
|
6987
|
+
}
|
|
6988
|
+
function split2(text, count2) {
|
|
6989
|
+
const words2 = [];
|
|
6990
|
+
let rest2 = text;
|
|
6991
|
+
for (let i = 0; i < count2; i++) {
|
|
6992
|
+
const match = /^(\S+)\s+/.exec(rest2);
|
|
6993
|
+
if (!match) return void 0;
|
|
6994
|
+
words2.push(match[1]);
|
|
6995
|
+
rest2 = rest2.slice(match[0].length);
|
|
6996
|
+
}
|
|
6997
|
+
return [words2, rest2.trim()];
|
|
6998
|
+
}
|
|
6999
|
+
function jobOf(content, pending, ctx) {
|
|
7000
|
+
const fields = content.startsWith("@") ? 1 : 5;
|
|
7001
|
+
const parts2 = split2(content, fields + (ctx.system ? 1 : 0));
|
|
7002
|
+
if (!parts2 || parts2[1] === "") throw new Error("no command");
|
|
7003
|
+
const [words2, command] = parts2;
|
|
7004
|
+
const schedule = words2.slice(0, fields).join(" ");
|
|
7005
|
+
const when = parseWhen(schedule);
|
|
7006
|
+
const user = ctx.system ? words2[fields] : void 0;
|
|
7007
|
+
if (user !== void 0 && !USER_NAME.test(user)) throw new Error(`bad user name ${user}`);
|
|
7008
|
+
if (pending !== void 0 && !JOB_NAME.test(pending))
|
|
7009
|
+
throw new Error(`bad job name "${pending}"`);
|
|
7010
|
+
if (pending !== void 0 && ctx.names.has(pending))
|
|
7011
|
+
throw new Error(`job name ${pending} is taken`);
|
|
7012
|
+
const hashed = hashId(`${ctx.path}
|
|
7013
|
+
${user ?? ""}
|
|
7014
|
+
${schedule}
|
|
7015
|
+
${command}`);
|
|
7016
|
+
let id2 = pending ?? hashed;
|
|
7017
|
+
for (let n = 2; pending === void 0 && ctx.names.has(id2); n++) id2 = `${hashed}.${n}`;
|
|
7018
|
+
ctx.names.add(id2);
|
|
7019
|
+
return {
|
|
7020
|
+
id: id2,
|
|
7021
|
+
...pending !== void 0 ? { name: pending } : {},
|
|
7022
|
+
schedule,
|
|
7023
|
+
when,
|
|
7024
|
+
...user !== void 0 ? { user } : {},
|
|
7025
|
+
command
|
|
7026
|
+
};
|
|
7027
|
+
}
|
|
7028
|
+
function parseCrontab(text, path, system = false) {
|
|
7029
|
+
const jobs = [];
|
|
7030
|
+
const errors = [];
|
|
7031
|
+
const env = {};
|
|
7032
|
+
const ctx = { path, system, names: /* @__PURE__ */ new Set() };
|
|
7033
|
+
let name2;
|
|
7034
|
+
for (const [index, raw] of text.split("\n").entries()) {
|
|
7035
|
+
const line = index + 1;
|
|
7036
|
+
const content = raw.trim();
|
|
7037
|
+
const named = NAME_LINE.exec(content);
|
|
7038
|
+
if (named) {
|
|
7039
|
+
name2 = named[1];
|
|
7040
|
+
continue;
|
|
7041
|
+
}
|
|
7042
|
+
const pending = name2;
|
|
7043
|
+
name2 = void 0;
|
|
7044
|
+
if (content === "" || content.startsWith("#")) continue;
|
|
7045
|
+
const assign = ENV_LINE.exec(content);
|
|
7046
|
+
if (assign) {
|
|
7047
|
+
env[assign[1]] = unquote(assign[2]);
|
|
7048
|
+
continue;
|
|
7049
|
+
}
|
|
7050
|
+
try {
|
|
7051
|
+
jobs.push({ line, ...jobOf(content, pending, ctx), env: { ...env } });
|
|
7052
|
+
} catch (err) {
|
|
7053
|
+
errors.push({ line, message: err.message });
|
|
7054
|
+
}
|
|
7055
|
+
}
|
|
7056
|
+
return { jobs, errors };
|
|
7057
|
+
}
|
|
7058
|
+
|
|
7059
|
+
// src/cron/service.ts
|
|
7060
|
+
var CRON_DIR = "/var/spool/cron";
|
|
7061
|
+
var STAMP_PATH = `${CRON_DIR}/stamp`;
|
|
7062
|
+
var LOG_DIR = "/var/log/cron";
|
|
7063
|
+
var ERR_LOG = `${LOG_DIR}/cron.err`;
|
|
7064
|
+
var LOG_CAP = 256 * 1024;
|
|
7065
|
+
var JOBS_PER_USER = 16;
|
|
7066
|
+
var WAKE_MS = 6e4;
|
|
7067
|
+
var BACK_JUMP_MS = 12e4;
|
|
7068
|
+
var DEFAULT_SHELL = "/bin/bash";
|
|
7069
|
+
var encoder = new TextEncoder();
|
|
7070
|
+
var EMPTY_STAMP = JSON.stringify({ jobs: {}, reboot: {} });
|
|
7071
|
+
var messageOf = (err) => err?.message ?? String(err);
|
|
7072
|
+
var keyOf2 = ({ source, job }) => `${source} ${job.id}`;
|
|
7073
|
+
function tail(bytes, cap = LOG_CAP) {
|
|
7074
|
+
return bytes.length > cap ? bytes.slice(bytes.length - cap) : bytes;
|
|
7075
|
+
}
|
|
7076
|
+
function concat2(parts2) {
|
|
7077
|
+
const out = new Uint8Array(parts2.reduce((n, part) => n + part.length, 0));
|
|
7078
|
+
let at = 0;
|
|
7079
|
+
for (const part of parts2) {
|
|
7080
|
+
out.set(part, at);
|
|
7081
|
+
at += part.length;
|
|
7082
|
+
}
|
|
7083
|
+
return out;
|
|
7084
|
+
}
|
|
7085
|
+
var Output = class {
|
|
7086
|
+
parts = [];
|
|
7087
|
+
size = 0;
|
|
7088
|
+
push(bytes) {
|
|
7089
|
+
this.parts.push(bytes.slice());
|
|
7090
|
+
this.size += bytes.length;
|
|
7091
|
+
if (this.size > LOG_CAP * 2) {
|
|
7092
|
+
const kept = tail(concat2(this.parts));
|
|
7093
|
+
this.parts = [kept];
|
|
7094
|
+
this.size = kept.length;
|
|
7095
|
+
}
|
|
7096
|
+
}
|
|
7097
|
+
bytes() {
|
|
7098
|
+
return tail(concat2(this.parts));
|
|
7099
|
+
}
|
|
7100
|
+
};
|
|
7101
|
+
function readStamp(text) {
|
|
7102
|
+
try {
|
|
7103
|
+
const parsed2 = JSON.parse(text ?? "");
|
|
7104
|
+
const jobs = parsed2.jobs && typeof parsed2.jobs === "object" ? parsed2.jobs : {};
|
|
7105
|
+
const reboot = parsed2.reboot && typeof parsed2.reboot === "object" ? parsed2.reboot : {};
|
|
7106
|
+
return { jobs: { ...jobs }, reboot: { ...reboot } };
|
|
7107
|
+
} catch {
|
|
7108
|
+
return { jobs: {}, reboot: {} };
|
|
7109
|
+
}
|
|
7110
|
+
}
|
|
7111
|
+
var CronService = class {
|
|
7112
|
+
host;
|
|
7113
|
+
clock;
|
|
7114
|
+
stopping = new AbortController();
|
|
7115
|
+
gate = new PathGate();
|
|
7116
|
+
running = /* @__PURE__ */ new Map();
|
|
7117
|
+
reported = /* @__PURE__ */ new Map();
|
|
7118
|
+
wake = new AbortController();
|
|
7119
|
+
started;
|
|
7120
|
+
rebooted = false;
|
|
7121
|
+
constructor(host) {
|
|
7122
|
+
this.host = host;
|
|
7123
|
+
this.clock = host.clock ?? systemCronClock;
|
|
7124
|
+
}
|
|
7125
|
+
start() {
|
|
7126
|
+
this.started ??= this.begin();
|
|
7127
|
+
return this.started;
|
|
7128
|
+
}
|
|
7129
|
+
stop() {
|
|
7130
|
+
this.stopping.abort();
|
|
7131
|
+
this.wake.abort();
|
|
7132
|
+
}
|
|
7133
|
+
async begin() {
|
|
7134
|
+
await this.host.ready?.().catch(() => void 0);
|
|
7135
|
+
if (this.stopping.signal.aborted) return;
|
|
7136
|
+
const { locks } = this.host;
|
|
7137
|
+
const fire = () => this.fire().catch((err) => {
|
|
7138
|
+
console.warn(`slicc-kernel cron: stopped: ${messageOf(err)}`);
|
|
7139
|
+
});
|
|
7140
|
+
if (!locks) return fire();
|
|
7141
|
+
await locks.request(this.host.lock, { signal: this.stopping.signal }, fire).catch(() => void 0);
|
|
7142
|
+
}
|
|
7143
|
+
poke = () => this.wake.abort();
|
|
7144
|
+
async fire() {
|
|
7145
|
+
await this.provision();
|
|
7146
|
+
const unwatch = await this.host.watch([SYSTEM_CRONTAB, SPOOL_DIR], this.poke);
|
|
7147
|
+
try {
|
|
7148
|
+
while (!this.stopping.signal.aborted) await this.pass();
|
|
7149
|
+
} finally {
|
|
7150
|
+
unwatch();
|
|
7151
|
+
}
|
|
7152
|
+
}
|
|
7153
|
+
async pass() {
|
|
7154
|
+
let until;
|
|
7155
|
+
try {
|
|
7156
|
+
until = await this.tick();
|
|
7157
|
+
} catch (err) {
|
|
7158
|
+
await this.error(`cron: ${messageOf(err)}`);
|
|
7159
|
+
until = this.clock.now() + WAKE_MS;
|
|
7160
|
+
}
|
|
7161
|
+
if (this.stopping.signal.aborted) return;
|
|
7162
|
+
if (this.wake.signal.aborted) this.wake = new AbortController();
|
|
7163
|
+
await this.clock.sleep(until, this.wake.signal);
|
|
7164
|
+
}
|
|
7165
|
+
async provision() {
|
|
7166
|
+
const { fs, owners } = this.host;
|
|
7167
|
+
for (const [dir, mode] of [
|
|
7168
|
+
[CRON_DIR, 493],
|
|
7169
|
+
[SPOOL_DIR, 448],
|
|
7170
|
+
[LOG_DIR, 493]
|
|
7171
|
+
]) {
|
|
7172
|
+
if (await fs.exists(dir)) continue;
|
|
7173
|
+
await fs.mkdir(dir, { recursive: true });
|
|
7174
|
+
if (owners) await fs.chown?.(dir, { uid: 0, gid: 0, mode, follow: false });
|
|
7175
|
+
}
|
|
7176
|
+
}
|
|
7177
|
+
async tick() {
|
|
7178
|
+
const { fs } = this.host;
|
|
7179
|
+
const loaded = await this.load();
|
|
7180
|
+
const stamp = readStamp(await fs.readFile(STAMP_PATH).catch(() => void 0));
|
|
7181
|
+
const now = this.clock.now();
|
|
7182
|
+
const utc = this.clock.utc === true;
|
|
7183
|
+
const due2 = [];
|
|
7184
|
+
const keys = /* @__PURE__ */ new Set();
|
|
7185
|
+
let next3 = now + WAKE_MS;
|
|
7186
|
+
for (const entry of loaded) {
|
|
7187
|
+
const key = keyOf2(entry);
|
|
7188
|
+
keys.add(key);
|
|
7189
|
+
const { when } = entry.job;
|
|
7190
|
+
if (when.reboot) {
|
|
7191
|
+
if (this.rebooted || stamp.reboot[key] === this.host.bootId) continue;
|
|
7192
|
+
stamp.reboot[key] = this.host.bootId;
|
|
7193
|
+
due2.push({ entry, due: now, missed: 0 });
|
|
7194
|
+
continue;
|
|
7195
|
+
}
|
|
7196
|
+
const last = stamp.jobs[key];
|
|
7197
|
+
if (typeof last !== "number" || last > now + BACK_JUMP_MS) stamp.jobs[key] = now;
|
|
7198
|
+
else {
|
|
7199
|
+
const missed = missedFires(when.schedule, last, now, utc);
|
|
7200
|
+
if (missed.last !== null) {
|
|
7201
|
+
stamp.jobs[key] = now;
|
|
7202
|
+
due2.push({ entry, due: missed.last, missed: missed.count - 1 });
|
|
7203
|
+
}
|
|
7204
|
+
}
|
|
7205
|
+
const coming = nextFire(when.schedule, Math.max(now, stamp.jobs[key]), utc);
|
|
7206
|
+
if (coming !== null && coming < next3) next3 = coming;
|
|
7207
|
+
}
|
|
7208
|
+
this.rebooted = true;
|
|
7209
|
+
for (const map of [stamp.jobs, stamp.reboot])
|
|
7210
|
+
for (const key of Object.keys(map)) if (!keys.has(key)) delete map[key];
|
|
7211
|
+
await this.writeStamp(stamp);
|
|
7212
|
+
for (const each of due2) void this.spawn(each);
|
|
7213
|
+
return next3;
|
|
7214
|
+
}
|
|
7215
|
+
async writeStamp(stamp) {
|
|
7216
|
+
const { fs, owners } = this.host;
|
|
7217
|
+
const text = JSON.stringify(stamp);
|
|
7218
|
+
const old = await fs.readFile(STAMP_PATH).catch(() => void 0);
|
|
7219
|
+
if (old === text || old === void 0 && text === EMPTY_STAMP) return;
|
|
7220
|
+
const fresh2 = `${STAMP_PATH}.new`;
|
|
7221
|
+
const owner = owners ? { uid: 0, gid: 0, mode: 384 } : void 0;
|
|
7222
|
+
await fs.writeFile(fresh2, text, owner);
|
|
7223
|
+
await fs.rename(fresh2, STAMP_PATH);
|
|
7224
|
+
}
|
|
7225
|
+
async load() {
|
|
7226
|
+
const { fs } = this.host;
|
|
7227
|
+
const out = [];
|
|
7228
|
+
const system = await this.table(SYSTEM_CRONTAB, 0, true);
|
|
7229
|
+
for (const job of system?.jobs ?? []) {
|
|
7230
|
+
const account = await this.host.lookup(job.user);
|
|
7231
|
+
if (account) out.push({ source: "system", account, job });
|
|
7232
|
+
}
|
|
7233
|
+
const names = await fs.readdir(SPOOL_DIR).catch(() => []);
|
|
7234
|
+
for (const name2 of names.sort()) {
|
|
7235
|
+
if (name2.startsWith(".") || name2.endsWith("~") || name2.endsWith(".new")) continue;
|
|
7236
|
+
const path = `${SPOOL_DIR}/${name2}`;
|
|
7237
|
+
const account = await this.host.lookup(name2);
|
|
7238
|
+
if (!account) {
|
|
7239
|
+
await this.once(path, "no user", [`${path}: skipped: there is no user ${name2}`]);
|
|
7240
|
+
continue;
|
|
7241
|
+
}
|
|
7242
|
+
const table = await this.table(path, account.uid, false);
|
|
7243
|
+
for (const job of table?.jobs ?? []) out.push({ source: name2, account, job });
|
|
7244
|
+
}
|
|
7245
|
+
return out;
|
|
7246
|
+
}
|
|
7247
|
+
async table(path, uid, system) {
|
|
7248
|
+
const { fs, owners } = this.host;
|
|
7249
|
+
const st = await fs.lstat(path).catch(() => void 0);
|
|
7250
|
+
if (!st) {
|
|
7251
|
+
this.reported.delete(path);
|
|
7252
|
+
return void 0;
|
|
7253
|
+
}
|
|
7254
|
+
const trusted = st.isFile && (!owners || (st.uid === uid || st.uid === 0) && (st.mode & 18) === 0);
|
|
7255
|
+
if (!trusted) {
|
|
7256
|
+
const who = uid === 0 ? "root" : "its user or root";
|
|
7257
|
+
const why = `${path}: skipped: it must be a file of ${who}, writable by its owner only`;
|
|
7258
|
+
await this.once(path, "untrusted", [why]);
|
|
7259
|
+
return void 0;
|
|
7260
|
+
}
|
|
7261
|
+
const text = await fs.readFile(path).catch(() => "");
|
|
7262
|
+
const table = parseCrontab(text, path, system);
|
|
7263
|
+
const errors = table.errors.map(({ line, message: message3 }) => `${path}:${line}: ${message3}`);
|
|
7264
|
+
for (const job of table.jobs) {
|
|
7265
|
+
if (job.user !== void 0 && !await this.host.lookup(job.user))
|
|
7266
|
+
errors.push(`${path}:${job.line}: there is no user ${job.user}`);
|
|
7267
|
+
}
|
|
7268
|
+
await this.once(path, text, errors);
|
|
7269
|
+
return table;
|
|
7270
|
+
}
|
|
7271
|
+
async once(path, version, lines2) {
|
|
7272
|
+
if (this.reported.get(path) === version) return;
|
|
7273
|
+
this.reported.set(path, version);
|
|
7274
|
+
for (const line of lines2) await this.error(line);
|
|
7275
|
+
}
|
|
7276
|
+
async error(line) {
|
|
7277
|
+
if (this.stopping.signal.aborted) return;
|
|
7278
|
+
const stamp = new Date(this.clock.now()).toISOString();
|
|
7279
|
+
await this.append(ERR_LOG, encoder.encode(`${stamp} ${line}
|
|
7280
|
+
`), 0, 0).catch(() => void 0);
|
|
7281
|
+
}
|
|
7282
|
+
async append(path, bytes, uid, gid) {
|
|
7283
|
+
const { fs, owners } = this.host;
|
|
7284
|
+
await this.gate.run(path, async () => {
|
|
7285
|
+
const dir = path.slice(0, path.lastIndexOf("/"));
|
|
7286
|
+
if (!await fs.lstat(dir).catch(() => void 0)) {
|
|
7287
|
+
await fs.mkdir(dir, { recursive: true });
|
|
7288
|
+
if (owners) await fs.chown?.(dir, { uid: 0, gid: 0, mode: 493, follow: false });
|
|
7289
|
+
}
|
|
7290
|
+
const st = await fs.lstat(path).catch(() => void 0);
|
|
7291
|
+
if (owners) await this.trustLog(dir, path, st, uid);
|
|
7292
|
+
const old = st ? await fs.readFileBuffer(path) : void 0;
|
|
7293
|
+
const next3 = tail(old ? concat2([old, bytes]) : bytes);
|
|
7294
|
+
const owner = owners ? { uid, gid, mode: 384 } : void 0;
|
|
7295
|
+
await fs.writeFile(path, next3, old === void 0 ? owner : void 0);
|
|
7296
|
+
});
|
|
7297
|
+
}
|
|
7298
|
+
async trustLog(dir, path, st, uid) {
|
|
7299
|
+
const parent = await this.host.fs.lstat(dir);
|
|
7300
|
+
if (!parent.isDirectory || parent.isSymbolicLink || parent.uid !== 0)
|
|
7301
|
+
throw new Error(`${path} not written: ${dir} must be a directory of root`);
|
|
7302
|
+
if (st && (!st.isFile || st.isSymbolicLink || st.uid !== uid && st.uid !== 0))
|
|
7303
|
+
throw new Error(`${path} not written: it must be a file of uid ${uid} or root`);
|
|
7304
|
+
}
|
|
7305
|
+
logOf({ account, job }) {
|
|
7306
|
+
return normalizePath(`${LOG_DIR}/${account.name}/${job.id}.log`);
|
|
7307
|
+
}
|
|
7308
|
+
async spawn({ entry, due: due2, missed }) {
|
|
7309
|
+
const { account, job } = entry;
|
|
7310
|
+
const log = this.logOf(entry);
|
|
7311
|
+
const iso = new Date(due2).toISOString();
|
|
7312
|
+
const count2 = this.running.get(account.uid) ?? 0;
|
|
7313
|
+
if (count2 >= JOBS_PER_USER) {
|
|
7314
|
+
const why = `${JOBS_PER_USER} cron jobs of ${account.name} are running`;
|
|
7315
|
+
await this.append(
|
|
7316
|
+
log,
|
|
7317
|
+
encoder.encode(`--- ${iso} skipped: ${why} ---
|
|
7318
|
+
`),
|
|
7319
|
+
account.uid,
|
|
7320
|
+
account.gid
|
|
7321
|
+
).catch((err) => this.error(messageOf(err)));
|
|
7322
|
+
await this.error(`${account.name}/${job.id}: run due ${iso} skipped: ${why}`);
|
|
7323
|
+
return;
|
|
7324
|
+
}
|
|
7325
|
+
this.running.set(account.uid, count2 + 1);
|
|
7326
|
+
const output = new Output();
|
|
7327
|
+
let ended;
|
|
7328
|
+
try {
|
|
7329
|
+
const cwd = await this.host.fs.exists(account.home) ? account.home : "/";
|
|
7330
|
+
const shell = job.env.SHELL ?? DEFAULT_SHELL;
|
|
7331
|
+
ended = await this.host.run({
|
|
7332
|
+
account,
|
|
7333
|
+
argv: [shell, "-c", job.command],
|
|
7334
|
+
cwd,
|
|
7335
|
+
env: {
|
|
7336
|
+
SHELL: shell,
|
|
7337
|
+
...job.env,
|
|
7338
|
+
SLICC_CRON: "1",
|
|
7339
|
+
SLICC_CRON_JOB: job.id,
|
|
7340
|
+
SLICC_CRON_DUE: iso,
|
|
7341
|
+
SLICC_CRON_MISSED: String(missed)
|
|
7342
|
+
},
|
|
7343
|
+
output: (bytes) => output.push(bytes)
|
|
7344
|
+
});
|
|
7345
|
+
} catch (err) {
|
|
7346
|
+
output.push(encoder.encode(`cron: ${messageOf(err)}
|
|
7347
|
+
`));
|
|
7348
|
+
ended = { status: 127 };
|
|
7349
|
+
} finally {
|
|
7350
|
+
this.running.set(account.uid, (this.running.get(account.uid) ?? 1) - 1);
|
|
7351
|
+
}
|
|
7352
|
+
if (this.stopping.signal.aborted) return;
|
|
7353
|
+
const exit = ended.signal ? `signal=${ended.signal}` : `exit=${ended.status}`;
|
|
7354
|
+
const header4 = encoder.encode(`--- ${iso} ${exit} missed=${missed} ---
|
|
7355
|
+
`);
|
|
7356
|
+
const body = output.bytes();
|
|
7357
|
+
const newline = body.length > 0 && body[body.length - 1] !== 10 ? encoder.encode("\n") : new Uint8Array();
|
|
7358
|
+
await this.append(log, concat2([header4, body, newline]), account.uid, account.gid).catch(
|
|
7359
|
+
(err) => this.error(messageOf(err))
|
|
7360
|
+
);
|
|
7361
|
+
}
|
|
7362
|
+
};
|
|
7363
|
+
|
|
6797
7364
|
// src/kernel/net/proxy-service.ts
|
|
6798
7365
|
var SEND_BUFFER2 = 1024 * 1024;
|
|
6799
7366
|
var TLS_HANDSHAKE = 22;
|
|
@@ -6858,12 +7425,12 @@ function localV4(a, b) {
|
|
|
6858
7425
|
return a === 127 || a === 0 || a === 169 && b === 254;
|
|
6859
7426
|
}
|
|
6860
7427
|
function hextets(address) {
|
|
6861
|
-
const [head,
|
|
7428
|
+
const [head, tail2, extra] = address.split("::");
|
|
6862
7429
|
if (extra !== void 0) return void 0;
|
|
6863
7430
|
const part = (text) => text ? text.split(":").map((h) => Number.parseInt(h, 16)) : [];
|
|
6864
7431
|
const front = part(head);
|
|
6865
|
-
const back = part(
|
|
6866
|
-
const groups =
|
|
7432
|
+
const back = part(tail2);
|
|
7433
|
+
const groups = tail2 === void 0 ? front : [...front, ...new Array(8 - front.length - back.length).fill(0), ...back];
|
|
6867
7434
|
return groups.length === 8 && groups.every((g) => g >= 0 && g <= 65535) ? groups : void 0;
|
|
6868
7435
|
}
|
|
6869
7436
|
function localV6(address) {
|
|
@@ -7989,12 +8556,12 @@ var FreshModules = class {
|
|
|
7989
8556
|
return new Proxy(fs, {
|
|
7990
8557
|
get(target, key, receiver) {
|
|
7991
8558
|
if (Object.hasOwn(overrides, key)) return overrides[key];
|
|
7992
|
-
const
|
|
7993
|
-
if (typeof
|
|
7994
|
-
let method = bound2.get(
|
|
8559
|
+
const value2 = Reflect.get(target, key, receiver);
|
|
8560
|
+
if (typeof value2 !== "function") return value2;
|
|
8561
|
+
let method = bound2.get(value2);
|
|
7995
8562
|
if (method === void 0) {
|
|
7996
|
-
method =
|
|
7997
|
-
bound2.set(
|
|
8563
|
+
method = value2.bind(target);
|
|
8564
|
+
bound2.set(value2, method);
|
|
7998
8565
|
}
|
|
7999
8566
|
return method;
|
|
8000
8567
|
}
|
|
@@ -8189,8 +8756,8 @@ var FsWatchers = class {
|
|
|
8189
8756
|
return new Proxy(fs, {
|
|
8190
8757
|
get(target, key, receiver) {
|
|
8191
8758
|
if (Object.hasOwn(overrides, key)) return overrides[key];
|
|
8192
|
-
const
|
|
8193
|
-
return typeof
|
|
8759
|
+
const value2 = Reflect.get(target, key, receiver);
|
|
8760
|
+
return typeof value2 === "function" ? value2.bind(target) : value2;
|
|
8194
8761
|
}
|
|
8195
8762
|
});
|
|
8196
8763
|
}
|
|
@@ -8247,7 +8814,7 @@ function captureFile(onData, control) {
|
|
|
8247
8814
|
close: () => control.ended()
|
|
8248
8815
|
});
|
|
8249
8816
|
}
|
|
8250
|
-
function
|
|
8817
|
+
function concat3(chunks2) {
|
|
8251
8818
|
const out = new Uint8Array(chunks2.reduce((n, c) => n + c.length, 0));
|
|
8252
8819
|
let offset = 0;
|
|
8253
8820
|
for (const chunk2 of chunks2) {
|
|
@@ -8417,14 +8984,14 @@ var ChildTable = class {
|
|
|
8417
8984
|
if (!slots2 || !chunks2) return new Uint8Array(0);
|
|
8418
8985
|
slots2.delete(slot2);
|
|
8419
8986
|
if (slots2.size === 0) this.leftovers.delete(pid);
|
|
8420
|
-
return
|
|
8987
|
+
return concat3(chunks2);
|
|
8421
8988
|
}
|
|
8422
8989
|
};
|
|
8423
8990
|
|
|
8424
8991
|
// src/kernel/clipboard.ts
|
|
8425
8992
|
var CLIPBOARD_MAX_BYTES = 1024 * 1024;
|
|
8426
8993
|
var CLIPBOARD_TIMEOUT_MS = 1e4;
|
|
8427
|
-
var
|
|
8994
|
+
var encoder2 = new TextEncoder();
|
|
8428
8995
|
var decoder = new TextDecoder("utf-8", { fatal: true });
|
|
8429
8996
|
var READY = { readable: true, writable: true, hangup: false };
|
|
8430
8997
|
function lineOf(err) {
|
|
@@ -8492,7 +9059,7 @@ var ClipboardChannel = class {
|
|
|
8492
9059
|
const asked = this.broker.ask(async (hook) => {
|
|
8493
9060
|
const text = await hook.read(stamp);
|
|
8494
9061
|
if (typeof text !== "string") throw new KernelError("EIO", "the clipboard gave no text");
|
|
8495
|
-
return
|
|
9062
|
+
return encoder2.encode(text);
|
|
8496
9063
|
});
|
|
8497
9064
|
this.snapshot = asked;
|
|
8498
9065
|
asked.then(
|
|
@@ -8602,12 +9169,12 @@ async function argvDigest(argv) {
|
|
|
8602
9169
|
const hash = new Uint8Array(await crypto.subtle.digest("SHA-256", bytes));
|
|
8603
9170
|
return [...hash].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
8604
9171
|
}
|
|
8605
|
-
function isStrings(
|
|
8606
|
-
return Array.isArray(
|
|
9172
|
+
function isStrings(value2) {
|
|
9173
|
+
return Array.isArray(value2) && value2.every((item) => typeof item === "string");
|
|
8607
9174
|
}
|
|
8608
|
-
function stringRecord(
|
|
8609
|
-
if (typeof
|
|
8610
|
-
const entries = Object.entries(
|
|
9175
|
+
function stringRecord(value2) {
|
|
9176
|
+
if (typeof value2 !== "object" || value2 === null || Array.isArray(value2)) return void 0;
|
|
9177
|
+
const entries = Object.entries(value2);
|
|
8611
9178
|
return entries.every(([, v]) => typeof v === "string") ? Object.fromEntries(entries) : void 0;
|
|
8612
9179
|
}
|
|
8613
9180
|
var TicketBook = class {
|
|
@@ -8767,14 +9334,14 @@ var DriverConnection = class _DriverConnection {
|
|
|
8767
9334
|
var S_ISGID4 = 1024;
|
|
8768
9335
|
var ID = /^\d{1,10}$/;
|
|
8769
9336
|
var MAX_ID2 = 4294967294;
|
|
8770
|
-
function idOption(
|
|
8771
|
-
return
|
|
9337
|
+
function idOption(value2) {
|
|
9338
|
+
return value2 === void 0 ? 0 : Number(value2);
|
|
8772
9339
|
}
|
|
8773
9340
|
function checkIds(options) {
|
|
8774
9341
|
for (const key of ["uid", "gid"]) {
|
|
8775
|
-
const
|
|
8776
|
-
if (
|
|
8777
|
-
if (!ID.test(
|
|
9342
|
+
const value2 = options[key];
|
|
9343
|
+
if (value2 === void 0) continue;
|
|
9344
|
+
if (!ID.test(value2) || Number(value2) > MAX_ID2) throw errnoError("EINVAL", `${key}=${value2}`);
|
|
8778
9345
|
}
|
|
8779
9346
|
}
|
|
8780
9347
|
var MAX_LINKS7 = 40;
|
|
@@ -8988,7 +9555,7 @@ function statOf(attr2, path, mount) {
|
|
|
8988
9555
|
} : {}
|
|
8989
9556
|
};
|
|
8990
9557
|
}
|
|
8991
|
-
function
|
|
9558
|
+
function concat4(chunks2, total) {
|
|
8992
9559
|
if (chunks2.length === 1 && chunks2[0]?.length === total) return chunks2[0];
|
|
8993
9560
|
const out = new Uint8Array(total);
|
|
8994
9561
|
let at = 0;
|
|
@@ -9495,7 +10062,7 @@ var MountFs = class _MountFs {
|
|
|
9495
10062
|
} finally {
|
|
9496
10063
|
await mount.conn.call({ op: "release", fh });
|
|
9497
10064
|
}
|
|
9498
|
-
return
|
|
10065
|
+
return concat4(chunks2, total);
|
|
9499
10066
|
}
|
|
9500
10067
|
async writeFile(path, content, owner, redirects = 0) {
|
|
9501
10068
|
const real = await this.follow(path, 0, true);
|
|
@@ -9590,7 +10157,7 @@ var MountFs = class _MountFs {
|
|
|
9590
10157
|
} finally {
|
|
9591
10158
|
await mount.conn.call({ op: "release", fh });
|
|
9592
10159
|
}
|
|
9593
|
-
return
|
|
10160
|
+
return concat4(chunks2, total);
|
|
9594
10161
|
}
|
|
9595
10162
|
fits(mount, real, end) {
|
|
9596
10163
|
if (mount.maxFile > 0 && end > mount.maxFile) {
|
|
@@ -10003,7 +10570,7 @@ var MountFs = class _MountFs {
|
|
|
10003
10570
|
await mount.conn.call({
|
|
10004
10571
|
op: "setattr",
|
|
10005
10572
|
path: rel2,
|
|
10006
|
-
...Object.fromEntries(attrs.filter(([,
|
|
10573
|
+
...Object.fromEntries(attrs.filter(([, value2]) => value2 !== void 0))
|
|
10007
10574
|
});
|
|
10008
10575
|
}
|
|
10009
10576
|
async chmod(path, mode, redirects = 0) {
|
|
@@ -10182,8 +10749,8 @@ async function storageUsage() {
|
|
|
10182
10749
|
}
|
|
10183
10750
|
var PLAIN_DIR_MODE = 493;
|
|
10184
10751
|
var done = { ok: true, kind: "void" };
|
|
10185
|
-
function json2(
|
|
10186
|
-
return { ok: true, kind: "json", json:
|
|
10752
|
+
function json2(value2) {
|
|
10753
|
+
return { ok: true, kind: "json", json: value2 };
|
|
10187
10754
|
}
|
|
10188
10755
|
function ownerFor2(entry, mode) {
|
|
10189
10756
|
const cred = entry.cred?.();
|
|
@@ -10742,9 +11309,9 @@ function storeBlocked(header4, [low, high]) {
|
|
|
10742
11309
|
}
|
|
10743
11310
|
var anyBlocked = (mask) => mask !== void 0 && (mask[0] !== 0 || mask[1] !== 0);
|
|
10744
11311
|
var U32 = 2 ** 32;
|
|
10745
|
-
function storeU53(header4, lo, hi,
|
|
10746
|
-
Atomics.store(header4, hi, Math.floor(
|
|
10747
|
-
Atomics.store(header4, lo,
|
|
11312
|
+
function storeU53(header4, lo, hi, value2) {
|
|
11313
|
+
Atomics.store(header4, hi, Math.floor(value2 / U32));
|
|
11314
|
+
Atomics.store(header4, lo, value2 % U32 | 0);
|
|
10748
11315
|
}
|
|
10749
11316
|
var SAB_STATE_READY = 2;
|
|
10750
11317
|
var SAB_STATUS_BYTES = 1;
|
|
@@ -10755,20 +11322,20 @@ var SAB_DEFAULT_WINDOW_BYTES = 1024 * 1024;
|
|
|
10755
11322
|
var SAB_MIN_BYTES = SAB_HEADER_BYTES + 4096;
|
|
10756
11323
|
var SYNC_SAB_REQ_MSG = "sync-sab-req";
|
|
10757
11324
|
var SYNC_SAB_NEXT_MSG = "sync-sab-next";
|
|
10758
|
-
var
|
|
11325
|
+
var encoder3 = new TextEncoder();
|
|
10759
11326
|
var decoder2 = new TextDecoder();
|
|
10760
11327
|
function encodeSabResult(result) {
|
|
10761
11328
|
if (!result.ok) {
|
|
10762
11329
|
return {
|
|
10763
11330
|
status: SAB_STATUS_ERRNO,
|
|
10764
|
-
payload:
|
|
11331
|
+
payload: encoder3.encode(JSON.stringify({ errno: result.errno, message: result.message }))
|
|
10765
11332
|
};
|
|
10766
11333
|
}
|
|
10767
11334
|
switch (result.kind) {
|
|
10768
11335
|
case "bytes":
|
|
10769
11336
|
return { status: SAB_STATUS_BYTES, payload: result.bytes };
|
|
10770
11337
|
case "json":
|
|
10771
|
-
return { status: SAB_STATUS_JSON, payload:
|
|
11338
|
+
return { status: SAB_STATUS_JSON, payload: encoder3.encode(JSON.stringify(result.json)) };
|
|
10772
11339
|
default:
|
|
10773
11340
|
return { status: SAB_STATUS_VOID, payload: new Uint8Array(0) };
|
|
10774
11341
|
}
|
|
@@ -10876,14 +11443,14 @@ function attachSyncSabResponder(port, sab, token, opts) {
|
|
|
10876
11443
|
|
|
10877
11444
|
// src/kernel/cpu-clock.ts
|
|
10878
11445
|
var SYS_CAP_US = 2e4;
|
|
10879
|
-
var
|
|
11446
|
+
var LOCAL2 = SAB_CLOCK_OFFSET;
|
|
10880
11447
|
var BLOCKED = 0;
|
|
10881
11448
|
var IDLE = 1;
|
|
10882
11449
|
function epochMicros() {
|
|
10883
11450
|
return Math.floor((performance.timeOrigin + performance.now()) * 1e3);
|
|
10884
11451
|
}
|
|
10885
11452
|
function slots(sab) {
|
|
10886
|
-
return new BigInt64Array(sab,
|
|
11453
|
+
return new BigInt64Array(sab, LOCAL2, SAB_CLOCK_I64);
|
|
10887
11454
|
}
|
|
10888
11455
|
var rawWait = Atomics.wait.bind(Atomics);
|
|
10889
11456
|
function localIdle(sab, now) {
|
|
@@ -11272,14 +11839,14 @@ var KernelDgram = class {
|
|
|
11272
11839
|
}
|
|
11273
11840
|
return this.options.get(`${level}:${name2}`) ?? 0;
|
|
11274
11841
|
}
|
|
11275
|
-
setOption(level, name2,
|
|
11276
|
-
if (level === SOL_SOCKET2 && name2 === SO_BROADCAST &&
|
|
11842
|
+
setOption(level, name2, value2) {
|
|
11843
|
+
if (level === SOL_SOCKET2 && name2 === SO_BROADCAST && value2 !== 0) {
|
|
11277
11844
|
throw new KernelError("EOPNOTSUPP");
|
|
11278
11845
|
}
|
|
11279
11846
|
if (level === IPPROTO_IP && name2 >= IP_MULTICAST_FIRST && name2 <= IP_MULTICAST_LAST) {
|
|
11280
11847
|
throw new KernelError("ENOPROTOOPT");
|
|
11281
11848
|
}
|
|
11282
|
-
this.options.set(`${level}:${name2}`,
|
|
11849
|
+
this.options.set(`${level}:${name2}`, value2);
|
|
11283
11850
|
}
|
|
11284
11851
|
close() {
|
|
11285
11852
|
if (this.closed) return;
|
|
@@ -11538,7 +12105,7 @@ var PATH_OPS = new Set(SYNC_FS_OPS);
|
|
|
11538
12105
|
var EARLY_WHOLE_FILE = 64 * 1024;
|
|
11539
12106
|
|
|
11540
12107
|
// src/process/process-fds.ts
|
|
11541
|
-
var
|
|
12108
|
+
var field3 = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
|
|
11542
12109
|
var pinnedRoot;
|
|
11543
12110
|
var rootKind = () => globalThis.navigator?.storage ? "opfs" : "memory";
|
|
11544
12111
|
function mountTable(mounts = []) {
|
|
@@ -11549,7 +12116,7 @@ function mountTable(mounts = []) {
|
|
|
11549
12116
|
if (m.state !== "ok") options.push(m.state);
|
|
11550
12117
|
const access2 = options.includes("ro") ? [] : ["rw"];
|
|
11551
12118
|
lines2.push(
|
|
11552
|
-
`${
|
|
12119
|
+
`${field3(m.source)} ${field3(m.target)} ${m.type} ${[...access2, ...options].join(",")} 0 0`
|
|
11553
12120
|
);
|
|
11554
12121
|
}
|
|
11555
12122
|
return `${lines2.join("\n")}
|
|
@@ -11705,7 +12272,7 @@ function memoryInfo(source, used = 0) {
|
|
|
11705
12272
|
["SReclaimable", kb(0)],
|
|
11706
12273
|
["SwapTotal", kb(0)],
|
|
11707
12274
|
["SwapFree", kb(0)]
|
|
11708
|
-
].map(([key,
|
|
12275
|
+
].map(([key, value2]) => `${`${key}:`.padEnd(16)}${value2.padStart(12)}`).concat("").join("\n");
|
|
11709
12276
|
}
|
|
11710
12277
|
function systemFile(name2, listing, now, memory) {
|
|
11711
12278
|
if (name2 === "version") return procVersion();
|
|
@@ -11960,15 +12527,15 @@ async function procAlias(fs, path, follow2) {
|
|
|
11960
12527
|
);
|
|
11961
12528
|
if (!physical) return void 0;
|
|
11962
12529
|
const walk2 = procWalk(path, follow2);
|
|
11963
|
-
let
|
|
11964
|
-
while (!
|
|
11965
|
-
const { at, check } =
|
|
12530
|
+
let step2 = walk2.next();
|
|
12531
|
+
while (!step2.done) {
|
|
12532
|
+
const { at, check } = step2.value;
|
|
11966
12533
|
const link2 = await readlink.call(fs, at).catch(() => void 0);
|
|
11967
12534
|
const isDir = (st) => st.isDirectory === true;
|
|
11968
12535
|
const target = link2 ?? (check ? await lstat.call(fs, at).then(isDir, failed) : true);
|
|
11969
|
-
|
|
12536
|
+
step2 = walk2.next(target);
|
|
11970
12537
|
}
|
|
11971
|
-
return
|
|
12538
|
+
return step2.value;
|
|
11972
12539
|
}
|
|
11973
12540
|
|
|
11974
12541
|
// src/kernel/eventfd.ts
|
|
@@ -12014,23 +12581,23 @@ var EventFd = class _EventFd {
|
|
|
12014
12581
|
blocked(signal);
|
|
12015
12582
|
await this.changes.wait(signal);
|
|
12016
12583
|
}
|
|
12017
|
-
const
|
|
12018
|
-
this.count -=
|
|
12584
|
+
const value2 = this.semaphore ? 1n : this.count;
|
|
12585
|
+
this.count -= value2;
|
|
12019
12586
|
this.changes.wake();
|
|
12020
12587
|
const out = new Uint8Array(_EventFd.SIZE);
|
|
12021
|
-
new DataView(out.buffer).setBigUint64(0,
|
|
12588
|
+
new DataView(out.buffer).setBigUint64(0, value2, true);
|
|
12022
12589
|
return out;
|
|
12023
12590
|
}
|
|
12024
12591
|
async write(bytes, signal) {
|
|
12025
12592
|
if (bytes.length < _EventFd.SIZE) throw new KernelError("EINVAL");
|
|
12026
|
-
const
|
|
12027
|
-
if (
|
|
12028
|
-
while (EVENTFD_MAX - this.count <
|
|
12593
|
+
const value2 = new DataView(bytes.buffer, bytes.byteOffset, _EventFd.SIZE).getBigUint64(0, true);
|
|
12594
|
+
if (value2 > EVENTFD_MAX) throw new KernelError("EINVAL");
|
|
12595
|
+
while (EVENTFD_MAX - this.count < value2) {
|
|
12029
12596
|
blocked(signal);
|
|
12030
12597
|
await this.changes.wait(signal);
|
|
12031
12598
|
}
|
|
12032
|
-
this.count +=
|
|
12033
|
-
if (
|
|
12599
|
+
this.count += value2;
|
|
12600
|
+
if (value2 > 0n) this.changes.wake();
|
|
12034
12601
|
return _EventFd.SIZE;
|
|
12035
12602
|
}
|
|
12036
12603
|
poll() {
|
|
@@ -12317,10 +12884,10 @@ var LockTable = class {
|
|
|
12317
12884
|
}
|
|
12318
12885
|
set(key, owner, kind, start2, end) {
|
|
12319
12886
|
if (kind !== "unlock" && this.holder(key, owner, { key, kind, start: start2, end })) return false;
|
|
12320
|
-
const
|
|
12887
|
+
const range2 = { start: start2, end };
|
|
12321
12888
|
const kept = [];
|
|
12322
12889
|
for (const lock of this.records.get(key) ?? []) {
|
|
12323
|
-
if (lock.owner !== owner || !overlaps(lock,
|
|
12890
|
+
if (lock.owner !== owner || !overlaps(lock, range2)) kept.push(lock);
|
|
12324
12891
|
else {
|
|
12325
12892
|
if (lock.start < start2) kept.push({ ...lock, end: start2 });
|
|
12326
12893
|
if (lock.end > end) kept.push({ ...lock, start: end });
|
|
@@ -12331,13 +12898,13 @@ var LockTable = class {
|
|
|
12331
12898
|
this.wake(key);
|
|
12332
12899
|
return true;
|
|
12333
12900
|
}
|
|
12334
|
-
async wait(key, owner, kind,
|
|
12335
|
-
const want = { key, kind, ...
|
|
12901
|
+
async wait(key, owner, kind, range2, blocking) {
|
|
12902
|
+
const want = { key, kind, ...range2 };
|
|
12336
12903
|
let signal;
|
|
12337
12904
|
for (; ; ) {
|
|
12338
12905
|
const holder = this.holder(key, owner, want);
|
|
12339
12906
|
if (!holder) {
|
|
12340
|
-
this.set(key, owner, kind,
|
|
12907
|
+
this.set(key, owner, kind, range2.start, range2.end);
|
|
12341
12908
|
return;
|
|
12342
12909
|
}
|
|
12343
12910
|
if (this.waitsOn(holder.owner, owner)) throw new KernelError("EDEADLK");
|
|
@@ -12460,7 +13027,7 @@ var HOST_OPS = [
|
|
|
12460
13027
|
"async-settle",
|
|
12461
13028
|
"async-close"
|
|
12462
13029
|
];
|
|
12463
|
-
var json3 = (
|
|
13030
|
+
var json3 = (value2) => ({ ok: true, kind: "json", json: value2 });
|
|
12464
13031
|
var done2 = { ok: true, kind: "void" };
|
|
12465
13032
|
var KEPT_OPS = /* @__PURE__ */ new Set(["fd-write"]);
|
|
12466
13033
|
var unknownSettled = false;
|
|
@@ -12490,9 +13057,9 @@ var AsyncOps = class {
|
|
|
12490
13057
|
);
|
|
12491
13058
|
return id2;
|
|
12492
13059
|
}
|
|
12493
|
-
resolve(
|
|
13060
|
+
resolve(value2) {
|
|
12494
13061
|
const id2 = this.hold();
|
|
12495
|
-
this.complete(id2, json3(
|
|
13062
|
+
this.complete(id2, json3(value2));
|
|
12496
13063
|
return id2;
|
|
12497
13064
|
}
|
|
12498
13065
|
hold() {
|
|
@@ -12637,19 +13204,19 @@ async function recordLock2(req, ctx) {
|
|
|
12637
13204
|
locks.dropFile(await fileKey(target, "close"), owner);
|
|
12638
13205
|
return done2;
|
|
12639
13206
|
}
|
|
12640
|
-
const
|
|
13207
|
+
const range2 = lockRange(req.start, req.len);
|
|
12641
13208
|
const key = await fileKey(target, req.kind, req.op === "lk-set" && req.fd !== void 0);
|
|
12642
13209
|
if (req.op === "lk-get") {
|
|
12643
|
-
const held = locks.holder(key, owner, { key, kind: req.kind, ...
|
|
13210
|
+
const held = locks.holder(key, owner, { key, kind: req.kind, ...range2 });
|
|
12644
13211
|
if (!held) return json3(null);
|
|
12645
13212
|
const len = held.end === Number.POSITIVE_INFINITY ? 0 : held.end - held.start;
|
|
12646
13213
|
return json3({ kind: held.kind, pid: held.owner, start: held.start, len });
|
|
12647
13214
|
}
|
|
12648
13215
|
if (req.kind !== "unlock" && req.wait) {
|
|
12649
|
-
await locks.wait(key, owner, req.kind,
|
|
13216
|
+
await locks.wait(key, owner, req.kind, range2, ctx.blocking);
|
|
12650
13217
|
return done2;
|
|
12651
13218
|
}
|
|
12652
|
-
if (!locks.set(key, owner, req.kind,
|
|
13219
|
+
if (!locks.set(key, owner, req.kind, range2.start, range2.end)) throw new KernelError("EAGAIN");
|
|
12653
13220
|
return done2;
|
|
12654
13221
|
}
|
|
12655
13222
|
|
|
@@ -12682,15 +13249,16 @@ var MAX_UNREAD = 16 * 1024 * 1024;
|
|
|
12682
13249
|
function errno(code, message3) {
|
|
12683
13250
|
return Object.assign(new Error(`${code}: ${message3}`), { code });
|
|
12684
13251
|
}
|
|
12685
|
-
function requestHead(method, url, headers, extra) {
|
|
13252
|
+
function requestHead(method, url, headers, extra, first = []) {
|
|
12686
13253
|
if (!TOKEN3.test(method)) throw errno("EINVAL", `method ${method}`);
|
|
12687
|
-
const lines2 = [`${method} ${url.pathname}${url.search} HTTP/1.1`, `
|
|
12688
|
-
for (const [name2,
|
|
13254
|
+
const lines2 = [`${method} ${url.pathname}${url.search} HTTP/1.1`, `host: ${url.host}`];
|
|
13255
|
+
for (const [name2, value2] of first) lines2.push(`${name2}: ${value2}`);
|
|
13256
|
+
for (const [name2, value2] of headers) {
|
|
12689
13257
|
if (OWN_HEADERS.has(name2.toLowerCase())) continue;
|
|
12690
|
-
if (!TOKEN3.test(name2) || !SAFE_VALUE.test(
|
|
12691
|
-
lines2.push(`${name2}: ${
|
|
13258
|
+
if (!TOKEN3.test(name2) || !SAFE_VALUE.test(value2)) throw errno("EINVAL", `header ${name2}`);
|
|
13259
|
+
lines2.push(`${name2}: ${value2}`);
|
|
12692
13260
|
}
|
|
12693
|
-
for (const [name2,
|
|
13261
|
+
for (const [name2, value2] of extra) lines2.push(`${name2}: ${value2}`);
|
|
12694
13262
|
return latin1Bytes(`${lines2.join("\r\n")}\r
|
|
12695
13263
|
\r
|
|
12696
13264
|
`);
|
|
@@ -12799,8 +13367,8 @@ var KernelLoopback = class {
|
|
|
12799
13367
|
async fetch(req, port) {
|
|
12800
13368
|
const url = new URL(req.url);
|
|
12801
13369
|
const body = req.body ?? (/^(POST|PUT|PATCH)$/i.test(req.method) ? new Uint8Array(0) : void 0);
|
|
12802
|
-
const length2 = body ? [["
|
|
12803
|
-
const head = requestHead(req.method, url, req.headers,
|
|
13370
|
+
const length2 = body ? [["content-length", String(body.length)]] : [];
|
|
13371
|
+
const head = requestHead(req.method, url, req.headers, length2, [["connection", "close"]]);
|
|
12804
13372
|
const socket = await this.connect(url, port, req.signal);
|
|
12805
13373
|
try {
|
|
12806
13374
|
await writeAll2(socket, body ? concat([head, body]) : head, req.signal);
|
|
@@ -12893,7 +13461,7 @@ var LoopbackWebSocket = class {
|
|
|
12893
13461
|
const queue = [];
|
|
12894
13462
|
let wake;
|
|
12895
13463
|
let ended = false;
|
|
12896
|
-
void this.pump(
|
|
13464
|
+
void this.pump(incoming, (message3) => {
|
|
12897
13465
|
queue.push(message3);
|
|
12898
13466
|
this.unread += message3.length;
|
|
12899
13467
|
wake?.();
|
|
@@ -12948,7 +13516,8 @@ var LoopbackWebSocket = class {
|
|
|
12948
13516
|
this.pending -= bytes.length;
|
|
12949
13517
|
})();
|
|
12950
13518
|
}
|
|
12951
|
-
async pump(
|
|
13519
|
+
async pump(incoming, deliver) {
|
|
13520
|
+
const reader = new WsReader(incoming, void 0, true, true);
|
|
12952
13521
|
let close = { code: 1006, reason: "", wasClean: false };
|
|
12953
13522
|
try {
|
|
12954
13523
|
for (; ; ) {
|
|
@@ -12970,11 +13539,18 @@ var LoopbackWebSocket = class {
|
|
|
12970
13539
|
} finally {
|
|
12971
13540
|
const late = setTimeout(() => this.stop.abort(), CLOSE_WAIT_MS3);
|
|
12972
13541
|
await this.writes;
|
|
13542
|
+
if (close.wasClean) await this.serverEnd(incoming);
|
|
12973
13543
|
clearTimeout(late);
|
|
12974
13544
|
this.socket.close();
|
|
12975
13545
|
this.settle(close);
|
|
12976
13546
|
}
|
|
12977
13547
|
}
|
|
13548
|
+
async serverEnd(incoming) {
|
|
13549
|
+
try {
|
|
13550
|
+
while ((await incoming.some(64 * 1024, this.stop.signal)).length > 0) ;
|
|
13551
|
+
} catch {
|
|
13552
|
+
}
|
|
13553
|
+
}
|
|
12978
13554
|
sendClose(code, reason) {
|
|
12979
13555
|
if (this.sentClose) return;
|
|
12980
13556
|
this.sentClose = true;
|
|
@@ -12998,7 +13574,7 @@ var LoopbackWebSocket = class {
|
|
|
12998
13574
|
};
|
|
12999
13575
|
|
|
13000
13576
|
// src/kernel/net/x509.ts
|
|
13001
|
-
function
|
|
13577
|
+
function concat5(parts2) {
|
|
13002
13578
|
const out = new Uint8Array(parts2.reduce((n, p) => n + p.length, 0));
|
|
13003
13579
|
let at = 0;
|
|
13004
13580
|
for (const p of parts2) {
|
|
@@ -13014,8 +13590,8 @@ function length(n) {
|
|
|
13014
13590
|
return Uint8Array.of(128 | bytes.length, ...bytes);
|
|
13015
13591
|
}
|
|
13016
13592
|
function tlv(tag, ...contents2) {
|
|
13017
|
-
const body =
|
|
13018
|
-
return
|
|
13593
|
+
const body = concat5(contents2);
|
|
13594
|
+
return concat5([Uint8Array.of(tag), length(body.length), body]);
|
|
13019
13595
|
}
|
|
13020
13596
|
var seq = (...parts2) => tlv(48, ...parts2);
|
|
13021
13597
|
var set2 = (...parts2) => tlv(49, ...parts2);
|
|
@@ -13026,7 +13602,7 @@ function integer(magnitude) {
|
|
|
13026
13602
|
let start2 = 0;
|
|
13027
13603
|
while (start2 < magnitude.length - 1 && magnitude[start2] === 0) start2++;
|
|
13028
13604
|
const trimmed = magnitude.subarray(start2);
|
|
13029
|
-
return tlv(2, trimmed[0] & 128 ?
|
|
13605
|
+
return tlv(2, trimmed[0] & 128 ? concat5([Uint8Array.of(0), trimmed]) : trimmed);
|
|
13030
13606
|
}
|
|
13031
13607
|
function oid(dotted) {
|
|
13032
13608
|
const [a, b, ...rest2] = dotted.split(".").map(Number);
|
|
@@ -13055,8 +13631,8 @@ function name(dn) {
|
|
|
13055
13631
|
rdns.push(set2(seq(oid("2.5.4.3"), utf8(dn.commonName))));
|
|
13056
13632
|
return seq(...rdns);
|
|
13057
13633
|
}
|
|
13058
|
-
function extension(id2, critical,
|
|
13059
|
-
return critical ? seq(oid(id2), TRUE, octets(
|
|
13634
|
+
function extension(id2, critical, value2) {
|
|
13635
|
+
return critical ? seq(oid(id2), TRUE, octets(value2)) : seq(oid(id2), octets(value2));
|
|
13060
13636
|
}
|
|
13061
13637
|
function children(der) {
|
|
13062
13638
|
const out = [];
|
|
@@ -13113,11 +13689,11 @@ function ipv6(host) {
|
|
|
13113
13689
|
if (!host.includes(":") || !/^[0-9A-Fa-f:.]+$/.test(host)) return void 0;
|
|
13114
13690
|
const v4 = /(\d{1,3}(?:\.\d{1,3}){3})$/.exec(host);
|
|
13115
13691
|
let text = host;
|
|
13116
|
-
const
|
|
13692
|
+
const tail2 = [];
|
|
13117
13693
|
if (v4) {
|
|
13118
13694
|
const bytes = ipv4(v4[1]);
|
|
13119
13695
|
if (!bytes) return void 0;
|
|
13120
|
-
|
|
13696
|
+
tail2.push(bytes[0] << 8 | bytes[1], bytes[2] << 8 | bytes[3]);
|
|
13121
13697
|
text = host.slice(0, -v4[1].length).replace(/:$/, host.endsWith(`::${v4[1]}`) ? ":" : "");
|
|
13122
13698
|
}
|
|
13123
13699
|
const halves = text.split("::");
|
|
@@ -13127,13 +13703,13 @@ function ipv6(host) {
|
|
|
13127
13703
|
const back = halves.length === 2 ? groups(halves[1]) : [];
|
|
13128
13704
|
if (![...head, ...back].every((g) => /^[0-9A-Fa-f]{1,4}$/.test(g))) return void 0;
|
|
13129
13705
|
const words2 = [...head, ...back].map((g) => Number.parseInt(g, 16));
|
|
13130
|
-
const missing4 = 8 - words2.length -
|
|
13706
|
+
const missing4 = 8 - words2.length - tail2.length;
|
|
13131
13707
|
if (halves.length === 2 ? missing4 < 1 : missing4 !== 0) return void 0;
|
|
13132
13708
|
const all = [
|
|
13133
13709
|
...head.map((g) => Number.parseInt(g, 16)),
|
|
13134
13710
|
...new Array(halves.length === 2 ? missing4 : 0).fill(0),
|
|
13135
13711
|
...back.map((g) => Number.parseInt(g, 16)),
|
|
13136
|
-
...
|
|
13712
|
+
...tail2
|
|
13137
13713
|
];
|
|
13138
13714
|
return Uint8Array.from(all.flatMap((w) => [w >> 8, w & 255]));
|
|
13139
13715
|
}
|
|
@@ -14123,11 +14699,11 @@ function waitFor(lookup4, signal) {
|
|
|
14123
14699
|
reject(new KernelError("EINTR"));
|
|
14124
14700
|
};
|
|
14125
14701
|
signal?.addEventListener("abort", abort, { once: true });
|
|
14126
|
-
void lookup4.work.then((
|
|
14702
|
+
void lookup4.work.then((value2) => {
|
|
14127
14703
|
if (signal?.aborted) return;
|
|
14128
14704
|
lookup4.waiters--;
|
|
14129
14705
|
signal?.removeEventListener("abort", abort);
|
|
14130
|
-
resolve2(
|
|
14706
|
+
resolve2(value2);
|
|
14131
14707
|
});
|
|
14132
14708
|
});
|
|
14133
14709
|
}
|
|
@@ -14164,7 +14740,7 @@ function defaultTermios() {
|
|
|
14164
14740
|
c_cc: cCc
|
|
14165
14741
|
};
|
|
14166
14742
|
}
|
|
14167
|
-
var
|
|
14743
|
+
var encoder4 = new TextEncoder();
|
|
14168
14744
|
function isContinuation(byte) {
|
|
14169
14745
|
return (byte & 192) === 128;
|
|
14170
14746
|
}
|
|
@@ -14287,7 +14863,7 @@ var KernelTty = class {
|
|
|
14287
14863
|
this.line.push(byte);
|
|
14288
14864
|
this.readable.push(Uint8Array.from(this.line));
|
|
14289
14865
|
this.line = [];
|
|
14290
|
-
if (echo) this.output(
|
|
14866
|
+
if (echo) this.output(encoder4.encode("\n"));
|
|
14291
14867
|
} else {
|
|
14292
14868
|
this.line.push(byte);
|
|
14293
14869
|
if (echo) this.echo(byte);
|
|
@@ -14312,7 +14888,7 @@ var KernelTty = class {
|
|
|
14312
14888
|
const utf83 = (this.termios.c_iflag & IUTF8) !== 0;
|
|
14313
14889
|
const cells = utf83 ? dropped2.filter((b) => !isContinuation(b)).length : dropped2.length;
|
|
14314
14890
|
if (cells > 0 && this.termios.c_lflag & ECHO) {
|
|
14315
|
-
this.output(
|
|
14891
|
+
this.output(encoder4.encode("\b \b".repeat(cells)), false);
|
|
14316
14892
|
}
|
|
14317
14893
|
}
|
|
14318
14894
|
echo(byte) {
|
|
@@ -14564,7 +15140,7 @@ function terminalOf(ctx, fd) {
|
|
|
14564
15140
|
if (!tty) throw new KernelError("ENOTTY");
|
|
14565
15141
|
return tty;
|
|
14566
15142
|
}
|
|
14567
|
-
var json4 = (
|
|
15143
|
+
var json4 = (value2) => ({ ok: true, kind: "json", json: value2 });
|
|
14568
15144
|
var done3 = { ok: true, kind: "void" };
|
|
14569
15145
|
function sizeKey(rows, cols) {
|
|
14570
15146
|
return `${rows}x${cols}`;
|
|
@@ -14780,8 +15356,8 @@ var Semaphore = class {
|
|
|
14780
15356
|
gid;
|
|
14781
15357
|
mode;
|
|
14782
15358
|
waiters = [];
|
|
14783
|
-
constructor(
|
|
14784
|
-
this.value =
|
|
15359
|
+
constructor(value2, uid, gid, mode) {
|
|
15360
|
+
this.value = value2;
|
|
14785
15361
|
this.uid = uid;
|
|
14786
15362
|
this.gid = gid;
|
|
14787
15363
|
this.mode = mode;
|
|
@@ -15406,10 +15982,10 @@ var VfsNodes = class {
|
|
|
15406
15982
|
async onEntry(path, op) {
|
|
15407
15983
|
const key = await this.entryKey(path);
|
|
15408
15984
|
const run2 = (this.entries.get(key) ?? Promise.resolve()).then(op);
|
|
15409
|
-
const
|
|
15410
|
-
this.entries.set(key,
|
|
15411
|
-
void
|
|
15412
|
-
if (this.entries.get(key) ===
|
|
15985
|
+
const tail2 = run2.catch(() => void 0);
|
|
15986
|
+
this.entries.set(key, tail2);
|
|
15987
|
+
void tail2.then(() => {
|
|
15988
|
+
if (this.entries.get(key) === tail2) this.entries.delete(key);
|
|
15413
15989
|
});
|
|
15414
15990
|
return run2;
|
|
15415
15991
|
}
|
|
@@ -16034,11 +16610,11 @@ var MAX_READ = 1024 * 1024;
|
|
|
16034
16610
|
var WRITE_ACCESS = 3;
|
|
16035
16611
|
var KEYBOARD = /* @__PURE__ */ new Set([SIG.INT, SIG.QUIT, SIG.TSTP]);
|
|
16036
16612
|
var DEFAULT_UMASK2 = 18;
|
|
16037
|
-
function words(
|
|
16038
|
-
if (!Array.isArray(
|
|
16613
|
+
function words(value2) {
|
|
16614
|
+
if (!Array.isArray(value2) || !value2.every((w) => typeof w === "string")) {
|
|
16039
16615
|
throw new KernelError("EINVAL");
|
|
16040
16616
|
}
|
|
16041
|
-
return [...
|
|
16617
|
+
return [...value2];
|
|
16042
16618
|
}
|
|
16043
16619
|
var ESCAPES = { " ": "\\t", "\n": "\\n", "\r": "\\r" };
|
|
16044
16620
|
function clipboardLine(text) {
|
|
@@ -18011,7 +18587,7 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
18011
18587
|
clearTimeout(entry.timer);
|
|
18012
18588
|
void entry.final.cancel().catch(() => void 0);
|
|
18013
18589
|
};
|
|
18014
|
-
const
|
|
18590
|
+
const keyOf3 = (owner, method, url) => `${owner} ${method} ${url}`;
|
|
18015
18591
|
const hold = (key, chain2) => {
|
|
18016
18592
|
drop(key);
|
|
18017
18593
|
const mine = [...held.keys()].filter((k) => held.get(k)?.owner === chain2.owner);
|
|
@@ -18030,7 +18606,7 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
18030
18606
|
const method = followedWith(hop.status, chain2.method);
|
|
18031
18607
|
const away = target.origin !== new URL(hop.url).origin;
|
|
18032
18608
|
const print = away ? unauthorized(chain2.fingerprint) : chain2.fingerprint;
|
|
18033
|
-
hold(
|
|
18609
|
+
hold(keyOf3(chain2.owner, method, target.href), {
|
|
18034
18610
|
...chain2,
|
|
18035
18611
|
method,
|
|
18036
18612
|
fingerprint: print,
|
|
@@ -18044,7 +18620,7 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
18044
18620
|
},
|
|
18045
18621
|
...inner.websocket ? { websocket: inner.websocket.bind(inner) } : {},
|
|
18046
18622
|
async fetch(request, owner = KERNEL) {
|
|
18047
|
-
const key =
|
|
18623
|
+
const key = keyOf3(owner, request.method, request.url);
|
|
18048
18624
|
const waiting = held.get(key);
|
|
18049
18625
|
if (waiting && waiting.fingerprint === fingerprint(request.headers)) {
|
|
18050
18626
|
held.delete(key);
|
|
@@ -18069,10 +18645,10 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
18069
18645
|
var FRAGMENT = 16;
|
|
18070
18646
|
var MIN_VALUE = 8;
|
|
18071
18647
|
var MIN_BASE64 = 8;
|
|
18072
|
-
var
|
|
18648
|
+
var encoder5 = new TextEncoder();
|
|
18073
18649
|
var STD = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
18074
18650
|
function utf82(text) {
|
|
18075
|
-
return
|
|
18651
|
+
return encoder5.encode(text);
|
|
18076
18652
|
}
|
|
18077
18653
|
function base642(bytes, padded = true) {
|
|
18078
18654
|
let out = "";
|
|
@@ -18104,30 +18680,30 @@ function embedded(bytes, offset) {
|
|
|
18104
18680
|
const last = Math.floor(8 * (offset + bytes.length) / 6);
|
|
18105
18681
|
return encoded.slice(first, last);
|
|
18106
18682
|
}
|
|
18107
|
-
function unicode(
|
|
18683
|
+
function unicode(value2, upper) {
|
|
18108
18684
|
let out = "";
|
|
18109
|
-
for (let i = 0; i <
|
|
18110
|
-
const unit =
|
|
18685
|
+
for (let i = 0; i < value2.length; i++) {
|
|
18686
|
+
const unit = value2.charCodeAt(i);
|
|
18111
18687
|
if (unit === 34) out += '\\"';
|
|
18112
18688
|
else if (unit === 92) out += "\\\\";
|
|
18113
18689
|
else if (unit < 32 || unit > 126) {
|
|
18114
18690
|
const code = unit.toString(16).padStart(4, "0");
|
|
18115
18691
|
out += `\\u${upper ? code.toUpperCase() : code}`;
|
|
18116
|
-
} else out +=
|
|
18692
|
+
} else out += value2[i];
|
|
18117
18693
|
}
|
|
18118
18694
|
return out;
|
|
18119
18695
|
}
|
|
18120
|
-
function percent(
|
|
18696
|
+
function percent(value2) {
|
|
18121
18697
|
let component;
|
|
18122
18698
|
try {
|
|
18123
|
-
component = encodeURIComponent(
|
|
18699
|
+
component = encodeURIComponent(value2);
|
|
18124
18700
|
} catch {
|
|
18125
18701
|
return [];
|
|
18126
18702
|
}
|
|
18127
18703
|
const lower = component.replace(/%[0-9A-F]{2}/g, (escape) => escape.toLowerCase());
|
|
18128
18704
|
const plus = component.replace(/%20/g, "+");
|
|
18129
18705
|
let form = "";
|
|
18130
|
-
for (const byte of utf82(
|
|
18706
|
+
for (const byte of utf82(value2)) {
|
|
18131
18707
|
const char = String.fromCharCode(byte);
|
|
18132
18708
|
if (/[A-Za-z0-9*\-._]/.test(char)) form += char;
|
|
18133
18709
|
else if (byte === 32) form += "+";
|
|
@@ -18135,8 +18711,8 @@ function percent(value) {
|
|
|
18135
18711
|
}
|
|
18136
18712
|
return [component, lower, plus, form];
|
|
18137
18713
|
}
|
|
18138
|
-
function html(
|
|
18139
|
-
return
|
|
18714
|
+
function html(value2, apostrophe) {
|
|
18715
|
+
return value2.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, apostrophe);
|
|
18140
18716
|
}
|
|
18141
18717
|
function encodings(bytes) {
|
|
18142
18718
|
const standard = [base642(bytes), base642(bytes, false)];
|
|
@@ -18146,9 +18722,9 @@ function encodings(bytes) {
|
|
|
18146
18722
|
}
|
|
18147
18723
|
return [...standard, ...standard.map(urlSafe)];
|
|
18148
18724
|
}
|
|
18149
|
-
function shapes(
|
|
18150
|
-
const raw = utf82(
|
|
18151
|
-
const seen = /* @__PURE__ */ new Set([
|
|
18725
|
+
function shapes(value2) {
|
|
18726
|
+
const raw = utf82(value2);
|
|
18727
|
+
const seen = /* @__PURE__ */ new Set([value2]);
|
|
18152
18728
|
const out = [];
|
|
18153
18729
|
if (raw.length < FRAGMENT) out.push({ bytes: raw, form: "raw" });
|
|
18154
18730
|
for (let offset = 0; raw.length >= FRAGMENT && offset + FRAGMENT <= raw.length; offset++) {
|
|
@@ -18159,17 +18735,17 @@ function shapes(value) {
|
|
|
18159
18735
|
seen.add(text);
|
|
18160
18736
|
out.push({ bytes: utf82(text), form });
|
|
18161
18737
|
};
|
|
18162
|
-
const json5 = JSON.stringify(
|
|
18738
|
+
const json5 = JSON.stringify(value2).slice(1, -1);
|
|
18163
18739
|
for (const text of [
|
|
18164
18740
|
json5,
|
|
18165
18741
|
json5.replace(/\//g, "\\/"),
|
|
18166
|
-
unicode(
|
|
18167
|
-
unicode(
|
|
18742
|
+
unicode(value2, false),
|
|
18743
|
+
unicode(value2, true)
|
|
18168
18744
|
]) {
|
|
18169
18745
|
add(text, "json");
|
|
18170
18746
|
}
|
|
18171
|
-
for (const text of percent(
|
|
18172
|
-
for (const text of [html(
|
|
18747
|
+
for (const text of percent(value2)) add(text, "percent");
|
|
18748
|
+
for (const text of [html(value2, "'"), html(value2, "'")]) add(text, "html");
|
|
18173
18749
|
for (const text of encodings(raw)) add(text, "base64");
|
|
18174
18750
|
add(hex2(raw), "hex");
|
|
18175
18751
|
add(hex2(raw).toUpperCase(), "hex");
|
|
@@ -18320,15 +18896,15 @@ function resolve(c, input, start2, end, source) {
|
|
|
18320
18896
|
growing: false
|
|
18321
18897
|
};
|
|
18322
18898
|
}
|
|
18323
|
-
const
|
|
18899
|
+
const value2 = c.values[source.secret];
|
|
18324
18900
|
let stop = end;
|
|
18325
18901
|
let at = source.offset + FRAGMENT;
|
|
18326
|
-
while (stop < input.length && at <
|
|
18902
|
+
while (stop < input.length && at < value2.length && input[stop] === value2[at]) {
|
|
18327
18903
|
stop++;
|
|
18328
18904
|
at++;
|
|
18329
18905
|
}
|
|
18330
|
-
const form = source.offset === 0 && at ===
|
|
18331
|
-
const growing = stop === input.length && at <
|
|
18906
|
+
const form = source.offset === 0 && at === value2.length ? "raw" : "fragment";
|
|
18907
|
+
const growing = stop === input.length && at < value2.length;
|
|
18332
18908
|
return { start: start2, end: stop, secret: source.secret, form, rank: RANK[form], growing };
|
|
18333
18909
|
}
|
|
18334
18910
|
function keep(best, candidate) {
|
|
@@ -18376,7 +18952,7 @@ function count(c, hits, candidate) {
|
|
|
18376
18952
|
hit.count += 1;
|
|
18377
18953
|
hits.set(key, hit);
|
|
18378
18954
|
}
|
|
18379
|
-
function
|
|
18955
|
+
function concat6(parts2) {
|
|
18380
18956
|
let length2 = 0;
|
|
18381
18957
|
for (const part of parts2) length2 += part.length;
|
|
18382
18958
|
const out = new Uint8Array(length2);
|
|
@@ -18418,7 +18994,7 @@ function pass(c, input, final) {
|
|
|
18418
18994
|
pos = candidate.end;
|
|
18419
18995
|
}
|
|
18420
18996
|
parts2.push(input.subarray(pos, cut));
|
|
18421
|
-
return { output:
|
|
18997
|
+
return { output: concat6(parts2), cut, hits };
|
|
18422
18998
|
}
|
|
18423
18999
|
function merge(into, from) {
|
|
18424
19000
|
for (const [key, hit] of from) {
|
|
@@ -18461,7 +19037,7 @@ function compile(secrets, options = {}) {
|
|
|
18461
19037
|
};
|
|
18462
19038
|
return {
|
|
18463
19039
|
push(chunk2) {
|
|
18464
|
-
pending =
|
|
19040
|
+
pending = concat6([pending, chunk2]);
|
|
18465
19041
|
return run2(false);
|
|
18466
19042
|
},
|
|
18467
19043
|
idle() {
|
|
@@ -18481,9 +19057,9 @@ function compile(secrets, options = {}) {
|
|
|
18481
19057
|
// src/kernel/scrub-file.ts
|
|
18482
19058
|
var SCRUB_IDLE_MS = 50;
|
|
18483
19059
|
var SCRUB_NONBLOCK_MAX = 64 * 1024;
|
|
18484
|
-
var
|
|
19060
|
+
var encoder6 = new TextEncoder();
|
|
18485
19061
|
function scrubberOf(secrets) {
|
|
18486
|
-
const usable = secrets.filter((s) =>
|
|
19062
|
+
const usable = secrets.filter((s) => encoder6.encode(s.value).length >= MIN_VALUE);
|
|
18487
19063
|
return usable.length > 0 ? compile(usable, { idleMs: SCRUB_IDLE_MS }) : void 0;
|
|
18488
19064
|
}
|
|
18489
19065
|
async function writeAll3(file, bytes) {
|
|
@@ -18501,7 +19077,7 @@ function interrupted2(err) {
|
|
|
18501
19077
|
function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
18502
19078
|
const file = inner.file;
|
|
18503
19079
|
const stream2 = scrubber.stream();
|
|
18504
|
-
let
|
|
19080
|
+
let tail2 = Promise.resolve();
|
|
18505
19081
|
let pending = 0;
|
|
18506
19082
|
let busy = false;
|
|
18507
19083
|
let timer;
|
|
@@ -18520,7 +19096,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
|
18520
19096
|
const later = (bytes) => {
|
|
18521
19097
|
if (bytes.length === 0) return;
|
|
18522
19098
|
pending += 1;
|
|
18523
|
-
|
|
19099
|
+
tail2 = tail2.then(() => writeAll3(file, bytes)).catch((err) => {
|
|
18524
19100
|
if (failed3 === void 0) failed3 = err;
|
|
18525
19101
|
}).finally(() => {
|
|
18526
19102
|
pending -= 1;
|
|
@@ -18671,7 +19247,7 @@ var SEALED_OPS = /* @__PURE__ */ new Set([
|
|
|
18671
19247
|
"cancel",
|
|
18672
19248
|
"materialize"
|
|
18673
19249
|
]);
|
|
18674
|
-
var
|
|
19250
|
+
var encoder7 = new TextEncoder();
|
|
18675
19251
|
var decoder3 = new TextDecoder("utf-8", { fatal: true });
|
|
18676
19252
|
function parseSealed(bytes) {
|
|
18677
19253
|
try {
|
|
@@ -18700,8 +19276,8 @@ function materializable(req) {
|
|
|
18700
19276
|
function errorReply(code, message3) {
|
|
18701
19277
|
return { v: 1, error: { code, message: message3 } };
|
|
18702
19278
|
}
|
|
18703
|
-
function isRecord(
|
|
18704
|
-
return typeof
|
|
19279
|
+
function isRecord(value2) {
|
|
19280
|
+
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
18705
19281
|
}
|
|
18706
19282
|
function serialized(reply) {
|
|
18707
19283
|
let plain2;
|
|
@@ -18752,7 +19328,7 @@ var SealedChannel = class {
|
|
|
18752
19328
|
await this.broker.tickets.record(req, reply, caller.pid);
|
|
18753
19329
|
if (this.inflight !== flight) return;
|
|
18754
19330
|
this.inflight = void 0;
|
|
18755
|
-
if (reply) this.reply =
|
|
19331
|
+
if (reply) this.reply = encoder7.encode(serialized(reply));
|
|
18756
19332
|
});
|
|
18757
19333
|
this.inflight = flight;
|
|
18758
19334
|
return length2;
|
|
@@ -19344,8 +19920,8 @@ function umountCall(target, flags2) {
|
|
|
19344
19920
|
var FSTAB_PATH = "/etc/fstab";
|
|
19345
19921
|
var FSTAB_RETRIES = [1e3, 4e3, 16e3];
|
|
19346
19922
|
var FINAL = /* @__PURE__ */ new Set(["EINVAL", "EBUSY", "EPERM", "EACCES"]);
|
|
19347
|
-
function unescape(
|
|
19348
|
-
return
|
|
19923
|
+
function unescape(field4) {
|
|
19924
|
+
return field4.replace(
|
|
19349
19925
|
/\\([0-7]{3})/g,
|
|
19350
19926
|
(_, octal) => String.fromCharCode(Number.parseInt(octal, 8))
|
|
19351
19927
|
);
|
|
@@ -19541,9 +20117,9 @@ var HostfsClient = class {
|
|
|
19541
20117
|
let buffered = "";
|
|
19542
20118
|
try {
|
|
19543
20119
|
for (; ; ) {
|
|
19544
|
-
const { done: done4, value } = await reader.read();
|
|
20120
|
+
const { done: done4, value: value2 } = await reader.read();
|
|
19545
20121
|
if (done4) return;
|
|
19546
|
-
buffered += decoder4.decode(
|
|
20122
|
+
buffered += decoder4.decode(value2, { stream: true });
|
|
19547
20123
|
let end = buffered.indexOf("\n");
|
|
19548
20124
|
while (end >= 0) {
|
|
19549
20125
|
const line = buffered.slice(0, end).trim();
|
|
@@ -19805,10 +20381,10 @@ function timed(transport, ms) {
|
|
|
19805
20381
|
reject(fsError2("ENOTCONN", why));
|
|
19806
20382
|
}, ms);
|
|
19807
20383
|
running.then(
|
|
19808
|
-
(
|
|
20384
|
+
(value2) => {
|
|
19809
20385
|
clearTimeout(timer);
|
|
19810
|
-
if (expired) late?.(
|
|
19811
|
-
resolve2(
|
|
20386
|
+
if (expired) late?.(value2);
|
|
20387
|
+
resolve2(value2);
|
|
19812
20388
|
},
|
|
19813
20389
|
(err) => {
|
|
19814
20390
|
clearTimeout(timer);
|
|
@@ -20223,9 +20799,9 @@ var ChunkedBytes = class {
|
|
|
20223
20799
|
if (size < this.size) {
|
|
20224
20800
|
const keep2 = Math.ceil(size / CHUNK3);
|
|
20225
20801
|
this.chunks.length = Math.min(this.chunks.length, keep2);
|
|
20226
|
-
const
|
|
20802
|
+
const tail2 = this.chunks[keep2 - 1];
|
|
20227
20803
|
const from = size - (keep2 - 1) * CHUNK3;
|
|
20228
|
-
if (
|
|
20804
|
+
if (tail2 && from < tail2.length) tail2.fill(0, from);
|
|
20229
20805
|
}
|
|
20230
20806
|
this.size = size;
|
|
20231
20807
|
}
|
|
@@ -20240,8 +20816,8 @@ var ChunkedBytes = class {
|
|
|
20240
20816
|
};
|
|
20241
20817
|
|
|
20242
20818
|
// src/mount/tmpfs.ts
|
|
20243
|
-
function idOption2(
|
|
20244
|
-
return
|
|
20819
|
+
function idOption2(value2) {
|
|
20820
|
+
return value2 !== void 0 && /^\d+$/.test(value2) ? Number(value2) : 0;
|
|
20245
20821
|
}
|
|
20246
20822
|
function created2(ino, kind, mode, from, owner) {
|
|
20247
20823
|
const now = Date.now();
|
|
@@ -20476,7 +21052,7 @@ function importedMemory(bytes) {
|
|
|
20476
21052
|
const count2 = u32();
|
|
20477
21053
|
for (let i = 0; i < count2; i++) {
|
|
20478
21054
|
const module = name2();
|
|
20479
|
-
const
|
|
21055
|
+
const field4 = name2();
|
|
20480
21056
|
const kind = bytes[at++];
|
|
20481
21057
|
if (kind === 0) u32();
|
|
20482
21058
|
else if (kind === 1) {
|
|
@@ -20484,7 +21060,7 @@ function importedMemory(bytes) {
|
|
|
20484
21060
|
limits();
|
|
20485
21061
|
} else if (kind === 2) {
|
|
20486
21062
|
const l = limits();
|
|
20487
|
-
return { module, name:
|
|
21063
|
+
return { module, name: field4, ...l };
|
|
20488
21064
|
} else if (kind === 3) at += 2;
|
|
20489
21065
|
else if (kind === 4) {
|
|
20490
21066
|
at++;
|
|
@@ -20575,12 +21151,12 @@ function readImports(r, types) {
|
|
|
20575
21151
|
const foreign = {};
|
|
20576
21152
|
for (let i = r.u32(); i > 0; i--) {
|
|
20577
21153
|
const module = r.name();
|
|
20578
|
-
const
|
|
21154
|
+
const field4 = r.name();
|
|
20579
21155
|
const kind = r.byte();
|
|
20580
21156
|
if (kind !== 0) skipImport(r, kind);
|
|
20581
21157
|
else {
|
|
20582
21158
|
const type = types[r.u32()] ?? "other";
|
|
20583
|
-
if (!RESERVED_NAMESPACES.has(module)) (foreign[module] ??= {})[
|
|
21159
|
+
if (!RESERVED_NAMESPACES.has(module)) (foreign[module] ??= {})[field4] = type;
|
|
20584
21160
|
}
|
|
20585
21161
|
}
|
|
20586
21162
|
return foreign;
|
|
@@ -21093,7 +21669,7 @@ var LAYOUT = [
|
|
|
21093
21669
|
];
|
|
21094
21670
|
var LOAD_SAMPLE_MS = 5e3;
|
|
21095
21671
|
var LOAD_WINDOWS_MS = [6e4, 3e5, 9e5];
|
|
21096
|
-
var
|
|
21672
|
+
var encoder8 = new TextEncoder();
|
|
21097
21673
|
var USERS_MODES = ["off", "report", "enforce"];
|
|
21098
21674
|
function usersMode(mode = "off") {
|
|
21099
21675
|
if (USERS_MODES.includes(mode)) return mode;
|
|
@@ -21153,10 +21729,10 @@ function shebangCommand(words2) {
|
|
|
21153
21729
|
const arg2 = words2.slice(1).join(" ");
|
|
21154
21730
|
return { interp: words2[0], args: arg2 ? [arg2] : [] };
|
|
21155
21731
|
}
|
|
21156
|
-
const
|
|
21157
|
-
const [interp, ...rest2] = words2.slice(
|
|
21732
|
+
const split3 = words2[1] === "-S";
|
|
21733
|
+
const [interp, ...rest2] = words2.slice(split3 ? 2 : 1);
|
|
21158
21734
|
const arg = rest2.join(" ");
|
|
21159
|
-
return { interp, args:
|
|
21735
|
+
return { interp, args: split3 ? rest2 : arg ? [arg] : [] };
|
|
21160
21736
|
}
|
|
21161
21737
|
function interpreter(head) {
|
|
21162
21738
|
const words2 = shebang(head);
|
|
@@ -21167,9 +21743,9 @@ function interpreter(head) {
|
|
|
21167
21743
|
}
|
|
21168
21744
|
function expandDefaults(defaults, env) {
|
|
21169
21745
|
const out = {};
|
|
21170
|
-
for (const [key,
|
|
21746
|
+
for (const [key, value2] of Object.entries(defaults ?? {})) {
|
|
21171
21747
|
let missing4 = false;
|
|
21172
|
-
const expanded =
|
|
21748
|
+
const expanded = value2.replace(ENV_REFERENCE, (_, name2) => {
|
|
21173
21749
|
const set3 = Object.hasOwn(env, name2) ? env[name2] : void 0;
|
|
21174
21750
|
if (set3 === void 0) missing4 = true;
|
|
21175
21751
|
return set3 ?? "";
|
|
@@ -21211,7 +21787,7 @@ function childHandle(handle) {
|
|
|
21211
21787
|
onState: (listener) => handle.onState(listener)
|
|
21212
21788
|
};
|
|
21213
21789
|
}
|
|
21214
|
-
function
|
|
21790
|
+
function concat7(chunks2) {
|
|
21215
21791
|
const out = new Uint8Array(chunks2.reduce((n, chunk2) => n + chunk2.length, 0));
|
|
21216
21792
|
let offset = 0;
|
|
21217
21793
|
for (const chunk2 of chunks2) {
|
|
@@ -21316,6 +21892,8 @@ var Launcher = class {
|
|
|
21316
21892
|
fileWatches;
|
|
21317
21893
|
nextPid = 1e3;
|
|
21318
21894
|
boot = Date.now();
|
|
21895
|
+
bootId = crypto.randomUUID();
|
|
21896
|
+
cron;
|
|
21319
21897
|
terminals = 0;
|
|
21320
21898
|
constructor(options) {
|
|
21321
21899
|
this.usersMode = usersMode(options.users);
|
|
@@ -21446,6 +22024,7 @@ var Launcher = class {
|
|
|
21446
22024
|
approve: options.approve,
|
|
21447
22025
|
timeoutMs: options.sudoTimeoutMs
|
|
21448
22026
|
});
|
|
22027
|
+
this.cron = this.cronService(options.cron);
|
|
21449
22028
|
void this.unlinked.sweep("/");
|
|
21450
22029
|
this.watchers.watch(
|
|
21451
22030
|
[this.modulesDir, this.pnpmHome, ...this.appended],
|
|
@@ -21457,6 +22036,38 @@ var Launcher = class {
|
|
|
21457
22036
|
this.resetCatalogs();
|
|
21458
22037
|
});
|
|
21459
22038
|
}
|
|
22039
|
+
cronService(options = {}) {
|
|
22040
|
+
return new CronService({
|
|
22041
|
+
fs: this.fs,
|
|
22042
|
+
owners: this.owners,
|
|
22043
|
+
lock: options.lock ?? "slicc-kernel-cron",
|
|
22044
|
+
bootId: this.bootId,
|
|
22045
|
+
...options.clock ? { clock: options.clock } : {},
|
|
22046
|
+
locks: cronLocks(),
|
|
22047
|
+
ready: () => this.fstab,
|
|
22048
|
+
lookup: (name2) => this.users.lookup(name2),
|
|
22049
|
+
watch: async (paths, notify) => {
|
|
22050
|
+
const local = this.watchers.watch(paths, { recursive: true }, () => notify());
|
|
22051
|
+
const remote = await this.watchFiles(paths, notify);
|
|
22052
|
+
return () => {
|
|
22053
|
+
local();
|
|
22054
|
+
remote();
|
|
22055
|
+
};
|
|
22056
|
+
},
|
|
22057
|
+
run: async ({ account, argv, cwd, env, output }) => {
|
|
22058
|
+
const ended = await this.run(argv, {
|
|
22059
|
+
user: account,
|
|
22060
|
+
cwd,
|
|
22061
|
+
env,
|
|
22062
|
+
login: true,
|
|
22063
|
+
collect: false,
|
|
22064
|
+
onStdout: output,
|
|
22065
|
+
onStderr: output
|
|
22066
|
+
});
|
|
22067
|
+
return { status: ended.status, ...signalField(ended.signal) };
|
|
22068
|
+
}
|
|
22069
|
+
});
|
|
22070
|
+
}
|
|
21460
22071
|
get owners() {
|
|
21461
22072
|
return this.usersMode !== "off";
|
|
21462
22073
|
}
|
|
@@ -21816,10 +22427,10 @@ var Launcher = class {
|
|
|
21816
22427
|
if (!swap) throw new SpawnError("EACCES");
|
|
21817
22428
|
const secrets = [];
|
|
21818
22429
|
for (const [name2, placeholder] of Object.entries(swap.placeholders)) {
|
|
21819
|
-
const
|
|
21820
|
-
if (
|
|
21821
|
-
env[name2] =
|
|
21822
|
-
secrets.push({ name: name2, value, placeholder });
|
|
22430
|
+
const value2 = swap.values[name2];
|
|
22431
|
+
if (value2 === void 0 || env[name2] !== placeholder) continue;
|
|
22432
|
+
env[name2] = value2;
|
|
22433
|
+
secrets.push({ name: name2, value: value2, placeholder });
|
|
21823
22434
|
}
|
|
21824
22435
|
const scrub = scrubberOf(secrets);
|
|
21825
22436
|
return { env, pid, cwd: booked.cwd, ...scrub ? { scrub } : {} };
|
|
@@ -21926,7 +22537,7 @@ var Launcher = class {
|
|
|
21926
22537
|
if (hit !== void 0) return hit;
|
|
21927
22538
|
const revocations = this.revocations;
|
|
21928
22539
|
const loading2 = load();
|
|
21929
|
-
const found = loading2.then(({ value }) =>
|
|
22540
|
+
const found = loading2.then(({ value: value2 }) => value2);
|
|
21930
22541
|
cache.set(key, found);
|
|
21931
22542
|
const drop = () => {
|
|
21932
22543
|
if (cache.get(key) === found) cache.delete(key);
|
|
@@ -22793,6 +23404,7 @@ var Launcher = class {
|
|
|
22793
23404
|
for (const holds2 of this.held) holds2.revoke(at);
|
|
22794
23405
|
}
|
|
22795
23406
|
unmountAll() {
|
|
23407
|
+
this.cron.stop();
|
|
22796
23408
|
this.booting.abort();
|
|
22797
23409
|
const targets = this.mounts.list().map((m) => m.target);
|
|
22798
23410
|
for (const target of targets.sort((a, b) => b.length - a.length)) this.umount(target, true);
|
|
@@ -22859,7 +23471,9 @@ var Launcher = class {
|
|
|
22859
23471
|
if (this.owners) await this.stampLayout();
|
|
22860
23472
|
if (this.owners) await this.sudoer.provision();
|
|
22861
23473
|
await writeCaFile(this.base, this.ca).catch(() => void 0);
|
|
23474
|
+
await this.cron.provision().catch(() => void 0);
|
|
22862
23475
|
this.fstab = this.mountFstab();
|
|
23476
|
+
void this.cron.start();
|
|
22863
23477
|
}
|
|
22864
23478
|
async mountFstab() {
|
|
22865
23479
|
const text = await this.base.readFile(FSTAB_PATH).catch(() => "");
|
|
@@ -22881,9 +23495,9 @@ var Launcher = class {
|
|
|
22881
23495
|
}
|
|
22882
23496
|
);
|
|
22883
23497
|
}
|
|
22884
|
-
environment(cwd, extra, account) {
|
|
23498
|
+
environment(cwd, extra, account, login = false) {
|
|
22885
23499
|
const env = {
|
|
22886
|
-
...this.env,
|
|
23500
|
+
...login ? networkEnv(this.hostname) : this.env,
|
|
22887
23501
|
...userEnv(account, this.pnpmHome),
|
|
22888
23502
|
PWD: cwd,
|
|
22889
23503
|
...extra
|
|
@@ -23035,7 +23649,7 @@ var Launcher = class {
|
|
|
23035
23649
|
},
|
|
23036
23650
|
account
|
|
23037
23651
|
);
|
|
23038
|
-
const report = (message3) => options.onData(
|
|
23652
|
+
const report = (message3) => options.onData(encoder8.encode(`${message3}\r
|
|
23039
23653
|
`));
|
|
23040
23654
|
const handle = await this.launch(planned, {
|
|
23041
23655
|
env,
|
|
@@ -23063,7 +23677,7 @@ var Launcher = class {
|
|
|
23063
23677
|
tagOption(options.tag);
|
|
23064
23678
|
const account = await this.account(options.user);
|
|
23065
23679
|
const { cwd, file, planned } = await this.starting(argv, options.cwd, account, options.tag);
|
|
23066
|
-
const env = this.environment(cwd, options.env, account);
|
|
23680
|
+
const env = this.environment(cwd, options.env, account, options.login);
|
|
23067
23681
|
const out = [];
|
|
23068
23682
|
const err = [];
|
|
23069
23683
|
const keep2 = options.collect !== false;
|
|
@@ -23073,13 +23687,13 @@ var Launcher = class {
|
|
|
23073
23687
|
};
|
|
23074
23688
|
const stdout = collect(out, options.onStdout);
|
|
23075
23689
|
const stderr = collect(err, options.onStderr);
|
|
23076
|
-
const report = (message3) => stderr(
|
|
23690
|
+
const report = (message3) => stderr(encoder8.encode(`${message3}
|
|
23077
23691
|
`));
|
|
23078
23692
|
if (!planned) {
|
|
23079
23693
|
const directory = await this.directory(file, this.fs.resolvePath(cwd, file));
|
|
23080
23694
|
report(`${file}: ${directory ? "Is a directory" : "command not found"}`);
|
|
23081
23695
|
const status2 = directory ? NOT_EXECUTABLE : NOT_FOUND;
|
|
23082
|
-
return { status: status2, stdout:
|
|
23696
|
+
return { status: status2, stdout: concat7(out), stderr: concat7(err) };
|
|
23083
23697
|
}
|
|
23084
23698
|
const fds = new FdTable();
|
|
23085
23699
|
fds.installAt(0, options.stdin ? bytesSource(options.stdin) : deviceFile("null"));
|
|
@@ -23097,9 +23711,12 @@ var Launcher = class {
|
|
|
23097
23711
|
options.onStarted?.(handle.pid);
|
|
23098
23712
|
const status = await handle.exited;
|
|
23099
23713
|
const signal = handle.termsig();
|
|
23100
|
-
return { status, ...signal ? { signal } : {}, stdout:
|
|
23714
|
+
return { status, ...signal ? { signal } : {}, stdout: concat7(out), stderr: concat7(err) };
|
|
23101
23715
|
}
|
|
23102
23716
|
};
|
|
23717
|
+
function cronLocks() {
|
|
23718
|
+
return globalThis.navigator?.locks;
|
|
23719
|
+
}
|
|
23103
23720
|
|
|
23104
23721
|
// src/node/loopback.ts
|
|
23105
23722
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -23139,10 +23756,10 @@ function hextets2(address) {
|
|
|
23139
23756
|
const [a, b, c, d] = dotted.split(".").map(Number);
|
|
23140
23757
|
text = `${address.slice(0, -dotted.length)}${(a << 8 | b).toString(16)}:${(c << 8 | d).toString(16)}`;
|
|
23141
23758
|
}
|
|
23142
|
-
const [head = "",
|
|
23759
|
+
const [head = "", tail2] = text.split("::");
|
|
23143
23760
|
const part = (side) => side ? side.split(":").map((w) => Number.parseInt(w, 16)) : [];
|
|
23144
23761
|
const left = part(head);
|
|
23145
|
-
const right =
|
|
23762
|
+
const right = tail2 === void 0 ? [] : part(tail2);
|
|
23146
23763
|
const gap = Array(8 - left.length - right.length).fill(0);
|
|
23147
23764
|
return [...left, ...gap, ...right];
|
|
23148
23765
|
}
|
|
@@ -23870,7 +24487,7 @@ function dialStream(port, onClose) {
|
|
|
23870
24487
|
|
|
23871
24488
|
// src/client/loopback-fetch.ts
|
|
23872
24489
|
var OWN_HEADERS2 = /* @__PURE__ */ new Set(["host", "connection", "content-length", "transfer-encoding"]);
|
|
23873
|
-
var
|
|
24490
|
+
var encoder9 = new TextEncoder();
|
|
23874
24491
|
var latin12 = new TextDecoder("latin1");
|
|
23875
24492
|
var ByteSource = class {
|
|
23876
24493
|
buffered = new Uint8Array(0);
|
|
@@ -23879,16 +24496,16 @@ var ByteSource = class {
|
|
|
23879
24496
|
this.reader = reader;
|
|
23880
24497
|
}
|
|
23881
24498
|
async more() {
|
|
23882
|
-
const { done: done4, value } = await this.reader.read();
|
|
24499
|
+
const { done: done4, value: value2 } = await this.reader.read();
|
|
23883
24500
|
if (done4) return false;
|
|
23884
|
-
const joined3 = new Uint8Array(this.buffered.length +
|
|
24501
|
+
const joined3 = new Uint8Array(this.buffered.length + value2.length);
|
|
23885
24502
|
joined3.set(this.buffered);
|
|
23886
|
-
joined3.set(
|
|
24503
|
+
joined3.set(value2, this.buffered.length);
|
|
23887
24504
|
this.buffered = joined3;
|
|
23888
24505
|
return true;
|
|
23889
24506
|
}
|
|
23890
24507
|
async until(marker) {
|
|
23891
|
-
const needle =
|
|
24508
|
+
const needle = encoder9.encode(marker);
|
|
23892
24509
|
for (; ; ) {
|
|
23893
24510
|
const at = indexOf(this.buffered, needle);
|
|
23894
24511
|
if (at >= 0) return this.take(at + needle.length);
|
|
@@ -23991,12 +24608,12 @@ async function requestBytes(request) {
|
|
|
23991
24608
|
const url = new URL(request.url);
|
|
23992
24609
|
const body = request.body ? new Uint8Array(await request.arrayBuffer()) : void 0;
|
|
23993
24610
|
const lines2 = [`${request.method} ${url.pathname}${url.search} HTTP/1.1`, `Host: ${url.host}`];
|
|
23994
|
-
request.headers.forEach((
|
|
23995
|
-
if (!OWN_HEADERS2.has(name2)) lines2.push(`${name2}: ${
|
|
24611
|
+
request.headers.forEach((value2, name2) => {
|
|
24612
|
+
if (!OWN_HEADERS2.has(name2)) lines2.push(`${name2}: ${value2}`);
|
|
23996
24613
|
});
|
|
23997
24614
|
if (body) lines2.push(`Content-Length: ${body.length}`);
|
|
23998
24615
|
lines2.push("Connection: close", "", "");
|
|
23999
|
-
const head =
|
|
24616
|
+
const head = encoder9.encode(lines2.join("\r\n"));
|
|
24000
24617
|
const out = new Uint8Array(head.length + (body?.length ?? 0));
|
|
24001
24618
|
out.set(head);
|
|
24002
24619
|
if (body) out.set(body, head.length);
|
|
@@ -24050,8 +24667,8 @@ var KernelCallError = class extends Error {
|
|
|
24050
24667
|
this.code = code;
|
|
24051
24668
|
}
|
|
24052
24669
|
};
|
|
24053
|
-
var
|
|
24054
|
-
var bytesOf2 = (data) => typeof data === "string" ?
|
|
24670
|
+
var encoder10 = new TextEncoder();
|
|
24671
|
+
var bytesOf2 = (data) => typeof data === "string" ? encoder10.encode(data) : data;
|
|
24055
24672
|
var UNAVAILABLE = {
|
|
24056
24673
|
manualRedirects: false,
|
|
24057
24674
|
encodedBodies: false,
|
|
@@ -24071,7 +24688,7 @@ async function holdLock(locks) {
|
|
|
24071
24688
|
await granted2.promise;
|
|
24072
24689
|
return { name: name2, release: () => held.resolve() };
|
|
24073
24690
|
}
|
|
24074
|
-
function
|
|
24691
|
+
function concat8(chunks2) {
|
|
24075
24692
|
const out = new Uint8Array(chunks2.reduce((n, c) => n + c.length, 0));
|
|
24076
24693
|
let at = 0;
|
|
24077
24694
|
for (const chunk2 of chunks2) {
|
|
@@ -24298,7 +24915,7 @@ async function runOn(channel, argv, opts) {
|
|
|
24298
24915
|
onStderr: tee(2, onStderr)
|
|
24299
24916
|
});
|
|
24300
24917
|
const { status, signal } = await child.ended;
|
|
24301
|
-
const text = (fd) => new TextDecoder().decode(
|
|
24918
|
+
const text = (fd) => new TextDecoder().decode(concat8(chunks2[fd]));
|
|
24302
24919
|
return {
|
|
24303
24920
|
pid: child.pid,
|
|
24304
24921
|
status,
|
|
@@ -24547,6 +25164,12 @@ function textOf(on) {
|
|
|
24547
25164
|
const decoder4 = new TextDecoder();
|
|
24548
25165
|
return (bytes) => on(decoder4.decode(bytes, { stream: true }));
|
|
24549
25166
|
}
|
|
25167
|
+
var cronLocks2 = /* @__PURE__ */ new WeakMap();
|
|
25168
|
+
function cronLock(root) {
|
|
25169
|
+
let lock = cronLocks2.get(root);
|
|
25170
|
+
if (!lock) cronLocks2.set(root, lock = `slicc-kernel-cron:${crypto.randomUUID()}`);
|
|
25171
|
+
return lock;
|
|
25172
|
+
}
|
|
24550
25173
|
async function createNodeKernel(options = {}) {
|
|
24551
25174
|
const root = options.root ?? memoryRoot();
|
|
24552
25175
|
const fs = new OpfsFs(root, void 0, void 0, { ranged: isMemoryRoot(root) });
|
|
@@ -24583,7 +25206,8 @@ async function createNodeKernel(options = {}) {
|
|
|
24583
25206
|
...options.protect ? { protect: options.protect } : {},
|
|
24584
25207
|
...options.sealed ? { sealed: options.sealed } : {},
|
|
24585
25208
|
...options.clipboard ? { clipboard: options.clipboard } : {},
|
|
24586
|
-
...options.approve ? { approve: options.approve } : {}
|
|
25209
|
+
...options.approve ? { approve: options.approve } : {},
|
|
25210
|
+
cron: { lock: cronLock(root), ...options.cron?.clock ? { clock: options.cron.clock } : {} }
|
|
24587
25211
|
});
|
|
24588
25212
|
await launcher.prepare();
|
|
24589
25213
|
const guard2 = (work) => new Promise((resolve2, reject) => {
|