UNPKG

@keyban/sdk-base

Version:

Keyban Javascript SDK provides core functionalities for the MPC wallet solution, supporting web and Node.js apps with TypeScript, custom storage, and Ethereum blockchain integration.

199 lines (197 loc) 5.79 kB
import { IFrameApiError, KeybanBaseError, SdkError } from './chunk-7H2SLR6W.js'; // src/api.ts var ApiServer = class _ApiServer { constructor() { window.addEventListener("message", this.#handleMessage); } // Forced validation of service's methods, see listener below static #definitions = { application: { getCurrent: true }, auth: { isAuthenticated: true, getUser: true, sendOtp: true, signUp: true, signIn: true, signOut: true, updateUser: true }, ecdsa: { dkg: true, sign: true, publicKey: true }, eddsa: { dkg: true, sign: true, publicKey: true }, account: { getAddress: true, getId: true }, loyalty: { getOptimisticBalance: true, getRewardTier: true, addToGoogleWallet: true, addToAppleWallet: true }, dpp: { getProduct: true, getPassport: true, claim: true, magicClaim: true }, clientShareStorage: { get: true, set: true } }; #handleMessage = async (event) => { if (!event.data.__KEYBAN_API) return; try { const originAllowed = await this.checkEventOrigin(event.origin); if (!originAllowed) throw new IFrameApiError( IFrameApiError.types.InvalidOrigin, "ApiServer" ); const { serviceName, methodName } = event.data; if (!_ApiServer.#definitions[serviceName]?.[methodName]) throw new IFrameApiError( IFrameApiError.types.InvalidCall, `ApiServer:${serviceName}.${methodName}` ); const fn = this[serviceName]?.[methodName]; if (!fn) throw new IFrameApiError( IFrameApiError.types.InvalidCall, `ApiServer:${serviceName}.${methodName}` ); const result = await fn.apply(this[serviceName], event.data.args); event.ports[0].postMessage([result, null]); } catch (error) { let err = error; if (!(err instanceof KeybanBaseError)) { console.error(error); err = new SdkError( SdkError.types.UnknownIframeApiError, "ApiServer", error ); } event.ports[0].postMessage([null, JSON.stringify(err)]); } }; static openPopup(url) { const channel = new MessageChannel(); return new Promise((resolve) => { channel.port1.onmessage = () => { channel.port1.close(); resolve(); }; const message = { type: "keyban:popup", url: url.toString() }; window.parent.postMessage(message, "*", [channel.port2]); }); } }; var ApiClient = class _ApiClient { #iframeUrl; #iframe; static #instances = /* @__PURE__ */ new Map(); static #getIframeUrl({ apiUrl, appId, network }) { const iframeUrl = new URL("/sdk-client/api", apiUrl); iframeUrl.searchParams.set("appId", appId); iframeUrl.searchParams.set("network", network); return iframeUrl; } /** * Returns a shared instance per unique iframe URL. * * @param options - API client options. * @returns ApiClient instance bound to the provided options. */ static getInstance(options) { const key = _ApiClient.#getIframeUrl(options).toString(); if (!_ApiClient.#instances.has(key)) _ApiClient.#instances.set(key, new _ApiClient(options)); return _ApiClient.#instances.get(key); } api; constructor(options) { this.#iframeUrl = _ApiClient.#getIframeUrl(options); window.addEventListener("message", this.#popupHandler); this.#iframe = new Promise((resolve, reject) => { const iframe = Object.assign(document.createElement("iframe"), { src: this.#iframeUrl, hidden: true, onload: () => resolve(iframe), onerror: reject }); document.body.appendChild(iframe); }); this.api = new Proxy({}, { // API Proxy get: (_target, serviceName) => new Proxy({}, { // Service Proxy get: (_target2, methodName) => new Proxy(() => { }, { // Method Proxy apply: (_target3, _thisArg, args) => this.#call(serviceName, methodName, args) }) }) }); } #popupHandler = async (event) => { const iframe = await this.#iframe; if (event.source !== iframe.contentWindow) return; if (typeof event.data !== "object") return; if (event.data.type != "keyban:popup") return; const width = 500; const height = 685; const left = window.screenX + (window.innerWidth - width) / 2; const top = window.screenY + (window.innerHeight - height) / 2; const popup = window.open( event.data.url, `keyban:popup`, `left=${left},top=${top},width=${width},height=${height},popup,resizable,scrollbars` ); await new Promise((resolve) => { const interval = setInterval(() => { if (!popup?.closed) return; clearInterval(interval); resolve(); }, 100); }); event.ports[0].postMessage("closed"); }; async #call(serviceName, methodName, args) { const iframe = await this.#iframe; const channel = new MessageChannel(); return await new Promise((resolve, reject) => { channel.port1.onmessage = ({ data: [result, error] }) => { channel.port1.close(); return error != null ? reject(new KeybanBaseError(JSON.parse(error))) : resolve(result); }; const message = { __KEYBAN_API: true, serviceName, methodName, args }; iframe.contentWindow?.postMessage(message, this.#iframeUrl.origin, [ channel.port2 ]); }); } }; export { ApiClient, ApiServer }; //# sourceMappingURL=chunk-5DFR5Z62.js.map //# sourceMappingURL=chunk-5DFR5Z62.js.map