@ai-ecoverse/slicc-kernel 1.152.1 → 1.153.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -2
- 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 +828 -152
- 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 +71 -21
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +966 -167
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +71 -21
- 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/fs/unlinked.d.ts +4 -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/process.d.ts +17 -0
- package/dist/types/launcher.d.ts +13 -0
- package/dist/types/mount/mount-fs.d.ts +1 -0
- package/dist/types/node.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/realm/sync-fs-token-registry.d.ts +1 -0
- package/dist/types/serve.d.ts +3 -0
- package/package.json +2 -2
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.153.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
|
};
|
|
@@ -4242,6 +4439,7 @@ var PathMarks = class {
|
|
|
4242
4439
|
floor = 0;
|
|
4243
4440
|
touched = /* @__PURE__ */ new Map();
|
|
4244
4441
|
flying = /* @__PURE__ */ new Map();
|
|
4442
|
+
waiting = /* @__PURE__ */ new Set();
|
|
4245
4443
|
generation() {
|
|
4246
4444
|
return this.gen;
|
|
4247
4445
|
}
|
|
@@ -4274,10 +4472,22 @@ var PathMarks = class {
|
|
|
4274
4472
|
const n = (this.flying.get(p) ?? 1) - 1;
|
|
4275
4473
|
if (n > 0) this.flying.set(p, n);
|
|
4276
4474
|
else this.flying.delete(p);
|
|
4475
|
+
for (const wake of [...this.waiting]) wake();
|
|
4277
4476
|
this.touch(p);
|
|
4278
4477
|
}
|
|
4279
4478
|
}
|
|
4280
4479
|
}
|
|
4480
|
+
async landed(path) {
|
|
4481
|
+
if (!this.inFlight(path)) return;
|
|
4482
|
+
await new Promise((resolve2) => {
|
|
4483
|
+
const wake = () => {
|
|
4484
|
+
if (this.inFlight(path)) return;
|
|
4485
|
+
this.waiting.delete(wake);
|
|
4486
|
+
resolve2();
|
|
4487
|
+
};
|
|
4488
|
+
this.waiting.add(wake);
|
|
4489
|
+
});
|
|
4490
|
+
}
|
|
4281
4491
|
inFlight(path) {
|
|
4282
4492
|
for (let p = path; this.flying.size > 0; p = parentOf2(p)) {
|
|
4283
4493
|
if (this.flying.has(p)) return true;
|
|
@@ -4468,6 +4678,9 @@ var UnlinkedKeeper = class {
|
|
|
4468
4678
|
changedSince(path, gen) {
|
|
4469
4679
|
return this.marks.changedSince(path, gen);
|
|
4470
4680
|
}
|
|
4681
|
+
landed(path) {
|
|
4682
|
+
return this.marks.landed(path);
|
|
4683
|
+
}
|
|
4471
4684
|
inFlight(path) {
|
|
4472
4685
|
return this.marks.inFlight(path);
|
|
4473
4686
|
}
|
|
@@ -4503,15 +4716,15 @@ var UnlinkedKeeper = class {
|
|
|
4503
4716
|
const releases = [];
|
|
4504
4717
|
const take = async () => {
|
|
4505
4718
|
for (; ; ) {
|
|
4506
|
-
const
|
|
4507
|
-
if (
|
|
4508
|
-
|
|
4509
|
-
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])) {
|
|
4510
4723
|
for (const release of releases.splice(0)) release();
|
|
4511
|
-
|
|
4512
|
-
|
|
4724
|
+
fresh3.push(...paths.splice(0));
|
|
4725
|
+
fresh3.sort();
|
|
4513
4726
|
}
|
|
4514
|
-
for (const path of
|
|
4727
|
+
for (const path of fresh3) {
|
|
4515
4728
|
paths.push(path);
|
|
4516
4729
|
releases.push(await this.gate.acquire(path));
|
|
4517
4730
|
}
|
|
@@ -4846,10 +5059,10 @@ var CronService = class {
|
|
|
4846
5059
|
const text = JSON.stringify(stamp);
|
|
4847
5060
|
const old = await fs.readFile(STAMP_PATH).catch(() => void 0);
|
|
4848
5061
|
if (old === text || old === void 0 && text === EMPTY_STAMP) return;
|
|
4849
|
-
const
|
|
5062
|
+
const fresh3 = `${STAMP_PATH}.new`;
|
|
4850
5063
|
const owner = owners ? { uid: 0, gid: 0, mode: 384 } : void 0;
|
|
4851
|
-
await fs.writeFile(
|
|
4852
|
-
await fs.rename(
|
|
5064
|
+
await fs.writeFile(fresh3, text, owner);
|
|
5065
|
+
await fs.rename(fresh3, STAMP_PATH);
|
|
4853
5066
|
}
|
|
4854
5067
|
async load() {
|
|
4855
5068
|
const { fs } = this.host;
|
|
@@ -6285,13 +6498,13 @@ function materializer(fs, listedAbsent) {
|
|
|
6285
6498
|
};
|
|
6286
6499
|
}
|
|
6287
6500
|
function withEtcFiles(fs, files) {
|
|
6288
|
-
const
|
|
6501
|
+
const bytesOf5 = (path) => {
|
|
6289
6502
|
const text = files.get(path)?.();
|
|
6290
6503
|
return text === void 0 ? void 0 : new TextEncoder().encode(text);
|
|
6291
6504
|
};
|
|
6292
6505
|
const absent2 = (path) => fs.lstat(path).then(() => false, missing2);
|
|
6293
6506
|
const follow2 = linkFollower(fs, files);
|
|
6294
|
-
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;
|
|
6295
6508
|
const fallback = (path, make) => async (err) => {
|
|
6296
6509
|
const at = missing2(err) ? await follow2(path) : void 0;
|
|
6297
6510
|
const bytes = at === void 0 ? void 0 : await listedAbsent(at);
|
|
@@ -6364,10 +6577,10 @@ var FreshModules = class {
|
|
|
6364
6577
|
this.fresh.set(key, { umask: mask, pid, added: 0, setup: mask !== DEFAULT_UMASK });
|
|
6365
6578
|
}
|
|
6366
6579
|
forget(pid) {
|
|
6367
|
-
for (const [path,
|
|
6580
|
+
for (const [path, fresh3] of this.fresh) if (fresh3.pid === pid) this.fresh.delete(path);
|
|
6368
6581
|
}
|
|
6369
|
-
drop(
|
|
6370
|
-
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);
|
|
6371
6584
|
}
|
|
6372
6585
|
moved(from, to) {
|
|
6373
6586
|
const source = normalizePath(from);
|
|
@@ -6376,10 +6589,10 @@ var FreshModules = class {
|
|
|
6376
6589
|
for (const key of [...this.fresh.keys()]) {
|
|
6377
6590
|
if (key === target || within3(key, target)) this.fresh.delete(key);
|
|
6378
6591
|
}
|
|
6379
|
-
for (const [key,
|
|
6592
|
+
for (const [key, fresh3] of [...this.fresh]) {
|
|
6380
6593
|
if (key !== source && !within3(key, source)) continue;
|
|
6381
6594
|
this.fresh.delete(key);
|
|
6382
|
-
this.fresh.set(target + key.slice(source.length),
|
|
6595
|
+
this.fresh.set(target + key.slice(source.length), fresh3);
|
|
6383
6596
|
}
|
|
6384
6597
|
}
|
|
6385
6598
|
wrap(fs) {
|
|
@@ -6389,15 +6602,15 @@ var FreshModules = class {
|
|
|
6389
6602
|
};
|
|
6390
6603
|
const decide = async (given, known) => {
|
|
6391
6604
|
const path = normalizePath(given);
|
|
6392
|
-
const
|
|
6393
|
-
if (!
|
|
6605
|
+
const fresh3 = this.fresh.get(path);
|
|
6606
|
+
if (!fresh3) return;
|
|
6394
6607
|
const bytes = known && known.length >= MAGIC.length ? known : await head(path);
|
|
6395
|
-
const want = isModule(bytes) ? 73 & ~
|
|
6396
|
-
|
|
6397
|
-
if (want ===
|
|
6608
|
+
const want = isModule(bytes) ? 73 & ~fresh3.umask : 0;
|
|
6609
|
+
fresh3.setup = false;
|
|
6610
|
+
if (want === fresh3.added) return;
|
|
6398
6611
|
const mode = (await fs.stat(path)).mode & 4095;
|
|
6399
|
-
await fs.chmod(path, mode & ~
|
|
6400
|
-
|
|
6612
|
+
await fs.chmod(path, mode & ~fresh3.added | want);
|
|
6613
|
+
fresh3.added = want;
|
|
6401
6614
|
};
|
|
6402
6615
|
const overrides = {
|
|
6403
6616
|
writeFile: async (path, content, owner) => {
|
|
@@ -6410,9 +6623,9 @@ var FreshModules = class {
|
|
|
6410
6623
|
}
|
|
6411
6624
|
},
|
|
6412
6625
|
chmod: async (path, mode) => {
|
|
6413
|
-
const
|
|
6414
|
-
if (
|
|
6415
|
-
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);
|
|
6416
6629
|
await fs.chmod(path, mode);
|
|
6417
6630
|
},
|
|
6418
6631
|
rm: async (path, options) => {
|
|
@@ -6429,8 +6642,8 @@ var FreshModules = class {
|
|
|
6429
6642
|
link: async (from, to, follow2) => {
|
|
6430
6643
|
await fs.link(from, to, follow2);
|
|
6431
6644
|
const source = follow2 && fs.realpath ? await fs.realpath(from, true).catch(() => from) : from;
|
|
6432
|
-
const
|
|
6433
|
-
if (
|
|
6645
|
+
const fresh3 = this.fresh.get(normalizePath(source));
|
|
6646
|
+
if (fresh3) this.fresh.set(normalizePath(to), fresh3);
|
|
6434
6647
|
}
|
|
6435
6648
|
};
|
|
6436
6649
|
const ranged2 = rangedOps(fs);
|
|
@@ -7134,7 +7347,7 @@ var FsWatchers = class {
|
|
|
7134
7347
|
};
|
|
7135
7348
|
const content = (run2, types) => async (...args) => {
|
|
7136
7349
|
const at = normalizePath(args[0]);
|
|
7137
|
-
const
|
|
7350
|
+
const fresh3 = this.covers(at) && !await fs.exists(at).catch(() => true);
|
|
7138
7351
|
let done4 = false;
|
|
7139
7352
|
try {
|
|
7140
7353
|
await run2(...args);
|
|
@@ -7143,11 +7356,11 @@ var FsWatchers = class {
|
|
|
7143
7356
|
const real = await realOf(at);
|
|
7144
7357
|
const paths = real === at ? [at] : [at, real];
|
|
7145
7358
|
this.report(paths);
|
|
7146
|
-
if (done4) for (const type of types(
|
|
7359
|
+
if (done4) for (const type of types(fresh3, args)) this.emit(type, paths);
|
|
7147
7360
|
}
|
|
7148
7361
|
};
|
|
7149
|
-
const written2 = (
|
|
7150
|
-
const overwritten = (
|
|
7362
|
+
const written2 = (fresh3) => fresh3 ? ["rename", "change"] : ["change"];
|
|
7363
|
+
const overwritten = (fresh3, args) => fresh3 || args[1].length === 0 ? written2(fresh3) : ["change", "change"];
|
|
7151
7364
|
const reshaping = (run2) => async (...args) => {
|
|
7152
7365
|
this.reshaped();
|
|
7153
7366
|
try {
|
|
@@ -7174,14 +7387,14 @@ var FsWatchers = class {
|
|
|
7174
7387
|
if (created4.length > 0 || !await fs.exists(ancestor)) created4.push(ancestor);
|
|
7175
7388
|
}
|
|
7176
7389
|
}
|
|
7177
|
-
const
|
|
7390
|
+
const fresh3 = !options?.recursive || this.typed.size > 0 && !await fs.exists(path);
|
|
7178
7391
|
let done4 = false;
|
|
7179
7392
|
try {
|
|
7180
7393
|
await fs.mkdir(path, options);
|
|
7181
7394
|
done4 = true;
|
|
7182
7395
|
} finally {
|
|
7183
7396
|
this.report([...created4, path]);
|
|
7184
|
-
if (done4) this.emit("rename",
|
|
7397
|
+
if (done4) this.emit("rename", fresh3 ? [...created4, path] : created4);
|
|
7185
7398
|
}
|
|
7186
7399
|
},
|
|
7187
7400
|
rm: reshaping(after(fs.rm.bind(fs), (path) => [path], "rename")),
|
|
@@ -7637,6 +7850,416 @@ var ClipboardBroker = class {
|
|
|
7637
7850
|
}
|
|
7638
7851
|
};
|
|
7639
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
|
+
|
|
7640
8263
|
// src/kernel/exec-ticket.ts
|
|
7641
8264
|
var TICKET_ENV = "SLICC_SEALED_TICKET";
|
|
7642
8265
|
var TICKET_TTL_MS = 3e4;
|
|
@@ -8190,6 +8813,9 @@ var HeldPaths = class extends Map {
|
|
|
8190
8813
|
trust(handle, doubt) {
|
|
8191
8814
|
if (this.doubted.get(handle) === doubt) this.doubted.delete(handle);
|
|
8192
8815
|
}
|
|
8816
|
+
pathOf(handle) {
|
|
8817
|
+
return this.handles.get(handle);
|
|
8818
|
+
}
|
|
8193
8819
|
keptFor(handle) {
|
|
8194
8820
|
return this.keptHandles.get(handle);
|
|
8195
8821
|
}
|
|
@@ -8202,9 +8828,9 @@ var HeldPaths = class extends Map {
|
|
|
8202
8828
|
return false;
|
|
8203
8829
|
}
|
|
8204
8830
|
keep(path, file) {
|
|
8205
|
-
const
|
|
8206
|
-
for (const id2 of
|
|
8207
|
-
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));
|
|
8208
8834
|
this.unlinked.set(path, file);
|
|
8209
8835
|
}
|
|
8210
8836
|
unkeep(path, file) {
|
|
@@ -9400,8 +10026,8 @@ var MountFs = class _MountFs {
|
|
|
9400
10026
|
}
|
|
9401
10027
|
this.writable(mount, real);
|
|
9402
10028
|
const { uid, gid, mode } = change;
|
|
9403
|
-
const
|
|
9404
|
-
const set3 =
|
|
10029
|
+
const fresh3 = change.kind === "new" && { uid, gid, mode };
|
|
10030
|
+
const set3 = fresh3 ? await this.driverOwner(found, real, fresh3, false) : change;
|
|
9405
10031
|
this.table.forget(mount, real);
|
|
9406
10032
|
const attrs = Object.entries({ uid: set3.uid, gid: set3.gid, mode: set3.mode });
|
|
9407
10033
|
await mount.conn.call({
|
|
@@ -9673,10 +10299,10 @@ async function runMkdir(entry, path, req) {
|
|
|
9673
10299
|
const plain3 = plainDirMode(entry, req.mode);
|
|
9674
10300
|
const parentsMode = !req.exclusive ? plainParentsMode(entry) : void 0;
|
|
9675
10301
|
const fixParents = parentsMode !== void 0 ? await missingParents(fs, path, parentsMode) : void 0;
|
|
9676
|
-
const
|
|
10302
|
+
const fresh3 = plain3 !== void 0 && !await fs.exists(path);
|
|
9677
10303
|
await (req.exclusive ? mkdirExclusive(entry, path, req.mode) : fs.mkdir(path, mkdirOptions(entry, req.mode)));
|
|
9678
10304
|
await fixParents?.();
|
|
9679
|
-
if (
|
|
10305
|
+
if (fresh3) await fs.chmod(path, plain3);
|
|
9680
10306
|
return done;
|
|
9681
10307
|
}
|
|
9682
10308
|
async function shownAs(entry, path, st) {
|
|
@@ -10073,12 +10699,20 @@ async function linkedElsewhere(fs, path, from) {
|
|
|
10073
10699
|
const source = from === void 0 ? void 0 : await fs.lstat(from).catch(() => void 0);
|
|
10074
10700
|
return !(source && source.ino === st.ino && source.dev === st.dev);
|
|
10075
10701
|
}
|
|
10702
|
+
async function gatedByHandle(entry, opEntry, path, req, opReq) {
|
|
10703
|
+
const heldAt2 = () => req.handle === void 0 ? void 0 : opEntry.heldAt?.(req.handle);
|
|
10704
|
+
if (req.handle !== void 0) await opEntry.replacements?.landed?.(heldAt2() ?? path);
|
|
10705
|
+
const at = heldAt2() ?? path;
|
|
10706
|
+
const serve = async () => run(opEntry, await keptOr(opEntry, at, req.handle), opReq);
|
|
10707
|
+
return entry.gate ? entry.gate(at, serve) : serve();
|
|
10708
|
+
}
|
|
10076
10709
|
async function keptOr(entry, path, handle) {
|
|
10077
10710
|
if (handle !== void 0) {
|
|
10078
10711
|
const hidden = entry.keptFor?.(handle)?.hidden;
|
|
10079
10712
|
if (hidden !== void 0) return hidden;
|
|
10080
|
-
|
|
10081
|
-
|
|
10713
|
+
const at = entry.heldAt?.(handle) ?? path;
|
|
10714
|
+
await bound(entry, at, handle);
|
|
10715
|
+
return at;
|
|
10082
10716
|
}
|
|
10083
10717
|
const kept = entry.unlinked?.(path);
|
|
10084
10718
|
return kept && !await entry.fs.exists(path) ? kept.hidden : path;
|
|
@@ -10271,8 +10905,7 @@ async function dispatchPath(entry, req) {
|
|
|
10271
10905
|
if (entry.revoked?.(resolvedPath))
|
|
10272
10906
|
return { ok: false, errno: "EIO", message: `${resolvedPath} was unmounted` };
|
|
10273
10907
|
if (req.op === "write" && req.mode === 1 || UNLINKED_OPS.has(req.op)) {
|
|
10274
|
-
|
|
10275
|
-
return await (entry.gate ? entry.gate(resolvedPath, serve) : serve());
|
|
10908
|
+
return await gatedByHandle(entry, opEntry, resolvedPath, req, opReq);
|
|
10276
10909
|
}
|
|
10277
10910
|
if (!entry.own || !OWN_OPS.has(req.op)) return await run(opEntry, resolvedPath, opReq);
|
|
10278
10911
|
const target = resolvedArg2 ?? (TWO_PATHS.has(req.op) ? fs.resolvePath(cwd, req.arg2 ?? "") : resolvedPath);
|
|
@@ -10673,9 +11306,9 @@ var Pages = class {
|
|
|
10673
11306
|
const page = (start2 + at) / PAGE;
|
|
10674
11307
|
if (this.pages.has(page)) continue;
|
|
10675
11308
|
const part = bytes.subarray(at, Math.min(at + PAGE, bytes.length));
|
|
10676
|
-
const
|
|
10677
|
-
|
|
10678
|
-
this.pages.set(page,
|
|
11309
|
+
const fresh3 = this.take(part.length);
|
|
11310
|
+
fresh3.set(part);
|
|
11311
|
+
this.pages.set(page, fresh3);
|
|
10679
11312
|
}
|
|
10680
11313
|
}
|
|
10681
11314
|
read(at, length2) {
|
|
@@ -12937,18 +13570,18 @@ var TlsEngine = class {
|
|
|
12937
13570
|
chainFlags(store, chain2, hostname) {
|
|
12938
13571
|
const verify = this.m._tls_chain_verify;
|
|
12939
13572
|
if (!verify || chain2.length === 0) return void 0;
|
|
12940
|
-
const
|
|
13573
|
+
const joined5 = new Uint8Array(chain2.reduce((n, c) => n + c.length, 0));
|
|
12941
13574
|
let at = 0;
|
|
12942
13575
|
for (const der2 of chain2) {
|
|
12943
|
-
|
|
13576
|
+
joined5.set(der2, at);
|
|
12944
13577
|
at += der2.length;
|
|
12945
13578
|
}
|
|
12946
13579
|
const name2 = this.put(new TextEncoder().encode(hostname));
|
|
12947
13580
|
try {
|
|
12948
|
-
return this.withBytes(
|
|
13581
|
+
return this.withBytes(joined5, (p) => {
|
|
12949
13582
|
const out = this.scratch;
|
|
12950
13583
|
this.m.HEAPU8.fill(255, out, out + 4);
|
|
12951
|
-
const ret = verify(store.ptr, p,
|
|
13584
|
+
const ret = verify(store.ptr, p, joined5.length, name2, out);
|
|
12952
13585
|
const flags2 = new DataView(this.m.HEAPU8.buffer, out, 4).getUint32(0, true);
|
|
12953
13586
|
if (ret === 0) return flags2 === 0 ? 0 : void 0;
|
|
12954
13587
|
return ret === 1 && flags2 !== 0 ? flags2 : void 0;
|
|
@@ -15682,6 +16315,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
|
15682
16315
|
...file.tty ? { tty: file.tty } : {},
|
|
15683
16316
|
identity: file.identity ?? file,
|
|
15684
16317
|
...file.clipboard ? { clipboard: file.clipboard } : {},
|
|
16318
|
+
...file.embedder ? { embedder: file.embedder } : {},
|
|
15685
16319
|
...file.write ? {
|
|
15686
16320
|
write: async (bytes, signal) => {
|
|
15687
16321
|
await turn(signal);
|
|
@@ -15738,7 +16372,8 @@ function scrubStdio(fds, scrubber) {
|
|
|
15738
16372
|
const stdio = stdioFiles(fds);
|
|
15739
16373
|
for (const fd of fds.numbers()) {
|
|
15740
16374
|
const original = fds.get(fd);
|
|
15741
|
-
|
|
16375
|
+
const named = original.file.tty || original.file.clipboard || original.file.embedder;
|
|
16376
|
+
if (!stdio.has(original) && !named) continue;
|
|
15742
16377
|
const known = wrapped.get(original);
|
|
15743
16378
|
const flags2 = fds.statusFlags(fd);
|
|
15744
16379
|
const wrapper = known ? known.retain() : scrubbed(original.retain(), scrubber);
|
|
@@ -15751,9 +16386,9 @@ function scrubStdio(fds, scrubber) {
|
|
|
15751
16386
|
// src/kernel/net/sealed-scrubs.ts
|
|
15752
16387
|
function addTo(tree2, host, secrets) {
|
|
15753
16388
|
const entry = tree2.get(host) ?? { secrets: [], version: 0, scrubber: void 0 };
|
|
15754
|
-
const
|
|
15755
|
-
if (
|
|
15756
|
-
entry.secrets = [...entry.secrets, ...
|
|
16389
|
+
const fresh3 = secrets.filter((s) => !entry.secrets.some((e) => e.value === s.value));
|
|
16390
|
+
if (fresh3.length === 0) return;
|
|
16391
|
+
entry.secrets = [...entry.secrets, ...fresh3];
|
|
15757
16392
|
entry.version += 1;
|
|
15758
16393
|
entry.scrubber = void 0;
|
|
15759
16394
|
tree2.set(host, entry);
|
|
@@ -15967,13 +16602,13 @@ function serialized(reply) {
|
|
|
15967
16602
|
const text = JSON.stringify(reply);
|
|
15968
16603
|
plain3 = text === void 0 ? void 0 : JSON.parse(text);
|
|
15969
16604
|
} catch (err) {
|
|
15970
|
-
return JSON.stringify(errorReply("EIO",
|
|
16605
|
+
return JSON.stringify(errorReply("EIO", lineOf3(err)));
|
|
15971
16606
|
}
|
|
15972
16607
|
if (!isRecord(plain3)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
|
|
15973
16608
|
const { v: _, ...rest2 } = plain3;
|
|
15974
16609
|
return JSON.stringify({ v: 1, ...rest2 });
|
|
15975
16610
|
}
|
|
15976
|
-
function
|
|
16611
|
+
function lineOf3(err) {
|
|
15977
16612
|
const text = err instanceof Error ? err.message : String(err);
|
|
15978
16613
|
return (text.split("\n")[0] ?? "").slice(0, 200);
|
|
15979
16614
|
}
|
|
@@ -16024,7 +16659,7 @@ var SealedChannel = class {
|
|
|
16024
16659
|
if (signal.aborted) return void 0;
|
|
16025
16660
|
const asked = Promise.resolve().then(() => hook(req, { signal })).then(
|
|
16026
16661
|
(reply2) => isRecord(reply2) ? reply2 : errorReply("EIO", "the vault gave no reply"),
|
|
16027
|
-
(err) => errorReply("EIO",
|
|
16662
|
+
(err) => errorReply("EIO", lineOf3(err))
|
|
16028
16663
|
);
|
|
16029
16664
|
const reply = await Promise.race([asked, stopped]);
|
|
16030
16665
|
if (!signal.aborted) return reply;
|
|
@@ -17141,13 +17776,13 @@ var PgServer = class {
|
|
|
17141
17776
|
at += whole;
|
|
17142
17777
|
}
|
|
17143
17778
|
this.buffer = data.slice(at);
|
|
17144
|
-
const
|
|
17779
|
+
const joined5 = new Uint8Array(out.reduce((n, b) => n + b.length, 0));
|
|
17145
17780
|
let to = 0;
|
|
17146
17781
|
for (const b of out) {
|
|
17147
|
-
|
|
17782
|
+
joined5.set(b, to);
|
|
17148
17783
|
to += b.length;
|
|
17149
17784
|
}
|
|
17150
|
-
return
|
|
17785
|
+
return joined5;
|
|
17151
17786
|
}
|
|
17152
17787
|
};
|
|
17153
17788
|
function frame3(type, body) {
|
|
@@ -17370,7 +18005,7 @@ function latin12(bytes) {
|
|
|
17370
18005
|
for (const b of bytes) out += String.fromCharCode(b);
|
|
17371
18006
|
return out;
|
|
17372
18007
|
}
|
|
17373
|
-
function
|
|
18008
|
+
function bytesOf2(text) {
|
|
17374
18009
|
const out = new Uint8Array(text.length);
|
|
17375
18010
|
for (let i = 0; i < text.length; i++) out[i] = text.charCodeAt(i);
|
|
17376
18011
|
return out;
|
|
@@ -17489,12 +18124,12 @@ var SessionWriter = class {
|
|
|
17489
18124
|
if (this.failed !== void 0) throw this.failed;
|
|
17490
18125
|
if (this.mode === "pass") return this.conn.write(bytes);
|
|
17491
18126
|
clearTimeout(this.timer);
|
|
17492
|
-
const
|
|
17493
|
-
|
|
17494
|
-
|
|
18127
|
+
const joined5 = new Uint8Array(this.buffer.length + bytes.length);
|
|
18128
|
+
joined5.set(this.buffer);
|
|
18129
|
+
joined5.set(bytes, this.buffer.length);
|
|
17495
18130
|
this.buffer.fill(0);
|
|
17496
|
-
this.buffer =
|
|
17497
|
-
if (this.mode === "sniff") this.mode = modeOf(latin12(
|
|
18131
|
+
this.buffer = joined5;
|
|
18132
|
+
if (this.mode === "sniff") this.mode = modeOf(latin12(joined5.subarray(0, 8))) ?? "sniff";
|
|
17498
18133
|
if (this.mode === "pg" && !this.sawPg) {
|
|
17499
18134
|
this.sawPg = true;
|
|
17500
18135
|
if (!this.s.verified) void this.proof("pg");
|
|
@@ -17522,7 +18157,7 @@ var SessionWriter = class {
|
|
|
17522
18157
|
const out = await this.smtp.line(latin12(all.subarray(0, at))).catch(() => ({ line: latin12(all.subarray(0, at)) }));
|
|
17523
18158
|
all.fill(0);
|
|
17524
18159
|
if ("values" in out && out.values) this.remember(out.values);
|
|
17525
|
-
const line =
|
|
18160
|
+
const line = bytesOf2(`${out.line}\r
|
|
17526
18161
|
`);
|
|
17527
18162
|
try {
|
|
17528
18163
|
await writeAll3(this.conn, line);
|
|
@@ -17579,7 +18214,7 @@ var SessionWriter = class {
|
|
|
17579
18214
|
latin12(all.subarray(0, end)),
|
|
17580
18215
|
(position, placeholders, head2) => this.ask("http1", position, { placeholders, head: head2 })
|
|
17581
18216
|
).catch(() => void 0);
|
|
17582
|
-
const head = done4 ?
|
|
18217
|
+
const head = done4 ? bytesOf2(done4.head) : all.subarray(0, end);
|
|
17583
18218
|
if (done4) this.remember(done4.values);
|
|
17584
18219
|
try {
|
|
17585
18220
|
await writeAll3(this.conn, head);
|
|
@@ -17642,7 +18277,7 @@ var ScrubReader = class {
|
|
|
17642
18277
|
const before = this.current();
|
|
17643
18278
|
const out = this.through(got);
|
|
17644
18279
|
if (before.length === 0 && out !== void 0) return out;
|
|
17645
|
-
if (before.length > 0) return
|
|
18280
|
+
if (before.length > 0) return joined3(before, out);
|
|
17646
18281
|
}
|
|
17647
18282
|
}
|
|
17648
18283
|
through(got) {
|
|
@@ -17658,7 +18293,7 @@ var ScrubReader = class {
|
|
|
17658
18293
|
return out.length > 0 ? out : void 0;
|
|
17659
18294
|
}
|
|
17660
18295
|
};
|
|
17661
|
-
function
|
|
18296
|
+
function joined3(a, b) {
|
|
17662
18297
|
if (!b) return a;
|
|
17663
18298
|
const out = new Uint8Array(a.length + b.length);
|
|
17664
18299
|
out.set(a);
|
|
@@ -18566,7 +19201,7 @@ async function connect(req, proc) {
|
|
|
18566
19201
|
dialing?.catch(() => void 0);
|
|
18567
19202
|
throw new KernelError("EINPROGRESS");
|
|
18568
19203
|
}
|
|
18569
|
-
if (dialing !== void 0) await
|
|
19204
|
+
if (dialing !== void 0) await interruptible3(dialing, proc.blocking());
|
|
18570
19205
|
return ok3();
|
|
18571
19206
|
}
|
|
18572
19207
|
async function bindUnixDgram(proc, socket, addr) {
|
|
@@ -18631,7 +19266,7 @@ async function unixDatagram(req, dgram, proc) {
|
|
|
18631
19266
|
function domainOf(socket) {
|
|
18632
19267
|
return socket instanceof UnixDgram ? "unix" : "inet";
|
|
18633
19268
|
}
|
|
18634
|
-
function
|
|
19269
|
+
function interruptible3(dialing, signal) {
|
|
18635
19270
|
return new Promise((resolve2, reject) => {
|
|
18636
19271
|
const abort = () => reject(new KernelError("EINTR"));
|
|
18637
19272
|
signal.addEventListener("abort", abort, { once: true });
|
|
@@ -19635,7 +20270,7 @@ var ProcessWatches = class {
|
|
|
19635
20270
|
};
|
|
19636
20271
|
|
|
19637
20272
|
// src/kernel/process.ts
|
|
19638
|
-
function
|
|
20273
|
+
function aborted2(signal) {
|
|
19639
20274
|
return new Promise((_, reject) => {
|
|
19640
20275
|
signal.addEventListener("abort", () => reject(new KernelError("EINTR")), { once: true });
|
|
19641
20276
|
});
|
|
@@ -19725,6 +20360,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
19725
20360
|
"fd-open-sealed",
|
|
19726
20361
|
"fd-open-clipboard",
|
|
19727
20362
|
"fd-clipboard-abort",
|
|
20363
|
+
"fd-open-embedder",
|
|
19728
20364
|
"tty-get",
|
|
19729
20365
|
"tty-set",
|
|
19730
20366
|
"tty-winsz",
|
|
@@ -20278,6 +20914,7 @@ var WasmProcess = class {
|
|
|
20278
20914
|
if (!read) throw new KernelError(req.peek && file.read ? "EOPNOTSUPP" : "EBADF");
|
|
20279
20915
|
if (file.tty) this.checkForeground(file.tty);
|
|
20280
20916
|
if (file.clipboard) return this.readClipboard(file.clipboard, req, cancelled);
|
|
20917
|
+
if (file.embedder) return this.readEmbedder(file, req, cancelled);
|
|
20281
20918
|
if (file instanceof EventFd && req.max < EventFd.SIZE) throw new KernelError("EINVAL");
|
|
20282
20919
|
if (req.max <= 0) return new Uint8Array(0);
|
|
20283
20920
|
if (file instanceof KernelSocket && file.unconnected) throw new KernelError("ENOTCONN");
|
|
@@ -20298,6 +20935,81 @@ var WasmProcess = class {
|
|
|
20298
20935
|
throw err;
|
|
20299
20936
|
}
|
|
20300
20937
|
}
|
|
20938
|
+
async readEmbedder(file, req, cancelled) {
|
|
20939
|
+
const channel = file.embedder;
|
|
20940
|
+
if (req.max <= 0) return new Uint8Array(0);
|
|
20941
|
+
channel.caller = await this.embedderCaller();
|
|
20942
|
+
try {
|
|
20943
|
+
return await channel.read(Math.min(req.max, MAX_READ), this.blockingSignal(cancelled));
|
|
20944
|
+
} catch (err) {
|
|
20945
|
+
await this.deviceComplaint(EMBEDDER_PATH, err);
|
|
20946
|
+
throw err;
|
|
20947
|
+
}
|
|
20948
|
+
}
|
|
20949
|
+
async writeEmbedder(file, body, nonblock, cancelled) {
|
|
20950
|
+
const channel = file.embedder;
|
|
20951
|
+
channel.caller = await this.embedderCaller();
|
|
20952
|
+
const write = file.write;
|
|
20953
|
+
if (!pollFile(file).writable && nonblock) throw new KernelError("EAGAIN");
|
|
20954
|
+
try {
|
|
20955
|
+
return await write.call(file, body, this.blockingSignal(cancelled));
|
|
20956
|
+
} catch (err) {
|
|
20957
|
+
await this.deviceComplaint(EMBEDDER_PATH, err);
|
|
20958
|
+
throw err;
|
|
20959
|
+
}
|
|
20960
|
+
}
|
|
20961
|
+
async deviceComplaint(path, err) {
|
|
20962
|
+
const name2 = this.options.clipboardName;
|
|
20963
|
+
if (name2 === void 0 || !(err instanceof KernelError) || err.detail === void 0) return;
|
|
20964
|
+
if (err.code === "EINTR") return;
|
|
20965
|
+
await this.complainLine(`${name2}: ${path}: ${clipboardLine(err.detail)}`);
|
|
20966
|
+
}
|
|
20967
|
+
async complainLine(line) {
|
|
20968
|
+
const stderr = this.fds.has(2) ? this.fds.get(2).file : void 0;
|
|
20969
|
+
if (!stderr?.write || stderr.clipboard || stderr.embedder || stderr.sealed) return;
|
|
20970
|
+
const timeout = new Promise((r) => setTimeout(() => r(0), 1e3));
|
|
20971
|
+
await Promise.race([
|
|
20972
|
+
stderr.write(new TextEncoder().encode(`${line}
|
|
20973
|
+
`), AbortSignal.timeout(1e3)).catch(() => 0),
|
|
20974
|
+
timeout
|
|
20975
|
+
]);
|
|
20976
|
+
}
|
|
20977
|
+
async embedderCaller() {
|
|
20978
|
+
const shown = await this.options.identity?.();
|
|
20979
|
+
const session = this.options.embedderSession?.() ?? { client: 0, uid: 0 };
|
|
20980
|
+
const name2 = this.options.clipboardName ?? this.options.embedderName ?? "program";
|
|
20981
|
+
return {
|
|
20982
|
+
pid: this.pid,
|
|
20983
|
+
shownPid: shown?.pid ?? this.pid,
|
|
20984
|
+
euid: this.cred.euid,
|
|
20985
|
+
egid: this.cred.egid,
|
|
20986
|
+
groups: [...this.cred.groups],
|
|
20987
|
+
sessionUid: session.uid,
|
|
20988
|
+
client: session.client,
|
|
20989
|
+
tags: this.options.embedder?.tagsOf(this.pid),
|
|
20990
|
+
progress: (line) => void this.complainLine(`${name2}: ${line}`),
|
|
20991
|
+
closing: () => AbortSignal.any([this.interrupt.signal, this.gone.signal])
|
|
20992
|
+
};
|
|
20993
|
+
}
|
|
20994
|
+
async closeFd(fd) {
|
|
20995
|
+
this.options.locks?.closed(this.pid, fd);
|
|
20996
|
+
await this.dropRecordLocks(fd);
|
|
20997
|
+
const closing2 = this.fds.get(fd).file;
|
|
20998
|
+
const channel = closing2.clipboard;
|
|
20999
|
+
if (channel) channel.stamp = await this.clipboardStamp();
|
|
21000
|
+
if (closing2.embedder) closing2.embedder.caller = await this.embedderCaller();
|
|
21001
|
+
await Promise.resolve(this.fds.close(fd)).catch(async (err) => {
|
|
21002
|
+
if (channel) await this.clipboardComplaint(err);
|
|
21003
|
+
if (closing2.embedder) await this.deviceComplaint(EMBEDDER_PATH, err);
|
|
21004
|
+
throw err;
|
|
21005
|
+
});
|
|
21006
|
+
}
|
|
21007
|
+
async openEmbedder(flags2) {
|
|
21008
|
+
const broker = this.options.embedder;
|
|
21009
|
+
if (!broker) throw new KernelError("ENOENT");
|
|
21010
|
+
const file = broker.channel(openAccess(flags2), await this.embedderCaller());
|
|
21011
|
+
return this.fds.install(this.options.outputFilter?.(file) ?? file, 3);
|
|
21012
|
+
}
|
|
20301
21013
|
async complain(line) {
|
|
20302
21014
|
const stderr = this.fds.has(2) ? this.fds.get(2).file : void 0;
|
|
20303
21015
|
if (!stderr?.write || stderr.sealed || stderr.clipboard) return false;
|
|
@@ -20328,6 +21040,7 @@ var WasmProcess = class {
|
|
|
20328
21040
|
const file = this.fds.get(fd).file;
|
|
20329
21041
|
if (file.sealed) return file.sealed.send(body, await this.sealedCaller(), this.gone.signal);
|
|
20330
21042
|
if (!file.write) throw new KernelError("EBADF");
|
|
21043
|
+
if (file.embedder) return this.writeEmbedder(file, body, nonblock, cancelled);
|
|
20331
21044
|
if (!pollFile(file).writable) {
|
|
20332
21045
|
if (nonblock) throw new KernelError("EAGAIN");
|
|
20333
21046
|
return file.write(body, this.blockingSignal(cancelled));
|
|
@@ -20375,11 +21088,11 @@ var WasmProcess = class {
|
|
|
20375
21088
|
} else if (req.create) {
|
|
20376
21089
|
await nodes.onEntry(path, async () => {
|
|
20377
21090
|
const marks = this.options.owners || plain3 !== void 0;
|
|
20378
|
-
const
|
|
21091
|
+
const fresh3 = marks && !await present3(fs, path, true);
|
|
20379
21092
|
this.fds.installAt(fd, this.openVfsFile(open, await nodes.identify(path), fs));
|
|
20380
21093
|
await this.fds.get(fd).file.stat?.();
|
|
20381
|
-
if (
|
|
20382
|
-
else if (
|
|
21094
|
+
if (fresh3 && plain3 !== void 0) await fs.chmod?.(path, plain3);
|
|
21095
|
+
else if (fresh3) {
|
|
20383
21096
|
await fs.chown?.(path, { ...this.newOwner(req.mode), kind: "new" });
|
|
20384
21097
|
}
|
|
20385
21098
|
});
|
|
@@ -20597,17 +21310,9 @@ var WasmProcess = class {
|
|
|
20597
21310
|
kind: "json",
|
|
20598
21311
|
json: await this.write(req.fd, req.body, req.nonblock, cancelled)
|
|
20599
21312
|
};
|
|
20600
|
-
case "fd-close":
|
|
20601
|
-
this.
|
|
20602
|
-
await this.dropRecordLocks(req.fd);
|
|
20603
|
-
const channel = this.fds.get(req.fd).file.clipboard;
|
|
20604
|
-
if (channel) channel.stamp = await this.clipboardStamp();
|
|
20605
|
-
await Promise.resolve(this.fds.close(req.fd)).catch(async (err) => {
|
|
20606
|
-
if (channel) await this.clipboardComplaint(err);
|
|
20607
|
-
throw err;
|
|
20608
|
-
});
|
|
21313
|
+
case "fd-close":
|
|
21314
|
+
await this.closeFd(req.fd);
|
|
20609
21315
|
return { ok: true, kind: "void" };
|
|
20610
|
-
}
|
|
20611
21316
|
case "fd-pipe": {
|
|
20612
21317
|
const pipe = openPipe();
|
|
20613
21318
|
const read = this.fds.install(pipe.read, 3);
|
|
@@ -20667,6 +21372,8 @@ var WasmProcess = class {
|
|
|
20667
21372
|
return { ok: true, kind: "json", json: this.openSealed(req.flags) };
|
|
20668
21373
|
case "fd-open-clipboard":
|
|
20669
21374
|
return { ok: true, kind: "json", json: await this.openClipboard(req.flags) };
|
|
21375
|
+
case "fd-open-embedder":
|
|
21376
|
+
return { ok: true, kind: "json", json: await this.openEmbedder(req.flags) };
|
|
20670
21377
|
case "fd-clipboard-abort": {
|
|
20671
21378
|
const file = this.fds.get(req.fd);
|
|
20672
21379
|
file.file.clipboard?.abort();
|
|
@@ -21161,7 +21868,7 @@ var WasmProcess = class {
|
|
|
21161
21868
|
else {
|
|
21162
21869
|
const { source, target, type, flags: flags2, data } = req;
|
|
21163
21870
|
const signal = this.blockingSignal(cancelled);
|
|
21164
|
-
await Promise.race([mount({ source, target, type, flags: flags2, data }, signal),
|
|
21871
|
+
await Promise.race([mount({ source, target, type, flags: flags2, data }, signal), aborted2(signal)]);
|
|
21165
21872
|
}
|
|
21166
21873
|
} catch (err) {
|
|
21167
21874
|
const code = err?.code;
|
|
@@ -21171,7 +21878,7 @@ var WasmProcess = class {
|
|
|
21171
21878
|
return { ok: true, kind: "void" };
|
|
21172
21879
|
}
|
|
21173
21880
|
pause(cancelled) {
|
|
21174
|
-
return
|
|
21881
|
+
return aborted2(this.blockingSignal(cancelled));
|
|
21175
21882
|
}
|
|
21176
21883
|
alarm;
|
|
21177
21884
|
dlLog = [];
|
|
@@ -21707,6 +22414,7 @@ function holdingToken(opts, holds2, caller) {
|
|
|
21707
22414
|
boundIno: holds2.boundIno.bind(holds2),
|
|
21708
22415
|
trust: holds2.trust.bind(holds2),
|
|
21709
22416
|
keptFor: (handle) => holds2.keptFor(handle),
|
|
22417
|
+
heldAt: (handle) => holds2.pathOf(handle),
|
|
21710
22418
|
unlinked: (path) => holds2.keptAt(path),
|
|
21711
22419
|
gate: (path, op) => opts.unlinkGate && holds2.holding(path) ? opts.unlinkGate.run(holds2.keyOf(path), op) : op(),
|
|
21712
22420
|
own: (path, op) => holds2.own(path, op),
|
|
@@ -21720,6 +22428,15 @@ function linksOf(opts) {
|
|
|
21720
22428
|
function clipboardName(opts) {
|
|
21721
22429
|
return opts.program.abi === "js" ? {} : { clipboardName: opts.argv0 };
|
|
21722
22430
|
}
|
|
22431
|
+
function embedderOptions(opts) {
|
|
22432
|
+
if (!opts.embedder) return {};
|
|
22433
|
+
return {
|
|
22434
|
+
embedder: opts.embedder.broker,
|
|
22435
|
+
embedderSession: opts.embedder.session,
|
|
22436
|
+
embedderName: opts.argv0,
|
|
22437
|
+
...clipboardName(opts)
|
|
22438
|
+
};
|
|
22439
|
+
}
|
|
21723
22440
|
function processOptions(opts, header5, hooks, created4) {
|
|
21724
22441
|
return {
|
|
21725
22442
|
...inherited(opts),
|
|
@@ -21727,6 +22444,7 @@ function processOptions(opts, header5, hooks, created4) {
|
|
|
21727
22444
|
...opts.sealed ? { sealed: opts.sealed } : {},
|
|
21728
22445
|
...opts.outputFilter ? { outputFilter: opts.outputFilter } : {},
|
|
21729
22446
|
...opts.clipboard ? { clipboard: opts.clipboard, ...clipboardName(opts) } : {},
|
|
22447
|
+
...embedderOptions(opts),
|
|
21730
22448
|
...opts.readonlyAt ? { readonlyAt: opts.readonlyAt } : {},
|
|
21731
22449
|
...opts.source ? { source: opts.source } : {},
|
|
21732
22450
|
noLinks: opts.noLinks,
|
|
@@ -24475,9 +25193,9 @@ var OpfsFs = class {
|
|
|
24475
25193
|
this.lookups++;
|
|
24476
25194
|
if (split2(path).length === 0) return this.root;
|
|
24477
25195
|
const cached = this.files.get(path);
|
|
24478
|
-
const
|
|
24479
|
-
if (cached && !
|
|
24480
|
-
if (cached &&
|
|
25196
|
+
const fresh3 = cached && performance.now() - (this.found.get(cached) ?? -CHECK_MS) < CHECK_MS;
|
|
25197
|
+
if (cached && !fresh3) this.files.delete(path);
|
|
25198
|
+
if (cached && fresh3) {
|
|
24481
25199
|
if (this.glanced(cached)) return this.remember(path, cached);
|
|
24482
25200
|
try {
|
|
24483
25201
|
await this.glance(cached);
|
|
@@ -24695,8 +25413,8 @@ var OpfsFs = class {
|
|
|
24695
25413
|
glanced(handle) {
|
|
24696
25414
|
if (this.exact > 0) return void 0;
|
|
24697
25415
|
const seen = this.glances.get(handle);
|
|
24698
|
-
const
|
|
24699
|
-
return
|
|
25416
|
+
const fresh3 = seen && seen.changes === this.changes && this.recent(seen, GLANCE_LOOKUPS);
|
|
25417
|
+
return fresh3 ? seen.file : void 0;
|
|
24700
25418
|
}
|
|
24701
25419
|
async glance(handle) {
|
|
24702
25420
|
const at = performance.now();
|
|
@@ -24886,13 +25604,13 @@ var OpfsFs = class {
|
|
|
24886
25604
|
async keptFor(path) {
|
|
24887
25605
|
const at = normalizePath(path);
|
|
24888
25606
|
const cached = this.files.get(at);
|
|
24889
|
-
const
|
|
24890
|
-
const [target, existed] =
|
|
25607
|
+
const fresh3 = cached && performance.now() - (this.found.get(cached) ?? -CHECK_MS) < CHECK_MS;
|
|
25608
|
+
const [target, existed] = fresh3 ? [at, true] : await this.writeTarget(path);
|
|
24891
25609
|
if (!existed) return [void 0, target, false];
|
|
24892
25610
|
this.refuse(target);
|
|
24893
25611
|
const [entry] = await this.meta.get([target]);
|
|
24894
25612
|
if (entry?.fifo || entry?.socket) throw fsError("ENXIO", path);
|
|
24895
|
-
const kept =
|
|
25613
|
+
const kept = fresh3 ? cached : this.files.get(target);
|
|
24896
25614
|
const usable2 = kept && performance.now() - (this.found.get(kept) ?? -CHECK_MS) < CHECK_MS;
|
|
24897
25615
|
return [usable2 ? kept : void 0, target, true];
|
|
24898
25616
|
}
|
|
@@ -26607,14 +27325,14 @@ var RESTORE_AGAIN_MS = 3e4;
|
|
|
26607
27325
|
function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
26608
27326
|
const handles = /* @__PURE__ */ new Map();
|
|
26609
27327
|
let nextFh = 0;
|
|
26610
|
-
const
|
|
27328
|
+
const fresh3 = (remote) => {
|
|
26611
27329
|
if (remote.client.token === remote.token && !remote.client.gone) return remote;
|
|
26612
27330
|
throw fsError2("ESTALE", "the folder was granted again, so this open file is gone");
|
|
26613
27331
|
};
|
|
26614
27332
|
const live = (fh) => {
|
|
26615
27333
|
const remote = handles.get(fh);
|
|
26616
27334
|
if (!remote) throw fsError2("EBADF", `handle ${fh}`);
|
|
26617
|
-
return
|
|
27335
|
+
return fresh3(remote);
|
|
26618
27336
|
};
|
|
26619
27337
|
const call = (op, body = {}) => current().call(op, body);
|
|
26620
27338
|
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);
|
|
@@ -26696,7 +27414,7 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
|
26696
27414
|
if (!remote) throw fsError2("EBADF", `handle ${fh}`);
|
|
26697
27415
|
handles.delete(fh);
|
|
26698
27416
|
try {
|
|
26699
|
-
await
|
|
27417
|
+
await fresh3(remote).client.call("release", { fh: remote.fh }, true);
|
|
26700
27418
|
} finally {
|
|
26701
27419
|
if (remote.restore) await settle(current(), remote.restore);
|
|
26702
27420
|
}
|
|
@@ -27060,7 +27778,7 @@ var PortTransport = class {
|
|
|
27060
27778
|
}).finally(() => this.fail("the folder's watch ended"));
|
|
27061
27779
|
}
|
|
27062
27780
|
};
|
|
27063
|
-
var
|
|
27781
|
+
var errorOf2 = (err) => ({
|
|
27064
27782
|
code: typeof codeOf7(err) === "string" ? codeOf7(err) : "EIO",
|
|
27065
27783
|
message: err?.message ?? String(err)
|
|
27066
27784
|
});
|
|
@@ -27110,7 +27828,7 @@ function serveHostfsPort(port, transport) {
|
|
|
27110
27828
|
);
|
|
27111
27829
|
send2({ id: id2, end: true });
|
|
27112
27830
|
} catch (err) {
|
|
27113
|
-
send2({ id: id2, error:
|
|
27831
|
+
send2({ id: id2, error: errorOf2(err) });
|
|
27114
27832
|
} finally {
|
|
27115
27833
|
watches.delete(id2);
|
|
27116
27834
|
}
|
|
@@ -27138,7 +27856,7 @@ function serveHostfsPort(port, transport) {
|
|
|
27138
27856
|
if (op !== "call") throw fsError2("EINVAL", `unknown hostfs port op ${op}`);
|
|
27139
27857
|
send2({ id: id2, result: await answer2(data.name, data.body) });
|
|
27140
27858
|
} catch (err) {
|
|
27141
|
-
send2({ id: id2, error:
|
|
27859
|
+
send2({ id: id2, error: errorOf2(err) });
|
|
27142
27860
|
}
|
|
27143
27861
|
};
|
|
27144
27862
|
const stop = () => {
|
|
@@ -27771,7 +28489,7 @@ function homeModeOf(mode) {
|
|
|
27771
28489
|
}
|
|
27772
28490
|
return mode;
|
|
27773
28491
|
}
|
|
27774
|
-
function
|
|
28492
|
+
function joined4(name2, rows) {
|
|
27775
28493
|
let changed = false;
|
|
27776
28494
|
for (const g of rows) {
|
|
27777
28495
|
if (g.members.includes(name2)) continue;
|
|
@@ -27958,7 +28676,7 @@ var UserDb = class {
|
|
|
27958
28676
|
await this.provision(found, this.umaskFor(options), shared);
|
|
27959
28677
|
await this.stampHome(found, shared, homeMode);
|
|
27960
28678
|
}
|
|
27961
|
-
if (
|
|
28679
|
+
if (joined4(name2, more)) await this.fs.writeFile(GROUP, formatGroup(group));
|
|
27962
28680
|
remember();
|
|
27963
28681
|
return this.account(found, groups);
|
|
27964
28682
|
}
|
|
@@ -27967,10 +28685,10 @@ var UserDb = class {
|
|
|
27967
28685
|
if (groups.some((r) => r.name === name2)) throw fsError("EEXIST", `group ${name2} exists`);
|
|
27968
28686
|
const uid = freeId(users, groups);
|
|
27969
28687
|
const row = { name: name2, uid, gid: uid, gecos: name2, home, shell: "/bin/bash" };
|
|
27970
|
-
|
|
28688
|
+
joined4(name2, extra);
|
|
27971
28689
|
group.push({ name: name2, gid: uid, members: [] });
|
|
27972
28690
|
passwd.push(row);
|
|
27973
|
-
const
|
|
28691
|
+
const fresh3 = !await this.fs.exists(home);
|
|
27974
28692
|
await this.fs.mkdir(home, { recursive: true });
|
|
27975
28693
|
try {
|
|
27976
28694
|
await this.provision(row, this.umaskFor(options), shared);
|
|
@@ -27978,7 +28696,7 @@ var UserDb = class {
|
|
|
27978
28696
|
await this.fs.mkdir("/etc", { recursive: true });
|
|
27979
28697
|
await this.commit(formatPasswd(passwd), formatGroup(group));
|
|
27980
28698
|
} catch (err) {
|
|
27981
|
-
if (
|
|
28699
|
+
if (fresh3) await this.fs.rm(home, { recursive: true, force: true });
|
|
27982
28700
|
throw err;
|
|
27983
28701
|
}
|
|
27984
28702
|
remember();
|
|
@@ -28356,12 +29074,12 @@ ${lines2}
|
|
|
28356
29074
|
const timer = setTimeout(() => control.abort("expired"), timeout);
|
|
28357
29075
|
const withdraw = () => control.abort("withdrawn");
|
|
28358
29076
|
requester.addEventListener("abort", withdraw, { once: true });
|
|
28359
|
-
const
|
|
29077
|
+
const aborted3 = new Promise(
|
|
28360
29078
|
(resolve2) => control.signal.addEventListener("abort", () => resolve2("aborted"), { once: true })
|
|
28361
29079
|
);
|
|
28362
29080
|
try {
|
|
28363
29081
|
const answered = Promise.resolve().then(() => approve(req, { signal: control.signal })).catch(() => "deny");
|
|
28364
|
-
const answer2 = await Promise.race([answered,
|
|
29082
|
+
const answer2 = await Promise.race([answered, aborted3]);
|
|
28365
29083
|
if (answer2 === "aborted" || control.signal.aborted) {
|
|
28366
29084
|
return control.signal.reason === "expired" ? failed2("ETIMEDOUT", "sudo: the request expired") : failed2("EINTR", "sudo: the request was withdrawn");
|
|
28367
29085
|
}
|
|
@@ -28487,6 +29205,7 @@ var SUDO_SOURCE = [
|
|
|
28487
29205
|
].join("\n");
|
|
28488
29206
|
|
|
28489
29207
|
// src/launcher.ts
|
|
29208
|
+
var NO_SESSION = { client: -1, uid: -1 };
|
|
28490
29209
|
var MODULE_URLS = 16;
|
|
28491
29210
|
function dataModuleUrl(source) {
|
|
28492
29211
|
const bytes = new TextEncoder().encode(source);
|
|
@@ -28745,6 +29464,7 @@ var Launcher = class {
|
|
|
28745
29464
|
described = /* @__PURE__ */ new Map();
|
|
28746
29465
|
creds = /* @__PURE__ */ new Map();
|
|
28747
29466
|
tags = /* @__PURE__ */ new Map();
|
|
29467
|
+
sessions = /* @__PURE__ */ new Map();
|
|
28748
29468
|
tagBases = /* @__PURE__ */ new Map();
|
|
28749
29469
|
links = /* @__PURE__ */ new Map();
|
|
28750
29470
|
freshModules = new FreshModules();
|
|
@@ -28805,6 +29525,7 @@ var Launcher = class {
|
|
|
28805
29525
|
sealed;
|
|
28806
29526
|
scrubs = /* @__PURE__ */ new Map();
|
|
28807
29527
|
clipboard;
|
|
29528
|
+
embedder;
|
|
28808
29529
|
rootFs;
|
|
28809
29530
|
fileWatches;
|
|
28810
29531
|
nextPid = 1e3;
|
|
@@ -28826,14 +29547,14 @@ var Launcher = class {
|
|
|
28826
29547
|
void 0,
|
|
28827
29548
|
(pid) => this.tagsOf(pid)
|
|
28828
29549
|
);
|
|
29550
|
+
this.embedder = this.embedderBroker(options.embedder);
|
|
28829
29551
|
this.sealed = new SealedBroker(
|
|
28830
29552
|
options.sealed,
|
|
28831
29553
|
this.usersMode,
|
|
28832
29554
|
void 0,
|
|
28833
29555
|
(pid) => this.tagsOf(pid)
|
|
28834
29556
|
);
|
|
28835
|
-
this.
|
|
28836
|
-
this.sealed.userOf = async (uid) => (await this.users.lookup(uid))?.name;
|
|
29557
|
+
this.wireSealed();
|
|
28837
29558
|
if (this.owners) options.fs.trackOwners?.();
|
|
28838
29559
|
this.watchers.tap((paths) => {
|
|
28839
29560
|
this.changes.publish(...paths);
|
|
@@ -29894,6 +30615,8 @@ var Launcher = class {
|
|
|
29894
30615
|
}
|
|
29895
30616
|
marks(pid, req) {
|
|
29896
30617
|
if (req.tags?.length) this.tags.set(pid, req.tags);
|
|
30618
|
+
const session = req.session ?? this.sessions.get(req.ppid ?? -1);
|
|
30619
|
+
if (session) this.sessions.set(pid, session);
|
|
29897
30620
|
if (req.tags?.length) this.tagBases.set(pid, req.tagBase ?? req.tags.length);
|
|
29898
30621
|
if (req.links !== void 0) this.links.set(pid, req.links);
|
|
29899
30622
|
}
|
|
@@ -29973,6 +30696,7 @@ var Launcher = class {
|
|
|
29973
30696
|
sealed: this.sealed,
|
|
29974
30697
|
...scrubs ? { outputFilter: (file) => scrubbedAll(file, scrubs) } : {},
|
|
29975
30698
|
clipboard: this.clipboard,
|
|
30699
|
+
embedder: { broker: this.embedder, session: () => this.sessionOf(pid) },
|
|
29976
30700
|
...this.dac ? { dac: this.dac } : {},
|
|
29977
30701
|
program: req.program,
|
|
29978
30702
|
changes: this.changes.sab,
|
|
@@ -30101,6 +30825,7 @@ var Launcher = class {
|
|
|
30101
30825
|
this.childTimes.delete(pid);
|
|
30102
30826
|
this.creds.delete(pid);
|
|
30103
30827
|
this.tags.delete(pid);
|
|
30828
|
+
this.sessions.delete(pid);
|
|
30104
30829
|
this.tagBases.delete(pid);
|
|
30105
30830
|
this.links.delete(pid);
|
|
30106
30831
|
this.granted.delete(pid);
|
|
@@ -30146,8 +30871,8 @@ var Launcher = class {
|
|
|
30146
30871
|
this.sampledAt = Math.max(this.sampledAt, now);
|
|
30147
30872
|
this.load = this.load.map((avg, i) => {
|
|
30148
30873
|
const window = LOAD_WINDOWS_MS[i];
|
|
30149
|
-
const
|
|
30150
|
-
return avg * Math.exp(-elapsed / window) + running *
|
|
30874
|
+
const fresh3 = 1 - Math.exp(-LOAD_SAMPLE_MS / window);
|
|
30875
|
+
return avg * Math.exp(-elapsed / window) + running * fresh3;
|
|
30151
30876
|
});
|
|
30152
30877
|
}
|
|
30153
30878
|
idleSince;
|
|
@@ -30377,7 +31102,7 @@ var Launcher = class {
|
|
|
30377
31102
|
forker(ppid, parent) {
|
|
30378
31103
|
const { exec: _exec, pgid: _pgid, group: _group, pid: _pid, scrub: _scrub, ...image } = parent;
|
|
30379
31104
|
return async (state, given) => {
|
|
30380
|
-
const
|
|
31105
|
+
const fresh3 = (fds, quietOom) => this.start({
|
|
30381
31106
|
...image,
|
|
30382
31107
|
quietOom,
|
|
30383
31108
|
cwd: state.cwd ?? parent.cwd,
|
|
@@ -30393,7 +31118,7 @@ var Launcher = class {
|
|
|
30393
31118
|
tagBase: this.tagBases.get(ppid),
|
|
30394
31119
|
links: this.links.get(ppid)
|
|
30395
31120
|
});
|
|
30396
|
-
return childHandle(await this.admitted(parent.program.abi !== "js", given,
|
|
31121
|
+
return childHandle(await this.admitted(parent.program.abi !== "js", given, fresh3));
|
|
30397
31122
|
};
|
|
30398
31123
|
}
|
|
30399
31124
|
keySignal(tty, fallback, sig, send2) {
|
|
@@ -30429,6 +31154,25 @@ var Launcher = class {
|
|
|
30429
31154
|
credOf(pid) {
|
|
30430
31155
|
return this.creds.get(pid)?.() ?? copyCred(ROOT);
|
|
30431
31156
|
}
|
|
31157
|
+
wireSealed() {
|
|
31158
|
+
this.sealed.tickets.normalise = (path) => physicalPathAsync(this.base, path);
|
|
31159
|
+
this.sealed.userOf = async (uid) => (await this.users.lookup(uid))?.name;
|
|
31160
|
+
}
|
|
31161
|
+
embedderBroker(hook) {
|
|
31162
|
+
const broker = new EmbedderBroker(
|
|
31163
|
+
this.usersMode,
|
|
31164
|
+
{
|
|
31165
|
+
groupId: async (name2) => (await this.users.groups()).find((g) => g.name === name2)?.gid,
|
|
31166
|
+
userId: async (name2) => (await this.users.lookup(name2))?.uid
|
|
31167
|
+
},
|
|
31168
|
+
(pid) => this.tagsOf(pid)
|
|
31169
|
+
);
|
|
31170
|
+
broker.register(0, hook);
|
|
31171
|
+
return broker;
|
|
31172
|
+
}
|
|
31173
|
+
sessionOf(pid) {
|
|
31174
|
+
return this.sessions.get(pid) ?? NO_SESSION;
|
|
31175
|
+
}
|
|
30432
31176
|
tagOf(pid) {
|
|
30433
31177
|
return this.tags.get(pid)?.[0];
|
|
30434
31178
|
}
|
|
@@ -30700,8 +31444,8 @@ var Launcher = class {
|
|
|
30700
31444
|
for (const [path, mode] of layout) {
|
|
30701
31445
|
if (isProtected(this.prefixes, normalizePath(path))) continue;
|
|
30702
31446
|
const real = await this.realLayoutPath(path);
|
|
30703
|
-
const
|
|
30704
|
-
if (
|
|
31447
|
+
const fresh3 = real !== void 0 && !await this.base.hasOwner?.(real);
|
|
31448
|
+
if (fresh3) await this.base.chown?.(real, { uid: 0, gid: 0, mode, follow: false });
|
|
30705
31449
|
}
|
|
30706
31450
|
}
|
|
30707
31451
|
async realLayoutPath(given) {
|
|
@@ -30874,9 +31618,10 @@ var Launcher = class {
|
|
|
30874
31618
|
if (!found) throw fsError("ENOENT", `no user ${String(user)}`);
|
|
30875
31619
|
return found;
|
|
30876
31620
|
}
|
|
30877
|
-
identity(account, given) {
|
|
31621
|
+
identity(account, given, session = 0) {
|
|
30878
31622
|
return {
|
|
30879
31623
|
...given,
|
|
31624
|
+
session: { client: session, uid: account.uid },
|
|
30880
31625
|
cred: credOf(account),
|
|
30881
31626
|
...account.umask !== void 0 ? { umask: account.umask } : {}
|
|
30882
31627
|
};
|
|
@@ -30996,9 +31741,9 @@ var Launcher = class {
|
|
|
30996
31741
|
}
|
|
30997
31742
|
moved(from, to, source) {
|
|
30998
31743
|
this.renameLog.add(from, to);
|
|
31744
|
+
for (const holds2 of this.held) holds2.renamed(from, to);
|
|
30999
31745
|
if (source) return;
|
|
31000
31746
|
for (const nodes of this.openFiles) nodes.renamed(from, to);
|
|
31001
|
-
for (const holds2 of this.held) holds2.renamed(from, to);
|
|
31002
31747
|
this.watchers.moved(from, to);
|
|
31003
31748
|
}
|
|
31004
31749
|
processChain(fs, nodes, unlinked) {
|
|
@@ -31063,7 +31808,7 @@ var Launcher = class {
|
|
|
31063
31808
|
cwd,
|
|
31064
31809
|
fds,
|
|
31065
31810
|
report,
|
|
31066
|
-
...this.identity(account, tagged)
|
|
31811
|
+
...this.identity(account, tagged, options.session)
|
|
31067
31812
|
});
|
|
31068
31813
|
leader = handle.pid;
|
|
31069
31814
|
void handle.exited.then(() => tty.hangup());
|
|
@@ -31120,7 +31865,7 @@ var Launcher = class {
|
|
|
31120
31865
|
fds,
|
|
31121
31866
|
report,
|
|
31122
31867
|
...group,
|
|
31123
|
-
...this.identity(account, tagged)
|
|
31868
|
+
...this.identity(account, tagged, options.session)
|
|
31124
31869
|
});
|
|
31125
31870
|
options.onStarted?.(handle.pid);
|
|
31126
31871
|
const status = await handle.exited;
|
|
@@ -31563,7 +32308,7 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS3 } = {})
|
|
|
31563
32308
|
}
|
|
31564
32309
|
|
|
31565
32310
|
// src/client/protocol.ts
|
|
31566
|
-
var PROTOCOL = [1,
|
|
32311
|
+
var PROTOCOL = [1, 13];
|
|
31567
32312
|
var FS_METHODS = [
|
|
31568
32313
|
"readFile",
|
|
31569
32314
|
"writeFile",
|
|
@@ -31730,14 +32475,15 @@ async function runAs(l, self, requested) {
|
|
|
31730
32475
|
function clientCred(self) {
|
|
31731
32476
|
return self ? credOf(self) : copyCred(ROOT);
|
|
31732
32477
|
}
|
|
31733
|
-
async function runTagged(l, self, options, tag) {
|
|
32478
|
+
async function runTagged(l, self, options, tag, session = -1) {
|
|
31734
32479
|
tagOption(options.tag);
|
|
31735
32480
|
const tags = withTag(withTag(void 0, tag), options.tag);
|
|
31736
32481
|
return {
|
|
31737
32482
|
user: await runAs(l, self, options.user),
|
|
31738
32483
|
tag,
|
|
31739
32484
|
tags,
|
|
31740
|
-
tagBase: tag === void 0 ? 0 : 1
|
|
32485
|
+
tagBase: tag === void 0 ? 0 : 1,
|
|
32486
|
+
session
|
|
31741
32487
|
};
|
|
31742
32488
|
}
|
|
31743
32489
|
function processes(l, self) {
|
|
@@ -31818,10 +32564,12 @@ function facadeRegistry(send2, gone) {
|
|
|
31818
32564
|
}
|
|
31819
32565
|
};
|
|
31820
32566
|
}
|
|
31821
|
-
function hostRegistries(send2, gone) {
|
|
32567
|
+
function hostRegistries(send2, gone, port) {
|
|
31822
32568
|
const cdps = cdpRegistry(send2, gone);
|
|
31823
32569
|
const facades = facadeRegistry(send2, gone);
|
|
32570
|
+
const requests = requestBinding(send2, port);
|
|
31824
32571
|
return {
|
|
32572
|
+
requests,
|
|
31825
32573
|
answer(l, req) {
|
|
31826
32574
|
if (req.op === "serve-cdp") return cdps.serve(l, req);
|
|
31827
32575
|
if (req.op === "unserve-cdp") return cdps.drop(req.registration);
|
|
@@ -31829,6 +32577,7 @@ function hostRegistries(send2, gone) {
|
|
|
31829
32577
|
return facades.drop(req.registration);
|
|
31830
32578
|
},
|
|
31831
32579
|
close() {
|
|
32580
|
+
requests.close();
|
|
31832
32581
|
cdps.close();
|
|
31833
32582
|
facades.close();
|
|
31834
32583
|
}
|
|
@@ -31863,6 +32612,28 @@ var TRAITS_WATCH = -1;
|
|
|
31863
32612
|
function traitsWatch(launcher, transport, send2) {
|
|
31864
32613
|
return launcher.onTraits(() => send2({ traits: transport.traits }));
|
|
31865
32614
|
}
|
|
32615
|
+
function requestBinding(send2, port) {
|
|
32616
|
+
const asker = embedderAsker({ postMessage: (m, t) => send2(m, t) });
|
|
32617
|
+
let unbind;
|
|
32618
|
+
port.addEventListener("message", (event) => {
|
|
32619
|
+
const reply = embedderReplyOf(event.data);
|
|
32620
|
+
if (reply) asker.answer(reply);
|
|
32621
|
+
});
|
|
32622
|
+
return {
|
|
32623
|
+
async accept(host, hello) {
|
|
32624
|
+
if (!hello.requests) return void 0;
|
|
32625
|
+
if (!host.attachRequests || host.session === void 0)
|
|
32626
|
+
return "EPERM: this port may not answer requests";
|
|
32627
|
+
const launcher = await host.launcher();
|
|
32628
|
+
unbind = launcher.embedder.register(
|
|
32629
|
+
host.session,
|
|
32630
|
+
asker.hookFor(host.session, hello.requests)
|
|
32631
|
+
);
|
|
32632
|
+
return void 0;
|
|
32633
|
+
},
|
|
32634
|
+
close: () => unbind?.()
|
|
32635
|
+
};
|
|
32636
|
+
}
|
|
31866
32637
|
function serveClient(port, host) {
|
|
31867
32638
|
let state = "new";
|
|
31868
32639
|
let self;
|
|
@@ -31877,7 +32648,7 @@ function serveClient(port, host) {
|
|
|
31877
32648
|
if (state !== "closed") port.postMessage(message3, transfer);
|
|
31878
32649
|
};
|
|
31879
32650
|
const reply = (id2, body, transfer) => send2({ id: id2, ...body }, transfer);
|
|
31880
|
-
const hosts = hostRegistries(send2, ended.promise);
|
|
32651
|
+
const hosts = hostRegistries(send2, ended.promise, port);
|
|
31881
32652
|
function detach(kill = false, bye = "the slicc-kernel detached this client") {
|
|
31882
32653
|
if (state === "closed") return;
|
|
31883
32654
|
send2({ bye });
|
|
@@ -31894,7 +32665,7 @@ function serveClient(port, host) {
|
|
|
31894
32665
|
ended.resolve();
|
|
31895
32666
|
}
|
|
31896
32667
|
async function hello(message3) {
|
|
31897
|
-
const refused3 = versionError(message3.protocol);
|
|
32668
|
+
const refused3 = versionError(message3.protocol) ?? await hosts.requests.accept(host, message3);
|
|
31898
32669
|
if (refused3) {
|
|
31899
32670
|
send2({ hello: { protocol: PROTOCOL, error: refused3 } });
|
|
31900
32671
|
detach();
|
|
@@ -31919,7 +32690,7 @@ function serveClient(port, host) {
|
|
|
31919
32690
|
async function terminal(req, l) {
|
|
31920
32691
|
const session = await l.openTerminal(req.argv, {
|
|
31921
32692
|
...req.options,
|
|
31922
|
-
...await runTagged(l, self, req.options, host.tag),
|
|
32693
|
+
...await runTagged(l, self, req.options, host.tag, host.session),
|
|
31923
32694
|
onData: (bytes) => reply(req.id, { fd: 1, bytes: bytes.slice() })
|
|
31924
32695
|
});
|
|
31925
32696
|
if (state === "closed") {
|
|
@@ -31942,7 +32713,7 @@ function serveClient(port, host) {
|
|
|
31942
32713
|
let leader;
|
|
31943
32714
|
const result = await l.run(req.argv, {
|
|
31944
32715
|
...req.options,
|
|
31945
|
-
...await runTagged(l, self, req.options, host.tag),
|
|
32716
|
+
...await runTagged(l, self, req.options, host.tag, host.session),
|
|
31946
32717
|
collect: false,
|
|
31947
32718
|
onStdout: out(1),
|
|
31948
32719
|
onStderr: out(2),
|
|
@@ -32122,11 +32893,11 @@ function guarded2(check, signal) {
|
|
|
32122
32893
|
signal.throwIfAborted();
|
|
32123
32894
|
let stop = () => {
|
|
32124
32895
|
};
|
|
32125
|
-
const
|
|
32896
|
+
const aborted3 = new Promise((_, reject) => {
|
|
32126
32897
|
stop = () => reject(signal.reason);
|
|
32127
32898
|
signal.addEventListener("abort", stop, { once: true });
|
|
32128
32899
|
});
|
|
32129
|
-
return Promise.race([check,
|
|
32900
|
+
return Promise.race([check, aborted3]).finally(() => signal.removeEventListener("abort", stop));
|
|
32130
32901
|
}
|
|
32131
32902
|
var loopbackStore = new AsyncLocalStorage();
|
|
32132
32903
|
var subscribed = false;
|
|
@@ -32241,7 +33012,7 @@ function valid(name2) {
|
|
|
32241
33012
|
}
|
|
32242
33013
|
}
|
|
32243
33014
|
var CHUNK4 = 1024 * 1024;
|
|
32244
|
-
function
|
|
33015
|
+
function bytesOf3(data) {
|
|
32245
33016
|
if (typeof data === "string") return new TextEncoder().encode(data);
|
|
32246
33017
|
if (data instanceof Blob) return data.arrayBuffer().then((buffer) => new Uint8Array(buffer));
|
|
32247
33018
|
if (ArrayBuffer.isView(data)) {
|
|
@@ -32321,7 +33092,7 @@ var MemoryFile = class {
|
|
|
32321
33092
|
const next3 = keepExistingData ? new Chunks([...this.data.blobs], this.data.size) : new Chunks();
|
|
32322
33093
|
let position = 0;
|
|
32323
33094
|
const put = async (data) => {
|
|
32324
|
-
const bytes = await
|
|
33095
|
+
const bytes = await bytesOf3(data);
|
|
32325
33096
|
await next3.write(position, bytes);
|
|
32326
33097
|
position += bytes.length;
|
|
32327
33098
|
};
|
|
@@ -32453,11 +33224,11 @@ function abortable(work, signal) {
|
|
|
32453
33224
|
if (signal.aborted) return Promise.reject(signal.reason);
|
|
32454
33225
|
let stop = () => {
|
|
32455
33226
|
};
|
|
32456
|
-
const
|
|
33227
|
+
const aborted3 = new Promise((_, reject) => {
|
|
32457
33228
|
stop = () => reject(signal.reason);
|
|
32458
33229
|
signal.addEventListener("abort", stop, { once: true });
|
|
32459
33230
|
});
|
|
32460
|
-
return Promise.race([work,
|
|
33231
|
+
return Promise.race([work, aborted3]).finally(() => signal.removeEventListener("abort", stop));
|
|
32461
33232
|
}
|
|
32462
33233
|
function probe(secure2, host, port, ms, signal) {
|
|
32463
33234
|
return new Promise((resolve2) => {
|
|
@@ -32816,10 +33587,10 @@ var ByteSource = class {
|
|
|
32816
33587
|
async more() {
|
|
32817
33588
|
const { done: done4, value: value2 } = await this.reader.read();
|
|
32818
33589
|
if (done4) return false;
|
|
32819
|
-
const
|
|
32820
|
-
|
|
32821
|
-
|
|
32822
|
-
this.buffered =
|
|
33590
|
+
const joined5 = new Uint8Array(this.buffered.length + value2.length);
|
|
33591
|
+
joined5.set(this.buffered);
|
|
33592
|
+
joined5.set(value2, this.buffered.length);
|
|
33593
|
+
this.buffered = joined5;
|
|
32823
33594
|
return true;
|
|
32824
33595
|
}
|
|
32825
33596
|
async until(marker) {
|
|
@@ -32986,7 +33757,7 @@ var KernelCallError = class extends Error {
|
|
|
32986
33757
|
}
|
|
32987
33758
|
};
|
|
32988
33759
|
var encoder12 = new TextEncoder();
|
|
32989
|
-
var
|
|
33760
|
+
var bytesOf4 = (data) => typeof data === "string" ? encoder12.encode(data) : data;
|
|
32990
33761
|
var UNAVAILABLE = {
|
|
32991
33762
|
manualRedirects: false,
|
|
32992
33763
|
encodedBodies: false,
|
|
@@ -33070,7 +33841,9 @@ var Channel = class {
|
|
|
33070
33841
|
call(call) {
|
|
33071
33842
|
return this.request(call).done;
|
|
33072
33843
|
}
|
|
33844
|
+
requests;
|
|
33073
33845
|
receive(data) {
|
|
33846
|
+
if (this.requests?.handle(data)) return;
|
|
33074
33847
|
if (data.traits && data.id === void 0) {
|
|
33075
33848
|
if (this.remote) this.remote.traits = data.traits;
|
|
33076
33849
|
for (const listener of [...this.traitsListeners]) listener(data.traits);
|
|
@@ -33193,7 +33966,7 @@ async function spawnOn(channel, argv, opts) {
|
|
|
33193
33966
|
});
|
|
33194
33967
|
const started = Promise.withResolvers();
|
|
33195
33968
|
let endedBy;
|
|
33196
|
-
const options = { ...rest2, ...stdin !== void 0 ? { stdin:
|
|
33969
|
+
const options = { ...rest2, ...stdin !== void 0 ? { stdin: bytesOf4(stdin) } : {} };
|
|
33197
33970
|
const { done: done4 } = channel.request(
|
|
33198
33971
|
{ op: "spawn", argv, options },
|
|
33199
33972
|
{
|
|
@@ -33276,7 +34049,7 @@ async function terminalOn(channel, argv, opts) {
|
|
|
33276
34049
|
listener = next3;
|
|
33277
34050
|
if (next3) for (const bytes of backlog.splice(0)) next3(bytes);
|
|
33278
34051
|
},
|
|
33279
|
-
write: (data) => send2({ action: "write", bytes:
|
|
34052
|
+
write: (data) => send2({ action: "write", bytes: bytesOf4(data) }),
|
|
33280
34053
|
resize: (cols, rows) => send2({ action: "resize", cols, rows }),
|
|
33281
34054
|
signal: (name2) => send2({ action: "signal", signal: name2 }),
|
|
33282
34055
|
close: () => send2({ action: "close" })
|
|
@@ -33338,8 +34111,10 @@ function since(channel, minor, what, run2) {
|
|
|
33338
34111
|
}
|
|
33339
34112
|
return run2();
|
|
33340
34113
|
}
|
|
33341
|
-
async function greet(channel, lock, timeoutMs) {
|
|
33342
|
-
channel.post({
|
|
34114
|
+
async function greet(channel, lock, timeoutMs, requests) {
|
|
34115
|
+
channel.post({
|
|
34116
|
+
hello: { protocol: PROTOCOL, ...lock ? { lock } : {}, ...requests ? { requests } : {} }
|
|
34117
|
+
});
|
|
33343
34118
|
const timer = setTimeout(
|
|
33344
34119
|
() => channel.end(
|
|
33345
34120
|
new KernelGoneError(`no slicc-kernel answered on this port within ${timeoutMs} ms`)
|
|
@@ -33364,7 +34139,14 @@ async function attachKernel(port, options = {}) {
|
|
|
33364
34139
|
const locks = options.locks === null ? void 0 : options.locks ?? locksOf();
|
|
33365
34140
|
const own = await holdLock(locks);
|
|
33366
34141
|
const channel = new Channel(port, own.release);
|
|
33367
|
-
const
|
|
34142
|
+
const requests = options.requests;
|
|
34143
|
+
if (requests) channel.requests = embedderAnswerer(port, () => requests);
|
|
34144
|
+
const hello = await greet(
|
|
34145
|
+
channel,
|
|
34146
|
+
own.name,
|
|
34147
|
+
options.timeoutMs ?? 1e4,
|
|
34148
|
+
requests ? kindsOf(requests) : void 0
|
|
34149
|
+
);
|
|
33368
34150
|
channel.protocol = hello.protocol;
|
|
33369
34151
|
if (hello.lock && locks) void locks.request(hello.lock, () => channel.end(new KernelGoneError()));
|
|
33370
34152
|
const transport = new RemoteTransport(
|
|
@@ -33578,6 +34360,31 @@ function cacheDirOf(dir) {
|
|
|
33578
34360
|
}
|
|
33579
34361
|
return dir;
|
|
33580
34362
|
}
|
|
34363
|
+
var nodeSessions = 0;
|
|
34364
|
+
function nodeClient(launcher, clients, { user, tag, requests }) {
|
|
34365
|
+
tagOption(tag);
|
|
34366
|
+
const { port1, port2 } = new MessageChannel2();
|
|
34367
|
+
const session = ++nodeSessions;
|
|
34368
|
+
const served2 = serveClient(port1, {
|
|
34369
|
+
launcher: async () => launcher,
|
|
34370
|
+
signal: signalNumber,
|
|
34371
|
+
session,
|
|
34372
|
+
...requests === "attach" ? { attachRequests: true } : {},
|
|
34373
|
+
...user !== void 0 ? { user } : {},
|
|
34374
|
+
...tag !== void 0 ? { tag } : {}
|
|
34375
|
+
});
|
|
34376
|
+
clients.add(served2);
|
|
34377
|
+
const unbind = requests && requests !== "attach" ? launcher.embedder.register(session, checkedRequests(requests)) : void 0;
|
|
34378
|
+
void served2.closed.then(() => {
|
|
34379
|
+
clients.delete(served2);
|
|
34380
|
+
unbind?.();
|
|
34381
|
+
});
|
|
34382
|
+
return port2;
|
|
34383
|
+
}
|
|
34384
|
+
function checkedRequests(hook) {
|
|
34385
|
+
const kinds = kindsOf(hook);
|
|
34386
|
+
return { kinds, handle: (request) => hook.handle(request) };
|
|
34387
|
+
}
|
|
33581
34388
|
async function createNodeKernel(options = {}) {
|
|
33582
34389
|
const root = options.root ?? memoryRoot();
|
|
33583
34390
|
const fs = new OpfsFs(root, void 0, void 0, { ranged: isMemoryRoot(root) });
|
|
@@ -33618,6 +34425,7 @@ async function createNodeKernel(options = {}) {
|
|
|
33618
34425
|
...options.protect ? { protect: options.protect } : {},
|
|
33619
34426
|
...options.sealed ? { sealed: options.sealed } : {},
|
|
33620
34427
|
...options.clipboard ? { clipboard: options.clipboard } : {},
|
|
34428
|
+
...options.requests ? { embedder: checkedRequests(options.requests) } : {},
|
|
33621
34429
|
...options.approve ? { approve: options.approve } : {},
|
|
33622
34430
|
...options.wasmMemories ? { wasmMemories: options.wasmMemories } : {},
|
|
33623
34431
|
cron: { lock: cronLock(root), ...options.cron?.clock ? { clock: options.cron.clock } : {} }
|
|
@@ -33708,22 +34516,13 @@ async function createNodeKernel(options = {}) {
|
|
|
33708
34516
|
addMember: (group, user) => guard2(() => launcher.users.addMember(group, user)),
|
|
33709
34517
|
removeMember: (group, user) => guard2(() => launcher.users.removeMember(group, user))
|
|
33710
34518
|
},
|
|
33711
|
-
async connect(
|
|
34519
|
+
async connect(connectOptions = {}) {
|
|
33712
34520
|
if (terminated) throw new Error(TERMINATED);
|
|
33713
|
-
|
|
34521
|
+
const { user } = connectOptions;
|
|
33714
34522
|
if (user !== void 0 && !await guard2(() => launcher.users.lookup(user))) {
|
|
33715
34523
|
throw fsError("ENOENT", `no user ${String(user)}`);
|
|
33716
34524
|
}
|
|
33717
|
-
|
|
33718
|
-
const served2 = serveClient(port1, {
|
|
33719
|
-
launcher: async () => launcher,
|
|
33720
|
-
signal: signalNumber,
|
|
33721
|
-
...user !== void 0 ? { user } : {},
|
|
33722
|
-
...tag !== void 0 ? { tag } : {}
|
|
33723
|
-
});
|
|
33724
|
-
clients.add(served2);
|
|
33725
|
-
void served2.closed.then(() => clients.delete(served2));
|
|
33726
|
-
return port2;
|
|
34525
|
+
return nodeClient(launcher, clients, connectOptions);
|
|
33727
34526
|
},
|
|
33728
34527
|
terminate() {
|
|
33729
34528
|
terminated = true;
|