UNPKG

pluto-mams

Version:
179 lines (178 loc) 6.68 kB
import { v4 as uuidv4 } from "uuid"; /** * Events that Pluto Multi App sends to all running XRPKs * Subscribe to these events with PMAEventHandler.addEventListener() */ export var PMAEventType; (function (PMAEventType) { PMAEventType["appAdded"] = "plutomams-event-app-added"; PMAEventType["appRemoved"] = "plutomams-event-app-removed"; PMAEventType["conversationUserUpdate"] = "plutomams-event-conversation-user-update"; PMAEventType["promiseResponse"] = "plutomams-event-promise-response"; })(PMAEventType || (PMAEventType = {})); /** * All events from an XRPK are sent using this type * @disclaimer Not intended to be used directly. Use the provided public functions to send events to Pluto Multi App * */ export const XRPKEventType = "plutomams-xrpk-message"; /** * Event descriptions that can be sent to Pluto Multi App from an XRPK * @disclaimer These are not event types, but descriptions of events. Use the provided public functions to send events to Pluto Multi App */ export var XRPKEventTypeDescription; (function (XRPKEventTypeDescription) { XRPKEventTypeDescription["launchXRPK"] = "launch-xrpk"; XRPKEventTypeDescription["removeXRPK"] = "remove-xrpk"; XRPKEventTypeDescription["getAppList"] = "retrieve-app-list"; })(XRPKEventTypeDescription || (XRPKEventTypeDescription = {})); ; /** * Pluto Multi App Event Handler * Use this class to send and receive messages to and from Pluto Multi App */ export default class PMAEventHandler { constructor() { const urlParams = new URLSearchParams(location.search); let appIdQueryParam = urlParams.get("appid"); // TODO: Handle the case where an appid is not set by Pluto Multi App this._appId = appIdQueryParam ? appIdQueryParam : uuidv4(); this._eventHandler = new EventHandler(); Object.values(PMAEventType).forEach(type => { this._eventHandler.registerEvent(type); window.parent.addEventListener(type, (e) => this._eventHandler.dispatchEvent(type, e.detail)); }); this._openPromises = {}; window.parent.addEventListener(PMAEventType.promiseResponse, (e) => this.handleResponse(e.detail.responseId, e.detail.data, e.detail.error)); } /** * Get the app ID of this XRPK, provided by Pluto Multi App */ get appId() { // TODO: Handle the case where an appid is not set by Pluto Multi App return this._appId; } /** * Add an event listenter for Pluto Multi App Events * @param type The `PlutoMAEventType` to subscribe to * @param callback The callback to run when the event is receieved */ addEventListener(type, callback) { this._eventHandler.addEventListener(type, callback); } /** * Request to launch an XRPK in Pluto Multi App * @param linkUrl The url of the XRPK. Must link directly to the file (ie. .wbn file) * @returns A promise once a response is receieved from Pluto Multi App */ launchXRPK(linkUrl) { if (!this.isIframe()) { console.log("App is not running as an xrpk; cannot send an event to Pluto Multi App"); } let responseId = this.generateResponseId(this._appId); return new Promise((resolve, reject) => { this._openPromises[responseId] = { resolve, reject }; window.parent.dispatchEvent(new CustomEvent(XRPKEventType, { detail: { type: XRPKEventTypeDescription.launchXRPK, appid: this.appId, url: linkUrl, responseId: responseId, }, })); }); } /** * Request to remove an XRPK in Pluto Multi App * @param appIdToRemove The app ID of the app to be removed * @returns A promise once a response is receieved from Pluto Multi App */ removeXRPK(appIdToRemove) { if (!this.isIframe()) { console.log("App is not running as an xrpk; cannot send an event to Pluto Multi App"); } let responseId = this.generateResponseId(this._appId); return new Promise((resolve, reject) => { this._openPromises[responseId] = { resolve, reject }; window.parent.dispatchEvent(new CustomEvent(XRPKEventType, { detail: { type: XRPKEventTypeDescription.removeXRPK, appid: this.appId, appIdToRemove, responseId, }, })); }); } /** * Get the current app list from Pluto Multi App * @return A promise that when resolved includes the app list * @returns A promise once a response is receieved from Pluto Multi App */ retrieveAppList() { if (!this.isIframe()) { console.log("App is not running as an xrpk; cannot send an event to Pluto Multi App"); } let responseId = this.generateResponseId(this._appId); return new Promise((resolve, reject) => { this._openPromises[responseId] = { resolve, reject }; window.parent.dispatchEvent(new CustomEvent(XRPKEventType, { detail: { type: XRPKEventTypeDescription.getAppList, appId: this.appId, responseId: responseId, }, })); }); } // Private functions handleResponse(responseId, data, error) { if (responseId in this._openPromises) { let { resolve, reject } = this._openPromises[responseId]; if (error) reject(error); else if (data) resolve(data); else resolve(); delete this._openPromises[responseId]; } } generateResponseId(messageId) { return `${messageId}-response-${uuidv4()}`; } isIframe() { try { return window.self !== window.top; } catch (e) { return true; } } } // Private helper classes class Event { constructor(type) { this.type = type; this.callbacks = []; } registerCallback(callback) { this.callbacks.push(callback); } } class EventHandler { constructor() { this.events = {}; } registerEvent(type) { var event = new Event(type); this.events[type] = event; } dispatchEvent(type, args) { this.events[type].callbacks.forEach((callback) => { callback(args); }); } addEventListener(type, callback) { this.events[type].registerCallback(callback); } }