UNPKG

@croct/plug

Version:

A fully-featured devkit for building natively personalized applications.

143 lines (142 loc) 4.79 kB
import { formatCause } from "@croct/sdk/error"; import { TabContextFactory } from "@croct/sdk/facade/evaluatorFacade"; import { PLAYGROUND_CONNECT_URL, PLAYGROUND_ORIGIN } from "./constants.js"; const CONNECTION_PARAMETER = "__cplay"; class PlaygroundPlugin { constructor(configuration) { this.sdkVersion = configuration.sdkVersion; this.appId = configuration.appId; this.connectionId = configuration.connectionId; this.tab = configuration.tab; this.contextFactory = configuration.contextFactory; this.storage = configuration.storage; this.eventSubscriber = configuration.eventSubscriber; this.cidAssigner = configuration.cidAssigner; this.tokenProvider = configuration.tokenProvider; this.logger = configuration.logger; } enable() { const connectionId = this.resolveConnectionId(); if (connectionId === null) { return; } this.syncListener = () => this.cidAssigner.assignCid().then((cid) => { this.syncToken(connectionId, cid); }).catch((error) => { this.logger.warn(`Sync failed: ${formatCause(error)}`); }); this.eventSubscriber.addListener("tokenChanged", this.syncListener); this.tab.addListener("urlChange", this.syncListener); return this.syncListener(); } resolveConnectionId() { if (this.connectionId !== void 0) { this.logger.debug("Connection ID passed in configuration"); return this.connectionId; } const url = new URL(this.tab.url); let connectionId = url.searchParams.get(CONNECTION_PARAMETER); if (connectionId === null || connectionId === "") { this.logger.debug("No connection ID found in URL"); connectionId = this.storage.getItem("connectionId"); this.logger.debug( connectionId !== null ? "Previous connection ID found" : "No previous connection ID found" ); return connectionId; } this.logger.debug("Connection ID found in URL"); this.storage.setItem("connectionId", connectionId); return connectionId; } disable() { if (this.syncListener !== void 0) { this.eventSubscriber.removeListener("tokenChanged", this.syncListener); this.tab.removeListener("urlChange", this.syncListener); delete this.syncListener; } } syncToken(connectionId, cid) { const iframe = document.createElement("iframe"); iframe.setAttribute("src", PLAYGROUND_CONNECT_URL); iframe.setAttribute("sandbox", "allow-scripts allow-same-origin"); iframe.style.visibility = "hidden"; iframe.style.opacity = "0"; iframe.style.border = "0"; iframe.style.width = "0"; iframe.style.height = "0"; const context = this.createContext(); iframe.onload = () => { if (iframe.contentWindow === null) { if (document.body.contains(iframe)) { document.body.removeChild(iframe); } this.logger.warn("Sync handshake failed"); return; } const listener = (event) => { if (event.origin !== PLAYGROUND_ORIGIN || event.data !== connectionId) { return; } window.removeEventListener("message", listener); if (document.body.contains(iframe)) { document.body.removeChild(iframe); } this.logger.debug("Sync completed"); }; window.addEventListener("message", listener); const payload = { appId: this.appId, connectionId, sdkVersion: this.sdkVersion, tabId: this.tab.id, cid, token: this.tokenProvider.getToken()?.toString() ?? null, context }; iframe.contentWindow.postMessage(payload, PLAYGROUND_ORIGIN); this.logger.debug("Waiting for sync acknowledgment..."); }; this.logger.debug("Sync started"); const connect = () => { document.body.appendChild(iframe); }; if (document.body === null) { document.addEventListener("DOMContentLoaded", connect); } else { connect(); } } createContext() { const { page, campaign, timeZone } = this.contextFactory.createContext(); const context = {}; if (page !== void 0) { context.page = page; } if (campaign !== void 0) { context.campaign = campaign; } if (timeZone !== void 0) { context.timeZone = timeZone; } return context; } } const factory = (props) => { const { sdk, options } = props; return new PlaygroundPlugin({ sdkVersion: sdk.version, appId: sdk.appId, connectionId: options.connectionId, tab: sdk.tab, storage: sdk.getTabStorage(), tokenProvider: sdk.userTokenStore, cidAssigner: sdk.cidAssigner, contextFactory: new TabContextFactory(sdk.tab), eventSubscriber: sdk.eventManager, logger: sdk.getLogger() }); }; export { PlaygroundPlugin, factory };