@ai-ecoverse/slicc-kernel 1.106.3 → 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 +17 -1
- package/dist/kernel-worker.js +1050 -441
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +1 -1
- package/dist/node.js +856 -241
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +1 -1
- 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/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
|
|
|
@@ -12685,13 +13252,13 @@ function errno(code, message3) {
|
|
|
12685
13252
|
function requestHead(method, url, headers, extra, first = []) {
|
|
12686
13253
|
if (!TOKEN3.test(method)) throw errno("EINVAL", `method ${method}`);
|
|
12687
13254
|
const lines2 = [`${method} ${url.pathname}${url.search} HTTP/1.1`, `host: ${url.host}`];
|
|
12688
|
-
for (const [name2,
|
|
12689
|
-
for (const [name2,
|
|
13255
|
+
for (const [name2, value2] of first) lines2.push(`${name2}: ${value2}`);
|
|
13256
|
+
for (const [name2, value2] of headers) {
|
|
12690
13257
|
if (OWN_HEADERS.has(name2.toLowerCase())) continue;
|
|
12691
|
-
if (!TOKEN3.test(name2) || !SAFE_VALUE.test(
|
|
12692
|
-
lines2.push(`${name2}: ${
|
|
13258
|
+
if (!TOKEN3.test(name2) || !SAFE_VALUE.test(value2)) throw errno("EINVAL", `header ${name2}`);
|
|
13259
|
+
lines2.push(`${name2}: ${value2}`);
|
|
12693
13260
|
}
|
|
12694
|
-
for (const [name2,
|
|
13261
|
+
for (const [name2, value2] of extra) lines2.push(`${name2}: ${value2}`);
|
|
12695
13262
|
return latin1Bytes(`${lines2.join("\r\n")}\r
|
|
12696
13263
|
\r
|
|
12697
13264
|
`);
|
|
@@ -13007,7 +13574,7 @@ var LoopbackWebSocket = class {
|
|
|
13007
13574
|
};
|
|
13008
13575
|
|
|
13009
13576
|
// src/kernel/net/x509.ts
|
|
13010
|
-
function
|
|
13577
|
+
function concat5(parts2) {
|
|
13011
13578
|
const out = new Uint8Array(parts2.reduce((n, p) => n + p.length, 0));
|
|
13012
13579
|
let at = 0;
|
|
13013
13580
|
for (const p of parts2) {
|
|
@@ -13023,8 +13590,8 @@ function length(n) {
|
|
|
13023
13590
|
return Uint8Array.of(128 | bytes.length, ...bytes);
|
|
13024
13591
|
}
|
|
13025
13592
|
function tlv(tag, ...contents2) {
|
|
13026
|
-
const body =
|
|
13027
|
-
return
|
|
13593
|
+
const body = concat5(contents2);
|
|
13594
|
+
return concat5([Uint8Array.of(tag), length(body.length), body]);
|
|
13028
13595
|
}
|
|
13029
13596
|
var seq = (...parts2) => tlv(48, ...parts2);
|
|
13030
13597
|
var set2 = (...parts2) => tlv(49, ...parts2);
|
|
@@ -13035,7 +13602,7 @@ function integer(magnitude) {
|
|
|
13035
13602
|
let start2 = 0;
|
|
13036
13603
|
while (start2 < magnitude.length - 1 && magnitude[start2] === 0) start2++;
|
|
13037
13604
|
const trimmed = magnitude.subarray(start2);
|
|
13038
|
-
return tlv(2, trimmed[0] & 128 ?
|
|
13605
|
+
return tlv(2, trimmed[0] & 128 ? concat5([Uint8Array.of(0), trimmed]) : trimmed);
|
|
13039
13606
|
}
|
|
13040
13607
|
function oid(dotted) {
|
|
13041
13608
|
const [a, b, ...rest2] = dotted.split(".").map(Number);
|
|
@@ -13064,8 +13631,8 @@ function name(dn) {
|
|
|
13064
13631
|
rdns.push(set2(seq(oid("2.5.4.3"), utf8(dn.commonName))));
|
|
13065
13632
|
return seq(...rdns);
|
|
13066
13633
|
}
|
|
13067
|
-
function extension(id2, critical,
|
|
13068
|
-
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));
|
|
13069
13636
|
}
|
|
13070
13637
|
function children(der) {
|
|
13071
13638
|
const out = [];
|
|
@@ -13122,11 +13689,11 @@ function ipv6(host) {
|
|
|
13122
13689
|
if (!host.includes(":") || !/^[0-9A-Fa-f:.]+$/.test(host)) return void 0;
|
|
13123
13690
|
const v4 = /(\d{1,3}(?:\.\d{1,3}){3})$/.exec(host);
|
|
13124
13691
|
let text = host;
|
|
13125
|
-
const
|
|
13692
|
+
const tail2 = [];
|
|
13126
13693
|
if (v4) {
|
|
13127
13694
|
const bytes = ipv4(v4[1]);
|
|
13128
13695
|
if (!bytes) return void 0;
|
|
13129
|
-
|
|
13696
|
+
tail2.push(bytes[0] << 8 | bytes[1], bytes[2] << 8 | bytes[3]);
|
|
13130
13697
|
text = host.slice(0, -v4[1].length).replace(/:$/, host.endsWith(`::${v4[1]}`) ? ":" : "");
|
|
13131
13698
|
}
|
|
13132
13699
|
const halves = text.split("::");
|
|
@@ -13136,13 +13703,13 @@ function ipv6(host) {
|
|
|
13136
13703
|
const back = halves.length === 2 ? groups(halves[1]) : [];
|
|
13137
13704
|
if (![...head, ...back].every((g) => /^[0-9A-Fa-f]{1,4}$/.test(g))) return void 0;
|
|
13138
13705
|
const words2 = [...head, ...back].map((g) => Number.parseInt(g, 16));
|
|
13139
|
-
const missing4 = 8 - words2.length -
|
|
13706
|
+
const missing4 = 8 - words2.length - tail2.length;
|
|
13140
13707
|
if (halves.length === 2 ? missing4 < 1 : missing4 !== 0) return void 0;
|
|
13141
13708
|
const all = [
|
|
13142
13709
|
...head.map((g) => Number.parseInt(g, 16)),
|
|
13143
13710
|
...new Array(halves.length === 2 ? missing4 : 0).fill(0),
|
|
13144
13711
|
...back.map((g) => Number.parseInt(g, 16)),
|
|
13145
|
-
...
|
|
13712
|
+
...tail2
|
|
13146
13713
|
];
|
|
13147
13714
|
return Uint8Array.from(all.flatMap((w) => [w >> 8, w & 255]));
|
|
13148
13715
|
}
|
|
@@ -14132,11 +14699,11 @@ function waitFor(lookup4, signal) {
|
|
|
14132
14699
|
reject(new KernelError("EINTR"));
|
|
14133
14700
|
};
|
|
14134
14701
|
signal?.addEventListener("abort", abort, { once: true });
|
|
14135
|
-
void lookup4.work.then((
|
|
14702
|
+
void lookup4.work.then((value2) => {
|
|
14136
14703
|
if (signal?.aborted) return;
|
|
14137
14704
|
lookup4.waiters--;
|
|
14138
14705
|
signal?.removeEventListener("abort", abort);
|
|
14139
|
-
resolve2(
|
|
14706
|
+
resolve2(value2);
|
|
14140
14707
|
});
|
|
14141
14708
|
});
|
|
14142
14709
|
}
|
|
@@ -14173,7 +14740,7 @@ function defaultTermios() {
|
|
|
14173
14740
|
c_cc: cCc
|
|
14174
14741
|
};
|
|
14175
14742
|
}
|
|
14176
|
-
var
|
|
14743
|
+
var encoder4 = new TextEncoder();
|
|
14177
14744
|
function isContinuation(byte) {
|
|
14178
14745
|
return (byte & 192) === 128;
|
|
14179
14746
|
}
|
|
@@ -14296,7 +14863,7 @@ var KernelTty = class {
|
|
|
14296
14863
|
this.line.push(byte);
|
|
14297
14864
|
this.readable.push(Uint8Array.from(this.line));
|
|
14298
14865
|
this.line = [];
|
|
14299
|
-
if (echo) this.output(
|
|
14866
|
+
if (echo) this.output(encoder4.encode("\n"));
|
|
14300
14867
|
} else {
|
|
14301
14868
|
this.line.push(byte);
|
|
14302
14869
|
if (echo) this.echo(byte);
|
|
@@ -14321,7 +14888,7 @@ var KernelTty = class {
|
|
|
14321
14888
|
const utf83 = (this.termios.c_iflag & IUTF8) !== 0;
|
|
14322
14889
|
const cells = utf83 ? dropped2.filter((b) => !isContinuation(b)).length : dropped2.length;
|
|
14323
14890
|
if (cells > 0 && this.termios.c_lflag & ECHO) {
|
|
14324
|
-
this.output(
|
|
14891
|
+
this.output(encoder4.encode("\b \b".repeat(cells)), false);
|
|
14325
14892
|
}
|
|
14326
14893
|
}
|
|
14327
14894
|
echo(byte) {
|
|
@@ -14573,7 +15140,7 @@ function terminalOf(ctx, fd) {
|
|
|
14573
15140
|
if (!tty) throw new KernelError("ENOTTY");
|
|
14574
15141
|
return tty;
|
|
14575
15142
|
}
|
|
14576
|
-
var json4 = (
|
|
15143
|
+
var json4 = (value2) => ({ ok: true, kind: "json", json: value2 });
|
|
14577
15144
|
var done3 = { ok: true, kind: "void" };
|
|
14578
15145
|
function sizeKey(rows, cols) {
|
|
14579
15146
|
return `${rows}x${cols}`;
|
|
@@ -14789,8 +15356,8 @@ var Semaphore = class {
|
|
|
14789
15356
|
gid;
|
|
14790
15357
|
mode;
|
|
14791
15358
|
waiters = [];
|
|
14792
|
-
constructor(
|
|
14793
|
-
this.value =
|
|
15359
|
+
constructor(value2, uid, gid, mode) {
|
|
15360
|
+
this.value = value2;
|
|
14794
15361
|
this.uid = uid;
|
|
14795
15362
|
this.gid = gid;
|
|
14796
15363
|
this.mode = mode;
|
|
@@ -15415,10 +15982,10 @@ var VfsNodes = class {
|
|
|
15415
15982
|
async onEntry(path, op) {
|
|
15416
15983
|
const key = await this.entryKey(path);
|
|
15417
15984
|
const run2 = (this.entries.get(key) ?? Promise.resolve()).then(op);
|
|
15418
|
-
const
|
|
15419
|
-
this.entries.set(key,
|
|
15420
|
-
void
|
|
15421
|
-
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);
|
|
15422
15989
|
});
|
|
15423
15990
|
return run2;
|
|
15424
15991
|
}
|
|
@@ -16043,11 +16610,11 @@ var MAX_READ = 1024 * 1024;
|
|
|
16043
16610
|
var WRITE_ACCESS = 3;
|
|
16044
16611
|
var KEYBOARD = /* @__PURE__ */ new Set([SIG.INT, SIG.QUIT, SIG.TSTP]);
|
|
16045
16612
|
var DEFAULT_UMASK2 = 18;
|
|
16046
|
-
function words(
|
|
16047
|
-
if (!Array.isArray(
|
|
16613
|
+
function words(value2) {
|
|
16614
|
+
if (!Array.isArray(value2) || !value2.every((w) => typeof w === "string")) {
|
|
16048
16615
|
throw new KernelError("EINVAL");
|
|
16049
16616
|
}
|
|
16050
|
-
return [...
|
|
16617
|
+
return [...value2];
|
|
16051
16618
|
}
|
|
16052
16619
|
var ESCAPES = { " ": "\\t", "\n": "\\n", "\r": "\\r" };
|
|
16053
16620
|
function clipboardLine(text) {
|
|
@@ -18020,7 +18587,7 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
18020
18587
|
clearTimeout(entry.timer);
|
|
18021
18588
|
void entry.final.cancel().catch(() => void 0);
|
|
18022
18589
|
};
|
|
18023
|
-
const
|
|
18590
|
+
const keyOf3 = (owner, method, url) => `${owner} ${method} ${url}`;
|
|
18024
18591
|
const hold = (key, chain2) => {
|
|
18025
18592
|
drop(key);
|
|
18026
18593
|
const mine = [...held.keys()].filter((k) => held.get(k)?.owner === chain2.owner);
|
|
@@ -18039,7 +18606,7 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
18039
18606
|
const method = followedWith(hop.status, chain2.method);
|
|
18040
18607
|
const away = target.origin !== new URL(hop.url).origin;
|
|
18041
18608
|
const print = away ? unauthorized(chain2.fingerprint) : chain2.fingerprint;
|
|
18042
|
-
hold(
|
|
18609
|
+
hold(keyOf3(chain2.owner, method, target.href), {
|
|
18043
18610
|
...chain2,
|
|
18044
18611
|
method,
|
|
18045
18612
|
fingerprint: print,
|
|
@@ -18053,7 +18620,7 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
18053
18620
|
},
|
|
18054
18621
|
...inner.websocket ? { websocket: inner.websocket.bind(inner) } : {},
|
|
18055
18622
|
async fetch(request, owner = KERNEL) {
|
|
18056
|
-
const key =
|
|
18623
|
+
const key = keyOf3(owner, request.method, request.url);
|
|
18057
18624
|
const waiting = held.get(key);
|
|
18058
18625
|
if (waiting && waiting.fingerprint === fingerprint(request.headers)) {
|
|
18059
18626
|
held.delete(key);
|
|
@@ -18078,10 +18645,10 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
18078
18645
|
var FRAGMENT = 16;
|
|
18079
18646
|
var MIN_VALUE = 8;
|
|
18080
18647
|
var MIN_BASE64 = 8;
|
|
18081
|
-
var
|
|
18648
|
+
var encoder5 = new TextEncoder();
|
|
18082
18649
|
var STD = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
18083
18650
|
function utf82(text) {
|
|
18084
|
-
return
|
|
18651
|
+
return encoder5.encode(text);
|
|
18085
18652
|
}
|
|
18086
18653
|
function base642(bytes, padded = true) {
|
|
18087
18654
|
let out = "";
|
|
@@ -18113,30 +18680,30 @@ function embedded(bytes, offset) {
|
|
|
18113
18680
|
const last = Math.floor(8 * (offset + bytes.length) / 6);
|
|
18114
18681
|
return encoded.slice(first, last);
|
|
18115
18682
|
}
|
|
18116
|
-
function unicode(
|
|
18683
|
+
function unicode(value2, upper) {
|
|
18117
18684
|
let out = "";
|
|
18118
|
-
for (let i = 0; i <
|
|
18119
|
-
const unit =
|
|
18685
|
+
for (let i = 0; i < value2.length; i++) {
|
|
18686
|
+
const unit = value2.charCodeAt(i);
|
|
18120
18687
|
if (unit === 34) out += '\\"';
|
|
18121
18688
|
else if (unit === 92) out += "\\\\";
|
|
18122
18689
|
else if (unit < 32 || unit > 126) {
|
|
18123
18690
|
const code = unit.toString(16).padStart(4, "0");
|
|
18124
18691
|
out += `\\u${upper ? code.toUpperCase() : code}`;
|
|
18125
|
-
} else out +=
|
|
18692
|
+
} else out += value2[i];
|
|
18126
18693
|
}
|
|
18127
18694
|
return out;
|
|
18128
18695
|
}
|
|
18129
|
-
function percent(
|
|
18696
|
+
function percent(value2) {
|
|
18130
18697
|
let component;
|
|
18131
18698
|
try {
|
|
18132
|
-
component = encodeURIComponent(
|
|
18699
|
+
component = encodeURIComponent(value2);
|
|
18133
18700
|
} catch {
|
|
18134
18701
|
return [];
|
|
18135
18702
|
}
|
|
18136
18703
|
const lower = component.replace(/%[0-9A-F]{2}/g, (escape) => escape.toLowerCase());
|
|
18137
18704
|
const plus = component.replace(/%20/g, "+");
|
|
18138
18705
|
let form = "";
|
|
18139
|
-
for (const byte of utf82(
|
|
18706
|
+
for (const byte of utf82(value2)) {
|
|
18140
18707
|
const char = String.fromCharCode(byte);
|
|
18141
18708
|
if (/[A-Za-z0-9*\-._]/.test(char)) form += char;
|
|
18142
18709
|
else if (byte === 32) form += "+";
|
|
@@ -18144,8 +18711,8 @@ function percent(value) {
|
|
|
18144
18711
|
}
|
|
18145
18712
|
return [component, lower, plus, form];
|
|
18146
18713
|
}
|
|
18147
|
-
function html(
|
|
18148
|
-
return
|
|
18714
|
+
function html(value2, apostrophe) {
|
|
18715
|
+
return value2.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, apostrophe);
|
|
18149
18716
|
}
|
|
18150
18717
|
function encodings(bytes) {
|
|
18151
18718
|
const standard = [base642(bytes), base642(bytes, false)];
|
|
@@ -18155,9 +18722,9 @@ function encodings(bytes) {
|
|
|
18155
18722
|
}
|
|
18156
18723
|
return [...standard, ...standard.map(urlSafe)];
|
|
18157
18724
|
}
|
|
18158
|
-
function shapes(
|
|
18159
|
-
const raw = utf82(
|
|
18160
|
-
const seen = /* @__PURE__ */ new Set([
|
|
18725
|
+
function shapes(value2) {
|
|
18726
|
+
const raw = utf82(value2);
|
|
18727
|
+
const seen = /* @__PURE__ */ new Set([value2]);
|
|
18161
18728
|
const out = [];
|
|
18162
18729
|
if (raw.length < FRAGMENT) out.push({ bytes: raw, form: "raw" });
|
|
18163
18730
|
for (let offset = 0; raw.length >= FRAGMENT && offset + FRAGMENT <= raw.length; offset++) {
|
|
@@ -18168,17 +18735,17 @@ function shapes(value) {
|
|
|
18168
18735
|
seen.add(text);
|
|
18169
18736
|
out.push({ bytes: utf82(text), form });
|
|
18170
18737
|
};
|
|
18171
|
-
const json5 = JSON.stringify(
|
|
18738
|
+
const json5 = JSON.stringify(value2).slice(1, -1);
|
|
18172
18739
|
for (const text of [
|
|
18173
18740
|
json5,
|
|
18174
18741
|
json5.replace(/\//g, "\\/"),
|
|
18175
|
-
unicode(
|
|
18176
|
-
unicode(
|
|
18742
|
+
unicode(value2, false),
|
|
18743
|
+
unicode(value2, true)
|
|
18177
18744
|
]) {
|
|
18178
18745
|
add(text, "json");
|
|
18179
18746
|
}
|
|
18180
|
-
for (const text of percent(
|
|
18181
|
-
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");
|
|
18182
18749
|
for (const text of encodings(raw)) add(text, "base64");
|
|
18183
18750
|
add(hex2(raw), "hex");
|
|
18184
18751
|
add(hex2(raw).toUpperCase(), "hex");
|
|
@@ -18329,15 +18896,15 @@ function resolve(c, input, start2, end, source) {
|
|
|
18329
18896
|
growing: false
|
|
18330
18897
|
};
|
|
18331
18898
|
}
|
|
18332
|
-
const
|
|
18899
|
+
const value2 = c.values[source.secret];
|
|
18333
18900
|
let stop = end;
|
|
18334
18901
|
let at = source.offset + FRAGMENT;
|
|
18335
|
-
while (stop < input.length && at <
|
|
18902
|
+
while (stop < input.length && at < value2.length && input[stop] === value2[at]) {
|
|
18336
18903
|
stop++;
|
|
18337
18904
|
at++;
|
|
18338
18905
|
}
|
|
18339
|
-
const form = source.offset === 0 && at ===
|
|
18340
|
-
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;
|
|
18341
18908
|
return { start: start2, end: stop, secret: source.secret, form, rank: RANK[form], growing };
|
|
18342
18909
|
}
|
|
18343
18910
|
function keep(best, candidate) {
|
|
@@ -18385,7 +18952,7 @@ function count(c, hits, candidate) {
|
|
|
18385
18952
|
hit.count += 1;
|
|
18386
18953
|
hits.set(key, hit);
|
|
18387
18954
|
}
|
|
18388
|
-
function
|
|
18955
|
+
function concat6(parts2) {
|
|
18389
18956
|
let length2 = 0;
|
|
18390
18957
|
for (const part of parts2) length2 += part.length;
|
|
18391
18958
|
const out = new Uint8Array(length2);
|
|
@@ -18427,7 +18994,7 @@ function pass(c, input, final) {
|
|
|
18427
18994
|
pos = candidate.end;
|
|
18428
18995
|
}
|
|
18429
18996
|
parts2.push(input.subarray(pos, cut));
|
|
18430
|
-
return { output:
|
|
18997
|
+
return { output: concat6(parts2), cut, hits };
|
|
18431
18998
|
}
|
|
18432
18999
|
function merge(into, from) {
|
|
18433
19000
|
for (const [key, hit] of from) {
|
|
@@ -18470,7 +19037,7 @@ function compile(secrets, options = {}) {
|
|
|
18470
19037
|
};
|
|
18471
19038
|
return {
|
|
18472
19039
|
push(chunk2) {
|
|
18473
|
-
pending =
|
|
19040
|
+
pending = concat6([pending, chunk2]);
|
|
18474
19041
|
return run2(false);
|
|
18475
19042
|
},
|
|
18476
19043
|
idle() {
|
|
@@ -18490,9 +19057,9 @@ function compile(secrets, options = {}) {
|
|
|
18490
19057
|
// src/kernel/scrub-file.ts
|
|
18491
19058
|
var SCRUB_IDLE_MS = 50;
|
|
18492
19059
|
var SCRUB_NONBLOCK_MAX = 64 * 1024;
|
|
18493
|
-
var
|
|
19060
|
+
var encoder6 = new TextEncoder();
|
|
18494
19061
|
function scrubberOf(secrets) {
|
|
18495
|
-
const usable = secrets.filter((s) =>
|
|
19062
|
+
const usable = secrets.filter((s) => encoder6.encode(s.value).length >= MIN_VALUE);
|
|
18496
19063
|
return usable.length > 0 ? compile(usable, { idleMs: SCRUB_IDLE_MS }) : void 0;
|
|
18497
19064
|
}
|
|
18498
19065
|
async function writeAll3(file, bytes) {
|
|
@@ -18510,7 +19077,7 @@ function interrupted2(err) {
|
|
|
18510
19077
|
function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
18511
19078
|
const file = inner.file;
|
|
18512
19079
|
const stream2 = scrubber.stream();
|
|
18513
|
-
let
|
|
19080
|
+
let tail2 = Promise.resolve();
|
|
18514
19081
|
let pending = 0;
|
|
18515
19082
|
let busy = false;
|
|
18516
19083
|
let timer;
|
|
@@ -18529,7 +19096,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
|
18529
19096
|
const later = (bytes) => {
|
|
18530
19097
|
if (bytes.length === 0) return;
|
|
18531
19098
|
pending += 1;
|
|
18532
|
-
|
|
19099
|
+
tail2 = tail2.then(() => writeAll3(file, bytes)).catch((err) => {
|
|
18533
19100
|
if (failed3 === void 0) failed3 = err;
|
|
18534
19101
|
}).finally(() => {
|
|
18535
19102
|
pending -= 1;
|
|
@@ -18680,7 +19247,7 @@ var SEALED_OPS = /* @__PURE__ */ new Set([
|
|
|
18680
19247
|
"cancel",
|
|
18681
19248
|
"materialize"
|
|
18682
19249
|
]);
|
|
18683
|
-
var
|
|
19250
|
+
var encoder7 = new TextEncoder();
|
|
18684
19251
|
var decoder3 = new TextDecoder("utf-8", { fatal: true });
|
|
18685
19252
|
function parseSealed(bytes) {
|
|
18686
19253
|
try {
|
|
@@ -18709,8 +19276,8 @@ function materializable(req) {
|
|
|
18709
19276
|
function errorReply(code, message3) {
|
|
18710
19277
|
return { v: 1, error: { code, message: message3 } };
|
|
18711
19278
|
}
|
|
18712
|
-
function isRecord(
|
|
18713
|
-
return typeof
|
|
19279
|
+
function isRecord(value2) {
|
|
19280
|
+
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
18714
19281
|
}
|
|
18715
19282
|
function serialized(reply) {
|
|
18716
19283
|
let plain2;
|
|
@@ -18761,7 +19328,7 @@ var SealedChannel = class {
|
|
|
18761
19328
|
await this.broker.tickets.record(req, reply, caller.pid);
|
|
18762
19329
|
if (this.inflight !== flight) return;
|
|
18763
19330
|
this.inflight = void 0;
|
|
18764
|
-
if (reply) this.reply =
|
|
19331
|
+
if (reply) this.reply = encoder7.encode(serialized(reply));
|
|
18765
19332
|
});
|
|
18766
19333
|
this.inflight = flight;
|
|
18767
19334
|
return length2;
|
|
@@ -19353,8 +19920,8 @@ function umountCall(target, flags2) {
|
|
|
19353
19920
|
var FSTAB_PATH = "/etc/fstab";
|
|
19354
19921
|
var FSTAB_RETRIES = [1e3, 4e3, 16e3];
|
|
19355
19922
|
var FINAL = /* @__PURE__ */ new Set(["EINVAL", "EBUSY", "EPERM", "EACCES"]);
|
|
19356
|
-
function unescape(
|
|
19357
|
-
return
|
|
19923
|
+
function unescape(field4) {
|
|
19924
|
+
return field4.replace(
|
|
19358
19925
|
/\\([0-7]{3})/g,
|
|
19359
19926
|
(_, octal) => String.fromCharCode(Number.parseInt(octal, 8))
|
|
19360
19927
|
);
|
|
@@ -19550,9 +20117,9 @@ var HostfsClient = class {
|
|
|
19550
20117
|
let buffered = "";
|
|
19551
20118
|
try {
|
|
19552
20119
|
for (; ; ) {
|
|
19553
|
-
const { done: done4, value } = await reader.read();
|
|
20120
|
+
const { done: done4, value: value2 } = await reader.read();
|
|
19554
20121
|
if (done4) return;
|
|
19555
|
-
buffered += decoder4.decode(
|
|
20122
|
+
buffered += decoder4.decode(value2, { stream: true });
|
|
19556
20123
|
let end = buffered.indexOf("\n");
|
|
19557
20124
|
while (end >= 0) {
|
|
19558
20125
|
const line = buffered.slice(0, end).trim();
|
|
@@ -19814,10 +20381,10 @@ function timed(transport, ms) {
|
|
|
19814
20381
|
reject(fsError2("ENOTCONN", why));
|
|
19815
20382
|
}, ms);
|
|
19816
20383
|
running.then(
|
|
19817
|
-
(
|
|
20384
|
+
(value2) => {
|
|
19818
20385
|
clearTimeout(timer);
|
|
19819
|
-
if (expired) late?.(
|
|
19820
|
-
resolve2(
|
|
20386
|
+
if (expired) late?.(value2);
|
|
20387
|
+
resolve2(value2);
|
|
19821
20388
|
},
|
|
19822
20389
|
(err) => {
|
|
19823
20390
|
clearTimeout(timer);
|
|
@@ -20232,9 +20799,9 @@ var ChunkedBytes = class {
|
|
|
20232
20799
|
if (size < this.size) {
|
|
20233
20800
|
const keep2 = Math.ceil(size / CHUNK3);
|
|
20234
20801
|
this.chunks.length = Math.min(this.chunks.length, keep2);
|
|
20235
|
-
const
|
|
20802
|
+
const tail2 = this.chunks[keep2 - 1];
|
|
20236
20803
|
const from = size - (keep2 - 1) * CHUNK3;
|
|
20237
|
-
if (
|
|
20804
|
+
if (tail2 && from < tail2.length) tail2.fill(0, from);
|
|
20238
20805
|
}
|
|
20239
20806
|
this.size = size;
|
|
20240
20807
|
}
|
|
@@ -20249,8 +20816,8 @@ var ChunkedBytes = class {
|
|
|
20249
20816
|
};
|
|
20250
20817
|
|
|
20251
20818
|
// src/mount/tmpfs.ts
|
|
20252
|
-
function idOption2(
|
|
20253
|
-
return
|
|
20819
|
+
function idOption2(value2) {
|
|
20820
|
+
return value2 !== void 0 && /^\d+$/.test(value2) ? Number(value2) : 0;
|
|
20254
20821
|
}
|
|
20255
20822
|
function created2(ino, kind, mode, from, owner) {
|
|
20256
20823
|
const now = Date.now();
|
|
@@ -20485,7 +21052,7 @@ function importedMemory(bytes) {
|
|
|
20485
21052
|
const count2 = u32();
|
|
20486
21053
|
for (let i = 0; i < count2; i++) {
|
|
20487
21054
|
const module = name2();
|
|
20488
|
-
const
|
|
21055
|
+
const field4 = name2();
|
|
20489
21056
|
const kind = bytes[at++];
|
|
20490
21057
|
if (kind === 0) u32();
|
|
20491
21058
|
else if (kind === 1) {
|
|
@@ -20493,7 +21060,7 @@ function importedMemory(bytes) {
|
|
|
20493
21060
|
limits();
|
|
20494
21061
|
} else if (kind === 2) {
|
|
20495
21062
|
const l = limits();
|
|
20496
|
-
return { module, name:
|
|
21063
|
+
return { module, name: field4, ...l };
|
|
20497
21064
|
} else if (kind === 3) at += 2;
|
|
20498
21065
|
else if (kind === 4) {
|
|
20499
21066
|
at++;
|
|
@@ -20584,12 +21151,12 @@ function readImports(r, types) {
|
|
|
20584
21151
|
const foreign = {};
|
|
20585
21152
|
for (let i = r.u32(); i > 0; i--) {
|
|
20586
21153
|
const module = r.name();
|
|
20587
|
-
const
|
|
21154
|
+
const field4 = r.name();
|
|
20588
21155
|
const kind = r.byte();
|
|
20589
21156
|
if (kind !== 0) skipImport(r, kind);
|
|
20590
21157
|
else {
|
|
20591
21158
|
const type = types[r.u32()] ?? "other";
|
|
20592
|
-
if (!RESERVED_NAMESPACES.has(module)) (foreign[module] ??= {})[
|
|
21159
|
+
if (!RESERVED_NAMESPACES.has(module)) (foreign[module] ??= {})[field4] = type;
|
|
20593
21160
|
}
|
|
20594
21161
|
}
|
|
20595
21162
|
return foreign;
|
|
@@ -21102,7 +21669,7 @@ var LAYOUT = [
|
|
|
21102
21669
|
];
|
|
21103
21670
|
var LOAD_SAMPLE_MS = 5e3;
|
|
21104
21671
|
var LOAD_WINDOWS_MS = [6e4, 3e5, 9e5];
|
|
21105
|
-
var
|
|
21672
|
+
var encoder8 = new TextEncoder();
|
|
21106
21673
|
var USERS_MODES = ["off", "report", "enforce"];
|
|
21107
21674
|
function usersMode(mode = "off") {
|
|
21108
21675
|
if (USERS_MODES.includes(mode)) return mode;
|
|
@@ -21162,10 +21729,10 @@ function shebangCommand(words2) {
|
|
|
21162
21729
|
const arg2 = words2.slice(1).join(" ");
|
|
21163
21730
|
return { interp: words2[0], args: arg2 ? [arg2] : [] };
|
|
21164
21731
|
}
|
|
21165
|
-
const
|
|
21166
|
-
const [interp, ...rest2] = words2.slice(
|
|
21732
|
+
const split3 = words2[1] === "-S";
|
|
21733
|
+
const [interp, ...rest2] = words2.slice(split3 ? 2 : 1);
|
|
21167
21734
|
const arg = rest2.join(" ");
|
|
21168
|
-
return { interp, args:
|
|
21735
|
+
return { interp, args: split3 ? rest2 : arg ? [arg] : [] };
|
|
21169
21736
|
}
|
|
21170
21737
|
function interpreter(head) {
|
|
21171
21738
|
const words2 = shebang(head);
|
|
@@ -21176,9 +21743,9 @@ function interpreter(head) {
|
|
|
21176
21743
|
}
|
|
21177
21744
|
function expandDefaults(defaults, env) {
|
|
21178
21745
|
const out = {};
|
|
21179
|
-
for (const [key,
|
|
21746
|
+
for (const [key, value2] of Object.entries(defaults ?? {})) {
|
|
21180
21747
|
let missing4 = false;
|
|
21181
|
-
const expanded =
|
|
21748
|
+
const expanded = value2.replace(ENV_REFERENCE, (_, name2) => {
|
|
21182
21749
|
const set3 = Object.hasOwn(env, name2) ? env[name2] : void 0;
|
|
21183
21750
|
if (set3 === void 0) missing4 = true;
|
|
21184
21751
|
return set3 ?? "";
|
|
@@ -21220,7 +21787,7 @@ function childHandle(handle) {
|
|
|
21220
21787
|
onState: (listener) => handle.onState(listener)
|
|
21221
21788
|
};
|
|
21222
21789
|
}
|
|
21223
|
-
function
|
|
21790
|
+
function concat7(chunks2) {
|
|
21224
21791
|
const out = new Uint8Array(chunks2.reduce((n, chunk2) => n + chunk2.length, 0));
|
|
21225
21792
|
let offset = 0;
|
|
21226
21793
|
for (const chunk2 of chunks2) {
|
|
@@ -21325,6 +21892,8 @@ var Launcher = class {
|
|
|
21325
21892
|
fileWatches;
|
|
21326
21893
|
nextPid = 1e3;
|
|
21327
21894
|
boot = Date.now();
|
|
21895
|
+
bootId = crypto.randomUUID();
|
|
21896
|
+
cron;
|
|
21328
21897
|
terminals = 0;
|
|
21329
21898
|
constructor(options) {
|
|
21330
21899
|
this.usersMode = usersMode(options.users);
|
|
@@ -21455,6 +22024,7 @@ var Launcher = class {
|
|
|
21455
22024
|
approve: options.approve,
|
|
21456
22025
|
timeoutMs: options.sudoTimeoutMs
|
|
21457
22026
|
});
|
|
22027
|
+
this.cron = this.cronService(options.cron);
|
|
21458
22028
|
void this.unlinked.sweep("/");
|
|
21459
22029
|
this.watchers.watch(
|
|
21460
22030
|
[this.modulesDir, this.pnpmHome, ...this.appended],
|
|
@@ -21466,6 +22036,38 @@ var Launcher = class {
|
|
|
21466
22036
|
this.resetCatalogs();
|
|
21467
22037
|
});
|
|
21468
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
|
+
}
|
|
21469
22071
|
get owners() {
|
|
21470
22072
|
return this.usersMode !== "off";
|
|
21471
22073
|
}
|
|
@@ -21825,10 +22427,10 @@ var Launcher = class {
|
|
|
21825
22427
|
if (!swap) throw new SpawnError("EACCES");
|
|
21826
22428
|
const secrets = [];
|
|
21827
22429
|
for (const [name2, placeholder] of Object.entries(swap.placeholders)) {
|
|
21828
|
-
const
|
|
21829
|
-
if (
|
|
21830
|
-
env[name2] =
|
|
21831
|
-
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 });
|
|
21832
22434
|
}
|
|
21833
22435
|
const scrub = scrubberOf(secrets);
|
|
21834
22436
|
return { env, pid, cwd: booked.cwd, ...scrub ? { scrub } : {} };
|
|
@@ -21935,7 +22537,7 @@ var Launcher = class {
|
|
|
21935
22537
|
if (hit !== void 0) return hit;
|
|
21936
22538
|
const revocations = this.revocations;
|
|
21937
22539
|
const loading2 = load();
|
|
21938
|
-
const found = loading2.then(({ value }) =>
|
|
22540
|
+
const found = loading2.then(({ value: value2 }) => value2);
|
|
21939
22541
|
cache.set(key, found);
|
|
21940
22542
|
const drop = () => {
|
|
21941
22543
|
if (cache.get(key) === found) cache.delete(key);
|
|
@@ -22802,6 +23404,7 @@ var Launcher = class {
|
|
|
22802
23404
|
for (const holds2 of this.held) holds2.revoke(at);
|
|
22803
23405
|
}
|
|
22804
23406
|
unmountAll() {
|
|
23407
|
+
this.cron.stop();
|
|
22805
23408
|
this.booting.abort();
|
|
22806
23409
|
const targets = this.mounts.list().map((m) => m.target);
|
|
22807
23410
|
for (const target of targets.sort((a, b) => b.length - a.length)) this.umount(target, true);
|
|
@@ -22868,7 +23471,9 @@ var Launcher = class {
|
|
|
22868
23471
|
if (this.owners) await this.stampLayout();
|
|
22869
23472
|
if (this.owners) await this.sudoer.provision();
|
|
22870
23473
|
await writeCaFile(this.base, this.ca).catch(() => void 0);
|
|
23474
|
+
await this.cron.provision().catch(() => void 0);
|
|
22871
23475
|
this.fstab = this.mountFstab();
|
|
23476
|
+
void this.cron.start();
|
|
22872
23477
|
}
|
|
22873
23478
|
async mountFstab() {
|
|
22874
23479
|
const text = await this.base.readFile(FSTAB_PATH).catch(() => "");
|
|
@@ -22890,9 +23495,9 @@ var Launcher = class {
|
|
|
22890
23495
|
}
|
|
22891
23496
|
);
|
|
22892
23497
|
}
|
|
22893
|
-
environment(cwd, extra, account) {
|
|
23498
|
+
environment(cwd, extra, account, login = false) {
|
|
22894
23499
|
const env = {
|
|
22895
|
-
...this.env,
|
|
23500
|
+
...login ? networkEnv(this.hostname) : this.env,
|
|
22896
23501
|
...userEnv(account, this.pnpmHome),
|
|
22897
23502
|
PWD: cwd,
|
|
22898
23503
|
...extra
|
|
@@ -23044,7 +23649,7 @@ var Launcher = class {
|
|
|
23044
23649
|
},
|
|
23045
23650
|
account
|
|
23046
23651
|
);
|
|
23047
|
-
const report = (message3) => options.onData(
|
|
23652
|
+
const report = (message3) => options.onData(encoder8.encode(`${message3}\r
|
|
23048
23653
|
`));
|
|
23049
23654
|
const handle = await this.launch(planned, {
|
|
23050
23655
|
env,
|
|
@@ -23072,7 +23677,7 @@ var Launcher = class {
|
|
|
23072
23677
|
tagOption(options.tag);
|
|
23073
23678
|
const account = await this.account(options.user);
|
|
23074
23679
|
const { cwd, file, planned } = await this.starting(argv, options.cwd, account, options.tag);
|
|
23075
|
-
const env = this.environment(cwd, options.env, account);
|
|
23680
|
+
const env = this.environment(cwd, options.env, account, options.login);
|
|
23076
23681
|
const out = [];
|
|
23077
23682
|
const err = [];
|
|
23078
23683
|
const keep2 = options.collect !== false;
|
|
@@ -23082,13 +23687,13 @@ var Launcher = class {
|
|
|
23082
23687
|
};
|
|
23083
23688
|
const stdout = collect(out, options.onStdout);
|
|
23084
23689
|
const stderr = collect(err, options.onStderr);
|
|
23085
|
-
const report = (message3) => stderr(
|
|
23690
|
+
const report = (message3) => stderr(encoder8.encode(`${message3}
|
|
23086
23691
|
`));
|
|
23087
23692
|
if (!planned) {
|
|
23088
23693
|
const directory = await this.directory(file, this.fs.resolvePath(cwd, file));
|
|
23089
23694
|
report(`${file}: ${directory ? "Is a directory" : "command not found"}`);
|
|
23090
23695
|
const status2 = directory ? NOT_EXECUTABLE : NOT_FOUND;
|
|
23091
|
-
return { status: status2, stdout:
|
|
23696
|
+
return { status: status2, stdout: concat7(out), stderr: concat7(err) };
|
|
23092
23697
|
}
|
|
23093
23698
|
const fds = new FdTable();
|
|
23094
23699
|
fds.installAt(0, options.stdin ? bytesSource(options.stdin) : deviceFile("null"));
|
|
@@ -23106,9 +23711,12 @@ var Launcher = class {
|
|
|
23106
23711
|
options.onStarted?.(handle.pid);
|
|
23107
23712
|
const status = await handle.exited;
|
|
23108
23713
|
const signal = handle.termsig();
|
|
23109
|
-
return { status, ...signal ? { signal } : {}, stdout:
|
|
23714
|
+
return { status, ...signal ? { signal } : {}, stdout: concat7(out), stderr: concat7(err) };
|
|
23110
23715
|
}
|
|
23111
23716
|
};
|
|
23717
|
+
function cronLocks() {
|
|
23718
|
+
return globalThis.navigator?.locks;
|
|
23719
|
+
}
|
|
23112
23720
|
|
|
23113
23721
|
// src/node/loopback.ts
|
|
23114
23722
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -23148,10 +23756,10 @@ function hextets2(address) {
|
|
|
23148
23756
|
const [a, b, c, d] = dotted.split(".").map(Number);
|
|
23149
23757
|
text = `${address.slice(0, -dotted.length)}${(a << 8 | b).toString(16)}:${(c << 8 | d).toString(16)}`;
|
|
23150
23758
|
}
|
|
23151
|
-
const [head = "",
|
|
23759
|
+
const [head = "", tail2] = text.split("::");
|
|
23152
23760
|
const part = (side) => side ? side.split(":").map((w) => Number.parseInt(w, 16)) : [];
|
|
23153
23761
|
const left = part(head);
|
|
23154
|
-
const right =
|
|
23762
|
+
const right = tail2 === void 0 ? [] : part(tail2);
|
|
23155
23763
|
const gap = Array(8 - left.length - right.length).fill(0);
|
|
23156
23764
|
return [...left, ...gap, ...right];
|
|
23157
23765
|
}
|
|
@@ -23879,7 +24487,7 @@ function dialStream(port, onClose) {
|
|
|
23879
24487
|
|
|
23880
24488
|
// src/client/loopback-fetch.ts
|
|
23881
24489
|
var OWN_HEADERS2 = /* @__PURE__ */ new Set(["host", "connection", "content-length", "transfer-encoding"]);
|
|
23882
|
-
var
|
|
24490
|
+
var encoder9 = new TextEncoder();
|
|
23883
24491
|
var latin12 = new TextDecoder("latin1");
|
|
23884
24492
|
var ByteSource = class {
|
|
23885
24493
|
buffered = new Uint8Array(0);
|
|
@@ -23888,16 +24496,16 @@ var ByteSource = class {
|
|
|
23888
24496
|
this.reader = reader;
|
|
23889
24497
|
}
|
|
23890
24498
|
async more() {
|
|
23891
|
-
const { done: done4, value } = await this.reader.read();
|
|
24499
|
+
const { done: done4, value: value2 } = await this.reader.read();
|
|
23892
24500
|
if (done4) return false;
|
|
23893
|
-
const joined3 = new Uint8Array(this.buffered.length +
|
|
24501
|
+
const joined3 = new Uint8Array(this.buffered.length + value2.length);
|
|
23894
24502
|
joined3.set(this.buffered);
|
|
23895
|
-
joined3.set(
|
|
24503
|
+
joined3.set(value2, this.buffered.length);
|
|
23896
24504
|
this.buffered = joined3;
|
|
23897
24505
|
return true;
|
|
23898
24506
|
}
|
|
23899
24507
|
async until(marker) {
|
|
23900
|
-
const needle =
|
|
24508
|
+
const needle = encoder9.encode(marker);
|
|
23901
24509
|
for (; ; ) {
|
|
23902
24510
|
const at = indexOf(this.buffered, needle);
|
|
23903
24511
|
if (at >= 0) return this.take(at + needle.length);
|
|
@@ -24000,12 +24608,12 @@ async function requestBytes(request) {
|
|
|
24000
24608
|
const url = new URL(request.url);
|
|
24001
24609
|
const body = request.body ? new Uint8Array(await request.arrayBuffer()) : void 0;
|
|
24002
24610
|
const lines2 = [`${request.method} ${url.pathname}${url.search} HTTP/1.1`, `Host: ${url.host}`];
|
|
24003
|
-
request.headers.forEach((
|
|
24004
|
-
if (!OWN_HEADERS2.has(name2)) lines2.push(`${name2}: ${
|
|
24611
|
+
request.headers.forEach((value2, name2) => {
|
|
24612
|
+
if (!OWN_HEADERS2.has(name2)) lines2.push(`${name2}: ${value2}`);
|
|
24005
24613
|
});
|
|
24006
24614
|
if (body) lines2.push(`Content-Length: ${body.length}`);
|
|
24007
24615
|
lines2.push("Connection: close", "", "");
|
|
24008
|
-
const head =
|
|
24616
|
+
const head = encoder9.encode(lines2.join("\r\n"));
|
|
24009
24617
|
const out = new Uint8Array(head.length + (body?.length ?? 0));
|
|
24010
24618
|
out.set(head);
|
|
24011
24619
|
if (body) out.set(body, head.length);
|
|
@@ -24059,8 +24667,8 @@ var KernelCallError = class extends Error {
|
|
|
24059
24667
|
this.code = code;
|
|
24060
24668
|
}
|
|
24061
24669
|
};
|
|
24062
|
-
var
|
|
24063
|
-
var bytesOf2 = (data) => typeof data === "string" ?
|
|
24670
|
+
var encoder10 = new TextEncoder();
|
|
24671
|
+
var bytesOf2 = (data) => typeof data === "string" ? encoder10.encode(data) : data;
|
|
24064
24672
|
var UNAVAILABLE = {
|
|
24065
24673
|
manualRedirects: false,
|
|
24066
24674
|
encodedBodies: false,
|
|
@@ -24080,7 +24688,7 @@ async function holdLock(locks) {
|
|
|
24080
24688
|
await granted2.promise;
|
|
24081
24689
|
return { name: name2, release: () => held.resolve() };
|
|
24082
24690
|
}
|
|
24083
|
-
function
|
|
24691
|
+
function concat8(chunks2) {
|
|
24084
24692
|
const out = new Uint8Array(chunks2.reduce((n, c) => n + c.length, 0));
|
|
24085
24693
|
let at = 0;
|
|
24086
24694
|
for (const chunk2 of chunks2) {
|
|
@@ -24307,7 +24915,7 @@ async function runOn(channel, argv, opts) {
|
|
|
24307
24915
|
onStderr: tee(2, onStderr)
|
|
24308
24916
|
});
|
|
24309
24917
|
const { status, signal } = await child.ended;
|
|
24310
|
-
const text = (fd) => new TextDecoder().decode(
|
|
24918
|
+
const text = (fd) => new TextDecoder().decode(concat8(chunks2[fd]));
|
|
24311
24919
|
return {
|
|
24312
24920
|
pid: child.pid,
|
|
24313
24921
|
status,
|
|
@@ -24556,6 +25164,12 @@ function textOf(on) {
|
|
|
24556
25164
|
const decoder4 = new TextDecoder();
|
|
24557
25165
|
return (bytes) => on(decoder4.decode(bytes, { stream: true }));
|
|
24558
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
|
+
}
|
|
24559
25173
|
async function createNodeKernel(options = {}) {
|
|
24560
25174
|
const root = options.root ?? memoryRoot();
|
|
24561
25175
|
const fs = new OpfsFs(root, void 0, void 0, { ranged: isMemoryRoot(root) });
|
|
@@ -24592,7 +25206,8 @@ async function createNodeKernel(options = {}) {
|
|
|
24592
25206
|
...options.protect ? { protect: options.protect } : {},
|
|
24593
25207
|
...options.sealed ? { sealed: options.sealed } : {},
|
|
24594
25208
|
...options.clipboard ? { clipboard: options.clipboard } : {},
|
|
24595
|
-
...options.approve ? { approve: options.approve } : {}
|
|
25209
|
+
...options.approve ? { approve: options.approve } : {},
|
|
25210
|
+
cron: { lock: cronLock(root), ...options.cron?.clock ? { clock: options.cron.clock } : {} }
|
|
24596
25211
|
});
|
|
24597
25212
|
await launcher.prepare();
|
|
24598
25213
|
const guard2 = (work) => new Promise((resolve2, reject) => {
|