@ai-ecoverse/slicc-kernel 1.152.2 → 1.154.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 +28 -3
- package/dist/driver-worker.js +147 -10
- package/dist/driver-worker.js.map +4 -4
- package/dist/index.js +168 -14
- package/dist/index.js.map +4 -4
- package/dist/kernel-worker.js +844 -167
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-driver-worker.js +147 -10
- package/dist/node-driver-worker.js.map +4 -4
- package/dist/node-process-worker.js +81 -24
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +982 -182
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +81 -24
- package/dist/process-worker.js.map +3 -3
- package/dist/types/client/attach.d.ts +2 -0
- package/dist/types/client/protocol.d.ts +4 -0
- package/dist/types/client/serve-client.d.ts +2 -0
- package/dist/types/embedder-relay.d.ts +58 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/kernel/embedder.d.ts +100 -0
- package/dist/types/kernel/fd-table.d.ts +3 -1
- package/dist/types/kernel/host.d.ts +8 -0
- package/dist/types/kernel/net/tls-client.d.ts +4 -1
- package/dist/types/kernel/net/tls-engine.d.ts +5 -2
- package/dist/types/kernel/net/tls-server.d.ts +2 -0
- package/dist/types/kernel/net/tls-uplink.d.ts +2 -0
- package/dist/types/kernel/process.d.ts +17 -0
- package/dist/types/kernel/socket-syscalls.d.ts +3 -0
- package/dist/types/launcher.d.ts +13 -0
- package/dist/types/node.d.ts +3 -0
- package/dist/types/process/js/js-net.d.ts +3 -0
- package/dist/types/process/kernel-streams.d.ts +2 -1
- package/dist/types/process/wasi/wasi-fds.d.ts +1 -0
- package/dist/types/serve.d.ts +3 -0
- package/package.json +4 -4
package/dist/node.js
CHANGED
|
@@ -93,6 +93,202 @@ function portCdpHook(ask, gone) {
|
|
|
93
93
|
});
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
// src/embedder-relay.ts
|
|
97
|
+
function fresh2(bytes) {
|
|
98
|
+
return bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength ? bytes : bytes.slice();
|
|
99
|
+
}
|
|
100
|
+
function errorOf(err) {
|
|
101
|
+
const name2 = err?.name;
|
|
102
|
+
const message3 = err instanceof Error ? err.message : String(err);
|
|
103
|
+
return { name: typeof name2 === "string" ? name2 : "Error", message: message3 };
|
|
104
|
+
}
|
|
105
|
+
function embedderAsker(port) {
|
|
106
|
+
const asks = /* @__PURE__ */ new Map();
|
|
107
|
+
let next3 = 0;
|
|
108
|
+
const post = (message3, transfer = []) => port.postMessage({ embedder: message3 }, transfer);
|
|
109
|
+
const push = (asked, item) => {
|
|
110
|
+
asked.chunks.push(item);
|
|
111
|
+
asked.wake?.();
|
|
112
|
+
};
|
|
113
|
+
const reply = (id2, asked) => new ReadableStream(
|
|
114
|
+
{
|
|
115
|
+
pull: async (controller) => {
|
|
116
|
+
if (asked.chunks.length === 0) {
|
|
117
|
+
post({ id: id2, pull: true });
|
|
118
|
+
await new Promise((resolve2) => {
|
|
119
|
+
asked.wake = resolve2;
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
const item = asked.chunks.shift();
|
|
123
|
+
if (item instanceof Uint8Array) controller.enqueue(item);
|
|
124
|
+
else if (item === null || item === void 0) {
|
|
125
|
+
asks.delete(id2);
|
|
126
|
+
controller.close();
|
|
127
|
+
} else {
|
|
128
|
+
asks.delete(id2);
|
|
129
|
+
controller.error(Object.assign(new Error(item.message), { name: item.name }));
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
cancel: (reason) => {
|
|
133
|
+
asks.delete(id2);
|
|
134
|
+
post({ id: id2, cancel: String(reason ?? "closed") });
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
{ highWaterMark: 0 }
|
|
138
|
+
);
|
|
139
|
+
const sendBody = async (id2, asked) => {
|
|
140
|
+
const got = await asked.body.read().catch(() => ({ done: true, value: void 0 }));
|
|
141
|
+
if (got.done) post({ id: id2, bodyEnd: true });
|
|
142
|
+
else {
|
|
143
|
+
const bytes = fresh2(got.value);
|
|
144
|
+
post({ id: id2, body: bytes }, [bytes.buffer]);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
const hookFor = (client, kinds) => ({
|
|
148
|
+
kinds,
|
|
149
|
+
handle: async (request) => {
|
|
150
|
+
const id2 = ++next3;
|
|
151
|
+
const asked = {
|
|
152
|
+
ready: Promise.withResolvers(),
|
|
153
|
+
chunks: [],
|
|
154
|
+
wake: void 0,
|
|
155
|
+
body: request.body.getReader(),
|
|
156
|
+
progress: request.progress
|
|
157
|
+
};
|
|
158
|
+
asks.set(id2, asked);
|
|
159
|
+
const cancel = () => {
|
|
160
|
+
asks.delete(id2);
|
|
161
|
+
post({
|
|
162
|
+
id: id2,
|
|
163
|
+
cancel: String(request.signal.reason?.message ?? "closed")
|
|
164
|
+
});
|
|
165
|
+
asked.ready.reject(request.signal.reason);
|
|
166
|
+
push(asked, { name: "AbortError", message: "cancelled" });
|
|
167
|
+
};
|
|
168
|
+
request.signal.addEventListener("abort", cancel, { once: true });
|
|
169
|
+
const { kind, options, stamp } = request;
|
|
170
|
+
post({ ask: { id: id2, client, kind, options, stamp } });
|
|
171
|
+
await asked.ready.promise;
|
|
172
|
+
return reply(id2, asked);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
const answer2 = (message3) => {
|
|
176
|
+
const asked = asks.get(message3.id);
|
|
177
|
+
if (!asked) return;
|
|
178
|
+
if ("ready" in message3) asked.ready.resolve();
|
|
179
|
+
else if ("chunk" in message3) push(asked, message3.chunk);
|
|
180
|
+
else if ("done" in message3) push(asked, null);
|
|
181
|
+
else if ("error" in message3) {
|
|
182
|
+
asked.ready.reject(
|
|
183
|
+
Object.assign(new Error(message3.error.message), { name: message3.error.name })
|
|
184
|
+
);
|
|
185
|
+
asks.delete(message3.id);
|
|
186
|
+
void asked.body.cancel(message3.error.message).catch(() => void 0);
|
|
187
|
+
push(asked, message3.error);
|
|
188
|
+
} else if ("progress" in message3) asked.progress(message3.progress);
|
|
189
|
+
else void sendBody(message3.id, asked);
|
|
190
|
+
};
|
|
191
|
+
return { hookFor, answer: answer2 };
|
|
192
|
+
}
|
|
193
|
+
function bytesOf(reply) {
|
|
194
|
+
if (reply instanceof ReadableStream) return reply;
|
|
195
|
+
const bytes = typeof reply === "string" ? new TextEncoder().encode(reply) : reply instanceof Uint8Array ? reply : new Uint8Array(0);
|
|
196
|
+
return new ReadableStream({
|
|
197
|
+
start(controller) {
|
|
198
|
+
if (bytes.length > 0) controller.enqueue(bytes);
|
|
199
|
+
controller.close();
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
function bodyStream(id2, state, post) {
|
|
204
|
+
return new ReadableStream(
|
|
205
|
+
{
|
|
206
|
+
pull: async (controller) => {
|
|
207
|
+
if (state.body.length === 0) post({ id: id2, bodyPull: true });
|
|
208
|
+
while (state.body.length === 0 && !state.abort.signal.aborted) {
|
|
209
|
+
await new Promise((resolve2) => {
|
|
210
|
+
state.wakeBody = resolve2;
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
const next3 = state.body.shift();
|
|
214
|
+
if (next3) controller.enqueue(next3);
|
|
215
|
+
else controller.close();
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
{ highWaterMark: 0 }
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
function embedderAnswerer(port, hookFor) {
|
|
222
|
+
const running = /* @__PURE__ */ new Map();
|
|
223
|
+
const post = (message3, transfer = []) => port.postMessage({ embedderReply: message3 }, transfer);
|
|
224
|
+
const fail3 = (id2, err) => {
|
|
225
|
+
running.delete(id2);
|
|
226
|
+
post({ id: id2, error: errorOf(err) });
|
|
227
|
+
};
|
|
228
|
+
const start2 = async (ask) => {
|
|
229
|
+
const state = { abort: new AbortController(), body: [], wakeBody: void 0 };
|
|
230
|
+
running.set(ask.id, state);
|
|
231
|
+
try {
|
|
232
|
+
const hook = hookFor(ask.client);
|
|
233
|
+
if (!hook || !Object.hasOwn(hook.kinds, ask.kind))
|
|
234
|
+
throw Object.assign(new Error(`this page does not answer ${ask.kind}`), {
|
|
235
|
+
name: "NotSupportedError"
|
|
236
|
+
});
|
|
237
|
+
const reply = await hook.handle({
|
|
238
|
+
kind: ask.kind,
|
|
239
|
+
options: ask.options,
|
|
240
|
+
body: bodyStream(ask.id, state, post),
|
|
241
|
+
stamp: ask.stamp,
|
|
242
|
+
signal: state.abort.signal,
|
|
243
|
+
progress: (line) => post({ id: ask.id, progress: String(line) })
|
|
244
|
+
});
|
|
245
|
+
state.reader = bytesOf(reply).getReader();
|
|
246
|
+
post({ id: ask.id, ready: true });
|
|
247
|
+
} catch (err) {
|
|
248
|
+
fail3(ask.id, err);
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
const pull = async (id2, state) => {
|
|
252
|
+
try {
|
|
253
|
+
const got = await state.reader.read();
|
|
254
|
+
if (got.done) {
|
|
255
|
+
running.delete(id2);
|
|
256
|
+
post({ id: id2, done: true });
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const bytes = fresh2(got.value);
|
|
260
|
+
post({ id: id2, chunk: bytes }, [bytes.buffer]);
|
|
261
|
+
} catch (err) {
|
|
262
|
+
fail3(id2, err);
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
const step2 = (message3) => {
|
|
266
|
+
const state = running.get(message3.id);
|
|
267
|
+
if (!state) return;
|
|
268
|
+
if ("body" in message3) state.body.push(message3.body);
|
|
269
|
+
else if ("bodyEnd" in message3) state.body.push(null);
|
|
270
|
+
else if ("pull" in message3) void pull(message3.id, state);
|
|
271
|
+
else {
|
|
272
|
+
running.delete(message3.id);
|
|
273
|
+
state.abort.abort(new DOMException(message3.cancel, "AbortError"));
|
|
274
|
+
void state.reader?.cancel(message3.cancel).catch(() => void 0);
|
|
275
|
+
}
|
|
276
|
+
state.wakeBody?.();
|
|
277
|
+
};
|
|
278
|
+
return {
|
|
279
|
+
handle(data) {
|
|
280
|
+
const message3 = data?.embedder;
|
|
281
|
+
if (!message3) return false;
|
|
282
|
+
if ("ask" in message3) void start2(message3.ask);
|
|
283
|
+
else step2(message3);
|
|
284
|
+
return true;
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
function embedderReplyOf(data) {
|
|
289
|
+
return data?.embedderReply;
|
|
290
|
+
}
|
|
291
|
+
|
|
96
292
|
// src/facade/port.ts
|
|
97
293
|
var FACADE_GONE = "the facade host is gone";
|
|
98
294
|
function serveFacadePort(port, hook, { name: name2, stamp }, onDone) {
|
|
@@ -1082,6 +1278,7 @@ function kernelFdKind(file) {
|
|
|
1082
1278
|
if (file.tty) return "tty";
|
|
1083
1279
|
if (file.sealed) return "sealed";
|
|
1084
1280
|
if (file.clipboard) return "clipboard";
|
|
1281
|
+
if (file.embedder) return "embedder";
|
|
1085
1282
|
return file.seek ? "file" : "stream";
|
|
1086
1283
|
}
|
|
1087
1284
|
var FdTable = class _FdTable {
|
|
@@ -3365,7 +3562,7 @@ function satisfies(version, range2) {
|
|
|
3365
3562
|
}
|
|
3366
3563
|
|
|
3367
3564
|
// src/version.ts
|
|
3368
|
-
var KERNEL_VERSION = true ? "1.
|
|
3565
|
+
var KERNEL_VERSION = true ? "1.154.0" : "0.0.0-dev";
|
|
3369
3566
|
var OS_RELEASE = "6.0.0-slicc";
|
|
3370
3567
|
function procVersion() {
|
|
3371
3568
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -4210,9 +4407,9 @@ var Crontabs = class {
|
|
|
4210
4407
|
const json5 = JSON.stringify({ v: TAGS_VERSION, ...kept });
|
|
4211
4408
|
if (json5 === await fs.readFile(TAGS_PATH).catch(() => "")) return;
|
|
4212
4409
|
const owner = owners ? { uid: 0, gid: 0, mode: 384 } : void 0;
|
|
4213
|
-
const
|
|
4214
|
-
await fs.writeFile(
|
|
4215
|
-
await fs.rename(
|
|
4410
|
+
const fresh3 = `${TAGS_PATH}.${crypto.randomUUID()}.new`;
|
|
4411
|
+
await fs.writeFile(fresh3, json5, owner);
|
|
4412
|
+
await fs.rename(fresh3, TAGS_PATH);
|
|
4216
4413
|
}
|
|
4217
4414
|
async install(path, target, text, caller) {
|
|
4218
4415
|
if (text.length > CRONTAB_MAX) return { error: "crontab: the table is too long" };
|
|
@@ -4226,11 +4423,11 @@ var Crontabs = class {
|
|
|
4226
4423
|
await fs.mkdir(SPOOL_DIR, { recursive: true });
|
|
4227
4424
|
if (owners) await fs.chown?.(SPOOL_DIR, { uid: 0, gid: 0, mode: 448, follow: false });
|
|
4228
4425
|
}
|
|
4229
|
-
const
|
|
4426
|
+
const fresh3 = `${SPOOL_DIR}/.${target.name}.${crypto.randomUUID()}.new`;
|
|
4230
4427
|
const owner = owners ? { uid: target.uid, gid: target.gid, mode: 384 } : void 0;
|
|
4231
4428
|
await this.retag(path, text, caller);
|
|
4232
|
-
await fs.writeFile(
|
|
4233
|
-
await fs.rename(
|
|
4429
|
+
await fs.writeFile(fresh3, text, owner);
|
|
4430
|
+
await fs.rename(fresh3, path);
|
|
4234
4431
|
return { text: "" };
|
|
4235
4432
|
}
|
|
4236
4433
|
};
|
|
@@ -4519,15 +4716,15 @@ var UnlinkedKeeper = class {
|
|
|
4519
4716
|
const releases = [];
|
|
4520
4717
|
const take = async () => {
|
|
4521
4718
|
for (; ; ) {
|
|
4522
|
-
const
|
|
4523
|
-
if (
|
|
4524
|
-
|
|
4525
|
-
if (paths.some((path) => path >
|
|
4719
|
+
const fresh3 = [...this.heldWithin(target).keys()].filter((path) => !paths.includes(path));
|
|
4720
|
+
if (fresh3.length === 0) return;
|
|
4721
|
+
fresh3.sort();
|
|
4722
|
+
if (paths.some((path) => path > fresh3[0])) {
|
|
4526
4723
|
for (const release of releases.splice(0)) release();
|
|
4527
|
-
|
|
4528
|
-
|
|
4724
|
+
fresh3.push(...paths.splice(0));
|
|
4725
|
+
fresh3.sort();
|
|
4529
4726
|
}
|
|
4530
|
-
for (const path of
|
|
4727
|
+
for (const path of fresh3) {
|
|
4531
4728
|
paths.push(path);
|
|
4532
4729
|
releases.push(await this.gate.acquire(path));
|
|
4533
4730
|
}
|
|
@@ -4862,10 +5059,10 @@ var CronService = class {
|
|
|
4862
5059
|
const text = JSON.stringify(stamp);
|
|
4863
5060
|
const old = await fs.readFile(STAMP_PATH).catch(() => void 0);
|
|
4864
5061
|
if (old === text || old === void 0 && text === EMPTY_STAMP) return;
|
|
4865
|
-
const
|
|
5062
|
+
const fresh3 = `${STAMP_PATH}.new`;
|
|
4866
5063
|
const owner = owners ? { uid: 0, gid: 0, mode: 384 } : void 0;
|
|
4867
|
-
await fs.writeFile(
|
|
4868
|
-
await fs.rename(
|
|
5064
|
+
await fs.writeFile(fresh3, text, owner);
|
|
5065
|
+
await fs.rename(fresh3, STAMP_PATH);
|
|
4869
5066
|
}
|
|
4870
5067
|
async load() {
|
|
4871
5068
|
const { fs } = this.host;
|
|
@@ -6301,13 +6498,13 @@ function materializer(fs, listedAbsent) {
|
|
|
6301
6498
|
};
|
|
6302
6499
|
}
|
|
6303
6500
|
function withEtcFiles(fs, files) {
|
|
6304
|
-
const
|
|
6501
|
+
const bytesOf5 = (path) => {
|
|
6305
6502
|
const text = files.get(path)?.();
|
|
6306
6503
|
return text === void 0 ? void 0 : new TextEncoder().encode(text);
|
|
6307
6504
|
};
|
|
6308
6505
|
const absent2 = (path) => fs.lstat(path).then(() => false, missing2);
|
|
6309
6506
|
const follow2 = linkFollower(fs, files);
|
|
6310
|
-
const listedAbsent = async (path) => files.has(path) && await absent2(path) ?
|
|
6507
|
+
const listedAbsent = async (path) => files.has(path) && await absent2(path) ? bytesOf5(path) : void 0;
|
|
6311
6508
|
const fallback = (path, make) => async (err) => {
|
|
6312
6509
|
const at = missing2(err) ? await follow2(path) : void 0;
|
|
6313
6510
|
const bytes = at === void 0 ? void 0 : await listedAbsent(at);
|
|
@@ -6380,10 +6577,10 @@ var FreshModules = class {
|
|
|
6380
6577
|
this.fresh.set(key, { umask: mask, pid, added: 0, setup: mask !== DEFAULT_UMASK });
|
|
6381
6578
|
}
|
|
6382
6579
|
forget(pid) {
|
|
6383
|
-
for (const [path,
|
|
6580
|
+
for (const [path, fresh3] of this.fresh) if (fresh3.pid === pid) this.fresh.delete(path);
|
|
6384
6581
|
}
|
|
6385
|
-
drop(
|
|
6386
|
-
for (const [key, note] of [...this.fresh]) if (note ===
|
|
6582
|
+
drop(fresh3) {
|
|
6583
|
+
for (const [key, note] of [...this.fresh]) if (note === fresh3) this.fresh.delete(key);
|
|
6387
6584
|
}
|
|
6388
6585
|
moved(from, to) {
|
|
6389
6586
|
const source = normalizePath(from);
|
|
@@ -6392,10 +6589,10 @@ var FreshModules = class {
|
|
|
6392
6589
|
for (const key of [...this.fresh.keys()]) {
|
|
6393
6590
|
if (key === target || within3(key, target)) this.fresh.delete(key);
|
|
6394
6591
|
}
|
|
6395
|
-
for (const [key,
|
|
6592
|
+
for (const [key, fresh3] of [...this.fresh]) {
|
|
6396
6593
|
if (key !== source && !within3(key, source)) continue;
|
|
6397
6594
|
this.fresh.delete(key);
|
|
6398
|
-
this.fresh.set(target + key.slice(source.length),
|
|
6595
|
+
this.fresh.set(target + key.slice(source.length), fresh3);
|
|
6399
6596
|
}
|
|
6400
6597
|
}
|
|
6401
6598
|
wrap(fs) {
|
|
@@ -6405,15 +6602,15 @@ var FreshModules = class {
|
|
|
6405
6602
|
};
|
|
6406
6603
|
const decide = async (given, known) => {
|
|
6407
6604
|
const path = normalizePath(given);
|
|
6408
|
-
const
|
|
6409
|
-
if (!
|
|
6605
|
+
const fresh3 = this.fresh.get(path);
|
|
6606
|
+
if (!fresh3) return;
|
|
6410
6607
|
const bytes = known && known.length >= MAGIC.length ? known : await head(path);
|
|
6411
|
-
const want = isModule(bytes) ? 73 & ~
|
|
6412
|
-
|
|
6413
|
-
if (want ===
|
|
6608
|
+
const want = isModule(bytes) ? 73 & ~fresh3.umask : 0;
|
|
6609
|
+
fresh3.setup = false;
|
|
6610
|
+
if (want === fresh3.added) return;
|
|
6414
6611
|
const mode = (await fs.stat(path)).mode & 4095;
|
|
6415
|
-
await fs.chmod(path, mode & ~
|
|
6416
|
-
|
|
6612
|
+
await fs.chmod(path, mode & ~fresh3.added | want);
|
|
6613
|
+
fresh3.added = want;
|
|
6417
6614
|
};
|
|
6418
6615
|
const overrides = {
|
|
6419
6616
|
writeFile: async (path, content, owner) => {
|
|
@@ -6426,9 +6623,9 @@ var FreshModules = class {
|
|
|
6426
6623
|
}
|
|
6427
6624
|
},
|
|
6428
6625
|
chmod: async (path, mode) => {
|
|
6429
|
-
const
|
|
6430
|
-
if (
|
|
6431
|
-
else if (
|
|
6626
|
+
const fresh3 = this.fresh.get(normalizePath(path));
|
|
6627
|
+
if (fresh3?.setup && (mode & 4095) === (438 & ~fresh3.umask)) fresh3.setup = false;
|
|
6628
|
+
else if (fresh3) this.drop(fresh3);
|
|
6432
6629
|
await fs.chmod(path, mode);
|
|
6433
6630
|
},
|
|
6434
6631
|
rm: async (path, options) => {
|
|
@@ -6445,8 +6642,8 @@ var FreshModules = class {
|
|
|
6445
6642
|
link: async (from, to, follow2) => {
|
|
6446
6643
|
await fs.link(from, to, follow2);
|
|
6447
6644
|
const source = follow2 && fs.realpath ? await fs.realpath(from, true).catch(() => from) : from;
|
|
6448
|
-
const
|
|
6449
|
-
if (
|
|
6645
|
+
const fresh3 = this.fresh.get(normalizePath(source));
|
|
6646
|
+
if (fresh3) this.fresh.set(normalizePath(to), fresh3);
|
|
6450
6647
|
}
|
|
6451
6648
|
};
|
|
6452
6649
|
const ranged2 = rangedOps(fs);
|
|
@@ -7150,7 +7347,7 @@ var FsWatchers = class {
|
|
|
7150
7347
|
};
|
|
7151
7348
|
const content = (run2, types) => async (...args) => {
|
|
7152
7349
|
const at = normalizePath(args[0]);
|
|
7153
|
-
const
|
|
7350
|
+
const fresh3 = this.covers(at) && !await fs.exists(at).catch(() => true);
|
|
7154
7351
|
let done4 = false;
|
|
7155
7352
|
try {
|
|
7156
7353
|
await run2(...args);
|
|
@@ -7159,11 +7356,11 @@ var FsWatchers = class {
|
|
|
7159
7356
|
const real = await realOf(at);
|
|
7160
7357
|
const paths = real === at ? [at] : [at, real];
|
|
7161
7358
|
this.report(paths);
|
|
7162
|
-
if (done4) for (const type of types(
|
|
7359
|
+
if (done4) for (const type of types(fresh3, args)) this.emit(type, paths);
|
|
7163
7360
|
}
|
|
7164
7361
|
};
|
|
7165
|
-
const written2 = (
|
|
7166
|
-
const overwritten = (
|
|
7362
|
+
const written2 = (fresh3) => fresh3 ? ["rename", "change"] : ["change"];
|
|
7363
|
+
const overwritten = (fresh3, args) => fresh3 || args[1].length === 0 ? written2(fresh3) : ["change", "change"];
|
|
7167
7364
|
const reshaping = (run2) => async (...args) => {
|
|
7168
7365
|
this.reshaped();
|
|
7169
7366
|
try {
|
|
@@ -7190,14 +7387,14 @@ var FsWatchers = class {
|
|
|
7190
7387
|
if (created4.length > 0 || !await fs.exists(ancestor)) created4.push(ancestor);
|
|
7191
7388
|
}
|
|
7192
7389
|
}
|
|
7193
|
-
const
|
|
7390
|
+
const fresh3 = !options?.recursive || this.typed.size > 0 && !await fs.exists(path);
|
|
7194
7391
|
let done4 = false;
|
|
7195
7392
|
try {
|
|
7196
7393
|
await fs.mkdir(path, options);
|
|
7197
7394
|
done4 = true;
|
|
7198
7395
|
} finally {
|
|
7199
7396
|
this.report([...created4, path]);
|
|
7200
|
-
if (done4) this.emit("rename",
|
|
7397
|
+
if (done4) this.emit("rename", fresh3 ? [...created4, path] : created4);
|
|
7201
7398
|
}
|
|
7202
7399
|
},
|
|
7203
7400
|
rm: reshaping(after(fs.rm.bind(fs), (path) => [path], "rename")),
|
|
@@ -7653,6 +7850,416 @@ var ClipboardBroker = class {
|
|
|
7653
7850
|
}
|
|
7654
7851
|
};
|
|
7655
7852
|
|
|
7853
|
+
// src/kernel/embedder.ts
|
|
7854
|
+
var EMBEDDER_PATH = "/dev/embedder";
|
|
7855
|
+
var EMBEDDER_HEADER_MAX = 64 * 1024;
|
|
7856
|
+
var EMBEDDER_WINDOW = 1024 * 1024;
|
|
7857
|
+
var EMBEDDER_BUDGET = 256 * 1024 * 1024;
|
|
7858
|
+
var EMBEDDER_PER_PROCESS = 16;
|
|
7859
|
+
var EMBEDDER_PROGRESS_PER_SECOND = 4;
|
|
7860
|
+
var KIND = /^[a-z][a-z0-9-]*(\.[a-z0-9-]+)*$/;
|
|
7861
|
+
var NL = 10;
|
|
7862
|
+
var READY2 = { readable: true, writable: true, hangup: false };
|
|
7863
|
+
function lineOf2(err) {
|
|
7864
|
+
const text = err instanceof Error ? err.message : String(err);
|
|
7865
|
+
return (text.split("\n")[0] ?? "").slice(0, 200);
|
|
7866
|
+
}
|
|
7867
|
+
var ERRNOS = {
|
|
7868
|
+
NotAllowedError: "EACCES",
|
|
7869
|
+
AbortError: "EACCES",
|
|
7870
|
+
NotSupportedError: "ENOTSUP",
|
|
7871
|
+
NotFoundError: "ENOENT"
|
|
7872
|
+
};
|
|
7873
|
+
function embedderFailure(err) {
|
|
7874
|
+
if (err instanceof KernelError) return err;
|
|
7875
|
+
const name2 = err?.name;
|
|
7876
|
+
return new KernelError(ERRNOS[String(name2)] ?? "EIO", lineOf2(err));
|
|
7877
|
+
}
|
|
7878
|
+
function headerOf(bytes) {
|
|
7879
|
+
let parsed2;
|
|
7880
|
+
try {
|
|
7881
|
+
parsed2 = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
7882
|
+
} catch {
|
|
7883
|
+
throw new KernelError("EINVAL", "the request header is not JSON");
|
|
7884
|
+
}
|
|
7885
|
+
if (typeof parsed2 !== "object" || parsed2 === null || Array.isArray(parsed2))
|
|
7886
|
+
throw new KernelError("EINVAL", "the request header is not an object");
|
|
7887
|
+
const { kind, ...options } = parsed2;
|
|
7888
|
+
if (typeof kind !== "string" || kind.length > 64 || !KIND.test(kind))
|
|
7889
|
+
throw new KernelError("EINVAL", "the request has no valid kind");
|
|
7890
|
+
return { kind, options };
|
|
7891
|
+
}
|
|
7892
|
+
function joined2(a, b) {
|
|
7893
|
+
const out = new Uint8Array(a.length + b.length);
|
|
7894
|
+
out.set(a);
|
|
7895
|
+
out.set(b, a.length);
|
|
7896
|
+
return out;
|
|
7897
|
+
}
|
|
7898
|
+
function aborted(signal) {
|
|
7899
|
+
if (!signal) return void 0;
|
|
7900
|
+
return new Promise((_, reject) => {
|
|
7901
|
+
const stop = () => reject(new KernelError("EINTR"));
|
|
7902
|
+
if (signal.aborted) stop();
|
|
7903
|
+
else signal.addEventListener("abort", stop, { once: true });
|
|
7904
|
+
});
|
|
7905
|
+
}
|
|
7906
|
+
async function interruptible2(work, signal) {
|
|
7907
|
+
const stop = aborted(signal);
|
|
7908
|
+
if (!stop) return work;
|
|
7909
|
+
stop.catch(() => void 0);
|
|
7910
|
+
return Promise.race([work, stop]);
|
|
7911
|
+
}
|
|
7912
|
+
var Budget2 = class {
|
|
7913
|
+
used = 0;
|
|
7914
|
+
limit;
|
|
7915
|
+
constructor(limit) {
|
|
7916
|
+
this.limit = limit;
|
|
7917
|
+
}
|
|
7918
|
+
take(n) {
|
|
7919
|
+
if (this.used + n > this.limit) return false;
|
|
7920
|
+
this.used += n;
|
|
7921
|
+
return true;
|
|
7922
|
+
}
|
|
7923
|
+
give(n) {
|
|
7924
|
+
this.used = Math.max(0, this.used - n);
|
|
7925
|
+
}
|
|
7926
|
+
};
|
|
7927
|
+
var BodyPipe = class {
|
|
7928
|
+
queue = [];
|
|
7929
|
+
size = 0;
|
|
7930
|
+
ended = false;
|
|
7931
|
+
wake;
|
|
7932
|
+
room;
|
|
7933
|
+
stream;
|
|
7934
|
+
constructor() {
|
|
7935
|
+
this.stream = new ReadableStream(
|
|
7936
|
+
{
|
|
7937
|
+
pull: async (controller) => {
|
|
7938
|
+
while (this.queue.length === 0 && !this.ended) {
|
|
7939
|
+
await new Promise((resolve2) => {
|
|
7940
|
+
this.wake = resolve2;
|
|
7941
|
+
});
|
|
7942
|
+
}
|
|
7943
|
+
const next3 = this.queue.shift();
|
|
7944
|
+
if (next3) {
|
|
7945
|
+
this.size -= next3.length;
|
|
7946
|
+
this.room?.();
|
|
7947
|
+
controller.enqueue(next3);
|
|
7948
|
+
} else controller.close();
|
|
7949
|
+
}
|
|
7950
|
+
},
|
|
7951
|
+
{ highWaterMark: 0 }
|
|
7952
|
+
);
|
|
7953
|
+
}
|
|
7954
|
+
get full() {
|
|
7955
|
+
return this.size >= EMBEDDER_WINDOW;
|
|
7956
|
+
}
|
|
7957
|
+
push(bytes) {
|
|
7958
|
+
if (bytes.length === 0) return;
|
|
7959
|
+
this.queue.push(bytes.slice());
|
|
7960
|
+
this.size += bytes.length;
|
|
7961
|
+
this.wake?.();
|
|
7962
|
+
}
|
|
7963
|
+
waitRoom() {
|
|
7964
|
+
return new Promise((resolve2) => {
|
|
7965
|
+
this.room = resolve2;
|
|
7966
|
+
});
|
|
7967
|
+
}
|
|
7968
|
+
end() {
|
|
7969
|
+
this.ended = true;
|
|
7970
|
+
this.wake?.();
|
|
7971
|
+
this.room?.();
|
|
7972
|
+
}
|
|
7973
|
+
};
|
|
7974
|
+
function replyStream(reply) {
|
|
7975
|
+
if (reply instanceof ReadableStream) return reply;
|
|
7976
|
+
const bytes = typeof reply === "string" ? new TextEncoder().encode(reply) : reply instanceof Uint8Array ? reply : new Uint8Array(0);
|
|
7977
|
+
return new ReadableStream({
|
|
7978
|
+
start(controller) {
|
|
7979
|
+
if (bytes.length > 0) controller.enqueue(bytes);
|
|
7980
|
+
controller.close();
|
|
7981
|
+
}
|
|
7982
|
+
});
|
|
7983
|
+
}
|
|
7984
|
+
var Throttle = class {
|
|
7985
|
+
window = 0;
|
|
7986
|
+
count = 0;
|
|
7987
|
+
allow(now) {
|
|
7988
|
+
if (now - this.window >= 1e3) {
|
|
7989
|
+
this.window = now;
|
|
7990
|
+
this.count = 0;
|
|
7991
|
+
}
|
|
7992
|
+
this.count += 1;
|
|
7993
|
+
return this.count <= EMBEDDER_PROGRESS_PER_SECOND;
|
|
7994
|
+
}
|
|
7995
|
+
};
|
|
7996
|
+
var EmbedderChannel = class {
|
|
7997
|
+
access;
|
|
7998
|
+
owner;
|
|
7999
|
+
caller;
|
|
8000
|
+
broker;
|
|
8001
|
+
header = new Uint8Array(0);
|
|
8002
|
+
body;
|
|
8003
|
+
reply;
|
|
8004
|
+
replied;
|
|
8005
|
+
rest;
|
|
8006
|
+
done = false;
|
|
8007
|
+
failure;
|
|
8008
|
+
reported = false;
|
|
8009
|
+
abort = new AbortController();
|
|
8010
|
+
closed = false;
|
|
8011
|
+
throttle = new Throttle();
|
|
8012
|
+
constructor(broker, access2, caller) {
|
|
8013
|
+
this.broker = broker;
|
|
8014
|
+
this.access = access2;
|
|
8015
|
+
this.caller = caller;
|
|
8016
|
+
this.owner = caller.pid;
|
|
8017
|
+
}
|
|
8018
|
+
get dispatched() {
|
|
8019
|
+
return this.body !== void 0;
|
|
8020
|
+
}
|
|
8021
|
+
fail(err) {
|
|
8022
|
+
this.failure ??= embedderFailure(err);
|
|
8023
|
+
return this.failure;
|
|
8024
|
+
}
|
|
8025
|
+
report(err) {
|
|
8026
|
+
this.reported = true;
|
|
8027
|
+
return this.fail(err);
|
|
8028
|
+
}
|
|
8029
|
+
async dispatch(bytes) {
|
|
8030
|
+
const { kind, options } = headerOf(bytes);
|
|
8031
|
+
const stamp = await this.broker.admit(kind, this.caller);
|
|
8032
|
+
const hook = this.broker.hookFor(this.caller.client);
|
|
8033
|
+
const body = new BodyPipe();
|
|
8034
|
+
this.body = body;
|
|
8035
|
+
const caller = this.caller;
|
|
8036
|
+
const progress = (line) => {
|
|
8037
|
+
if (this.throttle.allow(Date.now())) caller.progress(lineOf2(line));
|
|
8038
|
+
};
|
|
8039
|
+
const asked = Promise.resolve().then(
|
|
8040
|
+
() => hook.handle({
|
|
8041
|
+
kind,
|
|
8042
|
+
options,
|
|
8043
|
+
body: body.stream,
|
|
8044
|
+
stamp,
|
|
8045
|
+
signal: this.abort.signal,
|
|
8046
|
+
progress
|
|
8047
|
+
})
|
|
8048
|
+
).then((reply) => replyStream(reply).getReader());
|
|
8049
|
+
this.replied = asked.catch((err) => {
|
|
8050
|
+
body.end();
|
|
8051
|
+
throw this.fail(err);
|
|
8052
|
+
});
|
|
8053
|
+
this.replied.catch(() => void 0);
|
|
8054
|
+
}
|
|
8055
|
+
async write(bytes, signal) {
|
|
8056
|
+
if (this.access === "read") throw new KernelError("EBADF");
|
|
8057
|
+
if (this.failure) throw this.report(this.failure);
|
|
8058
|
+
if (this.reply || this.done) throw new KernelError("EBADF");
|
|
8059
|
+
if (this.body) return this.writeBody(bytes, signal);
|
|
8060
|
+
const at = bytes.indexOf(NL);
|
|
8061
|
+
const head = at < 0 ? bytes : bytes.subarray(0, at);
|
|
8062
|
+
if (this.header.length + head.length > EMBEDDER_HEADER_MAX)
|
|
8063
|
+
throw this.report(new KernelError("EINVAL", "the request header is too long"));
|
|
8064
|
+
this.header = joined2(this.header, head);
|
|
8065
|
+
if (at < 0) return bytes.length;
|
|
8066
|
+
try {
|
|
8067
|
+
await this.dispatch(this.header);
|
|
8068
|
+
} catch (err) {
|
|
8069
|
+
throw this.report(err);
|
|
8070
|
+
}
|
|
8071
|
+
this.body?.push(bytes.subarray(at + 1));
|
|
8072
|
+
return bytes.length;
|
|
8073
|
+
}
|
|
8074
|
+
async writeBody(bytes, signal) {
|
|
8075
|
+
const body = this.body;
|
|
8076
|
+
while (body.full && !this.failure) {
|
|
8077
|
+
await interruptible2(body.waitRoom(), signal).catch((err) => {
|
|
8078
|
+
this.cancel("interrupted");
|
|
8079
|
+
throw err;
|
|
8080
|
+
});
|
|
8081
|
+
}
|
|
8082
|
+
if (this.failure) throw this.report(this.failure);
|
|
8083
|
+
body.push(bytes);
|
|
8084
|
+
return bytes.length;
|
|
8085
|
+
}
|
|
8086
|
+
async readerOf(signal) {
|
|
8087
|
+
if (this.reply) return this.reply;
|
|
8088
|
+
if (!this.body) {
|
|
8089
|
+
try {
|
|
8090
|
+
await this.dispatch(this.header);
|
|
8091
|
+
} catch (err) {
|
|
8092
|
+
throw this.fail(err);
|
|
8093
|
+
}
|
|
8094
|
+
}
|
|
8095
|
+
this.body?.end();
|
|
8096
|
+
this.reply = await interruptible2(
|
|
8097
|
+
this.replied,
|
|
8098
|
+
signal
|
|
8099
|
+
);
|
|
8100
|
+
return this.reply;
|
|
8101
|
+
}
|
|
8102
|
+
async read(max, signal) {
|
|
8103
|
+
if (this.access === "write") throw new KernelError("EBADF");
|
|
8104
|
+
if (this.failure) throw this.report(this.failure);
|
|
8105
|
+
if (this.done || max <= 0) return new Uint8Array(0);
|
|
8106
|
+
try {
|
|
8107
|
+
return await this.next(max, signal);
|
|
8108
|
+
} catch (err) {
|
|
8109
|
+
if (err instanceof KernelError && err.code === "EINTR") {
|
|
8110
|
+
this.cancel("interrupted");
|
|
8111
|
+
throw err;
|
|
8112
|
+
}
|
|
8113
|
+
throw this.report(err);
|
|
8114
|
+
}
|
|
8115
|
+
}
|
|
8116
|
+
async next(max, signal) {
|
|
8117
|
+
const reader = await this.readerOf(signal);
|
|
8118
|
+
let chunk2 = this.rest;
|
|
8119
|
+
this.rest = void 0;
|
|
8120
|
+
if (!chunk2) {
|
|
8121
|
+
const got = await interruptible2(reader.read(), signal);
|
|
8122
|
+
if (got.done) {
|
|
8123
|
+
this.done = true;
|
|
8124
|
+
return new Uint8Array(0);
|
|
8125
|
+
}
|
|
8126
|
+
chunk2 = got.value;
|
|
8127
|
+
}
|
|
8128
|
+
if (chunk2.length > max) this.rest = chunk2.subarray(max);
|
|
8129
|
+
return chunk2.subarray(0, max);
|
|
8130
|
+
}
|
|
8131
|
+
poll() {
|
|
8132
|
+
return this.body?.full ? { ...READY2, writable: false } : READY2;
|
|
8133
|
+
}
|
|
8134
|
+
cancel(reason) {
|
|
8135
|
+
if (this.abort.signal.aborted) return;
|
|
8136
|
+
this.abort.abort(new DOMException(reason, "AbortError"));
|
|
8137
|
+
this.body?.end();
|
|
8138
|
+
void this.reply?.cancel(reason).catch(() => void 0);
|
|
8139
|
+
}
|
|
8140
|
+
async close() {
|
|
8141
|
+
if (this.closed) return;
|
|
8142
|
+
const signal = this.caller.closing();
|
|
8143
|
+
this.closed = true;
|
|
8144
|
+
try {
|
|
8145
|
+
if (this.access === "read") return;
|
|
8146
|
+
if (this.failure) {
|
|
8147
|
+
if (this.reported) return;
|
|
8148
|
+
throw this.report(this.failure);
|
|
8149
|
+
}
|
|
8150
|
+
if (this.access === "both" && this.dispatched) return;
|
|
8151
|
+
if (!this.dispatched && this.header.length === 0) return;
|
|
8152
|
+
await this.drain(signal);
|
|
8153
|
+
} finally {
|
|
8154
|
+
if (!this.done) this.cancel("closed");
|
|
8155
|
+
this.broker.release(this);
|
|
8156
|
+
}
|
|
8157
|
+
}
|
|
8158
|
+
async drain(signal) {
|
|
8159
|
+
try {
|
|
8160
|
+
const reader = await this.readerOf(signal);
|
|
8161
|
+
for (; ; ) {
|
|
8162
|
+
const got = await interruptible2(reader.read(), signal);
|
|
8163
|
+
if (got.done) break;
|
|
8164
|
+
}
|
|
8165
|
+
this.done = true;
|
|
8166
|
+
} catch (err) {
|
|
8167
|
+
if (err instanceof KernelError && err.code === "EINTR") this.cancel("interrupted");
|
|
8168
|
+
throw this.fail(err);
|
|
8169
|
+
}
|
|
8170
|
+
}
|
|
8171
|
+
};
|
|
8172
|
+
var EmbedderBroker = class {
|
|
8173
|
+
users;
|
|
8174
|
+
lookup;
|
|
8175
|
+
hooks = /* @__PURE__ */ new Map();
|
|
8176
|
+
budget;
|
|
8177
|
+
open = /* @__PURE__ */ new Map();
|
|
8178
|
+
tagsOf;
|
|
8179
|
+
constructor(users, lookup4, tagsOf = () => void 0, budget = EMBEDDER_BUDGET) {
|
|
8180
|
+
this.users = users;
|
|
8181
|
+
this.tagsOf = tagsOf;
|
|
8182
|
+
this.lookup = lookup4;
|
|
8183
|
+
this.budget = new Budget2(budget);
|
|
8184
|
+
}
|
|
8185
|
+
register(client, hook) {
|
|
8186
|
+
if (!hook) return () => void 0;
|
|
8187
|
+
this.hooks.set(client, hook);
|
|
8188
|
+
return () => {
|
|
8189
|
+
if (this.hooks.get(client) === hook) this.hooks.delete(client);
|
|
8190
|
+
};
|
|
8191
|
+
}
|
|
8192
|
+
hookFor(client) {
|
|
8193
|
+
return this.hooks.get(client);
|
|
8194
|
+
}
|
|
8195
|
+
async allowed(policy, caller) {
|
|
8196
|
+
if (caller.euid === 0 || caller.euid === caller.sessionUid) return true;
|
|
8197
|
+
if (policy.group !== void 0) {
|
|
8198
|
+
const gid = await this.lookup.groupId(policy.group);
|
|
8199
|
+
if (gid !== void 0 && (caller.egid === gid || caller.groups.includes(gid))) return true;
|
|
8200
|
+
}
|
|
8201
|
+
for (const user of policy.users ?? []) {
|
|
8202
|
+
const uid = typeof user === "number" ? user : await this.lookup.userId(user);
|
|
8203
|
+
if (uid === caller.euid) return true;
|
|
8204
|
+
}
|
|
8205
|
+
return false;
|
|
8206
|
+
}
|
|
8207
|
+
async admit(kind, caller) {
|
|
8208
|
+
const hook = this.hooks.get(caller.client);
|
|
8209
|
+
if (!hook) throw new KernelError("ENOTSUP", "no page answers requests for this session");
|
|
8210
|
+
const policy = Object.hasOwn(hook.kinds, kind) ? hook.kinds[kind] : void 0;
|
|
8211
|
+
if (!policy) throw new KernelError("ENOTSUP", `this embedder does not answer ${kind}`);
|
|
8212
|
+
if (this.users !== "off" && !await this.allowed(policy, caller))
|
|
8213
|
+
throw new KernelError("EACCES", `${kind} is not allowed for this user`);
|
|
8214
|
+
const tags = caller.tags;
|
|
8215
|
+
return {
|
|
8216
|
+
pid: caller.shownPid,
|
|
8217
|
+
uid: caller.euid,
|
|
8218
|
+
gid: caller.egid,
|
|
8219
|
+
groups: [...caller.groups],
|
|
8220
|
+
users: this.users,
|
|
8221
|
+
kind,
|
|
8222
|
+
...tags?.length ? { tag: tags[0], tags: [...tags] } : {}
|
|
8223
|
+
};
|
|
8224
|
+
}
|
|
8225
|
+
channel(access2, caller) {
|
|
8226
|
+
const mine = this.open.get(caller.pid) ?? /* @__PURE__ */ new Set();
|
|
8227
|
+
if (mine.size >= EMBEDDER_PER_PROCESS)
|
|
8228
|
+
throw new KernelError("EMFILE", `at most ${EMBEDDER_PER_PROCESS} requests per process`);
|
|
8229
|
+
if (!this.budget.take(2 * EMBEDDER_WINDOW))
|
|
8230
|
+
throw new KernelError("EAGAIN", "the embedder request budget is spent");
|
|
8231
|
+
const channel = new EmbedderChannel(this, access2, caller);
|
|
8232
|
+
mine.add(channel);
|
|
8233
|
+
this.open.set(caller.pid, mine);
|
|
8234
|
+
return new OpenFile({
|
|
8235
|
+
read: channel.read.bind(channel),
|
|
8236
|
+
write: (bytes, signal) => channel.write(bytes, signal),
|
|
8237
|
+
poll: () => channel.poll(),
|
|
8238
|
+
close: () => channel.close(),
|
|
8239
|
+
embedder: channel
|
|
8240
|
+
});
|
|
8241
|
+
}
|
|
8242
|
+
release(channel) {
|
|
8243
|
+
const mine = this.open.get(channel.owner);
|
|
8244
|
+
if (!mine?.delete(channel)) return;
|
|
8245
|
+
if (mine.size === 0) this.open.delete(channel.owner);
|
|
8246
|
+
this.budget.give(2 * EMBEDDER_WINDOW);
|
|
8247
|
+
}
|
|
8248
|
+
};
|
|
8249
|
+
function kindsOf(hook) {
|
|
8250
|
+
if (typeof hook?.handle !== "function" || typeof hook.kinds !== "object" || !hook.kinds)
|
|
8251
|
+
throw new TypeError("requests needs kinds and handle");
|
|
8252
|
+
return Object.fromEntries(
|
|
8253
|
+
Object.entries(hook.kinds).map(([kind, policy]) => [
|
|
8254
|
+
kind,
|
|
8255
|
+
{
|
|
8256
|
+
...policy?.group !== void 0 ? { group: String(policy.group) } : {},
|
|
8257
|
+
...policy?.users ? { users: [...policy.users] } : {}
|
|
8258
|
+
}
|
|
8259
|
+
])
|
|
8260
|
+
);
|
|
8261
|
+
}
|
|
8262
|
+
|
|
7656
8263
|
// src/kernel/exec-ticket.ts
|
|
7657
8264
|
var TICKET_ENV = "SLICC_SEALED_TICKET";
|
|
7658
8265
|
var TICKET_TTL_MS = 3e4;
|
|
@@ -8221,9 +8828,9 @@ var HeldPaths = class extends Map {
|
|
|
8221
8828
|
return false;
|
|
8222
8829
|
}
|
|
8223
8830
|
keep(path, file) {
|
|
8224
|
-
const
|
|
8225
|
-
for (const id2 of
|
|
8226
|
-
this.uses.set(file, Math.max(
|
|
8831
|
+
const fresh3 = this.handlesAt(path).filter((id2) => !this.keptHandles.has(id2));
|
|
8832
|
+
for (const id2 of fresh3) this.keptHandles.set(id2, file);
|
|
8833
|
+
this.uses.set(file, Math.max(fresh3.length, 1));
|
|
8227
8834
|
this.unlinked.set(path, file);
|
|
8228
8835
|
}
|
|
8229
8836
|
unkeep(path, file) {
|
|
@@ -9419,8 +10026,8 @@ var MountFs = class _MountFs {
|
|
|
9419
10026
|
}
|
|
9420
10027
|
this.writable(mount, real);
|
|
9421
10028
|
const { uid, gid, mode } = change;
|
|
9422
|
-
const
|
|
9423
|
-
const set3 =
|
|
10029
|
+
const fresh3 = change.kind === "new" && { uid, gid, mode };
|
|
10030
|
+
const set3 = fresh3 ? await this.driverOwner(found, real, fresh3, false) : change;
|
|
9424
10031
|
this.table.forget(mount, real);
|
|
9425
10032
|
const attrs = Object.entries({ uid: set3.uid, gid: set3.gid, mode: set3.mode });
|
|
9426
10033
|
await mount.conn.call({
|
|
@@ -9692,10 +10299,10 @@ async function runMkdir(entry, path, req) {
|
|
|
9692
10299
|
const plain3 = plainDirMode(entry, req.mode);
|
|
9693
10300
|
const parentsMode = !req.exclusive ? plainParentsMode(entry) : void 0;
|
|
9694
10301
|
const fixParents = parentsMode !== void 0 ? await missingParents(fs, path, parentsMode) : void 0;
|
|
9695
|
-
const
|
|
10302
|
+
const fresh3 = plain3 !== void 0 && !await fs.exists(path);
|
|
9696
10303
|
await (req.exclusive ? mkdirExclusive(entry, path, req.mode) : fs.mkdir(path, mkdirOptions(entry, req.mode)));
|
|
9697
10304
|
await fixParents?.();
|
|
9698
|
-
if (
|
|
10305
|
+
if (fresh3) await fs.chmod(path, plain3);
|
|
9699
10306
|
return done;
|
|
9700
10307
|
}
|
|
9701
10308
|
async function shownAs(entry, path, st) {
|
|
@@ -10699,9 +11306,9 @@ var Pages = class {
|
|
|
10699
11306
|
const page = (start2 + at) / PAGE;
|
|
10700
11307
|
if (this.pages.has(page)) continue;
|
|
10701
11308
|
const part = bytes.subarray(at, Math.min(at + PAGE, bytes.length));
|
|
10702
|
-
const
|
|
10703
|
-
|
|
10704
|
-
this.pages.set(page,
|
|
11309
|
+
const fresh3 = this.take(part.length);
|
|
11310
|
+
fresh3.set(part);
|
|
11311
|
+
this.pages.set(page, fresh3);
|
|
10705
11312
|
}
|
|
10706
11313
|
}
|
|
10707
11314
|
read(at, length2) {
|
|
@@ -12820,6 +13427,7 @@ var TLS_SERVER_REQUEST_CERT = 1;
|
|
|
12820
13427
|
var TLS_SERVER_REQUIRE_CERT = 2;
|
|
12821
13428
|
var TLS_SERVER_SELECT = 4;
|
|
12822
13429
|
var TLS_HANDSHAKE_SELECT = 2;
|
|
13430
|
+
var TLS_KEYLOG = 8;
|
|
12823
13431
|
var SCRATCH = 64 * 1024;
|
|
12824
13432
|
var EOF = -1;
|
|
12825
13433
|
var TlsError = class extends Error {
|
|
@@ -12887,6 +13495,9 @@ var TlsEngine = class {
|
|
|
12887
13495
|
if (!ptr) throw this.error(this.m._tls_last_error(), "server certificate");
|
|
12888
13496
|
return new TlsLeaf(this, this.m, ptr);
|
|
12889
13497
|
}
|
|
13498
|
+
get keylogs() {
|
|
13499
|
+
return typeof this.m._tls_keylog === "function";
|
|
13500
|
+
}
|
|
12890
13501
|
get serverSelect() {
|
|
12891
13502
|
return typeof this.m._tls_server_select === "function";
|
|
12892
13503
|
}
|
|
@@ -12917,9 +13528,11 @@ var TlsEngine = class {
|
|
|
12917
13528
|
this.m._free(ptr);
|
|
12918
13529
|
}
|
|
12919
13530
|
}
|
|
12920
|
-
intoScratch(fn) {
|
|
13531
|
+
intoScratch(fn, secret = false) {
|
|
12921
13532
|
const n = fn(this.scratch, SCRATCH);
|
|
12922
|
-
|
|
13533
|
+
const out = n > 0 ? this.taken(n) : n;
|
|
13534
|
+
if (secret && n > 0) this.m.HEAPU8.fill(0, this.scratch, this.scratch + n);
|
|
13535
|
+
return out;
|
|
12923
13536
|
}
|
|
12924
13537
|
get sessionControls() {
|
|
12925
13538
|
return typeof this.m._tls_client_cert === "function";
|
|
@@ -12963,18 +13576,18 @@ var TlsEngine = class {
|
|
|
12963
13576
|
chainFlags(store, chain2, hostname) {
|
|
12964
13577
|
const verify = this.m._tls_chain_verify;
|
|
12965
13578
|
if (!verify || chain2.length === 0) return void 0;
|
|
12966
|
-
const
|
|
13579
|
+
const joined5 = new Uint8Array(chain2.reduce((n, c) => n + c.length, 0));
|
|
12967
13580
|
let at = 0;
|
|
12968
13581
|
for (const der2 of chain2) {
|
|
12969
|
-
|
|
13582
|
+
joined5.set(der2, at);
|
|
12970
13583
|
at += der2.length;
|
|
12971
13584
|
}
|
|
12972
13585
|
const name2 = this.put(new TextEncoder().encode(hostname));
|
|
12973
13586
|
try {
|
|
12974
|
-
return this.withBytes(
|
|
13587
|
+
return this.withBytes(joined5, (p) => {
|
|
12975
13588
|
const out = this.scratch;
|
|
12976
13589
|
this.m.HEAPU8.fill(255, out, out + 4);
|
|
12977
|
-
const ret = verify(store.ptr, p,
|
|
13590
|
+
const ret = verify(store.ptr, p, joined5.length, name2, out);
|
|
12978
13591
|
const flags2 = new DataView(this.m.HEAPU8.buffer, out, 4).getUint32(0, true);
|
|
12979
13592
|
if (ret === 0) return flags2 === 0 ? 0 : void 0;
|
|
12980
13593
|
return ret === 1 && flags2 !== 0 ? flags2 : void 0;
|
|
@@ -13130,6 +13743,14 @@ var TlsSession = class {
|
|
|
13130
13743
|
get version() {
|
|
13131
13744
|
return this.c._tls_version(this.ptr);
|
|
13132
13745
|
}
|
|
13746
|
+
keylog() {
|
|
13747
|
+
const drain2 = this.m._tls_keylog;
|
|
13748
|
+
const out = this.engine.intoScratch((p, max) => drain2(this.ptr, p, max), true);
|
|
13749
|
+
if (!(out instanceof Uint8Array)) return [];
|
|
13750
|
+
const text = new TextDecoder().decode(out);
|
|
13751
|
+
out.fill(0);
|
|
13752
|
+
return text.split("\n").filter((line) => line.length > 0);
|
|
13753
|
+
}
|
|
13133
13754
|
get sni() {
|
|
13134
13755
|
const out = this.engine.intoScratch(
|
|
13135
13756
|
(p, max) => this.m._tls_sni(this.ptr, p, max)
|
|
@@ -14650,7 +15271,7 @@ function isIP(name2) {
|
|
|
14650
15271
|
return ipv4Bytes(name2) !== void 0 || name2.includes(":") && ipv6Groups(name2) !== void 0;
|
|
14651
15272
|
}
|
|
14652
15273
|
function clientFlags(o) {
|
|
14653
|
-
return (o.insecure ? TLS_CLIENT_INSECURE_SKIP_VERIFY : 0) | (o.sni === false ? TLS_CLIENT_NO_SNI : 0) | (o.checkHostname === false ? TLS_CLIENT_VERIFY_CHAIN_ONLY : 0);
|
|
15274
|
+
return (o.insecure ? TLS_CLIENT_INSECURE_SKIP_VERIFY : 0) | (o.sni === false ? TLS_CLIENT_NO_SNI : 0) | (o.checkHostname === false ? TLS_CLIENT_VERIFY_CHAIN_ONLY : 0) | (o.keylog ? TLS_KEYLOG : 0);
|
|
14654
15275
|
}
|
|
14655
15276
|
function openSession(o) {
|
|
14656
15277
|
return o.engine.clientSession(o.store, o.servername, o.alpn, clientFlags(o));
|
|
@@ -14765,7 +15386,8 @@ async function infoOf(o, session) {
|
|
|
14765
15386
|
peerCertificates: chain2,
|
|
14766
15387
|
...controlsOf(o, session, protocol, chain2, shape),
|
|
14767
15388
|
verified: verdictOf(o, session),
|
|
14768
|
-
handshakeAt: Date.now()
|
|
15389
|
+
handshakeAt: Date.now(),
|
|
15390
|
+
...o.keylog ? { keylog: session.keylog() } : {}
|
|
14769
15391
|
};
|
|
14770
15392
|
}
|
|
14771
15393
|
var FATAL_ALERT = -30592;
|
|
@@ -14885,7 +15507,7 @@ async function serverHandshake(conn, session, inbox, hooks) {
|
|
|
14885
15507
|
}
|
|
14886
15508
|
}
|
|
14887
15509
|
}
|
|
14888
|
-
async function tlsServer(conn, session, clientCerts, select) {
|
|
15510
|
+
async function tlsServer(conn, session, clientCerts, select, keylog = false) {
|
|
14889
15511
|
let first;
|
|
14890
15512
|
const watched = {
|
|
14891
15513
|
...conn,
|
|
@@ -14908,7 +15530,8 @@ async function tlsServer(conn, session, clientCerts, select) {
|
|
|
14908
15530
|
servername: session.sni,
|
|
14909
15531
|
authorized: clientCerts && chain2.length > 0 && code === void 0,
|
|
14910
15532
|
...clientCerts && chain2.length > 0 && code ? { authorizationError: code } : {},
|
|
14911
|
-
peerCertificates: chain2
|
|
15533
|
+
peerCertificates: chain2,
|
|
15534
|
+
...keylog ? { keylog: session.keylog() } : {}
|
|
14912
15535
|
};
|
|
14913
15536
|
return { conn: plaintext(conn, session, inbox), info };
|
|
14914
15537
|
} catch (err) {
|
|
@@ -15708,6 +16331,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
|
15708
16331
|
...file.tty ? { tty: file.tty } : {},
|
|
15709
16332
|
identity: file.identity ?? file,
|
|
15710
16333
|
...file.clipboard ? { clipboard: file.clipboard } : {},
|
|
16334
|
+
...file.embedder ? { embedder: file.embedder } : {},
|
|
15711
16335
|
...file.write ? {
|
|
15712
16336
|
write: async (bytes, signal) => {
|
|
15713
16337
|
await turn(signal);
|
|
@@ -15764,7 +16388,8 @@ function scrubStdio(fds, scrubber) {
|
|
|
15764
16388
|
const stdio = stdioFiles(fds);
|
|
15765
16389
|
for (const fd of fds.numbers()) {
|
|
15766
16390
|
const original = fds.get(fd);
|
|
15767
|
-
|
|
16391
|
+
const named = original.file.tty || original.file.clipboard || original.file.embedder;
|
|
16392
|
+
if (!stdio.has(original) && !named) continue;
|
|
15768
16393
|
const known = wrapped.get(original);
|
|
15769
16394
|
const flags2 = fds.statusFlags(fd);
|
|
15770
16395
|
const wrapper = known ? known.retain() : scrubbed(original.retain(), scrubber);
|
|
@@ -15777,9 +16402,9 @@ function scrubStdio(fds, scrubber) {
|
|
|
15777
16402
|
// src/kernel/net/sealed-scrubs.ts
|
|
15778
16403
|
function addTo(tree2, host, secrets) {
|
|
15779
16404
|
const entry = tree2.get(host) ?? { secrets: [], version: 0, scrubber: void 0 };
|
|
15780
|
-
const
|
|
15781
|
-
if (
|
|
15782
|
-
entry.secrets = [...entry.secrets, ...
|
|
16405
|
+
const fresh3 = secrets.filter((s) => !entry.secrets.some((e) => e.value === s.value));
|
|
16406
|
+
if (fresh3.length === 0) return;
|
|
16407
|
+
entry.secrets = [...entry.secrets, ...fresh3];
|
|
15783
16408
|
entry.version += 1;
|
|
15784
16409
|
entry.scrubber = void 0;
|
|
15785
16410
|
tree2.set(host, entry);
|
|
@@ -15993,13 +16618,13 @@ function serialized(reply) {
|
|
|
15993
16618
|
const text = JSON.stringify(reply);
|
|
15994
16619
|
plain3 = text === void 0 ? void 0 : JSON.parse(text);
|
|
15995
16620
|
} catch (err) {
|
|
15996
|
-
return JSON.stringify(errorReply("EIO",
|
|
16621
|
+
return JSON.stringify(errorReply("EIO", lineOf3(err)));
|
|
15997
16622
|
}
|
|
15998
16623
|
if (!isRecord(plain3)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
|
|
15999
16624
|
const { v: _, ...rest2 } = plain3;
|
|
16000
16625
|
return JSON.stringify({ v: 1, ...rest2 });
|
|
16001
16626
|
}
|
|
16002
|
-
function
|
|
16627
|
+
function lineOf3(err) {
|
|
16003
16628
|
const text = err instanceof Error ? err.message : String(err);
|
|
16004
16629
|
return (text.split("\n")[0] ?? "").slice(0, 200);
|
|
16005
16630
|
}
|
|
@@ -16050,7 +16675,7 @@ var SealedChannel = class {
|
|
|
16050
16675
|
if (signal.aborted) return void 0;
|
|
16051
16676
|
const asked = Promise.resolve().then(() => hook(req, { signal })).then(
|
|
16052
16677
|
(reply2) => isRecord(reply2) ? reply2 : errorReply("EIO", "the vault gave no reply"),
|
|
16053
|
-
(err) => errorReply("EIO",
|
|
16678
|
+
(err) => errorReply("EIO", lineOf3(err))
|
|
16054
16679
|
);
|
|
16055
16680
|
const reply = await Promise.race([asked, stopped]);
|
|
16056
16681
|
if (!signal.aborted) return reply;
|
|
@@ -17167,13 +17792,13 @@ var PgServer = class {
|
|
|
17167
17792
|
at += whole;
|
|
17168
17793
|
}
|
|
17169
17794
|
this.buffer = data.slice(at);
|
|
17170
|
-
const
|
|
17795
|
+
const joined5 = new Uint8Array(out.reduce((n, b) => n + b.length, 0));
|
|
17171
17796
|
let to = 0;
|
|
17172
17797
|
for (const b of out) {
|
|
17173
|
-
|
|
17798
|
+
joined5.set(b, to);
|
|
17174
17799
|
to += b.length;
|
|
17175
17800
|
}
|
|
17176
|
-
return
|
|
17801
|
+
return joined5;
|
|
17177
17802
|
}
|
|
17178
17803
|
};
|
|
17179
17804
|
function frame3(type, body) {
|
|
@@ -17396,7 +18021,7 @@ function latin12(bytes) {
|
|
|
17396
18021
|
for (const b of bytes) out += String.fromCharCode(b);
|
|
17397
18022
|
return out;
|
|
17398
18023
|
}
|
|
17399
|
-
function
|
|
18024
|
+
function bytesOf2(text) {
|
|
17400
18025
|
const out = new Uint8Array(text.length);
|
|
17401
18026
|
for (let i = 0; i < text.length; i++) out[i] = text.charCodeAt(i);
|
|
17402
18027
|
return out;
|
|
@@ -17515,12 +18140,12 @@ var SessionWriter = class {
|
|
|
17515
18140
|
if (this.failed !== void 0) throw this.failed;
|
|
17516
18141
|
if (this.mode === "pass") return this.conn.write(bytes);
|
|
17517
18142
|
clearTimeout(this.timer);
|
|
17518
|
-
const
|
|
17519
|
-
|
|
17520
|
-
|
|
18143
|
+
const joined5 = new Uint8Array(this.buffer.length + bytes.length);
|
|
18144
|
+
joined5.set(this.buffer);
|
|
18145
|
+
joined5.set(bytes, this.buffer.length);
|
|
17521
18146
|
this.buffer.fill(0);
|
|
17522
|
-
this.buffer =
|
|
17523
|
-
if (this.mode === "sniff") this.mode = modeOf(latin12(
|
|
18147
|
+
this.buffer = joined5;
|
|
18148
|
+
if (this.mode === "sniff") this.mode = modeOf(latin12(joined5.subarray(0, 8))) ?? "sniff";
|
|
17524
18149
|
if (this.mode === "pg" && !this.sawPg) {
|
|
17525
18150
|
this.sawPg = true;
|
|
17526
18151
|
if (!this.s.verified) void this.proof("pg");
|
|
@@ -17548,7 +18173,7 @@ var SessionWriter = class {
|
|
|
17548
18173
|
const out = await this.smtp.line(latin12(all.subarray(0, at))).catch(() => ({ line: latin12(all.subarray(0, at)) }));
|
|
17549
18174
|
all.fill(0);
|
|
17550
18175
|
if ("values" in out && out.values) this.remember(out.values);
|
|
17551
|
-
const line =
|
|
18176
|
+
const line = bytesOf2(`${out.line}\r
|
|
17552
18177
|
`);
|
|
17553
18178
|
try {
|
|
17554
18179
|
await writeAll3(this.conn, line);
|
|
@@ -17605,7 +18230,7 @@ var SessionWriter = class {
|
|
|
17605
18230
|
latin12(all.subarray(0, end)),
|
|
17606
18231
|
(position, placeholders, head2) => this.ask("http1", position, { placeholders, head: head2 })
|
|
17607
18232
|
).catch(() => void 0);
|
|
17608
|
-
const head = done4 ?
|
|
18233
|
+
const head = done4 ? bytesOf2(done4.head) : all.subarray(0, end);
|
|
17609
18234
|
if (done4) this.remember(done4.values);
|
|
17610
18235
|
try {
|
|
17611
18236
|
await writeAll3(this.conn, head);
|
|
@@ -17668,7 +18293,7 @@ var ScrubReader = class {
|
|
|
17668
18293
|
const before = this.current();
|
|
17669
18294
|
const out = this.through(got);
|
|
17670
18295
|
if (before.length === 0 && out !== void 0) return out;
|
|
17671
|
-
if (before.length > 0) return
|
|
18296
|
+
if (before.length > 0) return joined3(before, out);
|
|
17672
18297
|
}
|
|
17673
18298
|
}
|
|
17674
18299
|
through(got) {
|
|
@@ -17684,7 +18309,7 @@ var ScrubReader = class {
|
|
|
17684
18309
|
return out.length > 0 ? out : void 0;
|
|
17685
18310
|
}
|
|
17686
18311
|
};
|
|
17687
|
-
function
|
|
18312
|
+
function joined3(a, b) {
|
|
17688
18313
|
if (!b) return a;
|
|
17689
18314
|
const out = new Uint8Array(a.length + b.length);
|
|
17690
18315
|
out.set(a);
|
|
@@ -17799,7 +18424,8 @@ function sessionOf(info, servername) {
|
|
|
17799
18424
|
} : {},
|
|
17800
18425
|
servername,
|
|
17801
18426
|
peerCertificates: info.peerCertificates.map(encode),
|
|
17802
|
-
...controls(info)
|
|
18427
|
+
...controls(info),
|
|
18428
|
+
...info.keylog ? { keylog: info.keylog } : {}
|
|
17803
18429
|
};
|
|
17804
18430
|
}
|
|
17805
18431
|
function controls(info) {
|
|
@@ -17941,11 +18567,14 @@ async function prepareWith(support, req, servername, cert) {
|
|
|
17941
18567
|
insecure: req.insecure === true,
|
|
17942
18568
|
...req.sni === false ? { sni: false } : {},
|
|
17943
18569
|
...req.checkHostname === false ? { checkHostname: false } : {},
|
|
18570
|
+
...req.keylog === true ? { keylog: true } : {},
|
|
17944
18571
|
clientCertificate: cert !== void 0,
|
|
17945
18572
|
bundled: own === void 0
|
|
17946
18573
|
};
|
|
17947
18574
|
let session;
|
|
17948
18575
|
try {
|
|
18576
|
+
if (req.keylog === true && !engine.keylogs)
|
|
18577
|
+
throw new KernelError("ENOTSUP", "the installed tls engine has no key log");
|
|
17949
18578
|
const controls2 = req.sni === false || req.checkHostname === false || cert !== void 0;
|
|
17950
18579
|
if (controls2 && !engine.sessionControls) {
|
|
17951
18580
|
throw new KernelError("ENOTSUP", "the installed tls engine has no client certificates");
|
|
@@ -17993,7 +18622,7 @@ function secure(prepared, seal) {
|
|
|
17993
18622
|
try {
|
|
17994
18623
|
const made2 = await tlsClient(raw2, prepared.options);
|
|
17995
18624
|
const engine = prepared.options.engine;
|
|
17996
|
-
const session = sealing({ ...seal, engine }, raw2, made2.info, prepared.options.servername);
|
|
18625
|
+
const session = prepared.options.keylog ? void 0 : sealing({ ...seal, engine }, raw2, made2.info, prepared.options.servername);
|
|
17997
18626
|
if (!session) return made2;
|
|
17998
18627
|
made2.info.substitutes = substitutes(session);
|
|
17999
18628
|
if (made2.info.substitutes && session.verified)
|
|
@@ -18106,25 +18735,31 @@ function certFlags(req) {
|
|
|
18106
18735
|
if (!req.requestCert) return 0;
|
|
18107
18736
|
return req.rejectUnauthorized === false ? TLS_SERVER_REQUEST_CERT : TLS_SERVER_REQUIRE_CERT;
|
|
18108
18737
|
}
|
|
18109
|
-
|
|
18110
|
-
|
|
18738
|
+
var CERT_FLAGS = TLS_SERVER_REQUEST_CERT | TLS_SERVER_REQUIRE_CERT;
|
|
18739
|
+
function selectFlag(req) {
|
|
18740
|
+
if (!req.select) return 0;
|
|
18111
18741
|
if (req.alpn && req.alpn.length > 0)
|
|
18112
18742
|
throw new KernelError("EINVAL", "ERR_TLS_ALPN_CALLBACK_WITH_PROTOCOLS: alpn with select");
|
|
18113
|
-
return
|
|
18743
|
+
return TLS_SERVER_SELECT;
|
|
18744
|
+
}
|
|
18745
|
+
function flagsOf(req) {
|
|
18746
|
+
return certFlags(req) | selectFlag(req) | (req.keylog ? TLS_KEYLOG : 0);
|
|
18114
18747
|
}
|
|
18115
|
-
async function engineOf(proc, select) {
|
|
18748
|
+
async function engineOf(proc, { select, keylog }) {
|
|
18116
18749
|
const engine = await supportOf(proc.net).engine();
|
|
18117
18750
|
if (!engine.serverSessions)
|
|
18118
18751
|
throw new KernelError("ENOTSUP", "the installed tls engine has no server sessions");
|
|
18752
|
+
if (keylog && !engine.keylogs)
|
|
18753
|
+
throw new KernelError("ENOTSUP", "the installed tls engine has no key log");
|
|
18119
18754
|
if (select && !engine.serverSelect)
|
|
18120
18755
|
throw new KernelError("ENOTSUP", "the installed tls engine has no server selection");
|
|
18121
18756
|
return engine;
|
|
18122
18757
|
}
|
|
18123
|
-
async function importedLeaf(proc, own,
|
|
18758
|
+
async function importedLeaf(proc, own, needs = {}) {
|
|
18124
18759
|
const cert = certBytes(own);
|
|
18125
18760
|
let engine;
|
|
18126
18761
|
try {
|
|
18127
|
-
engine = await engineOf(proc,
|
|
18762
|
+
engine = await engineOf(proc, needs);
|
|
18128
18763
|
} catch (err) {
|
|
18129
18764
|
wipe(cert);
|
|
18130
18765
|
throw err;
|
|
@@ -18154,12 +18789,12 @@ async function serverOf(proc, req) {
|
|
|
18154
18789
|
delete req.cert;
|
|
18155
18790
|
if (!own && !req.select)
|
|
18156
18791
|
throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: a server needs cert and key");
|
|
18157
|
-
const { engine, leaf } = own ? await importedLeaf(proc, own, req
|
|
18792
|
+
const { engine, leaf } = own ? await importedLeaf(proc, own, req) : { engine: await engineOf(proc, { ...req, select: true }), leaf: void 0 };
|
|
18158
18793
|
let mine;
|
|
18159
18794
|
try {
|
|
18160
18795
|
mine = req.ca && req.ca.length > 0 ? storeOf(engine, req.ca) : void 0;
|
|
18161
18796
|
const flags2 = flagsOf(req);
|
|
18162
|
-
const store = mine ?? (flags2 &
|
|
18797
|
+
const store = mine ?? (flags2 & CERT_FLAGS ? await defaultStore(engine, supportOf(proc.net).roots) : void 0);
|
|
18163
18798
|
return {
|
|
18164
18799
|
engine,
|
|
18165
18800
|
leaf,
|
|
@@ -18193,7 +18828,8 @@ function servedOf(info) {
|
|
|
18193
18828
|
authorized: info.authorized,
|
|
18194
18829
|
...info.authorizationError ? { authorizationError: info.authorizationError } : {},
|
|
18195
18830
|
peerCertificates: info.peerCertificates.map(encode),
|
|
18196
|
-
cipher: info.cipher
|
|
18831
|
+
cipher: info.cipher,
|
|
18832
|
+
...info.keylog ? { keylog: info.keylog } : {}
|
|
18197
18833
|
};
|
|
18198
18834
|
}
|
|
18199
18835
|
var selections = /* @__PURE__ */ new WeakMap();
|
|
@@ -18216,13 +18852,14 @@ async function serveSecure(proc, socket, req) {
|
|
|
18216
18852
|
const { engine, leaf, alpn, store, flags: flags2 } = server;
|
|
18217
18853
|
const limit = handshakeSignal(proc, server.timeoutMs);
|
|
18218
18854
|
const { pausedAt, select } = pausing(limit.signal);
|
|
18219
|
-
const certs = (flags2 &
|
|
18855
|
+
const certs = (flags2 & CERT_FLAGS) !== 0;
|
|
18220
18856
|
const run2 = socket.secureLink(
|
|
18221
18857
|
(raw2) => tlsServer(
|
|
18222
18858
|
raw2,
|
|
18223
18859
|
engine.serverSession(leaf, alpn, store, flags2),
|
|
18224
18860
|
certs,
|
|
18225
|
-
flags2 & TLS_SERVER_SELECT ? select : void 0
|
|
18861
|
+
flags2 & TLS_SERVER_SELECT ? select : void 0,
|
|
18862
|
+
(flags2 & TLS_KEYLOG) !== 0
|
|
18226
18863
|
),
|
|
18227
18864
|
limit.signal,
|
|
18228
18865
|
(reason) => !shared && reason === timedOut
|
|
@@ -18592,7 +19229,7 @@ async function connect(req, proc) {
|
|
|
18592
19229
|
dialing?.catch(() => void 0);
|
|
18593
19230
|
throw new KernelError("EINPROGRESS");
|
|
18594
19231
|
}
|
|
18595
|
-
if (dialing !== void 0) await
|
|
19232
|
+
if (dialing !== void 0) await interruptible3(dialing, proc.blocking());
|
|
18596
19233
|
return ok3();
|
|
18597
19234
|
}
|
|
18598
19235
|
async function bindUnixDgram(proc, socket, addr) {
|
|
@@ -18657,7 +19294,7 @@ async function unixDatagram(req, dgram, proc) {
|
|
|
18657
19294
|
function domainOf(socket) {
|
|
18658
19295
|
return socket instanceof UnixDgram ? "unix" : "inet";
|
|
18659
19296
|
}
|
|
18660
|
-
function
|
|
19297
|
+
function interruptible3(dialing, signal) {
|
|
18661
19298
|
return new Promise((resolve2, reject) => {
|
|
18662
19299
|
const abort = () => reject(new KernelError("EINTR"));
|
|
18663
19300
|
signal.addEventListener("abort", abort, { once: true });
|
|
@@ -18692,7 +19329,7 @@ var NOT_HTTP_PORTS = /* @__PURE__ */ new Set([
|
|
|
18692
19329
|
]);
|
|
18693
19330
|
var HOST_NAME = /^[A-Za-z0-9.-]+$|^\[?[0-9A-Fa-f:.]+\]?$/;
|
|
18694
19331
|
function sessionControls(req) {
|
|
18695
|
-
return req.sni === false || req.checkHostname === false || req.clientCert !== void 0;
|
|
19332
|
+
return req.sni === false || req.checkHostname === false || req.clientCert !== void 0 || req.keylog === true;
|
|
18696
19333
|
}
|
|
18697
19334
|
function wantsKernel(req) {
|
|
18698
19335
|
if (req.path === "kernel") return true;
|
|
@@ -19661,7 +20298,7 @@ var ProcessWatches = class {
|
|
|
19661
20298
|
};
|
|
19662
20299
|
|
|
19663
20300
|
// src/kernel/process.ts
|
|
19664
|
-
function
|
|
20301
|
+
function aborted2(signal) {
|
|
19665
20302
|
return new Promise((_, reject) => {
|
|
19666
20303
|
signal.addEventListener("abort", () => reject(new KernelError("EINTR")), { once: true });
|
|
19667
20304
|
});
|
|
@@ -19751,6 +20388,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
19751
20388
|
"fd-open-sealed",
|
|
19752
20389
|
"fd-open-clipboard",
|
|
19753
20390
|
"fd-clipboard-abort",
|
|
20391
|
+
"fd-open-embedder",
|
|
19754
20392
|
"tty-get",
|
|
19755
20393
|
"tty-set",
|
|
19756
20394
|
"tty-winsz",
|
|
@@ -20304,6 +20942,7 @@ var WasmProcess = class {
|
|
|
20304
20942
|
if (!read) throw new KernelError(req.peek && file.read ? "EOPNOTSUPP" : "EBADF");
|
|
20305
20943
|
if (file.tty) this.checkForeground(file.tty);
|
|
20306
20944
|
if (file.clipboard) return this.readClipboard(file.clipboard, req, cancelled);
|
|
20945
|
+
if (file.embedder) return this.readEmbedder(file, req, cancelled);
|
|
20307
20946
|
if (file instanceof EventFd && req.max < EventFd.SIZE) throw new KernelError("EINVAL");
|
|
20308
20947
|
if (req.max <= 0) return new Uint8Array(0);
|
|
20309
20948
|
if (file instanceof KernelSocket && file.unconnected) throw new KernelError("ENOTCONN");
|
|
@@ -20324,6 +20963,81 @@ var WasmProcess = class {
|
|
|
20324
20963
|
throw err;
|
|
20325
20964
|
}
|
|
20326
20965
|
}
|
|
20966
|
+
async readEmbedder(file, req, cancelled) {
|
|
20967
|
+
const channel = file.embedder;
|
|
20968
|
+
if (req.max <= 0) return new Uint8Array(0);
|
|
20969
|
+
channel.caller = await this.embedderCaller();
|
|
20970
|
+
try {
|
|
20971
|
+
return await channel.read(Math.min(req.max, MAX_READ), this.blockingSignal(cancelled));
|
|
20972
|
+
} catch (err) {
|
|
20973
|
+
await this.deviceComplaint(EMBEDDER_PATH, err);
|
|
20974
|
+
throw err;
|
|
20975
|
+
}
|
|
20976
|
+
}
|
|
20977
|
+
async writeEmbedder(file, body, nonblock, cancelled) {
|
|
20978
|
+
const channel = file.embedder;
|
|
20979
|
+
channel.caller = await this.embedderCaller();
|
|
20980
|
+
const write = file.write;
|
|
20981
|
+
if (!pollFile(file).writable && nonblock) throw new KernelError("EAGAIN");
|
|
20982
|
+
try {
|
|
20983
|
+
return await write.call(file, body, this.blockingSignal(cancelled));
|
|
20984
|
+
} catch (err) {
|
|
20985
|
+
await this.deviceComplaint(EMBEDDER_PATH, err);
|
|
20986
|
+
throw err;
|
|
20987
|
+
}
|
|
20988
|
+
}
|
|
20989
|
+
async deviceComplaint(path, err) {
|
|
20990
|
+
const name2 = this.options.clipboardName;
|
|
20991
|
+
if (name2 === void 0 || !(err instanceof KernelError) || err.detail === void 0) return;
|
|
20992
|
+
if (err.code === "EINTR") return;
|
|
20993
|
+
await this.complainLine(`${name2}: ${path}: ${clipboardLine(err.detail)}`);
|
|
20994
|
+
}
|
|
20995
|
+
async complainLine(line) {
|
|
20996
|
+
const stderr = this.fds.has(2) ? this.fds.get(2).file : void 0;
|
|
20997
|
+
if (!stderr?.write || stderr.clipboard || stderr.embedder || stderr.sealed) return;
|
|
20998
|
+
const timeout = new Promise((r) => setTimeout(() => r(0), 1e3));
|
|
20999
|
+
await Promise.race([
|
|
21000
|
+
stderr.write(new TextEncoder().encode(`${line}
|
|
21001
|
+
`), AbortSignal.timeout(1e3)).catch(() => 0),
|
|
21002
|
+
timeout
|
|
21003
|
+
]);
|
|
21004
|
+
}
|
|
21005
|
+
async embedderCaller() {
|
|
21006
|
+
const shown = await this.options.identity?.();
|
|
21007
|
+
const session = this.options.embedderSession?.() ?? { client: 0, uid: 0 };
|
|
21008
|
+
const name2 = this.options.clipboardName ?? this.options.embedderName ?? "program";
|
|
21009
|
+
return {
|
|
21010
|
+
pid: this.pid,
|
|
21011
|
+
shownPid: shown?.pid ?? this.pid,
|
|
21012
|
+
euid: this.cred.euid,
|
|
21013
|
+
egid: this.cred.egid,
|
|
21014
|
+
groups: [...this.cred.groups],
|
|
21015
|
+
sessionUid: session.uid,
|
|
21016
|
+
client: session.client,
|
|
21017
|
+
tags: this.options.embedder?.tagsOf(this.pid),
|
|
21018
|
+
progress: (line) => void this.complainLine(`${name2}: ${line}`),
|
|
21019
|
+
closing: () => AbortSignal.any([this.interrupt.signal, this.gone.signal])
|
|
21020
|
+
};
|
|
21021
|
+
}
|
|
21022
|
+
async closeFd(fd) {
|
|
21023
|
+
this.options.locks?.closed(this.pid, fd);
|
|
21024
|
+
await this.dropRecordLocks(fd);
|
|
21025
|
+
const closing2 = this.fds.get(fd).file;
|
|
21026
|
+
const channel = closing2.clipboard;
|
|
21027
|
+
if (channel) channel.stamp = await this.clipboardStamp();
|
|
21028
|
+
if (closing2.embedder) closing2.embedder.caller = await this.embedderCaller();
|
|
21029
|
+
await Promise.resolve(this.fds.close(fd)).catch(async (err) => {
|
|
21030
|
+
if (channel) await this.clipboardComplaint(err);
|
|
21031
|
+
if (closing2.embedder) await this.deviceComplaint(EMBEDDER_PATH, err);
|
|
21032
|
+
throw err;
|
|
21033
|
+
});
|
|
21034
|
+
}
|
|
21035
|
+
async openEmbedder(flags2) {
|
|
21036
|
+
const broker = this.options.embedder;
|
|
21037
|
+
if (!broker) throw new KernelError("ENOENT");
|
|
21038
|
+
const file = broker.channel(openAccess(flags2), await this.embedderCaller());
|
|
21039
|
+
return this.fds.install(this.options.outputFilter?.(file) ?? file, 3);
|
|
21040
|
+
}
|
|
20327
21041
|
async complain(line) {
|
|
20328
21042
|
const stderr = this.fds.has(2) ? this.fds.get(2).file : void 0;
|
|
20329
21043
|
if (!stderr?.write || stderr.sealed || stderr.clipboard) return false;
|
|
@@ -20354,6 +21068,7 @@ var WasmProcess = class {
|
|
|
20354
21068
|
const file = this.fds.get(fd).file;
|
|
20355
21069
|
if (file.sealed) return file.sealed.send(body, await this.sealedCaller(), this.gone.signal);
|
|
20356
21070
|
if (!file.write) throw new KernelError("EBADF");
|
|
21071
|
+
if (file.embedder) return this.writeEmbedder(file, body, nonblock, cancelled);
|
|
20357
21072
|
if (!pollFile(file).writable) {
|
|
20358
21073
|
if (nonblock) throw new KernelError("EAGAIN");
|
|
20359
21074
|
return file.write(body, this.blockingSignal(cancelled));
|
|
@@ -20401,11 +21116,11 @@ var WasmProcess = class {
|
|
|
20401
21116
|
} else if (req.create) {
|
|
20402
21117
|
await nodes.onEntry(path, async () => {
|
|
20403
21118
|
const marks = this.options.owners || plain3 !== void 0;
|
|
20404
|
-
const
|
|
21119
|
+
const fresh3 = marks && !await present3(fs, path, true);
|
|
20405
21120
|
this.fds.installAt(fd, this.openVfsFile(open, await nodes.identify(path), fs));
|
|
20406
21121
|
await this.fds.get(fd).file.stat?.();
|
|
20407
|
-
if (
|
|
20408
|
-
else if (
|
|
21122
|
+
if (fresh3 && plain3 !== void 0) await fs.chmod?.(path, plain3);
|
|
21123
|
+
else if (fresh3) {
|
|
20409
21124
|
await fs.chown?.(path, { ...this.newOwner(req.mode), kind: "new" });
|
|
20410
21125
|
}
|
|
20411
21126
|
});
|
|
@@ -20623,17 +21338,9 @@ var WasmProcess = class {
|
|
|
20623
21338
|
kind: "json",
|
|
20624
21339
|
json: await this.write(req.fd, req.body, req.nonblock, cancelled)
|
|
20625
21340
|
};
|
|
20626
|
-
case "fd-close":
|
|
20627
|
-
this.
|
|
20628
|
-
await this.dropRecordLocks(req.fd);
|
|
20629
|
-
const channel = this.fds.get(req.fd).file.clipboard;
|
|
20630
|
-
if (channel) channel.stamp = await this.clipboardStamp();
|
|
20631
|
-
await Promise.resolve(this.fds.close(req.fd)).catch(async (err) => {
|
|
20632
|
-
if (channel) await this.clipboardComplaint(err);
|
|
20633
|
-
throw err;
|
|
20634
|
-
});
|
|
21341
|
+
case "fd-close":
|
|
21342
|
+
await this.closeFd(req.fd);
|
|
20635
21343
|
return { ok: true, kind: "void" };
|
|
20636
|
-
}
|
|
20637
21344
|
case "fd-pipe": {
|
|
20638
21345
|
const pipe = openPipe();
|
|
20639
21346
|
const read = this.fds.install(pipe.read, 3);
|
|
@@ -20693,6 +21400,8 @@ var WasmProcess = class {
|
|
|
20693
21400
|
return { ok: true, kind: "json", json: this.openSealed(req.flags) };
|
|
20694
21401
|
case "fd-open-clipboard":
|
|
20695
21402
|
return { ok: true, kind: "json", json: await this.openClipboard(req.flags) };
|
|
21403
|
+
case "fd-open-embedder":
|
|
21404
|
+
return { ok: true, kind: "json", json: await this.openEmbedder(req.flags) };
|
|
20696
21405
|
case "fd-clipboard-abort": {
|
|
20697
21406
|
const file = this.fds.get(req.fd);
|
|
20698
21407
|
file.file.clipboard?.abort();
|
|
@@ -21187,7 +21896,7 @@ var WasmProcess = class {
|
|
|
21187
21896
|
else {
|
|
21188
21897
|
const { source, target, type, flags: flags2, data } = req;
|
|
21189
21898
|
const signal = this.blockingSignal(cancelled);
|
|
21190
|
-
await Promise.race([mount({ source, target, type, flags: flags2, data }, signal),
|
|
21899
|
+
await Promise.race([mount({ source, target, type, flags: flags2, data }, signal), aborted2(signal)]);
|
|
21191
21900
|
}
|
|
21192
21901
|
} catch (err) {
|
|
21193
21902
|
const code = err?.code;
|
|
@@ -21197,7 +21906,7 @@ var WasmProcess = class {
|
|
|
21197
21906
|
return { ok: true, kind: "void" };
|
|
21198
21907
|
}
|
|
21199
21908
|
pause(cancelled) {
|
|
21200
|
-
return
|
|
21909
|
+
return aborted2(this.blockingSignal(cancelled));
|
|
21201
21910
|
}
|
|
21202
21911
|
alarm;
|
|
21203
21912
|
dlLog = [];
|
|
@@ -21747,6 +22456,15 @@ function linksOf(opts) {
|
|
|
21747
22456
|
function clipboardName(opts) {
|
|
21748
22457
|
return opts.program.abi === "js" ? {} : { clipboardName: opts.argv0 };
|
|
21749
22458
|
}
|
|
22459
|
+
function embedderOptions(opts) {
|
|
22460
|
+
if (!opts.embedder) return {};
|
|
22461
|
+
return {
|
|
22462
|
+
embedder: opts.embedder.broker,
|
|
22463
|
+
embedderSession: opts.embedder.session,
|
|
22464
|
+
embedderName: opts.argv0,
|
|
22465
|
+
...clipboardName(opts)
|
|
22466
|
+
};
|
|
22467
|
+
}
|
|
21750
22468
|
function processOptions(opts, header5, hooks, created4) {
|
|
21751
22469
|
return {
|
|
21752
22470
|
...inherited(opts),
|
|
@@ -21754,6 +22472,7 @@ function processOptions(opts, header5, hooks, created4) {
|
|
|
21754
22472
|
...opts.sealed ? { sealed: opts.sealed } : {},
|
|
21755
22473
|
...opts.outputFilter ? { outputFilter: opts.outputFilter } : {},
|
|
21756
22474
|
...opts.clipboard ? { clipboard: opts.clipboard, ...clipboardName(opts) } : {},
|
|
22475
|
+
...embedderOptions(opts),
|
|
21757
22476
|
...opts.readonlyAt ? { readonlyAt: opts.readonlyAt } : {},
|
|
21758
22477
|
...opts.source ? { source: opts.source } : {},
|
|
21759
22478
|
noLinks: opts.noLinks,
|
|
@@ -24502,9 +25221,9 @@ var OpfsFs = class {
|
|
|
24502
25221
|
this.lookups++;
|
|
24503
25222
|
if (split2(path).length === 0) return this.root;
|
|
24504
25223
|
const cached = this.files.get(path);
|
|
24505
|
-
const
|
|
24506
|
-
if (cached && !
|
|
24507
|
-
if (cached &&
|
|
25224
|
+
const fresh3 = cached && performance.now() - (this.found.get(cached) ?? -CHECK_MS) < CHECK_MS;
|
|
25225
|
+
if (cached && !fresh3) this.files.delete(path);
|
|
25226
|
+
if (cached && fresh3) {
|
|
24508
25227
|
if (this.glanced(cached)) return this.remember(path, cached);
|
|
24509
25228
|
try {
|
|
24510
25229
|
await this.glance(cached);
|
|
@@ -24722,8 +25441,8 @@ var OpfsFs = class {
|
|
|
24722
25441
|
glanced(handle) {
|
|
24723
25442
|
if (this.exact > 0) return void 0;
|
|
24724
25443
|
const seen = this.glances.get(handle);
|
|
24725
|
-
const
|
|
24726
|
-
return
|
|
25444
|
+
const fresh3 = seen && seen.changes === this.changes && this.recent(seen, GLANCE_LOOKUPS);
|
|
25445
|
+
return fresh3 ? seen.file : void 0;
|
|
24727
25446
|
}
|
|
24728
25447
|
async glance(handle) {
|
|
24729
25448
|
const at = performance.now();
|
|
@@ -24913,13 +25632,13 @@ var OpfsFs = class {
|
|
|
24913
25632
|
async keptFor(path) {
|
|
24914
25633
|
const at = normalizePath(path);
|
|
24915
25634
|
const cached = this.files.get(at);
|
|
24916
|
-
const
|
|
24917
|
-
const [target, existed] =
|
|
25635
|
+
const fresh3 = cached && performance.now() - (this.found.get(cached) ?? -CHECK_MS) < CHECK_MS;
|
|
25636
|
+
const [target, existed] = fresh3 ? [at, true] : await this.writeTarget(path);
|
|
24918
25637
|
if (!existed) return [void 0, target, false];
|
|
24919
25638
|
this.refuse(target);
|
|
24920
25639
|
const [entry] = await this.meta.get([target]);
|
|
24921
25640
|
if (entry?.fifo || entry?.socket) throw fsError("ENXIO", path);
|
|
24922
|
-
const kept =
|
|
25641
|
+
const kept = fresh3 ? cached : this.files.get(target);
|
|
24923
25642
|
const usable2 = kept && performance.now() - (this.found.get(kept) ?? -CHECK_MS) < CHECK_MS;
|
|
24924
25643
|
return [usable2 ? kept : void 0, target, true];
|
|
24925
25644
|
}
|
|
@@ -26634,14 +27353,14 @@ var RESTORE_AGAIN_MS = 3e4;
|
|
|
26634
27353
|
function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
26635
27354
|
const handles = /* @__PURE__ */ new Map();
|
|
26636
27355
|
let nextFh = 0;
|
|
26637
|
-
const
|
|
27356
|
+
const fresh3 = (remote) => {
|
|
26638
27357
|
if (remote.client.token === remote.token && !remote.client.gone) return remote;
|
|
26639
27358
|
throw fsError2("ESTALE", "the folder was granted again, so this open file is gone");
|
|
26640
27359
|
};
|
|
26641
27360
|
const live = (fh) => {
|
|
26642
27361
|
const remote = handles.get(fh);
|
|
26643
27362
|
if (!remote) throw fsError2("EBADF", `handle ${fh}`);
|
|
26644
|
-
return
|
|
27363
|
+
return fresh3(remote);
|
|
26645
27364
|
};
|
|
26646
27365
|
const call = (op, body = {}) => current().call(op, body);
|
|
26647
27366
|
const same2 = (was, mode, seen) => seen?.mode === (mode | 128) && (was.ino !== void 0 && seen.ino !== void 0 ? seen.ino === was.ino : seen.size === was.size && seen.mtime === was.mtime);
|
|
@@ -26723,7 +27442,7 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
|
26723
27442
|
if (!remote) throw fsError2("EBADF", `handle ${fh}`);
|
|
26724
27443
|
handles.delete(fh);
|
|
26725
27444
|
try {
|
|
26726
|
-
await
|
|
27445
|
+
await fresh3(remote).client.call("release", { fh: remote.fh }, true);
|
|
26727
27446
|
} finally {
|
|
26728
27447
|
if (remote.restore) await settle(current(), remote.restore);
|
|
26729
27448
|
}
|
|
@@ -27087,7 +27806,7 @@ var PortTransport = class {
|
|
|
27087
27806
|
}).finally(() => this.fail("the folder's watch ended"));
|
|
27088
27807
|
}
|
|
27089
27808
|
};
|
|
27090
|
-
var
|
|
27809
|
+
var errorOf2 = (err) => ({
|
|
27091
27810
|
code: typeof codeOf7(err) === "string" ? codeOf7(err) : "EIO",
|
|
27092
27811
|
message: err?.message ?? String(err)
|
|
27093
27812
|
});
|
|
@@ -27137,7 +27856,7 @@ function serveHostfsPort(port, transport) {
|
|
|
27137
27856
|
);
|
|
27138
27857
|
send2({ id: id2, end: true });
|
|
27139
27858
|
} catch (err) {
|
|
27140
|
-
send2({ id: id2, error:
|
|
27859
|
+
send2({ id: id2, error: errorOf2(err) });
|
|
27141
27860
|
} finally {
|
|
27142
27861
|
watches.delete(id2);
|
|
27143
27862
|
}
|
|
@@ -27165,7 +27884,7 @@ function serveHostfsPort(port, transport) {
|
|
|
27165
27884
|
if (op !== "call") throw fsError2("EINVAL", `unknown hostfs port op ${op}`);
|
|
27166
27885
|
send2({ id: id2, result: await answer2(data.name, data.body) });
|
|
27167
27886
|
} catch (err) {
|
|
27168
|
-
send2({ id: id2, error:
|
|
27887
|
+
send2({ id: id2, error: errorOf2(err) });
|
|
27169
27888
|
}
|
|
27170
27889
|
};
|
|
27171
27890
|
const stop = () => {
|
|
@@ -27798,7 +28517,7 @@ function homeModeOf(mode) {
|
|
|
27798
28517
|
}
|
|
27799
28518
|
return mode;
|
|
27800
28519
|
}
|
|
27801
|
-
function
|
|
28520
|
+
function joined4(name2, rows) {
|
|
27802
28521
|
let changed = false;
|
|
27803
28522
|
for (const g of rows) {
|
|
27804
28523
|
if (g.members.includes(name2)) continue;
|
|
@@ -27985,7 +28704,7 @@ var UserDb = class {
|
|
|
27985
28704
|
await this.provision(found, this.umaskFor(options), shared);
|
|
27986
28705
|
await this.stampHome(found, shared, homeMode);
|
|
27987
28706
|
}
|
|
27988
|
-
if (
|
|
28707
|
+
if (joined4(name2, more)) await this.fs.writeFile(GROUP, formatGroup(group));
|
|
27989
28708
|
remember();
|
|
27990
28709
|
return this.account(found, groups);
|
|
27991
28710
|
}
|
|
@@ -27994,10 +28713,10 @@ var UserDb = class {
|
|
|
27994
28713
|
if (groups.some((r) => r.name === name2)) throw fsError("EEXIST", `group ${name2} exists`);
|
|
27995
28714
|
const uid = freeId(users, groups);
|
|
27996
28715
|
const row = { name: name2, uid, gid: uid, gecos: name2, home, shell: "/bin/bash" };
|
|
27997
|
-
|
|
28716
|
+
joined4(name2, extra);
|
|
27998
28717
|
group.push({ name: name2, gid: uid, members: [] });
|
|
27999
28718
|
passwd.push(row);
|
|
28000
|
-
const
|
|
28719
|
+
const fresh3 = !await this.fs.exists(home);
|
|
28001
28720
|
await this.fs.mkdir(home, { recursive: true });
|
|
28002
28721
|
try {
|
|
28003
28722
|
await this.provision(row, this.umaskFor(options), shared);
|
|
@@ -28005,7 +28724,7 @@ var UserDb = class {
|
|
|
28005
28724
|
await this.fs.mkdir("/etc", { recursive: true });
|
|
28006
28725
|
await this.commit(formatPasswd(passwd), formatGroup(group));
|
|
28007
28726
|
} catch (err) {
|
|
28008
|
-
if (
|
|
28727
|
+
if (fresh3) await this.fs.rm(home, { recursive: true, force: true });
|
|
28009
28728
|
throw err;
|
|
28010
28729
|
}
|
|
28011
28730
|
remember();
|
|
@@ -28383,12 +29102,12 @@ ${lines2}
|
|
|
28383
29102
|
const timer = setTimeout(() => control.abort("expired"), timeout);
|
|
28384
29103
|
const withdraw = () => control.abort("withdrawn");
|
|
28385
29104
|
requester.addEventListener("abort", withdraw, { once: true });
|
|
28386
|
-
const
|
|
29105
|
+
const aborted3 = new Promise(
|
|
28387
29106
|
(resolve2) => control.signal.addEventListener("abort", () => resolve2("aborted"), { once: true })
|
|
28388
29107
|
);
|
|
28389
29108
|
try {
|
|
28390
29109
|
const answered = Promise.resolve().then(() => approve(req, { signal: control.signal })).catch(() => "deny");
|
|
28391
|
-
const answer2 = await Promise.race([answered,
|
|
29110
|
+
const answer2 = await Promise.race([answered, aborted3]);
|
|
28392
29111
|
if (answer2 === "aborted" || control.signal.aborted) {
|
|
28393
29112
|
return control.signal.reason === "expired" ? failed2("ETIMEDOUT", "sudo: the request expired") : failed2("EINTR", "sudo: the request was withdrawn");
|
|
28394
29113
|
}
|
|
@@ -28514,6 +29233,7 @@ var SUDO_SOURCE = [
|
|
|
28514
29233
|
].join("\n");
|
|
28515
29234
|
|
|
28516
29235
|
// src/launcher.ts
|
|
29236
|
+
var NO_SESSION = { client: -1, uid: -1 };
|
|
28517
29237
|
var MODULE_URLS = 16;
|
|
28518
29238
|
function dataModuleUrl(source) {
|
|
28519
29239
|
const bytes = new TextEncoder().encode(source);
|
|
@@ -28772,6 +29492,7 @@ var Launcher = class {
|
|
|
28772
29492
|
described = /* @__PURE__ */ new Map();
|
|
28773
29493
|
creds = /* @__PURE__ */ new Map();
|
|
28774
29494
|
tags = /* @__PURE__ */ new Map();
|
|
29495
|
+
sessions = /* @__PURE__ */ new Map();
|
|
28775
29496
|
tagBases = /* @__PURE__ */ new Map();
|
|
28776
29497
|
links = /* @__PURE__ */ new Map();
|
|
28777
29498
|
freshModules = new FreshModules();
|
|
@@ -28832,6 +29553,7 @@ var Launcher = class {
|
|
|
28832
29553
|
sealed;
|
|
28833
29554
|
scrubs = /* @__PURE__ */ new Map();
|
|
28834
29555
|
clipboard;
|
|
29556
|
+
embedder;
|
|
28835
29557
|
rootFs;
|
|
28836
29558
|
fileWatches;
|
|
28837
29559
|
nextPid = 1e3;
|
|
@@ -28853,14 +29575,14 @@ var Launcher = class {
|
|
|
28853
29575
|
void 0,
|
|
28854
29576
|
(pid) => this.tagsOf(pid)
|
|
28855
29577
|
);
|
|
29578
|
+
this.embedder = this.embedderBroker(options.embedder);
|
|
28856
29579
|
this.sealed = new SealedBroker(
|
|
28857
29580
|
options.sealed,
|
|
28858
29581
|
this.usersMode,
|
|
28859
29582
|
void 0,
|
|
28860
29583
|
(pid) => this.tagsOf(pid)
|
|
28861
29584
|
);
|
|
28862
|
-
this.
|
|
28863
|
-
this.sealed.userOf = async (uid) => (await this.users.lookup(uid))?.name;
|
|
29585
|
+
this.wireSealed();
|
|
28864
29586
|
if (this.owners) options.fs.trackOwners?.();
|
|
28865
29587
|
this.watchers.tap((paths) => {
|
|
28866
29588
|
this.changes.publish(...paths);
|
|
@@ -29921,6 +30643,8 @@ var Launcher = class {
|
|
|
29921
30643
|
}
|
|
29922
30644
|
marks(pid, req) {
|
|
29923
30645
|
if (req.tags?.length) this.tags.set(pid, req.tags);
|
|
30646
|
+
const session = req.session ?? this.sessions.get(req.ppid ?? -1);
|
|
30647
|
+
if (session) this.sessions.set(pid, session);
|
|
29924
30648
|
if (req.tags?.length) this.tagBases.set(pid, req.tagBase ?? req.tags.length);
|
|
29925
30649
|
if (req.links !== void 0) this.links.set(pid, req.links);
|
|
29926
30650
|
}
|
|
@@ -30000,6 +30724,7 @@ var Launcher = class {
|
|
|
30000
30724
|
sealed: this.sealed,
|
|
30001
30725
|
...scrubs ? { outputFilter: (file) => scrubbedAll(file, scrubs) } : {},
|
|
30002
30726
|
clipboard: this.clipboard,
|
|
30727
|
+
embedder: { broker: this.embedder, session: () => this.sessionOf(pid) },
|
|
30003
30728
|
...this.dac ? { dac: this.dac } : {},
|
|
30004
30729
|
program: req.program,
|
|
30005
30730
|
changes: this.changes.sab,
|
|
@@ -30128,6 +30853,7 @@ var Launcher = class {
|
|
|
30128
30853
|
this.childTimes.delete(pid);
|
|
30129
30854
|
this.creds.delete(pid);
|
|
30130
30855
|
this.tags.delete(pid);
|
|
30856
|
+
this.sessions.delete(pid);
|
|
30131
30857
|
this.tagBases.delete(pid);
|
|
30132
30858
|
this.links.delete(pid);
|
|
30133
30859
|
this.granted.delete(pid);
|
|
@@ -30173,8 +30899,8 @@ var Launcher = class {
|
|
|
30173
30899
|
this.sampledAt = Math.max(this.sampledAt, now);
|
|
30174
30900
|
this.load = this.load.map((avg, i) => {
|
|
30175
30901
|
const window = LOAD_WINDOWS_MS[i];
|
|
30176
|
-
const
|
|
30177
|
-
return avg * Math.exp(-elapsed / window) + running *
|
|
30902
|
+
const fresh3 = 1 - Math.exp(-LOAD_SAMPLE_MS / window);
|
|
30903
|
+
return avg * Math.exp(-elapsed / window) + running * fresh3;
|
|
30178
30904
|
});
|
|
30179
30905
|
}
|
|
30180
30906
|
idleSince;
|
|
@@ -30404,7 +31130,7 @@ var Launcher = class {
|
|
|
30404
31130
|
forker(ppid, parent) {
|
|
30405
31131
|
const { exec: _exec, pgid: _pgid, group: _group, pid: _pid, scrub: _scrub, ...image } = parent;
|
|
30406
31132
|
return async (state, given) => {
|
|
30407
|
-
const
|
|
31133
|
+
const fresh3 = (fds, quietOom) => this.start({
|
|
30408
31134
|
...image,
|
|
30409
31135
|
quietOom,
|
|
30410
31136
|
cwd: state.cwd ?? parent.cwd,
|
|
@@ -30420,7 +31146,7 @@ var Launcher = class {
|
|
|
30420
31146
|
tagBase: this.tagBases.get(ppid),
|
|
30421
31147
|
links: this.links.get(ppid)
|
|
30422
31148
|
});
|
|
30423
|
-
return childHandle(await this.admitted(parent.program.abi !== "js", given,
|
|
31149
|
+
return childHandle(await this.admitted(parent.program.abi !== "js", given, fresh3));
|
|
30424
31150
|
};
|
|
30425
31151
|
}
|
|
30426
31152
|
keySignal(tty, fallback, sig, send2) {
|
|
@@ -30456,6 +31182,25 @@ var Launcher = class {
|
|
|
30456
31182
|
credOf(pid) {
|
|
30457
31183
|
return this.creds.get(pid)?.() ?? copyCred(ROOT);
|
|
30458
31184
|
}
|
|
31185
|
+
wireSealed() {
|
|
31186
|
+
this.sealed.tickets.normalise = (path) => physicalPathAsync(this.base, path);
|
|
31187
|
+
this.sealed.userOf = async (uid) => (await this.users.lookup(uid))?.name;
|
|
31188
|
+
}
|
|
31189
|
+
embedderBroker(hook) {
|
|
31190
|
+
const broker = new EmbedderBroker(
|
|
31191
|
+
this.usersMode,
|
|
31192
|
+
{
|
|
31193
|
+
groupId: async (name2) => (await this.users.groups()).find((g) => g.name === name2)?.gid,
|
|
31194
|
+
userId: async (name2) => (await this.users.lookup(name2))?.uid
|
|
31195
|
+
},
|
|
31196
|
+
(pid) => this.tagsOf(pid)
|
|
31197
|
+
);
|
|
31198
|
+
broker.register(0, hook);
|
|
31199
|
+
return broker;
|
|
31200
|
+
}
|
|
31201
|
+
sessionOf(pid) {
|
|
31202
|
+
return this.sessions.get(pid) ?? NO_SESSION;
|
|
31203
|
+
}
|
|
30459
31204
|
tagOf(pid) {
|
|
30460
31205
|
return this.tags.get(pid)?.[0];
|
|
30461
31206
|
}
|
|
@@ -30727,8 +31472,8 @@ var Launcher = class {
|
|
|
30727
31472
|
for (const [path, mode] of layout) {
|
|
30728
31473
|
if (isProtected(this.prefixes, normalizePath(path))) continue;
|
|
30729
31474
|
const real = await this.realLayoutPath(path);
|
|
30730
|
-
const
|
|
30731
|
-
if (
|
|
31475
|
+
const fresh3 = real !== void 0 && !await this.base.hasOwner?.(real);
|
|
31476
|
+
if (fresh3) await this.base.chown?.(real, { uid: 0, gid: 0, mode, follow: false });
|
|
30732
31477
|
}
|
|
30733
31478
|
}
|
|
30734
31479
|
async realLayoutPath(given) {
|
|
@@ -30901,9 +31646,10 @@ var Launcher = class {
|
|
|
30901
31646
|
if (!found) throw fsError("ENOENT", `no user ${String(user)}`);
|
|
30902
31647
|
return found;
|
|
30903
31648
|
}
|
|
30904
|
-
identity(account, given) {
|
|
31649
|
+
identity(account, given, session = 0) {
|
|
30905
31650
|
return {
|
|
30906
31651
|
...given,
|
|
31652
|
+
session: { client: session, uid: account.uid },
|
|
30907
31653
|
cred: credOf(account),
|
|
30908
31654
|
...account.umask !== void 0 ? { umask: account.umask } : {}
|
|
30909
31655
|
};
|
|
@@ -31090,7 +31836,7 @@ var Launcher = class {
|
|
|
31090
31836
|
cwd,
|
|
31091
31837
|
fds,
|
|
31092
31838
|
report,
|
|
31093
|
-
...this.identity(account, tagged)
|
|
31839
|
+
...this.identity(account, tagged, options.session)
|
|
31094
31840
|
});
|
|
31095
31841
|
leader = handle.pid;
|
|
31096
31842
|
void handle.exited.then(() => tty.hangup());
|
|
@@ -31147,7 +31893,7 @@ var Launcher = class {
|
|
|
31147
31893
|
fds,
|
|
31148
31894
|
report,
|
|
31149
31895
|
...group,
|
|
31150
|
-
...this.identity(account, tagged)
|
|
31896
|
+
...this.identity(account, tagged, options.session)
|
|
31151
31897
|
});
|
|
31152
31898
|
options.onStarted?.(handle.pid);
|
|
31153
31899
|
const status = await handle.exited;
|
|
@@ -31590,7 +32336,7 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS3 } = {})
|
|
|
31590
32336
|
}
|
|
31591
32337
|
|
|
31592
32338
|
// src/client/protocol.ts
|
|
31593
|
-
var PROTOCOL = [1,
|
|
32339
|
+
var PROTOCOL = [1, 13];
|
|
31594
32340
|
var FS_METHODS = [
|
|
31595
32341
|
"readFile",
|
|
31596
32342
|
"writeFile",
|
|
@@ -31757,14 +32503,15 @@ async function runAs(l, self, requested) {
|
|
|
31757
32503
|
function clientCred(self) {
|
|
31758
32504
|
return self ? credOf(self) : copyCred(ROOT);
|
|
31759
32505
|
}
|
|
31760
|
-
async function runTagged(l, self, options, tag) {
|
|
32506
|
+
async function runTagged(l, self, options, tag, session = -1) {
|
|
31761
32507
|
tagOption(options.tag);
|
|
31762
32508
|
const tags = withTag(withTag(void 0, tag), options.tag);
|
|
31763
32509
|
return {
|
|
31764
32510
|
user: await runAs(l, self, options.user),
|
|
31765
32511
|
tag,
|
|
31766
32512
|
tags,
|
|
31767
|
-
tagBase: tag === void 0 ? 0 : 1
|
|
32513
|
+
tagBase: tag === void 0 ? 0 : 1,
|
|
32514
|
+
session
|
|
31768
32515
|
};
|
|
31769
32516
|
}
|
|
31770
32517
|
function processes(l, self) {
|
|
@@ -31845,10 +32592,12 @@ function facadeRegistry(send2, gone) {
|
|
|
31845
32592
|
}
|
|
31846
32593
|
};
|
|
31847
32594
|
}
|
|
31848
|
-
function hostRegistries(send2, gone) {
|
|
32595
|
+
function hostRegistries(send2, gone, port) {
|
|
31849
32596
|
const cdps = cdpRegistry(send2, gone);
|
|
31850
32597
|
const facades = facadeRegistry(send2, gone);
|
|
32598
|
+
const requests = requestBinding(send2, port);
|
|
31851
32599
|
return {
|
|
32600
|
+
requests,
|
|
31852
32601
|
answer(l, req) {
|
|
31853
32602
|
if (req.op === "serve-cdp") return cdps.serve(l, req);
|
|
31854
32603
|
if (req.op === "unserve-cdp") return cdps.drop(req.registration);
|
|
@@ -31856,6 +32605,7 @@ function hostRegistries(send2, gone) {
|
|
|
31856
32605
|
return facades.drop(req.registration);
|
|
31857
32606
|
},
|
|
31858
32607
|
close() {
|
|
32608
|
+
requests.close();
|
|
31859
32609
|
cdps.close();
|
|
31860
32610
|
facades.close();
|
|
31861
32611
|
}
|
|
@@ -31890,6 +32640,28 @@ var TRAITS_WATCH = -1;
|
|
|
31890
32640
|
function traitsWatch(launcher, transport, send2) {
|
|
31891
32641
|
return launcher.onTraits(() => send2({ traits: transport.traits }));
|
|
31892
32642
|
}
|
|
32643
|
+
function requestBinding(send2, port) {
|
|
32644
|
+
const asker = embedderAsker({ postMessage: (m, t) => send2(m, t) });
|
|
32645
|
+
let unbind;
|
|
32646
|
+
port.addEventListener("message", (event) => {
|
|
32647
|
+
const reply = embedderReplyOf(event.data);
|
|
32648
|
+
if (reply) asker.answer(reply);
|
|
32649
|
+
});
|
|
32650
|
+
return {
|
|
32651
|
+
async accept(host, hello) {
|
|
32652
|
+
if (!hello.requests) return void 0;
|
|
32653
|
+
if (!host.attachRequests || host.session === void 0)
|
|
32654
|
+
return "EPERM: this port may not answer requests";
|
|
32655
|
+
const launcher = await host.launcher();
|
|
32656
|
+
unbind = launcher.embedder.register(
|
|
32657
|
+
host.session,
|
|
32658
|
+
asker.hookFor(host.session, hello.requests)
|
|
32659
|
+
);
|
|
32660
|
+
return void 0;
|
|
32661
|
+
},
|
|
32662
|
+
close: () => unbind?.()
|
|
32663
|
+
};
|
|
32664
|
+
}
|
|
31893
32665
|
function serveClient(port, host) {
|
|
31894
32666
|
let state = "new";
|
|
31895
32667
|
let self;
|
|
@@ -31904,7 +32676,7 @@ function serveClient(port, host) {
|
|
|
31904
32676
|
if (state !== "closed") port.postMessage(message3, transfer);
|
|
31905
32677
|
};
|
|
31906
32678
|
const reply = (id2, body, transfer) => send2({ id: id2, ...body }, transfer);
|
|
31907
|
-
const hosts = hostRegistries(send2, ended.promise);
|
|
32679
|
+
const hosts = hostRegistries(send2, ended.promise, port);
|
|
31908
32680
|
function detach(kill = false, bye = "the slicc-kernel detached this client") {
|
|
31909
32681
|
if (state === "closed") return;
|
|
31910
32682
|
send2({ bye });
|
|
@@ -31921,7 +32693,7 @@ function serveClient(port, host) {
|
|
|
31921
32693
|
ended.resolve();
|
|
31922
32694
|
}
|
|
31923
32695
|
async function hello(message3) {
|
|
31924
|
-
const refused3 = versionError(message3.protocol);
|
|
32696
|
+
const refused3 = versionError(message3.protocol) ?? await hosts.requests.accept(host, message3);
|
|
31925
32697
|
if (refused3) {
|
|
31926
32698
|
send2({ hello: { protocol: PROTOCOL, error: refused3 } });
|
|
31927
32699
|
detach();
|
|
@@ -31946,7 +32718,7 @@ function serveClient(port, host) {
|
|
|
31946
32718
|
async function terminal(req, l) {
|
|
31947
32719
|
const session = await l.openTerminal(req.argv, {
|
|
31948
32720
|
...req.options,
|
|
31949
|
-
...await runTagged(l, self, req.options, host.tag),
|
|
32721
|
+
...await runTagged(l, self, req.options, host.tag, host.session),
|
|
31950
32722
|
onData: (bytes) => reply(req.id, { fd: 1, bytes: bytes.slice() })
|
|
31951
32723
|
});
|
|
31952
32724
|
if (state === "closed") {
|
|
@@ -31969,7 +32741,7 @@ function serveClient(port, host) {
|
|
|
31969
32741
|
let leader;
|
|
31970
32742
|
const result = await l.run(req.argv, {
|
|
31971
32743
|
...req.options,
|
|
31972
|
-
...await runTagged(l, self, req.options, host.tag),
|
|
32744
|
+
...await runTagged(l, self, req.options, host.tag, host.session),
|
|
31973
32745
|
collect: false,
|
|
31974
32746
|
onStdout: out(1),
|
|
31975
32747
|
onStderr: out(2),
|
|
@@ -32149,11 +32921,11 @@ function guarded2(check, signal) {
|
|
|
32149
32921
|
signal.throwIfAborted();
|
|
32150
32922
|
let stop = () => {
|
|
32151
32923
|
};
|
|
32152
|
-
const
|
|
32924
|
+
const aborted3 = new Promise((_, reject) => {
|
|
32153
32925
|
stop = () => reject(signal.reason);
|
|
32154
32926
|
signal.addEventListener("abort", stop, { once: true });
|
|
32155
32927
|
});
|
|
32156
|
-
return Promise.race([check,
|
|
32928
|
+
return Promise.race([check, aborted3]).finally(() => signal.removeEventListener("abort", stop));
|
|
32157
32929
|
}
|
|
32158
32930
|
var loopbackStore = new AsyncLocalStorage();
|
|
32159
32931
|
var subscribed = false;
|
|
@@ -32268,7 +33040,7 @@ function valid(name2) {
|
|
|
32268
33040
|
}
|
|
32269
33041
|
}
|
|
32270
33042
|
var CHUNK4 = 1024 * 1024;
|
|
32271
|
-
function
|
|
33043
|
+
function bytesOf3(data) {
|
|
32272
33044
|
if (typeof data === "string") return new TextEncoder().encode(data);
|
|
32273
33045
|
if (data instanceof Blob) return data.arrayBuffer().then((buffer) => new Uint8Array(buffer));
|
|
32274
33046
|
if (ArrayBuffer.isView(data)) {
|
|
@@ -32348,7 +33120,7 @@ var MemoryFile = class {
|
|
|
32348
33120
|
const next3 = keepExistingData ? new Chunks([...this.data.blobs], this.data.size) : new Chunks();
|
|
32349
33121
|
let position = 0;
|
|
32350
33122
|
const put = async (data) => {
|
|
32351
|
-
const bytes = await
|
|
33123
|
+
const bytes = await bytesOf3(data);
|
|
32352
33124
|
await next3.write(position, bytes);
|
|
32353
33125
|
position += bytes.length;
|
|
32354
33126
|
};
|
|
@@ -32480,11 +33252,11 @@ function abortable(work, signal) {
|
|
|
32480
33252
|
if (signal.aborted) return Promise.reject(signal.reason);
|
|
32481
33253
|
let stop = () => {
|
|
32482
33254
|
};
|
|
32483
|
-
const
|
|
33255
|
+
const aborted3 = new Promise((_, reject) => {
|
|
32484
33256
|
stop = () => reject(signal.reason);
|
|
32485
33257
|
signal.addEventListener("abort", stop, { once: true });
|
|
32486
33258
|
});
|
|
32487
|
-
return Promise.race([work,
|
|
33259
|
+
return Promise.race([work, aborted3]).finally(() => signal.removeEventListener("abort", stop));
|
|
32488
33260
|
}
|
|
32489
33261
|
function probe(secure2, host, port, ms, signal) {
|
|
32490
33262
|
return new Promise((resolve2) => {
|
|
@@ -32843,10 +33615,10 @@ var ByteSource = class {
|
|
|
32843
33615
|
async more() {
|
|
32844
33616
|
const { done: done4, value: value2 } = await this.reader.read();
|
|
32845
33617
|
if (done4) return false;
|
|
32846
|
-
const
|
|
32847
|
-
|
|
32848
|
-
|
|
32849
|
-
this.buffered =
|
|
33618
|
+
const joined5 = new Uint8Array(this.buffered.length + value2.length);
|
|
33619
|
+
joined5.set(this.buffered);
|
|
33620
|
+
joined5.set(value2, this.buffered.length);
|
|
33621
|
+
this.buffered = joined5;
|
|
32850
33622
|
return true;
|
|
32851
33623
|
}
|
|
32852
33624
|
async until(marker) {
|
|
@@ -33013,7 +33785,7 @@ var KernelCallError = class extends Error {
|
|
|
33013
33785
|
}
|
|
33014
33786
|
};
|
|
33015
33787
|
var encoder12 = new TextEncoder();
|
|
33016
|
-
var
|
|
33788
|
+
var bytesOf4 = (data) => typeof data === "string" ? encoder12.encode(data) : data;
|
|
33017
33789
|
var UNAVAILABLE = {
|
|
33018
33790
|
manualRedirects: false,
|
|
33019
33791
|
encodedBodies: false,
|
|
@@ -33097,7 +33869,9 @@ var Channel = class {
|
|
|
33097
33869
|
call(call) {
|
|
33098
33870
|
return this.request(call).done;
|
|
33099
33871
|
}
|
|
33872
|
+
requests;
|
|
33100
33873
|
receive(data) {
|
|
33874
|
+
if (this.requests?.handle(data)) return;
|
|
33101
33875
|
if (data.traits && data.id === void 0) {
|
|
33102
33876
|
if (this.remote) this.remote.traits = data.traits;
|
|
33103
33877
|
for (const listener of [...this.traitsListeners]) listener(data.traits);
|
|
@@ -33220,7 +33994,7 @@ async function spawnOn(channel, argv, opts) {
|
|
|
33220
33994
|
});
|
|
33221
33995
|
const started = Promise.withResolvers();
|
|
33222
33996
|
let endedBy;
|
|
33223
|
-
const options = { ...rest2, ...stdin !== void 0 ? { stdin:
|
|
33997
|
+
const options = { ...rest2, ...stdin !== void 0 ? { stdin: bytesOf4(stdin) } : {} };
|
|
33224
33998
|
const { done: done4 } = channel.request(
|
|
33225
33999
|
{ op: "spawn", argv, options },
|
|
33226
34000
|
{
|
|
@@ -33303,7 +34077,7 @@ async function terminalOn(channel, argv, opts) {
|
|
|
33303
34077
|
listener = next3;
|
|
33304
34078
|
if (next3) for (const bytes of backlog.splice(0)) next3(bytes);
|
|
33305
34079
|
},
|
|
33306
|
-
write: (data) => send2({ action: "write", bytes:
|
|
34080
|
+
write: (data) => send2({ action: "write", bytes: bytesOf4(data) }),
|
|
33307
34081
|
resize: (cols, rows) => send2({ action: "resize", cols, rows }),
|
|
33308
34082
|
signal: (name2) => send2({ action: "signal", signal: name2 }),
|
|
33309
34083
|
close: () => send2({ action: "close" })
|
|
@@ -33365,8 +34139,10 @@ function since(channel, minor, what, run2) {
|
|
|
33365
34139
|
}
|
|
33366
34140
|
return run2();
|
|
33367
34141
|
}
|
|
33368
|
-
async function greet(channel, lock, timeoutMs) {
|
|
33369
|
-
channel.post({
|
|
34142
|
+
async function greet(channel, lock, timeoutMs, requests) {
|
|
34143
|
+
channel.post({
|
|
34144
|
+
hello: { protocol: PROTOCOL, ...lock ? { lock } : {}, ...requests ? { requests } : {} }
|
|
34145
|
+
});
|
|
33370
34146
|
const timer = setTimeout(
|
|
33371
34147
|
() => channel.end(
|
|
33372
34148
|
new KernelGoneError(`no slicc-kernel answered on this port within ${timeoutMs} ms`)
|
|
@@ -33391,7 +34167,14 @@ async function attachKernel(port, options = {}) {
|
|
|
33391
34167
|
const locks = options.locks === null ? void 0 : options.locks ?? locksOf();
|
|
33392
34168
|
const own = await holdLock(locks);
|
|
33393
34169
|
const channel = new Channel(port, own.release);
|
|
33394
|
-
const
|
|
34170
|
+
const requests = options.requests;
|
|
34171
|
+
if (requests) channel.requests = embedderAnswerer(port, () => requests);
|
|
34172
|
+
const hello = await greet(
|
|
34173
|
+
channel,
|
|
34174
|
+
own.name,
|
|
34175
|
+
options.timeoutMs ?? 1e4,
|
|
34176
|
+
requests ? kindsOf(requests) : void 0
|
|
34177
|
+
);
|
|
33395
34178
|
channel.protocol = hello.protocol;
|
|
33396
34179
|
if (hello.lock && locks) void locks.request(hello.lock, () => channel.end(new KernelGoneError()));
|
|
33397
34180
|
const transport = new RemoteTransport(
|
|
@@ -33605,6 +34388,31 @@ function cacheDirOf(dir) {
|
|
|
33605
34388
|
}
|
|
33606
34389
|
return dir;
|
|
33607
34390
|
}
|
|
34391
|
+
var nodeSessions = 0;
|
|
34392
|
+
function nodeClient(launcher, clients, { user, tag, requests }) {
|
|
34393
|
+
tagOption(tag);
|
|
34394
|
+
const { port1, port2 } = new MessageChannel2();
|
|
34395
|
+
const session = ++nodeSessions;
|
|
34396
|
+
const served2 = serveClient(port1, {
|
|
34397
|
+
launcher: async () => launcher,
|
|
34398
|
+
signal: signalNumber,
|
|
34399
|
+
session,
|
|
34400
|
+
...requests === "attach" ? { attachRequests: true } : {},
|
|
34401
|
+
...user !== void 0 ? { user } : {},
|
|
34402
|
+
...tag !== void 0 ? { tag } : {}
|
|
34403
|
+
});
|
|
34404
|
+
clients.add(served2);
|
|
34405
|
+
const unbind = requests && requests !== "attach" ? launcher.embedder.register(session, checkedRequests(requests)) : void 0;
|
|
34406
|
+
void served2.closed.then(() => {
|
|
34407
|
+
clients.delete(served2);
|
|
34408
|
+
unbind?.();
|
|
34409
|
+
});
|
|
34410
|
+
return port2;
|
|
34411
|
+
}
|
|
34412
|
+
function checkedRequests(hook) {
|
|
34413
|
+
const kinds = kindsOf(hook);
|
|
34414
|
+
return { kinds, handle: (request) => hook.handle(request) };
|
|
34415
|
+
}
|
|
33608
34416
|
async function createNodeKernel(options = {}) {
|
|
33609
34417
|
const root = options.root ?? memoryRoot();
|
|
33610
34418
|
const fs = new OpfsFs(root, void 0, void 0, { ranged: isMemoryRoot(root) });
|
|
@@ -33645,6 +34453,7 @@ async function createNodeKernel(options = {}) {
|
|
|
33645
34453
|
...options.protect ? { protect: options.protect } : {},
|
|
33646
34454
|
...options.sealed ? { sealed: options.sealed } : {},
|
|
33647
34455
|
...options.clipboard ? { clipboard: options.clipboard } : {},
|
|
34456
|
+
...options.requests ? { embedder: checkedRequests(options.requests) } : {},
|
|
33648
34457
|
...options.approve ? { approve: options.approve } : {},
|
|
33649
34458
|
...options.wasmMemories ? { wasmMemories: options.wasmMemories } : {},
|
|
33650
34459
|
cron: { lock: cronLock(root), ...options.cron?.clock ? { clock: options.cron.clock } : {} }
|
|
@@ -33735,22 +34544,13 @@ async function createNodeKernel(options = {}) {
|
|
|
33735
34544
|
addMember: (group, user) => guard2(() => launcher.users.addMember(group, user)),
|
|
33736
34545
|
removeMember: (group, user) => guard2(() => launcher.users.removeMember(group, user))
|
|
33737
34546
|
},
|
|
33738
|
-
async connect(
|
|
34547
|
+
async connect(connectOptions = {}) {
|
|
33739
34548
|
if (terminated) throw new Error(TERMINATED);
|
|
33740
|
-
|
|
34549
|
+
const { user } = connectOptions;
|
|
33741
34550
|
if (user !== void 0 && !await guard2(() => launcher.users.lookup(user))) {
|
|
33742
34551
|
throw fsError("ENOENT", `no user ${String(user)}`);
|
|
33743
34552
|
}
|
|
33744
|
-
|
|
33745
|
-
const served2 = serveClient(port1, {
|
|
33746
|
-
launcher: async () => launcher,
|
|
33747
|
-
signal: signalNumber,
|
|
33748
|
-
...user !== void 0 ? { user } : {},
|
|
33749
|
-
...tag !== void 0 ? { tag } : {}
|
|
33750
|
-
});
|
|
33751
|
-
clients.add(served2);
|
|
33752
|
-
void served2.closed.then(() => clients.delete(served2));
|
|
33753
|
-
return port2;
|
|
34553
|
+
return nodeClient(launcher, clients, connectOptions);
|
|
33754
34554
|
},
|
|
33755
34555
|
terminate() {
|
|
33756
34556
|
terminated = true;
|