text: var __extends = (this && this.__extends) || (function () {
      var extendStatics = function (d, b) {
          extendStatics = Object.setPrototypeOf ||
              ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
              function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
          return extendStatics(d, b);
      };
      return function (d, b) {
          extendStatics(d, b);
          function __() { this.constructor = d; }
          d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
      };
  })();
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
      return new (P || (P = Promise))(function (resolve, reject) {
          function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
          function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
          function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
          step((generator = generator.apply(thisArg, _arguments || [])).next());
      });
  };
  var __generator = (this && this.__generator) || function (thisArg, body) {
      var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
      return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
      function verb(n) { return function (v) { return step([n, v]); }; }
      function step(op) {
          if (f) throw new TypeError("Generator is already executing.");
          while (_) try {
              if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
              if (y = 0, t) op = [op[0] & 2, t.value];
              switch (op[0]) {
                  case 0: case 1: t = op; break;
                  case 4: _.label++; return { value: op[1], done: false };
                  case 5: _.label++; y = op[1]; op = [0]; continue;
                  case 7: op = _.ops.pop(); _.trys.pop(); continue;
                  default:
                      if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                      if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                      if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                      if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                      if (t[2]) _.ops.pop();
                      _.trys.pop(); continue;
              }
              op = body.call(thisArg, _);
          } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
          if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
      }
  };
  (function (factory) {
      if (typeof module === "object" && typeof module.exports === "object") {
          var v = factory(require, exports);
          if (v !== undefined) module.exports = v;
      }
      else if (typeof define === "function" && define.amd) {
          define(["require", "exports", "events", "./util"], factory);
      }
  })(function (require, exports) {
      "use strict";
      var _this = this;
      Object.defineProperty(exports, "__esModule", { value: true });
      var events_1 = require("events");
      var util_1 = require("./util");
      /* eslint-disable @typescript-eslint/no-explicit-any */
      // This is so we can internally listen to errors for cleaning up without
      // removing the ability to throw if nothing external is listening.
      var internalErrorEvent = Symbol("error");
      /**
       * Allow using a proxy like it's returned synchronously. This only works because
       * all proxy methods must return promises.
       */
      var unpromisify = function (proxyPromise) {
          return new Proxy({}, {
              get: function (target, name) {
                  if (typeof target[name] === "undefined") {
                      target[name] = function () {
                          var args = [];
                          for (var _i = 0; _i < arguments.length; _i++) {
                              args[_i] = arguments[_i];
                          }
                          return __awaiter(_this, void 0, void 0, function () {
                              var proxy;
                              var _a;
                              return __generator(this, function (_b) {
                                  switch (_b.label) {
                                      case 0: return [4 /*yield*/, proxyPromise];
                                      case 1:
                                          proxy = _b.sent();
                                          return [2 /*return*/, proxy ? (_a = proxy)[name].apply(_a, args) : undefined];
                                  }
                              });
                          });
                      };
                  }
                  return target[name];
              },
          });
      };
      /**
       * Client-side emitter that just forwards server proxy events to its own
       * emitter. It also turns a promisified server proxy into a non-promisified
       * proxy so we don't need a bunch of `then` calls everywhere.
       */
      var ClientProxy = /** @class */ (function (_super) {
          __extends(ClientProxy, _super);
          /**
           * You can specify not to bind events in order to avoid emitting twice for
           * duplex streams.
           */
          function ClientProxy(_proxyPromise, bindEvents) {
              if (bindEvents === void 0) { bindEvents = true; }
              var _this = _super.call(this) || this;
              _this._proxyPromise = _proxyPromise;
              _this.bindEvents = bindEvents;
              _this._proxy = _this.initialize(_this._proxyPromise);
              if (_this.bindEvents) {
                  _this.on("disconnected", function (error) {
                      try {
                          _this.emit("error", error);
                      }
                      catch (error) {
                          // If nothing is listening, EventEmitter will throw an error.
                      }
                      _this.handleDisconnect();
                  });
              }
              return _this;
          }
          /**
           * Bind to the error event without counting as a listener for the purpose of
           * throwing if nothing is listening.
           */
          ClientProxy.prototype.onInternalError = function (listener) {
              _super.prototype.on.call(this, internalErrorEvent, listener);
          };
          /**
           * Bind the event locally and ensure the event is bound on the server.
           */
          ClientProxy.prototype.addListener = function (event, listener) {
              this.catch(this.proxy.bindDelayedEvent(event));
              return _super.prototype.on.call(this, event, listener);
          };
          /**
           * Alias for `addListener`.
           */
          ClientProxy.prototype.on = function (event, listener) {
              return this.addListener(event, listener);
          };
          /**
           * Same as the parent except also emit the internal error event for errors.
           */
          ClientProxy.prototype.emit = function (event) {
              var args = [];
              for (var _i = 1; _i < arguments.length; _i++) {
                  args[_i - 1] = arguments[_i];
              }
              if (event === "error") {
                  _super.prototype.emit.apply(this, [internalErrorEvent].concat(args));
              }
              return _super.prototype.emit.apply(this, [event].concat(args));
          };
          Object.defineProperty(ClientProxy.prototype, "proxyPromise", {
              /**
               * Original promise for the server proxy. Can be used to be passed as an
               * argument.
               */
              get: function () {
                  return this._proxyPromise;
              },
              enumerable: true,
              configurable: true
          });
          Object.defineProperty(ClientProxy.prototype, "proxy", {
              /**
               * Server proxy.
               */
              get: function () {
                  return this._proxy;
              },
              enumerable: true,
              configurable: true
          });
          /**
           * Initialize the proxy by unpromisifying if necessary and binding to its
           * events.
           */
          ClientProxy.prototype.initialize = function (proxyPromise) {
              var _this = this;
              this._proxyPromise = proxyPromise;
              this._proxy = util_1.isPromise(this._proxyPromise) ? unpromisify(this._proxyPromise) : this._proxyPromise;
              if (this.bindEvents) {
                  this.proxy.onEvent(function (event) {
                      var args = [];
                      for (var _i = 1; _i < arguments.length; _i++) {
                          args[_i - 1] = arguments[_i];
                      }
                      _this.emit.apply(_this, [event].concat(args));
                  });
              }
              return this._proxy;
          };
          /**
           * Emit an error event if the promise errors.
           */
          ClientProxy.prototype.catch = function (promise) {
              var _this = this;
              if (promise) {
                  promise.catch(function (e) { return _this.emit("error", e); });
              }
              return this;
          };
          return ClientProxy;
      }(events_1.EventEmitter));
      exports.ClientProxy = ClientProxy;
      /**
       * The actual proxy instance on the server. Every method must only accept
       * serializable arguments and must return promises with serializable values.
       *
       * If a proxy itself has proxies on creation (like how ChildProcess has stdin),
       * then it should return all of those at once, otherwise you will miss events
       * from those child proxies and fail to dispose them properly.
       *
       * Events listeners are added client-side (since all events automatically
       * forward to the client), so onDone and onEvent do not need to be asynchronous.
       */
      var ServerProxy = /** @class */ (function () {
          function ServerProxy(options) {
              this.options = options;
              this.callbacks = [];
              this.instance = options.instance;
          }
          /**
           * Dispose the proxy.
           */
          ServerProxy.prototype.dispose = function () {
              return __awaiter(this, void 0, void 0, function () {
                  return __generator(this, function (_a) {
                      this.instance.removeAllListeners();
                      return [2 /*return*/];
                  });
              });
          };
          /**
           * This is used instead of an event to force it to be implemented since there
           * would be no guarantee the implementation would remember to emit the event.
           */
          ServerProxy.prototype.onDone = function (cb) {
              var _this = this;
              this.options.doneEvents.forEach(function (event) { return _this.instance.on(event, cb); });
          };
          /**
           * Bind an event that will not fire without first binding it and shouldn't be
           * bound immediately.
        
           * For example, binding to `data` switches a stream to flowing mode, so we
           * don't want to do it until we're asked. Otherwise something like `pipe`
           * won't work because potentially some or all of the data will already have
           * been flushed out.
           */
          ServerProxy.prototype.bindDelayedEvent = function (event) {
              return __awaiter(this, void 0, void 0, function () {
                  var _this = this;
                  return __generator(this, function (_a) {
                      if (this.options.delayedEvents &&
                          this.options.delayedEvents.includes(event) &&
                          !this.options.bindEvents.includes(event)) {
                          this.options.bindEvents.push(event);
                          this.callbacks.forEach(function (cb) {
                              _this.instance.on(event, function () {
                                  var args = [];
                                  for (var _i = 0; _i < arguments.length; _i++) {
                                      args[_i] = arguments[_i];
                                  }
                                  return cb.apply(void 0, [event].concat(args));
                              });
                          });
                      }
                      return [2 /*return*/];
                  });
              });
          };
          /**
           * Listen to all possible events. On the client, this is to reduce boilerplate
           * that would just be a bunch of error-prone forwarding of each individual
           * event from the proxy to its own emitter.
           *
           * It also fixes a timing issue because we just always send all events from
           * the server, so we never miss any due to listening too late.
           *
           * This cannot be async because then we can bind to the events too late.
           */
          ServerProxy.prototype.onEvent = function (cb) {
              var _this = this;
              this.callbacks.push(cb);
              this.options.bindEvents.forEach(function (event) {
                  _this.instance.on(event, function () {
                      var args = [];
                      for (var _i = 0; _i < arguments.length; _i++) {
                          args[_i] = arguments[_i];
                      }
                      return cb.apply(void 0, [event].concat(args));
                  });
              });
          };
          return ServerProxy;
      }());
      exports.ServerProxy = ServerProxy;
      /**
       * Supported top-level module proxies.
       */
      var Module;
      (function (Module) {
          Module["Buffer"] = "buffer";
          Module["ChildProcess"] = "child_process";
          Module["Crypto"] = "crypto";
          Module["Events"] = "events";
          Module["Fs"] = "fs";
          Module["Net"] = "net";
          Module["Os"] = "os";
          Module["Path"] = "path";
          Module["Process"] = "process";
          Module["Stream"] = "stream";
          Module["StringDecoder"] = "string_decoder";
          Module["Timers"] = "timers";
          Module["Tty"] = "tty";
          Module["Util"] = "util";
      })(Module = exports.Module || (exports.Module = {}));
      /**
       * Batch remote calls.
       */
      var Batch = /** @class */ (function () {
          function Batch(
          /**
           * Flush after reaching this amount of time.
           */
          maxTime, 
          /**
           * Flush after reaching this count.
           */
          maxCount, 
          /**
           * Flush after not receiving more requests for this amount of time.
           * This is pretty low by default so essentially we just end up batching
           * requests that are all made at the same time.
           */
          idleTime) {
              var _this = this;
              if (maxTime === void 0) { maxTime = 1000; }
              if (maxCount === void 0) { maxCount = 100; }
              if (idleTime === void 0) { idleTime = 1; }
              this.maxTime = maxTime;
              this.maxCount = maxCount;
              this.idleTime = idleTime;
              this.batch = [];
              this.add = function (args) {
                  return new Promise(function (resolve, reject) {
                      _this.batch.push({
                          args: args,
                          resolve: resolve,
                          reject: reject,
                      });
                      if (_this.batch.length >= _this.maxCount) {
                          _this.flush();
                      }
                      else {
                          clearTimeout(_this.idleTimeout);
                          _this.idleTimeout = setTimeout(_this.flush, _this.idleTime);
                          if (typeof _this.maxTimeout === "undefined") {
                              _this.maxTimeout = setTimeout(_this.flush, _this.maxTime);
                          }
                      }
                  });
              };
              /**
               * Flush out the current batch.
               */
              this.flush = function () {
                  clearTimeout(_this.idleTimeout);
                  clearTimeout(_this.maxTimeout);
                  _this.maxTimeout = undefined;
                  var batch = _this.batch;
                  _this.batch = [];
                  _this.remoteCall(batch.map(function (q) { return q.args; }))
                      .then(function (results) {
                      batch.forEach(function (item, i) {
                          var result = results[i];
                          if (result && result instanceof Error) {
                              item.reject(result);
                          }
                          else {
                              item.resolve(result);
                          }
                      });
                  })
                      .catch(function (error) { return batch.forEach(function (item) { return item.reject(error); }); });
              };
          }
          return Batch;
      }());
      exports.Batch = Batch;
      var NotImplementedProxy = /** @class */ (function () {
          function NotImplementedProxy(name) {
              return new Proxy(this, {
                  get: function (target, prop) {
                      if (prop in target) {
                          return target[prop];
                      }
                      throw new Error("not implemented: " + name + "->" + String(prop));
                  },
              });
          }
          return NotImplementedProxy;
      }());
      exports.NotImplementedProxy = NotImplementedProxy;
  });
  