@ai-ecoverse/slicc-kernel 1.152.2 → 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 +796 -147
- 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 +934 -162
- 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/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/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/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
|
};
|
|
@@ -4519,15 +4716,15 @@ var UnlinkedKeeper = class {
|
|
|
4519
4716
|
const releases = [];
|
|
4520
4717
|
const take = async () => {
|
|
4521
4718
|
for (; ; ) {
|
|
4522
|
-
const
|
|
4523
|
-
if (
|
|
4524
|
-
|
|
4525
|
-
if (paths.some((path) => path >
|
|
4719
|
+
const fresh3 = [...this.heldWithin(target).keys()].filter((path) => !paths.includes(path));
|
|
4720
|
+
if (fresh3.length === 0) return;
|
|
4721
|
+
fresh3.sort();
|
|
4722
|
+
if (paths.some((path) => path > fresh3[0])) {
|
|
4526
4723
|
for (const release of releases.splice(0)) release();
|
|
4527
|
-
|
|
4528
|
-
|
|
4724
|
+
fresh3.push(...paths.splice(0));
|
|
4725
|
+
fresh3.sort();
|
|
4529
4726
|
}
|
|
4530
|
-
for (const path of
|
|
4727
|
+
for (const path of fresh3) {
|
|
4531
4728
|
paths.push(path);
|
|
4532
4729
|
releases.push(await this.gate.acquire(path));
|
|
4533
4730
|
}
|
|
@@ -4862,10 +5059,10 @@ var CronService = class {
|
|
|
4862
5059
|
const text = JSON.stringify(stamp);
|
|
4863
5060
|
const old = await fs.readFile(STAMP_PATH).catch(() => void 0);
|
|
4864
5061
|
if (old === text || old === void 0 && text === EMPTY_STAMP) return;
|
|
4865
|
-
const
|
|
5062
|
+
const fresh3 = `${STAMP_PATH}.new`;
|
|
4866
5063
|
const owner = owners ? { uid: 0, gid: 0, mode: 384 } : void 0;
|
|
4867
|
-
await fs.writeFile(
|
|
4868
|
-
await fs.rename(
|
|
5064
|
+
await fs.writeFile(fresh3, text, owner);
|
|
5065
|
+
await fs.rename(fresh3, STAMP_PATH);
|
|
4869
5066
|
}
|
|
4870
5067
|
async load() {
|
|
4871
5068
|
const { fs } = this.host;
|
|
@@ -6301,13 +6498,13 @@ function materializer(fs, listedAbsent) {
|
|
|
6301
6498
|
};
|
|
6302
6499
|
}
|
|
6303
6500
|
function withEtcFiles(fs, files) {
|
|
6304
|
-
const
|
|
6501
|
+
const bytesOf5 = (path) => {
|
|
6305
6502
|
const text = files.get(path)?.();
|
|
6306
6503
|
return text === void 0 ? void 0 : new TextEncoder().encode(text);
|
|
6307
6504
|
};
|
|
6308
6505
|
const absent2 = (path) => fs.lstat(path).then(() => false, missing2);
|
|
6309
6506
|
const follow2 = linkFollower(fs, files);
|
|
6310
|
-
const listedAbsent = async (path) => files.has(path) && await absent2(path) ?
|
|
6507
|
+
const listedAbsent = async (path) => files.has(path) && await absent2(path) ? bytesOf5(path) : void 0;
|
|
6311
6508
|
const fallback = (path, make) => async (err) => {
|
|
6312
6509
|
const at = missing2(err) ? await follow2(path) : void 0;
|
|
6313
6510
|
const bytes = at === void 0 ? void 0 : await listedAbsent(at);
|
|
@@ -6380,10 +6577,10 @@ var FreshModules = class {
|
|
|
6380
6577
|
this.fresh.set(key, { umask: mask, pid, added: 0, setup: mask !== DEFAULT_UMASK });
|
|
6381
6578
|
}
|
|
6382
6579
|
forget(pid) {
|
|
6383
|
-
for (const [path,
|
|
6580
|
+
for (const [path, fresh3] of this.fresh) if (fresh3.pid === pid) this.fresh.delete(path);
|
|
6384
6581
|
}
|
|
6385
|
-
drop(
|
|
6386
|
-
for (const [key, note] of [...this.fresh]) if (note ===
|
|
6582
|
+
drop(fresh3) {
|
|
6583
|
+
for (const [key, note] of [...this.fresh]) if (note === fresh3) this.fresh.delete(key);
|
|
6387
6584
|
}
|
|
6388
6585
|
moved(from, to) {
|
|
6389
6586
|
const source = normalizePath(from);
|
|
@@ -6392,10 +6589,10 @@ var FreshModules = class {
|
|
|
6392
6589
|
for (const key of [...this.fresh.keys()]) {
|
|
6393
6590
|
if (key === target || within3(key, target)) this.fresh.delete(key);
|
|
6394
6591
|
}
|
|
6395
|
-
for (const [key,
|
|
6592
|
+
for (const [key, fresh3] of [...this.fresh]) {
|
|
6396
6593
|
if (key !== source && !within3(key, source)) continue;
|
|
6397
6594
|
this.fresh.delete(key);
|
|
6398
|
-
this.fresh.set(target + key.slice(source.length),
|
|
6595
|
+
this.fresh.set(target + key.slice(source.length), fresh3);
|
|
6399
6596
|
}
|
|
6400
6597
|
}
|
|
6401
6598
|
wrap(fs) {
|
|
@@ -6405,15 +6602,15 @@ var FreshModules = class {
|
|
|
6405
6602
|
};
|
|
6406
6603
|
const decide = async (given, known) => {
|
|
6407
6604
|
const path = normalizePath(given);
|
|
6408
|
-
const
|
|
6409
|
-
if (!
|
|
6605
|
+
const fresh3 = this.fresh.get(path);
|
|
6606
|
+
if (!fresh3) return;
|
|
6410
6607
|
const bytes = known && known.length >= MAGIC.length ? known : await head(path);
|
|
6411
|
-
const want = isModule(bytes) ? 73 & ~
|
|
6412
|
-
|
|
6413
|
-
if (want ===
|
|
6608
|
+
const want = isModule(bytes) ? 73 & ~fresh3.umask : 0;
|
|
6609
|
+
fresh3.setup = false;
|
|
6610
|
+
if (want === fresh3.added) return;
|
|
6414
6611
|
const mode = (await fs.stat(path)).mode & 4095;
|
|
6415
|
-
await fs.chmod(path, mode & ~
|
|
6416
|
-
|
|
6612
|
+
await fs.chmod(path, mode & ~fresh3.added | want);
|
|
6613
|
+
fresh3.added = want;
|
|
6417
6614
|
};
|
|
6418
6615
|
const overrides = {
|
|
6419
6616
|
writeFile: async (path, content, owner) => {
|
|
@@ -6426,9 +6623,9 @@ var FreshModules = class {
|
|
|
6426
6623
|
}
|
|
6427
6624
|
},
|
|
6428
6625
|
chmod: async (path, mode) => {
|
|
6429
|
-
const
|
|
6430
|
-
if (
|
|
6431
|
-
else if (
|
|
6626
|
+
const fresh3 = this.fresh.get(normalizePath(path));
|
|
6627
|
+
if (fresh3?.setup && (mode & 4095) === (438 & ~fresh3.umask)) fresh3.setup = false;
|
|
6628
|
+
else if (fresh3) this.drop(fresh3);
|
|
6432
6629
|
await fs.chmod(path, mode);
|
|
6433
6630
|
},
|
|
6434
6631
|
rm: async (path, options) => {
|
|
@@ -6445,8 +6642,8 @@ var FreshModules = class {
|
|
|
6445
6642
|
link: async (from, to, follow2) => {
|
|
6446
6643
|
await fs.link(from, to, follow2);
|
|
6447
6644
|
const source = follow2 && fs.realpath ? await fs.realpath(from, true).catch(() => from) : from;
|
|
6448
|
-
const
|
|
6449
|
-
if (
|
|
6645
|
+
const fresh3 = this.fresh.get(normalizePath(source));
|
|
6646
|
+
if (fresh3) this.fresh.set(normalizePath(to), fresh3);
|
|
6450
6647
|
}
|
|
6451
6648
|
};
|
|
6452
6649
|
const ranged2 = rangedOps(fs);
|
|
@@ -7150,7 +7347,7 @@ var FsWatchers = class {
|
|
|
7150
7347
|
};
|
|
7151
7348
|
const content = (run2, types) => async (...args) => {
|
|
7152
7349
|
const at = normalizePath(args[0]);
|
|
7153
|
-
const
|
|
7350
|
+
const fresh3 = this.covers(at) && !await fs.exists(at).catch(() => true);
|
|
7154
7351
|
let done4 = false;
|
|
7155
7352
|
try {
|
|
7156
7353
|
await run2(...args);
|
|
@@ -7159,11 +7356,11 @@ var FsWatchers = class {
|
|
|
7159
7356
|
const real = await realOf(at);
|
|
7160
7357
|
const paths = real === at ? [at] : [at, real];
|
|
7161
7358
|
this.report(paths);
|
|
7162
|
-
if (done4) for (const type of types(
|
|
7359
|
+
if (done4) for (const type of types(fresh3, args)) this.emit(type, paths);
|
|
7163
7360
|
}
|
|
7164
7361
|
};
|
|
7165
|
-
const written2 = (
|
|
7166
|
-
const overwritten = (
|
|
7362
|
+
const written2 = (fresh3) => fresh3 ? ["rename", "change"] : ["change"];
|
|
7363
|
+
const overwritten = (fresh3, args) => fresh3 || args[1].length === 0 ? written2(fresh3) : ["change", "change"];
|
|
7167
7364
|
const reshaping = (run2) => async (...args) => {
|
|
7168
7365
|
this.reshaped();
|
|
7169
7366
|
try {
|
|
@@ -7190,14 +7387,14 @@ var FsWatchers = class {
|
|
|
7190
7387
|
if (created4.length > 0 || !await fs.exists(ancestor)) created4.push(ancestor);
|
|
7191
7388
|
}
|
|
7192
7389
|
}
|
|
7193
|
-
const
|
|
7390
|
+
const fresh3 = !options?.recursive || this.typed.size > 0 && !await fs.exists(path);
|
|
7194
7391
|
let done4 = false;
|
|
7195
7392
|
try {
|
|
7196
7393
|
await fs.mkdir(path, options);
|
|
7197
7394
|
done4 = true;
|
|
7198
7395
|
} finally {
|
|
7199
7396
|
this.report([...created4, path]);
|
|
7200
|
-
if (done4) this.emit("rename",
|
|
7397
|
+
if (done4) this.emit("rename", fresh3 ? [...created4, path] : created4);
|
|
7201
7398
|
}
|
|
7202
7399
|
},
|
|
7203
7400
|
rm: reshaping(after(fs.rm.bind(fs), (path) => [path], "rename")),
|
|
@@ -7653,6 +7850,416 @@ var ClipboardBroker = class {
|
|
|
7653
7850
|
}
|
|
7654
7851
|
};
|
|
7655
7852
|
|
|
7853
|
+
// src/kernel/embedder.ts
|
|
7854
|
+
var EMBEDDER_PATH = "/dev/embedder";
|
|
7855
|
+
var EMBEDDER_HEADER_MAX = 64 * 1024;
|
|
7856
|
+
var EMBEDDER_WINDOW = 1024 * 1024;
|
|
7857
|
+
var EMBEDDER_BUDGET = 256 * 1024 * 1024;
|
|
7858
|
+
var EMBEDDER_PER_PROCESS = 16;
|
|
7859
|
+
var EMBEDDER_PROGRESS_PER_SECOND = 4;
|
|
7860
|
+
var KIND = /^[a-z][a-z0-9-]*(\.[a-z0-9-]+)*$/;
|
|
7861
|
+
var NL = 10;
|
|
7862
|
+
var READY2 = { readable: true, writable: true, hangup: false };
|
|
7863
|
+
function lineOf2(err) {
|
|
7864
|
+
const text = err instanceof Error ? err.message : String(err);
|
|
7865
|
+
return (text.split("\n")[0] ?? "").slice(0, 200);
|
|
7866
|
+
}
|
|
7867
|
+
var ERRNOS = {
|
|
7868
|
+
NotAllowedError: "EACCES",
|
|
7869
|
+
AbortError: "EACCES",
|
|
7870
|
+
NotSupportedError: "ENOTSUP",
|
|
7871
|
+
NotFoundError: "ENOENT"
|
|
7872
|
+
};
|
|
7873
|
+
function embedderFailure(err) {
|
|
7874
|
+
if (err instanceof KernelError) return err;
|
|
7875
|
+
const name2 = err?.name;
|
|
7876
|
+
return new KernelError(ERRNOS[String(name2)] ?? "EIO", lineOf2(err));
|
|
7877
|
+
}
|
|
7878
|
+
function headerOf(bytes) {
|
|
7879
|
+
let parsed2;
|
|
7880
|
+
try {
|
|
7881
|
+
parsed2 = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
7882
|
+
} catch {
|
|
7883
|
+
throw new KernelError("EINVAL", "the request header is not JSON");
|
|
7884
|
+
}
|
|
7885
|
+
if (typeof parsed2 !== "object" || parsed2 === null || Array.isArray(parsed2))
|
|
7886
|
+
throw new KernelError("EINVAL", "the request header is not an object");
|
|
7887
|
+
const { kind, ...options } = parsed2;
|
|
7888
|
+
if (typeof kind !== "string" || kind.length > 64 || !KIND.test(kind))
|
|
7889
|
+
throw new KernelError("EINVAL", "the request has no valid kind");
|
|
7890
|
+
return { kind, options };
|
|
7891
|
+
}
|
|
7892
|
+
function joined2(a, b) {
|
|
7893
|
+
const out = new Uint8Array(a.length + b.length);
|
|
7894
|
+
out.set(a);
|
|
7895
|
+
out.set(b, a.length);
|
|
7896
|
+
return out;
|
|
7897
|
+
}
|
|
7898
|
+
function aborted(signal) {
|
|
7899
|
+
if (!signal) return void 0;
|
|
7900
|
+
return new Promise((_, reject) => {
|
|
7901
|
+
const stop = () => reject(new KernelError("EINTR"));
|
|
7902
|
+
if (signal.aborted) stop();
|
|
7903
|
+
else signal.addEventListener("abort", stop, { once: true });
|
|
7904
|
+
});
|
|
7905
|
+
}
|
|
7906
|
+
async function interruptible2(work, signal) {
|
|
7907
|
+
const stop = aborted(signal);
|
|
7908
|
+
if (!stop) return work;
|
|
7909
|
+
stop.catch(() => void 0);
|
|
7910
|
+
return Promise.race([work, stop]);
|
|
7911
|
+
}
|
|
7912
|
+
var Budget2 = class {
|
|
7913
|
+
used = 0;
|
|
7914
|
+
limit;
|
|
7915
|
+
constructor(limit) {
|
|
7916
|
+
this.limit = limit;
|
|
7917
|
+
}
|
|
7918
|
+
take(n) {
|
|
7919
|
+
if (this.used + n > this.limit) return false;
|
|
7920
|
+
this.used += n;
|
|
7921
|
+
return true;
|
|
7922
|
+
}
|
|
7923
|
+
give(n) {
|
|
7924
|
+
this.used = Math.max(0, this.used - n);
|
|
7925
|
+
}
|
|
7926
|
+
};
|
|
7927
|
+
var BodyPipe = class {
|
|
7928
|
+
queue = [];
|
|
7929
|
+
size = 0;
|
|
7930
|
+
ended = false;
|
|
7931
|
+
wake;
|
|
7932
|
+
room;
|
|
7933
|
+
stream;
|
|
7934
|
+
constructor() {
|
|
7935
|
+
this.stream = new ReadableStream(
|
|
7936
|
+
{
|
|
7937
|
+
pull: async (controller) => {
|
|
7938
|
+
while (this.queue.length === 0 && !this.ended) {
|
|
7939
|
+
await new Promise((resolve2) => {
|
|
7940
|
+
this.wake = resolve2;
|
|
7941
|
+
});
|
|
7942
|
+
}
|
|
7943
|
+
const next3 = this.queue.shift();
|
|
7944
|
+
if (next3) {
|
|
7945
|
+
this.size -= next3.length;
|
|
7946
|
+
this.room?.();
|
|
7947
|
+
controller.enqueue(next3);
|
|
7948
|
+
} else controller.close();
|
|
7949
|
+
}
|
|
7950
|
+
},
|
|
7951
|
+
{ highWaterMark: 0 }
|
|
7952
|
+
);
|
|
7953
|
+
}
|
|
7954
|
+
get full() {
|
|
7955
|
+
return this.size >= EMBEDDER_WINDOW;
|
|
7956
|
+
}
|
|
7957
|
+
push(bytes) {
|
|
7958
|
+
if (bytes.length === 0) return;
|
|
7959
|
+
this.queue.push(bytes.slice());
|
|
7960
|
+
this.size += bytes.length;
|
|
7961
|
+
this.wake?.();
|
|
7962
|
+
}
|
|
7963
|
+
waitRoom() {
|
|
7964
|
+
return new Promise((resolve2) => {
|
|
7965
|
+
this.room = resolve2;
|
|
7966
|
+
});
|
|
7967
|
+
}
|
|
7968
|
+
end() {
|
|
7969
|
+
this.ended = true;
|
|
7970
|
+
this.wake?.();
|
|
7971
|
+
this.room?.();
|
|
7972
|
+
}
|
|
7973
|
+
};
|
|
7974
|
+
function replyStream(reply) {
|
|
7975
|
+
if (reply instanceof ReadableStream) return reply;
|
|
7976
|
+
const bytes = typeof reply === "string" ? new TextEncoder().encode(reply) : reply instanceof Uint8Array ? reply : new Uint8Array(0);
|
|
7977
|
+
return new ReadableStream({
|
|
7978
|
+
start(controller) {
|
|
7979
|
+
if (bytes.length > 0) controller.enqueue(bytes);
|
|
7980
|
+
controller.close();
|
|
7981
|
+
}
|
|
7982
|
+
});
|
|
7983
|
+
}
|
|
7984
|
+
var Throttle = class {
|
|
7985
|
+
window = 0;
|
|
7986
|
+
count = 0;
|
|
7987
|
+
allow(now) {
|
|
7988
|
+
if (now - this.window >= 1e3) {
|
|
7989
|
+
this.window = now;
|
|
7990
|
+
this.count = 0;
|
|
7991
|
+
}
|
|
7992
|
+
this.count += 1;
|
|
7993
|
+
return this.count <= EMBEDDER_PROGRESS_PER_SECOND;
|
|
7994
|
+
}
|
|
7995
|
+
};
|
|
7996
|
+
var EmbedderChannel = class {
|
|
7997
|
+
access;
|
|
7998
|
+
owner;
|
|
7999
|
+
caller;
|
|
8000
|
+
broker;
|
|
8001
|
+
header = new Uint8Array(0);
|
|
8002
|
+
body;
|
|
8003
|
+
reply;
|
|
8004
|
+
replied;
|
|
8005
|
+
rest;
|
|
8006
|
+
done = false;
|
|
8007
|
+
failure;
|
|
8008
|
+
reported = false;
|
|
8009
|
+
abort = new AbortController();
|
|
8010
|
+
closed = false;
|
|
8011
|
+
throttle = new Throttle();
|
|
8012
|
+
constructor(broker, access2, caller) {
|
|
8013
|
+
this.broker = broker;
|
|
8014
|
+
this.access = access2;
|
|
8015
|
+
this.caller = caller;
|
|
8016
|
+
this.owner = caller.pid;
|
|
8017
|
+
}
|
|
8018
|
+
get dispatched() {
|
|
8019
|
+
return this.body !== void 0;
|
|
8020
|
+
}
|
|
8021
|
+
fail(err) {
|
|
8022
|
+
this.failure ??= embedderFailure(err);
|
|
8023
|
+
return this.failure;
|
|
8024
|
+
}
|
|
8025
|
+
report(err) {
|
|
8026
|
+
this.reported = true;
|
|
8027
|
+
return this.fail(err);
|
|
8028
|
+
}
|
|
8029
|
+
async dispatch(bytes) {
|
|
8030
|
+
const { kind, options } = headerOf(bytes);
|
|
8031
|
+
const stamp = await this.broker.admit(kind, this.caller);
|
|
8032
|
+
const hook = this.broker.hookFor(this.caller.client);
|
|
8033
|
+
const body = new BodyPipe();
|
|
8034
|
+
this.body = body;
|
|
8035
|
+
const caller = this.caller;
|
|
8036
|
+
const progress = (line) => {
|
|
8037
|
+
if (this.throttle.allow(Date.now())) caller.progress(lineOf2(line));
|
|
8038
|
+
};
|
|
8039
|
+
const asked = Promise.resolve().then(
|
|
8040
|
+
() => hook.handle({
|
|
8041
|
+
kind,
|
|
8042
|
+
options,
|
|
8043
|
+
body: body.stream,
|
|
8044
|
+
stamp,
|
|
8045
|
+
signal: this.abort.signal,
|
|
8046
|
+
progress
|
|
8047
|
+
})
|
|
8048
|
+
).then((reply) => replyStream(reply).getReader());
|
|
8049
|
+
this.replied = asked.catch((err) => {
|
|
8050
|
+
body.end();
|
|
8051
|
+
throw this.fail(err);
|
|
8052
|
+
});
|
|
8053
|
+
this.replied.catch(() => void 0);
|
|
8054
|
+
}
|
|
8055
|
+
async write(bytes, signal) {
|
|
8056
|
+
if (this.access === "read") throw new KernelError("EBADF");
|
|
8057
|
+
if (this.failure) throw this.report(this.failure);
|
|
8058
|
+
if (this.reply || this.done) throw new KernelError("EBADF");
|
|
8059
|
+
if (this.body) return this.writeBody(bytes, signal);
|
|
8060
|
+
const at = bytes.indexOf(NL);
|
|
8061
|
+
const head = at < 0 ? bytes : bytes.subarray(0, at);
|
|
8062
|
+
if (this.header.length + head.length > EMBEDDER_HEADER_MAX)
|
|
8063
|
+
throw this.report(new KernelError("EINVAL", "the request header is too long"));
|
|
8064
|
+
this.header = joined2(this.header, head);
|
|
8065
|
+
if (at < 0) return bytes.length;
|
|
8066
|
+
try {
|
|
8067
|
+
await this.dispatch(this.header);
|
|
8068
|
+
} catch (err) {
|
|
8069
|
+
throw this.report(err);
|
|
8070
|
+
}
|
|
8071
|
+
this.body?.push(bytes.subarray(at + 1));
|
|
8072
|
+
return bytes.length;
|
|
8073
|
+
}
|
|
8074
|
+
async writeBody(bytes, signal) {
|
|
8075
|
+
const body = this.body;
|
|
8076
|
+
while (body.full && !this.failure) {
|
|
8077
|
+
await interruptible2(body.waitRoom(), signal).catch((err) => {
|
|
8078
|
+
this.cancel("interrupted");
|
|
8079
|
+
throw err;
|
|
8080
|
+
});
|
|
8081
|
+
}
|
|
8082
|
+
if (this.failure) throw this.report(this.failure);
|
|
8083
|
+
body.push(bytes);
|
|
8084
|
+
return bytes.length;
|
|
8085
|
+
}
|
|
8086
|
+
async readerOf(signal) {
|
|
8087
|
+
if (this.reply) return this.reply;
|
|
8088
|
+
if (!this.body) {
|
|
8089
|
+
try {
|
|
8090
|
+
await this.dispatch(this.header);
|
|
8091
|
+
} catch (err) {
|
|
8092
|
+
throw this.fail(err);
|
|
8093
|
+
}
|
|
8094
|
+
}
|
|
8095
|
+
this.body?.end();
|
|
8096
|
+
this.reply = await interruptible2(
|
|
8097
|
+
this.replied,
|
|
8098
|
+
signal
|
|
8099
|
+
);
|
|
8100
|
+
return this.reply;
|
|
8101
|
+
}
|
|
8102
|
+
async read(max, signal) {
|
|
8103
|
+
if (this.access === "write") throw new KernelError("EBADF");
|
|
8104
|
+
if (this.failure) throw this.report(this.failure);
|
|
8105
|
+
if (this.done || max <= 0) return new Uint8Array(0);
|
|
8106
|
+
try {
|
|
8107
|
+
return await this.next(max, signal);
|
|
8108
|
+
} catch (err) {
|
|
8109
|
+
if (err instanceof KernelError && err.code === "EINTR") {
|
|
8110
|
+
this.cancel("interrupted");
|
|
8111
|
+
throw err;
|
|
8112
|
+
}
|
|
8113
|
+
throw this.report(err);
|
|
8114
|
+
}
|
|
8115
|
+
}
|
|
8116
|
+
async next(max, signal) {
|
|
8117
|
+
const reader = await this.readerOf(signal);
|
|
8118
|
+
let chunk2 = this.rest;
|
|
8119
|
+
this.rest = void 0;
|
|
8120
|
+
if (!chunk2) {
|
|
8121
|
+
const got = await interruptible2(reader.read(), signal);
|
|
8122
|
+
if (got.done) {
|
|
8123
|
+
this.done = true;
|
|
8124
|
+
return new Uint8Array(0);
|
|
8125
|
+
}
|
|
8126
|
+
chunk2 = got.value;
|
|
8127
|
+
}
|
|
8128
|
+
if (chunk2.length > max) this.rest = chunk2.subarray(max);
|
|
8129
|
+
return chunk2.subarray(0, max);
|
|
8130
|
+
}
|
|
8131
|
+
poll() {
|
|
8132
|
+
return this.body?.full ? { ...READY2, writable: false } : READY2;
|
|
8133
|
+
}
|
|
8134
|
+
cancel(reason) {
|
|
8135
|
+
if (this.abort.signal.aborted) return;
|
|
8136
|
+
this.abort.abort(new DOMException(reason, "AbortError"));
|
|
8137
|
+
this.body?.end();
|
|
8138
|
+
void this.reply?.cancel(reason).catch(() => void 0);
|
|
8139
|
+
}
|
|
8140
|
+
async close() {
|
|
8141
|
+
if (this.closed) return;
|
|
8142
|
+
const signal = this.caller.closing();
|
|
8143
|
+
this.closed = true;
|
|
8144
|
+
try {
|
|
8145
|
+
if (this.access === "read") return;
|
|
8146
|
+
if (this.failure) {
|
|
8147
|
+
if (this.reported) return;
|
|
8148
|
+
throw this.report(this.failure);
|
|
8149
|
+
}
|
|
8150
|
+
if (this.access === "both" && this.dispatched) return;
|
|
8151
|
+
if (!this.dispatched && this.header.length === 0) return;
|
|
8152
|
+
await this.drain(signal);
|
|
8153
|
+
} finally {
|
|
8154
|
+
if (!this.done) this.cancel("closed");
|
|
8155
|
+
this.broker.release(this);
|
|
8156
|
+
}
|
|
8157
|
+
}
|
|
8158
|
+
async drain(signal) {
|
|
8159
|
+
try {
|
|
8160
|
+
const reader = await this.readerOf(signal);
|
|
8161
|
+
for (; ; ) {
|
|
8162
|
+
const got = await interruptible2(reader.read(), signal);
|
|
8163
|
+
if (got.done) break;
|
|
8164
|
+
}
|
|
8165
|
+
this.done = true;
|
|
8166
|
+
} catch (err) {
|
|
8167
|
+
if (err instanceof KernelError && err.code === "EINTR") this.cancel("interrupted");
|
|
8168
|
+
throw this.fail(err);
|
|
8169
|
+
}
|
|
8170
|
+
}
|
|
8171
|
+
};
|
|
8172
|
+
var EmbedderBroker = class {
|
|
8173
|
+
users;
|
|
8174
|
+
lookup;
|
|
8175
|
+
hooks = /* @__PURE__ */ new Map();
|
|
8176
|
+
budget;
|
|
8177
|
+
open = /* @__PURE__ */ new Map();
|
|
8178
|
+
tagsOf;
|
|
8179
|
+
constructor(users, lookup4, tagsOf = () => void 0, budget = EMBEDDER_BUDGET) {
|
|
8180
|
+
this.users = users;
|
|
8181
|
+
this.tagsOf = tagsOf;
|
|
8182
|
+
this.lookup = lookup4;
|
|
8183
|
+
this.budget = new Budget2(budget);
|
|
8184
|
+
}
|
|
8185
|
+
register(client, hook) {
|
|
8186
|
+
if (!hook) return () => void 0;
|
|
8187
|
+
this.hooks.set(client, hook);
|
|
8188
|
+
return () => {
|
|
8189
|
+
if (this.hooks.get(client) === hook) this.hooks.delete(client);
|
|
8190
|
+
};
|
|
8191
|
+
}
|
|
8192
|
+
hookFor(client) {
|
|
8193
|
+
return this.hooks.get(client);
|
|
8194
|
+
}
|
|
8195
|
+
async allowed(policy, caller) {
|
|
8196
|
+
if (caller.euid === 0 || caller.euid === caller.sessionUid) return true;
|
|
8197
|
+
if (policy.group !== void 0) {
|
|
8198
|
+
const gid = await this.lookup.groupId(policy.group);
|
|
8199
|
+
if (gid !== void 0 && (caller.egid === gid || caller.groups.includes(gid))) return true;
|
|
8200
|
+
}
|
|
8201
|
+
for (const user of policy.users ?? []) {
|
|
8202
|
+
const uid = typeof user === "number" ? user : await this.lookup.userId(user);
|
|
8203
|
+
if (uid === caller.euid) return true;
|
|
8204
|
+
}
|
|
8205
|
+
return false;
|
|
8206
|
+
}
|
|
8207
|
+
async admit(kind, caller) {
|
|
8208
|
+
const hook = this.hooks.get(caller.client);
|
|
8209
|
+
if (!hook) throw new KernelError("ENOTSUP", "no page answers requests for this session");
|
|
8210
|
+
const policy = Object.hasOwn(hook.kinds, kind) ? hook.kinds[kind] : void 0;
|
|
8211
|
+
if (!policy) throw new KernelError("ENOTSUP", `this embedder does not answer ${kind}`);
|
|
8212
|
+
if (this.users !== "off" && !await this.allowed(policy, caller))
|
|
8213
|
+
throw new KernelError("EACCES", `${kind} is not allowed for this user`);
|
|
8214
|
+
const tags = caller.tags;
|
|
8215
|
+
return {
|
|
8216
|
+
pid: caller.shownPid,
|
|
8217
|
+
uid: caller.euid,
|
|
8218
|
+
gid: caller.egid,
|
|
8219
|
+
groups: [...caller.groups],
|
|
8220
|
+
users: this.users,
|
|
8221
|
+
kind,
|
|
8222
|
+
...tags?.length ? { tag: tags[0], tags: [...tags] } : {}
|
|
8223
|
+
};
|
|
8224
|
+
}
|
|
8225
|
+
channel(access2, caller) {
|
|
8226
|
+
const mine = this.open.get(caller.pid) ?? /* @__PURE__ */ new Set();
|
|
8227
|
+
if (mine.size >= EMBEDDER_PER_PROCESS)
|
|
8228
|
+
throw new KernelError("EMFILE", `at most ${EMBEDDER_PER_PROCESS} requests per process`);
|
|
8229
|
+
if (!this.budget.take(2 * EMBEDDER_WINDOW))
|
|
8230
|
+
throw new KernelError("EAGAIN", "the embedder request budget is spent");
|
|
8231
|
+
const channel = new EmbedderChannel(this, access2, caller);
|
|
8232
|
+
mine.add(channel);
|
|
8233
|
+
this.open.set(caller.pid, mine);
|
|
8234
|
+
return new OpenFile({
|
|
8235
|
+
read: channel.read.bind(channel),
|
|
8236
|
+
write: (bytes, signal) => channel.write(bytes, signal),
|
|
8237
|
+
poll: () => channel.poll(),
|
|
8238
|
+
close: () => channel.close(),
|
|
8239
|
+
embedder: channel
|
|
8240
|
+
});
|
|
8241
|
+
}
|
|
8242
|
+
release(channel) {
|
|
8243
|
+
const mine = this.open.get(channel.owner);
|
|
8244
|
+
if (!mine?.delete(channel)) return;
|
|
8245
|
+
if (mine.size === 0) this.open.delete(channel.owner);
|
|
8246
|
+
this.budget.give(2 * EMBEDDER_WINDOW);
|
|
8247
|
+
}
|
|
8248
|
+
};
|
|
8249
|
+
function kindsOf(hook) {
|
|
8250
|
+
if (typeof hook?.handle !== "function" || typeof hook.kinds !== "object" || !hook.kinds)
|
|
8251
|
+
throw new TypeError("requests needs kinds and handle");
|
|
8252
|
+
return Object.fromEntries(
|
|
8253
|
+
Object.entries(hook.kinds).map(([kind, policy]) => [
|
|
8254
|
+
kind,
|
|
8255
|
+
{
|
|
8256
|
+
...policy?.group !== void 0 ? { group: String(policy.group) } : {},
|
|
8257
|
+
...policy?.users ? { users: [...policy.users] } : {}
|
|
8258
|
+
}
|
|
8259
|
+
])
|
|
8260
|
+
);
|
|
8261
|
+
}
|
|
8262
|
+
|
|
7656
8263
|
// src/kernel/exec-ticket.ts
|
|
7657
8264
|
var TICKET_ENV = "SLICC_SEALED_TICKET";
|
|
7658
8265
|
var TICKET_TTL_MS = 3e4;
|
|
@@ -8221,9 +8828,9 @@ var HeldPaths = class extends Map {
|
|
|
8221
8828
|
return false;
|
|
8222
8829
|
}
|
|
8223
8830
|
keep(path, file) {
|
|
8224
|
-
const
|
|
8225
|
-
for (const id2 of
|
|
8226
|
-
this.uses.set(file, Math.max(
|
|
8831
|
+
const fresh3 = this.handlesAt(path).filter((id2) => !this.keptHandles.has(id2));
|
|
8832
|
+
for (const id2 of fresh3) this.keptHandles.set(id2, file);
|
|
8833
|
+
this.uses.set(file, Math.max(fresh3.length, 1));
|
|
8227
8834
|
this.unlinked.set(path, file);
|
|
8228
8835
|
}
|
|
8229
8836
|
unkeep(path, file) {
|
|
@@ -9419,8 +10026,8 @@ var MountFs = class _MountFs {
|
|
|
9419
10026
|
}
|
|
9420
10027
|
this.writable(mount, real);
|
|
9421
10028
|
const { uid, gid, mode } = change;
|
|
9422
|
-
const
|
|
9423
|
-
const set3 =
|
|
10029
|
+
const fresh3 = change.kind === "new" && { uid, gid, mode };
|
|
10030
|
+
const set3 = fresh3 ? await this.driverOwner(found, real, fresh3, false) : change;
|
|
9424
10031
|
this.table.forget(mount, real);
|
|
9425
10032
|
const attrs = Object.entries({ uid: set3.uid, gid: set3.gid, mode: set3.mode });
|
|
9426
10033
|
await mount.conn.call({
|
|
@@ -9692,10 +10299,10 @@ async function runMkdir(entry, path, req) {
|
|
|
9692
10299
|
const plain3 = plainDirMode(entry, req.mode);
|
|
9693
10300
|
const parentsMode = !req.exclusive ? plainParentsMode(entry) : void 0;
|
|
9694
10301
|
const fixParents = parentsMode !== void 0 ? await missingParents(fs, path, parentsMode) : void 0;
|
|
9695
|
-
const
|
|
10302
|
+
const fresh3 = plain3 !== void 0 && !await fs.exists(path);
|
|
9696
10303
|
await (req.exclusive ? mkdirExclusive(entry, path, req.mode) : fs.mkdir(path, mkdirOptions(entry, req.mode)));
|
|
9697
10304
|
await fixParents?.();
|
|
9698
|
-
if (
|
|
10305
|
+
if (fresh3) await fs.chmod(path, plain3);
|
|
9699
10306
|
return done;
|
|
9700
10307
|
}
|
|
9701
10308
|
async function shownAs(entry, path, st) {
|
|
@@ -10699,9 +11306,9 @@ var Pages = class {
|
|
|
10699
11306
|
const page = (start2 + at) / PAGE;
|
|
10700
11307
|
if (this.pages.has(page)) continue;
|
|
10701
11308
|
const part = bytes.subarray(at, Math.min(at + PAGE, bytes.length));
|
|
10702
|
-
const
|
|
10703
|
-
|
|
10704
|
-
this.pages.set(page,
|
|
11309
|
+
const fresh3 = this.take(part.length);
|
|
11310
|
+
fresh3.set(part);
|
|
11311
|
+
this.pages.set(page, fresh3);
|
|
10705
11312
|
}
|
|
10706
11313
|
}
|
|
10707
11314
|
read(at, length2) {
|
|
@@ -12963,18 +13570,18 @@ var TlsEngine = class {
|
|
|
12963
13570
|
chainFlags(store, chain2, hostname) {
|
|
12964
13571
|
const verify = this.m._tls_chain_verify;
|
|
12965
13572
|
if (!verify || chain2.length === 0) return void 0;
|
|
12966
|
-
const
|
|
13573
|
+
const joined5 = new Uint8Array(chain2.reduce((n, c) => n + c.length, 0));
|
|
12967
13574
|
let at = 0;
|
|
12968
13575
|
for (const der2 of chain2) {
|
|
12969
|
-
|
|
13576
|
+
joined5.set(der2, at);
|
|
12970
13577
|
at += der2.length;
|
|
12971
13578
|
}
|
|
12972
13579
|
const name2 = this.put(new TextEncoder().encode(hostname));
|
|
12973
13580
|
try {
|
|
12974
|
-
return this.withBytes(
|
|
13581
|
+
return this.withBytes(joined5, (p) => {
|
|
12975
13582
|
const out = this.scratch;
|
|
12976
13583
|
this.m.HEAPU8.fill(255, out, out + 4);
|
|
12977
|
-
const ret = verify(store.ptr, p,
|
|
13584
|
+
const ret = verify(store.ptr, p, joined5.length, name2, out);
|
|
12978
13585
|
const flags2 = new DataView(this.m.HEAPU8.buffer, out, 4).getUint32(0, true);
|
|
12979
13586
|
if (ret === 0) return flags2 === 0 ? 0 : void 0;
|
|
12980
13587
|
return ret === 1 && flags2 !== 0 ? flags2 : void 0;
|
|
@@ -15708,6 +16315,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
|
15708
16315
|
...file.tty ? { tty: file.tty } : {},
|
|
15709
16316
|
identity: file.identity ?? file,
|
|
15710
16317
|
...file.clipboard ? { clipboard: file.clipboard } : {},
|
|
16318
|
+
...file.embedder ? { embedder: file.embedder } : {},
|
|
15711
16319
|
...file.write ? {
|
|
15712
16320
|
write: async (bytes, signal) => {
|
|
15713
16321
|
await turn(signal);
|
|
@@ -15764,7 +16372,8 @@ function scrubStdio(fds, scrubber) {
|
|
|
15764
16372
|
const stdio = stdioFiles(fds);
|
|
15765
16373
|
for (const fd of fds.numbers()) {
|
|
15766
16374
|
const original = fds.get(fd);
|
|
15767
|
-
|
|
16375
|
+
const named = original.file.tty || original.file.clipboard || original.file.embedder;
|
|
16376
|
+
if (!stdio.has(original) && !named) continue;
|
|
15768
16377
|
const known = wrapped.get(original);
|
|
15769
16378
|
const flags2 = fds.statusFlags(fd);
|
|
15770
16379
|
const wrapper = known ? known.retain() : scrubbed(original.retain(), scrubber);
|
|
@@ -15777,9 +16386,9 @@ function scrubStdio(fds, scrubber) {
|
|
|
15777
16386
|
// src/kernel/net/sealed-scrubs.ts
|
|
15778
16387
|
function addTo(tree2, host, secrets) {
|
|
15779
16388
|
const entry = tree2.get(host) ?? { secrets: [], version: 0, scrubber: void 0 };
|
|
15780
|
-
const
|
|
15781
|
-
if (
|
|
15782
|
-
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];
|
|
15783
16392
|
entry.version += 1;
|
|
15784
16393
|
entry.scrubber = void 0;
|
|
15785
16394
|
tree2.set(host, entry);
|
|
@@ -15993,13 +16602,13 @@ function serialized(reply) {
|
|
|
15993
16602
|
const text = JSON.stringify(reply);
|
|
15994
16603
|
plain3 = text === void 0 ? void 0 : JSON.parse(text);
|
|
15995
16604
|
} catch (err) {
|
|
15996
|
-
return JSON.stringify(errorReply("EIO",
|
|
16605
|
+
return JSON.stringify(errorReply("EIO", lineOf3(err)));
|
|
15997
16606
|
}
|
|
15998
16607
|
if (!isRecord(plain3)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
|
|
15999
16608
|
const { v: _, ...rest2 } = plain3;
|
|
16000
16609
|
return JSON.stringify({ v: 1, ...rest2 });
|
|
16001
16610
|
}
|
|
16002
|
-
function
|
|
16611
|
+
function lineOf3(err) {
|
|
16003
16612
|
const text = err instanceof Error ? err.message : String(err);
|
|
16004
16613
|
return (text.split("\n")[0] ?? "").slice(0, 200);
|
|
16005
16614
|
}
|
|
@@ -16050,7 +16659,7 @@ var SealedChannel = class {
|
|
|
16050
16659
|
if (signal.aborted) return void 0;
|
|
16051
16660
|
const asked = Promise.resolve().then(() => hook(req, { signal })).then(
|
|
16052
16661
|
(reply2) => isRecord(reply2) ? reply2 : errorReply("EIO", "the vault gave no reply"),
|
|
16053
|
-
(err) => errorReply("EIO",
|
|
16662
|
+
(err) => errorReply("EIO", lineOf3(err))
|
|
16054
16663
|
);
|
|
16055
16664
|
const reply = await Promise.race([asked, stopped]);
|
|
16056
16665
|
if (!signal.aborted) return reply;
|
|
@@ -17167,13 +17776,13 @@ var PgServer = class {
|
|
|
17167
17776
|
at += whole;
|
|
17168
17777
|
}
|
|
17169
17778
|
this.buffer = data.slice(at);
|
|
17170
|
-
const
|
|
17779
|
+
const joined5 = new Uint8Array(out.reduce((n, b) => n + b.length, 0));
|
|
17171
17780
|
let to = 0;
|
|
17172
17781
|
for (const b of out) {
|
|
17173
|
-
|
|
17782
|
+
joined5.set(b, to);
|
|
17174
17783
|
to += b.length;
|
|
17175
17784
|
}
|
|
17176
|
-
return
|
|
17785
|
+
return joined5;
|
|
17177
17786
|
}
|
|
17178
17787
|
};
|
|
17179
17788
|
function frame3(type, body) {
|
|
@@ -17396,7 +18005,7 @@ function latin12(bytes) {
|
|
|
17396
18005
|
for (const b of bytes) out += String.fromCharCode(b);
|
|
17397
18006
|
return out;
|
|
17398
18007
|
}
|
|
17399
|
-
function
|
|
18008
|
+
function bytesOf2(text) {
|
|
17400
18009
|
const out = new Uint8Array(text.length);
|
|
17401
18010
|
for (let i = 0; i < text.length; i++) out[i] = text.charCodeAt(i);
|
|
17402
18011
|
return out;
|
|
@@ -17515,12 +18124,12 @@ var SessionWriter = class {
|
|
|
17515
18124
|
if (this.failed !== void 0) throw this.failed;
|
|
17516
18125
|
if (this.mode === "pass") return this.conn.write(bytes);
|
|
17517
18126
|
clearTimeout(this.timer);
|
|
17518
|
-
const
|
|
17519
|
-
|
|
17520
|
-
|
|
18127
|
+
const joined5 = new Uint8Array(this.buffer.length + bytes.length);
|
|
18128
|
+
joined5.set(this.buffer);
|
|
18129
|
+
joined5.set(bytes, this.buffer.length);
|
|
17521
18130
|
this.buffer.fill(0);
|
|
17522
|
-
this.buffer =
|
|
17523
|
-
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";
|
|
17524
18133
|
if (this.mode === "pg" && !this.sawPg) {
|
|
17525
18134
|
this.sawPg = true;
|
|
17526
18135
|
if (!this.s.verified) void this.proof("pg");
|
|
@@ -17548,7 +18157,7 @@ var SessionWriter = class {
|
|
|
17548
18157
|
const out = await this.smtp.line(latin12(all.subarray(0, at))).catch(() => ({ line: latin12(all.subarray(0, at)) }));
|
|
17549
18158
|
all.fill(0);
|
|
17550
18159
|
if ("values" in out && out.values) this.remember(out.values);
|
|
17551
|
-
const line =
|
|
18160
|
+
const line = bytesOf2(`${out.line}\r
|
|
17552
18161
|
`);
|
|
17553
18162
|
try {
|
|
17554
18163
|
await writeAll3(this.conn, line);
|
|
@@ -17605,7 +18214,7 @@ var SessionWriter = class {
|
|
|
17605
18214
|
latin12(all.subarray(0, end)),
|
|
17606
18215
|
(position, placeholders, head2) => this.ask("http1", position, { placeholders, head: head2 })
|
|
17607
18216
|
).catch(() => void 0);
|
|
17608
|
-
const head = done4 ?
|
|
18217
|
+
const head = done4 ? bytesOf2(done4.head) : all.subarray(0, end);
|
|
17609
18218
|
if (done4) this.remember(done4.values);
|
|
17610
18219
|
try {
|
|
17611
18220
|
await writeAll3(this.conn, head);
|
|
@@ -17668,7 +18277,7 @@ var ScrubReader = class {
|
|
|
17668
18277
|
const before = this.current();
|
|
17669
18278
|
const out = this.through(got);
|
|
17670
18279
|
if (before.length === 0 && out !== void 0) return out;
|
|
17671
|
-
if (before.length > 0) return
|
|
18280
|
+
if (before.length > 0) return joined3(before, out);
|
|
17672
18281
|
}
|
|
17673
18282
|
}
|
|
17674
18283
|
through(got) {
|
|
@@ -17684,7 +18293,7 @@ var ScrubReader = class {
|
|
|
17684
18293
|
return out.length > 0 ? out : void 0;
|
|
17685
18294
|
}
|
|
17686
18295
|
};
|
|
17687
|
-
function
|
|
18296
|
+
function joined3(a, b) {
|
|
17688
18297
|
if (!b) return a;
|
|
17689
18298
|
const out = new Uint8Array(a.length + b.length);
|
|
17690
18299
|
out.set(a);
|
|
@@ -18592,7 +19201,7 @@ async function connect(req, proc) {
|
|
|
18592
19201
|
dialing?.catch(() => void 0);
|
|
18593
19202
|
throw new KernelError("EINPROGRESS");
|
|
18594
19203
|
}
|
|
18595
|
-
if (dialing !== void 0) await
|
|
19204
|
+
if (dialing !== void 0) await interruptible3(dialing, proc.blocking());
|
|
18596
19205
|
return ok3();
|
|
18597
19206
|
}
|
|
18598
19207
|
async function bindUnixDgram(proc, socket, addr) {
|
|
@@ -18657,7 +19266,7 @@ async function unixDatagram(req, dgram, proc) {
|
|
|
18657
19266
|
function domainOf(socket) {
|
|
18658
19267
|
return socket instanceof UnixDgram ? "unix" : "inet";
|
|
18659
19268
|
}
|
|
18660
|
-
function
|
|
19269
|
+
function interruptible3(dialing, signal) {
|
|
18661
19270
|
return new Promise((resolve2, reject) => {
|
|
18662
19271
|
const abort = () => reject(new KernelError("EINTR"));
|
|
18663
19272
|
signal.addEventListener("abort", abort, { once: true });
|
|
@@ -19661,7 +20270,7 @@ var ProcessWatches = class {
|
|
|
19661
20270
|
};
|
|
19662
20271
|
|
|
19663
20272
|
// src/kernel/process.ts
|
|
19664
|
-
function
|
|
20273
|
+
function aborted2(signal) {
|
|
19665
20274
|
return new Promise((_, reject) => {
|
|
19666
20275
|
signal.addEventListener("abort", () => reject(new KernelError("EINTR")), { once: true });
|
|
19667
20276
|
});
|
|
@@ -19751,6 +20360,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
19751
20360
|
"fd-open-sealed",
|
|
19752
20361
|
"fd-open-clipboard",
|
|
19753
20362
|
"fd-clipboard-abort",
|
|
20363
|
+
"fd-open-embedder",
|
|
19754
20364
|
"tty-get",
|
|
19755
20365
|
"tty-set",
|
|
19756
20366
|
"tty-winsz",
|
|
@@ -20304,6 +20914,7 @@ var WasmProcess = class {
|
|
|
20304
20914
|
if (!read) throw new KernelError(req.peek && file.read ? "EOPNOTSUPP" : "EBADF");
|
|
20305
20915
|
if (file.tty) this.checkForeground(file.tty);
|
|
20306
20916
|
if (file.clipboard) return this.readClipboard(file.clipboard, req, cancelled);
|
|
20917
|
+
if (file.embedder) return this.readEmbedder(file, req, cancelled);
|
|
20307
20918
|
if (file instanceof EventFd && req.max < EventFd.SIZE) throw new KernelError("EINVAL");
|
|
20308
20919
|
if (req.max <= 0) return new Uint8Array(0);
|
|
20309
20920
|
if (file instanceof KernelSocket && file.unconnected) throw new KernelError("ENOTCONN");
|
|
@@ -20324,6 +20935,81 @@ var WasmProcess = class {
|
|
|
20324
20935
|
throw err;
|
|
20325
20936
|
}
|
|
20326
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
|
+
}
|
|
20327
21013
|
async complain(line) {
|
|
20328
21014
|
const stderr = this.fds.has(2) ? this.fds.get(2).file : void 0;
|
|
20329
21015
|
if (!stderr?.write || stderr.sealed || stderr.clipboard) return false;
|
|
@@ -20354,6 +21040,7 @@ var WasmProcess = class {
|
|
|
20354
21040
|
const file = this.fds.get(fd).file;
|
|
20355
21041
|
if (file.sealed) return file.sealed.send(body, await this.sealedCaller(), this.gone.signal);
|
|
20356
21042
|
if (!file.write) throw new KernelError("EBADF");
|
|
21043
|
+
if (file.embedder) return this.writeEmbedder(file, body, nonblock, cancelled);
|
|
20357
21044
|
if (!pollFile(file).writable) {
|
|
20358
21045
|
if (nonblock) throw new KernelError("EAGAIN");
|
|
20359
21046
|
return file.write(body, this.blockingSignal(cancelled));
|
|
@@ -20401,11 +21088,11 @@ var WasmProcess = class {
|
|
|
20401
21088
|
} else if (req.create) {
|
|
20402
21089
|
await nodes.onEntry(path, async () => {
|
|
20403
21090
|
const marks = this.options.owners || plain3 !== void 0;
|
|
20404
|
-
const
|
|
21091
|
+
const fresh3 = marks && !await present3(fs, path, true);
|
|
20405
21092
|
this.fds.installAt(fd, this.openVfsFile(open, await nodes.identify(path), fs));
|
|
20406
21093
|
await this.fds.get(fd).file.stat?.();
|
|
20407
|
-
if (
|
|
20408
|
-
else if (
|
|
21094
|
+
if (fresh3 && plain3 !== void 0) await fs.chmod?.(path, plain3);
|
|
21095
|
+
else if (fresh3) {
|
|
20409
21096
|
await fs.chown?.(path, { ...this.newOwner(req.mode), kind: "new" });
|
|
20410
21097
|
}
|
|
20411
21098
|
});
|
|
@@ -20623,17 +21310,9 @@ var WasmProcess = class {
|
|
|
20623
21310
|
kind: "json",
|
|
20624
21311
|
json: await this.write(req.fd, req.body, req.nonblock, cancelled)
|
|
20625
21312
|
};
|
|
20626
|
-
case "fd-close":
|
|
20627
|
-
this.
|
|
20628
|
-
await this.dropRecordLocks(req.fd);
|
|
20629
|
-
const channel = this.fds.get(req.fd).file.clipboard;
|
|
20630
|
-
if (channel) channel.stamp = await this.clipboardStamp();
|
|
20631
|
-
await Promise.resolve(this.fds.close(req.fd)).catch(async (err) => {
|
|
20632
|
-
if (channel) await this.clipboardComplaint(err);
|
|
20633
|
-
throw err;
|
|
20634
|
-
});
|
|
21313
|
+
case "fd-close":
|
|
21314
|
+
await this.closeFd(req.fd);
|
|
20635
21315
|
return { ok: true, kind: "void" };
|
|
20636
|
-
}
|
|
20637
21316
|
case "fd-pipe": {
|
|
20638
21317
|
const pipe = openPipe();
|
|
20639
21318
|
const read = this.fds.install(pipe.read, 3);
|
|
@@ -20693,6 +21372,8 @@ var WasmProcess = class {
|
|
|
20693
21372
|
return { ok: true, kind: "json", json: this.openSealed(req.flags) };
|
|
20694
21373
|
case "fd-open-clipboard":
|
|
20695
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) };
|
|
20696
21377
|
case "fd-clipboard-abort": {
|
|
20697
21378
|
const file = this.fds.get(req.fd);
|
|
20698
21379
|
file.file.clipboard?.abort();
|
|
@@ -21187,7 +21868,7 @@ var WasmProcess = class {
|
|
|
21187
21868
|
else {
|
|
21188
21869
|
const { source, target, type, flags: flags2, data } = req;
|
|
21189
21870
|
const signal = this.blockingSignal(cancelled);
|
|
21190
|
-
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)]);
|
|
21191
21872
|
}
|
|
21192
21873
|
} catch (err) {
|
|
21193
21874
|
const code = err?.code;
|
|
@@ -21197,7 +21878,7 @@ var WasmProcess = class {
|
|
|
21197
21878
|
return { ok: true, kind: "void" };
|
|
21198
21879
|
}
|
|
21199
21880
|
pause(cancelled) {
|
|
21200
|
-
return
|
|
21881
|
+
return aborted2(this.blockingSignal(cancelled));
|
|
21201
21882
|
}
|
|
21202
21883
|
alarm;
|
|
21203
21884
|
dlLog = [];
|
|
@@ -21747,6 +22428,15 @@ function linksOf(opts) {
|
|
|
21747
22428
|
function clipboardName(opts) {
|
|
21748
22429
|
return opts.program.abi === "js" ? {} : { clipboardName: opts.argv0 };
|
|
21749
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
|
+
}
|
|
21750
22440
|
function processOptions(opts, header5, hooks, created4) {
|
|
21751
22441
|
return {
|
|
21752
22442
|
...inherited(opts),
|
|
@@ -21754,6 +22444,7 @@ function processOptions(opts, header5, hooks, created4) {
|
|
|
21754
22444
|
...opts.sealed ? { sealed: opts.sealed } : {},
|
|
21755
22445
|
...opts.outputFilter ? { outputFilter: opts.outputFilter } : {},
|
|
21756
22446
|
...opts.clipboard ? { clipboard: opts.clipboard, ...clipboardName(opts) } : {},
|
|
22447
|
+
...embedderOptions(opts),
|
|
21757
22448
|
...opts.readonlyAt ? { readonlyAt: opts.readonlyAt } : {},
|
|
21758
22449
|
...opts.source ? { source: opts.source } : {},
|
|
21759
22450
|
noLinks: opts.noLinks,
|
|
@@ -24502,9 +25193,9 @@ var OpfsFs = class {
|
|
|
24502
25193
|
this.lookups++;
|
|
24503
25194
|
if (split2(path).length === 0) return this.root;
|
|
24504
25195
|
const cached = this.files.get(path);
|
|
24505
|
-
const
|
|
24506
|
-
if (cached && !
|
|
24507
|
-
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) {
|
|
24508
25199
|
if (this.glanced(cached)) return this.remember(path, cached);
|
|
24509
25200
|
try {
|
|
24510
25201
|
await this.glance(cached);
|
|
@@ -24722,8 +25413,8 @@ var OpfsFs = class {
|
|
|
24722
25413
|
glanced(handle) {
|
|
24723
25414
|
if (this.exact > 0) return void 0;
|
|
24724
25415
|
const seen = this.glances.get(handle);
|
|
24725
|
-
const
|
|
24726
|
-
return
|
|
25416
|
+
const fresh3 = seen && seen.changes === this.changes && this.recent(seen, GLANCE_LOOKUPS);
|
|
25417
|
+
return fresh3 ? seen.file : void 0;
|
|
24727
25418
|
}
|
|
24728
25419
|
async glance(handle) {
|
|
24729
25420
|
const at = performance.now();
|
|
@@ -24913,13 +25604,13 @@ var OpfsFs = class {
|
|
|
24913
25604
|
async keptFor(path) {
|
|
24914
25605
|
const at = normalizePath(path);
|
|
24915
25606
|
const cached = this.files.get(at);
|
|
24916
|
-
const
|
|
24917
|
-
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);
|
|
24918
25609
|
if (!existed) return [void 0, target, false];
|
|
24919
25610
|
this.refuse(target);
|
|
24920
25611
|
const [entry] = await this.meta.get([target]);
|
|
24921
25612
|
if (entry?.fifo || entry?.socket) throw fsError("ENXIO", path);
|
|
24922
|
-
const kept =
|
|
25613
|
+
const kept = fresh3 ? cached : this.files.get(target);
|
|
24923
25614
|
const usable2 = kept && performance.now() - (this.found.get(kept) ?? -CHECK_MS) < CHECK_MS;
|
|
24924
25615
|
return [usable2 ? kept : void 0, target, true];
|
|
24925
25616
|
}
|
|
@@ -26634,14 +27325,14 @@ var RESTORE_AGAIN_MS = 3e4;
|
|
|
26634
27325
|
function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
26635
27326
|
const handles = /* @__PURE__ */ new Map();
|
|
26636
27327
|
let nextFh = 0;
|
|
26637
|
-
const
|
|
27328
|
+
const fresh3 = (remote) => {
|
|
26638
27329
|
if (remote.client.token === remote.token && !remote.client.gone) return remote;
|
|
26639
27330
|
throw fsError2("ESTALE", "the folder was granted again, so this open file is gone");
|
|
26640
27331
|
};
|
|
26641
27332
|
const live = (fh) => {
|
|
26642
27333
|
const remote = handles.get(fh);
|
|
26643
27334
|
if (!remote) throw fsError2("EBADF", `handle ${fh}`);
|
|
26644
|
-
return
|
|
27335
|
+
return fresh3(remote);
|
|
26645
27336
|
};
|
|
26646
27337
|
const call = (op, body = {}) => current().call(op, body);
|
|
26647
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);
|
|
@@ -26723,7 +27414,7 @@ function hostfsHandlers(current, againMs = RESTORE_AGAIN_MS) {
|
|
|
26723
27414
|
if (!remote) throw fsError2("EBADF", `handle ${fh}`);
|
|
26724
27415
|
handles.delete(fh);
|
|
26725
27416
|
try {
|
|
26726
|
-
await
|
|
27417
|
+
await fresh3(remote).client.call("release", { fh: remote.fh }, true);
|
|
26727
27418
|
} finally {
|
|
26728
27419
|
if (remote.restore) await settle(current(), remote.restore);
|
|
26729
27420
|
}
|
|
@@ -27087,7 +27778,7 @@ var PortTransport = class {
|
|
|
27087
27778
|
}).finally(() => this.fail("the folder's watch ended"));
|
|
27088
27779
|
}
|
|
27089
27780
|
};
|
|
27090
|
-
var
|
|
27781
|
+
var errorOf2 = (err) => ({
|
|
27091
27782
|
code: typeof codeOf7(err) === "string" ? codeOf7(err) : "EIO",
|
|
27092
27783
|
message: err?.message ?? String(err)
|
|
27093
27784
|
});
|
|
@@ -27137,7 +27828,7 @@ function serveHostfsPort(port, transport) {
|
|
|
27137
27828
|
);
|
|
27138
27829
|
send2({ id: id2, end: true });
|
|
27139
27830
|
} catch (err) {
|
|
27140
|
-
send2({ id: id2, error:
|
|
27831
|
+
send2({ id: id2, error: errorOf2(err) });
|
|
27141
27832
|
} finally {
|
|
27142
27833
|
watches.delete(id2);
|
|
27143
27834
|
}
|
|
@@ -27165,7 +27856,7 @@ function serveHostfsPort(port, transport) {
|
|
|
27165
27856
|
if (op !== "call") throw fsError2("EINVAL", `unknown hostfs port op ${op}`);
|
|
27166
27857
|
send2({ id: id2, result: await answer2(data.name, data.body) });
|
|
27167
27858
|
} catch (err) {
|
|
27168
|
-
send2({ id: id2, error:
|
|
27859
|
+
send2({ id: id2, error: errorOf2(err) });
|
|
27169
27860
|
}
|
|
27170
27861
|
};
|
|
27171
27862
|
const stop = () => {
|
|
@@ -27798,7 +28489,7 @@ function homeModeOf(mode) {
|
|
|
27798
28489
|
}
|
|
27799
28490
|
return mode;
|
|
27800
28491
|
}
|
|
27801
|
-
function
|
|
28492
|
+
function joined4(name2, rows) {
|
|
27802
28493
|
let changed = false;
|
|
27803
28494
|
for (const g of rows) {
|
|
27804
28495
|
if (g.members.includes(name2)) continue;
|
|
@@ -27985,7 +28676,7 @@ var UserDb = class {
|
|
|
27985
28676
|
await this.provision(found, this.umaskFor(options), shared);
|
|
27986
28677
|
await this.stampHome(found, shared, homeMode);
|
|
27987
28678
|
}
|
|
27988
|
-
if (
|
|
28679
|
+
if (joined4(name2, more)) await this.fs.writeFile(GROUP, formatGroup(group));
|
|
27989
28680
|
remember();
|
|
27990
28681
|
return this.account(found, groups);
|
|
27991
28682
|
}
|
|
@@ -27994,10 +28685,10 @@ var UserDb = class {
|
|
|
27994
28685
|
if (groups.some((r) => r.name === name2)) throw fsError("EEXIST", `group ${name2} exists`);
|
|
27995
28686
|
const uid = freeId(users, groups);
|
|
27996
28687
|
const row = { name: name2, uid, gid: uid, gecos: name2, home, shell: "/bin/bash" };
|
|
27997
|
-
|
|
28688
|
+
joined4(name2, extra);
|
|
27998
28689
|
group.push({ name: name2, gid: uid, members: [] });
|
|
27999
28690
|
passwd.push(row);
|
|
28000
|
-
const
|
|
28691
|
+
const fresh3 = !await this.fs.exists(home);
|
|
28001
28692
|
await this.fs.mkdir(home, { recursive: true });
|
|
28002
28693
|
try {
|
|
28003
28694
|
await this.provision(row, this.umaskFor(options), shared);
|
|
@@ -28005,7 +28696,7 @@ var UserDb = class {
|
|
|
28005
28696
|
await this.fs.mkdir("/etc", { recursive: true });
|
|
28006
28697
|
await this.commit(formatPasswd(passwd), formatGroup(group));
|
|
28007
28698
|
} catch (err) {
|
|
28008
|
-
if (
|
|
28699
|
+
if (fresh3) await this.fs.rm(home, { recursive: true, force: true });
|
|
28009
28700
|
throw err;
|
|
28010
28701
|
}
|
|
28011
28702
|
remember();
|
|
@@ -28383,12 +29074,12 @@ ${lines2}
|
|
|
28383
29074
|
const timer = setTimeout(() => control.abort("expired"), timeout);
|
|
28384
29075
|
const withdraw = () => control.abort("withdrawn");
|
|
28385
29076
|
requester.addEventListener("abort", withdraw, { once: true });
|
|
28386
|
-
const
|
|
29077
|
+
const aborted3 = new Promise(
|
|
28387
29078
|
(resolve2) => control.signal.addEventListener("abort", () => resolve2("aborted"), { once: true })
|
|
28388
29079
|
);
|
|
28389
29080
|
try {
|
|
28390
29081
|
const answered = Promise.resolve().then(() => approve(req, { signal: control.signal })).catch(() => "deny");
|
|
28391
|
-
const answer2 = await Promise.race([answered,
|
|
29082
|
+
const answer2 = await Promise.race([answered, aborted3]);
|
|
28392
29083
|
if (answer2 === "aborted" || control.signal.aborted) {
|
|
28393
29084
|
return control.signal.reason === "expired" ? failed2("ETIMEDOUT", "sudo: the request expired") : failed2("EINTR", "sudo: the request was withdrawn");
|
|
28394
29085
|
}
|
|
@@ -28514,6 +29205,7 @@ var SUDO_SOURCE = [
|
|
|
28514
29205
|
].join("\n");
|
|
28515
29206
|
|
|
28516
29207
|
// src/launcher.ts
|
|
29208
|
+
var NO_SESSION = { client: -1, uid: -1 };
|
|
28517
29209
|
var MODULE_URLS = 16;
|
|
28518
29210
|
function dataModuleUrl(source) {
|
|
28519
29211
|
const bytes = new TextEncoder().encode(source);
|
|
@@ -28772,6 +29464,7 @@ var Launcher = class {
|
|
|
28772
29464
|
described = /* @__PURE__ */ new Map();
|
|
28773
29465
|
creds = /* @__PURE__ */ new Map();
|
|
28774
29466
|
tags = /* @__PURE__ */ new Map();
|
|
29467
|
+
sessions = /* @__PURE__ */ new Map();
|
|
28775
29468
|
tagBases = /* @__PURE__ */ new Map();
|
|
28776
29469
|
links = /* @__PURE__ */ new Map();
|
|
28777
29470
|
freshModules = new FreshModules();
|
|
@@ -28832,6 +29525,7 @@ var Launcher = class {
|
|
|
28832
29525
|
sealed;
|
|
28833
29526
|
scrubs = /* @__PURE__ */ new Map();
|
|
28834
29527
|
clipboard;
|
|
29528
|
+
embedder;
|
|
28835
29529
|
rootFs;
|
|
28836
29530
|
fileWatches;
|
|
28837
29531
|
nextPid = 1e3;
|
|
@@ -28853,14 +29547,14 @@ var Launcher = class {
|
|
|
28853
29547
|
void 0,
|
|
28854
29548
|
(pid) => this.tagsOf(pid)
|
|
28855
29549
|
);
|
|
29550
|
+
this.embedder = this.embedderBroker(options.embedder);
|
|
28856
29551
|
this.sealed = new SealedBroker(
|
|
28857
29552
|
options.sealed,
|
|
28858
29553
|
this.usersMode,
|
|
28859
29554
|
void 0,
|
|
28860
29555
|
(pid) => this.tagsOf(pid)
|
|
28861
29556
|
);
|
|
28862
|
-
this.
|
|
28863
|
-
this.sealed.userOf = async (uid) => (await this.users.lookup(uid))?.name;
|
|
29557
|
+
this.wireSealed();
|
|
28864
29558
|
if (this.owners) options.fs.trackOwners?.();
|
|
28865
29559
|
this.watchers.tap((paths) => {
|
|
28866
29560
|
this.changes.publish(...paths);
|
|
@@ -29921,6 +30615,8 @@ var Launcher = class {
|
|
|
29921
30615
|
}
|
|
29922
30616
|
marks(pid, req) {
|
|
29923
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);
|
|
29924
30620
|
if (req.tags?.length) this.tagBases.set(pid, req.tagBase ?? req.tags.length);
|
|
29925
30621
|
if (req.links !== void 0) this.links.set(pid, req.links);
|
|
29926
30622
|
}
|
|
@@ -30000,6 +30696,7 @@ var Launcher = class {
|
|
|
30000
30696
|
sealed: this.sealed,
|
|
30001
30697
|
...scrubs ? { outputFilter: (file) => scrubbedAll(file, scrubs) } : {},
|
|
30002
30698
|
clipboard: this.clipboard,
|
|
30699
|
+
embedder: { broker: this.embedder, session: () => this.sessionOf(pid) },
|
|
30003
30700
|
...this.dac ? { dac: this.dac } : {},
|
|
30004
30701
|
program: req.program,
|
|
30005
30702
|
changes: this.changes.sab,
|
|
@@ -30128,6 +30825,7 @@ var Launcher = class {
|
|
|
30128
30825
|
this.childTimes.delete(pid);
|
|
30129
30826
|
this.creds.delete(pid);
|
|
30130
30827
|
this.tags.delete(pid);
|
|
30828
|
+
this.sessions.delete(pid);
|
|
30131
30829
|
this.tagBases.delete(pid);
|
|
30132
30830
|
this.links.delete(pid);
|
|
30133
30831
|
this.granted.delete(pid);
|
|
@@ -30173,8 +30871,8 @@ var Launcher = class {
|
|
|
30173
30871
|
this.sampledAt = Math.max(this.sampledAt, now);
|
|
30174
30872
|
this.load = this.load.map((avg, i) => {
|
|
30175
30873
|
const window = LOAD_WINDOWS_MS[i];
|
|
30176
|
-
const
|
|
30177
|
-
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;
|
|
30178
30876
|
});
|
|
30179
30877
|
}
|
|
30180
30878
|
idleSince;
|
|
@@ -30404,7 +31102,7 @@ var Launcher = class {
|
|
|
30404
31102
|
forker(ppid, parent) {
|
|
30405
31103
|
const { exec: _exec, pgid: _pgid, group: _group, pid: _pid, scrub: _scrub, ...image } = parent;
|
|
30406
31104
|
return async (state, given) => {
|
|
30407
|
-
const
|
|
31105
|
+
const fresh3 = (fds, quietOom) => this.start({
|
|
30408
31106
|
...image,
|
|
30409
31107
|
quietOom,
|
|
30410
31108
|
cwd: state.cwd ?? parent.cwd,
|
|
@@ -30420,7 +31118,7 @@ var Launcher = class {
|
|
|
30420
31118
|
tagBase: this.tagBases.get(ppid),
|
|
30421
31119
|
links: this.links.get(ppid)
|
|
30422
31120
|
});
|
|
30423
|
-
return childHandle(await this.admitted(parent.program.abi !== "js", given,
|
|
31121
|
+
return childHandle(await this.admitted(parent.program.abi !== "js", given, fresh3));
|
|
30424
31122
|
};
|
|
30425
31123
|
}
|
|
30426
31124
|
keySignal(tty, fallback, sig, send2) {
|
|
@@ -30456,6 +31154,25 @@ var Launcher = class {
|
|
|
30456
31154
|
credOf(pid) {
|
|
30457
31155
|
return this.creds.get(pid)?.() ?? copyCred(ROOT);
|
|
30458
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
|
+
}
|
|
30459
31176
|
tagOf(pid) {
|
|
30460
31177
|
return this.tags.get(pid)?.[0];
|
|
30461
31178
|
}
|
|
@@ -30727,8 +31444,8 @@ var Launcher = class {
|
|
|
30727
31444
|
for (const [path, mode] of layout) {
|
|
30728
31445
|
if (isProtected(this.prefixes, normalizePath(path))) continue;
|
|
30729
31446
|
const real = await this.realLayoutPath(path);
|
|
30730
|
-
const
|
|
30731
|
-
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 });
|
|
30732
31449
|
}
|
|
30733
31450
|
}
|
|
30734
31451
|
async realLayoutPath(given) {
|
|
@@ -30901,9 +31618,10 @@ var Launcher = class {
|
|
|
30901
31618
|
if (!found) throw fsError("ENOENT", `no user ${String(user)}`);
|
|
30902
31619
|
return found;
|
|
30903
31620
|
}
|
|
30904
|
-
identity(account, given) {
|
|
31621
|
+
identity(account, given, session = 0) {
|
|
30905
31622
|
return {
|
|
30906
31623
|
...given,
|
|
31624
|
+
session: { client: session, uid: account.uid },
|
|
30907
31625
|
cred: credOf(account),
|
|
30908
31626
|
...account.umask !== void 0 ? { umask: account.umask } : {}
|
|
30909
31627
|
};
|
|
@@ -31090,7 +31808,7 @@ var Launcher = class {
|
|
|
31090
31808
|
cwd,
|
|
31091
31809
|
fds,
|
|
31092
31810
|
report,
|
|
31093
|
-
...this.identity(account, tagged)
|
|
31811
|
+
...this.identity(account, tagged, options.session)
|
|
31094
31812
|
});
|
|
31095
31813
|
leader = handle.pid;
|
|
31096
31814
|
void handle.exited.then(() => tty.hangup());
|
|
@@ -31147,7 +31865,7 @@ var Launcher = class {
|
|
|
31147
31865
|
fds,
|
|
31148
31866
|
report,
|
|
31149
31867
|
...group,
|
|
31150
|
-
...this.identity(account, tagged)
|
|
31868
|
+
...this.identity(account, tagged, options.session)
|
|
31151
31869
|
});
|
|
31152
31870
|
options.onStarted?.(handle.pid);
|
|
31153
31871
|
const status = await handle.exited;
|
|
@@ -31590,7 +32308,7 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS3 } = {})
|
|
|
31590
32308
|
}
|
|
31591
32309
|
|
|
31592
32310
|
// src/client/protocol.ts
|
|
31593
|
-
var PROTOCOL = [1,
|
|
32311
|
+
var PROTOCOL = [1, 13];
|
|
31594
32312
|
var FS_METHODS = [
|
|
31595
32313
|
"readFile",
|
|
31596
32314
|
"writeFile",
|
|
@@ -31757,14 +32475,15 @@ async function runAs(l, self, requested) {
|
|
|
31757
32475
|
function clientCred(self) {
|
|
31758
32476
|
return self ? credOf(self) : copyCred(ROOT);
|
|
31759
32477
|
}
|
|
31760
|
-
async function runTagged(l, self, options, tag) {
|
|
32478
|
+
async function runTagged(l, self, options, tag, session = -1) {
|
|
31761
32479
|
tagOption(options.tag);
|
|
31762
32480
|
const tags = withTag(withTag(void 0, tag), options.tag);
|
|
31763
32481
|
return {
|
|
31764
32482
|
user: await runAs(l, self, options.user),
|
|
31765
32483
|
tag,
|
|
31766
32484
|
tags,
|
|
31767
|
-
tagBase: tag === void 0 ? 0 : 1
|
|
32485
|
+
tagBase: tag === void 0 ? 0 : 1,
|
|
32486
|
+
session
|
|
31768
32487
|
};
|
|
31769
32488
|
}
|
|
31770
32489
|
function processes(l, self) {
|
|
@@ -31845,10 +32564,12 @@ function facadeRegistry(send2, gone) {
|
|
|
31845
32564
|
}
|
|
31846
32565
|
};
|
|
31847
32566
|
}
|
|
31848
|
-
function hostRegistries(send2, gone) {
|
|
32567
|
+
function hostRegistries(send2, gone, port) {
|
|
31849
32568
|
const cdps = cdpRegistry(send2, gone);
|
|
31850
32569
|
const facades = facadeRegistry(send2, gone);
|
|
32570
|
+
const requests = requestBinding(send2, port);
|
|
31851
32571
|
return {
|
|
32572
|
+
requests,
|
|
31852
32573
|
answer(l, req) {
|
|
31853
32574
|
if (req.op === "serve-cdp") return cdps.serve(l, req);
|
|
31854
32575
|
if (req.op === "unserve-cdp") return cdps.drop(req.registration);
|
|
@@ -31856,6 +32577,7 @@ function hostRegistries(send2, gone) {
|
|
|
31856
32577
|
return facades.drop(req.registration);
|
|
31857
32578
|
},
|
|
31858
32579
|
close() {
|
|
32580
|
+
requests.close();
|
|
31859
32581
|
cdps.close();
|
|
31860
32582
|
facades.close();
|
|
31861
32583
|
}
|
|
@@ -31890,6 +32612,28 @@ var TRAITS_WATCH = -1;
|
|
|
31890
32612
|
function traitsWatch(launcher, transport, send2) {
|
|
31891
32613
|
return launcher.onTraits(() => send2({ traits: transport.traits }));
|
|
31892
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
|
+
}
|
|
31893
32637
|
function serveClient(port, host) {
|
|
31894
32638
|
let state = "new";
|
|
31895
32639
|
let self;
|
|
@@ -31904,7 +32648,7 @@ function serveClient(port, host) {
|
|
|
31904
32648
|
if (state !== "closed") port.postMessage(message3, transfer);
|
|
31905
32649
|
};
|
|
31906
32650
|
const reply = (id2, body, transfer) => send2({ id: id2, ...body }, transfer);
|
|
31907
|
-
const hosts = hostRegistries(send2, ended.promise);
|
|
32651
|
+
const hosts = hostRegistries(send2, ended.promise, port);
|
|
31908
32652
|
function detach(kill = false, bye = "the slicc-kernel detached this client") {
|
|
31909
32653
|
if (state === "closed") return;
|
|
31910
32654
|
send2({ bye });
|
|
@@ -31921,7 +32665,7 @@ function serveClient(port, host) {
|
|
|
31921
32665
|
ended.resolve();
|
|
31922
32666
|
}
|
|
31923
32667
|
async function hello(message3) {
|
|
31924
|
-
const refused3 = versionError(message3.protocol);
|
|
32668
|
+
const refused3 = versionError(message3.protocol) ?? await hosts.requests.accept(host, message3);
|
|
31925
32669
|
if (refused3) {
|
|
31926
32670
|
send2({ hello: { protocol: PROTOCOL, error: refused3 } });
|
|
31927
32671
|
detach();
|
|
@@ -31946,7 +32690,7 @@ function serveClient(port, host) {
|
|
|
31946
32690
|
async function terminal(req, l) {
|
|
31947
32691
|
const session = await l.openTerminal(req.argv, {
|
|
31948
32692
|
...req.options,
|
|
31949
|
-
...await runTagged(l, self, req.options, host.tag),
|
|
32693
|
+
...await runTagged(l, self, req.options, host.tag, host.session),
|
|
31950
32694
|
onData: (bytes) => reply(req.id, { fd: 1, bytes: bytes.slice() })
|
|
31951
32695
|
});
|
|
31952
32696
|
if (state === "closed") {
|
|
@@ -31969,7 +32713,7 @@ function serveClient(port, host) {
|
|
|
31969
32713
|
let leader;
|
|
31970
32714
|
const result = await l.run(req.argv, {
|
|
31971
32715
|
...req.options,
|
|
31972
|
-
...await runTagged(l, self, req.options, host.tag),
|
|
32716
|
+
...await runTagged(l, self, req.options, host.tag, host.session),
|
|
31973
32717
|
collect: false,
|
|
31974
32718
|
onStdout: out(1),
|
|
31975
32719
|
onStderr: out(2),
|
|
@@ -32149,11 +32893,11 @@ function guarded2(check, signal) {
|
|
|
32149
32893
|
signal.throwIfAborted();
|
|
32150
32894
|
let stop = () => {
|
|
32151
32895
|
};
|
|
32152
|
-
const
|
|
32896
|
+
const aborted3 = new Promise((_, reject) => {
|
|
32153
32897
|
stop = () => reject(signal.reason);
|
|
32154
32898
|
signal.addEventListener("abort", stop, { once: true });
|
|
32155
32899
|
});
|
|
32156
|
-
return Promise.race([check,
|
|
32900
|
+
return Promise.race([check, aborted3]).finally(() => signal.removeEventListener("abort", stop));
|
|
32157
32901
|
}
|
|
32158
32902
|
var loopbackStore = new AsyncLocalStorage();
|
|
32159
32903
|
var subscribed = false;
|
|
@@ -32268,7 +33012,7 @@ function valid(name2) {
|
|
|
32268
33012
|
}
|
|
32269
33013
|
}
|
|
32270
33014
|
var CHUNK4 = 1024 * 1024;
|
|
32271
|
-
function
|
|
33015
|
+
function bytesOf3(data) {
|
|
32272
33016
|
if (typeof data === "string") return new TextEncoder().encode(data);
|
|
32273
33017
|
if (data instanceof Blob) return data.arrayBuffer().then((buffer) => new Uint8Array(buffer));
|
|
32274
33018
|
if (ArrayBuffer.isView(data)) {
|
|
@@ -32348,7 +33092,7 @@ var MemoryFile = class {
|
|
|
32348
33092
|
const next3 = keepExistingData ? new Chunks([...this.data.blobs], this.data.size) : new Chunks();
|
|
32349
33093
|
let position = 0;
|
|
32350
33094
|
const put = async (data) => {
|
|
32351
|
-
const bytes = await
|
|
33095
|
+
const bytes = await bytesOf3(data);
|
|
32352
33096
|
await next3.write(position, bytes);
|
|
32353
33097
|
position += bytes.length;
|
|
32354
33098
|
};
|
|
@@ -32480,11 +33224,11 @@ function abortable(work, signal) {
|
|
|
32480
33224
|
if (signal.aborted) return Promise.reject(signal.reason);
|
|
32481
33225
|
let stop = () => {
|
|
32482
33226
|
};
|
|
32483
|
-
const
|
|
33227
|
+
const aborted3 = new Promise((_, reject) => {
|
|
32484
33228
|
stop = () => reject(signal.reason);
|
|
32485
33229
|
signal.addEventListener("abort", stop, { once: true });
|
|
32486
33230
|
});
|
|
32487
|
-
return Promise.race([work,
|
|
33231
|
+
return Promise.race([work, aborted3]).finally(() => signal.removeEventListener("abort", stop));
|
|
32488
33232
|
}
|
|
32489
33233
|
function probe(secure2, host, port, ms, signal) {
|
|
32490
33234
|
return new Promise((resolve2) => {
|
|
@@ -32843,10 +33587,10 @@ var ByteSource = class {
|
|
|
32843
33587
|
async more() {
|
|
32844
33588
|
const { done: done4, value: value2 } = await this.reader.read();
|
|
32845
33589
|
if (done4) return false;
|
|
32846
|
-
const
|
|
32847
|
-
|
|
32848
|
-
|
|
32849
|
-
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;
|
|
32850
33594
|
return true;
|
|
32851
33595
|
}
|
|
32852
33596
|
async until(marker) {
|
|
@@ -33013,7 +33757,7 @@ var KernelCallError = class extends Error {
|
|
|
33013
33757
|
}
|
|
33014
33758
|
};
|
|
33015
33759
|
var encoder12 = new TextEncoder();
|
|
33016
|
-
var
|
|
33760
|
+
var bytesOf4 = (data) => typeof data === "string" ? encoder12.encode(data) : data;
|
|
33017
33761
|
var UNAVAILABLE = {
|
|
33018
33762
|
manualRedirects: false,
|
|
33019
33763
|
encodedBodies: false,
|
|
@@ -33097,7 +33841,9 @@ var Channel = class {
|
|
|
33097
33841
|
call(call) {
|
|
33098
33842
|
return this.request(call).done;
|
|
33099
33843
|
}
|
|
33844
|
+
requests;
|
|
33100
33845
|
receive(data) {
|
|
33846
|
+
if (this.requests?.handle(data)) return;
|
|
33101
33847
|
if (data.traits && data.id === void 0) {
|
|
33102
33848
|
if (this.remote) this.remote.traits = data.traits;
|
|
33103
33849
|
for (const listener of [...this.traitsListeners]) listener(data.traits);
|
|
@@ -33220,7 +33966,7 @@ async function spawnOn(channel, argv, opts) {
|
|
|
33220
33966
|
});
|
|
33221
33967
|
const started = Promise.withResolvers();
|
|
33222
33968
|
let endedBy;
|
|
33223
|
-
const options = { ...rest2, ...stdin !== void 0 ? { stdin:
|
|
33969
|
+
const options = { ...rest2, ...stdin !== void 0 ? { stdin: bytesOf4(stdin) } : {} };
|
|
33224
33970
|
const { done: done4 } = channel.request(
|
|
33225
33971
|
{ op: "spawn", argv, options },
|
|
33226
33972
|
{
|
|
@@ -33303,7 +34049,7 @@ async function terminalOn(channel, argv, opts) {
|
|
|
33303
34049
|
listener = next3;
|
|
33304
34050
|
if (next3) for (const bytes of backlog.splice(0)) next3(bytes);
|
|
33305
34051
|
},
|
|
33306
|
-
write: (data) => send2({ action: "write", bytes:
|
|
34052
|
+
write: (data) => send2({ action: "write", bytes: bytesOf4(data) }),
|
|
33307
34053
|
resize: (cols, rows) => send2({ action: "resize", cols, rows }),
|
|
33308
34054
|
signal: (name2) => send2({ action: "signal", signal: name2 }),
|
|
33309
34055
|
close: () => send2({ action: "close" })
|
|
@@ -33365,8 +34111,10 @@ function since(channel, minor, what, run2) {
|
|
|
33365
34111
|
}
|
|
33366
34112
|
return run2();
|
|
33367
34113
|
}
|
|
33368
|
-
async function greet(channel, lock, timeoutMs) {
|
|
33369
|
-
channel.post({
|
|
34114
|
+
async function greet(channel, lock, timeoutMs, requests) {
|
|
34115
|
+
channel.post({
|
|
34116
|
+
hello: { protocol: PROTOCOL, ...lock ? { lock } : {}, ...requests ? { requests } : {} }
|
|
34117
|
+
});
|
|
33370
34118
|
const timer = setTimeout(
|
|
33371
34119
|
() => channel.end(
|
|
33372
34120
|
new KernelGoneError(`no slicc-kernel answered on this port within ${timeoutMs} ms`)
|
|
@@ -33391,7 +34139,14 @@ async function attachKernel(port, options = {}) {
|
|
|
33391
34139
|
const locks = options.locks === null ? void 0 : options.locks ?? locksOf();
|
|
33392
34140
|
const own = await holdLock(locks);
|
|
33393
34141
|
const channel = new Channel(port, own.release);
|
|
33394
|
-
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
|
+
);
|
|
33395
34150
|
channel.protocol = hello.protocol;
|
|
33396
34151
|
if (hello.lock && locks) void locks.request(hello.lock, () => channel.end(new KernelGoneError()));
|
|
33397
34152
|
const transport = new RemoteTransport(
|
|
@@ -33605,6 +34360,31 @@ function cacheDirOf(dir) {
|
|
|
33605
34360
|
}
|
|
33606
34361
|
return dir;
|
|
33607
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
|
+
}
|
|
33608
34388
|
async function createNodeKernel(options = {}) {
|
|
33609
34389
|
const root = options.root ?? memoryRoot();
|
|
33610
34390
|
const fs = new OpfsFs(root, void 0, void 0, { ranged: isMemoryRoot(root) });
|
|
@@ -33645,6 +34425,7 @@ async function createNodeKernel(options = {}) {
|
|
|
33645
34425
|
...options.protect ? { protect: options.protect } : {},
|
|
33646
34426
|
...options.sealed ? { sealed: options.sealed } : {},
|
|
33647
34427
|
...options.clipboard ? { clipboard: options.clipboard } : {},
|
|
34428
|
+
...options.requests ? { embedder: checkedRequests(options.requests) } : {},
|
|
33648
34429
|
...options.approve ? { approve: options.approve } : {},
|
|
33649
34430
|
...options.wasmMemories ? { wasmMemories: options.wasmMemories } : {},
|
|
33650
34431
|
cron: { lock: cronLock(root), ...options.cron?.clock ? { clock: options.cron.clock } : {} }
|
|
@@ -33735,22 +34516,13 @@ async function createNodeKernel(options = {}) {
|
|
|
33735
34516
|
addMember: (group, user) => guard2(() => launcher.users.addMember(group, user)),
|
|
33736
34517
|
removeMember: (group, user) => guard2(() => launcher.users.removeMember(group, user))
|
|
33737
34518
|
},
|
|
33738
|
-
async connect(
|
|
34519
|
+
async connect(connectOptions = {}) {
|
|
33739
34520
|
if (terminated) throw new Error(TERMINATED);
|
|
33740
|
-
|
|
34521
|
+
const { user } = connectOptions;
|
|
33741
34522
|
if (user !== void 0 && !await guard2(() => launcher.users.lookup(user))) {
|
|
33742
34523
|
throw fsError("ENOENT", `no user ${String(user)}`);
|
|
33743
34524
|
}
|
|
33744
|
-
|
|
33745
|
-
const served2 = serveClient(port1, {
|
|
33746
|
-
launcher: async () => launcher,
|
|
33747
|
-
signal: signalNumber,
|
|
33748
|
-
...user !== void 0 ? { user } : {},
|
|
33749
|
-
...tag !== void 0 ? { tag } : {}
|
|
33750
|
-
});
|
|
33751
|
-
clients.add(served2);
|
|
33752
|
-
void served2.closed.then(() => clients.delete(served2));
|
|
33753
|
-
return port2;
|
|
34525
|
+
return nodeClient(launcher, clients, connectOptions);
|
|
33754
34526
|
},
|
|
33755
34527
|
terminate() {
|
|
33756
34528
|
terminated = true;
|