j-queue-sdk-web
Advanced tools
Comparing version
@@ -1,2 +0,2 @@ | ||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ConnectionJQueueSdkWeb=e():t.ConnectionJQueueSdkWeb=e()}(this,(()=>(()=>{"use strict";var t={156:function(t,e,n){var i=this&&this.__awaiter||function(t,e,n,i){return new(n||(n=Promise))((function(s,o){function a(t){try{l(i.next(t))}catch(t){o(t)}}function r(t){try{l(i.throw(t))}catch(t){o(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(a,r)}l((i=i.apply(t,e||[])).next())}))};Object.defineProperty(e,"__esModule",{value:!0});const s=n(613);class o{static log(t,e="info",n){("error"===e?console.error:"warn"===e?console.warn:console.log)(`[J-Queue] ${t}`,null!=n?n:"")}static injectStyles(t){if("undefined"==typeof document||document.querySelector("style[data-jqueue-styles]"))return;const e=document.createElement("style");e.dataset.jqueueStyles="",e.textContent=this.CONFIG.STYLES.LOADER(t),document.head.appendChild(e)}static createPopup(t,e){if("undefined"==typeof document)return;this.removePopup();const n=document.createElement("div");n.id="__jqueue_popup",n.style.cssText=null!=e?e:this.CONFIG.STYLES.POPUP,n.innerHTML=t,document.body.appendChild(n),this.state.popupEl=n}static removePopup(){var t;"undefined"!=typeof document&&(null===(t=this.state.popupEl)||void 0===t||t.remove(),this.state.popupEl=null)}static toggleNavigation(t){"undefined"!=typeof window&&this.state.isNavigating!==t&&(window.onbeforeunload=t?()=>{var t;return(null===(t=this.state.queueStatus)||void 0===t?void 0:t.uuid)&&this.state.apiUrl&&this.sendLeaveRequest(),"Navigation is currently blocked."}:null,this.state.isNavigating=t)}static sendLeaveRequest(){const{apiUrl:t,queueStatus:e}=this.state;if(t&&(null==e?void 0:e.uuid))try{const n=JSON.stringify({uuid:e.uuid});navigator.sendBeacon(`${t}${this.CONFIG.API_ENDPOINTS.LEAVE}`,n)}catch(t){this.log("Leave API (sendBeacon) failed","error",t)}}static getDefaultPopupContent(t,e="ko",n){var i;const s=this.CONFIG.MESSAGES[e],o=null!==(i=null==n?void 0:n.textColor)&&void 0!==i?i:"#276bff";return`\n <div style="display: flex; flex-direction: column; align-items: center; width: 100%;">\n <div style="padding: 20px; text-align: center;">\n <p style="font-size: 18px; line-height: 1.5; margin: 0 0 20px 0; color: ${o};">\n ${s.MESS_1}<br>${s.MESS_2}\n </p>\n <div style="position: relative; width: 150px; height: 150px; margin: 20px auto;">\n <span style="position: absolute; inset: 0;" class="loader-jqueue_popup"></span>\n <div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center;">\n <div style="font-size: 14px; color: ${o};">${s.MESS_3}</div>\n <div style="font-size: 36px; color: ${o}; font-weight: bold;">${t}</div>\n </div>\n </div>\n </div>\n </div>\n `}static getAdjustedPollInterval(t,e){return t>=100?e+t/100*1e3:e}static handleStatusUpdate(t,e,n){var i,o;if(!(null==t?void 0:t.data))return void this.log("Invalid status response received","warn");const{status:a,position:r,uuid:l}=t.data;this.state.queueStatus={status:a,position:r,uuid:l},this.state.storageKey&&"undefined"!=typeof sessionStorage&&sessionStorage.setItem(this.state.storageKey,l),this.statusListeners.forEach((t=>t({status:a,position:r,uuid:l})));const u=this.getAdjustedPollInterval(r,this.CONFIG.TTL_INTERVAL);if(u!==n.value&&(n.value=u,this.startTtlEmission(n.value)),a===s.OnlineQueueStatus.ACTIVE)this.removePopup(),this.toggleNavigation(!1);else{const t="function"==typeof(null==e?void 0:e.content)?e.content(r):null!==(i=null==e?void 0:e.content)&&void 0!==i?i:this.getDefaultPopupContent(r,null!==(o=null==e?void 0:e.language)&&void 0!==o?o:"ko",e);this.createPopup(t,null==e?void 0:e.style),this.toggleNavigation(!0)}}static startTtlEmission(t){this.ttlInterval&&clearInterval(this.ttlInterval),this.ttlInterval=setInterval((()=>{var t,e;if((null===(t=this.state.socket)||void 0===t?void 0:t.readyState)===WebSocket.OPEN&&(null===(e=this.state.queueStatus)||void 0===e?void 0:e.uuid)&&this.state.socketConfig)try{this.state.socket.send(JSON.stringify({event:"online-queue:status",data:Object.assign(Object.assign({},this.state.socketConfig.query),{uuid:this.state.queueStatus.uuid})})),this.log("Sent online-queue:status")}catch(t){this.log("Failed to send online-queue:status","error",t)}}),t)}static reconnect(t,e,n,i,s){this.reconnectAttempts>=this.CONFIG.RECONNECTION_ATTEMPTS?this.log("Max reconnection attempts reached","error"):(this.reconnectAttempts++,this.log(`Reconnection attempt ${this.reconnectAttempts} in ${this.CONFIG.RECONNECTION_DELAY}ms`,"info"),setTimeout((()=>{this.setupWebSocket(t,e,n,i,s)}),this.CONFIG.RECONNECTION_DELAY))}static setupWebSocket(t,e,n,i,s){const o=new URLSearchParams(Object.assign(Object.assign({},e.query),{uuid:n})).toString(),a=new WebSocket(`${t}?${o}`);this.state.socket=a;const r={value:this.getAdjustedPollInterval(0,this.CONFIG.TTL_INTERVAL)};a.onopen=()=>{if(this.log("WebSocket connected"),this.reconnectAttempts=0,this.isFirstConnection)try{a.send(JSON.stringify({event:"online-queue:join",data:Object.assign({},e.query)})),this.log("Sent online-queue:join"),this.isFirstConnection=!1}catch(t){this.log("Failed to send online-queue:join","error",t)}this.startTtlEmission(r.value)},a.onmessage=t=>{try{const e=JSON.parse(t.data);if(!e.event||!e.data)return void this.log("Invalid WebSocket message format","warn");"online-queue:status"===e.event?this.handleStatusUpdate({data:e.data},s,r):i&&i[e.event]?i[e.event](e.data,{createPopup:this.createPopup.bind(this),removePopup:this.removePopup.bind(this),preventNavigation:()=>this.toggleNavigation(!0),allowNavigation:()=>this.toggleNavigation(!1)}):this.log(`Unhandled WebSocket event: ${e.event}`,"warn")}catch(t){this.log("Failed to parse WebSocket message","error",t)}},a.onerror=t=>{this.log("WebSocket error","error",t)},a.onclose=o=>{this.log(`WebSocket closed: code=${o.code}, reason=${o.reason}`,"warn"),this.ttlInterval&&(clearInterval(this.ttlInterval),this.ttlInterval=null),this.reconnect(t,e,n,i,s)}}static addStatusListener(t){this.statusListeners.push(t)}static removeStatusListener(t){this.statusListeners=this.statusListeners.filter((e=>e!==t))}static getQueueStatus(){return this.state.queueStatus}static init(t){return i(this,arguments,void 0,(function*({wsUrl:t,apiUrl:e,socketConfig:n={},popupConfig:i={},customEvents:s={},option:o={storageKey:this.CONFIG.STORAGE_KEY}}){var a;if(!t||!e)throw new Error("Both wsUrl and apiUrl are required for initialization");if("undefined"==typeof window)throw new Error("WebSocket is not supported in this environment.");this.state=Object.assign(Object.assign({},this.state),{storageKey:null!==(a=o.storageKey)&&void 0!==a?a:this.CONFIG.STORAGE_KEY,wsUrl:t,apiUrl:e,socketConfig:n}),this.injectStyles(i);try{return this.setupWebSocket(t,n,"",s,i),{disconnect:()=>this.disconnect()}}catch(t){return this.log("Initialization failed","error",t),{disconnect:()=>this.disconnect()}}}))}static cleanup(){this.state.storageKey&&"undefined"!=typeof sessionStorage&&sessionStorage.removeItem(this.state.storageKey),this.ttlInterval&&(clearInterval(this.ttlInterval),this.ttlInterval=null),this.removePopup(),this.toggleNavigation(!1),this.state={socket:null,popupEl:null,isNavigating:!1,storageKey:null,queueStatus:null,wsUrl:null,apiUrl:null,socketConfig:null},this.statusListeners=[],this.reconnectAttempts=0,this.isFirstConnection=!0}static disconnect(){var t,e;(null===(t=this.state.socket)||void 0===t?void 0:t.readyState)===WebSocket.OPEN&&(null===(e=this.state.queueStatus)||void 0===e?void 0:e.uuid)&&this.state.apiUrl&&this.sendLeaveRequest(),this.state.socket&&(this.state.socket.close(),this.state.socket=null),this.cleanup()}}o.CONFIG={TTL_INTERVAL:5e3,STORAGE_KEY:"queue_token",API_ENDPOINTS:{LEAVE:"/leave"},MESSAGES:{en:{MESS_1:"Progressing sequentially based on access order.",MESS_2:"We are doing our best to proceed quickly.",MESS_3:"Queue Number"},ko:{MESS_1:"접속한 순서대로 순차적 진행 중입니다.",MESS_2:"빠른 서비스 진행을 위해 최선을 다하고 있습니다.",MESS_3:"대기순번"}},STYLES:{POPUP:"\n position: fixed;\n inset: 0;\n width: 100%;\n height: 100%;\n background: #fff;\n z-index: 10000;\n display: flex;\n justify-content: center;\n align-items: center;\n font-size: 28px;\n ",LOADER:t=>{var e,n;return`\n .loader-jqueue_popup {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n display: inline-block;\n position: relative;\n background: linear-gradient(0deg, ${null!==(e=null==t?void 0:t.loaderGradientEnd)&&void 0!==e?e:"rgba(39,107,255,0.05)"} 33%, ${null!==(n=null==t?void 0:t.loaderGradientStart)&&void 0!==n?n:"#276bff"} 100%);\n box-sizing: border-box;\n animation: rotation 1s linear infinite;\n }\n .loader-jqueue_popup::after {\n content: '';\n box-sizing: border-box;\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n width: 96%;\n height: 96%;\n border-radius: 50%;\n background: #fff;\n }\n @keyframes rotation {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n `}},RECONNECTION_ATTEMPTS:3,RECONNECTION_DELAY:1e3},o.state={socket:null,popupEl:null,isNavigating:!1,storageKey:null,queueStatus:null,wsUrl:null,apiUrl:null,socketConfig:null},o.ttlInterval=null,o.statusListeners=[],o.reconnectAttempts=0,o.isFirstConnection=!0,"undefined"!=typeof window&&(window.ConnectionJQueueSdkWeb=o,console.log("Initialized on window")),e.default=o},613:(t,e)=>{var n;Object.defineProperty(e,"__esModule",{value:!0}),e.OnlineQueueStatus=void 0,function(t){t[t.WAITING=1]="WAITING",t[t.ACTIVE=2]="ACTIVE"}(n||(e.OnlineQueueStatus=n={}))}},e={},n=function n(i){var s=e[i];if(void 0!==s)return s.exports;var o=e[i]={exports:{}};return t[i].call(o.exports,o,o.exports,n),o.exports}(156);return n.default})())); | ||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("io")):"function"==typeof define&&define.amd?define(["io"],e):"object"==typeof exports?exports.ConnectionJQueueSdkWeb=e(require("io")):t.ConnectionJQueueSdkWeb=e(t.io)}(this,(t=>(()=>{"use strict";var e={156:function(t,e,n){var i=this&&this.__awaiter||function(t,e,n,i){return new(n||(n=Promise))((function(s,o){function a(t){try{l(i.next(t))}catch(t){o(t)}}function u(t){try{l(i.throw(t))}catch(t){o(t)}}function l(t){var e;t.done?s(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(a,u)}l((i=i.apply(t,e||[])).next())}))};Object.defineProperty(e,"__esModule",{value:!0});const s=n(676),o=n(613);class a{static log(t,e="info",n){("error"===e?console.error:"warn"===e?console.warn:console.log)(`[J-Queue] ${t}`,null!=n?n:"")}static injectStyles(t){if("undefined"==typeof document||document.querySelector("style[data-jqueue-styles]"))return;const e=document.createElement("style");e.dataset.jqueueStyles="",e.textContent=this.CONFIG.STYLES.LOADER(t),document.head.appendChild(e)}static createPopup(t,e){if("undefined"==typeof document)return;this.removePopup();const n=document.createElement("div");n.id="__jqueue_popup",n.style.cssText=null!=e?e:this.CONFIG.STYLES.POPUP,n.innerHTML=t,document.body.appendChild(n),this.state.popupEl=n}static removePopup(){var t;"undefined"!=typeof document&&(null===(t=this.state.popupEl)||void 0===t||t.remove(),this.state.popupEl=null)}static toggleNavigation(t){"undefined"!=typeof window&&this.state.isNavigating!==t&&(window.onbeforeunload=t?()=>{var t;return(null===(t=this.state.queueStatus)||void 0===t?void 0:t.uuid)&&this.state.apiUrl&&this.sendLeaveRequest(),"Navigation is currently blocked."}:null,this.state.isNavigating=t)}static sendLeaveRequest(){const{apiUrl:t,queueStatus:e}=this.state;if(t&&(null==e?void 0:e.uuid))try{const n=JSON.stringify({uuid:e.uuid});navigator.sendBeacon(`${t}${this.CONFIG.API_ENDPOINTS.LEAVE}`,n)}catch(t){this.log("Leave API (sendBeacon) failed","error",t)}}static getDefaultPopupContent(t,e="ko",n){var i;const s=this.CONFIG.MESSAGES[e],o=null!==(i=null==n?void 0:n.textColor)&&void 0!==i?i:"#276bff";return`\n <div style="display: flex; flex-direction: column; align-items: center; width: 100%;">\n <div style="padding: 20px; text-align: center;">\n <p style="font-size: 16px; line-height: 1.5; margin: 0 0 20px 0; color: ${o};">\n ${s.MESS_1}<br>${s.MESS_2}\n </p>\n <div style="position: relative; width: 150px; height: 150px; margin: 20px auto;">\n <span style="position: absolute; inset: 0;" class="loader-jqueue_popup"></span>\n <div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center;">\n <div style="font-size: 14px; color: ${o};">${s.MESS_3}</div>\n <div style="font-size: 36px; color: ${o}; font-weight: bold;">${t}</div>\n </div>\n </div>\n </div>\n </div>\n `}static getAdjustedPollInterval(t,e){return t>=100?e+t/100*1e3:e}static handleStatusUpdate(t,e,n){var i,s;if(!(null==t?void 0:t.data))return void this.log("Invalid status response received","warn");const{status:a,position:u,uuid:l}=t.data;this.state.queueStatus={status:a,position:u,uuid:l},this.state.storageKey&&"undefined"!=typeof sessionStorage&&sessionStorage.setItem(this.state.storageKey,l),this.statusListeners.forEach((t=>t({status:a,position:u,uuid:l})));const r=this.getAdjustedPollInterval(u,this.CONFIG.TTL_INTERVAL);if(r!==n.value&&(n.value=r,this.startTtlEmission(n.value)),a===o.OnlineQueueStatus.ACTIVE)this.removePopup(),this.toggleNavigation(!1);else{const t="function"==typeof(null==e?void 0:e.content)?e.content(u):null!==(i=null==e?void 0:e.content)&&void 0!==i?i:this.getDefaultPopupContent(u,null!==(s=null==e?void 0:e.language)&&void 0!==s?s:"ko",e);this.createPopup(t,null==e?void 0:e.style),this.toggleNavigation(!0)}}static startTtlEmission(t){this.ttlInterval&&clearInterval(this.ttlInterval),this.ttlInterval=setInterval((()=>{var t,e;(null===(t=this.state.socket)||void 0===t?void 0:t.connected)&&(null===(e=this.state.queueStatus)||void 0===e?void 0:e.uuid)&&this.state.socketConfig&&(this.state.socket.emit("online-queue:status",Object.assign(Object.assign({},this.state.socketConfig.query),{uuid:this.state.queueStatus.uuid})),this.log("Sent online-queue:status"))}),t)}static setupSocket(t,e,n,i,o){const a=(0,s.io)(t,{query:Object.assign(Object.assign({},e.query),{uuid:n}),transports:e.transports||["websocket"],reconnectionAttempts:e.reconnectionAttempts||3,reconnectionDelay:e.reconnectionDelay||1e3});this.state.socket=a;const u={value:this.getAdjustedPollInterval(0,this.CONFIG.TTL_INTERVAL)};let l=!0;a.on("connect",(()=>{this.log("Socket.IO connected"),l&&(a.emit("online-queue:join",Object.assign({},e.query)),this.log("Sent online-queue:join"),l=!1),this.startTtlEmission(u.value)})),a.on("online-queue:join",(t=>{this.handleStatusUpdate(t,o,u)})),a.on("online-queue:status",(t=>{this.handleStatusUpdate(t,o,u)})),i&&Object.keys(i).forEach((t=>{a.on(t,(e=>{i[t](e,{createPopup:this.createPopup.bind(this),removePopup:this.removePopup.bind(this),preventNavigation:()=>this.toggleNavigation(!0),allowNavigation:()=>this.toggleNavigation(!1)})}))})),a.on("connect_error",(t=>{this.log("Socket.IO connection error","error",t)})),a.on("disconnect",(t=>{this.log(`Socket.IO disconnected: ${t}`,"warn"),this.ttlInterval&&(clearInterval(this.ttlInterval),this.ttlInterval=null)}))}static addStatusListener(t){this.statusListeners.push(t)}static removeStatusListener(t){this.statusListeners=this.statusListeners.filter((e=>e!==t))}static getQueueStatus(){return this.state.queueStatus}static init(t){return i(this,arguments,void 0,(function*({wsUrl:t,apiUrl:e,socketConfig:n={},popupConfig:i={},customEvents:s={},option:o={storageKey:this.CONFIG.STORAGE_KEY}}){var a;if(!t||!e)throw new Error("Both wsUrl and apiUrl are required for initialization");if("undefined"==typeof window)throw new Error("Socket.IO is not supported in this environment.");this.state=Object.assign(Object.assign({},this.state),{storageKey:null!==(a=o.storageKey)&&void 0!==a?a:this.CONFIG.STORAGE_KEY,wsUrl:t,apiUrl:e,socketConfig:n}),this.injectStyles(i);try{return this.setupSocket(t,n,"",s,i),{disconnect:()=>this.disconnect()}}catch(t){return this.log("Initialization failed","error",t),{disconnect:()=>this.disconnect()}}}))}static cleanup(){this.state.storageKey&&"undefined"!=typeof sessionStorage&&sessionStorage.removeItem(this.state.storageKey),this.ttlInterval&&(clearInterval(this.ttlInterval),this.ttlInterval=null),this.removePopup(),this.toggleNavigation(!1),this.state={socket:null,popupEl:null,isNavigating:!1,storageKey:null,queueStatus:null,wsUrl:null,apiUrl:null,socketConfig:null},this.statusListeners=[]}static disconnect(){var t,e,n;(null===(t=this.state.socket)||void 0===t?void 0:t.connected)&&(null===(e=this.state.queueStatus)||void 0===e?void 0:e.uuid)&&this.state.apiUrl&&this.sendLeaveRequest(),null===(n=this.state.socket)||void 0===n||n.disconnect(),this.cleanup()}}a.CONFIG={TTL_INTERVAL:3e4,STORAGE_KEY:"queue_token",API_ENDPOINTS:{LEAVE:"/leave"},MESSAGES:{en:{MESS_1:"Progressing sequentially based on access order.",MESS_2:"We are doing our best to proceed quickly.",MESS_3:"Queue Number"},ko:{MESS_1:"접속한 순서대로 순차적 진행 중입니다.",MESS_2:"빠른 서비스 진행을 위해 최선을 다하고 있습니다.",MESS_3:"대기순번"}},STYLES:{POPUP:"\n position: fixed;\n inset: 0;\n width: 100%;\n height: 100%;\n background: #fff;\n z-index: 10000;\n display: flex;\n justify-content: center;\n align-items: center;\n font-size: 28px;\n ",LOADER:t=>{var e,n;return`\n .loader-jqueue_popup {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n display: inline-block;\n position: relative;\n background: linear-gradient(0deg, ${null!==(e=null==t?void 0:t.loaderGradientEnd)&&void 0!==e?e:"rgba(39,107,255,0.05)"} 33%, ${null!==(n=null==t?void 0:t.loaderGradientStart)&&void 0!==n?n:"#276bff"} 100%);\n box-sizing: border-box;\n animation: rotation 1s linear infinite;\n }\n .loader-jqueue_popup::after {\n content: '';\n box-sizing: border-box;\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n width: 96%;\n height: 96%;\n border-radius: 50%;\n background: #fff;\n }\n @keyframes rotation {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n `}}},a.state={socket:null,popupEl:null,isNavigating:!1,storageKey:null,queueStatus:null,wsUrl:null,apiUrl:null,socketConfig:null},a.ttlInterval=null,a.statusListeners=[],"undefined"!=typeof window&&(window.ConnectionJQueueSdkWeb=a),e.default=a},613:(t,e)=>{var n;Object.defineProperty(e,"__esModule",{value:!0}),e.OnlineQueueStatus=void 0,function(t){t[t.WAITING=1]="WAITING",t[t.ACTIVE=2]="ACTIVE"}(n||(e.OnlineQueueStatus=n={}))},676:e=>{e.exports=t}},n={},i=function t(i){var s=n[i];if(void 0!==s)return s.exports;var o=n[i]={exports:{}};return e[i].call(o.exports,o,o.exports,t),o.exports}(156);return i.default})())); | ||
//# sourceMappingURL=j-queue-sdk-web.js.map |
@@ -0,4 +1,5 @@ | ||
import { Socket } from 'socket.io-client'; | ||
import { InitConfig, OnlineQueueStatus } from './types'; | ||
interface ConnectionState { | ||
socket: WebSocket | null; | ||
socket: Socket | null; | ||
popupEl: HTMLElement | null; | ||
@@ -21,4 +22,2 @@ isNavigating: boolean; | ||
private static statusListeners; | ||
private static reconnectAttempts; | ||
private static isFirstConnection; | ||
/** Logs messages with a prefix, supporting different log levels. */ | ||
@@ -44,6 +43,4 @@ private static log; | ||
private static startTtlEmission; | ||
/** Attempts to reconnect to the WebSocket server. */ | ||
private static reconnect; | ||
/** Configures the WebSocket connection with event handlers and periodic TTL emission. */ | ||
private static setupWebSocket; | ||
/** Configures the Socket.IO connection with event handlers and periodic TTL emission. */ | ||
private static setupSocket; | ||
/** Adds a listener for queue status updates. */ | ||
@@ -61,3 +58,3 @@ static addStatusListener(listener: (status: NonNullable<ConnectionState['queueStatus']>) => void): void; | ||
private static cleanup; | ||
/** Disconnects the WebSocket connection and cleans up resources. */ | ||
/** Disconnects the Socket.IO connection and cleans up resources. */ | ||
private static disconnect; | ||
@@ -64,0 +61,0 @@ } |
@@ -12,2 +12,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const socket_io_client_1 = require("socket.io-client"); | ||
const types_1 = require("./types"); | ||
@@ -85,3 +86,3 @@ class ConnectionJQueueSdkWeb { | ||
<div style="padding: 20px; text-align: center;"> | ||
<p style="font-size: 18px; line-height: 1.5; margin: 0 0 20px 0; color: ${textColor};"> | ||
<p style="font-size: 16px; line-height: 1.5; margin: 0 0 20px 0; color: ${textColor};"> | ||
${messages.MESS_1}<br>${messages.MESS_2} | ||
@@ -142,87 +143,51 @@ </p> | ||
var _a, _b; | ||
if (((_a = this.state.socket) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN && ((_b = this.state.queueStatus) === null || _b === void 0 ? void 0 : _b.uuid) && this.state.socketConfig) { | ||
try { | ||
this.state.socket.send(JSON.stringify({ | ||
event: 'online-queue:status', | ||
data: Object.assign(Object.assign({}, this.state.socketConfig.query), { uuid: this.state.queueStatus.uuid }), | ||
})); | ||
this.log('Sent online-queue:status'); | ||
} | ||
catch (error) { | ||
this.log('Failed to send online-queue:status', 'error', error); | ||
} | ||
if (((_a = this.state.socket) === null || _a === void 0 ? void 0 : _a.connected) && ((_b = this.state.queueStatus) === null || _b === void 0 ? void 0 : _b.uuid) && this.state.socketConfig) { | ||
this.state.socket.emit('online-queue:status', Object.assign(Object.assign({}, this.state.socketConfig.query), { uuid: this.state.queueStatus.uuid })); | ||
this.log('Sent online-queue:status'); | ||
} | ||
}, interval); | ||
} | ||
/** Attempts to reconnect to the WebSocket server. */ | ||
static reconnect(wsUrl, socketConfig, uuid, customEvents, popupConfig) { | ||
if (this.reconnectAttempts >= this.CONFIG.RECONNECTION_ATTEMPTS) { | ||
this.log('Max reconnection attempts reached', 'error'); | ||
return; | ||
} | ||
this.reconnectAttempts++; | ||
this.log(`Reconnection attempt ${this.reconnectAttempts} in ${this.CONFIG.RECONNECTION_DELAY}ms`, 'info'); | ||
setTimeout(() => { | ||
this.setupWebSocket(wsUrl, socketConfig, uuid, customEvents, popupConfig); | ||
}, this.CONFIG.RECONNECTION_DELAY); | ||
} | ||
/** Configures the WebSocket connection with event handlers and periodic TTL emission. */ | ||
static setupWebSocket(wsUrl, socketConfig, uuid, customEvents, popupConfig) { | ||
// Append query parameters to wsUrl | ||
const query = new URLSearchParams(Object.assign(Object.assign({}, socketConfig.query), { uuid })).toString(); | ||
const ws = new WebSocket(`${wsUrl}?${query}`); | ||
this.state.socket = ws; | ||
/** Configures the Socket.IO connection with event handlers and periodic TTL emission. */ | ||
static setupSocket(wsUrl, socketConfig, uuid, customEvents, popupConfig) { | ||
const socket = (0, socket_io_client_1.io)(wsUrl, { | ||
query: Object.assign(Object.assign({}, socketConfig.query), { uuid }), | ||
transports: socketConfig.transports || ['websocket'], | ||
reconnectionAttempts: socketConfig.reconnectionAttempts || 3, | ||
reconnectionDelay: socketConfig.reconnectionDelay || 1000, | ||
}); | ||
this.state.socket = socket; | ||
const currentTtlInterval = { value: this.getAdjustedPollInterval(0, this.CONFIG.TTL_INTERVAL) }; | ||
ws.onopen = () => { | ||
this.log('WebSocket connected'); | ||
this.reconnectAttempts = 0; // Reset reconnection attempts | ||
if (this.isFirstConnection) { | ||
try { | ||
ws.send(JSON.stringify({ | ||
event: 'online-queue:join', | ||
data: Object.assign({}, socketConfig.query), | ||
})); | ||
this.log('Sent online-queue:join'); | ||
this.isFirstConnection = false; | ||
} | ||
catch (error) { | ||
this.log('Failed to send online-queue:join', 'error', error); | ||
} | ||
let isFirstConnection = true; | ||
socket.on('connect', () => { | ||
this.log('Socket.IO connected'); | ||
if (isFirstConnection) { | ||
socket.emit('online-queue:join', Object.assign({}, socketConfig.query)); | ||
this.log('Sent online-queue:join'); | ||
isFirstConnection = false; | ||
} | ||
this.startTtlEmission(currentTtlInterval.value); | ||
}; | ||
ws.onmessage = (event) => { | ||
try { | ||
const message = JSON.parse(event.data); | ||
if (!message.event || !message.data) { | ||
this.log('Invalid WebSocket message format', 'warn'); | ||
return; | ||
} | ||
switch (message.event) { | ||
case 'online-queue:status': | ||
this.handleStatusUpdate({ data: message.data }, popupConfig, currentTtlInterval); | ||
break; | ||
default: | ||
if (customEvents && customEvents[message.event]) { | ||
customEvents[message.event](message.data, { | ||
createPopup: this.createPopup.bind(this), | ||
removePopup: this.removePopup.bind(this), | ||
preventNavigation: () => this.toggleNavigation(true), | ||
allowNavigation: () => this.toggleNavigation(false), | ||
}); | ||
} | ||
else { | ||
this.log(`Unhandled WebSocket event: ${message.event}`, 'warn'); | ||
} | ||
} | ||
} | ||
catch (error) { | ||
this.log('Failed to parse WebSocket message', 'error', error); | ||
} | ||
}; | ||
ws.onerror = (error) => { | ||
this.log('WebSocket error', 'error', error); | ||
}; | ||
ws.onclose = (event) => { | ||
this.log(`WebSocket closed: code=${event.code}, reason=${event.reason}`, 'warn'); | ||
}); | ||
socket.on('online-queue:join', (data) => { | ||
this.handleStatusUpdate(data, popupConfig, currentTtlInterval); | ||
}); | ||
socket.on('online-queue:status', (data) => { | ||
this.handleStatusUpdate(data, popupConfig, currentTtlInterval); | ||
}); | ||
if (customEvents) { | ||
Object.keys(customEvents).forEach((event) => { | ||
socket.on(event, (data) => { | ||
customEvents[event](data, { | ||
createPopup: this.createPopup.bind(this), | ||
removePopup: this.removePopup.bind(this), | ||
preventNavigation: () => this.toggleNavigation(true), | ||
allowNavigation: () => this.toggleNavigation(false), | ||
}); | ||
}); | ||
}); | ||
} | ||
socket.on('connect_error', (error) => { | ||
this.log('Socket.IO connection error', 'error', error); | ||
}); | ||
socket.on('disconnect', (reason) => { | ||
this.log(`Socket.IO disconnected: ${reason}`, 'warn'); | ||
if (this.ttlInterval) { | ||
@@ -232,4 +197,3 @@ clearInterval(this.ttlInterval); | ||
} | ||
this.reconnect(wsUrl, socketConfig, uuid, customEvents, popupConfig); | ||
}; | ||
}); | ||
} | ||
@@ -255,3 +219,3 @@ /** Adds a listener for queue status updates. */ | ||
if (typeof window === 'undefined') | ||
throw new Error('WebSocket is not supported in this environment.'); | ||
throw new Error('Socket.IO is not supported in this environment.'); | ||
this.state = Object.assign(Object.assign({}, this.state), { storageKey: (_b = option.storageKey) !== null && _b !== void 0 ? _b : this.CONFIG.STORAGE_KEY, wsUrl, | ||
@@ -262,3 +226,4 @@ apiUrl, | ||
try { | ||
this.setupWebSocket(wsUrl, socketConfig, '', customEvents, popupConfig); | ||
// Connect socket immediately | ||
this.setupSocket(wsUrl, socketConfig, '', customEvents, popupConfig); | ||
return { disconnect: () => this.disconnect() }; | ||
@@ -294,15 +259,10 @@ } | ||
this.statusListeners = []; | ||
this.reconnectAttempts = 0; | ||
this.isFirstConnection = true; | ||
} | ||
/** Disconnects the WebSocket connection and cleans up resources. */ | ||
/** Disconnects the Socket.IO connection and cleans up resources. */ | ||
static disconnect() { | ||
var _a, _b; | ||
if (((_a = this.state.socket) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN && ((_b = this.state.queueStatus) === null || _b === void 0 ? void 0 : _b.uuid) && this.state.apiUrl) { | ||
var _a, _b, _c; | ||
if (((_a = this.state.socket) === null || _a === void 0 ? void 0 : _a.connected) && ((_b = this.state.queueStatus) === null || _b === void 0 ? void 0 : _b.uuid) && this.state.apiUrl) { | ||
this.sendLeaveRequest(); | ||
} | ||
if (this.state.socket) { | ||
this.state.socket.close(); | ||
this.state.socket = null; | ||
} | ||
(_c = this.state.socket) === null || _c === void 0 ? void 0 : _c.disconnect(); | ||
this.cleanup(); | ||
@@ -312,3 +272,3 @@ } | ||
ConnectionJQueueSdkWeb.CONFIG = { | ||
TTL_INTERVAL: 5000, // Base interval for online-queue:status | ||
TTL_INTERVAL: 30000, // Base interval for online-queue:status | ||
STORAGE_KEY: 'queue_token', | ||
@@ -375,4 +335,2 @@ API_ENDPOINTS: { | ||
}, | ||
RECONNECTION_ATTEMPTS: 3, | ||
RECONNECTION_DELAY: 1000, | ||
}; | ||
@@ -391,8 +349,6 @@ ConnectionJQueueSdkWeb.state = { | ||
ConnectionJQueueSdkWeb.statusListeners = []; | ||
ConnectionJQueueSdkWeb.reconnectAttempts = 0; | ||
ConnectionJQueueSdkWeb.isFirstConnection = true; | ||
if (typeof window !== 'undefined') { | ||
window.ConnectionJQueueSdkWeb = ConnectionJQueueSdkWeb; | ||
console.log('Initialized on window'); | ||
// console.log('Initialized on window'); | ||
} | ||
exports.default = ConnectionJQueueSdkWeb; |
{ | ||
"name": "j-queue-sdk-web", | ||
"version": "1.0.24", | ||
"version": "1.0.25", | ||
"description": "A TypeScript package to check WebSocket connection status and control web access with a popup", | ||
@@ -5,0 +5,0 @@ "main": "dist/j-queue-sdk-web.js", |
156
src/index.ts
@@ -0,5 +1,6 @@ | ||
import { io, Socket } from 'socket.io-client'; | ||
import { InitConfig, PopupConfig, OnlineQueueStatus, CustomEventUtils } from './types'; | ||
interface ConnectionState { | ||
socket: WebSocket | null; | ||
socket: Socket | null; | ||
popupEl: HTMLElement | null; | ||
@@ -26,3 +27,3 @@ isNavigating: boolean; | ||
private static readonly CONFIG = { | ||
TTL_INTERVAL: 5000, // Base interval for online-queue:status | ||
TTL_INTERVAL: 30000, // Base interval for online-queue:status | ||
STORAGE_KEY: 'queue_token', | ||
@@ -86,4 +87,2 @@ API_ENDPOINTS: { | ||
}, | ||
RECONNECTION_ATTEMPTS: 3, | ||
RECONNECTION_DELAY: 1000, | ||
}; | ||
@@ -104,4 +103,2 @@ | ||
private static statusListeners: Array<(status: NonNullable<ConnectionState['queueStatus']>) => void> = []; | ||
private static reconnectAttempts = 0; | ||
private static isFirstConnection = true; | ||
@@ -174,3 +171,3 @@ /** Logs messages with a prefix, supporting different log levels. */ | ||
<div style="padding: 20px; text-align: center;"> | ||
<p style="font-size: 18px; line-height: 1.5; margin: 0 0 20px 0; color: ${textColor};"> | ||
<p style="font-size: 16px; line-height: 1.5; margin: 0 0 20px 0; color: ${textColor};"> | ||
${messages.MESS_1}<br>${messages.MESS_2} | ||
@@ -236,12 +233,5 @@ </p> | ||
this.ttlInterval = setInterval(() => { | ||
if (this.state.socket?.readyState === WebSocket.OPEN && this.state.queueStatus?.uuid && this.state.socketConfig) { | ||
try { | ||
this.state.socket.send(JSON.stringify({ | ||
event: 'online-queue:status', | ||
data: { ...this.state.socketConfig.query, uuid: this.state.queueStatus.uuid }, | ||
})); | ||
this.log('Sent online-queue:status'); | ||
} catch (error) { | ||
this.log('Failed to send online-queue:status', 'error', error); | ||
} | ||
if (this.state.socket?.connected && this.state.queueStatus?.uuid && this.state.socketConfig) { | ||
this.state.socket.emit('online-queue:status', { ...this.state.socketConfig.query, uuid: this.state.queueStatus.uuid }); | ||
this.log('Sent online-queue:status'); | ||
} | ||
@@ -251,19 +241,4 @@ }, interval); | ||
/** Attempts to reconnect to the WebSocket server. */ | ||
private static reconnect(wsUrl: string, socketConfig: NonNullable<InitConfig['socketConfig']>, uuid: string, customEvents: InitConfig['customEvents'], popupConfig: InitConfig['popupConfig']): void { | ||
if (this.reconnectAttempts >= this.CONFIG.RECONNECTION_ATTEMPTS) { | ||
this.log('Max reconnection attempts reached', 'error'); | ||
return; | ||
} | ||
this.reconnectAttempts++; | ||
this.log(`Reconnection attempt ${this.reconnectAttempts} in ${this.CONFIG.RECONNECTION_DELAY}ms`, 'info'); | ||
setTimeout(() => { | ||
this.setupWebSocket(wsUrl, socketConfig, uuid, customEvents, popupConfig); | ||
}, this.CONFIG.RECONNECTION_DELAY); | ||
} | ||
/** Configures the WebSocket connection with event handlers and periodic TTL emission. */ | ||
private static setupWebSocket( | ||
/** Configures the Socket.IO connection with event handlers and periodic TTL emission. */ | ||
private static setupSocket( | ||
wsUrl: string, | ||
@@ -275,64 +250,50 @@ socketConfig: NonNullable<InitConfig['socketConfig']>, | ||
): void { | ||
// Append query parameters to wsUrl | ||
const query = new URLSearchParams({ ...socketConfig.query, uuid }).toString(); | ||
const ws = new WebSocket(`${wsUrl}?${query}`); | ||
this.state.socket = ws; | ||
const socket = io(wsUrl, { | ||
query: { ...socketConfig.query, uuid }, | ||
transports: socketConfig.transports || ['websocket'], | ||
reconnectionAttempts: socketConfig.reconnectionAttempts || 3, | ||
reconnectionDelay: socketConfig.reconnectionDelay || 1000, | ||
}); | ||
this.state.socket = socket; | ||
const currentTtlInterval = { value: this.getAdjustedPollInterval(0, this.CONFIG.TTL_INTERVAL) }; | ||
let isFirstConnection = true; | ||
ws.onopen = () => { | ||
this.log('WebSocket connected'); | ||
this.reconnectAttempts = 0; // Reset reconnection attempts | ||
if (this.isFirstConnection) { | ||
try { | ||
ws.send(JSON.stringify({ | ||
event: 'online-queue:join', | ||
data: { ...socketConfig.query }, | ||
})); | ||
this.log('Sent online-queue:join'); | ||
this.isFirstConnection = false; | ||
} catch (error) { | ||
this.log('Failed to send online-queue:join', 'error', error); | ||
} | ||
socket.on('connect', () => { | ||
this.log('Socket.IO connected'); | ||
if (isFirstConnection) { | ||
socket.emit('online-queue:join', { ...socketConfig.query }); | ||
this.log('Sent online-queue:join'); | ||
isFirstConnection = false; | ||
} | ||
this.startTtlEmission(currentTtlInterval.value); | ||
}; | ||
}); | ||
ws.onmessage = (event) => { | ||
try { | ||
const message = JSON.parse(event.data as string); | ||
if (!message.event || !message.data) { | ||
this.log('Invalid WebSocket message format', 'warn'); | ||
return; | ||
} | ||
socket.on('online-queue:join', (data: StatusResponse) => { | ||
this.handleStatusUpdate(data, popupConfig, currentTtlInterval); | ||
}); | ||
switch (message.event) { | ||
case 'online-queue:status': | ||
this.handleStatusUpdate({ data: message.data }, popupConfig, currentTtlInterval); | ||
break; | ||
default: | ||
if (customEvents && customEvents[message.event]) { | ||
customEvents[message.event](message.data, { | ||
createPopup: this.createPopup.bind(this), | ||
removePopup: this.removePopup.bind(this), | ||
preventNavigation: () => this.toggleNavigation(true), | ||
allowNavigation: () => this.toggleNavigation(false), | ||
}); | ||
} else { | ||
this.log(`Unhandled WebSocket event: ${message.event}`, 'warn'); | ||
} | ||
} | ||
} catch (error) { | ||
this.log('Failed to parse WebSocket message', 'error', error); | ||
} | ||
}; | ||
socket.on('online-queue:status', (data: StatusResponse) => { | ||
this.handleStatusUpdate(data, popupConfig, currentTtlInterval); | ||
}); | ||
ws.onerror = (error) => { | ||
this.log('WebSocket error', 'error', error); | ||
}; | ||
if (customEvents) { | ||
Object.keys(customEvents).forEach((event) => { | ||
socket.on(event, (data: any) => { | ||
customEvents[event](data, { | ||
createPopup: this.createPopup.bind(this), | ||
removePopup: this.removePopup.bind(this), | ||
preventNavigation: () => this.toggleNavigation(true), | ||
allowNavigation: () => this.toggleNavigation(false), | ||
}); | ||
}); | ||
}); | ||
} | ||
ws.onclose = (event) => { | ||
this.log(`WebSocket closed: code=${event.code}, reason=${event.reason}`, 'warn'); | ||
socket.on('connect_error', (error) => { | ||
this.log('Socket.IO connection error', 'error', error); | ||
}); | ||
socket.on('disconnect', (reason) => { | ||
this.log(`Socket.IO disconnected: ${reason}`, 'warn'); | ||
if (this.ttlInterval) { | ||
@@ -342,4 +303,3 @@ clearInterval(this.ttlInterval); | ||
} | ||
this.reconnect(wsUrl, socketConfig, uuid, customEvents, popupConfig); | ||
}; | ||
}); | ||
} | ||
@@ -372,3 +332,3 @@ | ||
if (!wsUrl || !apiUrl) throw new Error('Both wsUrl and apiUrl are required for initialization'); | ||
if (typeof window === 'undefined') throw new Error('WebSocket is not supported in this environment.'); | ||
if (typeof window === 'undefined') throw new Error('Socket.IO is not supported in this environment.'); | ||
@@ -385,3 +345,4 @@ this.state = { | ||
try { | ||
this.setupWebSocket(wsUrl, socketConfig, '', customEvents, popupConfig); | ||
// Connect socket immediately | ||
this.setupSocket(wsUrl, socketConfig, '', customEvents, popupConfig); | ||
return { disconnect: () => this.disconnect() }; | ||
@@ -416,15 +377,10 @@ } catch (error) { | ||
this.statusListeners = []; | ||
this.reconnectAttempts = 0; | ||
this.isFirstConnection = true; | ||
} | ||
/** Disconnects the WebSocket connection and cleans up resources. */ | ||
/** Disconnects the Socket.IO connection and cleans up resources. */ | ||
private static disconnect(): void { | ||
if (this.state.socket?.readyState === WebSocket.OPEN && this.state.queueStatus?.uuid && this.state.apiUrl) { | ||
if (this.state.socket?.connected && this.state.queueStatus?.uuid && this.state.apiUrl) { | ||
this.sendLeaveRequest(); | ||
} | ||
if (this.state.socket) { | ||
this.state.socket.close(); | ||
this.state.socket = null; | ||
} | ||
this.state.socket?.disconnect(); | ||
this.cleanup(); | ||
@@ -442,3 +398,3 @@ } | ||
window.ConnectionJQueueSdkWeb = ConnectionJQueueSdkWeb; | ||
console.log('Initialized on window'); | ||
// console.log('Initialized on window'); | ||
} | ||
@@ -445,0 +401,0 @@ |
Sorry, the diff of this file is not supported yet
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
1
Infinity%99831
-6.64%1220
-6.94%1
Infinity%