'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); const EventEmitter = require('eventemitter3'); const nanoid$1 = require('nanoid'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; } const EventEmitter__default = /*#__PURE__*/_interopDefaultLegacy(EventEmitter); const chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; const nanoid = nanoid$1.customAlphabet(chars); function generateId(len) { return nanoid(len); } class WebSocketerError extends Error { constructor(message, code, payload, name) { super(message || "Something went wrong"); this.name = name || "WebSocketerError"; this.code = code || "ERR_WSR_UNKNOWN"; this.payload = payload; } } function endRequestData(request, opt) { if (!request.rq) return request; return { ns: request.ns, id: request.id, nm: request.nm, rq: false, pl: opt?.payload, er: opt?.error, fr: opt?.from || (request.rq ? request.to : request.fr) || "", to: opt?.to || (request.rq ? request.fr : request.to) || "", ic: request.ic }; } class Client extends EventEmitter__default { constructor(client, options) { super(); this._requests = /* @__PURE__ */ new Map(); this._remotes = /* @__PURE__ */ new Map(); options = options || {}; options.errorFilter = options.errorFilter || ((err) => err); options.namespace = options.namespace || "websocketer"; options.timeout = options.timeout || 60; options.id = options.id || generateId(24); this._id = options.id; this._client = client; this._cluster = options.cluster; this._options = options; this.clear(); this._cluster?.register(this); this._sendInfo(); } get options() { return this._remotes; } get id() { return this._id; } get remotes() { return this._remotes; } get client() { return this._client; } get cluster() { return this._cluster; } destroy() { this._cluster?.unregister(this); this.clear(); this.removeAllListeners(); } clear() { this._requests.forEach((data) => clearTimeout(data.ti)); this._requests.clear(); this._remotes.clear(); this.removeAllListeners(); this.on("_remote_", (data) => { if (!this._remotes.has(data.id)) { this._remotes.set(data.id, data); this.emit("@remote", data); this._sendInfo(); } }); this.on("_request_", (data) => { return this.handleMessage(data); }); } async request(name, payload, to, opt) { if (to) { const replies = await this.requestMany(name, payload, [to], { noReply: opt?.noReply, continue: true }); const reply = replies[0]; if (reply?.name === this._options.namespace + "_error") throw reply.error; return reply; } return this._request(name, payload, to, opt); } async requestMany(name, payload, to, opt) { const results = await Promise.allSettled( to.map((id) => this._request(name, payload, id, { noReply: opt?.noReply })) ); return results.map((result) => { if (result.status === "rejected") { if (!opt?.continue) { throw result.reason; } else { return { name: this._options.namespace + "_error", error: result.reason }; } } return result.value; }); } async handleMessage(data) { if (data.ns !== this._options.namespace) return; if (data.rq) { if (this._cluster && !data.ic && data.to) { data.ic = true; this._cluster?.handleRequest(data); } else { return this.handleRequest(data); } } else { this.handleResponse(data); } return void 0; } async handleRequest(data) { try { let payload; data.client = this._client; const listeners = this.listeners(data.nm); if (!listeners || !listeners.length) { throw new WebSocketerError( "No listener", "ERR_WSR_NO_LISTENER" ); } for (let i = 0; i < listeners.length; i++) { payload = await listeners[i](data.pl, data); } return endRequestData( data, { payload, from: this._id, to: data.fr } ); } catch (error) { return endRequestData( data, { error: this._options.errorFilter( { name: error.name, code: error.code || "ERR_WSR_INTERNAL", message: error.message, payload: error.payload } ), from: this._id, to: data.fr } ); } } handleResponse(data) { const request = this._requests.get(data.id); if (!request) return; if (typeof request.rs === "function") { request.rs( data.er || null, data.pl, request ); } this._requests.delete(request.id); clearTimeout(request.ti); request.ti = null; } _sendInfo() { if (!this._cluster) this.request("_remote_", { id: this._id }); } async _request(name, payload, to, opt) { return new Promise((resolve, reject) => { try { if (opt?.noReply) { this._dispatch(name, payload, to); resolve(void 0); } else { this._dispatch(name, payload, to, (err, resPayload, request) => { if (err) { return reject( new WebSocketerError( `${err.message}${this._options.debug ? ` -> ${request.nm}` : ""}`, err.code, err.payload, "RemoteWebSocketerError" ) ); } resolve(resPayload); }); } } catch (error) { reject(new WebSocketerError(error.message)); } }); } _dispatch(name, payload, to, response) { const request = { ns: this._options.namespace, id: generateId(24), nm: name, rq: true, pl: payload, fr: this._id, to }; if (response) request.rs = true; if (to && this._cluster) { this.handleMessage(request); } else { this._send(request); } if (!response) return; request.rs = response; this._requests.set(request.id, request); request.ti = setTimeout( () => { request.ti = null; this._requests.delete(request.id); response( new WebSocketerError( "Timeout reached", "ERR_WSR_TIMEOUT" ), void 0, request ); }, 1e3 * this._options.timeout ); } } class WebSocketer extends Client { constructor(socket, options) { options = options || {}; super(socket, options); this._messageHandler = () => void 0; this._openHandler = () => void 0; this._options.ping = options.ping || 0; if (this._options.ping) { this._pingIntervalId = setInterval( async () => { try { await this.request("_ping_"); } catch (error) { } }, 1e3 * this._options.ping ); } const client = this._client; client.addEventListener( "message", this._messageHandler = async (e) => { let data; try { data = JSON.parse(typeof e.data === "string" ? e.data : e.data.toString()); } catch (error) { data = { ns: "", id: "", nm: "", fr: "", rq: false }; } const replyData = await this.handleMessage(data); if (replyData) this._send(replyData); } ); if (client.readyState === 1) { this._sendInfo(); } else { client.addEventListener( "open", this._openHandler = () => { this._sendInfo(); } ); } } destroy() { const client = this._client; client.removeEventListener("open", this._openHandler); client.removeEventListener("message", this._messageHandler); clearInterval(this._pingIntervalId); super.destroy(); } clear() { super.clear(); this.on("_ping_", (data) => data); } _send(message) { this._client.send(JSON.stringify(message)); } } function createWebSocketer(socket, options) { return new WebSocketer(socket, options); } exports.Client = Client; exports.WebSocketer = WebSocketer; exports.WebSocketerError = WebSocketerError; exports.createWebSocketer = createWebSocketer; exports.endRequestData = endRequestData; exports.generateId = generateId;