@ai-ecoverse/slicc-kernel 1.14.0 → 1.15.1
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 +18 -1
- package/dist/index.js +28 -9
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +256 -24
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +3 -0
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +216 -15
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +3 -0
- package/dist/process-worker.js.map +2 -2
- package/package.json +1 -1
package/dist/node.js
CHANGED
|
@@ -585,7 +585,8 @@ var ERRNO_BY_DOM_ERROR = {
|
|
|
585
585
|
TypeMismatchError: "ENOTDIR",
|
|
586
586
|
InvalidModificationError: "ENOTEMPTY",
|
|
587
587
|
NoModificationAllowedError: "EBUSY",
|
|
588
|
-
TypeError: "EINVAL"
|
|
588
|
+
TypeError: "EINVAL",
|
|
589
|
+
NotAllowedError: "EACCES"
|
|
589
590
|
};
|
|
590
591
|
function translate(err, path) {
|
|
591
592
|
if (typeof err?.code === "string") return err;
|
|
@@ -5910,6 +5911,157 @@ function serveFilesystem(port, handlers, capabilities = {}) {
|
|
|
5910
5911
|
return { invalidate: (paths) => reply({ invalidate: paths }) };
|
|
5911
5912
|
}
|
|
5912
5913
|
|
|
5914
|
+
// src/mount/fsa.ts
|
|
5915
|
+
var FSA_CAPABILITIES = { listingStats: true };
|
|
5916
|
+
var codeOf = (err) => err?.code;
|
|
5917
|
+
var denied = (err) => codeOf(err) === "EACCES" || err?.name === "NotAllowedError";
|
|
5918
|
+
function attrOf(st) {
|
|
5919
|
+
return {
|
|
5920
|
+
kind: st.isDirectory ? "directory" : st.isSymbolicLink ? "symlink" : "file",
|
|
5921
|
+
size: st.size,
|
|
5922
|
+
mtime: st.mtime.getTime(),
|
|
5923
|
+
mode: st.mode,
|
|
5924
|
+
ino: st.ino
|
|
5925
|
+
};
|
|
5926
|
+
}
|
|
5927
|
+
function kernelFsHandlers(fs) {
|
|
5928
|
+
const handles = /* @__PURE__ */ new Map();
|
|
5929
|
+
let nextFh = 0;
|
|
5930
|
+
const handle = (fh) => {
|
|
5931
|
+
const found = handles.get(fh);
|
|
5932
|
+
if (!found) throw fsError2("EBADF", `handle ${fh}`);
|
|
5933
|
+
return found;
|
|
5934
|
+
};
|
|
5935
|
+
async function existing(path) {
|
|
5936
|
+
try {
|
|
5937
|
+
return await fs.stat(path);
|
|
5938
|
+
} catch (err) {
|
|
5939
|
+
if (codeOf(err) === "ENOENT") return void 0;
|
|
5940
|
+
throw err;
|
|
5941
|
+
}
|
|
5942
|
+
}
|
|
5943
|
+
return {
|
|
5944
|
+
getattr: async (path) => attrOf(await fs.lstat(path)),
|
|
5945
|
+
readdir: async (path) => (await fs.readdirStat(path)).flatMap(([name2, st]) => {
|
|
5946
|
+
if (!st) return [];
|
|
5947
|
+
const attr = attrOf(st);
|
|
5948
|
+
return [{ name: name2, kind: attr.kind, attr }];
|
|
5949
|
+
}),
|
|
5950
|
+
async open(path, flags) {
|
|
5951
|
+
const st = await existing(path);
|
|
5952
|
+
if (st && flags.exclusive) throw fsError2("EEXIST", path);
|
|
5953
|
+
if (st?.isDirectory && flags.write) throw fsError2("EISDIR", path);
|
|
5954
|
+
if (!st && !flags.create) throw fsError2("ENOENT", path);
|
|
5955
|
+
const data = st && !flags.truncate ? await fs.readFileBuffer(path) : new Uint8Array(0);
|
|
5956
|
+
handles.set(++nextFh, { path, data, length: data.length, dirty: !st || flags.truncate });
|
|
5957
|
+
return nextFh;
|
|
5958
|
+
},
|
|
5959
|
+
async read(fh, offset, size) {
|
|
5960
|
+
const h = handle(fh);
|
|
5961
|
+
return h.data.slice(offset, Math.min(h.length, offset + size));
|
|
5962
|
+
},
|
|
5963
|
+
async write(fh, offset, bytes) {
|
|
5964
|
+
const h = handle(fh);
|
|
5965
|
+
const end = offset + bytes.length;
|
|
5966
|
+
if (end > h.data.length) {
|
|
5967
|
+
const grown = new Uint8Array(Math.max(end, h.data.length * 2));
|
|
5968
|
+
grown.set(h.data.subarray(0, h.length));
|
|
5969
|
+
h.data = grown;
|
|
5970
|
+
}
|
|
5971
|
+
h.data.set(bytes, offset);
|
|
5972
|
+
h.length = Math.max(h.length, end);
|
|
5973
|
+
h.dirty = true;
|
|
5974
|
+
},
|
|
5975
|
+
async release(fh) {
|
|
5976
|
+
const h = handle(fh);
|
|
5977
|
+
handles.delete(fh);
|
|
5978
|
+
if (h.dirty) await fs.writeFile(h.path, h.data.slice(0, h.length));
|
|
5979
|
+
},
|
|
5980
|
+
mkdir: (path) => fs.mkdir(path),
|
|
5981
|
+
async rmdir(path) {
|
|
5982
|
+
if (!(await fs.lstat(path)).isDirectory) throw fsError2("ENOTDIR", path);
|
|
5983
|
+
if ((await fs.readdir(path)).length > 0) throw fsError2("ENOTEMPTY", path);
|
|
5984
|
+
await fs.rm(path);
|
|
5985
|
+
},
|
|
5986
|
+
async unlink(path) {
|
|
5987
|
+
if ((await fs.lstat(path)).isDirectory) throw fsError2("EISDIR", path);
|
|
5988
|
+
await fs.rm(path);
|
|
5989
|
+
},
|
|
5990
|
+
rename: (from, to) => fs.rename(from, to),
|
|
5991
|
+
symlink: (target, path) => fs.symlink(target, path),
|
|
5992
|
+
readlink: (path) => fs.readlink(path),
|
|
5993
|
+
async setattr(path, change) {
|
|
5994
|
+
if (change.mode !== void 0) await fs.chmod(path, change.mode);
|
|
5995
|
+
if (change.mtime !== void 0) {
|
|
5996
|
+
await fs.utimes(path, new Date(change.mtime), new Date(change.mtime));
|
|
5997
|
+
}
|
|
5998
|
+
}
|
|
5999
|
+
};
|
|
6000
|
+
}
|
|
6001
|
+
var EMPTY_ROOT = { kind: "directory", size: 0, mtime: 0, mode: 16877 };
|
|
6002
|
+
function granted(handle) {
|
|
6003
|
+
if (!handle.queryPermission) return Promise.resolve(true);
|
|
6004
|
+
return handle.queryPermission({ mode: "readwrite" }).then(
|
|
6005
|
+
(state) => state === "granted",
|
|
6006
|
+
() => false
|
|
6007
|
+
);
|
|
6008
|
+
}
|
|
6009
|
+
function removableMedium(onLost, open = (handle) => new OpfsFs(handle)) {
|
|
6010
|
+
let current;
|
|
6011
|
+
const absent = () => fsError2("ENOMEDIUM", "No medium found");
|
|
6012
|
+
function wrap(pick) {
|
|
6013
|
+
return async (...args) => {
|
|
6014
|
+
const medium = current;
|
|
6015
|
+
if (!medium) throw absent();
|
|
6016
|
+
try {
|
|
6017
|
+
return await pick(medium.handlers)(...args);
|
|
6018
|
+
} catch (err) {
|
|
6019
|
+
if (!denied(err) || await granted(medium.handle)) throw err;
|
|
6020
|
+
if (current === medium) {
|
|
6021
|
+
current = void 0;
|
|
6022
|
+
onLost(medium.handle);
|
|
6023
|
+
}
|
|
6024
|
+
throw absent();
|
|
6025
|
+
}
|
|
6026
|
+
};
|
|
6027
|
+
}
|
|
6028
|
+
const getattr = wrap((h) => h.getattr);
|
|
6029
|
+
const readdir = wrap((h) => h.readdir);
|
|
6030
|
+
return {
|
|
6031
|
+
handlers: {
|
|
6032
|
+
getattr: (path) => current || path !== "/" ? getattr(path) : Promise.resolve(EMPTY_ROOT),
|
|
6033
|
+
readdir: (path) => current || path !== "/" ? readdir(path) : Promise.resolve([]),
|
|
6034
|
+
open: wrap((h) => h.open),
|
|
6035
|
+
read: wrap((h) => h.read),
|
|
6036
|
+
write: wrap((h) => h.write),
|
|
6037
|
+
release: wrap((h) => h.release),
|
|
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)
|
|
6045
|
+
},
|
|
6046
|
+
present: () => current !== void 0,
|
|
6047
|
+
insert(handle) {
|
|
6048
|
+
current = { handle, handlers: kernelFsHandlers(open(handle)) };
|
|
6049
|
+
},
|
|
6050
|
+
eject() {
|
|
6051
|
+
current = void 0;
|
|
6052
|
+
}
|
|
6053
|
+
};
|
|
6054
|
+
}
|
|
6055
|
+
|
|
6056
|
+
// src/mount/media.ts
|
|
6057
|
+
function memoryMedia() {
|
|
6058
|
+
const handles = /* @__PURE__ */ new Map();
|
|
6059
|
+
return {
|
|
6060
|
+
get: async (id) => handles.get(id),
|
|
6061
|
+
put: async (id, handle) => void handles.set(id, handle)
|
|
6062
|
+
};
|
|
6063
|
+
}
|
|
6064
|
+
|
|
5913
6065
|
// src/mount/connection.ts
|
|
5914
6066
|
var DRIVER_TIMEOUT_MS = 3e4;
|
|
5915
6067
|
function unref(timer) {
|
|
@@ -6053,14 +6205,16 @@ var MountTable = class {
|
|
|
6053
6205
|
this.deps = deps;
|
|
6054
6206
|
}
|
|
6055
6207
|
list() {
|
|
6056
|
-
return [...this.mounts.values()].map(
|
|
6057
|
-
type,
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6208
|
+
return [...this.mounts.values()].map(
|
|
6209
|
+
({ type, source, target, options, state, error, present }) => ({
|
|
6210
|
+
type,
|
|
6211
|
+
source,
|
|
6212
|
+
target,
|
|
6213
|
+
options: { ...options },
|
|
6214
|
+
state: state === "ok" && present?.() === false ? "nomedium" : state,
|
|
6215
|
+
...error ? { error } : {}
|
|
6216
|
+
})
|
|
6217
|
+
);
|
|
6064
6218
|
}
|
|
6065
6219
|
locate(path) {
|
|
6066
6220
|
let best;
|
|
@@ -6131,7 +6285,8 @@ var MountTable = class {
|
|
|
6131
6285
|
maxFile: options.maxfile !== void 0 ? parseSize(options.maxfile) : caps.maxFile ?? 0,
|
|
6132
6286
|
attrs: /* @__PURE__ */ new Map(),
|
|
6133
6287
|
lists: /* @__PURE__ */ new Map(),
|
|
6134
|
-
dispose: () => opened2.dispose()
|
|
6288
|
+
dispose: () => opened2.dispose(),
|
|
6289
|
+
...opened2.present ? { present: opened2.present } : {}
|
|
6135
6290
|
};
|
|
6136
6291
|
mounted = mount;
|
|
6137
6292
|
this.mounts.set(target, mount);
|
|
@@ -6861,6 +7016,10 @@ var Launcher = class {
|
|
|
6861
7016
|
pnpmHome;
|
|
6862
7017
|
mounts;
|
|
6863
7018
|
createDriverWorker;
|
|
7019
|
+
media;
|
|
7020
|
+
onMountPending;
|
|
7021
|
+
removable = /* @__PURE__ */ new Map();
|
|
7022
|
+
inserted = /* @__PURE__ */ new Map();
|
|
6864
7023
|
openFiles = /* @__PURE__ */ new Set();
|
|
6865
7024
|
held = /* @__PURE__ */ new Set();
|
|
6866
7025
|
nextPid = 1e3;
|
|
@@ -6875,6 +7034,8 @@ var Launcher = class {
|
|
|
6875
7034
|
this.base = this.watchers.wrap(this.mounts.wrap(options.fs));
|
|
6876
7035
|
this.createWorker = options.createWorker;
|
|
6877
7036
|
this.createDriverWorker = options.createDriverWorker;
|
|
7037
|
+
this.media = options.media ?? memoryMedia();
|
|
7038
|
+
this.onMountPending = options.onMountPending;
|
|
6878
7039
|
this.pnpmHome = options.env?.PNPM_HOME ?? PNPM_HOME;
|
|
6879
7040
|
this.modulesDir = options.modules ?? "/node_modules";
|
|
6880
7041
|
this.env = { ...networkEnv(), ...options.env };
|
|
@@ -7138,7 +7299,8 @@ var Launcher = class {
|
|
|
7138
7299
|
if (sig !== 0) handle.signal(sig);
|
|
7139
7300
|
return true;
|
|
7140
7301
|
}
|
|
7141
|
-
async driver(type,
|
|
7302
|
+
async driver(type, spec) {
|
|
7303
|
+
if (type === "fsa") return this.fsaDriver(spec);
|
|
7142
7304
|
if (type === "tmpfs") {
|
|
7143
7305
|
const { port1, port2 } = new MessageChannel();
|
|
7144
7306
|
serveFilesystem(port2, tmpfs(), { symlinks: true, chmod: true, attrTtl: 0 });
|
|
@@ -7179,8 +7341,47 @@ var Launcher = class {
|
|
|
7179
7341
|
})
|
|
7180
7342
|
};
|
|
7181
7343
|
}
|
|
7344
|
+
async fsaDriver(spec) {
|
|
7345
|
+
const { target, source } = spec;
|
|
7346
|
+
const ask = (handle) => this.onMountPending?.({ target, source, ...handle ? { handle } : {} });
|
|
7347
|
+
const { port1, port2 } = new MessageChannel();
|
|
7348
|
+
const medium = removableMedium((handle) => {
|
|
7349
|
+
served.invalidate(true);
|
|
7350
|
+
ask(handle);
|
|
7351
|
+
});
|
|
7352
|
+
const served = serveFilesystem(port2, medium.handlers, FSA_CAPABILITIES);
|
|
7353
|
+
const id = source.slice("fsa:".length);
|
|
7354
|
+
this.removable.set(target, { id, medium, served });
|
|
7355
|
+
const stored = this.inserted.get(id) ?? await this.media.get(id);
|
|
7356
|
+
if (stored && await granted(stored)) medium.insert(stored);
|
|
7357
|
+
else ask(stored);
|
|
7358
|
+
return {
|
|
7359
|
+
port: port1,
|
|
7360
|
+
present: () => medium.present(),
|
|
7361
|
+
dispose: () => {
|
|
7362
|
+
this.removable.delete(target);
|
|
7363
|
+
port1.close();
|
|
7364
|
+
port2.close();
|
|
7365
|
+
}
|
|
7366
|
+
};
|
|
7367
|
+
}
|
|
7182
7368
|
mount(spec) {
|
|
7183
|
-
|
|
7369
|
+
if (spec.type !== "fsa" || spec.source.startsWith("fsa:"))
|
|
7370
|
+
return this.mounts.mount(spec, this.fs);
|
|
7371
|
+
return this.mounts.mount({ ...spec, source: `fsa:${crypto.randomUUID()}` }, this.fs);
|
|
7372
|
+
}
|
|
7373
|
+
async insert(target, handle, source) {
|
|
7374
|
+
const at = normalizePath(target);
|
|
7375
|
+
const slot = this.removable.get(at);
|
|
7376
|
+
if (!slot) throw fsError("EINVAL", `${at} is not a removable mount`);
|
|
7377
|
+
if (source !== void 0 && source !== `fsa:${slot.id}`) {
|
|
7378
|
+
throw fsError("EINVAL", `${at} is no longer the drive ${source}`);
|
|
7379
|
+
}
|
|
7380
|
+
if (!await granted(handle)) throw fsError("EACCES", `${at}: no permission for this folder`);
|
|
7381
|
+
this.inserted.set(slot.id, handle);
|
|
7382
|
+
await this.media.put(slot.id, handle);
|
|
7383
|
+
slot.medium.insert(handle);
|
|
7384
|
+
slot.served.invalidate(true);
|
|
7184
7385
|
}
|
|
7185
7386
|
umount(target) {
|
|
7186
7387
|
this.mounts.umount(target);
|
|
@@ -7555,13 +7756,13 @@ async function holdLock(locks) {
|
|
|
7555
7756
|
if (!locks) return { release() {
|
|
7556
7757
|
} };
|
|
7557
7758
|
const name2 = `slicc-kernel-client:${crypto.randomUUID()}`;
|
|
7558
|
-
const
|
|
7759
|
+
const granted2 = Promise.withResolvers();
|
|
7559
7760
|
const held = Promise.withResolvers();
|
|
7560
7761
|
void locks.request(name2, () => {
|
|
7561
|
-
|
|
7762
|
+
granted2.resolve();
|
|
7562
7763
|
return held.promise;
|
|
7563
7764
|
});
|
|
7564
|
-
await
|
|
7765
|
+
await granted2.promise;
|
|
7565
7766
|
return { name: name2, release: () => held.resolve() };
|
|
7566
7767
|
}
|
|
7567
7768
|
function concat6(chunks2) {
|