gameglue 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/gg.cjs.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("oidc-client-ts"),t=require("jwt-decode"),s=require("socket.io-client");const i={},n=(e,t)=>o()?localStorage.setItem(e,t):i[e]=t,r=e=>o()?localStorage.getItem(e):i[e],o=()=>!("object"==typeof process&&"[object process]"===String(process));class a{constructor(t){this._oidcSettings={authority:"https://auth.gameglue.gg/realms/GameGlue",client_id:t.clientId,redirect_uri:c(t.redirect_uri||window.location.href),post_logout_redirect_uri:c(window.location.href),response_type:"code",scope:`openid ${(t.scopes||[]).join(" ")}`,response_mode:"fragment",filterProtocolClaims:!0},this._oidcClient=new e.OidcClient(this._oidcSettings),this._refreshCallback=()=>{},this._refreshTimeout=null}setTokenRefreshTimeout(e){if(!e)return;clearTimeout(this._refreshTimeout);const s=1e3*t(e).exp-Date.now()-5e3;s>0&&(this._refreshTimeout=setTimeout(()=>{this.attemptRefresh()},s))}setAccessToken(e){return this.setTokenRefreshTimeout(e),n("gg-auth-token",e)}getAccessToken(){let e=r("gg-auth-token");return this.setTokenRefreshTimeout(e),e}getUserId(){return t(this.getAccessToken()).sub}setRefreshToken(e){return n("gg-refresh-token",e)}getRefreshToken(e){return r("gg-refresh-token")}_shouldHandleRedirectResponse(){return location.hash.includes("state=")&&(location.hash.includes("code=")||location.hash.includes("error="))}async handleRedirectResponse(){let e=await this._oidcClient.processSigninResponse(window.location.href);!e.error&&e.access_token?(window.history.pushState("",document.title,window.location.pathname+window.location.search),this.setAccessToken(e.access_token),this.setRefreshToken(e.refresh_token)):console.error(e.error)}onTokenRefreshed(e){this._refreshCallback=e}async isAuthenticated(e){let s=this.getAccessToken();if(!s)return!1;const i=t(s),n=new Date(1e3*i.exp)<new Date;return n&&!e?(await this.attemptRefresh(),this.isAuthenticated(!0)):!(n&&e)}isTokenExpired(e){const s=t(e);return new Date(1e3*s.exp)<new Date}async attemptRefresh(){const e=`${this._oidcSettings.authority}/protocol/openid-connect/token`,t=this._oidcSettings.client_id,s=this.getRefreshToken();try{const i=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({client_id:t,grant_type:"refresh_token",refresh_token:s})});if(200===i.status){const e=await i.json();this.setAccessToken(e.access_token),this.setRefreshToken(e.refresh_token),this._refreshCallback(e)}}catch(e){console.log("Error: ",e)}}_triggerAuthRedirect(){this._oidcClient.createSigninRequest({state:{bar:15}}).then(function(e){window.location=e.url}).catch(function(e){console.error(e)})}async authenticate(){this._shouldHandleRedirectResponse()&&await this.handleRedirectResponse(),await this.isAuthenticated()||await this._triggerAuthRedirect()}}function c(e){return e.endsWith("/")?e.replace(/\/+$/,""):e}const h=require("event-emitter");class u{constructor(e,t){this._config=t,this._socket=e,this._callbacks=[],this._fields=t.fields?[...t.fields]:null}async establishConnection(){if(!this._socket||!this._config.userId||!this._config.gameId)throw new Error("Missing arguments in establishConnection");return new Promise(e=>{let t;t=this._fields?{userId:this._config.userId,gameId:this._config.gameId,fields:this._fields}:`${this._config.userId}:${this._config.gameId}`,this._socket.timeout(5e3).emit("listen",t,(t,s)=>t?e({status:"failed",reason:"Listen request timed out."}):"success"===s.status?e({status:"success"}):e({status:"failed",reason:s.reason}))})}setupEventListener(){return this._socket.on("update",this.emit.bind(this,"update")),this}async subscribe(e){if(!Array.isArray(e)||0===e.length)throw new Error("fields must be a non-empty array");if(this._fields)for(const t of e)this._fields.includes(t)||this._fields.push(t);else this._fields=[...e];return this._updateSubscription()}async unsubscribe(e){if(!Array.isArray(e)||0===e.length)throw new Error("fields must be a non-empty array");if(!this._fields)throw new Error("Cannot unsubscribe when receiving all fields. Use subscribe() first to set explicit field list.");return this._fields=this._fields.filter(t=>!e.includes(t)),this._updateSubscription()}getFields(){return this._fields?[...this._fields]:null}async sendCommand(e,t){if(!e||"string"!=typeof e)throw new Error("field must be a non-empty string");return new Promise(s=>{const i={userId:this._config.userId,gameId:this._config.gameId,data:{fieldName:e,value:t}};this._socket.timeout(5e3).emit("set",i,(e,t)=>s(e?{status:"failed",reason:"Command request timed out."}:t))})}async _updateSubscription(){return new Promise(e=>{const t={userId:this._config.userId,gameId:this._config.gameId,fields:this._fields};this._socket.timeout(5e3).emit("listen-update",t,(t,s)=>e(t?{status:"failed",reason:"Update request timed out."}:s))})}}h(u.prototype);const d={msfs:!0};class l extends a{constructor(e){super(e),this._socket=!1}async auth(){return await this.authenticate(),await this.isAuthenticated()&&await this.initialize(),this.getUserId()}async initialize(){return new Promise(e=>{const t=this.getAccessToken();this._socket=s.io("https://socks.gameglue.gg",{transports:["websocket"],auth:{token:t}}),this._socket.on("connect",()=>{e()}),this.onTokenRefreshed(this.updateSocketAuth)})}updateSocketAuth(e){this._socket.auth.token=e}async createListener(e){if(!e)throw new Error("Not a valid listener config");if(!e.gameId||!d[e.gameId])throw new Error("Not a valid Game ID");if(!e.userId)throw new Error("User ID not supplied");if(e.fields&&!Array.isArray(e.fields))throw new Error("fields must be an array");this._socket||await this.initialize();const t=new u(this._socket,e),s=await t.establishConnection();if(this._socket.io.on("reconnect_attempt",e=>{console.log("Refresh Attempt"),this.updateSocketAuth(this.getAccessToken())}),this._socket.io.on("reconnect",()=>{t.establishConnection()}),"success"!==s.status)throw new Error(`There was a problem setting up the listener. Reason: ${s.reason}`);return t.setupEventListener()}}"undefined"!=typeof window&&(window.GameGlue=l),exports.GameGlue=l,exports.default=l;
2
+ //# sourceMappingURL=gg.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gg.cjs.js","sources":["../src/utils.js","../src/auth.js","../src/listener.js","../src/index.js"],"sourcesContent":["const storageMap = {};\nexport const storage = {\n set: (key, value) => {\n return isBrowser() ? localStorage.setItem(key, value) : (storageMap[key] = value);\n },\n get: (key) => {\n return isBrowser() ? localStorage.getItem(key) : storageMap[key];\n }\n};\nexport const isBrowser = () => {\n return !(typeof process === 'object' && String(process) === '[object process]');\n}","import { OidcClient } from 'oidc-client-ts';\nimport { storage } from './utils';\nimport jwt_decode from 'jwt-decode';\n\n\nexport class GameGlueAuth {\n constructor(cfg) {\n this._oidcSettings = {\n authority: \"https://auth.gameglue.gg/realms/GameGlue\",\n client_id: cfg.clientId,\n redirect_uri: removeTrailingSlashes(cfg.redirect_uri || window.location.href),\n post_logout_redirect_uri: removeTrailingSlashes(window.location.href),\n response_type: \"code\",\n scope: `openid ${(cfg.scopes||[]).join(' ')}`,\n response_mode: \"fragment\",\n filterProtocolClaims: true\n };\n this._oidcClient = new OidcClient(this._oidcSettings);\n this._refreshCallback = () => {}\n this._refreshTimeout = null;\n }\n setTokenRefreshTimeout(token) {\n if (!token) {\n return;\n }\n clearTimeout(this._refreshTimeout);\n const timeUntilExp = (jwt_decode(token).exp * 1000) - Date.now() - 5000;\n if (timeUntilExp > 0) {\n this._refreshTimeout = setTimeout(() => {\n this.attemptRefresh();\n }, timeUntilExp);\n }\n }\n setAccessToken(token) {\n this.setTokenRefreshTimeout(token);\n return storage.set('gg-auth-token', token);\n }\n getAccessToken() {\n let token = storage.get('gg-auth-token');\n this.setTokenRefreshTimeout(token);\n return token;\n }\n getUserId() {\n const decoded = jwt_decode(this.getAccessToken());\n return decoded.sub;\n }\n setRefreshToken(token) {\n return storage.set('gg-refresh-token', token);\n }\n getRefreshToken(token) {\n return storage.get('gg-refresh-token');\n }\n _shouldHandleRedirectResponse() {\n return (location.hash.includes(\"state=\") && (location.hash.includes(\"code=\") || location.hash.includes(\"error=\")));\n }\n async handleRedirectResponse() {\n let response = await this._oidcClient.processSigninResponse(window.location.href);\n if (response.error || !response.access_token) {\n console.error(response.error);\n return;\n }\n window.history.pushState(\"\", document.title, window.location.pathname + window.location.search);\n this.setAccessToken(response.access_token);\n this.setRefreshToken(response.refresh_token);\n }\n onTokenRefreshed(callback) {\n this._refreshCallback = callback;\n }\n async isAuthenticated(refreshAttempted) {\n // 1. Get the access token\n let access_token = this.getAccessToken();\n \n // 2. If we don't have an access token, we're not authenticated\n if (!access_token) {\n return false;\n }\n // 3. Decode the token, then check to see if it has expired\n const decoded = jwt_decode(access_token);\n const expirationDate = new Date(decoded.exp*1000);\n const isExpired = (expirationDate < new Date());\n \n if (isExpired && !refreshAttempted) {\n await this.attemptRefresh();\n return this.isAuthenticated(true);\n }\n \n // This line might be a little confusing. Basically it's just saying if we tried to refresh the token,\n // but it's STILL expired, return false, otherwise return true.\n return !(isExpired && refreshAttempted);\n }\n isTokenExpired(token) {\n const decoded = jwt_decode(token);\n const expirationDate = new Date(decoded.exp*1000);\n return (expirationDate < new Date());\n }\n async attemptRefresh() {\n const url = `${this._oidcSettings.authority}/protocol/openid-connect/token`;\n const client_id = this._oidcSettings.client_id;\n const refresh_token = this.getRefreshToken();\n const grant_type = 'refresh_token';\n \n try {\n const response = await fetch(url, {\n method: 'POST',\n headers:{\n 'Content-Type': 'application/x-www-form-urlencoded'\n },\n body: new URLSearchParams({\n client_id,\n grant_type,\n refresh_token\n })\n });\n if (response.status === 200) {\n const resObj = await response.json();\n this.setAccessToken(resObj.access_token);\n this.setRefreshToken(resObj.refresh_token);\n this._refreshCallback(resObj);\n }\n } catch(e) {\n console.log('Error: ', e);\n }\n }\n _triggerAuthRedirect() {\n this._oidcClient.createSigninRequest({ state: { bar: 15 } }).then(function(req) {\n window.location = req.url;\n }).catch(function(err) {\n console.error(err);\n });\n }\n async authenticate() {\n if (this._shouldHandleRedirectResponse()) {\n await this.handleRedirectResponse();\n }\n \n let isAuthenticated = await this.isAuthenticated();\n if (!isAuthenticated) {\n await this._triggerAuthRedirect();\n }\n }\n}\n\nfunction removeTrailingSlashes(url) {\n if (url.endsWith('/')) {\n return url.replace(/\\/+$/, '');\n }\n return url;\n}","const EventEmitter = require('event-emitter');\n\nexport class Listener {\n constructor(socket, config) {\n this._config = config;\n this._socket = socket;\n this._callbacks = [];\n this._fields = config.fields ? [...config.fields] : null;\n }\n\n async establishConnection() {\n if (!this._socket || !this._config.userId || !this._config.gameId) {\n throw new Error('Missing arguments in establishConnection');\n }\n return new Promise((resolve) => {\n // Use object format if fields are specified, otherwise use legacy string format\n let listenPayload;\n if (this._fields) {\n listenPayload = {\n userId: this._config.userId,\n gameId: this._config.gameId,\n fields: this._fields\n };\n } else {\n listenPayload = `${this._config.userId}:${this._config.gameId}`;\n }\n\n this._socket.timeout(5000).emit('listen', listenPayload, (error, response) => {\n if (error) {\n return resolve({status: 'failed', reason: 'Listen request timed out.'});\n }\n if (response.status === 'success') {\n return resolve({status: 'success'});\n } else {\n return resolve({status: 'failed', reason: response.reason});\n }\n });\n });\n }\n\n setupEventListener() {\n this._socket.on('update', this.emit.bind(this, 'update'));\n return this;\n }\n\n /**\n * Subscribe to additional fields dynamically\n * @param {string[]} fields - Array of field names to add\n * @returns {Promise<{status: string, reason?: string}>}\n */\n async subscribe(fields) {\n if (!Array.isArray(fields) || fields.length === 0) {\n throw new Error('fields must be a non-empty array');\n }\n\n // Add new fields to existing list\n if (!this._fields) {\n this._fields = [...fields];\n } else {\n for (const field of fields) {\n if (!this._fields.includes(field)) {\n this._fields.push(field);\n }\n }\n }\n\n return this._updateSubscription();\n }\n\n /**\n * Unsubscribe from specific fields\n * @param {string[]} fields - Array of field names to remove\n * @returns {Promise<{status: string, reason?: string}>}\n */\n async unsubscribe(fields) {\n if (!Array.isArray(fields) || fields.length === 0) {\n throw new Error('fields must be a non-empty array');\n }\n\n if (!this._fields) {\n // Currently receiving all fields, create explicit list without these fields\n throw new Error('Cannot unsubscribe when receiving all fields. Use subscribe() first to set explicit field list.');\n }\n\n this._fields = this._fields.filter(f => !fields.includes(f));\n\n return this._updateSubscription();\n }\n\n /**\n * Get the current list of subscribed fields\n * @returns {string[]|null} - Array of field names, or null if receiving all fields\n */\n getFields() {\n return this._fields ? [...this._fields] : null;\n }\n\n /**\n * Send a command to the broadcaster (game client)\n * @param {string} field - The field/action name to set\n * @param {any} value - The value to set\n * @returns {Promise<{status: string, reason?: string}>}\n */\n async sendCommand(field, value) {\n if (!field || typeof field !== 'string') {\n throw new Error('field must be a non-empty string');\n }\n\n return new Promise((resolve) => {\n const payload = {\n userId: this._config.userId,\n gameId: this._config.gameId,\n data: {\n fieldName: field,\n value\n }\n };\n\n this._socket.timeout(5000).emit('set', payload, (error, response) => {\n if (error) {\n return resolve({ status: 'failed', reason: 'Command request timed out.' });\n }\n return resolve(response);\n });\n });\n }\n\n /**\n * Internal method to send subscription update to server\n */\n async _updateSubscription() {\n return new Promise((resolve) => {\n const payload = {\n userId: this._config.userId,\n gameId: this._config.gameId,\n fields: this._fields\n };\n\n this._socket.timeout(5000).emit('listen-update', payload, (error, response) => {\n if (error) {\n return resolve({status: 'failed', reason: 'Update request timed out.'});\n }\n return resolve(response);\n });\n });\n }\n}\n\nEventEmitter(Listener.prototype);","import { GameGlueAuth } from './auth';\nimport { io } from \"socket.io-client\";\nimport { Listener} from \"./listener\";\n\nconst GAME_IDS = {\n 'msfs': true,\n};\n\nclass GameGlue extends GameGlueAuth {\n constructor(cfg) {\n super(cfg);\n this._socket = false;\n }\n \n async auth() {\n await this.authenticate();\n if (await this.isAuthenticated()) {\n await this.initialize();\n }\n return this.getUserId();\n }\n \n async initialize() {\n return new Promise((resolve) => {\n const token = this.getAccessToken();\n // For local development, use 'http://localhost:3031'\n this._socket = io('https://socks.gameglue.gg', {\n transports: ['websocket'],\n auth: {\n token\n }\n });\n // TODO: Update this code to use the new refresh logic. Example in gg-client repo\n this._socket.on('connect', () => {\n resolve();\n });\n this.onTokenRefreshed(this.updateSocketAuth);\n });\n }\n \n updateSocketAuth(authToken) {\n this._socket.auth.token = authToken;\n }\n \n async createListener(config) {\n if (!config) throw new Error('Not a valid listener config');\n if (!config.gameId || !GAME_IDS[config.gameId]) throw new Error('Not a valid Game ID');\n if (!config.userId) throw new Error('User ID not supplied');\n if (config.fields && !Array.isArray(config.fields)) throw new Error('fields must be an array');\n\n // Ensure socket is initialized (handles page reload case)\n if (!this._socket) {\n await this.initialize();\n }\n\n const listener = new Listener(this._socket, config);\n const establishConnectionResponse = await listener.establishConnection();\n this._socket.io.on('reconnect_attempt', (d) => {\n console.log('Refresh Attempt');\n this.updateSocketAuth(this.getAccessToken());\n });\n this._socket.io.on('reconnect', () => {\n listener.establishConnection();\n });\n \n if (establishConnectionResponse.status !== 'success') {\n throw new Error(`There was a problem setting up the listener. Reason: ${establishConnectionResponse.reason}`);\n }\n \n return listener.setupEventListener();\n }\n}\n\nif (typeof window !== 'undefined') {\n window.GameGlue = GameGlue;\n}\n\nexport default GameGlue;\nexport { GameGlue };"],"names":["storageMap","storage","key","value","isBrowser","localStorage","setItem","getItem","process","String","GameGlueAuth","constructor","cfg","this","_oidcSettings","authority","client_id","clientId","redirect_uri","removeTrailingSlashes","window","location","href","post_logout_redirect_uri","response_type","scope","scopes","join","response_mode","filterProtocolClaims","_oidcClient","OidcClient","_refreshCallback","_refreshTimeout","setTokenRefreshTimeout","token","clearTimeout","timeUntilExp","jwt_decode","exp","Date","now","setTimeout","attemptRefresh","setAccessToken","getAccessToken","getUserId","sub","setRefreshToken","getRefreshToken","_shouldHandleRedirectResponse","hash","includes","handleRedirectResponse","response","processSigninResponse","error","access_token","history","pushState","document","title","pathname","search","refresh_token","console","onTokenRefreshed","callback","isAuthenticated","refreshAttempted","decoded","isExpired","isTokenExpired","url","fetch","method","headers","body","URLSearchParams","grant_type","status","resObj","json","e","log","_triggerAuthRedirect","createSigninRequest","state","bar","then","req","catch","err","authenticate","endsWith","replace","EventEmitter","require","Listener","socket","config","_config","_socket","_callbacks","_fields","fields","establishConnection","userId","gameId","Error","Promise","resolve","listenPayload","timeout","emit","reason","setupEventListener","on","bind","subscribe","Array","isArray","length","field","push","_updateSubscription","unsubscribe","filter","f","getFields","sendCommand","payload","data","fieldName","prototype","GAME_IDS","msfs","GameGlue","super","auth","initialize","io","transports","updateSocketAuth","authToken","createListener","listener","establishConnectionResponse","d"],"mappings":"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"}
package/dist/gg.esm.js ADDED
@@ -0,0 +1,2 @@
1
+ import{OidcClient as e}from"oidc-client-ts";import t from"jwt-decode";import{io as s}from"socket.io-client";const i={},o=(e,t)=>r()?localStorage.setItem(e,t):i[e]=t,n=e=>r()?localStorage.getItem(e):i[e],r=()=>!("object"==typeof process&&"[object process]"===String(process));class a{constructor(t){this._oidcSettings={authority:"https://auth.gameglue.gg/realms/GameGlue",client_id:t.clientId,redirect_uri:c(t.redirect_uri||window.location.href),post_logout_redirect_uri:c(window.location.href),response_type:"code",scope:`openid ${(t.scopes||[]).join(" ")}`,response_mode:"fragment",filterProtocolClaims:!0},this._oidcClient=new e(this._oidcSettings),this._refreshCallback=()=>{},this._refreshTimeout=null}setTokenRefreshTimeout(e){if(!e)return;clearTimeout(this._refreshTimeout);const s=1e3*t(e).exp-Date.now()-5e3;s>0&&(this._refreshTimeout=setTimeout(()=>{this.attemptRefresh()},s))}setAccessToken(e){return this.setTokenRefreshTimeout(e),o("gg-auth-token",e)}getAccessToken(){let e=n("gg-auth-token");return this.setTokenRefreshTimeout(e),e}getUserId(){return t(this.getAccessToken()).sub}setRefreshToken(e){return o("gg-refresh-token",e)}getRefreshToken(e){return n("gg-refresh-token")}_shouldHandleRedirectResponse(){return location.hash.includes("state=")&&(location.hash.includes("code=")||location.hash.includes("error="))}async handleRedirectResponse(){let e=await this._oidcClient.processSigninResponse(window.location.href);!e.error&&e.access_token?(window.history.pushState("",document.title,window.location.pathname+window.location.search),this.setAccessToken(e.access_token),this.setRefreshToken(e.refresh_token)):console.error(e.error)}onTokenRefreshed(e){this._refreshCallback=e}async isAuthenticated(e){let s=this.getAccessToken();if(!s)return!1;const i=t(s),o=new Date(1e3*i.exp)<new Date;return o&&!e?(await this.attemptRefresh(),this.isAuthenticated(!0)):!(o&&e)}isTokenExpired(e){const s=t(e);return new Date(1e3*s.exp)<new Date}async attemptRefresh(){const e=`${this._oidcSettings.authority}/protocol/openid-connect/token`,t=this._oidcSettings.client_id,s=this.getRefreshToken();try{const i=await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({client_id:t,grant_type:"refresh_token",refresh_token:s})});if(200===i.status){const e=await i.json();this.setAccessToken(e.access_token),this.setRefreshToken(e.refresh_token),this._refreshCallback(e)}}catch(e){console.log("Error: ",e)}}_triggerAuthRedirect(){this._oidcClient.createSigninRequest({state:{bar:15}}).then(function(e){window.location=e.url}).catch(function(e){console.error(e)})}async authenticate(){this._shouldHandleRedirectResponse()&&await this.handleRedirectResponse(),await this.isAuthenticated()||await this._triggerAuthRedirect()}}function c(e){return e.endsWith("/")?e.replace(/\/+$/,""):e}const h=require("event-emitter");class u{constructor(e,t){this._config=t,this._socket=e,this._callbacks=[],this._fields=t.fields?[...t.fields]:null}async establishConnection(){if(!this._socket||!this._config.userId||!this._config.gameId)throw new Error("Missing arguments in establishConnection");return new Promise(e=>{let t;t=this._fields?{userId:this._config.userId,gameId:this._config.gameId,fields:this._fields}:`${this._config.userId}:${this._config.gameId}`,this._socket.timeout(5e3).emit("listen",t,(t,s)=>t?e({status:"failed",reason:"Listen request timed out."}):"success"===s.status?e({status:"success"}):e({status:"failed",reason:s.reason}))})}setupEventListener(){return this._socket.on("update",this.emit.bind(this,"update")),this}async subscribe(e){if(!Array.isArray(e)||0===e.length)throw new Error("fields must be a non-empty array");if(this._fields)for(const t of e)this._fields.includes(t)||this._fields.push(t);else this._fields=[...e];return this._updateSubscription()}async unsubscribe(e){if(!Array.isArray(e)||0===e.length)throw new Error("fields must be a non-empty array");if(!this._fields)throw new Error("Cannot unsubscribe when receiving all fields. Use subscribe() first to set explicit field list.");return this._fields=this._fields.filter(t=>!e.includes(t)),this._updateSubscription()}getFields(){return this._fields?[...this._fields]:null}async sendCommand(e,t){if(!e||"string"!=typeof e)throw new Error("field must be a non-empty string");return new Promise(s=>{const i={userId:this._config.userId,gameId:this._config.gameId,data:{fieldName:e,value:t}};this._socket.timeout(5e3).emit("set",i,(e,t)=>s(e?{status:"failed",reason:"Command request timed out."}:t))})}async _updateSubscription(){return new Promise(e=>{const t={userId:this._config.userId,gameId:this._config.gameId,fields:this._fields};this._socket.timeout(5e3).emit("listen-update",t,(t,s)=>e(t?{status:"failed",reason:"Update request timed out."}:s))})}}h(u.prototype);const d={msfs:!0};class l extends a{constructor(e){super(e),this._socket=!1}async auth(){return await this.authenticate(),await this.isAuthenticated()&&await this.initialize(),this.getUserId()}async initialize(){return new Promise(e=>{const t=this.getAccessToken();this._socket=s("https://socks.gameglue.gg",{transports:["websocket"],auth:{token:t}}),this._socket.on("connect",()=>{e()}),this.onTokenRefreshed(this.updateSocketAuth)})}updateSocketAuth(e){this._socket.auth.token=e}async createListener(e){if(!e)throw new Error("Not a valid listener config");if(!e.gameId||!d[e.gameId])throw new Error("Not a valid Game ID");if(!e.userId)throw new Error("User ID not supplied");if(e.fields&&!Array.isArray(e.fields))throw new Error("fields must be an array");this._socket||await this.initialize();const t=new u(this._socket,e),s=await t.establishConnection();if(this._socket.io.on("reconnect_attempt",e=>{console.log("Refresh Attempt"),this.updateSocketAuth(this.getAccessToken())}),this._socket.io.on("reconnect",()=>{t.establishConnection()}),"success"!==s.status)throw new Error(`There was a problem setting up the listener. Reason: ${s.reason}`);return t.setupEventListener()}}"undefined"!=typeof window&&(window.GameGlue=l);export{l as GameGlue,l as default};
2
+ //# sourceMappingURL=gg.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gg.esm.js","sources":["../src/utils.js","../src/auth.js","../src/listener.js","../src/index.js"],"sourcesContent":["const storageMap = {};\nexport const storage = {\n set: (key, value) => {\n return isBrowser() ? localStorage.setItem(key, value) : (storageMap[key] = value);\n },\n get: (key) => {\n return isBrowser() ? localStorage.getItem(key) : storageMap[key];\n }\n};\nexport const isBrowser = () => {\n return !(typeof process === 'object' && String(process) === '[object process]');\n}","import { OidcClient } from 'oidc-client-ts';\nimport { storage } from './utils';\nimport jwt_decode from 'jwt-decode';\n\n\nexport class GameGlueAuth {\n constructor(cfg) {\n this._oidcSettings = {\n authority: \"https://auth.gameglue.gg/realms/GameGlue\",\n client_id: cfg.clientId,\n redirect_uri: removeTrailingSlashes(cfg.redirect_uri || window.location.href),\n post_logout_redirect_uri: removeTrailingSlashes(window.location.href),\n response_type: \"code\",\n scope: `openid ${(cfg.scopes||[]).join(' ')}`,\n response_mode: \"fragment\",\n filterProtocolClaims: true\n };\n this._oidcClient = new OidcClient(this._oidcSettings);\n this._refreshCallback = () => {}\n this._refreshTimeout = null;\n }\n setTokenRefreshTimeout(token) {\n if (!token) {\n return;\n }\n clearTimeout(this._refreshTimeout);\n const timeUntilExp = (jwt_decode(token).exp * 1000) - Date.now() - 5000;\n if (timeUntilExp > 0) {\n this._refreshTimeout = setTimeout(() => {\n this.attemptRefresh();\n }, timeUntilExp);\n }\n }\n setAccessToken(token) {\n this.setTokenRefreshTimeout(token);\n return storage.set('gg-auth-token', token);\n }\n getAccessToken() {\n let token = storage.get('gg-auth-token');\n this.setTokenRefreshTimeout(token);\n return token;\n }\n getUserId() {\n const decoded = jwt_decode(this.getAccessToken());\n return decoded.sub;\n }\n setRefreshToken(token) {\n return storage.set('gg-refresh-token', token);\n }\n getRefreshToken(token) {\n return storage.get('gg-refresh-token');\n }\n _shouldHandleRedirectResponse() {\n return (location.hash.includes(\"state=\") && (location.hash.includes(\"code=\") || location.hash.includes(\"error=\")));\n }\n async handleRedirectResponse() {\n let response = await this._oidcClient.processSigninResponse(window.location.href);\n if (response.error || !response.access_token) {\n console.error(response.error);\n return;\n }\n window.history.pushState(\"\", document.title, window.location.pathname + window.location.search);\n this.setAccessToken(response.access_token);\n this.setRefreshToken(response.refresh_token);\n }\n onTokenRefreshed(callback) {\n this._refreshCallback = callback;\n }\n async isAuthenticated(refreshAttempted) {\n // 1. Get the access token\n let access_token = this.getAccessToken();\n \n // 2. If we don't have an access token, we're not authenticated\n if (!access_token) {\n return false;\n }\n // 3. Decode the token, then check to see if it has expired\n const decoded = jwt_decode(access_token);\n const expirationDate = new Date(decoded.exp*1000);\n const isExpired = (expirationDate < new Date());\n \n if (isExpired && !refreshAttempted) {\n await this.attemptRefresh();\n return this.isAuthenticated(true);\n }\n \n // This line might be a little confusing. Basically it's just saying if we tried to refresh the token,\n // but it's STILL expired, return false, otherwise return true.\n return !(isExpired && refreshAttempted);\n }\n isTokenExpired(token) {\n const decoded = jwt_decode(token);\n const expirationDate = new Date(decoded.exp*1000);\n return (expirationDate < new Date());\n }\n async attemptRefresh() {\n const url = `${this._oidcSettings.authority}/protocol/openid-connect/token`;\n const client_id = this._oidcSettings.client_id;\n const refresh_token = this.getRefreshToken();\n const grant_type = 'refresh_token';\n \n try {\n const response = await fetch(url, {\n method: 'POST',\n headers:{\n 'Content-Type': 'application/x-www-form-urlencoded'\n },\n body: new URLSearchParams({\n client_id,\n grant_type,\n refresh_token\n })\n });\n if (response.status === 200) {\n const resObj = await response.json();\n this.setAccessToken(resObj.access_token);\n this.setRefreshToken(resObj.refresh_token);\n this._refreshCallback(resObj);\n }\n } catch(e) {\n console.log('Error: ', e);\n }\n }\n _triggerAuthRedirect() {\n this._oidcClient.createSigninRequest({ state: { bar: 15 } }).then(function(req) {\n window.location = req.url;\n }).catch(function(err) {\n console.error(err);\n });\n }\n async authenticate() {\n if (this._shouldHandleRedirectResponse()) {\n await this.handleRedirectResponse();\n }\n \n let isAuthenticated = await this.isAuthenticated();\n if (!isAuthenticated) {\n await this._triggerAuthRedirect();\n }\n }\n}\n\nfunction removeTrailingSlashes(url) {\n if (url.endsWith('/')) {\n return url.replace(/\\/+$/, '');\n }\n return url;\n}","const EventEmitter = require('event-emitter');\n\nexport class Listener {\n constructor(socket, config) {\n this._config = config;\n this._socket = socket;\n this._callbacks = [];\n this._fields = config.fields ? [...config.fields] : null;\n }\n\n async establishConnection() {\n if (!this._socket || !this._config.userId || !this._config.gameId) {\n throw new Error('Missing arguments in establishConnection');\n }\n return new Promise((resolve) => {\n // Use object format if fields are specified, otherwise use legacy string format\n let listenPayload;\n if (this._fields) {\n listenPayload = {\n userId: this._config.userId,\n gameId: this._config.gameId,\n fields: this._fields\n };\n } else {\n listenPayload = `${this._config.userId}:${this._config.gameId}`;\n }\n\n this._socket.timeout(5000).emit('listen', listenPayload, (error, response) => {\n if (error) {\n return resolve({status: 'failed', reason: 'Listen request timed out.'});\n }\n if (response.status === 'success') {\n return resolve({status: 'success'});\n } else {\n return resolve({status: 'failed', reason: response.reason});\n }\n });\n });\n }\n\n setupEventListener() {\n this._socket.on('update', this.emit.bind(this, 'update'));\n return this;\n }\n\n /**\n * Subscribe to additional fields dynamically\n * @param {string[]} fields - Array of field names to add\n * @returns {Promise<{status: string, reason?: string}>}\n */\n async subscribe(fields) {\n if (!Array.isArray(fields) || fields.length === 0) {\n throw new Error('fields must be a non-empty array');\n }\n\n // Add new fields to existing list\n if (!this._fields) {\n this._fields = [...fields];\n } else {\n for (const field of fields) {\n if (!this._fields.includes(field)) {\n this._fields.push(field);\n }\n }\n }\n\n return this._updateSubscription();\n }\n\n /**\n * Unsubscribe from specific fields\n * @param {string[]} fields - Array of field names to remove\n * @returns {Promise<{status: string, reason?: string}>}\n */\n async unsubscribe(fields) {\n if (!Array.isArray(fields) || fields.length === 0) {\n throw new Error('fields must be a non-empty array');\n }\n\n if (!this._fields) {\n // Currently receiving all fields, create explicit list without these fields\n throw new Error('Cannot unsubscribe when receiving all fields. Use subscribe() first to set explicit field list.');\n }\n\n this._fields = this._fields.filter(f => !fields.includes(f));\n\n return this._updateSubscription();\n }\n\n /**\n * Get the current list of subscribed fields\n * @returns {string[]|null} - Array of field names, or null if receiving all fields\n */\n getFields() {\n return this._fields ? [...this._fields] : null;\n }\n\n /**\n * Send a command to the broadcaster (game client)\n * @param {string} field - The field/action name to set\n * @param {any} value - The value to set\n * @returns {Promise<{status: string, reason?: string}>}\n */\n async sendCommand(field, value) {\n if (!field || typeof field !== 'string') {\n throw new Error('field must be a non-empty string');\n }\n\n return new Promise((resolve) => {\n const payload = {\n userId: this._config.userId,\n gameId: this._config.gameId,\n data: {\n fieldName: field,\n value\n }\n };\n\n this._socket.timeout(5000).emit('set', payload, (error, response) => {\n if (error) {\n return resolve({ status: 'failed', reason: 'Command request timed out.' });\n }\n return resolve(response);\n });\n });\n }\n\n /**\n * Internal method to send subscription update to server\n */\n async _updateSubscription() {\n return new Promise((resolve) => {\n const payload = {\n userId: this._config.userId,\n gameId: this._config.gameId,\n fields: this._fields\n };\n\n this._socket.timeout(5000).emit('listen-update', payload, (error, response) => {\n if (error) {\n return resolve({status: 'failed', reason: 'Update request timed out.'});\n }\n return resolve(response);\n });\n });\n }\n}\n\nEventEmitter(Listener.prototype);","import { GameGlueAuth } from './auth';\nimport { io } from \"socket.io-client\";\nimport { Listener} from \"./listener\";\n\nconst GAME_IDS = {\n 'msfs': true,\n};\n\nclass GameGlue extends GameGlueAuth {\n constructor(cfg) {\n super(cfg);\n this._socket = false;\n }\n \n async auth() {\n await this.authenticate();\n if (await this.isAuthenticated()) {\n await this.initialize();\n }\n return this.getUserId();\n }\n \n async initialize() {\n return new Promise((resolve) => {\n const token = this.getAccessToken();\n // For local development, use 'http://localhost:3031'\n this._socket = io('https://socks.gameglue.gg', {\n transports: ['websocket'],\n auth: {\n token\n }\n });\n // TODO: Update this code to use the new refresh logic. Example in gg-client repo\n this._socket.on('connect', () => {\n resolve();\n });\n this.onTokenRefreshed(this.updateSocketAuth);\n });\n }\n \n updateSocketAuth(authToken) {\n this._socket.auth.token = authToken;\n }\n \n async createListener(config) {\n if (!config) throw new Error('Not a valid listener config');\n if (!config.gameId || !GAME_IDS[config.gameId]) throw new Error('Not a valid Game ID');\n if (!config.userId) throw new Error('User ID not supplied');\n if (config.fields && !Array.isArray(config.fields)) throw new Error('fields must be an array');\n\n // Ensure socket is initialized (handles page reload case)\n if (!this._socket) {\n await this.initialize();\n }\n\n const listener = new Listener(this._socket, config);\n const establishConnectionResponse = await listener.establishConnection();\n this._socket.io.on('reconnect_attempt', (d) => {\n console.log('Refresh Attempt');\n this.updateSocketAuth(this.getAccessToken());\n });\n this._socket.io.on('reconnect', () => {\n listener.establishConnection();\n });\n \n if (establishConnectionResponse.status !== 'success') {\n throw new Error(`There was a problem setting up the listener. Reason: ${establishConnectionResponse.reason}`);\n }\n \n return listener.setupEventListener();\n }\n}\n\nif (typeof window !== 'undefined') {\n window.GameGlue = GameGlue;\n}\n\nexport default GameGlue;\nexport { GameGlue };"],"names":["storageMap","storage","key","value","isBrowser","localStorage","setItem","getItem","process","String","GameGlueAuth","constructor","cfg","this","_oidcSettings","authority","client_id","clientId","redirect_uri","removeTrailingSlashes","window","location","href","post_logout_redirect_uri","response_type","scope","scopes","join","response_mode","filterProtocolClaims","_oidcClient","OidcClient","_refreshCallback","_refreshTimeout","setTokenRefreshTimeout","token","clearTimeout","timeUntilExp","jwt_decode","exp","Date","now","setTimeout","attemptRefresh","setAccessToken","getAccessToken","getUserId","sub","setRefreshToken","getRefreshToken","_shouldHandleRedirectResponse","hash","includes","handleRedirectResponse","response","processSigninResponse","error","access_token","history","pushState","document","title","pathname","search","refresh_token","console","onTokenRefreshed","callback","isAuthenticated","refreshAttempted","decoded","isExpired","isTokenExpired","url","fetch","method","headers","body","URLSearchParams","grant_type","status","resObj","json","e","log","_triggerAuthRedirect","createSigninRequest","state","bar","then","req","catch","err","authenticate","endsWith","replace","EventEmitter","require","Listener","socket","config","_config","_socket","_callbacks","_fields","fields","establishConnection","userId","gameId","Error","Promise","resolve","listenPayload","timeout","emit","reason","setupEventListener","on","bind","subscribe","Array","isArray","length","field","push","_updateSubscription","unsubscribe","filter","f","getFields","sendCommand","payload","data","fieldName","prototype","GAME_IDS","msfs","GameGlue","super","auth","initialize","io","transports","updateSocketAuth","authToken","createListener","listener","establishConnectionResponse","d"],"mappings":"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"}