@croct/plug
Version:
A fully-featured devkit for building natively personalized applications.
143 lines (142 loc) • 4.79 kB
JavaScript
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
};