@volter/tabnode 0.3.1 → 0.4.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/dist/index.mjs CHANGED
@@ -6344,6 +6344,7 @@ function processByPid(pid) {
6344
6344
  return void 0;
6345
6345
  }
6346
6346
  const owners = /* @__PURE__ */ new Map();
6347
+ const allOwned = /* @__PURE__ */ new Map();
6347
6348
  const heldBy = /* @__PURE__ */ new WeakMap();
6348
6349
  const refHeld = /* @__PURE__ */ new WeakSet();
6349
6350
  const activeHandles = /* @__PURE__ */ new WeakSet();
@@ -6374,6 +6375,15 @@ function ownerOf(handle) {
6374
6375
  }
6375
6376
  function registerHandle(handle) {
6376
6377
  heldBy.set(handle, currentOwner());
6378
+ const token = heldBy.get(handle);
6379
+ if (token != null) {
6380
+ let owned = allOwned.get(token);
6381
+ if (!owned) {
6382
+ owned = /* @__PURE__ */ new Set();
6383
+ allOwned.set(token, owned);
6384
+ }
6385
+ owned.add(handle);
6386
+ }
6377
6387
  refHeld.add(handle);
6378
6388
  activeHandles.add(handle);
6379
6389
  hold(handle);
@@ -6395,6 +6405,12 @@ function handleHasRef(handle) {
6395
6405
  }
6396
6406
  function releaseHandle(handle) {
6397
6407
  drop(handle);
6408
+ const token = heldBy.get(handle);
6409
+ if (token != null) {
6410
+ const owned = allOwned.get(token);
6411
+ owned == null ? void 0 : owned.delete(handle);
6412
+ if ((owned == null ? void 0 : owned.size) === 0) allOwned.delete(token);
6413
+ }
6398
6414
  heldBy.delete(handle);
6399
6415
  refHeld.delete(handle);
6400
6416
  activeHandles.delete(handle);
@@ -6428,8 +6444,9 @@ function __releaseOwnedServers(token, stopTimers = true, stopProcess) {
6428
6444
  }
6429
6445
  }
6430
6446
  function __releaseOwnedHandles(token) {
6431
- const held = owners.get(token);
6447
+ const held = allOwned.get(token);
6432
6448
  if (!held) return;
6449
+ allOwned.delete(token);
6433
6450
  owners.delete(token);
6434
6451
  for (const handle of [...held]) {
6435
6452
  try {
@@ -6441,7 +6458,21 @@ function __releaseOwnedHandles(token) {
6441
6458
  function __adoptHandle(handle, token) {
6442
6459
  if (!handle) return;
6443
6460
  drop(handle);
6461
+ const previous = heldBy.get(handle);
6462
+ if (previous != null) {
6463
+ const owned = allOwned.get(previous);
6464
+ owned == null ? void 0 : owned.delete(handle);
6465
+ if ((owned == null ? void 0 : owned.size) === 0) allOwned.delete(previous);
6466
+ }
6444
6467
  heldBy.set(handle, token);
6468
+ if (token !== null) {
6469
+ let owned = allOwned.get(token);
6470
+ if (!owned) {
6471
+ owned = /* @__PURE__ */ new Set();
6472
+ allOwned.set(token, owned);
6473
+ }
6474
+ owned.add(handle);
6475
+ }
6445
6476
  hold(handle);
6446
6477
  }
6447
6478
  function ownedBytes$1(view) {
@@ -8790,7 +8821,9 @@ function refuseLinks(syscall, path2) {
8790
8821
  { code: "EPERM", errno: -1, syscall, path: path2 }
8791
8822
  );
8792
8823
  }
8793
- const pathModes = /* @__PURE__ */ new Map();
8824
+ function unsupportedMetadata(syscall) {
8825
+ throw Object.assign(new Error(`ENOTSUP: filesystem does not support ${syscall}`), { code: "ENOTSUP", syscall });
8826
+ }
8794
8827
  function treeHoldsLinks() {
8795
8828
  return vfs().holdsLinks === true;
8796
8829
  }
@@ -8854,19 +8887,18 @@ function fileFor(fd) {
8854
8887
  return file;
8855
8888
  }
8856
8889
  function statArray(stats, bigint, path2) {
8857
- var _a2, _b2;
8890
+ var _a2, _b2, _c2;
8858
8891
  const mtime = stats.mtime instanceof Date ? stats.mtime.getTime() : Number(stats.mtimeMs ?? 0);
8859
8892
  const atime = stats.atime instanceof Date ? stats.atime.getTime() : Number(stats.atimeMs ?? mtime);
8860
8893
  const ctime = stats.ctime instanceof Date ? stats.ctime.getTime() : Number(stats.ctimeMs ?? mtime);
8861
8894
  const birth = stats.birthtime instanceof Date ? stats.birthtime.getTime() : Number(stats.birthtimeMs ?? mtime);
8862
8895
  const seconds = (ms) => Math.floor(ms / 1e3);
8863
8896
  const nanos = (ms) => Math.floor(ms % 1e3 * 1e6);
8864
- const stored = path2 !== void 0 ? pathModes.get(path2) : void 0;
8865
- const permissions = (stored !== void 0 ? stored : Number(stats.mode ?? 0)) & 4095;
8866
- const type2 = ((_a2 = stats.isDirectory) == null ? void 0 : _a2.call(stats)) ? S_IFDIR : ((_b2 = stats.isSymbolicLink) == null ? void 0 : _b2.call(stats)) ? S_IFLNK : S_IFREG;
8897
+ const permissions = Number(stats.mode ?? (((_a2 = stats.isDirectory) == null ? void 0 : _a2.call(stats)) ? 493 : 420)) & 4095;
8898
+ const type2 = ((_b2 = stats.isDirectory) == null ? void 0 : _b2.call(stats)) ? S_IFDIR : ((_c2 = stats.isSymbolicLink) == null ? void 0 : _c2.call(stats)) ? S_IFLNK : S_IFREG;
8867
8899
  const values = [
8868
8900
  Number(stats.dev ?? 0),
8869
- type2 | (permissions || (type2 === S_IFDIR ? 493 : 420)),
8901
+ type2 | permissions,
8870
8902
  Number(stats.nlink ?? 1),
8871
8903
  Number(stats.uid ?? 0),
8872
8904
  Number(stats.gid ?? 0),
@@ -9012,15 +9044,23 @@ class FSEvent {
9012
9044
  __privateAdd(this, _watcher, null);
9013
9045
  __publicField(this, "initialized", false);
9014
9046
  }
9015
- start(path2, _persistent, recursive, _encoding2) {
9047
+ start(path2, persistent, recursive, _encoding2) {
9016
9048
  const name = asPath(path2);
9017
9049
  const tree2 = vfs();
9050
+ const cwd = callingCwd();
9051
+ const owner = currentOwner();
9018
9052
  try {
9019
9053
  __privateSet(this, _watcher, tree2.watch(name, { recursive: Boolean(recursive) }, (event, filename) => {
9020
- var _a2;
9021
- (_a2 = this.onchange) == null ? void 0 : _a2.call(this, 0, event === "rename" ? "rename" : "change", filename ?? "");
9054
+ const notify = () => withFilesystem(tree2, () => withCwd(cwd, () => {
9055
+ var _a2;
9056
+ return (_a2 = this.onchange) == null ? void 0 : _a2.call(this, 0, event === "rename" ? "rename" : "change", filename ?? "");
9057
+ }));
9058
+ if (owner === null) notify();
9059
+ else enterRun(owner, notify);
9022
9060
  }));
9023
9061
  this.initialized = true;
9062
+ registerHandle(this);
9063
+ if (persistent === false) unrefHandle(this);
9024
9064
  return 0;
9025
9065
  } catch (error) {
9026
9066
  const code2 = error.code;
@@ -9029,6 +9069,7 @@ class FSEvent {
9029
9069
  }
9030
9070
  close() {
9031
9071
  var _a2;
9072
+ releaseHandle(this);
9032
9073
  this.initialized = false;
9033
9074
  try {
9034
9075
  (_a2 = __privateGet(this, _watcher)) == null ? void 0 : _a2.close();
@@ -9037,14 +9078,16 @@ class FSEvent {
9037
9078
  __privateSet(this, _watcher, null);
9038
9079
  }
9039
9080
  ref() {
9081
+ if (this.initialized) refHandle(this);
9040
9082
  }
9041
9083
  unref() {
9084
+ unrefHandle(this);
9042
9085
  }
9043
9086
  getAsyncId() {
9044
9087
  return 0;
9045
9088
  }
9046
9089
  hasRef() {
9047
- return this.initialized;
9090
+ return this.initialized && handleHasRef(this);
9048
9091
  }
9049
9092
  }
9050
9093
  _watcher = new WeakMap();
@@ -9141,6 +9184,9 @@ const fsBinding = {
9141
9184
  const tree2 = vfs();
9142
9185
  const bits = flagBits();
9143
9186
  const exists = tree2.existsSync(name);
9187
+ if (exists && ((flags & 3) !== 0 || (flags & (bits.create | bits.truncate | bits.append)) !== 0)) {
9188
+ tree2.accessSync(name, 2);
9189
+ }
9144
9190
  if ((flags & bits.excl) !== 0 && (flags & bits.create) !== 0 && exists) throw createNodeError$1("EEXIST", "open", name);
9145
9191
  if (!exists) {
9146
9192
  if ((flags & bits.create) === 0) throw createNodeError$1("ENOENT", "open", name);
@@ -9292,10 +9338,10 @@ const fsBinding = {
9292
9338
  return bigint ? BigInt64Array.from(values.map((value) => BigInt(value))) : Float64Array.from(values);
9293
9339
  });
9294
9340
  },
9295
- access(path2, _mode, req) {
9341
+ access(path2, mode, req) {
9296
9342
  return answer(req, () => {
9297
9343
  const name = asPath(path2);
9298
- if (!vfs().existsSync(name)) throw createNodeError$1("ENOENT", "access", name);
9344
+ vfs().accessSync(name, mode);
9299
9345
  return void 0;
9300
9346
  });
9301
9347
  },
@@ -9400,13 +9446,10 @@ const fsBinding = {
9400
9446
  if (tree2.existsSync(name)) {
9401
9447
  const stats = tree2.statSync(name);
9402
9448
  if (!recursive || !stats.isDirectory()) throw createNodeError$1("EEXIST", "mkdir", name);
9403
- const stored = pathModes.get(name);
9404
- if (stored !== void 0 && (stored & 511) !== wanted) throw createNodeError$1("EEXIST", "mkdir", name);
9405
- pathModes.set(name, wanted);
9406
9449
  return void 0;
9407
9450
  }
9408
9451
  tree2.mkdirSync(name, { recursive });
9409
- pathModes.set(name, wanted);
9452
+ tree2.chmodSync(name, wanted);
9410
9453
  return void 0;
9411
9454
  });
9412
9455
  },
@@ -9478,46 +9521,50 @@ const fsBinding = {
9478
9521
  }
9479
9522
  });
9480
9523
  },
9481
- // ---- the calls a page's filesystem has nothing to do -------------------
9482
- // Ownership and times are a kernel's bookkeeping. Permissions `chmod` sets
9483
- // are kept here, because a program that sets a mode and stats it back must
9484
- // see what it set, and a missing path is ENOENT as Node's is.
9524
+ // Metadata belongs to the filesystem, including a host's permission view.
9525
+ // Never keep a realm-global mode table or bypass that view for descriptors.
9485
9526
  chmod(path2, mode, req) {
9486
9527
  return answer(req, () => {
9487
9528
  const name = asPath(path2);
9488
- if (!vfs().existsSync(name)) throw createNodeError$1("ENOENT", "chmod", name);
9489
- pathModes.set(name, mode & 4095);
9529
+ vfs().chmodSync(name, mode);
9490
9530
  return void 0;
9491
9531
  });
9492
9532
  },
9493
9533
  fchmod(fd, mode, req) {
9494
9534
  return answer(req, () => {
9495
9535
  const file = fileFor(fd);
9496
- pathModes.set(file.path, mode & 4095);
9536
+ file.tree.chmodSync(file.path, mode);
9497
9537
  return void 0;
9498
9538
  });
9499
9539
  },
9500
- chown(path2, _uid, _gid, req) {
9501
- return answer(req, () => {
9502
- const name = asPath(path2);
9503
- if (!vfs().existsSync(name)) throw createNodeError$1("ENOENT", "chown", name);
9504
- return void 0;
9505
- });
9540
+ chown(_path, _uid, _gid, req) {
9541
+ return answer(req, () => unsupportedMetadata("chown"));
9506
9542
  },
9507
9543
  fchown(_fd, _uid, _gid, req) {
9508
- return answer(req, () => void 0);
9544
+ return answer(req, () => unsupportedMetadata("fchown"));
9509
9545
  },
9510
9546
  lchown(_path, _uid, _gid, req) {
9511
- return answer(req, () => void 0);
9547
+ return answer(req, () => unsupportedMetadata("lchown"));
9512
9548
  },
9513
- utimes(_path, _atime, _mtime, req) {
9514
- return answer(req, () => void 0);
9549
+ utimes(path2, atime, mtime, req) {
9550
+ return answer(req, () => {
9551
+ vfs().utimesSync(asPath(path2), new Date(atime * 1e3), new Date(mtime * 1e3));
9552
+ return void 0;
9553
+ });
9515
9554
  },
9516
- futimes(_fd, _atime, _mtime, req) {
9517
- return answer(req, () => void 0);
9555
+ futimes(fd, atime, mtime, req) {
9556
+ return answer(req, () => {
9557
+ const file = fileFor(fd);
9558
+ file.tree.utimesSync(file.path, new Date(atime * 1e3), new Date(mtime * 1e3));
9559
+ return void 0;
9560
+ });
9518
9561
  },
9519
- lutimes(_path, _atime, _mtime, req) {
9520
- return answer(req, () => void 0);
9562
+ lutimes(path2, atime, mtime, req) {
9563
+ return answer(req, () => {
9564
+ if (treeHoldsLinks()) return unsupportedMetadata("lutimes");
9565
+ vfs().utimesSync(asPath(path2), new Date(atime * 1e3), new Date(mtime * 1e3));
9566
+ return void 0;
9567
+ });
9521
9568
  },
9522
9569
  fsync(_fd, req) {
9523
9570
  return answer(req, () => void 0);
@@ -26140,6 +26187,17 @@ class VirtualFS {
26140
26187
  /**
26141
26188
  * Get stats for path
26142
26189
  */
26190
+ chmodSync(path2, mode) {
26191
+ const node = this.getNode(path2);
26192
+ if (!node) throw createNodeError("ENOENT", "chmod", path2);
26193
+ node.mode = mode & 4095;
26194
+ }
26195
+ utimesSync(path2, atime, mtime) {
26196
+ const node = this.getNode(path2);
26197
+ if (!node) throw createNodeError("ENOENT", "utimes", path2);
26198
+ node.atime = atime instanceof Date ? atime.getTime() : atime * 1e3;
26199
+ node.mtime = mtime instanceof Date ? mtime.getTime() : mtime * 1e3;
26200
+ }
26143
26201
  statSync(path2) {
26144
26202
  var _a2;
26145
26203
  const node = this.getNode(path2);
@@ -26158,7 +26216,7 @@ class VirtualFS {
26158
26216
  isFIFO: () => false,
26159
26217
  isSocket: () => false,
26160
26218
  size,
26161
- mode: node.type === "directory" ? 493 : 420,
26219
+ mode: node.mode ?? (node.type === "directory" ? 493 : 420),
26162
26220
  mtime: new Date(mtime),
26163
26221
  atime: new Date(atime),
26164
26222
  ctime: new Date(mtime),
@@ -27892,7 +27950,7 @@ function initChildProcess(vfs2) {
27892
27950
  };
27893
27951
  };
27894
27952
  const nodeCommand = defineCommand("node", async (args, ctx) => {
27895
- var _a2, _b2;
27953
+ var _a2, _b2, _c2, _d2;
27896
27954
  if (!tree2) {
27897
27955
  return { stdout: "", stderr: "VFS not initialized\n", exitCode: 1 };
27898
27956
  }
@@ -27979,7 +28037,7 @@ function initChildProcess(vfs2) {
27979
28037
  // open, as a pipe whose writer has not closed.
27980
28038
  stdin: typeof ctx.stdin === "string" ? ctx.stdin : "",
27981
28039
  ...(streams == null ? void 0 : streams.held) || (streams == null ? void 0 : streams.stdinOpen) ? { stdinHeld: true } : {},
27982
- ...(streams == null ? void 0 : streams.held) ? { tty: true } : {},
28040
+ ...(streams == null ? void 0 : streams.held) || (streams == null ? void 0 : streams.terminal) ? { tty: true } : {},
27983
28041
  // The numbers this run was started with, so the guest's `process.pid`
27984
28042
  // is the one its parent's handle carries.
27985
28043
  ...runPid(runToken) ? { pid: runPid(runToken).pid, ppid: runPid(runToken).ppid } : {}
@@ -28021,12 +28079,28 @@ function initChildProcess(vfs2) {
28021
28079
  proc.argv0 = "node";
28022
28080
  proc.execArgv = execArgv;
28023
28081
  if (streams) streams.stdin = proc.stdin;
28024
- if (streams == null ? void 0 : streams.held) {
28082
+ if ((streams == null ? void 0 : streams.held) || (streams == null ? void 0 : streams.terminal)) {
28025
28083
  proc.stdout.isTTY = true;
28026
28084
  proc.stderr.isTTY = true;
28027
28085
  proc.stdin.isTTY = true;
28028
28086
  proc.stdin.setRawMode = () => proc.stdin;
28029
28087
  }
28088
+ const terminal = streams == null ? void 0 : streams.terminal;
28089
+ const resize = (columns, rows) => {
28090
+ for (const stream of [proc.stdout, proc.stderr]) {
28091
+ stream.columns = columns;
28092
+ stream.rows = rows;
28093
+ stream.emit("resize");
28094
+ }
28095
+ };
28096
+ let stopResize;
28097
+ let inputActive = true;
28098
+ let inputIterator;
28099
+ const readableInput = proc.stdin;
28100
+ const inputReading = () => {
28101
+ var _a3, _b3;
28102
+ return readableInput.readableFlowing === true || ((_a3 = readableInput._readableState) == null ? void 0 : _a3.reading) === true || ((_b3 = readableInput._readableState) == null ? void 0 : _b3.needReadable) === true || readableInput.listenerCount("data") > 0 || readableInput.listenerCount("readable") > 0;
28103
+ };
28030
28104
  if (Number.isInteger(channelFd) && channelFd >= 0 && runToken !== null) {
28031
28105
  enterRun(runToken, () => {
28032
28106
  attachChannel(proc, channelFd, channelSerialization);
@@ -28084,6 +28158,39 @@ ${reason.stack || ""}` : String(reason);
28084
28158
  };
28085
28159
  const detachUncaught = __onUncaughtException(proc, onUncaughtException);
28086
28160
  try {
28161
+ if (streams == null ? void 0 : streams.stdinStream) {
28162
+ inputIterator = streams.stdinStream[Symbol.asyncIterator]();
28163
+ const input = inputIterator;
28164
+ void (async () => {
28165
+ var _a3, _b3, _c3, _d3, _e2;
28166
+ const push = (chunk) => {
28167
+ if (runToken === null) proc.stdin.push(chunk);
28168
+ else enterRun(runToken, () => proc.stdin.push(chunk));
28169
+ };
28170
+ try {
28171
+ while (inputActive && !((_a3 = streams.signal) == null ? void 0 : _a3.aborted)) {
28172
+ while (inputActive && !((_b3 = streams.signal) == null ? void 0 : _b3.aborted) && (!inputReading() || readableInput.readableLength >= readableInput.readableHighWaterMark)) {
28173
+ await new Promise((resolve2) => (globalThis.__browserRuntimeNativeSetTimeout ?? setTimeout).call(globalThis, resolve2, 10));
28174
+ }
28175
+ if (!inputActive || ((_c3 = streams.signal) == null ? void 0 : _c3.aborted)) break;
28176
+ const next = await input.next();
28177
+ if (next.done) break;
28178
+ if (!inputActive || ((_d3 = streams.signal) == null ? void 0 : _d3.aborted)) break;
28179
+ push(next.value);
28180
+ }
28181
+ if (inputActive && !((_e2 = streams.signal) == null ? void 0 : _e2.aborted)) push(null);
28182
+ } catch (error) {
28183
+ if (inputActive) onUncaughtException(error);
28184
+ } finally {
28185
+ streams.stdinOpen = false;
28186
+ }
28187
+ })();
28188
+ }
28189
+ if (terminal) resize(terminal.columns, terminal.rows);
28190
+ stopResize = (_a2 = terminal == null ? void 0 : terminal.onResize) == null ? void 0 : _a2.call(terminal, (columns, rows) => {
28191
+ if (runToken === null) resize(columns, rows);
28192
+ else enterRun(runToken, () => resize(columns, rows));
28193
+ });
28087
28194
  let entrySettling;
28088
28195
  try {
28089
28196
  const runEntry = () => runtime.runFile(resolvedPath);
@@ -28121,7 +28228,7 @@ ${error.stack || ""}` : String(error);
28121
28228
  }
28122
28229
  }
28123
28230
  const __ownsHandles = () => runToken !== null && (__ownedServerPorts(runToken).length > 0 || __ownedHandleCount(runToken) > 0);
28124
- const __printedThenWorking = () => pendingGuestTimers(proc) > 0 || heldWork().count > 0 || __ownsHandles();
28231
+ const __printedThenWorking = () => (streams == null ? void 0 : streams.stdinOpen) === true && inputReading() || pendingGuestTimers(proc) > 0 || heldWork().count > 0 || __ownsHandles();
28125
28232
  if ((stdout.length > 0 || stderr.length > 0) && !__printedThenWorking()) {
28126
28233
  await new Promise((r) => (globalThis.__browserRuntimeNativeSetTimeout ?? setTimeout).call(globalThis, r, 0));
28127
28234
  if (exitCalled) return { stdout, stderr, exitCode };
@@ -28144,16 +28251,16 @@ ${error.stack || ""}` : String(error);
28144
28251
  const startTime = Date.now();
28145
28252
  let lastOutputLen = stdout.length + stderr.length;
28146
28253
  let idleMs = 0;
28147
- const stillWorking = () => pendingGuestTimers(proc) > 0 || __ownsHandles();
28254
+ const stillWorking = () => (streams == null ? void 0 : streams.stdinOpen) === true && inputReading() || pendingGuestTimers(proc) > 0 || __ownsHandles();
28148
28255
  const isLongRunning = !!(streams == null ? void 0 : streams.held);
28149
28256
  while (!exitCalled) {
28150
- if ((_a2 = streams == null ? void 0 : streams.signal) == null ? void 0 : _a2.aborted) break;
28257
+ if ((_b2 = streams == null ? void 0 : streams.signal) == null ? void 0 : _b2.aborted) break;
28151
28258
  const raceResult = await Promise.race([
28152
28259
  exitPromise.then(() => "exit"),
28153
28260
  new Promise((r) => (globalThis.__browserRuntimeNativeSetTimeout ?? setTimeout).call(globalThis, () => r("tick"), CHECK_MS))
28154
28261
  ]);
28155
28262
  if (raceResult === "exit" || exitCalled) break;
28156
- if ((_b2 = streams == null ? void 0 : streams.signal) == null ? void 0 : _b2.aborted) break;
28263
+ if ((_c2 = streams == null ? void 0 : streams.signal) == null ? void 0 : _c2.aborted) break;
28157
28264
  const currentLen = stdout.length + stderr.length;
28158
28265
  if (currentLen > lastOutputLen) {
28159
28266
  lastOutputLen = currentLen;
@@ -28178,6 +28285,16 @@ ${error.stack || ""}` : String(error);
28178
28285
  } finally {
28179
28286
  detachRejections();
28180
28287
  detachUncaught();
28288
+ inputActive = false;
28289
+ try {
28290
+ void Promise.resolve((_d2 = inputIterator == null ? void 0 : inputIterator.return) == null ? void 0 : _d2.call(inputIterator)).catch(() => {
28291
+ });
28292
+ } catch {
28293
+ }
28294
+ try {
28295
+ stopResize == null ? void 0 : stopResize();
28296
+ } catch {
28297
+ }
28181
28298
  if (runToken !== null) {
28182
28299
  __releaseOwnedServers(runToken, false);
28183
28300
  __releaseOwnedHandles(runToken);
@@ -33810,7 +33927,7 @@ class WorkerRuntime {
33810
33927
  this.worker = new Worker(
33811
33928
  new URL(
33812
33929
  /* @vite-ignore */
33813
- "/assets/runtime-worker-CUO9SNFs.js",
33930
+ "/assets/runtime-worker-DoV8lqBn.js",
33814
33931
  import.meta.url
33815
33932
  ),
33816
33933
  { type: "module" }
@@ -35228,7 +35345,7 @@ function ownedBytes(view) {
35228
35345
  return copy2;
35229
35346
  }
35230
35347
  function guestListeningServer(port, address) {
35231
- const hostname2 = address || "0.0.0.0";
35348
+ const hostname2 = address;
35232
35349
  return {
35233
35350
  listening: true,
35234
35351
  address: () => ({
@@ -35472,6 +35589,18 @@ const _ServerBridge = class _ServerBridge extends EventEmitter {
35472
35589
  __publicField(this, "upgradeChannel", null);
35473
35590
  __publicField(this, "serviceWorkerReady", false);
35474
35591
  __publicField(this, "keepaliveInterval", null);
35592
+ /**
35593
+ * Give back everything this bridge opened: the upgrade channel and the
35594
+ * service worker keepalive. A host that is done with a container calls it
35595
+ * and has its process back; calling it twice is nothing.
35596
+ */
35597
+ /**
35598
+ * Every port a guest starts listening on becomes a server this bridge can
35599
+ * answer for, and every port it stops listening on stops being one. The
35600
+ * news comes from the net binding, because that is where a port is taken;
35601
+ * the engine's `http` is Node's own file and knows nothing of a page.
35602
+ */
35603
+ __publicField(this, "guestServers", /* @__PURE__ */ new WeakSet());
35475
35604
  /** The server the service worker answers at the origin's root, the preview's; null for none. */
35476
35605
  __publicField(this, "primaryPort", null);
35477
35606
  __publicField(this, "ownDocuments");
@@ -35484,27 +35613,21 @@ const _ServerBridge = class _ServerBridge extends EventEmitter {
35484
35613
  this.watchGuestPorts();
35485
35614
  this.upgradeChannel = __substrateListenForUpgrades();
35486
35615
  }
35487
- /**
35488
- * Give back everything this bridge opened: the upgrade channel and the
35489
- * service worker keepalive. A host that is done with a container calls it
35490
- * and has its process back; calling it twice is nothing.
35491
- */
35492
- /**
35493
- * Every port a guest starts listening on becomes a server this bridge can
35494
- * answer for, and every port it stops listening on stops being one. The
35495
- * news comes from the net binding, because that is where a port is taken;
35496
- * the engine's `http` is Node's own file and knows nothing of a page.
35497
- */
35498
35616
  watchGuestPorts() {
35499
35617
  setPortWatchers(
35500
35618
  (port, address) => {
35501
35619
  if (this.servers.has(port)) return;
35502
35620
  const hostname2 = address || "0.0.0.0";
35503
- this.registerServer(guestListeningServer(port, hostname2), port, hostname2);
35621
+ const server = guestListeningServer(port, hostname2);
35622
+ this.guestServers.add(server);
35623
+ this.registerServer(server, port, hostname2);
35504
35624
  },
35505
35625
  (port) => {
35506
35626
  const entry = this.servers.get(port);
35507
- if (entry && entry.server === null) this.unregisterServer(port);
35627
+ if (entry && (entry.server === null || this.guestServers.has(entry.server))) {
35628
+ if (entry.server) entry.server.listening = false;
35629
+ this.unregisterServer(port);
35630
+ }
35508
35631
  }
35509
35632
  );
35510
35633
  }
@@ -35955,15 +36078,19 @@ function createContainer(options) {
35955
36078
  onStdout: runOptions == null ? void 0 : runOptions.onStdout,
35956
36079
  onStderr: runOptions == null ? void 0 : runOptions.onStderr,
35957
36080
  signal: runOptions == null ? void 0 : runOptions.signal,
35958
- held: (runOptions == null ? void 0 : runOptions.held) === true
36081
+ held: (runOptions == null ? void 0 : runOptions.held) === true,
36082
+ stdinStream: runOptions == null ? void 0 : runOptions.stdinStream,
36083
+ stdinOpen: (runOptions == null ? void 0 : runOptions.stdinStream) !== void 0,
36084
+ terminal: runOptions == null ? void 0 : runOptions.terminal
35959
36085
  });
35960
36086
  return new Promise((resolve2) => {
35961
36087
  runCommand(command, { cwd: runOptions == null ? void 0 : runOptions.cwd, env: runOptions == null ? void 0 : runOptions.env, stdin: typeof (runOptions == null ? void 0 : runOptions.stdin) === "string" ? runOptions.stdin : void 0, processToken, vfs: vfs2 }, (error, stdout, stderr) => {
36088
+ var _a3;
35962
36089
  releaseRunStreams(processToken);
35963
36090
  resolve2({
35964
36091
  stdout: String(stdout),
35965
36092
  stderr: String(stderr),
35966
- exitCode: error ? error.code ?? 1 : 0
36093
+ exitCode: ((_a3 = runOptions == null ? void 0 : runOptions.signal) == null ? void 0 : _a3.aborted) ? 143 : error ? error.code ?? 1 : 0
35967
36094
  });
35968
36095
  });
35969
36096
  });
@@ -45,7 +45,7 @@ export declare class FSEvent {
45
45
  #private;
46
46
  onchange: ((status: number, event: string, filename: string) => void) | null;
47
47
  initialized: boolean;
48
- start(path: unknown, _persistent?: boolean, recursive?: boolean, _encoding?: string): number;
48
+ start(path: unknown, persistent?: boolean, recursive?: boolean, _encoding?: string): number;
49
49
  close(): void;
50
50
  ref(): void;
51
51
  unref(): void;
@@ -109,7 +109,7 @@ export declare const fsBinding: {
109
109
  * a disk: a block size, and a count no program can exhaust.
110
110
  */
111
111
  statfs(_path: unknown, bigint: boolean, req?: FSReq): Float64Array | BigInt64Array | undefined;
112
- access(path: unknown, _mode: number, req?: FSReq): undefined;
112
+ access(path: unknown, mode: number, req?: FSReq): undefined;
113
113
  existsSync(path: unknown): boolean;
114
114
  /**
115
115
  * Node's `cpSync` asks this before it copies: a directory is not a file,
@@ -143,12 +143,12 @@ export declare const fsBinding: {
143
143
  mkdtemp(prefix: unknown, encoding: string, req?: FSReq): string | Uint8Array | undefined;
144
144
  chmod(path: unknown, mode: number, req?: FSReq): undefined;
145
145
  fchmod(fd: number, mode: number, req?: FSReq): undefined;
146
- chown(path: unknown, _uid: number, _gid: number, req?: FSReq): undefined;
146
+ chown(_path: unknown, _uid: number, _gid: number, req?: FSReq): undefined;
147
147
  fchown(_fd: number, _uid: number, _gid: number, req?: FSReq): undefined;
148
148
  lchown(_path: unknown, _uid: number, _gid: number, req?: FSReq): undefined;
149
- utimes(_path: unknown, _atime: number, _mtime: number, req?: FSReq): undefined;
150
- futimes(_fd: number, _atime: number, _mtime: number, req?: FSReq): undefined;
151
- lutimes(_path: unknown, _atime: number, _mtime: number, req?: FSReq): undefined;
149
+ utimes(path: unknown, atime: number, mtime: number, req?: FSReq): undefined;
150
+ futimes(fd: number, atime: number, mtime: number, req?: FSReq): undefined;
151
+ lutimes(path: unknown, atime: number, mtime: number, req?: FSReq): undefined;
152
152
  fsync(_fd: number, req?: FSReq): undefined;
153
153
  fdatasync(_fd: number, req?: FSReq): undefined;
154
154
  ftruncate(fd: number, length: number, req?: FSReq): undefined;
@@ -65,6 +65,7 @@ export declare class ServerBridge extends EventEmitter {
65
65
  * news comes from the net binding, because that is where a port is taken;
66
66
  * the engine's `http` is Node's own file and knows nothing of a page.
67
67
  */
68
+ private readonly guestServers;
68
69
  private watchGuestPorts;
69
70
  close(): void;
70
71
  /**
@@ -32,6 +32,12 @@ type RunStdin = {
32
32
  * output went down the child's channel.
33
33
  */
34
34
  export interface RunStreams {
35
+ stdinStream?: AsyncIterable<Uint8Array>;
36
+ terminal?: {
37
+ columns: number;
38
+ rows: number;
39
+ onResize?: (listener: (columns: number, rows: number) => void) => () => void;
40
+ };
35
41
  onStdout?: (data: string) => void;
36
42
  onStderr?: (data: string) => void;
37
43
  signal?: AbortSignal;
@@ -28,6 +28,7 @@ export interface FSNode {
28
28
  target?: string;
29
29
  children?: Map<string, FSNode>;
30
30
  mtime: number;
31
+ mode?: number;
31
32
  /**
32
33
  * When the file was last read. Node reports it apart from the write time
33
34
  * and `utimes` sets the two separately; this filesystem reported the write
@@ -154,6 +155,8 @@ export declare class VirtualFS {
154
155
  /**
155
156
  * Get stats for path
156
157
  */
158
+ chmodSync(path: string, mode: number): void;
159
+ utimesSync(path: string, atime: number | Date, mtime: number | Date): void;
157
160
  statSync(path: string): Stats;
158
161
  /**
159
162
  * lstatSync - same as statSync for our virtual FS (no symlinks)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/tabnode",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Node's own library, in a browser tab.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -68,6 +68,8 @@ export interface RunOptions {
68
68
  env?: Record<string, string>;
69
69
  /** What the shell reads on stdin, so a builtin reads what was piped to it. */
70
70
  stdin?: string;
71
+ stdinStream?: AsyncIterable<Uint8Array>;
72
+ terminal?: { columns: number; rows: number; onResize?: (listener: (columns: number, rows: number) => void) => () => void };
71
73
  /** Callback for streaming stdout chunks as they arrive (for long-running commands like vitest watch) */
72
74
  onStdout?: (data: string) => void;
73
75
  /** Callback for streaming stderr chunks as they arrive */
@@ -168,6 +170,9 @@ export function createContainer(options?: ContainerOptions): {
168
170
  onStderr: runOptions?.onStderr,
169
171
  signal: runOptions?.signal,
170
172
  held: runOptions?.held === true,
173
+ stdinStream: runOptions?.stdinStream,
174
+ stdinOpen: runOptions?.stdinStream !== undefined,
175
+ terminal: runOptions?.terminal,
171
176
  });
172
177
 
173
178
  return new Promise((resolve) => {
@@ -180,7 +185,7 @@ export function createContainer(options?: ContainerOptions): {
180
185
  resolve({
181
186
  stdout: String(stdout),
182
187
  stderr: String(stderr),
183
- exitCode: error ? (error.code ?? 1) : 0,
188
+ exitCode: runOptions?.signal?.aborted ? 143 : error ? (error.code ?? 1) : 0,
184
189
  });
185
190
  });
186
191
  });