nostr-websocket-utils
Version:
Robust WebSocket utilities for Nostr applications with automatic reconnection, supporting both ESM and CommonJS. Features channel-based messaging, heartbeat monitoring, message queueing, and comprehensive error handling with type-safe handlers.
2 lines • 13.6 kB
JavaScript
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.NostrWebSocketUtils=t():e.NostrWebSocketUtils=t()}(this,(()=>(()=>{"use strict";var e={793:e=>{function t(e){try{return JSON.stringify(e)}catch(e){return'"[Circular]"'}}e.exports=function(e,r,n){var i=n&&n.stringify||t;if("object"==typeof e&&null!==e){var s=r.length+1;if(1===s)return e;var o=new Array(s);o[0]=i(e);for(var l=1;l<s;l++)o[l]=i(r[l]);return o.join(" ")}if("string"!=typeof e)return e;var a=r.length;if(0===a)return e;for(var c="",u=0,h=-1,f=e&&e.length||0,g=0;g<f;){if(37===e.charCodeAt(g)&&g+1<f){switch(h=h>-1?h:0,e.charCodeAt(g+1)){case 100:case 102:if(u>=a)break;if(null==r[u])break;h<g&&(c+=e.slice(h,g)),c+=Number(r[u]),h=g+2,g++;break;case 105:if(u>=a)break;if(null==r[u])break;h<g&&(c+=e.slice(h,g)),c+=Math.floor(Number(r[u])),h=g+2,g++;break;case 79:case 111:case 106:if(u>=a)break;if(void 0===r[u])break;h<g&&(c+=e.slice(h,g));var d=typeof r[u];if("string"===d){c+="'"+r[u]+"'",h=g+2,g++;break}if("function"===d){c+=r[u].name||"<anonymous>",h=g+2,g++;break}c+=i(r[u]),h=g+2,g++;break;case 115:if(u>=a)break;h<g&&(c+=e.slice(h,g)),c+=String(r[u]),h=g+2,g++;break;case 37:h<g&&(c+=e.slice(h,g)),c+="%",h=g+2,g++,u--}++u}++g}if(-1===h)return e;h<f&&(c+=e.slice(h));return c}},591:e=>{e.exports=function(){throw new Error("ws does not work in the browser. Browser clients must use the native WebSocket object")}},874:(e,t,r)=>{const n=r(793);e.exports=h;const i=function(){function e(e){return void 0!==e&&e}try{return"undefined"!=typeof globalThis||Object.defineProperty(Object.prototype,"globalThis",{get:function(){return delete Object.prototype.globalThis,this.globalThis=this},configurable:!0}),globalThis}catch(t){return e(self)||e(window)||e(this)||{}}}().console||{},s={mapHttpRequest:v,mapHttpResponse:v,wrapRequestSerializer:b,wrapResponseSerializer:b,wrapErrorSerializer:b,req:v,res:v,err:p,errWithCause:p};function o(e,t){return"silent"===e?1/0:t.levels.values[e]}const l=Symbol("pino.logFuncs"),a=Symbol("pino.hierarchy"),c={error:"log",fatal:"error",warn:"error",info:"log",debug:"log",trace:"log"};function u(e,t){const r={logger:t,parent:e[a]};t[a]=r}function h(e){(e=e||{}).browser=e.browser||{};const t=e.browser.transmit;if(t&&"function"!=typeof t.send)throw Error("pino: transmit option must have a send function");const r=e.browser.write||i;e.browser.write&&(e.browser.asObject=!0);const n=e.serializers||{},s=function(e,t){if(Array.isArray(e))return e.filter((function(e){return"!stdSerializers.err"!==e}));return!0===e&&Object.keys(t)}(e.browser.serialize,n);let a=e.browser.serialize;Array.isArray(e.browser.serialize)&&e.browser.serialize.indexOf("!stdSerializers.err")>-1&&(a=!1);const p=Object.keys(e.customLevels||{}),v=["error","fatal","warn","info","debug","trace"].concat(p);"function"==typeof r&&v.forEach((function(e){r[e]=r})),(!1===e.enabled||e.browser.disabled)&&(e.level="silent");const b=e.level||"info",w=Object.create(r);w.log||(w.log=y),function(e,t,r){const n={};t.forEach((e=>{n[e]=r[e]?r[e]:i[e]||i[c[e]||"log"]||y})),e[l]=n}(w,v,r),u({},w),Object.defineProperty(w,"levelVal",{get:function(){return o(this.level,this)}}),Object.defineProperty(w,"level",{get:function(){return this._level},set:function(e){if("silent"!==e&&!this.levels.values[e])throw Error("unknown level "+e);this._level=e,f(this,E,w,"error"),f(this,E,w,"fatal"),f(this,E,w,"warn"),f(this,E,w,"info"),f(this,E,w,"debug"),f(this,E,w,"trace"),p.forEach((e=>{f(this,E,w,e)}))}});const E={transmit:t,serialize:s,asObject:e.browser.asObject,formatters:e.browser.formatters,levels:v,timestamp:m(e)};return w.levels=function(e){const t=e.customLevels||{},r=Object.assign({},h.levels.values,t),n=Object.assign({},h.levels.labels,function(e){const t={};return Object.keys(e).forEach((function(r){t[e[r]]=r})),t}(t));return{values:r,labels:n}}(e),w.level=b,w.setMaxListeners=w.getMaxListeners=w.emit=w.addListener=w.on=w.prependListener=w.once=w.prependOnceListener=w.removeListener=w.removeAllListeners=w.listeners=w.listenerCount=w.eventNames=w.write=w.flush=y,w.serializers=n,w._serialize=s,w._stdErrSerialize=a,w.child=function(r,i){if(!r)throw new Error("missing bindings for child Pino");i=i||{},s&&r.serializers&&(i.serializers=r.serializers);const o=i.serializers;if(s&&o){var l=Object.assign({},n,o),a=!0===e.browser.serialize?Object.keys(l):s;delete r.serializers,g([r],a,l,this._stdErrSerialize)}function c(e){this._childLevel=1+(0|e._childLevel),this.bindings=r,l&&(this.serializers=l,this._serialize=a),t&&(this._logEvent=d([].concat(e._logEvent.bindings,r)))}c.prototype=this;const h=new c(this);return u(this,h),h.level=this.level,h},t&&(w._logEvent=d()),w}function f(e,t,r,s){if(Object.defineProperty(e,s,{value:o(e.level,r)>o(s,r)?y:r[l][s],writable:!0,enumerable:!0,configurable:!0}),!t.transmit&&e[s]===y)return;e[s]=function(e,t,r,s){return a=e[l][s],function(){const l=t.timestamp(),c=new Array(arguments.length),u=Object.getPrototypeOf&&Object.getPrototypeOf(this)===i?i:this;for(var h=0;h<c.length;h++)c[h]=arguments[h];if(t.serialize&&!t.asObject&&g(c,this._serialize,this.serializers,this._stdErrSerialize),t.asObject||t.formatters?a.call(u,function(e,t,r,i,s={}){const{level:o=()=>e.levels.values[t],log:l=e=>e}=s;e._serialize&&g(r,e._serialize,e.serializers,e._stdErrSerialize);const a=r.slice();let c=a[0];const u={};i&&(u.time=i),u.level=o(t,e.levels.values[t]);let h=1+(0|e._childLevel);if(h<1&&(h=1),null!==c&&"object"==typeof c){for(;h--&&"object"==typeof a[0];)Object.assign(u,a.shift());c=a.length?n(a.shift(),a):void 0}else"string"==typeof c&&(c=n(a.shift(),a));return void 0!==c&&(u.msg=c),l(u)}(this,s,c,l,t.formatters)):a.apply(u,c),t.transmit){const n=t.transmit.level||e._level,i=r.levels.values[n],a=r.levels.values[s];if(a<i)return;!function(e,t,r){const n=t.send,i=t.ts,s=t.methodLevel,o=t.methodValue,l=t.val,a=e._logEvent.bindings;g(r,e._serialize||Object.keys(e.serializers),e.serializers,void 0===e._stdErrSerialize||e._stdErrSerialize),e._logEvent.ts=i,e._logEvent.messages=r.filter((function(e){return-1===a.indexOf(e)})),e._logEvent.level.label=s,e._logEvent.level.value=o,n(s,e._logEvent,l),e._logEvent=d(a)}(this,{ts:l,methodLevel:s,methodValue:a,transmitLevel:n,transmitValue:r.levels.values[t.transmit.level||e._level],send:t.transmit.send,val:o(e._level,r)},c)}};var a}(e,t,r,s);const c=function(e){const t=[];e.bindings&&t.push(e.bindings);let r=e[a];for(;r.parent;)r=r.parent,r.logger.bindings&&t.push(r.logger.bindings);return t.reverse()}(e);0!==c.length&&(e[s]=function(e,t){return function(){return t.apply(this,[...e,...arguments])}}(c,e[s]))}function g(e,t,r,n){for(const i in e)if(n&&e[i]instanceof Error)e[i]=h.stdSerializers.err(e[i]);else if("object"==typeof e[i]&&!Array.isArray(e[i]))for(const n in e[i])t&&t.indexOf(n)>-1&&n in r&&(e[i][n]=r[n](e[i][n]))}function d(e){return{ts:0,messages:[],bindings:e||[],level:{label:"",value:0}}}function p(e){const t={type:e.constructor.name,msg:e.message,stack:e.stack};for(const r in e)void 0===t[r]&&(t[r]=e[r]);return t}function m(e){return"function"==typeof e.timestamp?e.timestamp:!1===e.timestamp?w:E}function v(){return{}}function b(e){return e}function y(){}function w(){return!1}function E(){return Date.now()}h.levels={values:{fatal:60,error:50,warn:40,info:30,debug:20,trace:10},labels:{10:"trace",20:"debug",30:"info",40:"warn",50:"error",60:"fatal"}},h.stdSerializers=s,h.stdTimeFunctions=Object.assign({},{nullTime:w,epochTime:E,unixTime:function(){return Math.round(Date.now()/1e3)},isoTime:function(){return new Date(Date.now()).toISOString()}}),e.exports.default=h,e.exports.pino=h}},t={};function r(n){var i=t[n];if(void 0!==i)return i.exports;var s=t[n]={exports:{}};return e[n](s,s.exports,r),s.exports}r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var n={};r.d(n,{default:()=>d});var i,s,o=r(591),l=r.n(o);!function(e){e.HIGH="HIGH",e.NORMAL="NORMAL",e.LOW="LOW"}(i||(i={})),function(e){e.CONNECTING="CONNECTING",e.CONNECTED="CONNECTED",e.DISCONNECTED="DISCONNECTED",e.RECONNECTING="RECONNECTING",e.FAILED="FAILED"}(s||(s={}));var a=r(874),c=r.n(a);function u(e){return c()({name:e,level:process.env.LOG_LEVEL||"info",timestamp:c().stdTimeFunctions.isoTime})}var h=function(e,t,r,n){return new(r||(r=Promise))((function(i,s){function o(e){try{a(n.next(e))}catch(e){s(e)}}function l(e){try{a(n.throw(e))}catch(e){s(e)}}function a(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(o,l)}a((n=n.apply(e,t||[])).next())}))};class f{constructor(e,t={}){this.sender=e,this.options=t,this.queue=[],this.processing=!1,this.logger=u("MessageQueue")}enqueue(e){return h(this,void 0,void 0,(function*(){if(this.options.maxSize&&this.queue.length>=this.options.maxSize)throw new Error("Queue is full");const[t,...r]=e,n={type:t,data:1===r.length?r[0]:r,priority:i.NORMAL,queuedAt:Date.now(),retryCount:0};this.queue.push(n),this.queue.sort(((e,t)=>e.priority===t.priority?e.queuedAt-t.queuedAt:e.priority===i.HIGH?-1:1)),this.processing||this.processQueue().catch((e=>{this.logger.error({error:e},"Error processing queue")}))}))}processQueue(){return h(this,void 0,void 0,(function*(){if(!this.processing&&0!==this.queue.length){this.processing=!0;try{for(;this.queue.length>0;){const e=this.queue[0],t=[e.type,e.data];try{yield this.sender(t),this.queue.shift()}catch(r){if(this.logger.error({error:r,message:t},"Failed to send message"),this.options.maxRetries&&e.retryCount>=this.options.maxRetries){this.logger.warn({message:t},"Max retries reached, removing message from queue"),this.queue.shift();continue}e.retryCount++,yield new Promise((e=>setTimeout(e,this.options.retryDelay||1e3)))}}}finally{this.processing=!1}if(this.options.staleTimeout){const e=Date.now(),t=this.options.staleTimeout;this.queue.forEach(((r,n)=>{e-r.queuedAt>t&&(this.logger.warn({message:r},"Message is stale, removing from queue"),this.queue.splice(n,1))}))}}}))}getSize(){return this.queue.length}clear(){this.queue.length=0}}var g=function(e,t,r,n){return new(r||(r=Promise))((function(i,s){function o(e){try{a(n.next(e))}catch(e){s(e)}}function l(e){try{a(n.throw(e))}catch(e){s(e)}}function a(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(o,l)}a((n=n.apply(e,t||[])).next())}))};const d={NostrWSClient:class{constructor(e,t={}){this.relayUrls=e,this.options=t,this.ws=null,this.connectionState=s.DISCONNECTED,this.reconnectAttempts=0,this.reconnectTimeout=null,this.logger=t.logger||u("NostrWSClient"),this.queue=new f((e=>g(this,void 0,void 0,(function*(){if(!this.ws||this.connectionState!==s.CONNECTED)throw new Error("Not connected to relay");try{this.ws.send(JSON.stringify(e)),this.logger.debug({message:e},"Message sent")}catch(t){throw this.logger.error({error:t,message:e},"Failed to send message"),t}}))),{maxSize:t.queueSize,maxRetries:t.maxRetries,retryDelay:t.retryDelay})}connect(){return g(this,void 0,void 0,(function*(){if(this.connectionState!==s.CONNECTED)if(this.connectionState!==s.CONNECTING){this.connectionState=s.CONNECTING;try{const e=this.relayUrls[0];this.ws=new(l())(e),yield new Promise(((e,t)=>{const r=setTimeout((()=>{t(new Error("Connection timeout"))}),this.options.connectionTimeout||5e3);this.ws.on("open",(()=>{clearTimeout(r),this.connectionState=s.CONNECTED,this.reconnectAttempts=0,this.logger.info("Connected to relay"),e()})),this.ws.on("error",(e=>{clearTimeout(r),this.logger.error({error:e},"WebSocket error"),this.options.onError&&this.options.onError(e),t(e)})),this.ws.on("close",(()=>{this.handleDisconnect()})),this.ws.on("message",(e=>{this.handleMessage(e)}))}))}catch(e){throw this.logger.error({error:e},"Failed to connect"),this.handleDisconnect(),e}}else this.logger.debug("Connection already in progress");else this.logger.debug("Already connected")}))}disconnect(){return g(this,void 0,void 0,(function*(){this.connectionState!==s.DISCONNECTED?(this.connectionState=s.DISCONNECTED,this.reconnectTimeout&&(clearTimeout(this.reconnectTimeout),this.reconnectTimeout=null),this.ws&&(this.ws.close(),this.ws=null),this.logger.info("Disconnected from relay")):this.logger.debug("Already disconnected")}))}sendMessage(e){return g(this,void 0,void 0,(function*(){if(this.connectionState!==s.CONNECTED)throw new Error("Not connected to relay");yield this.queue.enqueue(e)}))}handleMessage(e){try{const t=JSON.parse(e.toString());this.logger.debug({message:t},"Received message"),this.options.onMessage&&this.options.onMessage(e.toString())}catch(t){this.logger.error({error:t,data:e},"Failed to parse message"),this.options.onError&&this.options.onError(t)}}handleDisconnect(){if(this.connectionState=s.DISCONNECTED,this.ws=null,this.options.retryAttempts&&this.reconnectAttempts<this.options.retryAttempts){this.connectionState=s.RECONNECTING,this.reconnectAttempts++;const e=this.options.retryDelay||1e3;this.logger.info({attempt:this.reconnectAttempts,maxAttempts:this.options.retryAttempts},`Reconnecting in ${e}ms`),this.reconnectTimeout=setTimeout((()=>{this.connect().catch((e=>{this.logger.error({error:e},"Reconnection failed")}))}),e)}else this.logger.warn("Max reconnection attempts reached"),this.connectionState=s.FAILED}getConnectionState(){return this.connectionState}}};return n=n.default})()));
//# sourceMappingURL=nostr-websocket-utils.min.js.map