@ai-ecoverse/slicc-kernel 1.15.1 → 1.16.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 +12 -1
- package/dist/index.js +15 -2
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +463 -65
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +4 -0
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +441 -62
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +4 -0
- package/dist/process-worker.js.map +2 -2
- package/package.json +2 -1
package/dist/node.js
CHANGED
|
@@ -1067,9 +1067,9 @@ var OpfsFs = class {
|
|
|
1067
1067
|
var NAME = /^[A-Za-z0-9._+-]+$/;
|
|
1068
1068
|
var ENV_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
1069
1069
|
var PACKAGE = /\$\{package\}/g;
|
|
1070
|
-
function inside(pkg,
|
|
1071
|
-
if (typeof
|
|
1072
|
-
const clean =
|
|
1070
|
+
function inside(pkg, rel2) {
|
|
1071
|
+
if (typeof rel2 !== "string" || rel2 === "") return void 0;
|
|
1072
|
+
const clean = rel2.replace(/^\.\//, "");
|
|
1073
1073
|
if (clean.startsWith("/") || clean.split("/").includes("..")) return void 0;
|
|
1074
1074
|
return `${pkg}/${clean}`;
|
|
1075
1075
|
}
|
|
@@ -5911,6 +5911,57 @@ function serveFilesystem(port, handlers, capabilities = {}) {
|
|
|
5911
5911
|
return { invalidate: (paths) => reply({ invalidate: paths }) };
|
|
5912
5912
|
}
|
|
5913
5913
|
|
|
5914
|
+
// src/mount/medium.ts
|
|
5915
|
+
var EMPTY_ROOT = { kind: "directory", size: 0, mtime: 0, mode: 16877 };
|
|
5916
|
+
var absent = () => fsError2("ENOMEDIUM", "No medium found");
|
|
5917
|
+
function mediumSlot(lost, onLost) {
|
|
5918
|
+
let current;
|
|
5919
|
+
function wrap(pick) {
|
|
5920
|
+
return async (...args) => {
|
|
5921
|
+
const medium = current;
|
|
5922
|
+
if (!medium) throw absent();
|
|
5923
|
+
try {
|
|
5924
|
+
return await pick(medium.handlers)(...args);
|
|
5925
|
+
} catch (err) {
|
|
5926
|
+
if (!await lost(err, medium.key)) throw err;
|
|
5927
|
+
if (current === medium) {
|
|
5928
|
+
current = void 0;
|
|
5929
|
+
onLost(medium.key);
|
|
5930
|
+
}
|
|
5931
|
+
throw absent();
|
|
5932
|
+
}
|
|
5933
|
+
};
|
|
5934
|
+
}
|
|
5935
|
+
const getattr = wrap((h) => h.getattr);
|
|
5936
|
+
const readdir = wrap((h) => h.readdir);
|
|
5937
|
+
const statfs = wrap((h) => async () => await h.statfs?.() ?? null);
|
|
5938
|
+
return {
|
|
5939
|
+
handlers: {
|
|
5940
|
+
getattr: (path) => current || path !== "/" ? getattr(path) : Promise.resolve(EMPTY_ROOT),
|
|
5941
|
+
readdir: (path) => current || path !== "/" ? readdir(path) : Promise.resolve([]),
|
|
5942
|
+
open: wrap((h) => h.open),
|
|
5943
|
+
read: wrap((h) => h.read),
|
|
5944
|
+
write: wrap((h) => h.write),
|
|
5945
|
+
release: wrap((h) => h.release),
|
|
5946
|
+
mkdir: wrap((h) => h.mkdir),
|
|
5947
|
+
rmdir: wrap((h) => h.rmdir),
|
|
5948
|
+
unlink: wrap((h) => h.unlink),
|
|
5949
|
+
rename: wrap((h) => h.rename),
|
|
5950
|
+
symlink: wrap((h) => h.symlink),
|
|
5951
|
+
readlink: wrap((h) => h.readlink),
|
|
5952
|
+
setattr: wrap((h) => h.setattr),
|
|
5953
|
+
statfs: () => current ? statfs() : Promise.resolve(null)
|
|
5954
|
+
},
|
|
5955
|
+
present: () => current !== void 0,
|
|
5956
|
+
insert(key, handlers) {
|
|
5957
|
+
current = { key, handlers };
|
|
5958
|
+
},
|
|
5959
|
+
eject() {
|
|
5960
|
+
current = void 0;
|
|
5961
|
+
}
|
|
5962
|
+
};
|
|
5963
|
+
}
|
|
5964
|
+
|
|
5914
5965
|
// src/mount/fsa.ts
|
|
5915
5966
|
var FSA_CAPABILITIES = { listingStats: true };
|
|
5916
5967
|
var codeOf = (err) => err?.code;
|
|
@@ -5998,7 +6049,6 @@ function kernelFsHandlers(fs) {
|
|
|
5998
6049
|
}
|
|
5999
6050
|
};
|
|
6000
6051
|
}
|
|
6001
|
-
var EMPTY_ROOT = { kind: "directory", size: 0, mtime: 0, mode: 16877 };
|
|
6002
6052
|
function granted(handle) {
|
|
6003
6053
|
if (!handle.queryPermission) return Promise.resolve(true);
|
|
6004
6054
|
return handle.queryPermission({ mode: "readwrite" }).then(
|
|
@@ -6007,48 +6057,345 @@ function granted(handle) {
|
|
|
6007
6057
|
);
|
|
6008
6058
|
}
|
|
6009
6059
|
function removableMedium(onLost, open = (handle) => new OpfsFs(handle)) {
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
6060
|
+
const slot = mediumSlot(
|
|
6061
|
+
async (err, handle) => denied(err) && !await granted(handle),
|
|
6062
|
+
onLost
|
|
6063
|
+
);
|
|
6064
|
+
return {
|
|
6065
|
+
handlers: slot.handlers,
|
|
6066
|
+
present: slot.present,
|
|
6067
|
+
insert: (handle) => slot.insert(handle, kernelFsHandlers(open(handle))),
|
|
6068
|
+
eject: slot.eject
|
|
6069
|
+
};
|
|
6070
|
+
}
|
|
6071
|
+
|
|
6072
|
+
// src/mount/hostfs.ts
|
|
6073
|
+
var HOSTFS_IO = 16 * 1024 * 1024;
|
|
6074
|
+
var codeOf2 = (err) => err?.code;
|
|
6075
|
+
var unreachable = (err) => codeOf2(err) === "ENOTCONN";
|
|
6076
|
+
function rel(path) {
|
|
6077
|
+
return path.replace(/^\/+/, "");
|
|
6078
|
+
}
|
|
6079
|
+
var HostfsClient = class {
|
|
6080
|
+
grant;
|
|
6081
|
+
regrant;
|
|
6082
|
+
fetch;
|
|
6083
|
+
constructor(grant, regrant, fetch2) {
|
|
6084
|
+
this.grant = grant;
|
|
6085
|
+
this.regrant = regrant;
|
|
6086
|
+
this.fetch = fetch2;
|
|
6087
|
+
}
|
|
6088
|
+
get capabilities() {
|
|
6089
|
+
return this.grant.capabilities ?? {};
|
|
6090
|
+
}
|
|
6091
|
+
get token() {
|
|
6092
|
+
return this.grant.token;
|
|
6093
|
+
}
|
|
6094
|
+
get maxIo() {
|
|
6095
|
+
return this.capabilities.maxIo ?? HOSTFS_IO;
|
|
6096
|
+
}
|
|
6097
|
+
async send(path, init, handle = false, retried = false) {
|
|
6098
|
+
let response;
|
|
6099
|
+
try {
|
|
6100
|
+
response = await this.fetch(`${this.grant.url}${path}`, {
|
|
6101
|
+
...init,
|
|
6102
|
+
credentials: "omit",
|
|
6103
|
+
headers: {
|
|
6104
|
+
...init.headers,
|
|
6105
|
+
"X-Hostfs-Token": this.grant.token
|
|
6023
6106
|
}
|
|
6024
|
-
|
|
6107
|
+
});
|
|
6108
|
+
} catch (err) {
|
|
6109
|
+
throw fsError2("ENOTCONN", `the host proxy is unreachable: ${err.message}`);
|
|
6110
|
+
}
|
|
6111
|
+
if (response.ok) return response;
|
|
6112
|
+
if (response.headers.get("X-Proxy-Error")) {
|
|
6113
|
+
await response.body?.cancel();
|
|
6114
|
+
if (retried || response.status !== 403) {
|
|
6115
|
+
throw fsError2("EACCES", `the host proxy refused this folder (${response.status})`);
|
|
6025
6116
|
}
|
|
6026
|
-
|
|
6117
|
+
this.grant = await this.regrant();
|
|
6118
|
+
if (handle)
|
|
6119
|
+
throw fsError2("ESTALE", "the folder was granted again, so its open files are gone");
|
|
6120
|
+
return this.send(path, init, false, true);
|
|
6121
|
+
}
|
|
6122
|
+
const errno = response.headers.get("X-Hostfs-Errno") ?? "EIO";
|
|
6123
|
+
const body = await response.json().catch(() => ({}));
|
|
6124
|
+
throw fsError2(errno, typeof body.message === "string" ? body.message : errno);
|
|
6125
|
+
}
|
|
6126
|
+
async call(op, body = {}, handle = false) {
|
|
6127
|
+
const response = await this.send(
|
|
6128
|
+
"/api/hostfs",
|
|
6129
|
+
{
|
|
6130
|
+
method: "POST",
|
|
6131
|
+
headers: { "Content-Type": "application/json" },
|
|
6132
|
+
body: JSON.stringify({ op, ...body })
|
|
6133
|
+
},
|
|
6134
|
+
handle
|
|
6135
|
+
);
|
|
6136
|
+
return await response.json();
|
|
6137
|
+
}
|
|
6138
|
+
async read(fh, offset, size, ifMatch) {
|
|
6139
|
+
const response = await this.send(
|
|
6140
|
+
"/api/hostfs",
|
|
6141
|
+
{
|
|
6142
|
+
method: "POST",
|
|
6143
|
+
headers: { "Content-Type": "application/json" },
|
|
6144
|
+
body: JSON.stringify({ op: "read", fh, offset, size, ...ifMatch ? { ifMatch } : {} })
|
|
6145
|
+
},
|
|
6146
|
+
true
|
|
6147
|
+
);
|
|
6148
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
6149
|
+
}
|
|
6150
|
+
async write(fh, offset, bytes) {
|
|
6151
|
+
const response = await this.send(
|
|
6152
|
+
"/api/hostfs/write",
|
|
6153
|
+
{
|
|
6154
|
+
method: "PUT",
|
|
6155
|
+
headers: {
|
|
6156
|
+
"Content-Type": "application/octet-stream",
|
|
6157
|
+
"X-Hostfs-Request": JSON.stringify({ fh, offset })
|
|
6158
|
+
},
|
|
6159
|
+
body: bytes
|
|
6160
|
+
},
|
|
6161
|
+
true
|
|
6162
|
+
);
|
|
6163
|
+
await response.body?.cancel();
|
|
6164
|
+
}
|
|
6165
|
+
async watch(signal, onEvent, onOpen = () => void 0) {
|
|
6166
|
+
const response = await this.send("/api/hostfs/watch", { method: "POST", signal });
|
|
6167
|
+
onOpen();
|
|
6168
|
+
const reader = response.body.getReader();
|
|
6169
|
+
const decoder2 = new TextDecoder();
|
|
6170
|
+
let buffered = "";
|
|
6171
|
+
try {
|
|
6172
|
+
for (; ; ) {
|
|
6173
|
+
const { done: done4, value } = await reader.read();
|
|
6174
|
+
if (done4) return;
|
|
6175
|
+
buffered += decoder2.decode(value, { stream: true });
|
|
6176
|
+
let end = buffered.indexOf("\n");
|
|
6177
|
+
while (end >= 0) {
|
|
6178
|
+
const line = buffered.slice(0, end).trim();
|
|
6179
|
+
buffered = buffered.slice(end + 1);
|
|
6180
|
+
if (line) onEvent(JSON.parse(line));
|
|
6181
|
+
end = buffered.indexOf("\n");
|
|
6182
|
+
}
|
|
6183
|
+
}
|
|
6184
|
+
} catch (err) {
|
|
6185
|
+
if (signal.aborted) return;
|
|
6186
|
+
throw fsError2("ENOTCONN", `the host proxy's watch broke: ${err.message}`);
|
|
6187
|
+
} finally {
|
|
6188
|
+
reader.releaseLock();
|
|
6189
|
+
}
|
|
6190
|
+
}
|
|
6191
|
+
};
|
|
6192
|
+
function hostfsHandlers(current) {
|
|
6193
|
+
const handles = /* @__PURE__ */ new Map();
|
|
6194
|
+
let nextFh = 0;
|
|
6195
|
+
const fresh = (remote) => {
|
|
6196
|
+
if (remote.client.token === remote.token) return remote;
|
|
6197
|
+
throw fsError2("ESTALE", "the folder was granted again, so this open file is gone");
|
|
6198
|
+
};
|
|
6199
|
+
const live = (fh) => {
|
|
6200
|
+
const remote = handles.get(fh);
|
|
6201
|
+
if (!remote) throw fsError2("EBADF", `handle ${fh}`);
|
|
6202
|
+
return fresh(remote);
|
|
6203
|
+
};
|
|
6204
|
+
const call = (op, body = {}) => current().call(op, body);
|
|
6205
|
+
async function writable(client, path, flags) {
|
|
6206
|
+
const opening = () => client.call("open", { path: rel(path), ...flags });
|
|
6207
|
+
try {
|
|
6208
|
+
return { opened: await opening(), restore: void 0 };
|
|
6209
|
+
} catch (err) {
|
|
6210
|
+
if (!flags.write || codeOf2(err) !== "EACCES") throw err;
|
|
6211
|
+
const mode = (await client.call("stat", { path: rel(path) })).mode ?? 0;
|
|
6212
|
+
if (mode & 128) throw err;
|
|
6213
|
+
const restore = { path: rel(path), mode };
|
|
6214
|
+
await client.call("setattr", { path: rel(path), mode: mode | 128 });
|
|
6215
|
+
const opened2 = await opening().catch(async (again) => {
|
|
6216
|
+
await client.call("setattr", restore);
|
|
6217
|
+
throw again;
|
|
6218
|
+
});
|
|
6219
|
+
return { opened: opened2, restore };
|
|
6220
|
+
}
|
|
6027
6221
|
}
|
|
6028
|
-
const getattr = wrap((h) => h.getattr);
|
|
6029
|
-
const readdir = wrap((h) => h.readdir);
|
|
6030
6222
|
return {
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
mkdir: wrap((h) => h.mkdir),
|
|
6039
|
-
rmdir: wrap((h) => h.rmdir),
|
|
6040
|
-
unlink: wrap((h) => h.unlink),
|
|
6041
|
-
rename: wrap((h) => h.rename),
|
|
6042
|
-
symlink: wrap((h) => h.symlink),
|
|
6043
|
-
readlink: wrap((h) => h.readlink),
|
|
6044
|
-
setattr: wrap((h) => h.setattr)
|
|
6223
|
+
getattr: async (path) => await call("stat", { path: rel(path) }),
|
|
6224
|
+
async readdir(path) {
|
|
6225
|
+
const { entries } = await call(
|
|
6226
|
+
"list",
|
|
6227
|
+
{ path: rel(path) }
|
|
6228
|
+
);
|
|
6229
|
+
return entries.map(({ name: name2, attr }) => ({ name: name2, kind: attr.kind, attr }));
|
|
6045
6230
|
},
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6231
|
+
async open(path, flags) {
|
|
6232
|
+
const client = current();
|
|
6233
|
+
const token = client.token;
|
|
6234
|
+
const { opened: opened2, restore } = await writable(client, path, flags);
|
|
6235
|
+
handles.set(++nextFh, {
|
|
6236
|
+
client,
|
|
6237
|
+
token,
|
|
6238
|
+
fh: opened2.fh,
|
|
6239
|
+
etag: flags.write ? void 0 : opened2.attr?.etag,
|
|
6240
|
+
restore
|
|
6241
|
+
});
|
|
6242
|
+
return nextFh;
|
|
6049
6243
|
},
|
|
6050
|
-
|
|
6051
|
-
|
|
6244
|
+
async read(fh, offset, size) {
|
|
6245
|
+
const remote = live(fh);
|
|
6246
|
+
return remote.client.read(
|
|
6247
|
+
remote.fh,
|
|
6248
|
+
offset,
|
|
6249
|
+
Math.min(size, remote.client.maxIo),
|
|
6250
|
+
remote.etag
|
|
6251
|
+
);
|
|
6252
|
+
},
|
|
6253
|
+
async write(fh, offset, bytes) {
|
|
6254
|
+
const remote = live(fh);
|
|
6255
|
+
const most = remote.client.maxIo;
|
|
6256
|
+
for (let at = 0; at < bytes.length; at += most) {
|
|
6257
|
+
await remote.client.write(remote.fh, offset + at, bytes.subarray(at, at + most));
|
|
6258
|
+
}
|
|
6259
|
+
},
|
|
6260
|
+
async release(fh) {
|
|
6261
|
+
const remote = handles.get(fh);
|
|
6262
|
+
if (!remote) throw fsError2("EBADF", `handle ${fh}`);
|
|
6263
|
+
handles.delete(fh);
|
|
6264
|
+
try {
|
|
6265
|
+
await fresh(remote).client.call("release", { fh: remote.fh }, true);
|
|
6266
|
+
} finally {
|
|
6267
|
+
if (remote.restore) await current().call("setattr", remote.restore);
|
|
6268
|
+
}
|
|
6269
|
+
},
|
|
6270
|
+
mkdir: async (path) => void await call("mkdir", { path: rel(path) }),
|
|
6271
|
+
rmdir: async (path) => void await call("rmdir", { path: rel(path) }),
|
|
6272
|
+
unlink: async (path) => void await call("unlink", { path: rel(path) }),
|
|
6273
|
+
rename: async (from, to) => void await call("rename", { from: rel(from), to: rel(to) }),
|
|
6274
|
+
symlink: async (target, path) => void await call("symlink", { target, path: rel(path) }),
|
|
6275
|
+
readlink: async (path) => (await call("readlink", { path: rel(path) })).target,
|
|
6276
|
+
setattr: async (path, change) => void await call("setattr", { path: rel(path), ...change }),
|
|
6277
|
+
statfs: () => call("statfs")
|
|
6278
|
+
};
|
|
6279
|
+
}
|
|
6280
|
+
function sleep(ms, signal) {
|
|
6281
|
+
return new Promise((resolve) => {
|
|
6282
|
+
const done4 = () => {
|
|
6283
|
+
clearTimeout(timer);
|
|
6284
|
+
signal.removeEventListener("abort", done4);
|
|
6285
|
+
resolve();
|
|
6286
|
+
};
|
|
6287
|
+
const timer = setTimeout(done4, ms);
|
|
6288
|
+
signal.addEventListener("abort", done4);
|
|
6289
|
+
});
|
|
6290
|
+
}
|
|
6291
|
+
function keepWatching(loop, signal) {
|
|
6292
|
+
const silenceMs = loop.silenceMs ?? 45e3;
|
|
6293
|
+
const [first, most] = loop.backoffMs ?? [1e3, 3e4];
|
|
6294
|
+
const ready2 = Promise.withResolvers();
|
|
6295
|
+
let wait = first;
|
|
6296
|
+
let up = false;
|
|
6297
|
+
let current;
|
|
6298
|
+
async function session() {
|
|
6299
|
+
const session2 = new AbortController();
|
|
6300
|
+
current = session2;
|
|
6301
|
+
const stop = () => session2.abort();
|
|
6302
|
+
signal.addEventListener("abort", stop);
|
|
6303
|
+
let timer;
|
|
6304
|
+
const quiet = () => {
|
|
6305
|
+
clearTimeout(timer);
|
|
6306
|
+
timer = setTimeout(stop, silenceMs);
|
|
6307
|
+
};
|
|
6308
|
+
let opened2 = false;
|
|
6309
|
+
try {
|
|
6310
|
+
const client = await loop.connect();
|
|
6311
|
+
await client.watch(
|
|
6312
|
+
session2.signal,
|
|
6313
|
+
(event) => {
|
|
6314
|
+
quiet();
|
|
6315
|
+
if (!event.ping) loop.event(event);
|
|
6316
|
+
},
|
|
6317
|
+
() => {
|
|
6318
|
+
quiet();
|
|
6319
|
+
opened2 = true;
|
|
6320
|
+
up = true;
|
|
6321
|
+
loop.up(client);
|
|
6322
|
+
ready2.resolve();
|
|
6323
|
+
}
|
|
6324
|
+
);
|
|
6325
|
+
return opened2;
|
|
6326
|
+
} catch {
|
|
6327
|
+
return opened2;
|
|
6328
|
+
} finally {
|
|
6329
|
+
clearTimeout(timer);
|
|
6330
|
+
signal.removeEventListener("abort", stop);
|
|
6331
|
+
}
|
|
6332
|
+
}
|
|
6333
|
+
void (async () => {
|
|
6334
|
+
while (!signal.aborted) {
|
|
6335
|
+
const began = Date.now();
|
|
6336
|
+
const opened2 = await session();
|
|
6337
|
+
if (signal.aborted) return;
|
|
6338
|
+
if (opened2 && Date.now() - began >= first) {
|
|
6339
|
+
wait = first;
|
|
6340
|
+
continue;
|
|
6341
|
+
}
|
|
6342
|
+
if (!opened2 && up) {
|
|
6343
|
+
up = false;
|
|
6344
|
+
loop.down();
|
|
6345
|
+
}
|
|
6346
|
+
ready2.resolve();
|
|
6347
|
+
await sleep(wait, signal);
|
|
6348
|
+
wait = Math.min(wait * 2, most);
|
|
6349
|
+
}
|
|
6350
|
+
})();
|
|
6351
|
+
return { ready: ready2.promise, kick: () => current?.abort() };
|
|
6352
|
+
}
|
|
6353
|
+
function invalidation(event) {
|
|
6354
|
+
return event.paths ?? true;
|
|
6355
|
+
}
|
|
6356
|
+
async function openHostfs(spec, hook, fetch2, timing = {}) {
|
|
6357
|
+
const readonly = spec.options?.ro !== void 0;
|
|
6358
|
+
const { port1, port2 } = new MessageChannel();
|
|
6359
|
+
const slot = mediumSlot(
|
|
6360
|
+
async (err) => unreachable(err),
|
|
6361
|
+
() => watching.kick()
|
|
6362
|
+
);
|
|
6363
|
+
const stop = new AbortController();
|
|
6364
|
+
const grant = () => hook(spec.source, { readonly });
|
|
6365
|
+
let active;
|
|
6366
|
+
const handlers = hostfsHandlers(() => active);
|
|
6367
|
+
const served = serveFilesystem(port2, slot.handlers, {
|
|
6368
|
+
symlinks: true,
|
|
6369
|
+
chmod: true,
|
|
6370
|
+
listingStats: true,
|
|
6371
|
+
maxIo: HOSTFS_IO,
|
|
6372
|
+
...readonly ? { readonly: true } : {}
|
|
6373
|
+
});
|
|
6374
|
+
const watching = keepWatching(
|
|
6375
|
+
{
|
|
6376
|
+
connect: async () => new HostfsClient(await grant(), grant, fetch2),
|
|
6377
|
+
up(client) {
|
|
6378
|
+
active = client;
|
|
6379
|
+
slot.insert(client, handlers);
|
|
6380
|
+
served.invalidate(true);
|
|
6381
|
+
},
|
|
6382
|
+
event: (event) => served.invalidate(invalidation(event)),
|
|
6383
|
+
down() {
|
|
6384
|
+
slot.eject();
|
|
6385
|
+
served.invalidate(true);
|
|
6386
|
+
},
|
|
6387
|
+
...timing
|
|
6388
|
+
},
|
|
6389
|
+
stop.signal
|
|
6390
|
+
);
|
|
6391
|
+
await watching.ready;
|
|
6392
|
+
return {
|
|
6393
|
+
port: port1,
|
|
6394
|
+
present: slot.present,
|
|
6395
|
+
dispose() {
|
|
6396
|
+
stop.abort();
|
|
6397
|
+
port1.close();
|
|
6398
|
+
port2.close();
|
|
6052
6399
|
}
|
|
6053
6400
|
};
|
|
6054
6401
|
}
|
|
@@ -6157,6 +6504,7 @@ var DriverConnection = class _DriverConnection {
|
|
|
6157
6504
|
|
|
6158
6505
|
// src/mount/mount-fs.ts
|
|
6159
6506
|
var MAX_LINKS4 = 40;
|
|
6507
|
+
var STALE_RETRIES = 3;
|
|
6160
6508
|
var DEFAULT_IO = 8 * 1024 * 1024;
|
|
6161
6509
|
var UNITS = { "": 1, k: 1024, m: 1024 ** 2, g: 1024 ** 3, t: 1024 ** 4 };
|
|
6162
6510
|
function parseSize(text) {
|
|
@@ -6223,8 +6571,8 @@ var MountTable = class {
|
|
|
6223
6571
|
best = mount;
|
|
6224
6572
|
}
|
|
6225
6573
|
if (!best) return void 0;
|
|
6226
|
-
const
|
|
6227
|
-
return { mount: best, rel:
|
|
6574
|
+
const rel2 = best.target === "/" ? path : path.slice(best.target.length);
|
|
6575
|
+
return { mount: best, rel: rel2 || "/" };
|
|
6228
6576
|
}
|
|
6229
6577
|
async mount(spec, fs) {
|
|
6230
6578
|
const target = normalizePath(spec.target);
|
|
@@ -6329,20 +6677,20 @@ var MountTable = class {
|
|
|
6329
6677
|
mount.lists.delete(parentOf4(path));
|
|
6330
6678
|
for (const key of [...mount.lists.keys()]) if (within3(key, path)) mount.lists.delete(key);
|
|
6331
6679
|
}
|
|
6332
|
-
async getattr(mount, path,
|
|
6680
|
+
async getattr(mount, path, rel2) {
|
|
6333
6681
|
if (mount.conn.failure) throw mount.conn.failure;
|
|
6334
6682
|
const cached = mount.attrs.get(path);
|
|
6335
6683
|
if (cached && cached.expires > Date.now()) return cached.value;
|
|
6336
|
-
const attr = await mount.conn.call({ op: "getattr", path:
|
|
6684
|
+
const attr = await mount.conn.call({ op: "getattr", path: rel2 });
|
|
6337
6685
|
const ttl = mount.caps.attrTtl ?? 1e3;
|
|
6338
6686
|
if (ttl > 0) mount.attrs.set(path, { value: attr, expires: Date.now() + ttl });
|
|
6339
6687
|
return attr;
|
|
6340
6688
|
}
|
|
6341
|
-
async readdir(mount, path,
|
|
6689
|
+
async readdir(mount, path, rel2) {
|
|
6342
6690
|
if (mount.conn.failure) throw mount.conn.failure;
|
|
6343
6691
|
const cached = mount.lists.get(path);
|
|
6344
6692
|
if (cached && cached.expires > Date.now()) return cached.value;
|
|
6345
|
-
const entries = await mount.conn.call({ op: "readdir", path:
|
|
6693
|
+
const entries = await mount.conn.call({ op: "readdir", path: rel2 });
|
|
6346
6694
|
const ttl = mount.caps.entryTtl ?? mount.caps.attrTtl ?? 1e3;
|
|
6347
6695
|
if (ttl > 0) mount.lists.set(path, { value: entries, expires: Date.now() + ttl });
|
|
6348
6696
|
return entries;
|
|
@@ -6387,10 +6735,10 @@ var MountFs = class {
|
|
|
6387
6735
|
const target = await found.mount.conn.call({ op: "readlink", path: found.rel });
|
|
6388
6736
|
return this.follow(this.base.resolvePath(parentOf4(real), target), hops + 1, create);
|
|
6389
6737
|
}
|
|
6390
|
-
async open(mount,
|
|
6738
|
+
async open(mount, rel2, write) {
|
|
6391
6739
|
return await mount.conn.call({
|
|
6392
6740
|
op: "open",
|
|
6393
|
-
path:
|
|
6741
|
+
path: rel2,
|
|
6394
6742
|
write,
|
|
6395
6743
|
create: write,
|
|
6396
6744
|
truncate: write,
|
|
@@ -6407,13 +6755,22 @@ var MountFs = class {
|
|
|
6407
6755
|
const real = await this.follow(path);
|
|
6408
6756
|
const found = this.at(real);
|
|
6409
6757
|
if (!found) return this.base.readFileBuffer(real);
|
|
6410
|
-
|
|
6411
|
-
|
|
6758
|
+
for (let attempt = 1; ; attempt++) {
|
|
6759
|
+
try {
|
|
6760
|
+
return await this.readWhole(found.mount, real, found.rel);
|
|
6761
|
+
} catch (err) {
|
|
6762
|
+
if (err.code !== "ESTALE" || attempt >= STALE_RETRIES) throw err;
|
|
6763
|
+
this.table.forget(found.mount, real);
|
|
6764
|
+
}
|
|
6765
|
+
}
|
|
6766
|
+
}
|
|
6767
|
+
async readWhole(mount, real, rel2) {
|
|
6768
|
+
const attr = await this.table.getattr(mount, real, rel2);
|
|
6412
6769
|
if (attr.kind === "directory") throw errnoError("EISDIR", real);
|
|
6413
6770
|
if (mount.maxFile > 0 && attr.size > mount.maxFile) {
|
|
6414
6771
|
throw errnoError("EFBIG", `${real} is larger than this mount's maxfile (${mount.maxFile})`);
|
|
6415
6772
|
}
|
|
6416
|
-
const fh = await this.open(mount,
|
|
6773
|
+
const fh = await this.open(mount, rel2, false);
|
|
6417
6774
|
const chunk2 = mount.caps.maxIo ?? DEFAULT_IO;
|
|
6418
6775
|
const chunks2 = [];
|
|
6419
6776
|
let total = 0;
|
|
@@ -6439,7 +6796,7 @@ var MountFs = class {
|
|
|
6439
6796
|
const real = await this.follow(path, 0, true);
|
|
6440
6797
|
const found = this.at(real);
|
|
6441
6798
|
if (!found) return this.base.writeFile(real, content);
|
|
6442
|
-
const { mount, rel } = found;
|
|
6799
|
+
const { mount, rel: rel2 } = found;
|
|
6443
6800
|
this.writable(mount, real);
|
|
6444
6801
|
const bytes = typeof content === "string" ? new TextEncoder().encode(content) : content;
|
|
6445
6802
|
if (mount.maxFile > 0 && bytes.length > mount.maxFile) {
|
|
@@ -6448,8 +6805,17 @@ var MountFs = class {
|
|
|
6448
6805
|
`${real} would be larger than this mount's maxfile (${mount.maxFile})`
|
|
6449
6806
|
);
|
|
6450
6807
|
}
|
|
6808
|
+
for (let attempt = 1; ; attempt++) {
|
|
6809
|
+
try {
|
|
6810
|
+
return await this.writeWhole(mount, real, rel2, bytes);
|
|
6811
|
+
} catch (err) {
|
|
6812
|
+
if (err.code !== "ESTALE" || attempt >= STALE_RETRIES) throw err;
|
|
6813
|
+
}
|
|
6814
|
+
}
|
|
6815
|
+
}
|
|
6816
|
+
async writeWhole(mount, real, rel2, bytes) {
|
|
6451
6817
|
this.table.forget(mount, real);
|
|
6452
|
-
const fh = await this.open(mount,
|
|
6818
|
+
const fh = await this.open(mount, rel2, true);
|
|
6453
6819
|
const chunk2 = mount.caps.maxIo ?? DEFAULT_IO;
|
|
6454
6820
|
try {
|
|
6455
6821
|
for (let offset = 0; offset < bytes.length; offset += chunk2) {
|
|
@@ -6516,16 +6882,16 @@ var MountFs = class {
|
|
|
6516
6882
|
async mkdir(path, options = {}) {
|
|
6517
6883
|
const found = this.at(path);
|
|
6518
6884
|
if (!found) return this.base.mkdir(path, options);
|
|
6519
|
-
const { mount, rel } = found;
|
|
6885
|
+
const { mount, rel: rel2 } = found;
|
|
6520
6886
|
const real = normalizePath(path);
|
|
6521
6887
|
this.writable(mount, real);
|
|
6522
6888
|
if (!options.recursive) {
|
|
6523
|
-
if (
|
|
6889
|
+
if (rel2 === "/") throw errnoError("EEXIST", real);
|
|
6524
6890
|
this.table.forget(mount, real);
|
|
6525
|
-
await mount.conn.call({ op: "mkdir", path:
|
|
6891
|
+
await mount.conn.call({ op: "mkdir", path: rel2 });
|
|
6526
6892
|
return;
|
|
6527
6893
|
}
|
|
6528
|
-
const parts =
|
|
6894
|
+
const parts = rel2.split("/").filter(Boolean);
|
|
6529
6895
|
for (let n = 1; n <= parts.length; n++) {
|
|
6530
6896
|
const sub = `/${parts.slice(0, n).join("/")}`;
|
|
6531
6897
|
const full = normalizePath(`${mount.target}${sub}`);
|
|
@@ -6539,25 +6905,25 @@ var MountFs = class {
|
|
|
6539
6905
|
async rm(path, options = {}) {
|
|
6540
6906
|
const found = this.at(path);
|
|
6541
6907
|
if (!found) return this.base.rm(path, options);
|
|
6542
|
-
const { mount, rel } = found;
|
|
6908
|
+
const { mount, rel: rel2 } = found;
|
|
6543
6909
|
const real = normalizePath(path);
|
|
6544
|
-
if (
|
|
6910
|
+
if (rel2 === "/") throw errnoError("EBUSY", `${real} is a mount point`);
|
|
6545
6911
|
this.writable(mount, real);
|
|
6546
6912
|
let attr;
|
|
6547
6913
|
try {
|
|
6548
|
-
attr = await this.table.getattr(mount, real,
|
|
6914
|
+
attr = await this.table.getattr(mount, real, rel2);
|
|
6549
6915
|
} catch (err) {
|
|
6550
6916
|
if (options.force && err.code === "ENOENT") return;
|
|
6551
6917
|
throw err;
|
|
6552
6918
|
}
|
|
6553
6919
|
this.table.forget(mount, real);
|
|
6554
6920
|
if (attr.kind === "directory" && options.recursive) {
|
|
6555
|
-
for (const entry of await this.table.readdir(mount, real,
|
|
6921
|
+
for (const entry of await this.table.readdir(mount, real, rel2)) {
|
|
6556
6922
|
await this.rm(`${real}/${entry.name}`, { recursive: true, force: options.force ?? false });
|
|
6557
6923
|
}
|
|
6558
6924
|
this.table.forget(mount, real);
|
|
6559
6925
|
}
|
|
6560
|
-
await mount.conn.call({ op: attr.kind === "directory" ? "rmdir" : "unlink", path:
|
|
6926
|
+
await mount.conn.call({ op: attr.kind === "directory" ? "rmdir" : "unlink", path: rel2 });
|
|
6561
6927
|
this.table.forget(mount, real);
|
|
6562
6928
|
}
|
|
6563
6929
|
async rename(from, to) {
|
|
@@ -7019,6 +7385,7 @@ var Launcher = class {
|
|
|
7019
7385
|
media;
|
|
7020
7386
|
onMountPending;
|
|
7021
7387
|
removable = /* @__PURE__ */ new Map();
|
|
7388
|
+
hostfs;
|
|
7022
7389
|
inserted = /* @__PURE__ */ new Map();
|
|
7023
7390
|
openFiles = /* @__PURE__ */ new Set();
|
|
7024
7391
|
held = /* @__PURE__ */ new Set();
|
|
@@ -7036,6 +7403,7 @@ var Launcher = class {
|
|
|
7036
7403
|
this.createDriverWorker = options.createDriverWorker;
|
|
7037
7404
|
this.media = options.media ?? memoryMedia();
|
|
7038
7405
|
this.onMountPending = options.onMountPending;
|
|
7406
|
+
this.hostfs = options;
|
|
7039
7407
|
this.pnpmHome = options.env?.PNPM_HOME ?? PNPM_HOME;
|
|
7040
7408
|
this.modulesDir = options.modules ?? "/node_modules";
|
|
7041
7409
|
this.env = { ...networkEnv(), ...options.env };
|
|
@@ -7301,6 +7669,17 @@ var Launcher = class {
|
|
|
7301
7669
|
}
|
|
7302
7670
|
async driver(type, spec) {
|
|
7303
7671
|
if (type === "fsa") return this.fsaDriver(spec);
|
|
7672
|
+
if (type === "hostfs") {
|
|
7673
|
+
const { hostfs, hostfsFetch, hostfsTiming } = this.hostfs;
|
|
7674
|
+
if (!hostfs)
|
|
7675
|
+
throw fsError("ENODEV", "this kernel has no hostfs hook (createKernel({ hostfs }))");
|
|
7676
|
+
return openHostfs(
|
|
7677
|
+
spec,
|
|
7678
|
+
hostfs,
|
|
7679
|
+
hostfsFetch ?? ((url, init) => fetch(url, init)),
|
|
7680
|
+
hostfsTiming
|
|
7681
|
+
);
|
|
7682
|
+
}
|
|
7304
7683
|
if (type === "tmpfs") {
|
|
7305
7684
|
const { port1, port2 } = new MessageChannel();
|
|
7306
7685
|
serveFilesystem(port2, tmpfs(), { symlinks: true, chmod: true, attrTtl: 0 });
|