@hot-labs/near-connect
Version:

328 lines (282 loc) • 10.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const nearConnectStatic_1 = require("../nearConnectStatic");
async function getIframeCode(args) {
const storage = await args.executor.getAllStorage();
const providers = args.executor.connector.providers;
const manifest = args.executor.manifest;
const uuid = args.id;
const code = args.code
.replaceAll(".localStorage", ".sandboxedLocalStorage")
.replaceAll("window.top", "window.selector")
.replaceAll("window.open", "window.selector.open");
const nonceAttr = args.cspNonce ? ` nonce="${args.cspNonce.replace(/[^A-Za-z0-9+/=]/g, "")}"` : "";
return /* html */ `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="root"></div>
<style>
:root {
--background-color: rgb(40, 40, 40);
--text-color: rgb(255, 255, 255);
--border-color: rgb(209, 209, 209);
}
* {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif
}
body, html {
box-sizing: border-box;
margin: 0;
padding: 0;
background-color: var(--background-color);
color: var(--text-color);
}
#root {
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;
background: radial-gradient(circle at center, #2c2c2c 0%, #1a1a1a 100%);
text-align: center;
}
#root * {
box-sizing: border-box;
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
color-scheme: light dark;
color: rgb(255, 255, 255);
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
}
.prompt-container img {
width: 100px;
height: 100px;
object-fit: cover;
border-radius: 12px;
}
.prompt-container h1 {
margin: 0;
font-size: 24px;
font-weight: 600;
margin-top: 16px;
}
.prompt-container p {
margin: 0;
font-size: 16px;
font-weight: 500;
color: rgb(209, 209, 209);
}
.prompt-container button {
background-color: #131313;
border: none;
border-radius: 12px;
padding: 12px 24px;
cursor: pointer;
transition: border-color 0.25s;
color: #fff;
outline: none;
font-size: 14px;
font-weight: 500;
font-family: inherit;
margin-top: 16px;
}
</style>
<script${nonceAttr}>
window.sandboxedLocalStorage = (() => {
let storage = ${JSON.stringify(storage)}
return {
setItem: function(key, value) {
window.selector.storage.set(key, value)
storage[key] = value || '';
},
getItem: function(key) {
return key in storage ? storage[key] : null;
},
removeItem: function(key) {
window.selector.storage.remove(key)
delete storage[key];
},
get length() {
return Object.keys(storage).length;
},
key: function(i) {
const keys = Object.keys(storage);
return keys[i] || null;
},
};
})();
const showPrompt = async (args) => {
const root = document.getElementById("root");
root.style.display = "flex";
root.innerHTML = \`
<div class="prompt-container">
<img src="${manifest.icon}" />
<h1>${manifest.name}</h1>
<p>\${args.title}</p>
<button>\${args.button}</button>
</div>
\`;
return new Promise((resolve) => {
root.querySelector("button")?.addEventListener("click", () => {
root.innerHTML = "";
resolve(true);
});
});
}
class ProxyWindow {
constructor(url, features) {
this.closed = false;
this.windowIdPromise = window.selector.call("open", { url, features });
window.addEventListener("message", async (event) => {
if (event.data.origin !== "${uuid}") return;
if (!event.data.method?.startsWith("proxy-window:")) return;
const method = event.data.method.replace("proxy-window:", "");
if (method === "closed" && event.data.windowId === await this.id()) this.closed = true;
});
}
async id() {
return await this.windowIdPromise;
}
async focus() {
await window.selector.call("panel.focus", { windowId: await this.id() });
}
async postMessage(data) {
window.selector.call("panel.postMessage", { windowId: await this.id(), data });
}
async close() {
await window.selector.call("panel.close", { windowId: await this.id() });
}
}
window.selector = {
wallet: null,
location: "${window.location.href}",
nearConnectVersion: "${nearConnectStatic_1.NEAR_CONNECT_VERSION}",
outerHeight: ${window.outerHeight},
screenY: ${window.screenY},
outerWidth: ${window.outerWidth},
screenX: ${window.screenX},
providers: {
mainnet: ${JSON.stringify(providers.mainnet)},
testnet: ${JSON.stringify(providers.testnet)},
},
uuid() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
const r = (Math.random() * 16) | 0;
const v = c === "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
},
walletConnect: {
connect(params) {
return window.selector.call("walletConnect.connect", params);
},
disconnect(params) {
return window.selector.call("walletConnect.disconnect", params);
},
request(params) {
return window.selector.call("walletConnect.request", params);
},
getProjectId() {
return window.selector.call("walletConnect.getProjectId", {});
},
getSession() {
return window.selector.call("walletConnect.getSession", {});
},
},
async ready(wallet) {
wallet.manifest = ${JSON.stringify(manifest)};
window.parent.postMessage({ method: "wallet-ready", origin: "${uuid}" }, "*");
window.selector.wallet = wallet;
},
async call(method, params) {
const id = window.selector.uuid();
window.parent.postMessage({ method, params, id, origin: "${uuid}" }, "*");
return new Promise((resolve, reject) => {
const handler = (event) => {
if (event.data.id !== id || event.data.origin !== "${uuid}") return;
window.removeEventListener("message", handler);
if (event.data.status === "failed") reject(event.data.result);
else resolve(event.data.result);
};
window.addEventListener("message", handler);
});
},
panelClosed(windowId) {
window.parent.postMessage({
method: "panel.closed",
origin: "${uuid}",
result: { windowId }
}, "*");
},
open(url, _, params) {
return new ProxyWindow(url, params)
},
external(entity, key, ...args) {
return window.selector.call("external", { entity, key, args: args || [] });
},
openNativeApp(url) {
return window.selector.call("open.nativeApp", { url });
},
ui: {
async whenApprove(options) {
window.selector.ui.showIframe();
await showPrompt(options);
window.selector.ui.hideIframe();
},
async showIframe() {
return await window.selector.call("ui.showIframe");
},
async hideIframe() {
return await window.selector.call("ui.hideIframe");
},
},
storage: {
async set(key, value) {
await window.selector.call("storage.set", { key, value });
},
async get(key) {
return await window.selector.call("storage.get", { key });
},
async remove(key) {
await window.selector.call("storage.remove", { key });
},
async keys() {
return await window.selector.call("storage.keys", {});
},
},
};
window.addEventListener("message", async (event) => {
if (event.data.origin !== "${uuid}") return;
if (!event.data.method?.startsWith("wallet:")) return;
const wallet = window.selector.wallet;
const method = event.data.method.replace("wallet:", "");
const payload = { id: event.data.id, origin: "${uuid}", method };
if (wallet == null || typeof wallet[method] !== "function") {
const data = { ...payload, status: "failed", result: "Method not found" };
window.parent.postMessage(data, "*");
return;
}
try {
const result = await wallet[method](event.data.params);
window.parent.postMessage({ ...payload, status: "success", result }, "*");
} catch (error) {
const data = { ...payload, status: "failed", result: error };
window.parent.postMessage(data, "*");
}
});
</script>
<script type="module"${nonceAttr}>${code}</script>
</body>
</html>
`;
}
exports.default = getIframeCode;
//# sourceMappingURL=code.js.map