constructor()

in src/js/node/wasi.ts [787:1787]


      constructor(wasiConfig = {}) {
        const defaultConfig = getDefaults();
        this.lastStdin = 0;
        this.sleep = wasiConfig.sleep || defaultConfig.sleep;
        this.getStdin = wasiConfig.getStdin;
        this.sendStdout = wasiConfig.sendStdout;
        this.sendStderr = wasiConfig.sendStderr;
        let preopens = wasiConfig.preopens ?? defaultConfig.preopens;
        this.env = wasiConfig.env ?? defaultConfig.env;

        const args = wasiConfig.args ?? defaultConfig.args;
        this.memory = void 0;
        this.view = void 0;
        this.bindings = wasiConfig.bindings || defaultConfig.bindings;
        const bindings = this.bindings;
        fs = bindings.fs;
        this.FD_MAP = /* @__PURE__ */ new Map([
          [
            constants_1.WASI_STDIN_FILENO,
            {
              real: 0,
              filetype: constants_1.WASI_FILETYPE_CHARACTER_DEVICE,
              rights: {
                base: STDIN_DEFAULT_RIGHTS,
                inheriting: BigInt(0),
              },
              path: "/dev/stdin",
            },
          ],
          [
            constants_1.WASI_STDOUT_FILENO,
            {
              real: 1,
              filetype: constants_1.WASI_FILETYPE_CHARACTER_DEVICE,
              rights: {
                base: STDOUT_DEFAULT_RIGHTS,
                inheriting: BigInt(0),
              },
              path: "/dev/stdout",
            },
          ],
          [
            constants_1.WASI_STDERR_FILENO,
            {
              real: 2,
              filetype: constants_1.WASI_FILETYPE_CHARACTER_DEVICE,
              rights: {
                base: STDERR_DEFAULT_RIGHTS,
                inheriting: BigInt(0),
              },
              path: "/dev/stderr",
            },
          ],
        ]);
        const path = bindings.path;
        for (const [k, v] of Object.entries(preopens)) {
          const real = fs.openSync(v, nodeFsConstants.O_RDONLY);
          const newfd = this.getUnusedFileDescriptor();
          this.FD_MAP.set(newfd, {
            real,
            filetype: constants_1.WASI_FILETYPE_DIRECTORY,
            rights: {
              base: constants_1.RIGHTS_DIRECTORY_BASE,
              inheriting: constants_1.RIGHTS_DIRECTORY_INHERITING,
            },
            fakePath: k,
            path: v,
          });
        }
        const getiovs = (iovs, iovsLen) => {
          this.refreshMemory();

          const { view, memory } = this;
          const { buffer } = memory;
          const { byteLength } = buffer;

          if (iovsLen === 1) {
            const ptr = iovs;
            const buf = view.getUint32(ptr, true);
            let bufLen = view.getUint32(ptr + 4, true);

            if (bufLen > byteLength - buf) {
              console.log({
                buf,
                bufLen,
                total_memory: byteLength,
              });
              log("getiovs: warning -- truncating buffer to fit in memory");
              bufLen = Math.min(bufLen, Math.max(0, byteLength - buf));
            }
            try {
              return [new Uint8Array(buffer, buf, bufLen)];
            } catch (err) {
              console.warn("WASI.getiovs -- invalid buffer", err);
              throw new types_1.WASIError(constants_1.WASI_EINVAL);
            }
          }

          // Avoid referencing Array because materializing the Array constructor can show up in profiling
          const buffers = [];
          buffers.length = iovsLen;

          for (let i = 0, ptr = iovs; i < iovsLen; i++, ptr += 8) {
            const buf = view.getUint32(ptr, true);
            let bufLen = view.getUint32(ptr + 4, true);

            if (bufLen > byteLength - buf) {
              console.log({
                buf,
                bufLen,
                total_memory: byteLength,
              });
              log("getiovs: warning -- truncating buffer to fit in memory");
              bufLen = Math.min(bufLen, Math.max(0, byteLength - buf));
            }
            try {
              buffers[i] = new Uint8Array(buffer, buf, bufLen);
            } catch (err) {
              console.warn("WASI.getiovs -- invalid buffer", err);
              throw new types_1.WASIError(constants_1.WASI_EINVAL);
            }
          }
          return buffers;
        };
        const CHECK_FD = (fd, rights) => {
          const stats = stat(this, fd);
          if (rights !== BigInt(0) && (stats.rights.base & rights) === BigInt(0)) {
            throw new types_1.WASIError(constants_1.WASI_EPERM);
          }
          return stats;
        };
        const CPUTIME_START = Bun.nanoseconds();
        const timeOrigin = Math.trunc(performance.timeOrigin * 1e6);
        const now = clockId => {
          switch (clockId) {
            case constants_1.WASI_CLOCK_MONOTONIC:
              return Bun.nanoseconds();
            case constants_1.WASI_CLOCK_REALTIME:
              return Bun.nanoseconds() + timeOrigin;
            case constants_1.WASI_CLOCK_PROCESS_CPUTIME_ID:
            case constants_1.WASI_CLOCK_THREAD_CPUTIME_ID:
              return Bun.nanoseconds() - CPUTIME_START;
            default:
              return null;
          }
        };
        this.wasiImport = {
          args_get: (argv, argvBuf) => {
            this.refreshMemory();
            let coffset = argv;
            let offset = argvBuf;
            args.forEach(a => {
              this.view.setUint32(coffset, offset, true);
              coffset += 4;
              offset += Buffer.from(this.memory.buffer).write(`${a}\0`, offset);
            });
            return constants_1.WASI_ESUCCESS;
          },
          args_sizes_get: (argc, argvBufSize) => {
            this.refreshMemory();
            this.view.setUint32(argc, args.length, true);
            const size = args.reduce((acc, a) => acc + Buffer.byteLength(a) + 1, 0);
            this.view.setUint32(argvBufSize, size, true);
            return constants_1.WASI_ESUCCESS;
          },
          environ_get: (environ, environBuf) => {
            this.refreshMemory();
            let coffset = environ;
            let offset = environBuf;
            Object.entries(this.env).forEach(([key, value]) => {
              this.view.setUint32(coffset, offset, true);
              coffset += 4;
              offset += Buffer.from(this.memory.buffer).write(`${key}=${value}\0`, offset);
            });
            return constants_1.WASI_ESUCCESS;
          },
          environ_sizes_get: (environCount, environBufSize) => {
            this.refreshMemory();
            const envProcessed = Object.entries(this.env).map(([key, value]) => `${key}=${value}\0`);
            const size = envProcessed.reduce((acc, e) => acc + Buffer.byteLength(e), 0);
            this.view.setUint32(environCount, envProcessed.length, true);
            this.view.setUint32(environBufSize, size, true);
            return constants_1.WASI_ESUCCESS;
          },
          clock_res_get: (clockId, resolution) => {
            let res;
            switch (clockId) {
              case constants_1.WASI_CLOCK_MONOTONIC:
              case constants_1.WASI_CLOCK_PROCESS_CPUTIME_ID:
              case constants_1.WASI_CLOCK_THREAD_CPUTIME_ID: {
                res = BigInt(1);
                break;
              }
              case constants_1.WASI_CLOCK_REALTIME: {
                res = BigInt(1e3);
                break;
              }
            }
            if (!res) {
              throw Error("invalid clockId");
            }
            this.view.setBigUint64(resolution, res);
            return constants_1.WASI_ESUCCESS;
          },
          clock_time_get: (clockId, _precision, time) => {
            this.refreshMemory();
            const n = now(clockId);
            if (n === null) {
              return constants_1.WASI_EINVAL;
            }
            this.view.setBigUint64(time, BigInt(n), true);
            return constants_1.WASI_ESUCCESS;
          },
          fd_advise: wrap((fd, _offset, _len, _advice) => {
            CHECK_FD(fd, constants_1.WASI_RIGHT_FD_ADVISE);
            return constants_1.WASI_ENOSYS;
          }),
          fd_allocate: wrap((fd, _offset, _len) => {
            CHECK_FD(fd, constants_1.WASI_RIGHT_FD_ALLOCATE);
            return constants_1.WASI_ENOSYS;
          }),
          fd_close: wrap(fd => {
            const stats = CHECK_FD(fd, BigInt(0));
            fs.closeSync(stats.real);
            this.FD_MAP.delete(fd);
            return constants_1.WASI_ESUCCESS;
          }),
          fd_datasync: wrap(fd => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_FD_DATASYNC);
            fs.fdatasyncSync(stats.real);
            return constants_1.WASI_ESUCCESS;
          }),
          fd_fdstat_get: wrap((fd, bufPtr) => {
            const stats = CHECK_FD(fd, BigInt(0));
            this.refreshMemory();
            if (stats.filetype == null) {
              throw Error("stats.filetype must be set");
            }
            this.view.setUint8(bufPtr, stats.filetype);
            this.view.setUint16(bufPtr + 2, 0, true);
            this.view.setUint16(bufPtr + 4, 0, true);
            this.view.setBigUint64(bufPtr + 8, BigInt(stats.rights.base), true);
            this.view.setBigUint64(bufPtr + 8 + 8, BigInt(stats.rights.inheriting), true);
            return constants_1.WASI_ESUCCESS;
          }),
          fd_fdstat_set_flags: wrap((fd, flags) => {
            CHECK_FD(fd, constants_1.WASI_RIGHT_FD_FDSTAT_SET_FLAGS);
            if (this.wasiImport.sock_fcntlSetFlags(fd, flags) == 0) {
              return constants_1.WASI_ESUCCESS;
            }
            return constants_1.WASI_ENOSYS;
          }),
          fd_fdstat_set_rights: wrap((fd, fsRightsBase, fsRightsInheriting) => {
            const stats = CHECK_FD(fd, BigInt(0));
            const nrb = stats.rights.base | fsRightsBase;
            if (nrb > stats.rights.base) {
              return constants_1.WASI_EPERM;
            }
            const nri = stats.rights.inheriting | fsRightsInheriting;
            if (nri > stats.rights.inheriting) {
              return constants_1.WASI_EPERM;
            }
            stats.rights.base = fsRightsBase;
            stats.rights.inheriting = fsRightsInheriting;
            return constants_1.WASI_ESUCCESS;
          }),
          fd_filestat_get: wrap((fd, bufPtr) => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_FD_FILESTAT_GET);
            const rstats = this.fstatSync(stats.real);
            this.refreshMemory();
            this.view.setBigUint64(bufPtr, BigInt(rstats.dev), true);
            bufPtr += 8;
            this.view.setBigUint64(bufPtr, BigInt(rstats.ino), true);
            bufPtr += 8;
            if (stats.filetype == null) {
              throw Error("stats.filetype must be set");
            }
            this.view.setUint8(bufPtr, stats.filetype);
            bufPtr += 8;
            this.view.setBigUint64(bufPtr, BigInt(rstats.nlink), true);
            bufPtr += 8;
            this.view.setBigUint64(bufPtr, BigInt(rstats.size), true);
            bufPtr += 8;
            this.view.setBigUint64(bufPtr, msToNs(rstats.atimeMs), true);
            bufPtr += 8;
            this.view.setBigUint64(bufPtr, msToNs(rstats.mtimeMs), true);
            bufPtr += 8;
            this.view.setBigUint64(bufPtr, msToNs(rstats.ctimeMs), true);
            return constants_1.WASI_ESUCCESS;
          }),
          fd_filestat_set_size: wrap((fd, stSize) => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_FD_FILESTAT_SET_SIZE);
            fs.ftruncateSync(stats.real, Number(stSize));
            return constants_1.WASI_ESUCCESS;
          }),
          fd_filestat_set_times: wrap((fd, stAtim, stMtim, fstflags) => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_FD_FILESTAT_SET_TIMES);
            const rstats = this.fstatSync(stats.real);
            let atim = rstats.atime;
            let mtim = rstats.mtime;
            const n = nsToMs(now(constants_1.WASI_CLOCK_REALTIME));
            const atimflags = constants_1.WASI_FILESTAT_SET_ATIM | constants_1.WASI_FILESTAT_SET_ATIM_NOW;
            if ((fstflags & atimflags) === atimflags) {
              return constants_1.WASI_EINVAL;
            }
            const mtimflags = constants_1.WASI_FILESTAT_SET_MTIM | constants_1.WASI_FILESTAT_SET_MTIM_NOW;
            if ((fstflags & mtimflags) === mtimflags) {
              return constants_1.WASI_EINVAL;
            }
            if ((fstflags & constants_1.WASI_FILESTAT_SET_ATIM) === constants_1.WASI_FILESTAT_SET_ATIM) {
              atim = nsToMs(stAtim);
            } else if ((fstflags & constants_1.WASI_FILESTAT_SET_ATIM_NOW) === constants_1.WASI_FILESTAT_SET_ATIM_NOW) {
              atim = n;
            }
            if ((fstflags & constants_1.WASI_FILESTAT_SET_MTIM) === constants_1.WASI_FILESTAT_SET_MTIM) {
              mtim = nsToMs(stMtim);
            } else if ((fstflags & constants_1.WASI_FILESTAT_SET_MTIM_NOW) === constants_1.WASI_FILESTAT_SET_MTIM_NOW) {
              mtim = n;
            }
            fs.futimesSync(stats.real, new Date(atim), new Date(mtim));
            return constants_1.WASI_ESUCCESS;
          }),
          fd_prestat_get: wrap((fd, bufPtr) => {
            const stats = CHECK_FD(fd, BigInt(0));
            this.refreshMemory();
            this.view.setUint8(bufPtr, constants_1.WASI_PREOPENTYPE_DIR);
            this.view.setUint32(bufPtr + 4, Buffer.byteLength(stats.fakePath ?? stats.path ?? ""), true);
            return constants_1.WASI_ESUCCESS;
          }),
          fd_prestat_dir_name: wrap((fd, pathPtr, pathLen) => {
            const stats = CHECK_FD(fd, BigInt(0));
            this.refreshMemory();
            Buffer.from(this.memory.buffer).write(stats.fakePath ?? stats.path ?? "", pathPtr, pathLen, "utf8");
            return constants_1.WASI_ESUCCESS;
          }),
          fd_pwrite: wrap((fd, iovs, iovsLen, offset, nwritten) => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_FD_WRITE | constants_1.WASI_RIGHT_FD_SEEK);
            let written = 0;
            getiovs(iovs, iovsLen).forEach(iov => {
              let w = 0;
              while (w < iov.byteLength) {
                w += fs.writeSync(stats.real, iov, w, iov.byteLength - w, Number(offset) + written + w);
              }
              written += w;
            });
            this.view.setUint32(nwritten, written, true);
            return constants_1.WASI_ESUCCESS;
          }),
          fd_write: wrap((fd, iovs, iovsLen, nwritten) => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_FD_WRITE);
            const IS_STDOUT = fd == constants_1.WASI_STDOUT_FILENO;
            const IS_STDERR = fd == constants_1.WASI_STDERR_FILENO;
            let written = 0;
            getiovs(iovs, iovsLen).forEach(iov => {
              if (iov.byteLength == 0) return;
              if (IS_STDOUT && this.sendStdout != null) {
                this.sendStdout(iov);
                written += iov.byteLength;
              } else if (IS_STDERR && this.sendStderr != null) {
                this.sendStderr(iov);
                written += iov.byteLength;
              } else {
                let w = 0;
                while (w < iov.byteLength) {
                  const i = fs.writeSync(
                    stats.real,
                    iov,
                    w,
                    iov.byteLength - w,
                    stats.offset ? Number(stats.offset) : null,
                  );
                  if (stats.offset) stats.offset += BigInt(i);
                  w += i;
                }
                written += w;
              }
            });
            this.view.setUint32(nwritten, written, true);
            return constants_1.WASI_ESUCCESS;
          }),
          fd_pread: wrap((fd, iovs, iovsLen, offset, nread) => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_FD_READ | constants_1.WASI_RIGHT_FD_SEEK);
            let read = 0;
            outer: for (const iov of getiovs(iovs, iovsLen)) {
              let r = 0;
              while (r < iov.byteLength) {
                const length = iov.byteLength - r;
                const rr = fs.readSync(stats.real, iov, r, iov.byteLength - r, Number(offset) + read + r);
                r += rr;
                read += rr;
                if (rr === 0 || rr < length) {
                  break outer;
                }
              }
              read += r;
            }
            this.view.setUint32(nread, read, true);
            return constants_1.WASI_ESUCCESS;
          }),
          fd_read: wrap((fd, iovs, iovsLen, nread) => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_FD_READ);
            const IS_STDIN = fd == constants_1.WASI_STDIN_FILENO;
            let read = 0;
            outer: for (const iov of getiovs(iovs, iovsLen)) {
              let r = 0;
              while (r < iov.byteLength) {
                let length = iov.byteLength - r;
                let position = IS_STDIN || stats.offset === void 0 ? null : Number(stats.offset);
                let rr = 0;
                if (IS_STDIN) {
                  if (this.getStdin != null) {
                    if (this.stdinBuffer == null) {
                      this.stdinBuffer = this.getStdin();
                    }
                    if (this.stdinBuffer != null) {
                      rr = this.stdinBuffer.copy(iov);
                      if (rr == this.stdinBuffer.length) {
                        this.stdinBuffer = void 0;
                      } else {
                        this.stdinBuffer = this.stdinBuffer.slice(rr);
                      }
                      if (rr > 0) {
                        this.lastStdin = new Date().valueOf();
                      }
                    }
                  } else {
                    if (this.sleep == null && !warnedAboutSleep) {
                      warnedAboutSleep = true;
                      console.log("(cpu waiting for stdin: please define a way to sleep!) ");
                    }
                    try {
                      rr = fs.readSync(stats.real, iov, r, length, position);
                    } catch (_err) {}
                    if (rr == 0) {
                      this.shortPause();
                    } else {
                      this.lastStdin = new Date().valueOf();
                    }
                  }
                } else {
                  rr = fs.readSync(stats.real, iov, r, length, position);
                }
                if (stats.filetype == constants_1.WASI_FILETYPE_REGULAR_FILE) {
                  stats.offset = (stats.offset ? stats.offset : BigInt(0)) + BigInt(rr);
                }
                r += rr;
                read += rr;
                if (rr === 0 || rr < length) {
                  break outer;
                }
              }
            }
            this.view.setUint32(nread, read, true);
            return constants_1.WASI_ESUCCESS;
          }),
          fd_readdir: wrap((fd, bufPtr, bufLen, cookie, bufusedPtr) => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_FD_READDIR);
            this.refreshMemory();
            const entries = fs.readdirSync(stats.path, { withFileTypes: true });
            const startPtr = bufPtr;
            for (let i = Number(cookie); i < entries.length; i += 1) {
              const entry = entries[i];
              let nameLength = Buffer.byteLength(entry.name);
              if (bufPtr - startPtr > bufLen) {
                break;
              }
              this.view.setBigUint64(bufPtr, BigInt(i + 1), true);
              bufPtr += 8;
              if (bufPtr - startPtr > bufLen) {
                break;
              }
              const rstats = fs.lstatSync(path.resolve(stats.path, entry.name));
              this.view.setBigUint64(bufPtr, BigInt(rstats.ino), true);
              bufPtr += 8;
              if (bufPtr - startPtr > bufLen) {
                break;
              }
              this.view.setUint32(bufPtr, nameLength, true);
              bufPtr += 4;
              if (bufPtr - startPtr > bufLen) {
                break;
              }
              let filetype;
              switch (true) {
                case rstats.isBlockDevice():
                  filetype = constants_1.WASI_FILETYPE_BLOCK_DEVICE;
                  break;
                case rstats.isCharacterDevice():
                  filetype = constants_1.WASI_FILETYPE_CHARACTER_DEVICE;
                  break;
                case rstats.isDirectory():
                  filetype = constants_1.WASI_FILETYPE_DIRECTORY;
                  break;
                case rstats.isFIFO():
                  filetype = constants_1.WASI_FILETYPE_SOCKET_STREAM;
                  break;
                case rstats.isFile():
                  filetype = constants_1.WASI_FILETYPE_REGULAR_FILE;
                  break;
                case rstats.isSocket():
                  filetype = constants_1.WASI_FILETYPE_SOCKET_STREAM;
                  break;
                case rstats.isSymbolicLink():
                  filetype = constants_1.WASI_FILETYPE_SYMBOLIC_LINK;
                  break;
                default:
                  filetype = constants_1.WASI_FILETYPE_UNKNOWN;
                  break;
              }
              this.view.setUint8(bufPtr, filetype);
              bufPtr += 1;
              bufPtr += 3;
              if (bufPtr + nameLength >= startPtr + bufLen) {
                break;
              }
              let memory_buffer = Buffer.from(this.memory.buffer);
              memory_buffer.write(entry.name, bufPtr);
              bufPtr += nameLength;
            }
            const bufused = bufPtr - startPtr;
            this.view.setUint32(bufusedPtr, Math.min(bufused, bufLen), true);
            return constants_1.WASI_ESUCCESS;
          }),
          fd_renumber: wrap((from, to) => {
            CHECK_FD(from, BigInt(0));
            CHECK_FD(to, BigInt(0));
            fs.closeSync(this.FD_MAP.get(from).real);
            this.FD_MAP.set(from, this.FD_MAP.get(to));
            this.FD_MAP.delete(to);
            return constants_1.WASI_ESUCCESS;
          }),
          fd_seek: wrap((fd, offset, whence, newOffsetPtr) => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_FD_SEEK);
            this.refreshMemory();
            switch (whence) {
              case constants_1.WASI_WHENCE_CUR:
                stats.offset = (stats.offset ? stats.offset : BigInt(0)) + BigInt(offset);
                break;
              case constants_1.WASI_WHENCE_END:
                const { size } = this.fstatSync(stats.real);
                stats.offset = BigInt(size) + BigInt(offset);
                break;
              case constants_1.WASI_WHENCE_SET:
                stats.offset = BigInt(offset);
                break;
            }
            if (stats.offset == null) {
              throw Error("stats.offset must be defined");
            }
            this.view.setBigUint64(newOffsetPtr, stats.offset, true);
            return constants_1.WASI_ESUCCESS;
          }),
          fd_tell: wrap((fd, offsetPtr) => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_FD_TELL);
            this.refreshMemory();
            if (!stats.offset) {
              stats.offset = BigInt(0);
            }
            this.view.setBigUint64(offsetPtr, stats.offset, true);
            return constants_1.WASI_ESUCCESS;
          }),
          fd_sync: wrap(fd => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_FD_SYNC);
            fs.fsyncSync(stats.real);
            return constants_1.WASI_ESUCCESS;
          }),
          path_create_directory: wrap((fd, pathPtr, pathLen) => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_PATH_CREATE_DIRECTORY);
            if (!stats.path) {
              return constants_1.WASI_EINVAL;
            }
            this.refreshMemory();
            const p = Buffer.from(this.memory.buffer, pathPtr, pathLen).toString();
            fs.mkdirSync(path.resolve(stats.path, p));
            return constants_1.WASI_ESUCCESS;
          }),
          path_filestat_get: wrap((fd, flags, pathPtr, pathLen, bufPtr) => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_PATH_FILESTAT_GET);
            if (!stats.path) {
              return constants_1.WASI_EINVAL;
            }
            this.refreshMemory();
            const p = Buffer.from(this.memory.buffer, pathPtr, pathLen).toString();
            let rstats;
            if (flags) {
              rstats = fs.statSync(path.resolve(stats.path, p));
            } else {
              rstats = fs.lstatSync(path.resolve(stats.path, p));
            }
            this.view.setBigUint64(bufPtr, BigInt(rstats.dev), true);
            bufPtr += 8;
            this.view.setBigUint64(bufPtr, BigInt(rstats.ino), true);
            bufPtr += 8;
            this.view.setUint8(bufPtr, translateFileAttributes(this, void 0, rstats).filetype);
            bufPtr += 8;
            this.view.setBigUint64(bufPtr, BigInt(rstats.nlink), true);
            bufPtr += 8;
            this.view.setBigUint64(bufPtr, BigInt(rstats.size), true);
            bufPtr += 8;
            this.view.setBigUint64(bufPtr, BigInt(rstats.atime.getTime() * 1e6), true);
            bufPtr += 8;
            this.view.setBigUint64(bufPtr, BigInt(rstats.mtime.getTime() * 1e6), true);
            bufPtr += 8;
            this.view.setBigUint64(bufPtr, BigInt(rstats.ctime.getTime() * 1e6), true);
            return constants_1.WASI_ESUCCESS;
          }),
          path_filestat_set_times: wrap((fd, _dirflags, pathPtr, pathLen, stAtim, stMtim, fstflags) => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_PATH_FILESTAT_SET_TIMES);
            if (!stats.path) {
              return constants_1.WASI_EINVAL;
            }
            this.refreshMemory();
            const rstats = this.fstatSync(stats.real);
            let atim = rstats.atime;
            let mtim = rstats.mtime;
            const n = nsToMs(now(constants_1.WASI_CLOCK_REALTIME));
            const atimflags = constants_1.WASI_FILESTAT_SET_ATIM | constants_1.WASI_FILESTAT_SET_ATIM_NOW;
            if ((fstflags & atimflags) === atimflags) {
              return constants_1.WASI_EINVAL;
            }
            const mtimflags = constants_1.WASI_FILESTAT_SET_MTIM | constants_1.WASI_FILESTAT_SET_MTIM_NOW;
            if ((fstflags & mtimflags) === mtimflags) {
              return constants_1.WASI_EINVAL;
            }
            if ((fstflags & constants_1.WASI_FILESTAT_SET_ATIM) === constants_1.WASI_FILESTAT_SET_ATIM) {
              atim = nsToMs(stAtim);
            } else if ((fstflags & constants_1.WASI_FILESTAT_SET_ATIM_NOW) === constants_1.WASI_FILESTAT_SET_ATIM_NOW) {
              atim = n;
            }
            if ((fstflags & constants_1.WASI_FILESTAT_SET_MTIM) === constants_1.WASI_FILESTAT_SET_MTIM) {
              mtim = nsToMs(stMtim);
            } else if ((fstflags & constants_1.WASI_FILESTAT_SET_MTIM_NOW) === constants_1.WASI_FILESTAT_SET_MTIM_NOW) {
              mtim = n;
            }
            const p = Buffer.from(this.memory.buffer, pathPtr, pathLen).toString();
            fs.utimesSync(path.resolve(stats.path, p), new Date(atim), new Date(mtim));
            return constants_1.WASI_ESUCCESS;
          }),
          path_link: wrap((oldFd, _oldFlags, oldPath, oldPathLen, newFd, newPath, newPathLen) => {
            const ostats = CHECK_FD(oldFd, constants_1.WASI_RIGHT_PATH_LINK_SOURCE);
            const nstats = CHECK_FD(newFd, constants_1.WASI_RIGHT_PATH_LINK_TARGET);
            if (!ostats.path || !nstats.path) {
              return constants_1.WASI_EINVAL;
            }
            this.refreshMemory();
            const op = Buffer.from(this.memory.buffer, oldPath, oldPathLen).toString();
            const np = Buffer.from(this.memory.buffer, newPath, newPathLen).toString();
            fs.linkSync(path.resolve(ostats.path, op), path.resolve(nstats.path, np));
            return constants_1.WASI_ESUCCESS;
          }),
          path_open: wrap(
            (dirfd, _dirflags, pathPtr, pathLen, oflags, fsRightsBase, fsRightsInheriting, fsFlags, fdPtr) => {
              try {
                const stats = CHECK_FD(dirfd, constants_1.WASI_RIGHT_PATH_OPEN);
                fsRightsBase = BigInt(fsRightsBase);
                fsRightsInheriting = BigInt(fsRightsInheriting);
                const read =
                  (fsRightsBase & (constants_1.WASI_RIGHT_FD_READ | constants_1.WASI_RIGHT_FD_READDIR)) !== BigInt(0);
                const write =
                  (fsRightsBase &
                    (constants_1.WASI_RIGHT_FD_DATASYNC |
                      constants_1.WASI_RIGHT_FD_WRITE |
                      constants_1.WASI_RIGHT_FD_ALLOCATE |
                      constants_1.WASI_RIGHT_FD_FILESTAT_SET_SIZE)) !==
                  BigInt(0);
                let noflags;
                if (write && read) {
                  noflags = nodeFsConstants.O_RDWR;
                } else if (read) {
                  noflags = nodeFsConstants.O_RDONLY;
                } else if (write) {
                  noflags = nodeFsConstants.O_WRONLY;
                }
                let neededBase = fsRightsBase | constants_1.WASI_RIGHT_PATH_OPEN;
                let neededInheriting = fsRightsBase | fsRightsInheriting;
                if ((oflags & constants_1.WASI_O_CREAT) !== 0) {
                  noflags |= nodeFsConstants.O_CREAT;
                  neededBase |= constants_1.WASI_RIGHT_PATH_CREATE_FILE;
                }
                if ((oflags & constants_1.WASI_O_DIRECTORY) !== 0) {
                  noflags |= nodeFsConstants.O_DIRECTORY;
                }
                if ((oflags & constants_1.WASI_O_EXCL) !== 0) {
                  noflags |= nodeFsConstants.O_EXCL;
                }
                if ((oflags & constants_1.WASI_O_TRUNC) !== 0) {
                  noflags |= nodeFsConstants.O_TRUNC;
                  neededBase |= constants_1.WASI_RIGHT_PATH_FILESTAT_SET_SIZE;
                }
                if ((fsFlags & constants_1.WASI_FDFLAG_APPEND) !== 0) {
                  noflags |= nodeFsConstants.O_APPEND;
                }
                if ((fsFlags & constants_1.WASI_FDFLAG_DSYNC) !== 0) {
                  if (nodeFsConstants.O_DSYNC) {
                    noflags |= nodeFsConstants.O_DSYNC;
                  } else {
                    noflags |= nodeFsConstants.O_SYNC;
                  }
                  neededInheriting |= constants_1.WASI_RIGHT_FD_DATASYNC;
                }
                if ((fsFlags & constants_1.WASI_FDFLAG_NONBLOCK) !== 0) {
                  noflags |= nodeFsConstants.O_NONBLOCK;
                }
                if ((fsFlags & constants_1.WASI_FDFLAG_RSYNC) !== 0) {
                  if (nodeFsConstants.O_RSYNC) {
                    noflags |= nodeFsConstants.O_RSYNC;
                  } else {
                    noflags |= nodeFsConstants.O_SYNC;
                  }
                  neededInheriting |= constants_1.WASI_RIGHT_FD_SYNC;
                }
                if ((fsFlags & constants_1.WASI_FDFLAG_SYNC) !== 0) {
                  noflags |= nodeFsConstants.O_SYNC;
                  neededInheriting |= constants_1.WASI_RIGHT_FD_SYNC;
                }
                if (write && (noflags & (nodeFsConstants.O_APPEND | nodeFsConstants.O_TRUNC)) === 0) {
                  neededInheriting |= constants_1.WASI_RIGHT_FD_SEEK;
                }
                this.refreshMemory();
                const p = Buffer.from(this.memory.buffer, pathPtr, pathLen).toString();
                if (p == "dev/tty") {
                  this.view.setUint32(fdPtr, constants_1.WASI_STDIN_FILENO, true);
                  return constants_1.WASI_ESUCCESS;
                }
                logOpen("path_open", p);
                if (p.startsWith("proc/")) {
                  throw new types_1.WASIError(constants_1.WASI_EBADF);
                }
                const fullUnresolved = path.resolve(p);
                let full;
                try {
                  full = fs.realpathSync(fullUnresolved);
                } catch (e) {
                  if (e?.code === "ENOENT") {
                    full = fullUnresolved;
                  } else {
                    throw e;
                  }
                }
                let isDirectory;
                if (write) {
                  try {
                    isDirectory = fs.statSync(full).isDirectory();
                  } catch (_err) {}
                }
                let realfd;
                if (!write && isDirectory) {
                  realfd = fs.openSync(full, nodeFsConstants.O_RDONLY);
                } else {
                  realfd = fs.openSync(full, noflags);
                }
                const newfd = this.getUnusedFileDescriptor();
                this.FD_MAP.set(newfd, {
                  real: realfd,
                  filetype: void 0,
                  rights: {
                    base: neededBase,
                    inheriting: neededInheriting,
                  },
                  path: full,
                });
                stat(this, newfd);
                this.view.setUint32(fdPtr, newfd, true);
              } catch (e) {
                console.error(e);
              }
              return constants_1.WASI_ESUCCESS;
            },
          ),
          path_readlink: wrap((fd, pathPtr, pathLen, buf, bufLen, bufused) => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_PATH_READLINK);
            if (!stats.path) {
              return constants_1.WASI_EINVAL;
            }
            this.refreshMemory();
            const p = Buffer.from(this.memory.buffer, pathPtr, pathLen).toString();
            const full = path.resolve(stats.path, p);
            const r = fs.readlinkSync(full);
            const used = Buffer.from(this.memory.buffer).write(r, buf, bufLen);
            this.view.setUint32(bufused, used, true);
            return constants_1.WASI_ESUCCESS;
          }),
          path_remove_directory: wrap((fd, pathPtr, pathLen) => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_PATH_REMOVE_DIRECTORY);
            if (!stats.path) {
              return constants_1.WASI_EINVAL;
            }
            this.refreshMemory();
            const p = Buffer.from(this.memory.buffer, pathPtr, pathLen).toString();
            fs.rmdirSync(path.resolve(stats.path, p));
            return constants_1.WASI_ESUCCESS;
          }),
          path_rename: wrap((oldFd, oldPath, oldPathLen, newFd, newPath, newPathLen) => {
            const ostats = CHECK_FD(oldFd, constants_1.WASI_RIGHT_PATH_RENAME_SOURCE);
            const nstats = CHECK_FD(newFd, constants_1.WASI_RIGHT_PATH_RENAME_TARGET);
            if (!ostats.path || !nstats.path) {
              return constants_1.WASI_EINVAL;
            }
            this.refreshMemory();
            const op = Buffer.from(this.memory.buffer, oldPath, oldPathLen).toString();
            const np = Buffer.from(this.memory.buffer, newPath, newPathLen).toString();
            fs.renameSync(path.resolve(ostats.path, op), path.resolve(nstats.path, np));
            return constants_1.WASI_ESUCCESS;
          }),
          path_symlink: wrap((oldPath, oldPathLen, fd, newPath, newPathLen) => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_PATH_SYMLINK);
            if (!stats.path) {
              return constants_1.WASI_EINVAL;
            }
            this.refreshMemory();
            const op = Buffer.from(this.memory.buffer, oldPath, oldPathLen).toString();
            const np = Buffer.from(this.memory.buffer, newPath, newPathLen).toString();
            fs.symlinkSync(op, path.resolve(stats.path, np));
            return constants_1.WASI_ESUCCESS;
          }),
          path_unlink_file: wrap((fd, pathPtr, pathLen) => {
            const stats = CHECK_FD(fd, constants_1.WASI_RIGHT_PATH_UNLINK_FILE);
            if (!stats.path) {
              return constants_1.WASI_EINVAL;
            }
            this.refreshMemory();
            const p = Buffer.from(this.memory.buffer, pathPtr, pathLen).toString();
            fs.unlinkSync(path.resolve(stats.path, p));
            return constants_1.WASI_ESUCCESS;
          }),
          poll_oneoff: (sin, sout, nsubscriptions, neventsPtr) => {
            let nevents = 0;
            let name = "";
            let waitTimeNs = BigInt(0);
            let fd = -1;
            let fd_type = "read";
            let fd_timeout_ms = 0;
            const startNs = BigInt(bindings.hrtime());
            this.refreshMemory();
            let last_sin = sin;
            for (let i = 0; i < nsubscriptions; i += 1) {
              const userdata = this.view.getBigUint64(sin, true);
              sin += 8;
              const type = this.view.getUint8(sin);
              sin += 1;
              sin += 7;
              if (log.enabled) {
                if (type == constants_1.WASI_EVENTTYPE_CLOCK) {
                  name = "poll_oneoff (type=WASI_EVENTTYPE_CLOCK): ";
                } else if (type == constants_1.WASI_EVENTTYPE_FD_READ) {
                  name = "poll_oneoff (type=WASI_EVENTTYPE_FD_READ): ";
                } else {
                  name = "poll_oneoff (type=WASI_EVENTTYPE_FD_WRITE): ";
                }
                log(name);
              }
              switch (type) {
                case constants_1.WASI_EVENTTYPE_CLOCK: {
                  const clockid = this.view.getUint32(sin, true);
                  sin += 4;
                  sin += 4;
                  const timeout = this.view.getBigUint64(sin, true);
                  sin += 8;
                  sin += 8;
                  const subclockflags = this.view.getUint16(sin, true);
                  sin += 2;
                  sin += 6;
                  const absolute = subclockflags === 1;
                  if (log.enabled) {
                    log(name, { clockid, timeout, absolute });
                  }
                  if (!absolute) {
                    fd_timeout_ms = timeout / BigInt(1e6);
                  }
                  let e = constants_1.WASI_ESUCCESS;
                  const t = now(clockid);
                  if (t == null) {
                    e = constants_1.WASI_EINVAL;
                  } else {
                    const tNS = BigInt(t);
                    const end = absolute ? timeout : tNS + timeout;
                    const waitNs = end - tNS;
                    if (waitNs > waitTimeNs) {
                      waitTimeNs = waitNs;
                    }
                  }
                  this.view.setBigUint64(sout, userdata, true);
                  sout += 8;
                  this.view.setUint16(sout, e, true);
                  sout += 2;
                  this.view.setUint8(sout, constants_1.WASI_EVENTTYPE_CLOCK);
                  sout += 1;
                  sout += 5;
                  nevents += 1;
                  break;
                }
                case constants_1.WASI_EVENTTYPE_FD_READ:
                case constants_1.WASI_EVENTTYPE_FD_WRITE: {
                  fd = this.view.getUint32(sin, true);
                  fd_type = type == constants_1.WASI_EVENTTYPE_FD_READ ? "read" : "write";
                  sin += 4;
                  log(name, "fd =", fd);
                  sin += 28;
                  this.view.setBigUint64(sout, userdata, true);
                  sout += 8;
                  this.view.setUint16(sout, constants_1.WASI_ENOSYS, true);
                  sout += 2;
                  this.view.setUint8(sout, type);
                  sout += 1;
                  sout += 5;
                  nevents += 1;
                  if (fd == constants_1.WASI_STDIN_FILENO && constants_1.WASI_EVENTTYPE_FD_READ == type) {
                    this.shortPause();
                  }
                  break;
                }
                default:
                  return constants_1.WASI_EINVAL;
              }
              if (sin - last_sin != 48) {
                console.warn("*** BUG in wasi-js in poll_oneoff ", {
                  i,
                  sin,
                  last_sin,
                  diff: sin - last_sin,
                });
              }
              last_sin = sin;
            }
            this.view.setUint32(neventsPtr, nevents, true);
            if (nevents == 2 && fd >= 0) {
              const r = this.wasiImport.sock_pollSocket(fd, fd_type, fd_timeout_ms);
              if (r != constants_1.WASI_ENOSYS) {
                return r;
              }
            }
            if (waitTimeNs > 0) {
              waitTimeNs -= Bun.nanoseconds() - timeOrigin;
              if (waitTimeNs >= 1e6) {
                if (this.sleep == null && !warnedAboutSleep) {
                  warnedAboutSleep = true;
                  console.log("(100% cpu burning waiting for stdin: please define a way to sleep!) ");
                }
                if (this.sleep != null) {
                  const ms = nsToMs(waitTimeNs);
                  this.sleep(ms);
                } else {
                  const end = BigInt(bindings.hrtime()) + waitTimeNs;
                  while (BigInt(bindings.hrtime()) < end) {}
                }
              }
            }
            return constants_1.WASI_ESUCCESS;
          },
          proc_exit: rval => {
            bindings.exit(rval);
            return constants_1.WASI_ESUCCESS;
          },
          proc_raise: sig => {
            if (!(sig in constants_1.SIGNAL_MAP)) {
              return constants_1.WASI_EINVAL;
            }
            bindings.kill(constants_1.SIGNAL_MAP[sig]);
            return constants_1.WASI_ESUCCESS;
          },
          random_get: (bufPtr, bufLen) => {
            this.refreshMemory();
            crypto.getRandomValues(this.memory.buffer, bufPtr, bufLen);
            return bufLen;
          },
          sched_yield() {
            return constants_1.WASI_ESUCCESS;
          },
          sock_recv() {
            return constants_1.WASI_ENOSYS;
          },
          sock_send() {
            return constants_1.WASI_ENOSYS;
          },
          sock_shutdown() {
            return constants_1.WASI_ENOSYS;
          },
          sock_fcntlSetFlags(_fd, _flags) {
            return constants_1.WASI_ENOSYS;
          },
          sock_pollSocket(_fd, _eventtype, _timeout_ms) {
            return constants_1.WASI_ENOSYS;
          },
        };
        if (log.enabled) {
          Object.keys(this.wasiImport).forEach(key => {
            const prevImport = this.wasiImport[key];
            this.wasiImport[key] = function (...args2) {
              log(key, args2);
              try {
                let result = prevImport(...args2);
                log("result", result);
                return result;
              } catch (e) {
                log("error: ", e);
                throw e;
              }
            };
          });
        }
      }