@volter/tabnode 0.3.1 → 0.4.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/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) {
@@ -7157,8 +7188,12 @@ function signalNameOf(signal) {
7157
7188
  if (typeof signal === "string") return signal;
7158
7189
  return signalNames[signal] ?? "SIGTERM";
7159
7190
  }
7160
- function spawningDirectory() {
7161
- const realm = globalThis.process;
7191
+ function parentProcess(token) {
7192
+ var _a2;
7193
+ return token !== null ? (_a2 = __runFor(token)) == null ? void 0 : _a2.process : globalThis.process;
7194
+ }
7195
+ function spawningDirectory(token) {
7196
+ const realm = parentProcess(token);
7162
7197
  if (typeof (realm == null ? void 0 : realm.cwd) !== "function") return void 0;
7163
7198
  try {
7164
7199
  return realm.cwd();
@@ -7166,9 +7201,13 @@ function spawningDirectory() {
7166
7201
  return void 0;
7167
7202
  }
7168
7203
  }
7169
- function inheritedWriter$1(fd) {
7204
+ function inheritedWriter$1(fd, token) {
7170
7205
  if (fd !== 1 && fd !== 2) return null;
7171
- const realm = globalThis.process;
7206
+ if (token !== null) {
7207
+ const parent = __runFor(token);
7208
+ return (fd === 1 ? parent == null ? void 0 : parent.stdout : parent == null ? void 0 : parent.stderr) ?? null;
7209
+ }
7210
+ const realm = parentProcess(token);
7172
7211
  const stream = fd === 1 ? realm == null ? void 0 : realm.stdout : realm == null ? void 0 : realm.stderr;
7173
7212
  if (!stream || typeof stream.write !== "function") return null;
7174
7213
  return (text2) => {
@@ -7220,7 +7259,7 @@ class Process {
7220
7259
  const request = {
7221
7260
  file: options.file,
7222
7261
  args: options.args ?? [options.file],
7223
- cwd: options.cwd ?? spawningDirectory(),
7262
+ cwd: options.cwd ?? spawningDirectory(ownerOf(this)),
7224
7263
  env,
7225
7264
  detached: options.detached === true,
7226
7265
  stdout: null,
@@ -7263,7 +7302,7 @@ class Process {
7263
7302
  request.stderrIsPipe = true;
7264
7303
  }
7265
7304
  } else if (entry.type === "inherit" || entry.type === "fd") {
7266
- const inherited = inheritedWriter$1(entry.fd ?? index2);
7305
+ const inherited = inheritedWriter$1(entry.fd ?? index2, ownerOf(this));
7267
7306
  if (index2 === 1) request.stdout = inherited;
7268
7307
  else request.stderr = inherited;
7269
7308
  }
@@ -8790,7 +8829,9 @@ function refuseLinks(syscall, path2) {
8790
8829
  { code: "EPERM", errno: -1, syscall, path: path2 }
8791
8830
  );
8792
8831
  }
8793
- const pathModes = /* @__PURE__ */ new Map();
8832
+ function unsupportedMetadata(syscall) {
8833
+ throw Object.assign(new Error(`ENOTSUP: filesystem does not support ${syscall}`), { code: "ENOTSUP", syscall });
8834
+ }
8794
8835
  function treeHoldsLinks() {
8795
8836
  return vfs().holdsLinks === true;
8796
8837
  }
@@ -8854,19 +8895,18 @@ function fileFor(fd) {
8854
8895
  return file;
8855
8896
  }
8856
8897
  function statArray(stats, bigint, path2) {
8857
- var _a2, _b2;
8898
+ var _a2, _b2, _c2;
8858
8899
  const mtime = stats.mtime instanceof Date ? stats.mtime.getTime() : Number(stats.mtimeMs ?? 0);
8859
8900
  const atime = stats.atime instanceof Date ? stats.atime.getTime() : Number(stats.atimeMs ?? mtime);
8860
8901
  const ctime = stats.ctime instanceof Date ? stats.ctime.getTime() : Number(stats.ctimeMs ?? mtime);
8861
8902
  const birth = stats.birthtime instanceof Date ? stats.birthtime.getTime() : Number(stats.birthtimeMs ?? mtime);
8862
8903
  const seconds = (ms) => Math.floor(ms / 1e3);
8863
8904
  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;
8905
+ const permissions = Number(stats.mode ?? (((_a2 = stats.isDirectory) == null ? void 0 : _a2.call(stats)) ? 493 : 420)) & 4095;
8906
+ 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
8907
  const values = [
8868
8908
  Number(stats.dev ?? 0),
8869
- type2 | (permissions || (type2 === S_IFDIR ? 493 : 420)),
8909
+ type2 | permissions,
8870
8910
  Number(stats.nlink ?? 1),
8871
8911
  Number(stats.uid ?? 0),
8872
8912
  Number(stats.gid ?? 0),
@@ -9012,15 +9052,23 @@ class FSEvent {
9012
9052
  __privateAdd(this, _watcher, null);
9013
9053
  __publicField(this, "initialized", false);
9014
9054
  }
9015
- start(path2, _persistent, recursive, _encoding2) {
9055
+ start(path2, persistent, recursive, _encoding2) {
9016
9056
  const name = asPath(path2);
9017
9057
  const tree2 = vfs();
9058
+ const cwd = callingCwd();
9059
+ const owner = currentOwner();
9018
9060
  try {
9019
9061
  __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 ?? "");
9062
+ const notify = () => withFilesystem(tree2, () => withCwd(cwd, () => {
9063
+ var _a2;
9064
+ return (_a2 = this.onchange) == null ? void 0 : _a2.call(this, 0, event === "rename" ? "rename" : "change", filename ?? "");
9065
+ }));
9066
+ if (owner === null) notify();
9067
+ else enterRun(owner, notify);
9022
9068
  }));
9023
9069
  this.initialized = true;
9070
+ registerHandle(this);
9071
+ if (persistent === false) unrefHandle(this);
9024
9072
  return 0;
9025
9073
  } catch (error) {
9026
9074
  const code2 = error.code;
@@ -9029,6 +9077,7 @@ class FSEvent {
9029
9077
  }
9030
9078
  close() {
9031
9079
  var _a2;
9080
+ releaseHandle(this);
9032
9081
  this.initialized = false;
9033
9082
  try {
9034
9083
  (_a2 = __privateGet(this, _watcher)) == null ? void 0 : _a2.close();
@@ -9037,14 +9086,16 @@ class FSEvent {
9037
9086
  __privateSet(this, _watcher, null);
9038
9087
  }
9039
9088
  ref() {
9089
+ if (this.initialized) refHandle(this);
9040
9090
  }
9041
9091
  unref() {
9092
+ unrefHandle(this);
9042
9093
  }
9043
9094
  getAsyncId() {
9044
9095
  return 0;
9045
9096
  }
9046
9097
  hasRef() {
9047
- return this.initialized;
9098
+ return this.initialized && handleHasRef(this);
9048
9099
  }
9049
9100
  }
9050
9101
  _watcher = new WeakMap();
@@ -9141,6 +9192,9 @@ const fsBinding = {
9141
9192
  const tree2 = vfs();
9142
9193
  const bits = flagBits();
9143
9194
  const exists = tree2.existsSync(name);
9195
+ if (exists && ((flags & 3) !== 0 || (flags & (bits.create | bits.truncate | bits.append)) !== 0)) {
9196
+ tree2.accessSync(name, 2);
9197
+ }
9144
9198
  if ((flags & bits.excl) !== 0 && (flags & bits.create) !== 0 && exists) throw createNodeError$1("EEXIST", "open", name);
9145
9199
  if (!exists) {
9146
9200
  if ((flags & bits.create) === 0) throw createNodeError$1("ENOENT", "open", name);
@@ -9292,10 +9346,10 @@ const fsBinding = {
9292
9346
  return bigint ? BigInt64Array.from(values.map((value) => BigInt(value))) : Float64Array.from(values);
9293
9347
  });
9294
9348
  },
9295
- access(path2, _mode, req) {
9349
+ access(path2, mode, req) {
9296
9350
  return answer(req, () => {
9297
9351
  const name = asPath(path2);
9298
- if (!vfs().existsSync(name)) throw createNodeError$1("ENOENT", "access", name);
9352
+ vfs().accessSync(name, mode);
9299
9353
  return void 0;
9300
9354
  });
9301
9355
  },
@@ -9400,13 +9454,10 @@ const fsBinding = {
9400
9454
  if (tree2.existsSync(name)) {
9401
9455
  const stats = tree2.statSync(name);
9402
9456
  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
9457
  return void 0;
9407
9458
  }
9408
9459
  tree2.mkdirSync(name, { recursive });
9409
- pathModes.set(name, wanted);
9460
+ tree2.chmodSync(name, wanted);
9410
9461
  return void 0;
9411
9462
  });
9412
9463
  },
@@ -9478,46 +9529,50 @@ const fsBinding = {
9478
9529
  }
9479
9530
  });
9480
9531
  },
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.
9532
+ // Metadata belongs to the filesystem, including a host's permission view.
9533
+ // Never keep a realm-global mode table or bypass that view for descriptors.
9485
9534
  chmod(path2, mode, req) {
9486
9535
  return answer(req, () => {
9487
9536
  const name = asPath(path2);
9488
- if (!vfs().existsSync(name)) throw createNodeError$1("ENOENT", "chmod", name);
9489
- pathModes.set(name, mode & 4095);
9537
+ vfs().chmodSync(name, mode);
9490
9538
  return void 0;
9491
9539
  });
9492
9540
  },
9493
9541
  fchmod(fd, mode, req) {
9494
9542
  return answer(req, () => {
9495
9543
  const file = fileFor(fd);
9496
- pathModes.set(file.path, mode & 4095);
9544
+ file.tree.chmodSync(file.path, mode);
9497
9545
  return void 0;
9498
9546
  });
9499
9547
  },
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
- });
9548
+ chown(_path, _uid, _gid, req) {
9549
+ return answer(req, () => unsupportedMetadata("chown"));
9506
9550
  },
9507
9551
  fchown(_fd, _uid, _gid, req) {
9508
- return answer(req, () => void 0);
9552
+ return answer(req, () => unsupportedMetadata("fchown"));
9509
9553
  },
9510
9554
  lchown(_path, _uid, _gid, req) {
9511
- return answer(req, () => void 0);
9555
+ return answer(req, () => unsupportedMetadata("lchown"));
9512
9556
  },
9513
- utimes(_path, _atime, _mtime, req) {
9514
- return answer(req, () => void 0);
9557
+ utimes(path2, atime, mtime, req) {
9558
+ return answer(req, () => {
9559
+ vfs().utimesSync(asPath(path2), new Date(atime * 1e3), new Date(mtime * 1e3));
9560
+ return void 0;
9561
+ });
9515
9562
  },
9516
- futimes(_fd, _atime, _mtime, req) {
9517
- return answer(req, () => void 0);
9563
+ futimes(fd, atime, mtime, req) {
9564
+ return answer(req, () => {
9565
+ const file = fileFor(fd);
9566
+ file.tree.utimesSync(file.path, new Date(atime * 1e3), new Date(mtime * 1e3));
9567
+ return void 0;
9568
+ });
9518
9569
  },
9519
- lutimes(_path, _atime, _mtime, req) {
9520
- return answer(req, () => void 0);
9570
+ lutimes(path2, atime, mtime, req) {
9571
+ return answer(req, () => {
9572
+ if (treeHoldsLinks()) return unsupportedMetadata("lutimes");
9573
+ vfs().utimesSync(asPath(path2), new Date(atime * 1e3), new Date(mtime * 1e3));
9574
+ return void 0;
9575
+ });
9521
9576
  },
9522
9577
  fsync(_fd, req) {
9523
9578
  return answer(req, () => void 0);
@@ -26140,6 +26195,17 @@ class VirtualFS {
26140
26195
  /**
26141
26196
  * Get stats for path
26142
26197
  */
26198
+ chmodSync(path2, mode) {
26199
+ const node = this.getNode(path2);
26200
+ if (!node) throw createNodeError("ENOENT", "chmod", path2);
26201
+ node.mode = mode & 4095;
26202
+ }
26203
+ utimesSync(path2, atime, mtime) {
26204
+ const node = this.getNode(path2);
26205
+ if (!node) throw createNodeError("ENOENT", "utimes", path2);
26206
+ node.atime = atime instanceof Date ? atime.getTime() : atime * 1e3;
26207
+ node.mtime = mtime instanceof Date ? mtime.getTime() : mtime * 1e3;
26208
+ }
26143
26209
  statSync(path2) {
26144
26210
  var _a2;
26145
26211
  const node = this.getNode(path2);
@@ -26158,7 +26224,7 @@ class VirtualFS {
26158
26224
  isFIFO: () => false,
26159
26225
  isSocket: () => false,
26160
26226
  size,
26161
- mode: node.type === "directory" ? 493 : 420,
26227
+ mode: node.mode ?? (node.type === "directory" ? 493 : 420),
26162
26228
  mtime: new Date(mtime),
26163
26229
  atime: new Date(atime),
26164
26230
  ctime: new Date(mtime),
@@ -27892,7 +27958,7 @@ function initChildProcess(vfs2) {
27892
27958
  };
27893
27959
  };
27894
27960
  const nodeCommand = defineCommand("node", async (args, ctx) => {
27895
- var _a2, _b2;
27961
+ var _a2, _b2, _c2, _d2;
27896
27962
  if (!tree2) {
27897
27963
  return { stdout: "", stderr: "VFS not initialized\n", exitCode: 1 };
27898
27964
  }
@@ -27979,7 +28045,7 @@ function initChildProcess(vfs2) {
27979
28045
  // open, as a pipe whose writer has not closed.
27980
28046
  stdin: typeof ctx.stdin === "string" ? ctx.stdin : "",
27981
28047
  ...(streams == null ? void 0 : streams.held) || (streams == null ? void 0 : streams.stdinOpen) ? { stdinHeld: true } : {},
27982
- ...(streams == null ? void 0 : streams.held) ? { tty: true } : {},
28048
+ ...(streams == null ? void 0 : streams.held) || (streams == null ? void 0 : streams.terminal) ? { tty: true } : {},
27983
28049
  // The numbers this run was started with, so the guest's `process.pid`
27984
28050
  // is the one its parent's handle carries.
27985
28051
  ...runPid(runToken) ? { pid: runPid(runToken).pid, ppid: runPid(runToken).ppid } : {}
@@ -27987,6 +28053,9 @@ function initChildProcess(vfs2) {
27987
28053
  const proc = runtime.getProcess();
27988
28054
  if (runToken !== null) setRunPid(runToken, proc.pid, proc.ppid);
27989
28055
  const releaseRun = runToken === null ? null : __recordRun(runToken, {
28056
+ process: proc,
28057
+ stdout: appendStdout,
28058
+ stderr: appendStderr,
27990
28059
  pendingTimers: () => pendingGuestTimers(proc),
27991
28060
  stopTimers: () => stopGuestTimers(proc),
27992
28061
  reportUncaught: (error) => __reportUncaughtException(proc, error)
@@ -28021,12 +28090,28 @@ function initChildProcess(vfs2) {
28021
28090
  proc.argv0 = "node";
28022
28091
  proc.execArgv = execArgv;
28023
28092
  if (streams) streams.stdin = proc.stdin;
28024
- if (streams == null ? void 0 : streams.held) {
28093
+ if ((streams == null ? void 0 : streams.held) || (streams == null ? void 0 : streams.terminal)) {
28025
28094
  proc.stdout.isTTY = true;
28026
28095
  proc.stderr.isTTY = true;
28027
28096
  proc.stdin.isTTY = true;
28028
28097
  proc.stdin.setRawMode = () => proc.stdin;
28029
28098
  }
28099
+ const terminal = streams == null ? void 0 : streams.terminal;
28100
+ const resize = (columns, rows) => {
28101
+ for (const stream of [proc.stdout, proc.stderr]) {
28102
+ stream.columns = columns;
28103
+ stream.rows = rows;
28104
+ stream.emit("resize");
28105
+ }
28106
+ };
28107
+ let stopResize;
28108
+ let inputActive = true;
28109
+ let inputIterator;
28110
+ const readableInput = proc.stdin;
28111
+ const inputReading = () => {
28112
+ var _a3, _b3;
28113
+ 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;
28114
+ };
28030
28115
  if (Number.isInteger(channelFd) && channelFd >= 0 && runToken !== null) {
28031
28116
  enterRun(runToken, () => {
28032
28117
  attachChannel(proc, channelFd, channelSerialization);
@@ -28084,6 +28169,39 @@ ${reason.stack || ""}` : String(reason);
28084
28169
  };
28085
28170
  const detachUncaught = __onUncaughtException(proc, onUncaughtException);
28086
28171
  try {
28172
+ if (streams == null ? void 0 : streams.stdinStream) {
28173
+ inputIterator = streams.stdinStream[Symbol.asyncIterator]();
28174
+ const input = inputIterator;
28175
+ void (async () => {
28176
+ var _a3, _b3, _c3, _d3, _e2;
28177
+ const push = (chunk) => {
28178
+ if (runToken === null) proc.stdin.push(chunk);
28179
+ else enterRun(runToken, () => proc.stdin.push(chunk));
28180
+ };
28181
+ try {
28182
+ while (inputActive && !((_a3 = streams.signal) == null ? void 0 : _a3.aborted)) {
28183
+ while (inputActive && !((_b3 = streams.signal) == null ? void 0 : _b3.aborted) && (!inputReading() || readableInput.readableLength >= readableInput.readableHighWaterMark)) {
28184
+ await new Promise((resolve2) => (globalThis.__browserRuntimeNativeSetTimeout ?? setTimeout).call(globalThis, resolve2, 10));
28185
+ }
28186
+ if (!inputActive || ((_c3 = streams.signal) == null ? void 0 : _c3.aborted)) break;
28187
+ const next = await input.next();
28188
+ if (next.done) break;
28189
+ if (!inputActive || ((_d3 = streams.signal) == null ? void 0 : _d3.aborted)) break;
28190
+ push(next.value);
28191
+ }
28192
+ if (inputActive && !((_e2 = streams.signal) == null ? void 0 : _e2.aborted)) push(null);
28193
+ } catch (error) {
28194
+ if (inputActive) onUncaughtException(error);
28195
+ } finally {
28196
+ streams.stdinOpen = false;
28197
+ }
28198
+ })();
28199
+ }
28200
+ if (terminal) resize(terminal.columns, terminal.rows);
28201
+ stopResize = (_a2 = terminal == null ? void 0 : terminal.onResize) == null ? void 0 : _a2.call(terminal, (columns, rows) => {
28202
+ if (runToken === null) resize(columns, rows);
28203
+ else enterRun(runToken, () => resize(columns, rows));
28204
+ });
28087
28205
  let entrySettling;
28088
28206
  try {
28089
28207
  const runEntry = () => runtime.runFile(resolvedPath);
@@ -28121,7 +28239,7 @@ ${error.stack || ""}` : String(error);
28121
28239
  }
28122
28240
  }
28123
28241
  const __ownsHandles = () => runToken !== null && (__ownedServerPorts(runToken).length > 0 || __ownedHandleCount(runToken) > 0);
28124
- const __printedThenWorking = () => pendingGuestTimers(proc) > 0 || heldWork().count > 0 || __ownsHandles();
28242
+ const __printedThenWorking = () => (streams == null ? void 0 : streams.stdinOpen) === true && inputReading() || pendingGuestTimers(proc) > 0 || heldWork().count > 0 || __ownsHandles();
28125
28243
  if ((stdout.length > 0 || stderr.length > 0) && !__printedThenWorking()) {
28126
28244
  await new Promise((r) => (globalThis.__browserRuntimeNativeSetTimeout ?? setTimeout).call(globalThis, r, 0));
28127
28245
  if (exitCalled) return { stdout, stderr, exitCode };
@@ -28144,16 +28262,16 @@ ${error.stack || ""}` : String(error);
28144
28262
  const startTime = Date.now();
28145
28263
  let lastOutputLen = stdout.length + stderr.length;
28146
28264
  let idleMs = 0;
28147
- const stillWorking = () => pendingGuestTimers(proc) > 0 || __ownsHandles();
28265
+ const stillWorking = () => (streams == null ? void 0 : streams.stdinOpen) === true && inputReading() || pendingGuestTimers(proc) > 0 || __ownsHandles();
28148
28266
  const isLongRunning = !!(streams == null ? void 0 : streams.held);
28149
28267
  while (!exitCalled) {
28150
- if ((_a2 = streams == null ? void 0 : streams.signal) == null ? void 0 : _a2.aborted) break;
28268
+ if ((_b2 = streams == null ? void 0 : streams.signal) == null ? void 0 : _b2.aborted) break;
28151
28269
  const raceResult = await Promise.race([
28152
28270
  exitPromise.then(() => "exit"),
28153
28271
  new Promise((r) => (globalThis.__browserRuntimeNativeSetTimeout ?? setTimeout).call(globalThis, () => r("tick"), CHECK_MS))
28154
28272
  ]);
28155
28273
  if (raceResult === "exit" || exitCalled) break;
28156
- if ((_b2 = streams == null ? void 0 : streams.signal) == null ? void 0 : _b2.aborted) break;
28274
+ if ((_c2 = streams == null ? void 0 : streams.signal) == null ? void 0 : _c2.aborted) break;
28157
28275
  const currentLen = stdout.length + stderr.length;
28158
28276
  if (currentLen > lastOutputLen) {
28159
28277
  lastOutputLen = currentLen;
@@ -28178,6 +28296,16 @@ ${error.stack || ""}` : String(error);
28178
28296
  } finally {
28179
28297
  detachRejections();
28180
28298
  detachUncaught();
28299
+ inputActive = false;
28300
+ try {
28301
+ void Promise.resolve((_d2 = inputIterator == null ? void 0 : inputIterator.return) == null ? void 0 : _d2.call(inputIterator)).catch(() => {
28302
+ });
28303
+ } catch {
28304
+ }
28305
+ try {
28306
+ stopResize == null ? void 0 : stopResize();
28307
+ } catch {
28308
+ }
28181
28309
  if (runToken !== null) {
28182
28310
  __releaseOwnedServers(runToken, false);
28183
28311
  __releaseOwnedHandles(runToken);
@@ -33810,7 +33938,7 @@ class WorkerRuntime {
33810
33938
  this.worker = new Worker(
33811
33939
  new URL(
33812
33940
  /* @vite-ignore */
33813
- "/assets/runtime-worker-CUO9SNFs.js",
33941
+ "/assets/runtime-worker-LWfW6VWE.js",
33814
33942
  import.meta.url
33815
33943
  ),
33816
33944
  { type: "module" }
@@ -35228,7 +35356,7 @@ function ownedBytes(view) {
35228
35356
  return copy2;
35229
35357
  }
35230
35358
  function guestListeningServer(port, address) {
35231
- const hostname2 = address || "0.0.0.0";
35359
+ const hostname2 = address;
35232
35360
  return {
35233
35361
  listening: true,
35234
35362
  address: () => ({
@@ -35472,6 +35600,18 @@ const _ServerBridge = class _ServerBridge extends EventEmitter {
35472
35600
  __publicField(this, "upgradeChannel", null);
35473
35601
  __publicField(this, "serviceWorkerReady", false);
35474
35602
  __publicField(this, "keepaliveInterval", null);
35603
+ /**
35604
+ * Give back everything this bridge opened: the upgrade channel and the
35605
+ * service worker keepalive. A host that is done with a container calls it
35606
+ * and has its process back; calling it twice is nothing.
35607
+ */
35608
+ /**
35609
+ * Every port a guest starts listening on becomes a server this bridge can
35610
+ * answer for, and every port it stops listening on stops being one. The
35611
+ * news comes from the net binding, because that is where a port is taken;
35612
+ * the engine's `http` is Node's own file and knows nothing of a page.
35613
+ */
35614
+ __publicField(this, "guestServers", /* @__PURE__ */ new WeakSet());
35475
35615
  /** The server the service worker answers at the origin's root, the preview's; null for none. */
35476
35616
  __publicField(this, "primaryPort", null);
35477
35617
  __publicField(this, "ownDocuments");
@@ -35484,27 +35624,21 @@ const _ServerBridge = class _ServerBridge extends EventEmitter {
35484
35624
  this.watchGuestPorts();
35485
35625
  this.upgradeChannel = __substrateListenForUpgrades();
35486
35626
  }
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
35627
  watchGuestPorts() {
35499
35628
  setPortWatchers(
35500
35629
  (port, address) => {
35501
35630
  if (this.servers.has(port)) return;
35502
35631
  const hostname2 = address || "0.0.0.0";
35503
- this.registerServer(guestListeningServer(port, hostname2), port, hostname2);
35632
+ const server = guestListeningServer(port, hostname2);
35633
+ this.guestServers.add(server);
35634
+ this.registerServer(server, port, hostname2);
35504
35635
  },
35505
35636
  (port) => {
35506
35637
  const entry = this.servers.get(port);
35507
- if (entry && entry.server === null) this.unregisterServer(port);
35638
+ if (entry && (entry.server === null || this.guestServers.has(entry.server))) {
35639
+ if (entry.server) entry.server.listening = false;
35640
+ this.unregisterServer(port);
35641
+ }
35508
35642
  }
35509
35643
  );
35510
35644
  }
@@ -35955,15 +36089,19 @@ function createContainer(options) {
35955
36089
  onStdout: runOptions == null ? void 0 : runOptions.onStdout,
35956
36090
  onStderr: runOptions == null ? void 0 : runOptions.onStderr,
35957
36091
  signal: runOptions == null ? void 0 : runOptions.signal,
35958
- held: (runOptions == null ? void 0 : runOptions.held) === true
36092
+ held: (runOptions == null ? void 0 : runOptions.held) === true,
36093
+ stdinStream: runOptions == null ? void 0 : runOptions.stdinStream,
36094
+ stdinOpen: (runOptions == null ? void 0 : runOptions.stdinStream) !== void 0,
36095
+ terminal: runOptions == null ? void 0 : runOptions.terminal
35959
36096
  });
35960
36097
  return new Promise((resolve2) => {
35961
36098
  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) => {
36099
+ var _a3;
35962
36100
  releaseRunStreams(processToken);
35963
36101
  resolve2({
35964
36102
  stdout: String(stdout),
35965
36103
  stderr: String(stderr),
35966
- exitCode: error ? error.code ?? 1 : 0
36104
+ exitCode: ((_a3 = runOptions == null ? void 0 : runOptions.signal) == null ? void 0 : _a3.aborted) ? 143 : error ? error.code ?? 1 : 0
35967
36105
  });
35968
36106
  });
35969
36107
  });
@@ -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;
@@ -21,7 +21,7 @@
21
21
  import { LibuvStreamWrap } from './stream_wrap';
22
22
  import { Pipe } from './pipe_wrap';
23
23
  import { type OwnedHandle } from './handles';
24
- import type { ProcessToken } from '../../process-tokens';
24
+ import { type ProcessToken } from '../../process-tokens';
25
25
  /** One entry of Node's `options.stdio`, as `getValidStdio` builds it. */
26
26
  export interface StdioEntry {
27
27
  type: 'pipe' | 'overlapped' | 'ignore' | 'inherit' | 'fd' | 'wrap';
@@ -14,12 +14,17 @@
14
14
  * for both. The guest never sees the variable: the environment the `node`
15
15
  * command gives its process has it removed.
16
16
  */
17
+ import type { Process } from './shims/process';
17
18
  /** Whatever the embedding runtime uses to name one guest process. */
18
19
  export type ProcessToken = string;
19
20
  /** The environment variable a run's name travels in, from `exec` to `node`. */
20
21
  export declare const PROCESS_TOKEN_ENV = "__TABNODE_PROCESS_TOKEN";
21
22
  /** What the engine can answer about one named run. */
22
23
  export interface OwnedRun {
24
+ /** The guest whose cwd and inherited streams belong to this run. */
25
+ process: Process;
26
+ stdout(text: string): void;
27
+ stderr(text: string): void;
23
28
  /** The timers the run's guest still holds, as Node's loop counts them. */
24
29
  pendingTimers(): number;
25
30
  /** Clear those timers, as ending the process clears them. */
@@ -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;