UNPKG

@croct/plug

Version:

A fully-featured devkit for building natively personalized applications.

181 lines (180 loc) 6.16 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var preview_exports = {}; __export(preview_exports, { PreviewPlugin: () => PreviewPlugin, factory: () => factory }); module.exports = __toCommonJS(preview_exports); var import_error = require("@croct/sdk/error"); var import_token = require('./sdk/token.cjs'); var import_constants = require('./constants.cjs'); const PREVIEW_PARAMETER = "croct-preview"; const PREVIEW_EXIT = "exit"; const _PreviewPlugin = class _PreviewPlugin { constructor(configuration) { this.cleanUp = []; this.tokenStore = configuration.tokenStore; this.logger = configuration.logger; } enable() { const url = new URL(window.location.href); const previewData = url.searchParams.get(PREVIEW_PARAMETER); if (previewData !== null) { this.updateToken(previewData); this.updateUrl(); setTimeout(this.updateUrl, 500); } const token = this.tokenStore.getToken(); if (token !== null) { this.insertWidget(this.getWidgetUrl(token)); } } disable() { const callbacks = this.cleanUp.splice(0); callbacks.forEach((cleanUp) => cleanUp()); } updateToken(data) { if (data === PREVIEW_EXIT) { this.logger.debug("Exiting preview mode."); this.tokenStore.setToken(null); return; } try { let token = import_token.Token.parse(data); const { exp } = token.getPayload(); if (exp !== void 0 && exp <= Date.now() / 1e3) { this.logger.debug("Preview token expired."); token = null; } this.logger.debug("Preview token updated."); this.tokenStore.setToken(token); } catch (error) { this.tokenStore.setToken(null); this.logger.warn(`Invalid preview token: ${(0, import_error.formatCause)(error)}`); } } getWidgetUrl(token) { const params = this.getWidgetParams(token); let queryString = params.toString(); if (queryString !== "") { queryString = `?${queryString}`; } return `${import_constants.PREVIEW_WIDGET_URL}${queryString}`; } getWidgetParams(token) { const { metadata = {} } = token.getPayload(); const params = new URLSearchParams(); if (metadata === null || typeof metadata !== "object" || Array.isArray(metadata)) { return params; } for (const [key, param] of Object.entries(_PreviewPlugin.PREVIEW_PARAMS)) { const value = metadata[key]; if (typeof value === "string") { params.set(param, value); } } return params; } insertWidget(url) { const widget = this.createWidget(url); const onMessage = (event) => { if (event.origin !== import_constants.PREVIEW_WIDGET_ORIGIN) { return; } switch (event.data.type) { case "croct:preview:leave": { this.tokenStore.setToken(null); const exitUrl = new URL(window.location.href); exitUrl.searchParams.set(PREVIEW_PARAMETER, PREVIEW_EXIT); window.location.replace(exitUrl.toString()); break; } case "croct:preview:resize": widget.style.width = `${event.data.width}px`; widget.style.height = `${event.data.height}px`; break; } }; window.addEventListener("message", onMessage); this.cleanUp.push(() => window.removeEventListener("message", onMessage)); const insert = () => { const container = document.body; container.prepend(widget); this.cleanUp.push(() => container.removeChild(widget)); this.logger.debug("Preview widget mounted."); const observer = new MutationObserver(() => { if (!container.contains(widget)) { container.prepend(widget); this.logger.debug("Preview widget removed from DOM, reinserting."); } }); observer.observe(container, { childList: true }); this.cleanUp.unshift(() => observer.disconnect()); }; if (document.readyState !== "loading") { insert(); } else { this.logger.debug("Waiting for document to be ready."); this.cleanUp.push(() => window.removeEventListener("DOMContentLoaded", insert)); window.addEventListener("DOMContentLoaded", insert); } } updateUrl() { const url = new URL(window.location.href); if (url.searchParams.has(PREVIEW_PARAMETER)) { url.searchParams.delete(PREVIEW_PARAMETER); window.history.replaceState({}, "", url.toString()); } } createWidget(url) { const widget = document.createElement("iframe"); widget.setAttribute("src", url); widget.setAttribute("sandbox", "allow-scripts allow-same-origin"); widget.style.position = "fixed"; widget.style.width = "0px"; widget.style.height = "0px"; widget.style.right = "0"; widget.style.bottom = "0"; widget.style.border = "0"; widget.style.overflow = "hidden"; widget.style.zIndex = "2147483647"; return widget; } }; _PreviewPlugin.PREVIEW_PARAMS = { previewMode: "previewMode", experienceName: "experience", experimentName: "experiment", audienceName: "audience", variantName: "variant", locale: "locale" }; let PreviewPlugin = _PreviewPlugin; const factory = (props) => { const { sdk } = props; return new PreviewPlugin({ tokenStore: props.sdk.previewTokenStore, logger: sdk.getLogger() }); }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { PreviewPlugin, factory });