@frak-labs/core-sdk 0.1.1 → 0.2.0-beta.7898df5b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -0
- package/cdn/bundle.js +14 -0
- package/dist/actions.cjs +1 -1
- package/dist/actions.d.cts +3 -3
- package/dist/actions.d.ts +3 -3
- package/dist/actions.js +1 -1
- package/dist/bundle.cjs +1 -1
- package/dist/bundle.d.cts +4 -6
- package/dist/bundle.d.ts +4 -6
- package/dist/bundle.js +1 -1
- package/dist/computeLegacyProductId-CCAZvLa5.d.cts +537 -0
- package/dist/computeLegacyProductId-b5cUWdAm.d.ts +537 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +3 -4
- package/dist/index.d.ts +3 -4
- package/dist/index.js +1 -1
- package/dist/{openSso-D--Airj6.d.cts → openSso-B0g7-807.d.cts} +173 -136
- package/dist/{openSso-DsKJ4y0j.d.ts → openSso-CMzwvaCa.d.ts} +173 -136
- package/dist/setupClient-BICl5fdX.js +13 -0
- package/dist/setupClient-nl8Dhh4V.cjs +13 -0
- package/dist/siweAuthenticate-BWmI2_TN.cjs +1 -0
- package/dist/{index-d8xS4ryI.d.ts → siweAuthenticate-CVigMOxz.d.cts} +113 -92
- package/dist/{index-C6FxkWPC.d.cts → siweAuthenticate-CnCZ7mok.d.ts} +113 -92
- package/dist/siweAuthenticate-zczqxm0a.js +1 -0
- package/dist/trackEvent-CeLFVzZn.js +1 -0
- package/dist/trackEvent-Ew5r5zfI.cjs +1 -0
- package/package.json +11 -22
- package/src/actions/displayEmbeddedWallet.ts +1 -0
- package/src/actions/displayModal.test.ts +12 -11
- package/src/actions/displayModal.ts +7 -18
- package/src/actions/ensureIdentity.ts +68 -0
- package/src/actions/{getProductInformation.test.ts → getMerchantInformation.test.ts} +33 -50
- package/src/actions/getMerchantInformation.ts +16 -0
- package/src/actions/index.ts +3 -2
- package/src/actions/openSso.ts +4 -2
- package/src/actions/referral/processReferral.test.ts +117 -242
- package/src/actions/referral/processReferral.ts +134 -204
- package/src/actions/referral/referralInteraction.test.ts +4 -12
- package/src/actions/referral/referralInteraction.ts +3 -13
- package/src/actions/sendInteraction.ts +46 -22
- package/src/actions/trackPurchaseStatus.test.ts +354 -141
- package/src/actions/trackPurchaseStatus.ts +48 -11
- package/src/actions/watchWalletStatus.ts +2 -3
- package/src/actions/wrapper/modalBuilder.test.ts +0 -14
- package/src/actions/wrapper/modalBuilder.ts +3 -12
- package/src/bundle.ts +0 -1
- package/src/clients/createIFrameFrakClient.ts +10 -5
- package/src/clients/transports/iframeLifecycleManager.test.ts +163 -4
- package/src/clients/transports/iframeLifecycleManager.ts +172 -33
- package/src/constants/interactionTypes.ts +12 -41
- package/src/index.ts +27 -16
- package/src/types/config.ts +6 -0
- package/src/types/context.ts +48 -6
- package/src/types/index.ts +15 -11
- package/src/types/lifecycle/client.ts +24 -1
- package/src/types/lifecycle/iframe.ts +6 -0
- package/src/types/rpc/displayModal.ts +2 -4
- package/src/types/rpc/embedded/index.ts +2 -2
- package/src/types/rpc/interaction.ts +31 -39
- package/src/types/rpc/merchantInformation.ts +77 -0
- package/src/types/rpc/modal/index.ts +0 -4
- package/src/types/rpc/modal/login.ts +5 -1
- package/src/types/rpc/walletStatus.ts +1 -7
- package/src/types/rpc.ts +22 -30
- package/src/types/tracking.ts +31 -0
- package/src/utils/FrakContext.test.ts +270 -186
- package/src/utils/FrakContext.ts +78 -56
- package/src/utils/backendUrl.test.ts +83 -0
- package/src/utils/backendUrl.ts +62 -0
- package/src/utils/clientId.test.ts +41 -0
- package/src/utils/clientId.ts +43 -0
- package/src/utils/compression/compress.test.ts +1 -1
- package/src/utils/compression/compress.ts +2 -2
- package/src/utils/compression/decompress.test.ts +8 -4
- package/src/utils/compression/decompress.ts +2 -2
- package/src/utils/{computeProductId.ts → computeLegacyProductId.ts} +2 -2
- package/src/utils/constants.ts +5 -0
- package/src/utils/deepLinkWithFallback.test.ts +243 -0
- package/src/utils/deepLinkWithFallback.ts +103 -0
- package/src/utils/formatAmount.ts +6 -0
- package/src/utils/iframeHelper.test.ts +18 -5
- package/src/utils/iframeHelper.ts +10 -3
- package/src/utils/index.ts +16 -1
- package/src/utils/merchantId.test.ts +653 -0
- package/src/utils/merchantId.ts +143 -0
- package/src/utils/sso.ts +18 -11
- package/src/utils/trackEvent.test.ts +23 -5
- package/src/utils/trackEvent.ts +13 -0
- package/cdn/bundle.iife.js +0 -14
- package/dist/actions-B5j-i1p0.cjs +0 -1
- package/dist/actions-q090Z0oR.js +0 -1
- package/dist/index-7OZ39x1U.d.ts +0 -195
- package/dist/index-CRsQWnTs.d.cts +0 -351
- package/dist/index-Ck1hudEi.d.ts +0 -351
- package/dist/index-zDq-VlKx.d.cts +0 -195
- package/dist/interaction-DMJ3ZfaF.d.cts +0 -45
- package/dist/interaction-KX1h9a7V.d.ts +0 -45
- package/dist/interactions-DnfM3oe0.js +0 -1
- package/dist/interactions-EIXhNLf6.cjs +0 -1
- package/dist/interactions.cjs +0 -1
- package/dist/interactions.d.cts +0 -2
- package/dist/interactions.d.ts +0 -2
- package/dist/interactions.js +0 -1
- package/dist/productTypes-BUkXJKZ7.cjs +0 -1
- package/dist/productTypes-CGb1MmBF.js +0 -1
- package/dist/src-1LQ4eLq5.js +0 -13
- package/dist/src-hW71KjPN.cjs +0 -13
- package/dist/trackEvent-CHnYa85W.js +0 -1
- package/dist/trackEvent-GuQm_1Nm.cjs +0 -1
- package/src/actions/getProductInformation.ts +0 -14
- package/src/actions/openSso.test.ts +0 -407
- package/src/actions/sendInteraction.test.ts +0 -219
- package/src/constants/interactionTypes.test.ts +0 -128
- package/src/constants/productTypes.test.ts +0 -130
- package/src/constants/productTypes.ts +0 -33
- package/src/interactions/index.ts +0 -5
- package/src/interactions/pressEncoder.test.ts +0 -215
- package/src/interactions/pressEncoder.ts +0 -53
- package/src/interactions/purchaseEncoder.test.ts +0 -291
- package/src/interactions/purchaseEncoder.ts +0 -99
- package/src/interactions/referralEncoder.test.ts +0 -170
- package/src/interactions/referralEncoder.ts +0 -47
- package/src/interactions/retailEncoder.test.ts +0 -107
- package/src/interactions/retailEncoder.ts +0 -37
- package/src/interactions/webshopEncoder.test.ts +0 -56
- package/src/interactions/webshopEncoder.ts +0 -30
- package/src/types/rpc/modal/openSession.ts +0 -25
- package/src/types/rpc/productInformation.ts +0 -59
- package/src/utils/computeProductId.test.ts +0 -80
- package/src/utils/sso.test.ts +0 -361
package/dist/src-1LQ4eLq5.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import{c as e}from"./trackEvent-CHnYa85W.js";import{Deferred as t,FrakRpcError as n,RpcErrorCodes as r,createRpcClient as i,decompressJson as a}from"@frak-labs/frame-connector";import{createClientCompressionMiddleware as o}from"@frak-labs/frame-connector/middleware";import{OpenPanel as s}from"@openpanel/web";const c=`nexus-wallet-backup`;function l(e,t){if(typeof window>`u`)return;let n=new URL(window.location.href),r=n.searchParams.get(`sso`);r&&(t.then(()=>{e.sendLifecycle({clientLifecycle:`sso-redirect-complete`,data:{compressed:r}}),console.log(`[SSO URL Listener] Forwarded compressed SSO data to iframe`)}).catch(e=>{console.error(`[SSO URL Listener] Failed to forward SSO data:`,e)}),n.searchParams.delete(`sso`),window.history.replaceState({},``,n.toString()),console.log(`[SSO URL Listener] SSO parameter detected and URL cleaned`))}var u=class e{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,t){this.lastResponse={message:e,response:t,timestamp:Date.now()}}setLastRequest(e){this.lastRequest={event:e,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?this.iframe.contentDocument.readyState===`complete`?1:0:-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(),i=`Unknown`;return e instanceof n?i=`FrakRpcError: ${e.code} '${e.message}'`:e instanceof Error?i=e.message:typeof e==`string`&&(i=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:i}}static empty(){return new e}formatDebugInfo(e){let t=this.gatherDebugInfo(e);return`
|
|
2
|
-
Debug Information:
|
|
3
|
-
-----------------
|
|
4
|
-
Timestamp: ${t.timestamp}
|
|
5
|
-
URL: ${t.encodedUrl}
|
|
6
|
-
Config: ${t.encodedConfig}
|
|
7
|
-
Navigator Info: ${t.navigatorInfo}
|
|
8
|
-
IFrame Status: ${t.iframeStatus}
|
|
9
|
-
Last Request: ${t.lastRequest}
|
|
10
|
-
Last Response: ${t.lastResponse}
|
|
11
|
-
Client Status: ${t.clientStatus}
|
|
12
|
-
Error: ${t.error}
|
|
13
|
-
`.trim()}};const d={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 f({walletBaseUrl:e,config:t}){let n=document.querySelector(`#frak-wallet`);n&&n.remove();let r=document.createElement(`iframe`);return r.id=d.id,r.name=d.name,r.allow=d.allow,r.style.zIndex=d.style.zIndex.toString(),p({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 p({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 m(e=`/listener`){if(!window.opener)return null;let t=t=>{try{return t.location.origin===window.location.origin&&t.location.pathname===e}catch{return!1}};if(t(window.opener))return window.opener;try{let e=window.opener.frames;for(let n=0;n<e.length;n++)if(t(e[n]))return e[n];return null}catch(t){return console.error(`[findIframeInOpener] Error finding iframe with pathname ${e}:`,t),null}}function h({iframe:e}){let n=new t;return{handleEvent:async t=>{if(!(`iframeLifecycle`in t))return;let{iframeLifecycle:r,data:i}=t;switch(r){case`connected`:n.resolve(!0);break;case`do-backup`:i.backup?localStorage.setItem(c,i.backup):localStorage.removeItem(c);break;case`remove-backup`:localStorage.removeItem(c);break;case`show`:case`hide`:p({iframe:e,isVisible:r===`show`});break;case`handshake`:e.contentWindow?.postMessage({clientLifecycle:`handshake-response`,data:{token:i.token,currentUrl:window.location.href}},`*`);break;case`redirect`:{let e=new URL(i.baseRedirectUrl);e.searchParams.has(`u`)?(e.searchParams.delete(`u`),e.searchParams.append(`u`,window.location.href),window.location.href=e.toString()):window.location.href=i.baseRedirectUrl;break}}},isConnected:n.promise}}function g({config:e,iframe:t}){let a=e?.walletUrl??`https://wallet.frak.id`,c=h({iframe:t}),l=new u(e,t);if(!t.contentWindow)throw new n(r.configError,`The iframe does not have a content window`);let d=i({emittingTransport:t.contentWindow,listeningTransport:window,targetOrigin:a,middleware:[{async onRequest(e,t){if(!await c.isConnected)throw new n(r.clientNotConnected,`The iframe provider isn't connected yet`);return t}},o(),{onRequest(e,t){return l.setLastRequest(e),t},onResponse(e,t){return l.setLastResponse(e,t),t}}],lifecycleHandlers:{iframeLifecycle:async(e,t)=>{await c.handleEvent(e)}}}),f=_(d,c),p=async()=>{f(),d.cleanup(),t.remove()},m;console.log(`[Frak SDK] Initializing OpenPanel`),m=new s({apiUrl:`https://op-api.gcp.frak.id`,clientId:`f305d11d-b93b-487c-80d4-92deb7903e98`,trackScreenViews:!0,trackOutgoingLinks:!0,trackAttributes:!1,filter:({type:e,payload:t})=>(e!==`track`||!t?.properties||`sdkVersion`in t.properties||(t.properties={...t.properties,sdkVersion:`0.1.1`}),!0)}),m.setGlobalProperties({sdkVersion:`0.1.1`}),m.init();let g=v({config:e,rpcClient:d,lifecycleManager:c}).then(()=>l.updateSetupStatus(!0));return{config:e,debugInfo:l,waitForConnection:c.isConnected,waitForSetup:g,request:d.request,listenerRequest:d.listen,destroy:p,openPanel:m}}function _(e,t){let n,r,i=()=>e.sendLifecycle({clientLifecycle:`heartbeat`});async function a(){i(),n=setInterval(i,1e3),r=setTimeout(()=>{o(),console.log(`Heartbeat timeout: connection failed`)},3e4),await t.isConnected,o()}function o(){n&&clearInterval(n),r&&clearTimeout(r)}return a(),o}async function v({config:e,rpcClient:t,lifecycleManager:n}){await n.isConnected,l(t,n.isConnected);async function r(){let n=e.customizations?.css;if(!n)return;let r={clientLifecycle:`modal-css`,data:{cssLink:n}};t.sendLifecycle(r)}async function i(){let n=e.customizations?.i18n;if(!n)return;let r={clientLifecycle:`modal-i18n`,data:{i18n:n}};t.sendLifecycle(r)}async function a(){if(typeof window>`u`)return;let e=window.localStorage.getItem(c);if(!e)return;let n={clientLifecycle:`restore-backup`,data:{backup:e}};t.sendLifecycle(n)}await Promise.allSettled([r(),i(),a()])}function y(t){return a(e(t))}const b={eur:`fr-FR`,usd:`en-US`,gbp:`en-GB`};function x(e){return e&&e in b?e:`eur`}function S(e){return e?b[e]??b.eur:b.eur}function C(e,t){let n=S(t),r=x(t);return e.toLocaleString(n,{style:`currency`,currency:r,minimumFractionDigits:0,maximumFractionDigits:2})}function w(e){return e?`${e}Amount`:`eurAmount`}async function T({config:e}){let t=E(e),n=await f({config:t});if(!n){console.error(`Failed to create iframe`);return}let r=g({config:t,iframe:n});if(await r.waitForSetup,!await r.waitForConnection){console.error(`Failed to connect to client`);return}return r}function E(e){let t=x(e.metadata?.currency);return{...e,metadata:{...e.metadata,currency:t}}}export{x as a,g as c,m as d,u as f,S as i,d as l,w as n,b as o,C as r,y as s,T as t,f as u};
|
package/dist/src-hW71KjPN.cjs
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
const e=require(`./trackEvent-GuQm_1Nm.cjs`);let t=require(`@frak-labs/frame-connector`),n=require(`@frak-labs/frame-connector/middleware`),r=require(`@openpanel/web`);const i=`nexus-wallet-backup`;function a(e,t){if(typeof window>`u`)return;let n=new URL(window.location.href),r=n.searchParams.get(`sso`);r&&(t.then(()=>{e.sendLifecycle({clientLifecycle:`sso-redirect-complete`,data:{compressed:r}}),console.log(`[SSO URL Listener] Forwarded compressed SSO data to iframe`)}).catch(e=>{console.error(`[SSO URL Listener] Failed to forward SSO data:`,e)}),n.searchParams.delete(`sso`),window.history.replaceState({},``,n.toString()),console.log(`[SSO URL Listener] SSO parameter detected and URL cleaned`))}var o=class e{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,t){this.lastResponse={message:e,response:t,timestamp:Date.now()}}setLastRequest(e){this.lastRequest={event:e,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?this.iframe.contentDocument.readyState===`complete`?1:0:-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 n=this.getIframeStatus(),r=this.getNavigatorInfo(),i=`Unknown`;return e instanceof t.FrakRpcError?i=`FrakRpcError: ${e.code} '${e.message}'`:e instanceof Error?i=e.message:typeof e==`string`&&(i=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:n?this.base64Encode(n):`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:i}}static empty(){return new e}formatDebugInfo(e){let t=this.gatherDebugInfo(e);return`
|
|
2
|
-
Debug Information:
|
|
3
|
-
-----------------
|
|
4
|
-
Timestamp: ${t.timestamp}
|
|
5
|
-
URL: ${t.encodedUrl}
|
|
6
|
-
Config: ${t.encodedConfig}
|
|
7
|
-
Navigator Info: ${t.navigatorInfo}
|
|
8
|
-
IFrame Status: ${t.iframeStatus}
|
|
9
|
-
Last Request: ${t.lastRequest}
|
|
10
|
-
Last Response: ${t.lastResponse}
|
|
11
|
-
Client Status: ${t.clientStatus}
|
|
12
|
-
Error: ${t.error}
|
|
13
|
-
`.trim()}};const s={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=s.id,r.name=s.name,r.allow=s.allow,r.style.zIndex=s.style.zIndex.toString(),l({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 l({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 u(e=`/listener`){if(!window.opener)return null;let t=t=>{try{return t.location.origin===window.location.origin&&t.location.pathname===e}catch{return!1}};if(t(window.opener))return window.opener;try{let e=window.opener.frames;for(let n=0;n<e.length;n++)if(t(e[n]))return e[n];return null}catch(t){return console.error(`[findIframeInOpener] Error finding iframe with pathname ${e}:`,t),null}}function d({iframe:e}){let n=new t.Deferred;return{handleEvent:async t=>{if(!(`iframeLifecycle`in t))return;let{iframeLifecycle:r,data:a}=t;switch(r){case`connected`:n.resolve(!0);break;case`do-backup`:a.backup?localStorage.setItem(i,a.backup):localStorage.removeItem(i);break;case`remove-backup`:localStorage.removeItem(i);break;case`show`:case`hide`:l({iframe:e,isVisible:r===`show`});break;case`handshake`:e.contentWindow?.postMessage({clientLifecycle:`handshake-response`,data:{token:a.token,currentUrl:window.location.href}},`*`);break;case`redirect`:{let e=new URL(a.baseRedirectUrl);e.searchParams.has(`u`)?(e.searchParams.delete(`u`),e.searchParams.append(`u`,window.location.href),window.location.href=e.toString()):window.location.href=a.baseRedirectUrl;break}}},isConnected:n.promise}}function f({config:e,iframe:i}){let a=e?.walletUrl??`https://wallet.frak.id`,s=d({iframe:i}),c=new o(e,i);if(!i.contentWindow)throw new t.FrakRpcError(t.RpcErrorCodes.configError,`The iframe does not have a content window`);let l=(0,t.createRpcClient)({emittingTransport:i.contentWindow,listeningTransport:window,targetOrigin:a,middleware:[{async onRequest(e,n){if(!await s.isConnected)throw new t.FrakRpcError(t.RpcErrorCodes.clientNotConnected,`The iframe provider isn't connected yet`);return n}},(0,n.createClientCompressionMiddleware)(),{onRequest(e,t){return c.setLastRequest(e),t},onResponse(e,t){return c.setLastResponse(e,t),t}}],lifecycleHandlers:{iframeLifecycle:async(e,t)=>{await s.handleEvent(e)}}}),u=p(l,s),f=async()=>{u(),l.cleanup(),i.remove()},h;console.log(`[Frak SDK] Initializing OpenPanel`),h=new r.OpenPanel({apiUrl:`https://op-api.gcp.frak.id`,clientId:`f305d11d-b93b-487c-80d4-92deb7903e98`,trackScreenViews:!0,trackOutgoingLinks:!0,trackAttributes:!1,filter:({type:e,payload:t})=>(e!==`track`||!t?.properties||`sdkVersion`in t.properties||(t.properties={...t.properties,sdkVersion:`0.1.1`}),!0)}),h.setGlobalProperties({sdkVersion:`0.1.1`}),h.init();let g=m({config:e,rpcClient:l,lifecycleManager:s}).then(()=>c.updateSetupStatus(!0));return{config:e,debugInfo:c,waitForConnection:s.isConnected,waitForSetup:g,request:l.request,listenerRequest:l.listen,destroy:f,openPanel:h}}function p(e,t){let n,r,i=()=>e.sendLifecycle({clientLifecycle:`heartbeat`});async function a(){i(),n=setInterval(i,1e3),r=setTimeout(()=>{o(),console.log(`Heartbeat timeout: connection failed`)},3e4),await t.isConnected,o()}function o(){n&&clearInterval(n),r&&clearTimeout(r)}return a(),o}async function m({config:e,rpcClient:t,lifecycleManager:n}){await n.isConnected,a(t,n.isConnected);async function r(){let n=e.customizations?.css;if(!n)return;let r={clientLifecycle:`modal-css`,data:{cssLink:n}};t.sendLifecycle(r)}async function o(){let n=e.customizations?.i18n;if(!n)return;let r={clientLifecycle:`modal-i18n`,data:{i18n:n}};t.sendLifecycle(r)}async function s(){if(typeof window>`u`)return;let e=window.localStorage.getItem(i);if(!e)return;let n={clientLifecycle:`restore-backup`,data:{backup:e}};t.sendLifecycle(n)}await Promise.allSettled([r(),o(),s()])}function h(n){return(0,t.decompressJson)(e.c(n))}const g={eur:`fr-FR`,usd:`en-US`,gbp:`en-GB`};function _(e){return e&&e in g?e:`eur`}function v(e){return e?g[e]??g.eur:g.eur}function y(e,t){let n=v(t),r=_(t);return e.toLocaleString(n,{style:`currency`,currency:r,minimumFractionDigits:0,maximumFractionDigits:2})}function b(e){return e?`${e}Amount`:`eurAmount`}async function x({config:e}){let t=S(e),n=await c({config:t});if(!n){console.error(`Failed to create iframe`);return}let r=f({config:t,iframe:n});if(await r.waitForSetup,!await r.waitForConnection){console.error(`Failed to connect to client`);return}return r}function S(e){let t=_(e.metadata?.currency);return{...e,metadata:{...e.metadata,currency:t}}}Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return c}});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{bytesToHex as e,hexToBytes as t,keccak256 as n,toHex as r}from"viem";import{compressJson as i}from"@frak-labs/frame-connector";function a({domain:e}={}){return n(r((e??window.location.host).replace(`www.`,``)))}function o(e){return btoa(Array.from(e,e=>String.fromCharCode(e)).join(``)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}function s(e){let t=e.length%4;return Uint8Array.from(atob(e.replace(/-/g,`+`).replace(/_/g,`/`).padEnd(e.length+(t===0?0:4-t),`=`)),e=>e.charCodeAt(0))}function c(e){return o(i(e))}function l(e,t,n,r,i){let a=c(u({redirectUrl:t.redirectUrl,directExit:t.directExit,lang:t.lang,productId:n,metadata:{name:r,css:i,logoUrl:t.metadata?.logoUrl,homepageLink:t.metadata?.homepageLink}})),o=new URL(e);return o.pathname=`/sso`,o.searchParams.set(`p`,a),o.toString()}function u(e){return{r:e.redirectUrl,d:e.directExit,l:e.lang,p:e.productId,m:{n:e.metadata?.name,css:e.metadata?.css,l:e.metadata?.logoUrl,h:e.metadata?.homepageLink}}}const d=`menubar=no,status=no,scrollbars=no,fullscreen=no,width=500, height=800`,f=`frak-sso`;async function p(e,t){let{metadata:n,customizations:r,walletUrl:i}=e.config;if(t.openInSameWindow??!!t.redirectUrl)return await e.request({method:`frak_openSso`,params:[t,n.name,r?.css]});let o=t.ssoPopupUrl??l(i??`https://wallet.frak.id`,t,a(),n.name,r?.css),s=window.open(o,f,d);if(!s)throw Error(`Popup was blocked. Please allow popups for this site.`);return s.focus(),await e.request({method:`frak_openSso`,params:[t,n.name,r?.css]})??{}}const m=`fCtx`;function h(e){if(e?.r)try{return o(t(e.r))}catch(t){console.error(`Error compressing Frak context`,{e:t,context:e})}}function g(t){if(!(!t||t.length===0))try{return{r:e(s(t),{size:20})}}catch(e){console.error(`Error decompressing Frak context`,{e,context:t})}}function _({url:e}){if(!e)return null;let t=new URL(e).searchParams.get(m);return t?g(t):null}function v({url:e,context:t}){if(!e)return null;let n=_({url:e}),r=n?{...n,...t}:t;if(!r.r)return null;let i=h(r);if(!i)return null;let a=new URL(e);return a.searchParams.set(m,i),a.toString()}function y(e){let t=new URL(e);return t.searchParams.delete(m),t.toString()}function b({url:e,context:t}){if(!window.location?.href||typeof window>`u`){console.error(`No window found, can't update context`);return}let n=e??window.location.href,r;r=t===null?y(n):v({url:n,context:t}),r&&window.history.replaceState(null,``,r.toString())}const x={compress:h,decompress:g,parse:_,update:v,remove:y,replaceUrl:b};function S(e,t,n={}){if(!e){console.debug(`[Frak] No client provided, skipping event tracking`);return}try{e.openPanel?.track(t,n)}catch(e){console.debug(`[Frak] Failed to track event:`,t,e)}}export{f as a,s as c,d as i,o as l,x as n,l as o,p as r,c as s,S as t,a as u};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
let e=require(`viem`),t=require(`@frak-labs/frame-connector`);function n({domain:t}={}){return(0,e.keccak256)((0,e.toHex)((t??window.location.host).replace(`www.`,``)))}function r(e){return btoa(Array.from(e,e=>String.fromCharCode(e)).join(``)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}function i(e){let t=e.length%4;return Uint8Array.from(atob(e.replace(/-/g,`+`).replace(/_/g,`/`).padEnd(e.length+(t===0?0:4-t),`=`)),e=>e.charCodeAt(0))}function a(e){return r((0,t.compressJson)(e))}function o(e,t,n,r,i){let o=a(s({redirectUrl:t.redirectUrl,directExit:t.directExit,lang:t.lang,productId:n,metadata:{name:r,css:i,logoUrl:t.metadata?.logoUrl,homepageLink:t.metadata?.homepageLink}})),c=new URL(e);return c.pathname=`/sso`,c.searchParams.set(`p`,o),c.toString()}function s(e){return{r:e.redirectUrl,d:e.directExit,l:e.lang,p:e.productId,m:{n:e.metadata?.name,css:e.metadata?.css,l:e.metadata?.logoUrl,h:e.metadata?.homepageLink}}}const c=`menubar=no,status=no,scrollbars=no,fullscreen=no,width=500, height=800`,l=`frak-sso`;async function u(e,t){let{metadata:r,customizations:i,walletUrl:a}=e.config;if(t.openInSameWindow??!!t.redirectUrl)return await e.request({method:`frak_openSso`,params:[t,r.name,i?.css]});let s=t.ssoPopupUrl??o(a??`https://wallet.frak.id`,t,n(),r.name,i?.css),u=window.open(s,l,c);if(!u)throw Error(`Popup was blocked. Please allow popups for this site.`);return u.focus(),await e.request({method:`frak_openSso`,params:[t,r.name,i?.css]})??{}}const d=`fCtx`;function f(t){if(t?.r)try{return r((0,e.hexToBytes)(t.r))}catch(e){console.error(`Error compressing Frak context`,{e,context:t})}}function p(t){if(!(!t||t.length===0))try{return{r:(0,e.bytesToHex)(i(t),{size:20})}}catch(e){console.error(`Error decompressing Frak context`,{e,context:t})}}function m({url:e}){if(!e)return null;let t=new URL(e).searchParams.get(d);return t?p(t):null}function h({url:e,context:t}){if(!e)return null;let n=m({url:e}),r=n?{...n,...t}:t;if(!r.r)return null;let i=f(r);if(!i)return null;let a=new URL(e);return a.searchParams.set(d,i),a.toString()}function g(e){let t=new URL(e);return t.searchParams.delete(d),t.toString()}function _({url:e,context:t}){if(!window.location?.href||typeof window>`u`){console.error(`No window found, can't update context`);return}let n=e??window.location.href,r;r=t===null?g(n):h({url:n,context:t}),r&&window.history.replaceState(null,``,r.toString())}const v={compress:f,decompress:p,parse:m,update:h,remove:g,replaceUrl:_};function y(e,t,n={}){if(!e){console.debug(`[Frak] No client provided, skipping event tracking`);return}try{e.openPanel?.track(t,n)}catch(e){console.debug(`[Frak] Failed to track event:`,t,e)}}Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return n}});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { FrakClient, GetProductInformationReturnType } from "../types";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Function used to get the current product information
|
|
5
|
-
* @param client - The current Frak Client
|
|
6
|
-
* @returns The product information in a promise
|
|
7
|
-
*/
|
|
8
|
-
export async function getProductInformation(
|
|
9
|
-
client: FrakClient
|
|
10
|
-
): Promise<GetProductInformationReturnType> {
|
|
11
|
-
return await client.request({
|
|
12
|
-
method: "frak_getProductInformation",
|
|
13
|
-
});
|
|
14
|
-
}
|
|
@@ -1,407 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for openSso action
|
|
3
|
-
* Tests SSO flows in both redirect and popup modes
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { vi } from "vitest";
|
|
7
|
-
|
|
8
|
-
// Mock utilities before imports
|
|
9
|
-
vi.mock("../utils/sso", () => ({
|
|
10
|
-
generateSsoUrl: vi.fn((walletUrl, _args, productId, name, _css) => {
|
|
11
|
-
return `${walletUrl}/sso?name=${name}&productId=${productId}`;
|
|
12
|
-
}),
|
|
13
|
-
}));
|
|
14
|
-
|
|
15
|
-
vi.mock("../utils/computeProductId", () => ({
|
|
16
|
-
computeProductId: vi.fn(
|
|
17
|
-
() =>
|
|
18
|
-
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
|
|
19
|
-
),
|
|
20
|
-
}));
|
|
21
|
-
|
|
22
|
-
import {
|
|
23
|
-
afterEach,
|
|
24
|
-
beforeEach,
|
|
25
|
-
describe,
|
|
26
|
-
expect,
|
|
27
|
-
it,
|
|
28
|
-
} from "../../tests/vitest-fixtures";
|
|
29
|
-
import type {
|
|
30
|
-
FrakClient,
|
|
31
|
-
OpenSsoParamsType,
|
|
32
|
-
OpenSsoReturnType,
|
|
33
|
-
} from "../types";
|
|
34
|
-
import { openSso, ssoPopupFeatures, ssoPopupName } from "./openSso";
|
|
35
|
-
|
|
36
|
-
describe("openSso", () => {
|
|
37
|
-
describe("constants", () => {
|
|
38
|
-
it("should have correct popup features", () => {
|
|
39
|
-
expect(ssoPopupFeatures).toBe(
|
|
40
|
-
"menubar=no,status=no,scrollbars=no,fullscreen=no,width=500, height=800"
|
|
41
|
-
);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it("should have correct popup name", () => {
|
|
45
|
-
expect(ssoPopupName).toBe("frak-sso");
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
describe("redirect mode", () => {
|
|
50
|
-
it("should use redirect mode when openInSameWindow is true", async () => {
|
|
51
|
-
const mockResponse: OpenSsoReturnType = {
|
|
52
|
-
wallet: "0x1234567890123456789012345678901234567890",
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const mockClient = {
|
|
56
|
-
config: {
|
|
57
|
-
metadata: { name: "Test App" },
|
|
58
|
-
},
|
|
59
|
-
request: vi.fn().mockResolvedValue(mockResponse),
|
|
60
|
-
} as unknown as FrakClient;
|
|
61
|
-
|
|
62
|
-
const params: OpenSsoParamsType = {
|
|
63
|
-
openInSameWindow: true,
|
|
64
|
-
metadata: {
|
|
65
|
-
logoUrl: "https://example.com/logo.png",
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const result = await openSso(mockClient, params);
|
|
70
|
-
|
|
71
|
-
expect(mockClient.request).toHaveBeenCalledWith({
|
|
72
|
-
method: "frak_openSso",
|
|
73
|
-
params: [params, "Test App", undefined],
|
|
74
|
-
});
|
|
75
|
-
expect(result).toEqual(mockResponse);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it("should use redirect mode when redirectUrl is provided", async () => {
|
|
79
|
-
const mockResponse: OpenSsoReturnType = {
|
|
80
|
-
wallet: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const mockClient = {
|
|
84
|
-
config: {
|
|
85
|
-
metadata: { name: "Test App" },
|
|
86
|
-
},
|
|
87
|
-
request: vi.fn().mockResolvedValue(mockResponse),
|
|
88
|
-
} as unknown as FrakClient;
|
|
89
|
-
|
|
90
|
-
const params: OpenSsoParamsType = {
|
|
91
|
-
redirectUrl: "https://example.com/callback",
|
|
92
|
-
metadata: {
|
|
93
|
-
logoUrl: "https://example.com/logo.png",
|
|
94
|
-
},
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
const result = await openSso(mockClient, params);
|
|
98
|
-
|
|
99
|
-
expect(mockClient.request).toHaveBeenCalledWith({
|
|
100
|
-
method: "frak_openSso",
|
|
101
|
-
params: [params, "Test App", undefined],
|
|
102
|
-
});
|
|
103
|
-
expect(result).toEqual(mockResponse);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it("should pass custom CSS in redirect mode", async () => {
|
|
107
|
-
const mockResponse: OpenSsoReturnType = {};
|
|
108
|
-
|
|
109
|
-
const mockClient = {
|
|
110
|
-
config: {
|
|
111
|
-
metadata: { name: "Test App" },
|
|
112
|
-
customizations: {
|
|
113
|
-
css: ":root { --primary: blue; }",
|
|
114
|
-
},
|
|
115
|
-
},
|
|
116
|
-
request: vi.fn().mockResolvedValue(mockResponse),
|
|
117
|
-
} as unknown as FrakClient;
|
|
118
|
-
|
|
119
|
-
const params: OpenSsoParamsType = {
|
|
120
|
-
openInSameWindow: true,
|
|
121
|
-
metadata: {
|
|
122
|
-
logoUrl: "https://example.com/logo.png",
|
|
123
|
-
},
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
await openSso(mockClient, params);
|
|
127
|
-
|
|
128
|
-
expect(mockClient.request).toHaveBeenCalledWith({
|
|
129
|
-
method: "frak_openSso",
|
|
130
|
-
params: [params, "Test App", ":root { --primary: blue; }"],
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
describe("popup mode", () => {
|
|
136
|
-
let windowOpenSpy: any;
|
|
137
|
-
let mockPopup: {
|
|
138
|
-
focus: ReturnType<typeof vi.fn>;
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
beforeEach(() => {
|
|
142
|
-
mockPopup = {
|
|
143
|
-
focus: vi.fn(),
|
|
144
|
-
};
|
|
145
|
-
windowOpenSpy = vi
|
|
146
|
-
.spyOn(window, "open")
|
|
147
|
-
.mockReturnValue(mockPopup as unknown as Window);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
afterEach(() => {
|
|
151
|
-
windowOpenSpy.mockRestore();
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it("should open popup with generated URL", async () => {
|
|
155
|
-
const mockResponse: OpenSsoReturnType = {
|
|
156
|
-
wallet: "0x1234567890123456789012345678901234567890",
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
const mockClient = {
|
|
160
|
-
config: {
|
|
161
|
-
metadata: { name: "Test App" },
|
|
162
|
-
walletUrl: "https://wallet.frak.id",
|
|
163
|
-
},
|
|
164
|
-
request: vi.fn().mockResolvedValue(mockResponse),
|
|
165
|
-
} as unknown as FrakClient;
|
|
166
|
-
|
|
167
|
-
const params: OpenSsoParamsType = {
|
|
168
|
-
metadata: {
|
|
169
|
-
logoUrl: "https://example.com/logo.png",
|
|
170
|
-
},
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
await openSso(mockClient, params);
|
|
174
|
-
|
|
175
|
-
expect(window.open).toHaveBeenCalledWith(
|
|
176
|
-
expect.stringContaining("https://wallet.frak.id/sso"),
|
|
177
|
-
"frak-sso",
|
|
178
|
-
"menubar=no,status=no,scrollbars=no,fullscreen=no,width=500, height=800"
|
|
179
|
-
);
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it("should use custom ssoPopupUrl when provided", async () => {
|
|
183
|
-
const mockResponse: OpenSsoReturnType = {};
|
|
184
|
-
|
|
185
|
-
const mockClient = {
|
|
186
|
-
config: {
|
|
187
|
-
metadata: { name: "Test App" },
|
|
188
|
-
},
|
|
189
|
-
request: vi.fn().mockResolvedValue(mockResponse),
|
|
190
|
-
} as unknown as FrakClient;
|
|
191
|
-
|
|
192
|
-
const params: OpenSsoParamsType = {
|
|
193
|
-
ssoPopupUrl: "https://custom-wallet.com/sso?custom=param",
|
|
194
|
-
metadata: {
|
|
195
|
-
logoUrl: "https://example.com/logo.png",
|
|
196
|
-
},
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
await openSso(mockClient, params);
|
|
200
|
-
|
|
201
|
-
expect(window.open).toHaveBeenCalledWith(
|
|
202
|
-
"https://custom-wallet.com/sso?custom=param",
|
|
203
|
-
"frak-sso",
|
|
204
|
-
"menubar=no,status=no,scrollbars=no,fullscreen=no,width=500, height=800"
|
|
205
|
-
);
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
it("should focus popup after opening", async () => {
|
|
209
|
-
const mockResponse: OpenSsoReturnType = {};
|
|
210
|
-
|
|
211
|
-
const mockClient = {
|
|
212
|
-
config: {
|
|
213
|
-
metadata: { name: "Test App" },
|
|
214
|
-
},
|
|
215
|
-
request: vi.fn().mockResolvedValue(mockResponse),
|
|
216
|
-
} as unknown as FrakClient;
|
|
217
|
-
|
|
218
|
-
const params: OpenSsoParamsType = {
|
|
219
|
-
metadata: {
|
|
220
|
-
logoUrl: "https://example.com/logo.png",
|
|
221
|
-
},
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
await openSso(mockClient, params);
|
|
225
|
-
|
|
226
|
-
expect(mockPopup.focus).toHaveBeenCalled();
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
it("should wait for SSO completion via client.request", async () => {
|
|
230
|
-
const mockResponse: OpenSsoReturnType = {
|
|
231
|
-
wallet: "0x1234567890123456789012345678901234567890",
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
const mockClient = {
|
|
235
|
-
config: {
|
|
236
|
-
metadata: { name: "Test App" },
|
|
237
|
-
},
|
|
238
|
-
request: vi.fn().mockResolvedValue(mockResponse),
|
|
239
|
-
} as unknown as FrakClient;
|
|
240
|
-
|
|
241
|
-
const params: OpenSsoParamsType = {
|
|
242
|
-
metadata: {
|
|
243
|
-
logoUrl: "https://example.com/logo.png",
|
|
244
|
-
},
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
const result = await openSso(mockClient, params);
|
|
248
|
-
|
|
249
|
-
expect(mockClient.request).toHaveBeenCalledWith({
|
|
250
|
-
method: "frak_openSso",
|
|
251
|
-
params: [params, "Test App", undefined],
|
|
252
|
-
});
|
|
253
|
-
expect(result).toEqual(mockResponse);
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
it("should return empty object when result is null", async () => {
|
|
257
|
-
const mockClient = {
|
|
258
|
-
config: {
|
|
259
|
-
metadata: { name: "Test App" },
|
|
260
|
-
},
|
|
261
|
-
request: vi.fn().mockResolvedValue(null),
|
|
262
|
-
} as unknown as FrakClient;
|
|
263
|
-
|
|
264
|
-
const params: OpenSsoParamsType = {
|
|
265
|
-
metadata: {
|
|
266
|
-
logoUrl: "https://example.com/logo.png",
|
|
267
|
-
},
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
const result = await openSso(mockClient, params);
|
|
271
|
-
|
|
272
|
-
expect(result).toEqual({});
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
it("should use default wallet URL when not configured", async () => {
|
|
276
|
-
const mockResponse: OpenSsoReturnType = {};
|
|
277
|
-
|
|
278
|
-
const mockClient = {
|
|
279
|
-
config: {
|
|
280
|
-
metadata: { name: "Test App" },
|
|
281
|
-
},
|
|
282
|
-
request: vi.fn().mockResolvedValue(mockResponse),
|
|
283
|
-
} as unknown as FrakClient;
|
|
284
|
-
|
|
285
|
-
const params: OpenSsoParamsType = {
|
|
286
|
-
metadata: {
|
|
287
|
-
logoUrl: "https://example.com/logo.png",
|
|
288
|
-
},
|
|
289
|
-
};
|
|
290
|
-
|
|
291
|
-
await openSso(mockClient, params);
|
|
292
|
-
|
|
293
|
-
expect(window.open).toHaveBeenCalledWith(
|
|
294
|
-
expect.stringContaining("https://wallet.frak.id/sso"),
|
|
295
|
-
expect.any(String),
|
|
296
|
-
expect.any(String)
|
|
297
|
-
);
|
|
298
|
-
});
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
describe("popup blocker", () => {
|
|
302
|
-
it("should throw error when popup is blocked", async () => {
|
|
303
|
-
vi.spyOn(window, "open").mockReturnValue(null);
|
|
304
|
-
|
|
305
|
-
const mockClient = {
|
|
306
|
-
config: {
|
|
307
|
-
metadata: { name: "Test App" },
|
|
308
|
-
},
|
|
309
|
-
request: vi.fn(),
|
|
310
|
-
} as unknown as FrakClient;
|
|
311
|
-
|
|
312
|
-
const params: OpenSsoParamsType = {
|
|
313
|
-
metadata: {
|
|
314
|
-
logoUrl: "https://example.com/logo.png",
|
|
315
|
-
},
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
await expect(openSso(mockClient, params)).rejects.toThrow(
|
|
319
|
-
"Popup was blocked. Please allow popups for this site."
|
|
320
|
-
);
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
it("should not call client.request when popup is blocked", async () => {
|
|
324
|
-
vi.spyOn(window, "open").mockReturnValue(null);
|
|
325
|
-
|
|
326
|
-
const mockClient = {
|
|
327
|
-
config: {
|
|
328
|
-
metadata: { name: "Test App" },
|
|
329
|
-
},
|
|
330
|
-
request: vi.fn(),
|
|
331
|
-
} as unknown as FrakClient;
|
|
332
|
-
|
|
333
|
-
const params: OpenSsoParamsType = {
|
|
334
|
-
metadata: {
|
|
335
|
-
logoUrl: "https://example.com/logo.png",
|
|
336
|
-
},
|
|
337
|
-
};
|
|
338
|
-
|
|
339
|
-
try {
|
|
340
|
-
await openSso(mockClient, params);
|
|
341
|
-
} catch {
|
|
342
|
-
// Expected error
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
expect(mockClient.request).not.toHaveBeenCalled();
|
|
346
|
-
});
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
describe("mode detection", () => {
|
|
350
|
-
it("should prefer openInSameWindow over redirectUrl", async () => {
|
|
351
|
-
const mockResponse: OpenSsoReturnType = {};
|
|
352
|
-
|
|
353
|
-
const mockClient = {
|
|
354
|
-
config: {
|
|
355
|
-
metadata: { name: "Test App" },
|
|
356
|
-
},
|
|
357
|
-
request: vi.fn().mockResolvedValue(mockResponse),
|
|
358
|
-
} as unknown as FrakClient;
|
|
359
|
-
|
|
360
|
-
const params: OpenSsoParamsType = {
|
|
361
|
-
openInSameWindow: false,
|
|
362
|
-
redirectUrl: "https://example.com/callback",
|
|
363
|
-
metadata: {
|
|
364
|
-
logoUrl: "https://example.com/logo.png",
|
|
365
|
-
},
|
|
366
|
-
};
|
|
367
|
-
|
|
368
|
-
const windowOpenSpy = vi.spyOn(window, "open").mockReturnValue({
|
|
369
|
-
focus: vi.fn(),
|
|
370
|
-
} as unknown as Window);
|
|
371
|
-
|
|
372
|
-
await openSso(mockClient, params);
|
|
373
|
-
|
|
374
|
-
// Should use popup mode because openInSameWindow=false
|
|
375
|
-
expect(window.open).toHaveBeenCalled();
|
|
376
|
-
|
|
377
|
-
windowOpenSpy.mockRestore();
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
it("should use popup mode when neither flag is set", async () => {
|
|
381
|
-
const mockResponse: OpenSsoReturnType = {};
|
|
382
|
-
|
|
383
|
-
const mockClient = {
|
|
384
|
-
config: {
|
|
385
|
-
metadata: { name: "Test App" },
|
|
386
|
-
},
|
|
387
|
-
request: vi.fn().mockResolvedValue(mockResponse),
|
|
388
|
-
} as unknown as FrakClient;
|
|
389
|
-
|
|
390
|
-
const params: OpenSsoParamsType = {
|
|
391
|
-
metadata: {
|
|
392
|
-
logoUrl: "https://example.com/logo.png",
|
|
393
|
-
},
|
|
394
|
-
};
|
|
395
|
-
|
|
396
|
-
const windowOpenSpy = vi.spyOn(window, "open").mockReturnValue({
|
|
397
|
-
focus: vi.fn(),
|
|
398
|
-
} as unknown as Window);
|
|
399
|
-
|
|
400
|
-
await openSso(mockClient, params);
|
|
401
|
-
|
|
402
|
-
expect(window.open).toHaveBeenCalled();
|
|
403
|
-
|
|
404
|
-
windowOpenSpy.mockRestore();
|
|
405
|
-
});
|
|
406
|
-
});
|
|
407
|
-
});
|