@frak-labs/core-sdk 0.2.1-beta.b38eef2e → 0.2.1-beta.d2556d47
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 +1 -2
- package/cdn/bundle.js +55 -3
- package/dist/actions.cjs +1 -1
- package/dist/actions.d.cts +2 -2
- package/dist/actions.d.ts +2 -2
- package/dist/actions.js +1 -1
- package/dist/bundle.cjs +1 -1
- package/dist/bundle.d.cts +4 -4
- package/dist/bundle.d.ts +4 -4
- package/dist/bundle.js +1 -1
- package/dist/{computeLegacyProductId-b5cUWdAm.d.ts → computeLegacyProductId-BP-ciVsp.d.cts} +30 -44
- package/dist/{computeLegacyProductId-CCAZvLa5.d.cts → computeLegacyProductId-DiJd7RNo.d.ts} +30 -44
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/{openSso-B0g7-807.d.cts → openSso-B8v3Vtnh.d.ts} +118 -46
- package/dist/{openSso-CMzwvaCa.d.ts → openSso-n_B4LSuW.d.cts} +118 -46
- package/dist/setupClient-Dr_UYfTD.cjs +13 -0
- package/dist/setupClient-TuhDjVJx.js +13 -0
- package/dist/siweAuthenticate-0UPcUqI1.js +1 -0
- package/dist/{siweAuthenticate-CVigMOxz.d.cts → siweAuthenticate-CDCsp8EJ.d.ts} +8 -5
- package/dist/siweAuthenticate-CfQibjZR.cjs +1 -0
- package/dist/{siweAuthenticate-CnCZ7mok.d.ts → siweAuthenticate-yITE-iKh.d.cts} +8 -5
- package/dist/trackEvent-5j5kkOCj.js +1 -0
- package/dist/trackEvent-B2uom25e.cjs +1 -0
- package/package.json +8 -8
- package/src/actions/displayEmbeddedWallet.ts +6 -2
- package/src/actions/displayModal.ts +6 -2
- package/src/actions/ensureIdentity.ts +2 -2
- package/src/actions/trackPurchaseStatus.test.ts +32 -20
- package/src/actions/trackPurchaseStatus.ts +3 -5
- package/src/actions/wrapper/modalBuilder.test.ts +4 -2
- package/src/actions/wrapper/modalBuilder.ts +6 -8
- package/src/clients/createIFrameFrakClient.ts +146 -25
- package/src/clients/transports/iframeLifecycleManager.test.ts +0 -80
- package/src/clients/transports/iframeLifecycleManager.ts +0 -44
- package/src/index.ts +5 -3
- package/src/types/config.ts +10 -3
- package/src/types/index.ts +6 -1
- package/src/types/lifecycle/client.ts +22 -27
- package/src/types/lifecycle/iframe.ts +0 -8
- package/src/types/resolvedConfig.ts +104 -0
- package/src/types/rpc/interaction.ts +4 -0
- package/src/types/rpc.ts +7 -5
- package/src/utils/backendUrl.test.ts +2 -2
- package/src/utils/backendUrl.ts +1 -1
- package/src/utils/index.ts +1 -5
- package/src/utils/sdkConfigStore.test.ts +405 -0
- package/src/utils/sdkConfigStore.ts +277 -0
- package/src/utils/sso.ts +3 -7
- package/dist/setupClient-CqTHGvVa.cjs +0 -13
- package/dist/setupClient-DTyvAPgh.js +0 -13
- package/dist/siweAuthenticate-BWmI2_TN.cjs +0 -1
- package/dist/siweAuthenticate-zczqxm0a.js +0 -1
- package/dist/trackEvent-CeLFVzZn.js +0 -1
- package/dist/trackEvent-Ew5r5zfI.cjs +0 -1
- package/src/utils/merchantId.test.ts +0 -653
- package/src/utils/merchantId.ts +0 -143
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { A as SendTransactionModalStepType, B as PrepareSsoReturnType, E as ModalRpcMetadata, F as SiweAuthenticationParams, H as FinalActionType, I as LoginModalStepType, O as ModalRpcStepsResultType, P as SiweAuthenticateReturnType, T as DisplayModalParamsType, U as FinalModalStepType, b as DisplayEmbeddedWalletResultType, h as GetMerchantInformationReturnType, i as FrakContext, j as SendTransactionReturnType, k as ModalStepTypes, l as FrakClient, p as WalletStatusReturnType, v as SendInteractionParamsType, y as DisplayEmbeddedWalletParamsType, z as PrepareSsoParamsType } from "./openSso-
|
|
1
|
+
import { A as SendTransactionModalStepType, B as PrepareSsoReturnType, E as ModalRpcMetadata, F as SiweAuthenticationParams, H as FinalActionType, I as LoginModalStepType, O as ModalRpcStepsResultType, P as SiweAuthenticateReturnType, T as DisplayModalParamsType, U as FinalModalStepType, b as DisplayEmbeddedWalletResultType, h as GetMerchantInformationReturnType, i as FrakContext, j as SendTransactionReturnType, k as ModalStepTypes, l as FrakClient, p as WalletStatusReturnType, v as SendInteractionParamsType, y as DisplayEmbeddedWalletParamsType, z as PrepareSsoParamsType } from "./openSso-B8v3Vtnh.js";
|
|
2
2
|
|
|
3
3
|
//#region src/actions/displayEmbeddedWallet.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Function used to display the Frak embedded wallet popup
|
|
6
6
|
* @param client - The current Frak Client
|
|
7
7
|
* @param params - The parameter used to customise the embedded wallet
|
|
8
|
+
* @param placement - Optional placement ID to associate with this display request
|
|
8
9
|
* @returns The embedded wallet display result
|
|
9
10
|
*/
|
|
10
|
-
declare function displayEmbeddedWallet(client: FrakClient, params: DisplayEmbeddedWalletParamsType): Promise<DisplayEmbeddedWalletResultType>;
|
|
11
|
+
declare function displayEmbeddedWallet(client: FrakClient, params: DisplayEmbeddedWalletParamsType, placement?: string): Promise<DisplayEmbeddedWalletResultType>;
|
|
11
12
|
//#endregion
|
|
12
13
|
//#region src/actions/displayModal.d.ts
|
|
13
14
|
/**
|
|
@@ -16,6 +17,7 @@ declare function displayEmbeddedWallet(client: FrakClient, params: DisplayEmbedd
|
|
|
16
17
|
* @param args
|
|
17
18
|
* @param args.steps - The different steps of the modal
|
|
18
19
|
* @param args.metadata - The metadata for the modal (customization, etc)
|
|
20
|
+
* @param placement - Optional placement ID to associate with this modal display
|
|
19
21
|
* @returns The result of each modal steps
|
|
20
22
|
*
|
|
21
23
|
* @description This function will display a modal to the user with the provided steps and metadata.
|
|
@@ -115,7 +117,7 @@ declare function displayEmbeddedWallet(client: FrakClient, params: DisplayEmbedd
|
|
|
115
117
|
declare function displayModal<T extends ModalStepTypes[] = ModalStepTypes[]>(client: FrakClient, {
|
|
116
118
|
steps,
|
|
117
119
|
metadata
|
|
118
|
-
}: DisplayModalParamsType<T
|
|
120
|
+
}: DisplayModalParamsType<T>, placement?: string): Promise<ModalRpcStepsResultType<T>>;
|
|
119
121
|
//#endregion
|
|
120
122
|
//#region src/actions/ensureIdentity.d.ts
|
|
121
123
|
/**
|
|
@@ -322,7 +324,7 @@ declare function sendInteraction(client: FrakClient, params: SendInteractionPara
|
|
|
322
324
|
* }
|
|
323
325
|
*
|
|
324
326
|
* @remarks
|
|
325
|
-
* - Merchant id is resolved in this order: explicit `args.merchantId`, `
|
|
327
|
+
* - Merchant id is resolved in this order: explicit `args.merchantId`, then `sdkConfigStore.resolveMerchantId()` (config store → sessionStorage → backend fetch).
|
|
326
328
|
* - This function supports anonymous users and will use the `x-frak-client-id` header when available.
|
|
327
329
|
* - At least one identity source must exist (`frak-wallet-interaction-token` or `x-frak-client-id`), otherwise the tracking request is skipped.
|
|
328
330
|
* - This function will print a warning if used in a non-browser environment or if no identity / merchant id can be resolved.
|
|
@@ -380,8 +382,9 @@ type ModalStepBuilder<Steps extends ModalStepTypes[] = ModalStepTypes[]> = {
|
|
|
380
382
|
/**
|
|
381
383
|
* Display the modal
|
|
382
384
|
* @param metadataOverride - Function returning optional metadata to override the current modal metadata
|
|
385
|
+
* @param placement - Optional placement ID to associate with this modal display
|
|
383
386
|
*/
|
|
384
|
-
display: (metadataOverride?: (current?: ModalRpcMetadata) => ModalRpcMetadata | undefined) => Promise<ModalRpcStepsResultType<Steps>>;
|
|
387
|
+
display: (metadataOverride?: (current?: ModalRpcMetadata) => ModalRpcMetadata | undefined, placement?: string) => Promise<ModalRpcStepsResultType<Steps>>;
|
|
385
388
|
};
|
|
386
389
|
/**
|
|
387
390
|
* Represent the output type of the modal builder
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require(`./trackEvent-B2uom25e.cjs`);let t=require(`viem`),n=require(`@frak-labs/frame-connector`),r=require(`viem/siwe`);async function i(e,t,n){return await e.request({method:`frak_displayEmbeddedWallet`,params:n?[t,e.config.metadata,n]:[t,e.config.metadata]})}async function a(e,{steps:t,metadata:n},r){return await e.request({method:`frak_displayModal`,params:r?[t,n,e.config.metadata,r]:[t,n,e.config.metadata]})}async function o(t){if(typeof window>`u`)return;let n=e.g();if(!n)return;let r=await e.n.resolveMerchantId();if(!r)return;let i=`frak-identity-ensured-${r}`;if(!window.sessionStorage.getItem(i))try{let a=e.s();(await fetch(`${a}/user/identity/ensure`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`,"x-wallet-sdk-auth":t,"x-frak-client-id":n},body:JSON.stringify({merchantId:r})})).ok&&window.sessionStorage.setItem(i,`1`)}catch{}}async function s(e){return await e.request({method:`frak_getMerchantInformation`})}async function c(e,t){let{metadata:n,customizations:r}=e.config;return await e.request({method:`frak_prepareSso`,params:[t,n.name,r?.css]})}async function l(t,n){try{await t.request({method:`frak_sendInteraction`,params:[n,{clientId:e.g()}]})}catch{console.warn(`[Frak SDK] Failed to send interaction:`,n.type)}}function u(t,n,r){let i=typeof window<`u`?window.location.href:void 0;return e.a(n)?(e.t(t,`user_referred_started`,{properties:{referrerClientId:n.c,walletStatus:r?.key}}),l(t,{type:`arrival`,referrerClientId:n.c,referrerMerchantId:n.m,referralTimestamp:n.t,landingUrl:i}),!0):e.i(n)?(e.t(t,`user_referred_started`,{properties:{referrer:n.r,walletStatus:r?.key}}),l(t,{type:`arrival`,referrerWallet:n.r,landingUrl:i}),!0):!1}function d(t){let n=e.g();return n?{v:2,c:n,m:t,t:Math.floor(Date.now()/1e3)}:null}function f(n,r){return e.a(n)?e.g()===n.c:e.i(n)&&r?.wallet?(0,t.isAddressEqual)(n.r,r.wallet):!1}function p(t,{walletStatus:n,frakContext:r,options:i}){if(!r)return`no-referrer`;if(f(r,n))return`self-referral`;if(!u(t,r,n))return`no-referrer`;let a=e.a(r)?r.m:i?.merchantId,o=i?.alwaysAppendUrl&&a?d(a):null;return e.r.replaceUrl({url:window.location?.href,context:o}),e.t(t,`user_referred_completed`,{properties:{status:`success`}}),`success`}async function m(t,{options:n}={}){let r=e.r.parse({url:window.location.href}),i=await g(t);try{return p(t,{walletStatus:i,frakContext:r,options:n})}catch(e){console.warn(`Error processing referral`,{error:e})}}async function h(t){if(typeof window>`u`){console.warn(`[Frak] No window found, can't track purchase`);return}let n=window.sessionStorage.getItem(`frak-wallet-interaction-token`),r=e.g();if(!n&&!r){console.warn(`[Frak] No identity found, skipping purchase check`);return}let i=t.merchantId??await e.n.resolveMerchantId();if(!i){console.warn(`[Frak] No merchant id found, skipping purchase check`);return}let a={Accept:`application/json`,"Content-Type":`application/json`};n&&(a[`x-wallet-sdk-auth`]=n),r&&(a[`x-frak-client-id`]=r);let o=e.s();await fetch(`${o}/user/track/purchase`,{method:`POST`,headers:a,body:JSON.stringify({customerId:t.customerId,orderId:t.orderId,token:t.token,merchantId:i})})}function g(e,t){if(!t)return e.request({method:`frak_listenToWalletStatus`}).then(t=>(_(e,t),t));let r=new n.Deferred,i=!1;return e.listenerRequest({method:`frak_listenToWalletStatus`},n=>{_(e,n),t(n),i||=(r.resolve(n),!0)}),r.promise}function _(e,t){typeof window>`u`||(e.openPanel?.setGlobalProperties({wallet:t.wallet??null}),t.interactionToken?(window.sessionStorage.setItem(`frak-wallet-interaction-token`,t.interactionToken),o(t.interactionToken)):window.sessionStorage.removeItem(`frak-wallet-interaction-token`))}function v(e,{metadata:t,login:n}){return y(e,{steps:{login:n??{}},metadata:t})}function y(e,t){function n(n){return y(e,{...t,steps:{...t.steps,sendTransaction:n}})}function r(n){return y(e,{...t,steps:{...t.steps,final:{...n,action:{key:`reward`}}}})}function i(n,r){return y(e,{...t,steps:{...t.steps,final:{...r,action:{key:`sharing`,options:n}}}})}async function o(n,r){return n&&(t.metadata=n(t.metadata??{})),await a(e,t,r)}return{params:t,sendTx:n,reward:r,sharing:i,display:o}}async function b(e,{tx:t,metadata:n}){return(await a(e,{metadata:n,steps:{login:{},sendTransaction:{tx:t}}})).sendTransaction}async function x(e,{siwe:t,metadata:n}){let i=e.config?.domain??window.location.host,o=t?.statement??`I confirm that I want to use my Frak wallet on: ${e.config.metadata.name}`;return(await a(e,{metadata:n,steps:{login:{},siweAuthenticate:{siwe:{...t,statement:o,nonce:t?.nonce??(0,r.generateSiweNonce)(),uri:t?.uri??`https://${i}`,version:t?.version??`1`,domain:i}}}})).siweAuthenticate}Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return s}});
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { A as SendTransactionModalStepType, B as PrepareSsoReturnType, E as ModalRpcMetadata, F as SiweAuthenticationParams, H as FinalActionType, I as LoginModalStepType, O as ModalRpcStepsResultType, P as SiweAuthenticateReturnType, T as DisplayModalParamsType, U as FinalModalStepType, b as DisplayEmbeddedWalletResultType, h as GetMerchantInformationReturnType, i as FrakContext, j as SendTransactionReturnType, k as ModalStepTypes, l as FrakClient, p as WalletStatusReturnType, v as SendInteractionParamsType, y as DisplayEmbeddedWalletParamsType, z as PrepareSsoParamsType } from "./openSso-
|
|
1
|
+
import { A as SendTransactionModalStepType, B as PrepareSsoReturnType, E as ModalRpcMetadata, F as SiweAuthenticationParams, H as FinalActionType, I as LoginModalStepType, O as ModalRpcStepsResultType, P as SiweAuthenticateReturnType, T as DisplayModalParamsType, U as FinalModalStepType, b as DisplayEmbeddedWalletResultType, h as GetMerchantInformationReturnType, i as FrakContext, j as SendTransactionReturnType, k as ModalStepTypes, l as FrakClient, p as WalletStatusReturnType, v as SendInteractionParamsType, y as DisplayEmbeddedWalletParamsType, z as PrepareSsoParamsType } from "./openSso-n_B4LSuW.cjs";
|
|
2
2
|
|
|
3
3
|
//#region src/actions/displayEmbeddedWallet.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Function used to display the Frak embedded wallet popup
|
|
6
6
|
* @param client - The current Frak Client
|
|
7
7
|
* @param params - The parameter used to customise the embedded wallet
|
|
8
|
+
* @param placement - Optional placement ID to associate with this display request
|
|
8
9
|
* @returns The embedded wallet display result
|
|
9
10
|
*/
|
|
10
|
-
declare function displayEmbeddedWallet(client: FrakClient, params: DisplayEmbeddedWalletParamsType): Promise<DisplayEmbeddedWalletResultType>;
|
|
11
|
+
declare function displayEmbeddedWallet(client: FrakClient, params: DisplayEmbeddedWalletParamsType, placement?: string): Promise<DisplayEmbeddedWalletResultType>;
|
|
11
12
|
//#endregion
|
|
12
13
|
//#region src/actions/displayModal.d.ts
|
|
13
14
|
/**
|
|
@@ -16,6 +17,7 @@ declare function displayEmbeddedWallet(client: FrakClient, params: DisplayEmbedd
|
|
|
16
17
|
* @param args
|
|
17
18
|
* @param args.steps - The different steps of the modal
|
|
18
19
|
* @param args.metadata - The metadata for the modal (customization, etc)
|
|
20
|
+
* @param placement - Optional placement ID to associate with this modal display
|
|
19
21
|
* @returns The result of each modal steps
|
|
20
22
|
*
|
|
21
23
|
* @description This function will display a modal to the user with the provided steps and metadata.
|
|
@@ -115,7 +117,7 @@ declare function displayEmbeddedWallet(client: FrakClient, params: DisplayEmbedd
|
|
|
115
117
|
declare function displayModal<T extends ModalStepTypes[] = ModalStepTypes[]>(client: FrakClient, {
|
|
116
118
|
steps,
|
|
117
119
|
metadata
|
|
118
|
-
}: DisplayModalParamsType<T
|
|
120
|
+
}: DisplayModalParamsType<T>, placement?: string): Promise<ModalRpcStepsResultType<T>>;
|
|
119
121
|
//#endregion
|
|
120
122
|
//#region src/actions/ensureIdentity.d.ts
|
|
121
123
|
/**
|
|
@@ -322,7 +324,7 @@ declare function sendInteraction(client: FrakClient, params: SendInteractionPara
|
|
|
322
324
|
* }
|
|
323
325
|
*
|
|
324
326
|
* @remarks
|
|
325
|
-
* - Merchant id is resolved in this order: explicit `args.merchantId`, `
|
|
327
|
+
* - Merchant id is resolved in this order: explicit `args.merchantId`, then `sdkConfigStore.resolveMerchantId()` (config store → sessionStorage → backend fetch).
|
|
326
328
|
* - This function supports anonymous users and will use the `x-frak-client-id` header when available.
|
|
327
329
|
* - At least one identity source must exist (`frak-wallet-interaction-token` or `x-frak-client-id`), otherwise the tracking request is skipped.
|
|
328
330
|
* - This function will print a warning if used in a non-browser environment or if no identity / merchant id can be resolved.
|
|
@@ -380,8 +382,9 @@ type ModalStepBuilder<Steps extends ModalStepTypes[] = ModalStepTypes[]> = {
|
|
|
380
382
|
/**
|
|
381
383
|
* Display the modal
|
|
382
384
|
* @param metadataOverride - Function returning optional metadata to override the current modal metadata
|
|
385
|
+
* @param placement - Optional placement ID to associate with this modal display
|
|
383
386
|
*/
|
|
384
|
-
display: (metadataOverride?: (current?: ModalRpcMetadata) => ModalRpcMetadata | undefined) => Promise<ModalRpcStepsResultType<Steps>>;
|
|
387
|
+
display: (metadataOverride?: (current?: ModalRpcMetadata) => ModalRpcMetadata | undefined, placement?: string) => Promise<ModalRpcStepsResultType<Steps>>;
|
|
385
388
|
};
|
|
386
389
|
/**
|
|
387
390
|
* Represent the output type of the modal builder
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{bytesToHex as e,hexToBytes as t,isAddress as n,keccak256 as r,toHex as i}from"viem";import{jsonDecode as a,jsonEncode as o}from"@frak-labs/frame-connector";const s=`frak-client-id`;function c(){return typeof crypto<`u`&&crypto.randomUUID?crypto.randomUUID():`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e===`x`?t:t&3|8).toString(16)})}function l(){if(typeof window>`u`||!window.localStorage)return console.warn(`[Frak SDK] No Window / localStorage available to save the clientId`),c();let e=localStorage.getItem(s);return e||(e=c(),localStorage.setItem(s,e)),e}function u({domain:e}={}){return r(i((e??window.location.host).replace(`www.`,``)))}function d(e){return btoa(Array.from(e,e=>String.fromCharCode(e)).join(``)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}function f(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 p(e){return d(o(e))}function m(e,t,n,r,i,a){let o=p(ee({redirectUrl:t.redirectUrl,directExit:t.directExit,lang:t.lang,merchantId:n,metadata:{name:r,css:a,logoUrl:t.metadata?.logoUrl,homepageLink:t.metadata?.homepageLink},clientId:i})),s=new URL(e);return s.pathname=`/sso`,s.searchParams.set(`p`,o),s.toString()}function ee(e){return{r:e.redirectUrl,cId:e.clientId,d:e.directExit,l:e.lang,m:e.merchantId,md:{n:e.metadata?.name,css:e.metadata?.css,l:e.metadata?.logoUrl,h:e.metadata?.homepageLink}}}const h=`menubar=no,status=no,scrollbars=no,fullscreen=no,width=500, height=800`,g=`frak-sso`;async function _(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 a=t.ssoPopupUrl??m(i??`https://wallet.frak.id`,t,u(),n.name,l(),r?.css),o=window.open(a,g,h);if(!o)throw Error(`Popup was blocked. Please allow popups for this site.`);return o.focus(),await e.request({method:`frak_openSso`,params:[t,n.name,r?.css]})??{}}const v=`https://backend.frak.id`;function y(e){return e.includes(`localhost:3000`)||e.includes(`localhost:3010`)}function b(e){return y(e)?`https://localhost:3030`:e.includes(`wallet-dev.frak.id`)||e.includes(`wallet.gcp-dev.frak.id`)?`https://backend.gcp-dev.frak.id`:v}function x(e){if(e)return b(e);if(typeof window<`u`){let e=window.FrakSetup?.client?.config?.walletUrl;if(e)return b(e)}return v}function S(e){return a(f(e))}function C(e){return`r`in e&&!(`v`in e)}function w(e){return`v`in e&&e.v===2}const T=`fCtx`;function E(e){if(e)try{return w(e)?!e.c||!e.m||!e.t?void 0:p({v:2,c:e.c,m:e.m,t:e.t}):d(t(e.r))}catch(t){console.error(`Error compressing Frak context`,{e:t,context:e})}}function D(t){if(!(!t||t.length===0))try{let r=S(t);if(r&&typeof r==`object`&&r.v===2)return r.c&&r.m&&r.t?{v:2,c:r.c,m:r.m,t:r.t}:void 0;let i=e(f(t),{size:20});if(n(i))return{r:i}}catch(e){console.error(`Error decompressing Frak context`,{e,context:t})}}function O({url:e}){if(!e)return null;let t=new URL(e).searchParams.get(T);return t?D(t):null}function k({url:e,context:t}){if(!e)return null;let n=E(t);if(!n)return null;let r=new URL(e);return r.searchParams.set(T,n),r.toString()}function A(e){let t=new URL(e);return t.searchParams.delete(T),t.toString()}function j({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?A(n):k({url:n,context:t}),r&&window.history.replaceState(null,``,r.toString())}const M={compress:E,decompress:D,parse:O,update:k,remove:A,replaceUrl:j},N=`__frakSdkConfig`,P=`frak-config-cache`,F=`frak-merchant-id`,I={key:P},L=typeof window<`u`;function R(){return{isResolved:!1,merchantId:``}}let z=null;function B(){if(!L)return null;try{let e=localStorage.getItem(I.key);if(!e)return null;let t=JSON.parse(e);return t.config?.isResolved?(z=t,t):null}catch{return null}}function V(){return(z??B())?.config}function H(){let e=z??B();return e?Date.now()-e.timestamp<3e4:!1}function U(e){if(!(!L||!e.isResolved))try{let t={config:e,timestamp:Date.now()};localStorage.setItem(I.key,JSON.stringify(t)),z=t}catch{}}function W(){if(L){z=null;try{localStorage.removeItem(I.key)}catch{}}}function G(){L&&(window[N]||(window[N]=V()??R()))}G();function K(){return L?window[N]??R():R()}function q(e){L&&window.dispatchEvent(new CustomEvent(`frak:config`,{detail:e}))}function J(e){return e??(L?window.location.hostname:``)}const Y=new Map,X=new Map;function Z(e,t){return`${e}:${t??``}`}async function Q(e,t,n){try{let r=x(t),i=n?`&lang=${encodeURIComponent(n)}`:``,a=await fetch(`${r}/user/merchant/resolve?domain=${encodeURIComponent(e)}${i}`);if(!a.ok){console.warn(`[Frak SDK] Merchant lookup failed for domain ${e}: ${a.status}`);return}let o=await a.json(),s=Z(e,n);if(Y.set(s,o),L)try{sessionStorage.setItem(F,o.merchantId)}catch{}return o}catch(e){console.warn(`[Frak SDK] Failed to fetch merchant config:`,e);return}}const $={getConfig:K,get isResolved(){return K().isResolved},get isCacheFresh(){return H()},setCacheScope(e,t){I.key=`${P}:${`${e}:${t??``}`}`,z=null},setConfig(e){if(L&&(window[N]=e),U(e),q(e),L&&e.merchantId)try{sessionStorage.setItem(F,e.merchantId)}catch{}},reset(){let e=V()??R();L&&(window[N]=e),q(e)},clearCache(){if(W(),Y.clear(),X.clear(),L)try{sessionStorage.removeItem(F)}catch{}},resolve(e,t,n){let r=J(e);if(!r)return Promise.resolve(void 0);let i=Z(r,n);if(Y.has(i))return Promise.resolve(Y.get(i));let a=X.get(i);if(a)return a;let o=Q(r,t,n).then(e=>(X.delete(i),e));return X.set(i,o),o},getMerchantId(){let e=K();if(e.isResolved&&e.merchantId)return e.merchantId;if(L)try{return sessionStorage.getItem(F)??void 0}catch{}},async resolveMerchantId(e,t){return $.getMerchantId()||(await $.resolve(e,t))?.merchantId}};function te(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{w as a,_ as c,m as d,p as f,l as g,u as h,C as i,h as l,d as m,$ as n,S as o,f as p,M as r,x as s,te as t,g as u};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let e=require(`viem`),t=require(`@frak-labs/frame-connector`);const n=`frak-client-id`;function r(){return typeof crypto<`u`&&crypto.randomUUID?crypto.randomUUID():`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e===`x`?t:t&3|8).toString(16)})}function i(){if(typeof window>`u`||!window.localStorage)return console.warn(`[Frak SDK] No Window / localStorage available to save the clientId`),r();let e=localStorage.getItem(n);return e||(e=r(),localStorage.setItem(n,e)),e}function a({domain:t}={}){return(0,e.keccak256)((0,e.toHex)((t??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((0,t.jsonEncode)(e))}function l(e,t,n,r,i,a){let o=c(u({redirectUrl:t.redirectUrl,directExit:t.directExit,lang:t.lang,merchantId:n,metadata:{name:r,css:a,logoUrl:t.metadata?.logoUrl,homepageLink:t.metadata?.homepageLink},clientId:i})),s=new URL(e);return s.pathname=`/sso`,s.searchParams.set(`p`,o),s.toString()}function u(e){return{r:e.redirectUrl,cId:e.clientId,d:e.directExit,l:e.lang,m:e.merchantId,md:{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:o}=e.config;if(t.openInSameWindow??!!t.redirectUrl)return await e.request({method:`frak_openSso`,params:[t,n.name,r?.css]});let s=t.ssoPopupUrl??l(o??`https://wallet.frak.id`,t,a(),n.name,i(),r?.css),c=window.open(s,f,d);if(!c)throw Error(`Popup was blocked. Please allow popups for this site.`);return c.focus(),await e.request({method:`frak_openSso`,params:[t,n.name,r?.css]})??{}}const m=`https://backend.frak.id`;function h(e){return e.includes(`localhost:3000`)||e.includes(`localhost:3010`)}function g(e){return h(e)?`https://localhost:3030`:e.includes(`wallet-dev.frak.id`)||e.includes(`wallet.gcp-dev.frak.id`)?`https://backend.gcp-dev.frak.id`:m}function _(e){if(e)return g(e);if(typeof window<`u`){let e=window.FrakSetup?.client?.config?.walletUrl;if(e)return g(e)}return m}function v(e){return(0,t.jsonDecode)(s(e))}function y(e){return`r`in e&&!(`v`in e)}function b(e){return`v`in e&&e.v===2}const x=`fCtx`;function S(t){if(t)try{return b(t)?!t.c||!t.m||!t.t?void 0:c({v:2,c:t.c,m:t.m,t:t.t}):o((0,e.hexToBytes)(t.r))}catch(e){console.error(`Error compressing Frak context`,{e,context:t})}}function C(t){if(!(!t||t.length===0))try{let n=v(t);if(n&&typeof n==`object`&&n.v===2)return n.c&&n.m&&n.t?{v:2,c:n.c,m:n.m,t:n.t}:void 0;let r=(0,e.bytesToHex)(s(t),{size:20});if((0,e.isAddress)(r))return{r}}catch(e){console.error(`Error decompressing Frak context`,{e,context:t})}}function w({url:e}){if(!e)return null;let t=new URL(e).searchParams.get(x);return t?C(t):null}function T({url:e,context:t}){if(!e)return null;let n=S(t);if(!n)return null;let r=new URL(e);return r.searchParams.set(x,n),r.toString()}function E(e){let t=new URL(e);return t.searchParams.delete(x),t.toString()}function D({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?E(n):T({url:n,context:t}),r&&window.history.replaceState(null,``,r.toString())}const O={compress:S,decompress:C,parse:w,update:T,remove:E,replaceUrl:D},k=`__frakSdkConfig`,A=`frak-config-cache`,j=`frak-merchant-id`,M={key:A},N=typeof window<`u`;function P(){return{isResolved:!1,merchantId:``}}let F=null;function I(){if(!N)return null;try{let e=localStorage.getItem(M.key);if(!e)return null;let t=JSON.parse(e);return t.config?.isResolved?(F=t,t):null}catch{return null}}function L(){return(F??I())?.config}function R(){let e=F??I();return e?Date.now()-e.timestamp<3e4:!1}function z(e){if(!(!N||!e.isResolved))try{let t={config:e,timestamp:Date.now()};localStorage.setItem(M.key,JSON.stringify(t)),F=t}catch{}}function B(){if(N){F=null;try{localStorage.removeItem(M.key)}catch{}}}function V(){N&&(window[k]||(window[k]=L()??P()))}V();function H(){return N?window[k]??P():P()}function U(e){N&&window.dispatchEvent(new CustomEvent(`frak:config`,{detail:e}))}function W(e){return e??(N?window.location.hostname:``)}const G=new Map,K=new Map;function q(e,t){return`${e}:${t??``}`}async function J(e,t,n){try{let r=_(t),i=n?`&lang=${encodeURIComponent(n)}`:``,a=await fetch(`${r}/user/merchant/resolve?domain=${encodeURIComponent(e)}${i}`);if(!a.ok){console.warn(`[Frak SDK] Merchant lookup failed for domain ${e}: ${a.status}`);return}let o=await a.json(),s=q(e,n);if(G.set(s,o),N)try{sessionStorage.setItem(j,o.merchantId)}catch{}return o}catch(e){console.warn(`[Frak SDK] Failed to fetch merchant config:`,e);return}}const Y={getConfig:H,get isResolved(){return H().isResolved},get isCacheFresh(){return R()},setCacheScope(e,t){M.key=`${A}:${`${e}:${t??``}`}`,F=null},setConfig(e){if(N&&(window[k]=e),z(e),U(e),N&&e.merchantId)try{sessionStorage.setItem(j,e.merchantId)}catch{}},reset(){let e=L()??P();N&&(window[k]=e),U(e)},clearCache(){if(B(),G.clear(),K.clear(),N)try{sessionStorage.removeItem(j)}catch{}},resolve(e,t,n){let r=W(e);if(!r)return Promise.resolve(void 0);let i=q(r,n);if(G.has(i))return Promise.resolve(G.get(i));let a=K.get(i);if(a)return a;let o=J(r,t,n).then(e=>(K.delete(i),e));return K.set(i,o),o},getMerchantId(){let e=H();if(e.isResolved&&e.merchantId)return e.merchantId;if(N)try{return sessionStorage.getItem(j)??void 0}catch{}},async resolveMerchantId(e,t){return Y.getMerchantId()||(await Y.resolve(e,t))?.merchantId}};function X(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 b}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,`g`,{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return Y}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return X}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return f}});
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"url": "https://twitter.com/QNivelais"
|
|
12
12
|
}
|
|
13
13
|
],
|
|
14
|
-
"version": "0.2.1-beta.
|
|
14
|
+
"version": "0.2.1-beta.d2556d47",
|
|
15
15
|
"description": "Core SDK of the Frak wallet, low level library to interact directly with the frak ecosystem.",
|
|
16
16
|
"repository": {
|
|
17
17
|
"url": "https://github.com/frak-id/wallet",
|
|
@@ -91,22 +91,22 @@
|
|
|
91
91
|
"viem": "^2.x"
|
|
92
92
|
},
|
|
93
93
|
"dependencies": {
|
|
94
|
-
"@frak-labs/frame-connector": "0.2.0-beta.
|
|
95
|
-
"@openpanel/web": "^1.0
|
|
94
|
+
"@frak-labs/frame-connector": "0.2.0-beta.d2556d47",
|
|
95
|
+
"@openpanel/web": "^1.2.0"
|
|
96
96
|
},
|
|
97
97
|
"devDependencies": {
|
|
98
98
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
99
99
|
"@frak-labs/dev-tooling": "0.0.0",
|
|
100
100
|
"@frak-labs/test-foundation": "0.1.0",
|
|
101
101
|
"@rolldown/plugin-node-polyfills": "^1.0.3",
|
|
102
|
-
"@types/jsdom": "^
|
|
102
|
+
"@types/jsdom": "^28.0.0",
|
|
103
103
|
"@types/node": "^24.10.13",
|
|
104
|
-
"@vitest/coverage-v8": "^4.0
|
|
105
|
-
"@vitest/ui": "^4.0
|
|
106
|
-
"jsdom": "^
|
|
104
|
+
"@vitest/coverage-v8": "^4.1.0",
|
|
105
|
+
"@vitest/ui": "^4.1.0",
|
|
106
|
+
"jsdom": "^29.0.0",
|
|
107
107
|
"tsdown": "^0.20.3",
|
|
108
108
|
"typescript": "^5.9.3",
|
|
109
109
|
"viem": "^2.39.0",
|
|
110
|
-
"vitest": "^4.0
|
|
110
|
+
"vitest": "^4.1.0"
|
|
111
111
|
}
|
|
112
112
|
}
|
|
@@ -8,14 +8,18 @@ import type {
|
|
|
8
8
|
* Function used to display the Frak embedded wallet popup
|
|
9
9
|
* @param client - The current Frak Client
|
|
10
10
|
* @param params - The parameter used to customise the embedded wallet
|
|
11
|
+
* @param placement - Optional placement ID to associate with this display request
|
|
11
12
|
* @returns The embedded wallet display result
|
|
12
13
|
*/
|
|
13
14
|
export async function displayEmbeddedWallet(
|
|
14
15
|
client: FrakClient,
|
|
15
|
-
params: DisplayEmbeddedWalletParamsType
|
|
16
|
+
params: DisplayEmbeddedWalletParamsType,
|
|
17
|
+
placement?: string
|
|
16
18
|
): Promise<DisplayEmbeddedWalletResultType> {
|
|
17
19
|
return await client.request({
|
|
18
20
|
method: "frak_displayEmbeddedWallet",
|
|
19
|
-
params:
|
|
21
|
+
params: placement
|
|
22
|
+
? [params, client.config.metadata, placement]
|
|
23
|
+
: [params, client.config.metadata],
|
|
20
24
|
});
|
|
21
25
|
}
|
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
* @param args
|
|
12
12
|
* @param args.steps - The different steps of the modal
|
|
13
13
|
* @param args.metadata - The metadata for the modal (customization, etc)
|
|
14
|
+
* @param placement - Optional placement ID to associate with this modal display
|
|
14
15
|
* @returns The result of each modal steps
|
|
15
16
|
*
|
|
16
17
|
* @description This function will display a modal to the user with the provided steps and metadata.
|
|
@@ -111,10 +112,13 @@ export async function displayModal<
|
|
|
111
112
|
T extends ModalStepTypes[] = ModalStepTypes[],
|
|
112
113
|
>(
|
|
113
114
|
client: FrakClient,
|
|
114
|
-
{ steps, metadata }: DisplayModalParamsType<T
|
|
115
|
+
{ steps, metadata }: DisplayModalParamsType<T>,
|
|
116
|
+
placement?: string
|
|
115
117
|
): Promise<ModalRpcStepsResultType<T>> {
|
|
116
118
|
return (await client.request({
|
|
117
119
|
method: "frak_displayModal",
|
|
118
|
-
params:
|
|
120
|
+
params: placement
|
|
121
|
+
? [steps, metadata, client.config.metadata, placement]
|
|
122
|
+
: [steps, metadata, client.config.metadata],
|
|
119
123
|
})) as ModalRpcStepsResultType<T>;
|
|
120
124
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getBackendUrl } from "../utils/backendUrl";
|
|
2
2
|
import { getClientId } from "../utils/clientId";
|
|
3
|
-
import {
|
|
3
|
+
import { sdkConfigStore } from "../utils/sdkConfigStore";
|
|
4
4
|
|
|
5
5
|
const ENSURE_STORAGE_PREFIX = "frak-identity-ensured-";
|
|
6
6
|
|
|
@@ -36,7 +36,7 @@ export async function ensureIdentity(interactionToken: string): Promise<void> {
|
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
const merchantId = await
|
|
39
|
+
const merchantId = await sdkConfigStore.resolveMerchantId();
|
|
40
40
|
if (!merchantId) {
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
@@ -11,12 +11,14 @@ vi.mock("../utils/clientId", () => ({
|
|
|
11
11
|
getClientId: vi.fn().mockReturnValue("test-client-id"),
|
|
12
12
|
}));
|
|
13
13
|
|
|
14
|
-
vi.mock("../utils/
|
|
15
|
-
|
|
14
|
+
vi.mock("../utils/sdkConfigStore", () => ({
|
|
15
|
+
sdkConfigStore: {
|
|
16
|
+
resolveMerchantId: vi.fn().mockResolvedValue(undefined),
|
|
17
|
+
},
|
|
16
18
|
}));
|
|
17
19
|
|
|
18
20
|
import { getClientId } from "../utils/clientId";
|
|
19
|
-
import {
|
|
21
|
+
import { sdkConfigStore } from "../utils/sdkConfigStore";
|
|
20
22
|
import { trackPurchaseStatus } from "./trackPurchaseStatus";
|
|
21
23
|
|
|
22
24
|
describe.sequential("trackPurchaseStatus", () => {
|
|
@@ -100,7 +102,9 @@ describe.sequential("trackPurchaseStatus", () => {
|
|
|
100
102
|
});
|
|
101
103
|
|
|
102
104
|
vi.mocked(getClientId).mockReturnValue("test-client-id");
|
|
103
|
-
vi.mocked(
|
|
105
|
+
vi.mocked(sdkConfigStore.resolveMerchantId).mockResolvedValue(
|
|
106
|
+
undefined
|
|
107
|
+
);
|
|
104
108
|
|
|
105
109
|
fetchSpy = vi.fn().mockResolvedValue({
|
|
106
110
|
ok: true,
|
|
@@ -228,12 +232,15 @@ describe.sequential("trackPurchaseStatus", () => {
|
|
|
228
232
|
test("should resolve merchantId from explicit param first", async () => {
|
|
229
233
|
setupStorage({
|
|
230
234
|
interactionToken: "token-123",
|
|
231
|
-
merchantId:
|
|
235
|
+
merchantId: null,
|
|
232
236
|
clientId: "test-client-id",
|
|
233
237
|
});
|
|
234
|
-
vi.mocked(
|
|
235
|
-
|
|
236
|
-
|
|
238
|
+
vi.mocked(sdkConfigStore.resolveMerchantId).mockResolvedValue(
|
|
239
|
+
"fetched-merchant-id"
|
|
240
|
+
);
|
|
241
|
+
const merchantLookupCallsBefore = vi.mocked(
|
|
242
|
+
sdkConfigStore.resolveMerchantId
|
|
243
|
+
).mock.calls.length;
|
|
237
244
|
|
|
238
245
|
await trackPurchaseStatus({
|
|
239
246
|
customerId: "cust-1",
|
|
@@ -253,19 +260,20 @@ describe.sequential("trackPurchaseStatus", () => {
|
|
|
253
260
|
merchantId: "explicit-merchant-id",
|
|
254
261
|
})
|
|
255
262
|
);
|
|
256
|
-
expect(
|
|
257
|
-
|
|
258
|
-
);
|
|
263
|
+
expect(
|
|
264
|
+
vi.mocked(sdkConfigStore.resolveMerchantId).mock.calls.length
|
|
265
|
+
).toBe(merchantLookupCallsBefore);
|
|
259
266
|
});
|
|
260
267
|
|
|
261
268
|
test("should fall back to sessionStorage for merchantId", async () => {
|
|
269
|
+
vi.mocked(sdkConfigStore.resolveMerchantId).mockResolvedValue(
|
|
270
|
+
"session-merchant-id"
|
|
271
|
+
);
|
|
262
272
|
setupStorage({
|
|
263
273
|
interactionToken: "token-123",
|
|
264
|
-
merchantId:
|
|
274
|
+
merchantId: null,
|
|
265
275
|
clientId: "test-client-id",
|
|
266
276
|
});
|
|
267
|
-
const merchantLookupCallsBefore =
|
|
268
|
-
vi.mocked(fetchMerchantId).mock.calls.length;
|
|
269
277
|
|
|
270
278
|
await trackPurchaseStatus({
|
|
271
279
|
customerId: "cust-1",
|
|
@@ -284,18 +292,20 @@ describe.sequential("trackPurchaseStatus", () => {
|
|
|
284
292
|
merchantId: "session-merchant-id",
|
|
285
293
|
})
|
|
286
294
|
);
|
|
287
|
-
expect(
|
|
288
|
-
|
|
289
|
-
);
|
|
295
|
+
expect(
|
|
296
|
+
vi.mocked(sdkConfigStore.resolveMerchantId)
|
|
297
|
+
).toHaveBeenCalled();
|
|
290
298
|
});
|
|
291
299
|
|
|
292
|
-
test("should fall back to
|
|
300
|
+
test("should fall back to resolveMerchantId when no explicit merchantId", async () => {
|
|
293
301
|
setupStorage({
|
|
294
302
|
interactionToken: "token-123",
|
|
295
303
|
merchantId: null,
|
|
296
304
|
clientId: "test-client-id",
|
|
297
305
|
});
|
|
298
|
-
vi.mocked(
|
|
306
|
+
vi.mocked(sdkConfigStore.resolveMerchantId).mockResolvedValue(
|
|
307
|
+
"fetched-merchant-id"
|
|
308
|
+
);
|
|
299
309
|
|
|
300
310
|
await trackPurchaseStatus({
|
|
301
311
|
customerId: "cust-1",
|
|
@@ -322,7 +332,9 @@ describe.sequential("trackPurchaseStatus", () => {
|
|
|
322
332
|
merchantId: null,
|
|
323
333
|
clientId: "test-client-id",
|
|
324
334
|
});
|
|
325
|
-
vi.mocked(
|
|
335
|
+
vi.mocked(sdkConfigStore.resolveMerchantId).mockResolvedValue(
|
|
336
|
+
undefined
|
|
337
|
+
);
|
|
326
338
|
const callCountBefore = getTrackingRequests().length;
|
|
327
339
|
|
|
328
340
|
await trackPurchaseStatus({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getBackendUrl } from "../utils/backendUrl";
|
|
2
2
|
import { getClientId } from "../utils/clientId";
|
|
3
|
-
import {
|
|
3
|
+
import { sdkConfigStore } from "../utils/sdkConfigStore";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Function used to track the status of a purchase
|
|
@@ -26,7 +26,7 @@ import { fetchMerchantId } from "../utils/merchantId";
|
|
|
26
26
|
* }
|
|
27
27
|
*
|
|
28
28
|
* @remarks
|
|
29
|
-
* - Merchant id is resolved in this order: explicit `args.merchantId`, `
|
|
29
|
+
* - Merchant id is resolved in this order: explicit `args.merchantId`, then `sdkConfigStore.resolveMerchantId()` (config store → sessionStorage → backend fetch).
|
|
30
30
|
* - This function supports anonymous users and will use the `x-frak-client-id` header when available.
|
|
31
31
|
* - At least one identity source must exist (`frak-wallet-interaction-token` or `x-frak-client-id`), otherwise the tracking request is skipped.
|
|
32
32
|
* - This function will print a warning if used in a non-browser environment or if no identity / merchant id can be resolved.
|
|
@@ -52,10 +52,8 @@ export async function trackPurchaseStatus(args: {
|
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
const merchantIdFromStorage =
|
|
56
|
-
window.sessionStorage.getItem("frak-merchant-id");
|
|
57
55
|
const merchantId =
|
|
58
|
-
args.merchantId ??
|
|
56
|
+
args.merchantId ?? (await sdkConfigStore.resolveMerchantId());
|
|
59
57
|
|
|
60
58
|
if (!merchantId) {
|
|
61
59
|
console.warn("[Frak] No merchant id found, skipping purchase check");
|
|
@@ -196,7 +196,8 @@ describe("modalBuilder", () => {
|
|
|
196
196
|
|
|
197
197
|
expect(displayModal).toHaveBeenCalledWith(
|
|
198
198
|
mockClient,
|
|
199
|
-
builder.params
|
|
199
|
+
builder.params,
|
|
200
|
+
undefined
|
|
200
201
|
);
|
|
201
202
|
});
|
|
202
203
|
|
|
@@ -216,7 +217,8 @@ describe("modalBuilder", () => {
|
|
|
216
217
|
mockClient,
|
|
217
218
|
expect.objectContaining({
|
|
218
219
|
metadata: { header: { title: "Overridden" } },
|
|
219
|
-
})
|
|
220
|
+
}),
|
|
221
|
+
undefined
|
|
220
222
|
);
|
|
221
223
|
});
|
|
222
224
|
|
|
@@ -46,11 +46,13 @@ export type ModalStepBuilder<
|
|
|
46
46
|
/**
|
|
47
47
|
* Display the modal
|
|
48
48
|
* @param metadataOverride - Function returning optional metadata to override the current modal metadata
|
|
49
|
+
* @param placement - Optional placement ID to associate with this modal display
|
|
49
50
|
*/
|
|
50
51
|
display: (
|
|
51
52
|
metadataOverride?: (
|
|
52
53
|
current?: ModalRpcMetadata
|
|
53
|
-
) => ModalRpcMetadata | undefined
|
|
54
|
+
) => ModalRpcMetadata | undefined,
|
|
55
|
+
placement?: string
|
|
54
56
|
) => Promise<ModalRpcStepsResultType<Steps>>;
|
|
55
57
|
};
|
|
56
58
|
|
|
@@ -177,27 +179,23 @@ function modalStepsBuilder<CurrentSteps extends ModalStepTypes[]>(
|
|
|
177
179
|
);
|
|
178
180
|
}
|
|
179
181
|
|
|
180
|
-
// Function to display it
|
|
181
182
|
async function display(
|
|
182
183
|
metadataOverride?: (
|
|
183
184
|
current?: ModalRpcMetadata
|
|
184
|
-
) => ModalRpcMetadata | undefined
|
|
185
|
+
) => ModalRpcMetadata | undefined,
|
|
186
|
+
placement?: string
|
|
185
187
|
) {
|
|
186
|
-
// If we have a metadata override, apply it
|
|
187
188
|
if (metadataOverride) {
|
|
188
189
|
params.metadata = metadataOverride(params.metadata ?? {});
|
|
189
190
|
}
|
|
190
|
-
return await displayModal(client, params);
|
|
191
|
+
return await displayModal(client, params, placement);
|
|
191
192
|
}
|
|
192
193
|
|
|
193
194
|
return {
|
|
194
|
-
// Access current modal params
|
|
195
195
|
params,
|
|
196
|
-
// Function to add new steps
|
|
197
196
|
sendTx,
|
|
198
197
|
reward,
|
|
199
198
|
sharing,
|
|
200
|
-
// Display the modal
|
|
201
199
|
display,
|
|
202
200
|
};
|
|
203
201
|
}
|