UNPKG

@joyid/common

Version:
643 lines (628 loc) 18.7 kB
// src/utils/errors.ts var DappErrorName = /* @__PURE__ */ ((DappErrorName2) => { DappErrorName2["DecodeError"] = "Decode Error"; DappErrorName2["InvalidParams"] = "Invalid Params"; DappErrorName2["UserRejected"] = "User Rejected"; DappErrorName2["NotAllowed"] = "Not Allowed"; return DappErrorName2; })(DappErrorName || {}); var DappError = class extends Error { constructor(message, name = "Invalid Params" /* InvalidParams */, rawError = void 0) { super(message); this.name = message === "User Rejected" /* UserRejected */ ? message : name; this.rawError = rawError; } }; // src/utils/qss.ts function encode(obj, pfx) { let k; let i; let tmp; let str = ""; for (k in obj) { if ((tmp = obj[k]) !== void 0) { if (Array.isArray(tmp)) { for (i = 0; i < tmp.length; i++) { str && (str += "&"); str += `${encodeURIComponent(k)}=${encodeURIComponent(tmp[i])}`; } } else { str && (str += "&"); str += `${encodeURIComponent(k)}=${encodeURIComponent(tmp)}`; } } } return (pfx || "") + str; } function toValue(mix) { if (!mix) return ""; const str = decodeURIComponent(mix); if (str === "false") return false; if (str === "true") return true; return +str * 0 === 0 && `${+str}` === str ? +str : str; } function decode(str) { let tmp; let k; const out = {}; const arr = str.split("&"); while (tmp = arr.shift()) { tmp = tmp.split("="); k = tmp.shift(); if (out[k] !== void 0) { out[k] = [].concat(out[k], toValue(tmp.shift())); } else { out[k] = toValue(tmp.shift()); } } return out; } // src/utils/search-params.ts function parseSearchWith(parser) { return (searchStr) => { if (searchStr.substring(0, 1) === "?") { searchStr = searchStr.substring(1); } const query = decode(searchStr); for (const key in query) { const value = query[key]; if (typeof value === "string") { try { query[key] = parser(value); } catch (err) { } } } if (Object.keys(query).length === 0) { throw new DappError("Invalid request", "Invalid Params" /* InvalidParams */); } return query; }; } function stringifySearchWith(stringify, parser) { function stringifyValue(val) { if (typeof val === "object" && val !== null) { try { return stringify(val); } catch (err) { } } else if (typeof val === "string" && typeof parser === "function") { try { parser(val); return stringify(val); } catch (err) { } } return val; } return (search) => { search = { ...search }; if (search) { Object.keys(search).forEach((key) => { const val = search[key]; if (typeof val === "undefined" || val === void 0) { delete search[key]; } else { search[key] = stringifyValue(val); } }); } const searchStr = encode(search).toString(); return searchStr ? `?${searchStr}` : ""; }; } var decodeSearch = parseSearchWith(JSON.parse); var encodeSearch = stringifySearchWith(JSON.stringify, JSON.parse); // src/utils/func.ts var safeExec = (fn) => { try { return fn(); } catch (error) { return null; } }; // src/utils/buffer.ts function base64URLStringToBuffer(base64URLString) { const base64 = base64URLString.replace(/-/g, "+").replace(/_/g, "/"); const padLength = (4 - base64.length % 4) % 4; const padded = base64.padEnd(base64.length + padLength, "="); const binary = atob(padded); const buffer = new ArrayBuffer(binary.length); const bytes = new Uint8Array(buffer); for (let i = 0; i < binary.length; i++) { bytes[i] = binary.charCodeAt(i); } return buffer; } function bufferToBase64URLString(buffer) { const bytes = new Uint8Array(buffer); let str = ""; for (let i = 0; i < bytes.length; i++) { const charCode = bytes[i]; if (charCode != null) { str += String.fromCharCode(charCode); } } const base64String = btoa(str); return base64String.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); } function hexToArrayBuffer(input) { const view = new Uint8Array(input.length / 2); for (let i = 0; i < input.length; i += 2) { view[i / 2] = Number.parseInt(input.substring(i, i + 2), 16); } return view.buffer; } function bufferToHex(buffer) { return [...new Uint8Array(buffer)].map((b) => b.toString(16).padStart(2, "0")).join(""); } function appendBuffer(buffer1, buffer2) { const tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); tmp.set(new Uint8Array(buffer1), 0); tmp.set(new Uint8Array(buffer2), buffer1.byteLength); return tmp.buffer; } function bufferToUTF8String(value) { return new TextDecoder("utf-8").decode(value); } function utf8StringToBuffer(value) { return new TextEncoder().encode(value); } function hexToUTF8String(value) { return bufferToUTF8String(hexToArrayBuffer(value)); } function remove0x(hex) { return hex.startsWith("0x") ? hex.slice(2) : hex; } function append0x(hex) { return hex.startsWith("0x") ? hex : `0x${hex}`; } function hexToString(hex) { let str = ""; for (let i = 0; i < hex.length; i += 2) str += String.fromCharCode(Number.parseInt(hex.substr(i, 2), 16)); return str; } function base64urlToHex(s) { return bufferToHex(base64URLStringToBuffer(s)); } // src/utils/browser.ts function isStandaloneBrowser() { return window.matchMedia("(display-mode: standalone)").matches || window.navigator.standalone; } // src/types/dapp.ts var SigningAlg = /* @__PURE__ */ ((SigningAlg2) => { SigningAlg2[SigningAlg2["RS256"] = -257] = "RS256"; SigningAlg2[SigningAlg2["ES256"] = -7] = "ES256"; return SigningAlg2; })(SigningAlg || {}); var DappRequestType = /* @__PURE__ */ ((DappRequestType2) => { DappRequestType2["Auth"] = "Auth"; DappRequestType2["SignMessage"] = "SignMessage"; DappRequestType2["SignEvm"] = "SignEvm"; DappRequestType2["SignPsbt"] = "SignPsbt"; DappRequestType2["BatchSignPsbt"] = "BatchSignPsbt"; DappRequestType2["SignCkbTx"] = "SignCkbTx"; DappRequestType2["SignCotaNFT"] = "SignCotaNFT"; DappRequestType2["SignCkbRawTx"] = "SignCkbRawTx"; DappRequestType2["SignNostrEvent"] = "SignNostrEvent"; DappRequestType2["EncryptNostrMessage"] = "EncryptNostrMessage"; DappRequestType2["EvmWeb2Login"] = "EvmWeb2Login"; DappRequestType2["DecryptNostrMessage"] = "DecryptNostrMessage"; DappRequestType2["AuthMiniApp"] = "AuthMiniApp"; DappRequestType2["SignMiniAppMessage"] = "SignMiniAppMessage"; DappRequestType2["SignMiniAppEvm"] = "SignMiniAppEvm"; return DappRequestType2; })(DappRequestType || {}); var DappCommunicationType = /* @__PURE__ */ ((DappCommunicationType2) => { DappCommunicationType2["Popup"] = "popup"; DappCommunicationType2["Redirect"] = "redirect"; return DappCommunicationType2; })(DappCommunicationType || {}); var SESSION_KEY_VER = "00"; // src/types/nostr.ts var EventKind = /* @__PURE__ */ ((EventKind2) => { EventKind2[EventKind2["Metadata"] = 0] = "Metadata"; EventKind2[EventKind2["Text"] = 1] = "Text"; EventKind2[EventKind2["RecommendRelay"] = 2] = "RecommendRelay"; EventKind2[EventKind2["Contacts"] = 3] = "Contacts"; EventKind2[EventKind2["EncryptedDirectMessage"] = 4] = "EncryptedDirectMessage"; EventKind2[EventKind2["EventDeletion"] = 5] = "EventDeletion"; EventKind2[EventKind2["Repost"] = 6] = "Repost"; EventKind2[EventKind2["Reaction"] = 7] = "Reaction"; EventKind2[EventKind2["BadgeAward"] = 8] = "BadgeAward"; EventKind2[EventKind2["ChannelCreation"] = 40] = "ChannelCreation"; EventKind2[EventKind2["ChannelMetadata"] = 41] = "ChannelMetadata"; EventKind2[EventKind2["ChannelMessage"] = 42] = "ChannelMessage"; EventKind2[EventKind2["ChannelHideMessage"] = 43] = "ChannelHideMessage"; EventKind2[EventKind2["ChannelMuteUser"] = 44] = "ChannelMuteUser"; EventKind2[EventKind2["Blank"] = 255] = "Blank"; EventKind2[EventKind2["Report"] = 1984] = "Report"; EventKind2[EventKind2["ZapRequest"] = 9734] = "ZapRequest"; EventKind2[EventKind2["Zap"] = 9735] = "Zap"; EventKind2[EventKind2["RelayList"] = 10002] = "RelayList"; EventKind2[EventKind2["ClientAuth"] = 22242] = "ClientAuth"; EventKind2[EventKind2["HttpAuth"] = 27235] = "HttpAuth"; EventKind2[EventKind2["ProfileBadge"] = 30008] = "ProfileBadge"; EventKind2[EventKind2["BadgeDefinition"] = 30009] = "BadgeDefinition"; EventKind2[EventKind2["Article"] = 30023] = "Article"; return EventKind2; })(EventKind || {}); // src/sdk/config.ts var internalConfig = { joyidAppURL: "https://testnet.joyid.dev" }; var initConfig = (config) => { Object.assign(internalConfig, config); return internalConfig; }; var getConfig = () => internalConfig; // src/sdk/errors.ts var GenericError = class _GenericError extends Error { constructor(error, error_description) { super(error_description); this.error = error; this.error_description = error_description; Object.setPrototypeOf(this, _GenericError.prototype); } }; var TimeoutError = class _TimeoutError extends GenericError { constructor() { super("timeout", "Timeout"); Object.setPrototypeOf(this, _TimeoutError.prototype); } }; var PopupTimeoutError = class _PopupTimeoutError extends TimeoutError { constructor(popup) { super(); this.popup = popup; Object.setPrototypeOf(this, _PopupTimeoutError.prototype); } }; var PopupCancelledError = class _PopupCancelledError extends GenericError { constructor(popup) { super("cancelled", "Popup closed"); this.popup = popup; Object.setPrototypeOf(this, _PopupCancelledError.prototype); } }; var PopupNotSupportedError = class extends GenericError { constructor(popup) { super( "NotSupported", "Popup window is blocked by browser. see: https://docs.joy.id/guide/best-practice#popup-window-blocked" ); this.popup = popup; Object.setPrototypeOf(this, PopupCancelledError.prototype); } }; var RedirectErrorWithState = class extends Error { constructor(message, state) { super(message); this.message = message; this.state = state; this.state = state; } }; // src/sdk/url.ts var JOYID_REDIRECT = "joyid-redirect"; var getRedirectResponse = (uri) => { const url = new URL(uri ?? window.location.href); const data = url.searchParams.get("_data_"); if (data == null) { throw new Error("No data found"); } const res = decodeSearch(data); if (res.error != null) { throw new RedirectErrorWithState(res.error, res.state); } return res.data; }; var buildJoyIDURL = (request, type, path) => { const joyidURL = request.joyidAppURL ?? getConfig().joyidAppURL; const url = new URL(`${joyidURL}`); url.pathname = path; let redirectTo = request.redirectURL; if (type === "redirect") { const redirectURL = new URL(redirectTo); redirectURL.searchParams.set(JOYID_REDIRECT, "true"); redirectTo = redirectURL.href; } url.searchParams.set("type", type); const data = encodeSearch({ ...request, redirectURL: redirectTo }); url.searchParams.set("_data_", data); return url.href; }; var isRedirectFromJoyID = (uri) => { try { const url = new URL(uri ?? window.location.href); return url.searchParams.has(JOYID_REDIRECT); } catch (error) { return false; } }; // src/sdk/popup.ts var DEFAULT_AUTHORIZE_TIMEOUT_IN_SECONDS = 3e3; var openPopup = (url = "") => { const width = 400; const height = 600; const left = window.screenX + (window.innerWidth - width) / 2; const top = window.screenY + (window.innerHeight - height) / 2; return window.open( url, "joyid:authorize:popup", `left=${left},top=${top},width=${width},height=${height},resizable,scrollbars=yes,status=1` ); }; var runPopup = async (config) => new Promise((resolve, reject) => { if (isStandaloneBrowser()) { reject(new PopupNotSupportedError(config.popup)); } let popupEventListener; let timeoutId; const popupTimer = setInterval(() => { if (config.popup?.closed) { clearInterval(popupTimer); clearTimeout(timeoutId); window.removeEventListener("message", popupEventListener, false); reject(new PopupCancelledError(config.popup)); } }, 1e3); timeoutId = setTimeout( () => { clearInterval(popupTimer); reject(new PopupTimeoutError(config.popup)); window.removeEventListener("message", popupEventListener, false); }, (config.timeoutInSeconds ?? DEFAULT_AUTHORIZE_TIMEOUT_IN_SECONDS) * 1e3 ); popupEventListener = (e) => { const joyidAppURL = config.joyidAppURL ?? getConfig().joyidAppURL; if (joyidAppURL == null) { throw new Error("joyidAppURL is not set in the config"); } const appURL = new URL(joyidAppURL); if (e.origin !== appURL.origin) { return; } if (!e.data || e.data?.type !== config.type) { return; } clearTimeout(timeoutId); clearInterval(popupTimer); window.removeEventListener("message", popupEventListener, false); config.popup.close(); if (e.data.error) { reject(new Error(e.data.error)); } resolve(e.data.data); }; window.addEventListener("message", popupEventListener); }); // src/sdk/block-dialog.ts var styleId = "joyid-block-dialog-style"; var approveId = "joyid-block-dialog-approve"; var rejectId = "joyid-block-dialog-reject"; var styleSheet = ` .joyid-block-dialog { position: fixed; top: 32px; left: 50%; width: 340px; margin-left: -170px; background: white; color: #333; display: flex; flex-flow: row nowrap; justify-content: space-between; align-items: center; height: 110px; z-index: 100002; box-sizing: border-box; border: 1px solid #ffffff; border-radius: 8px; padding: 16px 20px; } .joyid-block-dialog-bg { width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); position: fixed; top: 0; left: 0; display: none; z-index: 100001; display: block; } .joyid-block-dialog-title { font-weight: bold; font-size: 14px; margin-bottom: 8px; } .joyid-block-dialog-tip { font-size: 12px; color: #777; } .joyid-block-dialog-btn { width: 90px; height: 35px; font-size: 12px; text-align: center; border-radius: 6px; cursor: pointer; } .joyid-block-dialog-action { text-align: right; } #${approveId} { border: 1px solid #333; color: #333; background: #D2FF00; margin-bottom: 8px; } #${rejectId} { background: transparent; } `; var dialogInnerHtml = ` <div class="joyid-block-dialog"> <div class="joyid-block-dialog-content"> <div class="joyid-block-dialog-title"> Request Pop-up </div> <div class="joyid-block-dialog-tip"> Click Approve to complete creating or using wallet </div> </div> <div class="joyid-block-dialog-action"> <button class="joyid-block-dialog-btn" id="${approveId}">Approve</button> <button class="joyid-block-dialog-btn" id="${rejectId}">Reject</button> </div> </div> `; var appendStyle = () => { const _style = document.getElementById(styleId); if (_style != null) { return; } const style = document.createElement("style"); style.appendChild(document.createTextNode(styleSheet)); const head = document.head ?? document.getElementsByTagName("head")[0]; head.appendChild(style); }; var createBlockDialog = async (cb) => { appendStyle(); const dialog = document.createElement("div"); dialog.innerHTML = dialogInnerHtml; document.body.appendChild(dialog); const dialogBg = document.createElement("div"); dialogBg.className = "joyid-block-dialog-bg"; document.body.appendChild(dialogBg); const approveBtn = document.getElementById(approveId); const rejectBtn = document.getElementById(rejectId); const closeDialog = () => { document.body.removeChild(dialog); document.body.removeChild(dialogBg); }; return new Promise((resolve, reject) => { approveBtn?.addEventListener("click", async () => { try { const data = await cb(); closeDialog(); resolve(data); } catch (error) { closeDialog(); reject(error); } }); rejectBtn?.addEventListener("click", () => { closeDialog(); reject(new Error("User Rejected")); }); }); }; // src/sdk/auth.ts var buildJoyIDAuthURL = (request, type) => buildJoyIDURL(request, type, "/auth"); var authWithRedirect = (request) => { window.location.assign(buildJoyIDAuthURL(request, "redirect")); }; var authWithPopup = async (request, config) => { config = config ?? {}; if (config.popup == null) { config.popup = openPopup(""); if (config.popup == null) { return createBlockDialog(async () => authWithPopup(request, config)); } } config.popup.location.href = buildJoyIDAuthURL( request, "popup" /* Popup */ ); return runPopup({ ...request, ...config, type: "Auth" /* Auth */ }); }; var authCallback = (uri) => getRedirectResponse(uri); // src/sdk/sign-messge.ts var buildJoyIDSignMessageURL = (request, type) => buildJoyIDURL(request, type, "/sign-message"); var signMessageWithRedirect = (request) => { window.location.assign(buildJoyIDSignMessageURL(request, "redirect")); }; var signMessageWithPopup = async (request, config) => { config = config ?? {}; if (config.popup == null) { config.popup = openPopup(""); if (config.popup == null) { return createBlockDialog( async () => signMessageWithPopup(request, config) ); } } config.popup.location.href = buildJoyIDSignMessageURL(request, "popup"); return runPopup({ ...request, ...config, type: "SignMessage" /* SignMessage */ }); }; var signMessageCallback = (uri) => getRedirectResponse(uri); export { DappCommunicationType, DappError, DappErrorName, DappRequestType, EventKind, GenericError, PopupCancelledError, PopupNotSupportedError, PopupTimeoutError, RedirectErrorWithState, SESSION_KEY_VER, SigningAlg, TimeoutError, append0x, appendBuffer, appendStyle, authCallback, authWithPopup, authWithRedirect, base64URLStringToBuffer, base64urlToHex, bufferToBase64URLString, bufferToHex, bufferToUTF8String, buildJoyIDAuthURL, buildJoyIDSignMessageURL, buildJoyIDURL, createBlockDialog, decodeSearch, encodeSearch, getConfig, getRedirectResponse, hexToArrayBuffer, hexToString, hexToUTF8String, initConfig, internalConfig, isRedirectFromJoyID, isStandaloneBrowser, openPopup, parseSearchWith, remove0x, runPopup, safeExec, signMessageCallback, signMessageWithPopup, signMessageWithRedirect, stringifySearchWith, utf8StringToBuffer }; //# sourceMappingURL=index.js.map