zksync-sso
Version:
ZKsync Smart Sign On SDK
161 lines • 6.17 kB
JavaScript
import { standardErrors } from "../errors/index.js";
export class PopupCommunicator {
constructor(url, options) {
Object.defineProperty(this, "url", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "popup", {
enumerable: true,
configurable: true,
writable: true,
value: null
});
Object.defineProperty(this, "listeners", {
enumerable: true,
configurable: true,
writable: true,
value: new Map()
});
Object.defineProperty(this, "width", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "height", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "calculatePosition", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "postMessage", {
enumerable: true,
configurable: true,
writable: true,
value: async (message) => {
const popup = await this.waitForPopupLoaded();
popup.postMessage(message, this.url.origin);
}
});
Object.defineProperty(this, "postRequestAndWaitForResponse", {
enumerable: true,
configurable: true,
writable: true,
value: async (request) => {
const responsePromise = this.onMessage(({ requestId }) => requestId === request.id);
this.postMessage(request);
return await responsePromise;
}
});
Object.defineProperty(this, "onMessage", {
enumerable: true,
configurable: true,
writable: true,
value: async (predicate) => {
return new Promise((resolve, reject) => {
const listener = (event) => {
if (event.origin !== this.url.origin)
return; // origin validation
const message = event.data;
if (predicate(message)) {
resolve(message);
window.removeEventListener("message", listener);
this.listeners.delete(listener);
}
};
window.addEventListener("message", listener);
this.listeners.set(listener, { reject });
});
}
});
Object.defineProperty(this, "disconnect", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
// Note: Auth Server popup handles closing itself. this is a fallback.
try {
if (this.popup && !this.popup.closed) {
this.popup.close();
}
}
catch (error) {
console.warn("Failed to close popup", error);
}
this.popup = null;
this.listeners.forEach(({ reject }, listener) => {
reject(standardErrors.provider.userRejectedRequest("Request rejected"));
window.removeEventListener("message", listener);
});
this.listeners.clear();
}
});
Object.defineProperty(this, "openPopup", {
enumerable: true,
configurable: true,
writable: true,
value: () => {
const width = this.width;
const height = this.height;
const url = new URL(this.url.toString());
url.searchParams.set("origin", window.location.origin);
const { left, top } = this.calculatePosition
? this.calculatePosition(width, height)
: {
left: (window.innerWidth - width) / 2 + window.screenX,
top: (window.innerHeight - height) / 2 + window.screenY,
};
const popup = window.open(url, "ZKsync SSO", `width=${width}, height=${height}, left=${left}, top=${top}`);
if (!popup) {
throw standardErrors.rpc.internal("Pop up window failed to open");
}
popup.focus();
return popup;
}
});
Object.defineProperty(this, "waitForPopupLoaded", {
enumerable: true,
configurable: true,
writable: true,
value: async () => {
if (this.popup && !this.popup.closed) {
// Focus the popup if it's already open
this.popup.focus();
return this.popup;
}
this.popup = this.openPopup();
this.onMessage(({ event }) => event === "PopupUnload")
.then(this.disconnect)
.catch(() => { });
return this.onMessage(({ event }) => event === "PopupLoaded")
.then(() => {
if (!this.popup)
throw standardErrors.rpc.internal();
return this.popup;
});
}
});
Object.defineProperty(this, "ready", {
enumerable: true,
configurable: true,
writable: true,
value: async () => {
await this.waitForPopupLoaded();
}
});
this.url = new URL(url);
this.width = options?.width ?? 420;
this.height = options?.height ?? 600;
this.calculatePosition = options?.calculatePosition;
}
}
//# sourceMappingURL=PopupCommunicator.js.map