@joyid/common
Version:
Shared code for JoyID SDK
643 lines (578 loc) • 21.1 kB
JavaScript
Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// 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(_nullishCoalesce(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 = _nullishCoalesce(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(_nullishCoalesce(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 (_optionalChain([config, 'access', _ => _.popup, 'optionalAccess', _2 => _2.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);
},
(_nullishCoalesce(config.timeoutInSeconds, () => ( DEFAULT_AUTHORIZE_TIMEOUT_IN_SECONDS))) * 1e3
);
popupEventListener = (e) => {
const joyidAppURL = _nullishCoalesce(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 || _optionalChain([e, 'access', _3 => _3.data, 'optionalAccess', _4 => _4.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 = _nullishCoalesce(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) => {
_optionalChain([approveBtn, 'optionalAccess', _5 => _5.addEventListener, 'call', _6 => _6("click", async () => {
try {
const data = await cb();
closeDialog();
resolve(data);
} catch (error) {
closeDialog();
reject(error);
}
})]);
_optionalChain([rejectBtn, 'optionalAccess', _7 => _7.addEventListener, 'call', _8 => _8("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 = _nullishCoalesce(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 = _nullishCoalesce(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);
exports.DappCommunicationType = DappCommunicationType; exports.DappError = DappError; exports.DappErrorName = DappErrorName; exports.DappRequestType = DappRequestType; exports.EventKind = EventKind; exports.GenericError = GenericError; exports.PopupCancelledError = PopupCancelledError; exports.PopupNotSupportedError = PopupNotSupportedError; exports.PopupTimeoutError = PopupTimeoutError; exports.RedirectErrorWithState = RedirectErrorWithState; exports.SESSION_KEY_VER = SESSION_KEY_VER; exports.SigningAlg = SigningAlg; exports.TimeoutError = TimeoutError; exports.append0x = append0x; exports.appendBuffer = appendBuffer; exports.appendStyle = appendStyle; exports.authCallback = authCallback; exports.authWithPopup = authWithPopup; exports.authWithRedirect = authWithRedirect; exports.base64URLStringToBuffer = base64URLStringToBuffer; exports.base64urlToHex = base64urlToHex; exports.bufferToBase64URLString = bufferToBase64URLString; exports.bufferToHex = bufferToHex; exports.bufferToUTF8String = bufferToUTF8String; exports.buildJoyIDAuthURL = buildJoyIDAuthURL; exports.buildJoyIDSignMessageURL = buildJoyIDSignMessageURL; exports.buildJoyIDURL = buildJoyIDURL; exports.createBlockDialog = createBlockDialog; exports.decodeSearch = decodeSearch; exports.encodeSearch = encodeSearch; exports.getConfig = getConfig; exports.getRedirectResponse = getRedirectResponse; exports.hexToArrayBuffer = hexToArrayBuffer; exports.hexToString = hexToString; exports.hexToUTF8String = hexToUTF8String; exports.initConfig = initConfig; exports.internalConfig = internalConfig; exports.isRedirectFromJoyID = isRedirectFromJoyID; exports.isStandaloneBrowser = isStandaloneBrowser; exports.openPopup = openPopup; exports.parseSearchWith = parseSearchWith; exports.remove0x = remove0x; exports.runPopup = runPopup; exports.safeExec = safeExec; exports.signMessageCallback = signMessageCallback; exports.signMessageWithPopup = signMessageWithPopup; exports.signMessageWithRedirect = signMessageWithRedirect; exports.stringifySearchWith = stringifySearchWith; exports.utf8StringToBuffer = utf8StringToBuffer;
//# sourceMappingURL=index.cjs.map
;