UNPKG

@frak-labs/core-sdk

Version:

Core SDK of the Frak wallet, low level library to interact directly with the frak ecosystem.

13 lines 11.3 kB
import*as e from"@jsonjoy.com/json-pack/lib/cbor";import*as t from"viem";class n extends Error{code;data;constructor(e,t,n){super(t),this.code=e,this.data=n}}class r extends n{constructor(e){super(a.internalError,e)}}class o extends n{constructor(){super(a.clientNotConnected,"Client not found")}}let a={parseError:-32700,invalidRequest:-32600,methodNotFound:-32601,invalidParams:-32602,internalError:-32603,serverError:-32e3,clientNotConnected:-32001,configError:-32002,corruptedResponse:-32003,clientAborted:-32004,walletNotConnected:-32005,serverErrorForInteractionDelegation:-32006};class i{_promise;_resolve;_reject;constructor(){this._promise=new Promise((e,t)=>{this._resolve=e,this._reject=t})}get promise(){return this._promise}resolve=e=>{this._resolve?.(e)};reject=e=>{this._reject?.(e)}}function s(e){return btoa(Array.from(e,e=>String.fromCharCode(e)).join("")).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function c(e){let t=e.length%4;return Uint8Array.from(atob(e.replace(/-/g,"+").replace(/_/g,"/").padEnd(e.length+(0===t?0:4-t),"=")),e=>e.charCodeAt(0))}let l=new e.CborEncoder;function d(e){let t={...e,validationHash:p(e)};return l.encode(t)}function u(e){return l.encode(e)}function f(e){return s(u(e))}function p(e){return(0,t.sha256)(l.encode(e))}let h=new e.CborDecoder;function m(e){if(!e.length)throw new n(a.corruptedResponse,"Missing compressed data");let t=g(e);if(!t)throw new n(a.corruptedResponse,"Invalid compressed data");if(!t?.validationHash)throw new n(a.corruptedResponse,"Missing validation hash");let{validationHash:r,...o}=t;if(p(o)!==t.validationHash)throw new n(a.corruptedResponse,"Invalid data validation hash");return t}function g(e){try{return h.decode(e)}catch(t){return console.error("Invalid compressed data",{e:t,data:e}),null}}function w(e){return g(c(e))}let y="nexus-wallet-backup";class b{config;iframe;isSetupDone=!1;lastResponse=null;lastRequest=null;constructor(e,t){this.config=e,this.iframe=t,this.lastRequest=null,this.lastResponse=null}setLastResponse(e){this.lastResponse={event:e.data,origin:e.origin,timestamp:Date.now()}}setLastRequest(e,t){this.lastRequest={event:e,target:t,timestamp:Date.now()}}updateSetupStatus(e){this.isSetupDone=e}base64Encode(e){try{return btoa(JSON.stringify(e))}catch(e){return console.warn("Failed to encode debug data",e),btoa("Failed to encode data")}}getIframeStatus(){return this.iframe?{loading:this.iframe.hasAttribute("loading"),url:this.iframe.src,readyState:this.iframe.contentDocument?.readyState?+("complete"===this.iframe.contentDocument.readyState):-1,contentWindow:!!this.iframe.contentWindow,isConnected:this.iframe.isConnected}:null}getNavigatorInfo(){return navigator?{userAgent:navigator.userAgent,language:navigator.language,onLine:navigator.onLine,screenWidth:window.screen.width,screenHeight:window.screen.height,pixelRatio:window.devicePixelRatio}:null}gatherDebugInfo(e){let t=this.getIframeStatus(),r=this.getNavigatorInfo(),o="Unknown";return e instanceof n?o=`FrakRpcError: ${e.code} '${e.message}'`:e instanceof Error?o=e.message:"string"==typeof e&&(o=e),{timestamp:new Date().toISOString(),encodedUrl:btoa(window.location.href),encodedConfig:this.config?this.base64Encode(this.config):"no-config",navigatorInfo:r?this.base64Encode(r):"no-navigator",iframeStatus:t?this.base64Encode(t):"not-iframe",lastRequest:this.lastRequest?this.base64Encode(this.lastRequest):"No Frak request logged",lastResponse:this.lastResponse?this.base64Encode(this.lastResponse):"No Frak response logged",clientStatus:this.isSetupDone?"setup":"not-setup",error:o}}static empty(){return new b}formatDebugInfo(e){let t=this.gatherDebugInfo(e);return` Debug Information: ----------------- Timestamp: ${t.timestamp} URL: ${t.encodedUrl} Config: ${t.encodedConfig} Navigator Info: ${t.navigatorInfo} IFrame Status: ${t.iframeStatus} Last Request: ${t.lastRequest} Last Response: ${t.lastResponse} Client Status: ${t.clientStatus} Error: ${t.error} `.trim()}}let v={id:"frak-wallet",name:"frak-wallet",title:"Frak Wallet",allow:"publickey-credentials-get *; clipboard-write; web-share *",style:{width:"0",height:"0",border:"0",position:"absolute",zIndex:2000001,top:"-1000px",left:"-1000px",colorScheme:"auto"}};function C({walletBaseUrl:e,config:t}){let n=document.querySelector("#frak-wallet");n&&n.remove();let r=document.createElement("iframe");return r.id=v.id,r.name=v.name,r.allow=v.allow,r.style.zIndex=v.style.zIndex.toString(),R({iframe:r,isVisible:!1}),document.body.appendChild(r),new Promise(n=>{r?.addEventListener("load",()=>n(r)),r.src=`${t?.walletUrl??e??"https://wallet.frak.id"}/listener`})}function R({iframe:e,isVisible:t}){if(!t){e.style.width="0",e.style.height="0",e.style.border="0",e.style.position="fixed",e.style.top="-1000px",e.style.left="-1000px";return}e.style.position="fixed",e.style.top="0",e.style.left="0",e.style.width="100%",e.style.height="100%",e.style.pointerEvents="auto"}function S({config:e,iframe:t}){let o=function(){let e=new Map;return{createChannel:t=>{let n=Math.random().toString(36).substring(7);return e.set(n,t),n},getRpcResolver:t=>e.get(t),removeChannel:t=>e.delete(t),destroy:()=>e.clear()}}(),s=function({iframe:e}){let t=new i;return{handleEvent:async n=>{switch(n.iframeLifecycle){case"connected":t.resolve(!0);break;case"do-backup":n.data.backup?localStorage.setItem(y,n.data.backup):localStorage.removeItem(y);break;case"remove-backup":localStorage.removeItem(y);break;case"show":case"hide":R({iframe:e,isVisible:"show"===n.iframeLifecycle});break;case"handshake":e.contentWindow?.postMessage({clientLifecycle:"handshake-response",data:{token:n.data.token,currentUrl:window.location.href}},"*")}},isConnected:t.promise}}({iframe:t}),c=new b(e,t),l=function({frakWalletUrl:e,iframe:t,channelManager:r,iframeLifecycleManager:o,debugInfo:i}){if("undefined"==typeof window)throw new n(a.configError,"iframe client should be used in the browser");if(!t.contentWindow)throw new n(a.configError,"The iframe does not have a product window");let s=t.contentWindow;async function c(t){if(!t.origin)return;try{if(new URL(t.origin).origin.toLowerCase()!==new URL(e).origin.toLowerCase())return}catch(e){console.log("Unable to check frak msg origin",e);return}if("object"!=typeof t.data)return;if(i.setLastResponse(t),"iframeLifecycle"in t.data){await o.handleEvent(t.data);return}if("clientLifecycle"in t.data){console.error("Client lifecycle event received on the client side, dismissing it");return}let n=t.data.id,a=r.getRpcResolver(n);a&&a(t.data)}return window.addEventListener("message",c),{sendEvent:function(t){s.postMessage(t,{targetOrigin:e}),i.setLastRequest(t,e)},cleanup:function(){window.removeEventListener("message",c)}}}({frakWalletUrl:e?.walletUrl??"https://wallet.frak.id",iframe:t,channelManager:o,iframeLifecycleManager:s,debugInfo:c}),u=async e=>{if(!await s.isConnected)throw new n(a.clientNotConnected,"The iframe provider isn't connected yet");let t=new i,r=o.createChannel(e=>{let a=m(e.data);a.error?t.reject(new n(a.error.code,a.error.message,a.error?.data)):t.resolve(a.result),o.removeChannel(r)}),c=d(e);return l.sendEvent({id:r,topic:e.method,data:c}),t.promise},f=async(e,t)=>{if(!await s.isConnected)throw new n(a.clientNotConnected,"The iframe provider isn't connected yet");let i=o.createChannel(e=>{let n=m(e.data);if(n.result)t(n.result);else throw new r("No valid result in the response")}),c=d(e);l.sendEvent({id:i,topic:e.method,data:c})},p=function(e,t){let n,r;let o=()=>e.sendEvent({clientLifecycle:"heartbeat"});function a(){n&&clearInterval(n),r&&clearTimeout(r)}return async function(){o(),n=setInterval(o,100),r=setTimeout(()=>{a(),console.log("Heartbeat timeout: connection failed")},3e4),await t.isConnected,a()}(),a}(l,s),h=async()=>{p(),o.destroy(),l.cleanup(),t.remove()},g=E({config:e,messageHandler:l,lifecycleManager:s}).then(()=>c.updateSetupStatus(!0));return{config:e,debugInfo:c,waitForConnection:s.isConnected,waitForSetup:g,request:u,listenerRequest:f,destroy:h}}async function E({config:e,messageHandler:t,lifecycleManager:n}){async function r(){let n=e.customizations?.css;n&&t.sendEvent({clientLifecycle:"modal-css",data:{cssLink:n}})}async function o(){let n=e.customizations?.i18n;n&&t.sendEvent({clientLifecycle:"modal-i18n",data:{i18n:n}})}async function a(){if("undefined"==typeof window)return;let e=window.localStorage.getItem(y);e&&t.sendEvent({clientLifecycle:"restore-backup",data:{backup:e}})}await n.isConnected,await Promise.all([r(),o(),a()])}let k={eur:"fr-FR",usd:"en-US",gbp:"en-GB"};function x(e){return e&&e in k?e:"eur"}async function I({config:e}){let t=function(e){let t=x(e.metadata?.currency);return{...e,metadata:{...e.metadata,currency:t}}}(e),n=await C({config:t});if(!n){console.error("Failed to create iframe");return}let r=S({config:t,iframe:n});if(await r.waitForSetup,!await r.waitForConnection){console.error("Failed to connect to client");return}return r}let L="fCtx";function F(e){if(e?.r)try{let n=(0,t.hexToBytes)(e.r);return s(n)}catch(t){console.error("Error compressing Frak context",{e:t,context:e})}}function D(e){if(e&&0!==e.length)try{let n=c(e);return{r:(0,t.bytesToHex)(n,{size:20})}}catch(t){console.error("Error decompressing Frak context",{e:t,context:e})}}function U({url:e}){if(!e)return null;let t=new URL(e).searchParams.get(L);return t?D(t):null}function A({url:e,context:t}){if(!e)return null;let n=U({url:e}),r=n?{...n,...t}:t;if(!r.r)return null;let o=F(r);if(!o)return null;let a=new URL(e);return a.searchParams.set(L,o),a.toString()}function N(e){let t=new URL(e);return t.searchParams.delete(L),t.toString()}let $={compress:F,decompress:D,parse:U,update:A,remove:N,replaceUrl:function({url:e,context:t}){let n;if(!window.location?.href||"undefined"==typeof window){console.error("No window found, can't update context");return}let r=e??window.location.href;(n=null!==t?A({url:r,context:t}):N(r))&&window.history.replaceState(null,"",n.toString())}};function q(e){return e?k[e]??k.eur:k.eur}function T(e,t){let n=q(t),r=x(t);return e.toLocaleString(n,{style:"currency",currency:r,minimumFractionDigits:0,maximumFractionDigits:2})}function j(e){return e?`${e}Amount`:"eurAmount"}let _={dapp:1,press:2,webshop:3,retail:4,referral:30,purchase:31},M=Object.entries(_).reduce((e,[t,n])=>(e[t]=BigInt(1)<<BigInt(n),e),{}),P={press:{openArticle:"0xc0a24ffb",readArticle:"0xd5bd0fbe"},dapp:{proofVerifiableStorageUpdate:"0x2ab2aeef",callableVerifiableStorageUpdate:"0xa07da986"},webshop:{open:"0xb311798f"},referral:{referred:"0x010cc3b9",createLink:"0xb2c0f17c"},purchase:{started:"0xd87e90c3",completed:"0x8403aeb4",unsafeCompleted:"0x4d5b14e0"},retail:{customerMeeting:"0x74489004"}};export{o as ClientNotFound,b as DebugInfoGatherer,i as Deferred,$ as FrakContextManager,n as FrakRpcError,a as RpcErrorCodes,c as base64urlDecode,s as base64urlEncode,v as baseIframeProps,u as compressJson,f as compressJsonToB64,S as createIFrameFrakClient,C as createIframe,m as decompressDataAndCheckHash,g as decompressJson,w as decompressJsonFromB64,T as formatAmount,j as getCurrencyAmountKey,x as getSupportedCurrency,q as getSupportedLocale,d as hashAndCompressData,P as interactionTypes,k as locales,_ as productTypes,M as productTypesMask,I as setupClient};