diff --git a/dist/index.d.ts b/dist/index.d.ts
new file mode 100644
index 0000000..fbea39a
--- /dev/null
+++ b/dist/index.d.ts
@@ -0,0 +1,44 @@
+///
+import EventEmitter from "events";
+export default class ProtomuxRPC extends EventEmitter {
+ private _id;
+ private _ending;
+ private _error?;
+ private _responding;
+ private _requests;
+ private _defaultValueEncoding;
+ private _responders;
+ private _channel;
+ private _request;
+ private _response;
+ constructor(stream: any, options?: any);
+ private _mux;
+ get mux(): any;
+ private _ready;
+ get ready(): Promise;
+ get closed(): any;
+ get stream(): any;
+ private _init;
+ _onopen(handshake: any): void;
+ _onclose(): void;
+ _ondestroy(): void;
+ _onrequest({ id, method, value, }: {
+ id: number;
+ method: string;
+ value: any;
+ }): Promise;
+ _onresponse({ id, error, value }: {
+ id: number;
+ error: string;
+ value: any;
+ }): void;
+ respond(method: string, options: Function | any, handler: Function): this;
+ unrespond(method: string): this;
+ request(method: string, value: any, options?: any): Promise;
+ event(method: string, value: any, options?: any): void;
+ cork(): void;
+ uncork(): void;
+ end(): Promise;
+ _endMaybe(): void;
+ destroy(err: Error): void;
+}
diff --git a/dist/index.js b/dist/index.js
new file mode 100644
index 0000000..0b99bb8
--- /dev/null
+++ b/dist/index.js
@@ -0,0 +1,225 @@
+import EventEmitter from "events";
+// @ts-ignore
+import Protomux from "protomux";
+// @ts-ignore
+import c from "compact-encoding";
+// @ts-ignore
+import bitfield from "compact-encoding-bitfield";
+// @ts-ignore
+import bits from "bits-to-bytes";
+export default class ProtomuxRPC extends EventEmitter {
+ _id;
+ _ending;
+ _error;
+ _responding;
+ _requests;
+ _defaultValueEncoding;
+ _responders;
+ _channel;
+ _request;
+ _response;
+ constructor(stream, options = {}) {
+ super();
+ this._mux = Protomux.from(stream);
+ this._defaultValueEncoding = options?.valueEncoding;
+ this._id = 1;
+ this._ending = false;
+ this._responding = 0;
+ this._requests = new Map();
+ this._responders = new Map();
+ this._ready = this._init(options);
+ }
+ _mux;
+ get mux() {
+ return this._mux;
+ }
+ _ready;
+ get ready() {
+ return this._ready;
+ }
+ get closed() {
+ return this._channel.closed;
+ }
+ get stream() {
+ return this._mux.stream;
+ }
+ async _init(options) {
+ this._channel = await this._mux.createChannel({
+ protocol: "protomux-rpc",
+ id: options?.id,
+ handshake: options?.handshake
+ ? options?.handshakeEncoding || c.raw
+ : null,
+ onopen: this._onopen.bind(this),
+ onclose: this._onclose.bind(this),
+ ondestroy: this._ondestroy.bind(this),
+ });
+ if (this._channel === null)
+ throw new Error("duplicate channel");
+ this._request = await this._channel.addMessage({
+ encoding: request,
+ onmessage: this._onrequest.bind(this),
+ });
+ this._response = await this._channel.addMessage({
+ encoding: response,
+ onmessage: this._onresponse.bind(this),
+ });
+ this._channel.open(options?.handshake);
+ await this._channel.ready;
+ }
+ _onopen(handshake) {
+ this.emit("open", handshake);
+ }
+ _onclose() {
+ const err = this._error || new Error("channel closed");
+ for (const request of this._requests.values()) {
+ request.reject(err);
+ }
+ this._requests.clear();
+ this._responders.clear();
+ this.emit("close");
+ }
+ _ondestroy() {
+ this.emit("destroy");
+ }
+ async _onrequest({ id, method, value, }) {
+ let error = null;
+ const responder = this._responders.get(method);
+ if (responder === undefined)
+ error = `unknown method '${method}'`;
+ else {
+ const { valueEncoding = this._defaultValueEncoding, requestEncoding = valueEncoding, responseEncoding = valueEncoding, } = responder.options;
+ if (requestEncoding)
+ value = c.decode(requestEncoding, value);
+ this._responding++;
+ try {
+ value = await responder.handler(value);
+ }
+ catch (err) {
+ error = err.message;
+ }
+ this._responding--;
+ if (!error && responseEncoding && id) {
+ value = c.encode(responseEncoding, value);
+ }
+ }
+ if (id)
+ this._response.send({ id, error, value });
+ this._endMaybe();
+ }
+ _onresponse({ id, error, value }) {
+ if (id === 0)
+ return;
+ const request = this._requests.get(id);
+ if (request === undefined)
+ return;
+ this._requests.delete(id);
+ if (error)
+ request.reject(new Error(error));
+ else {
+ const { valueEncoding = this._defaultValueEncoding, responseEncoding = valueEncoding, } = request.options;
+ if (responseEncoding)
+ value = c.decode(responseEncoding, value);
+ request.resolve(value);
+ }
+ this._endMaybe();
+ }
+ respond(method, options, handler) {
+ if (typeof options === "function") {
+ handler = options;
+ options = {};
+ }
+ this._responders.set(method, { options, handler });
+ return this;
+ }
+ unrespond(method) {
+ this._responders.delete(method);
+ return this;
+ }
+ async request(method, value, options = {}) {
+ if (this.closed)
+ throw new Error("channel closed");
+ const { valueEncoding = this._defaultValueEncoding, requestEncoding = valueEncoding, } = options;
+ if (requestEncoding)
+ value = c.encode(requestEncoding, value);
+ const id = this._id++;
+ this._request.send({ id, method, value });
+ return new Promise((resolve, reject) => {
+ this._requests.set(id, { options, resolve, reject });
+ });
+ }
+ event(method, value, options = {}) {
+ if (this.closed)
+ throw new Error("channel closed");
+ const { valueEncoding = this._defaultValueEncoding, requestEncoding = valueEncoding, } = options;
+ if (requestEncoding)
+ value = c.encode(requestEncoding, value);
+ this._request.send({ id: 0, method, value });
+ }
+ cork() {
+ this._channel.cork();
+ }
+ uncork() {
+ this._channel.uncork();
+ }
+ async end() {
+ this._ending = true;
+ this._endMaybe();
+ await EventEmitter.once(this, "close");
+ }
+ _endMaybe() {
+ if (this._ending && this._responding === 0 && this._requests.size === 0) {
+ this._channel.close();
+ }
+ }
+ destroy(err) {
+ this._error = err || new Error("channel destroyed");
+ this._channel.close();
+ }
+}
+const request = {
+ preencode(state, m) {
+ c.uint.preencode(state, m.id);
+ c.string.preencode(state, m.method);
+ c.raw.preencode(state, m.value);
+ },
+ encode(state, m) {
+ c.uint.encode(state, m.id);
+ c.string.encode(state, m.method);
+ c.raw.encode(state, m.value);
+ },
+ decode(state) {
+ return {
+ id: c.uint.decode(state),
+ method: c.string.decode(state),
+ value: c.raw.decode(state),
+ };
+ },
+};
+const flags = bitfield(1);
+const response = {
+ preencode(state, m) {
+ flags.preencode(state);
+ c.uint.preencode(state, m.id);
+ if (m.error)
+ c.string.preencode(state, m.error);
+ else
+ c.raw.preencode(state, m.value);
+ },
+ encode(state, m) {
+ flags.encode(state, bits.of(m.error));
+ c.uint.encode(state, m.id);
+ if (m.error)
+ c.string.encode(state, m.error);
+ else
+ c.raw.encode(state, m.value);
+ },
+ decode(state) {
+ const [error] = bits.iterator(flags.decode(state));
+ return {
+ id: c.uint.decode(state),
+ error: error ? c.string.decode(state) : null,
+ value: !error ? c.raw.decode(state) : null,
+ };
+ },
+};