UNPKG

pluto-mae

Version:
180 lines (179 loc) 6.8 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"] = "plutomae-event-app-added"; PMAEventType["appRemoved"] = "plutomae-event-app-removed"; PMAEventType["conversationUserUpdate"] = "plutomae-event-conversation-user-update"; PMAEventType["promiseResponse"] = "plutomae-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 = "plutomae-xrpk-event"; /** * 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 events to and from Pluto Multi App */ export default class PMAEventHandler { constructor() { this._appId = this.getAppState().appId; 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)); } /** * 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 app. Must link directly to the file (ie. .wbn file) * @param position A vector 3 that tells Pluto Multi App Launcher where to initially position the app once launched (if supported by the app) * @returns A promise once a response is receieved from Pluto Multi App */ launchXRPK(linkUrl, position) { if (!this.isXRPK()) { return Promise.reject(new Error("App is not running as an xrpk; cannot send an event to Pluto Multi App")); } let responseId = this.generateResponseId(); 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, position: position, 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.isXRPK()) { return Promise.reject(new Error("App is not running as an xrpk; cannot send an event to Pluto Multi App")); } let responseId = this.generateResponseId(); 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.isXRPK()) { return Promise.reject(new Error("App is not running as an xrpk; cannot send an event to Pluto Multi App")); } let responseId = this.generateResponseId(); 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, }, })); }); } /** * App State is provided to every app by Pluto Multi App Launcher * @returns The App State object, or an empty object if the App State does not exist */ getAppState() { return window.AppState ? window.AppState : {}; } // 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() { return `${this._appId ? this._appId : "MAE"}-response-${uuidv4()}`; } isXRPK() { if (this._appId === undefined) return false; 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); } }