@frak-labs/core-sdk 0.2.0 → 0.2.1-beta.06c52c98
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-Raks6FXg.d.cts → computeLegacyProductId-BP-ciVsp.d.cts} +73 -88
- package/dist/{computeLegacyProductId-BkyJ4rEY.d.ts → computeLegacyProductId-DiJd7RNo.d.ts} +73 -88
- 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-BCJGchIb.d.cts → openSso-B8v3Vtnh.d.ts} +157 -52
- package/dist/{openSso-DG-_9CED.d.ts → openSso-n_B4LSuW.d.cts} +157 -52
- 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-Btem4QHs.d.ts → siweAuthenticate-CDCsp8EJ.d.ts} +35 -36
- package/dist/siweAuthenticate-CfQibjZR.cjs +1 -0
- package/dist/{siweAuthenticate-BH7Dn7nZ.d.cts → siweAuthenticate-yITE-iKh.d.cts} +35 -36
- 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/referral/processReferral.test.ts +109 -125
- package/src/actions/referral/processReferral.ts +134 -180
- package/src/actions/referral/referralInteraction.test.ts +3 -5
- package/src/actions/referral/referralInteraction.ts +2 -7
- 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 +8 -3
- package/src/types/config.ts +10 -3
- package/src/types/context.ts +48 -6
- package/src/types/index.ts +8 -2
- 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 +9 -0
- package/src/types/rpc.ts +7 -5
- package/src/types/tracking.ts +5 -34
- package/src/utils/FrakContext.test.ts +270 -186
- package/src/utils/FrakContext.ts +78 -56
- 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-CQrMDGyZ.js +0 -13
- package/dist/setupClient-Ccv3XxwL.cjs +0 -13
- package/dist/siweAuthenticate-BJHbtty4.js +0 -1
- package/dist/siweAuthenticate-Cwj3HP0m.cjs +0 -1
- package/dist/trackEvent-M2RLTQ2p.js +0 -1
- package/dist/trackEvent-T_R9ER2S.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
|
|
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
|
/**
|
|
@@ -188,61 +190,60 @@ declare function prepareSso(client: FrakClient, args: PrepareSsoParamsType): Pro
|
|
|
188
190
|
//#endregion
|
|
189
191
|
//#region src/actions/referral/processReferral.d.ts
|
|
190
192
|
/**
|
|
191
|
-
*
|
|
192
|
-
* @inline
|
|
193
|
-
*/
|
|
194
|
-
type ReferralState = "idle" | "processing" | "success" | "no-wallet" | "error" | "no-referrer" | "self-referral";
|
|
195
|
-
/**
|
|
196
|
-
* Options for the referral auto-interaction process
|
|
193
|
+
* Options for the referral auto-interaction process.
|
|
197
194
|
*/
|
|
198
195
|
type ProcessReferralOptions = {
|
|
199
196
|
/**
|
|
200
|
-
* If
|
|
197
|
+
* If true, always replace the URL with the current user's referral context
|
|
198
|
+
* so the next visitor gets referred by this user.
|
|
201
199
|
* @defaultValue false
|
|
202
200
|
*/
|
|
203
201
|
alwaysAppendUrl?: boolean;
|
|
202
|
+
/**
|
|
203
|
+
* Merchant ID for building the current user's referral context.
|
|
204
|
+
* Required when `alwaysAppendUrl` is true and the incoming context is V1.
|
|
205
|
+
* For V2 contexts, the merchantId is already embedded in the context.
|
|
206
|
+
*/
|
|
207
|
+
merchantId?: string;
|
|
204
208
|
};
|
|
205
209
|
/**
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
*
|
|
212
|
-
* 5. Update the current url with the right data
|
|
213
|
-
* 6. Return the resulting referral state
|
|
210
|
+
* The different states of the referral process.
|
|
211
|
+
* @inline
|
|
212
|
+
*/
|
|
213
|
+
type ReferralState = "idle" | "processing" | "success" | "no-referrer" | "self-referral";
|
|
214
|
+
/**
|
|
215
|
+
* Handle the full referral interaction flow:
|
|
214
216
|
*
|
|
215
|
-
*
|
|
217
|
+
* 1. Check if the user has been referred (if not, early exit)
|
|
218
|
+
* 2. Preflight self-referral check (if yes, early exit)
|
|
219
|
+
* 3. Track the arrival event
|
|
220
|
+
* 4. Replace the current URL with the user's own referral context
|
|
221
|
+
* 5. Return the resulting referral state
|
|
216
222
|
*
|
|
217
223
|
* @param client - The current Frak Client
|
|
218
224
|
* @param args
|
|
219
225
|
* @param args.walletStatus - The current user wallet status
|
|
220
|
-
* @param args.frakContext - The
|
|
221
|
-
* @param args.
|
|
222
|
-
* @
|
|
223
|
-
* @returns A promise with the resulting referral state
|
|
226
|
+
* @param args.frakContext - The referral context parsed from the URL
|
|
227
|
+
* @param args.options - Options for URL replacement and merchant context
|
|
228
|
+
* @returns The referral state
|
|
224
229
|
*
|
|
225
|
-
* @see {@link
|
|
226
|
-
* @see {@link @frak-labs/core-sdk!ModalStepTypes} for more details on each modal steps types
|
|
230
|
+
* @see {@link @frak-labs/core-sdk!ModalStepTypes} for modal step types
|
|
227
231
|
*/
|
|
228
232
|
declare function processReferral(client: FrakClient, {
|
|
229
233
|
walletStatus,
|
|
230
234
|
frakContext,
|
|
231
|
-
modalConfig,
|
|
232
235
|
options
|
|
233
236
|
}: {
|
|
234
237
|
walletStatus?: WalletStatusReturnType;
|
|
235
|
-
frakContext?:
|
|
236
|
-
modalConfig?: DisplayEmbeddedWalletParamsType;
|
|
238
|
+
frakContext?: FrakContext | null;
|
|
237
239
|
options?: ProcessReferralOptions;
|
|
238
|
-
}):
|
|
240
|
+
}): ReferralState;
|
|
239
241
|
//#endregion
|
|
240
242
|
//#region src/actions/referral/referralInteraction.d.ts
|
|
241
243
|
/**
|
|
242
244
|
* Function used to handle referral interactions
|
|
243
245
|
* @param client - The current Frak Client
|
|
244
246
|
* @param args
|
|
245
|
-
* @param args.modalConfig - The modal configuration to display if the user is not logged in
|
|
246
247
|
* @param args.options - Some options for the referral interaction
|
|
247
248
|
*
|
|
248
249
|
* @returns A promise with the resulting referral state, or undefined in case of an error
|
|
@@ -250,15 +251,12 @@ declare function processReferral(client: FrakClient, {
|
|
|
250
251
|
* @description This function will automatically handle the referral interaction process
|
|
251
252
|
*
|
|
252
253
|
* @see {@link processReferral} for more details on the automatic referral handling process
|
|
253
|
-
* @see {@link @frak-labs/core-sdk!ModalStepTypes} for more details on each modal steps types
|
|
254
254
|
*/
|
|
255
255
|
declare function referralInteraction(client: FrakClient, {
|
|
256
|
-
modalConfig,
|
|
257
256
|
options
|
|
258
257
|
}?: {
|
|
259
|
-
modalConfig?: DisplayEmbeddedWalletParamsType;
|
|
260
258
|
options?: ProcessReferralOptions;
|
|
261
|
-
}): Promise<("
|
|
259
|
+
}): Promise<("idle" | "processing" | "success" | "no-referrer" | "self-referral") | undefined>;
|
|
262
260
|
//#endregion
|
|
263
261
|
//#region src/actions/sendInteraction.d.ts
|
|
264
262
|
/**
|
|
@@ -326,7 +324,7 @@ declare function sendInteraction(client: FrakClient, params: SendInteractionPara
|
|
|
326
324
|
* }
|
|
327
325
|
*
|
|
328
326
|
* @remarks
|
|
329
|
-
* - 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).
|
|
330
328
|
* - This function supports anonymous users and will use the `x-frak-client-id` header when available.
|
|
331
329
|
* - At least one identity source must exist (`frak-wallet-interaction-token` or `x-frak-client-id`), otherwise the tracking request is skipped.
|
|
332
330
|
* - This function will print a warning if used in a non-browser environment or if no identity / merchant id can be resolved.
|
|
@@ -384,8 +382,9 @@ type ModalStepBuilder<Steps extends ModalStepTypes[] = ModalStepTypes[]> = {
|
|
|
384
382
|
/**
|
|
385
383
|
* Display the modal
|
|
386
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
|
|
387
386
|
*/
|
|
388
|
-
display: (metadataOverride?: (current?: ModalRpcMetadata) => ModalRpcMetadata | undefined) => Promise<ModalRpcStepsResultType<Steps>>;
|
|
387
|
+
display: (metadataOverride?: (current?: ModalRpcMetadata) => ModalRpcMetadata | undefined, placement?: string) => Promise<ModalRpcStepsResultType<Steps>>;
|
|
389
388
|
};
|
|
390
389
|
/**
|
|
391
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.
|
|
14
|
+
"version": "0.2.1-beta.06c52c98",
|
|
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",
|
|
95
|
-
"@openpanel/web": "^1.0
|
|
94
|
+
"@frak-labs/frame-connector": "0.2.0-beta.06c52c98",
|
|
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
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { FrakRpcError, RpcErrorCodes } from "@frak-labs/frame-connector";
|
|
2
1
|
import type { Address } from "viem";
|
|
3
|
-
import { vi } from "vitest";
|
|
2
|
+
import { vi } from "vitest";
|
|
4
3
|
import {
|
|
5
4
|
afterEach,
|
|
6
5
|
beforeEach,
|
|
@@ -11,15 +10,11 @@ import {
|
|
|
11
10
|
import type {
|
|
12
11
|
FrakClient,
|
|
13
12
|
FrakContext,
|
|
13
|
+
FrakContextV2,
|
|
14
14
|
WalletStatusReturnType,
|
|
15
15
|
} from "../../types";
|
|
16
16
|
import { processReferral } from "./processReferral";
|
|
17
17
|
|
|
18
|
-
// Mock dependencies
|
|
19
|
-
vi.mock("../displayEmbeddedWallet", () => ({
|
|
20
|
-
displayEmbeddedWallet: vi.fn(),
|
|
21
|
-
}));
|
|
22
|
-
|
|
23
18
|
vi.mock("../sendInteraction", () => ({
|
|
24
19
|
sendInteraction: vi.fn().mockResolvedValue(undefined),
|
|
25
20
|
}));
|
|
@@ -30,21 +25,18 @@ vi.mock("../../utils", () => ({
|
|
|
30
25
|
},
|
|
31
26
|
trackEvent: vi.fn(),
|
|
32
27
|
resolveMerchantId: vi.fn().mockResolvedValue(undefined),
|
|
28
|
+
getClientId: vi.fn().mockReturnValue("test-client-id"),
|
|
33
29
|
}));
|
|
34
30
|
|
|
35
31
|
describe("processReferral", () => {
|
|
36
32
|
let mockClient: FrakClient;
|
|
37
33
|
let mockAddress: Address;
|
|
38
|
-
let mockReferrerAddress: Address;
|
|
39
34
|
let mockWalletStatus: WalletStatusReturnType;
|
|
40
|
-
let mockFrakContext: Partial<FrakContext>;
|
|
41
35
|
|
|
42
36
|
beforeEach(async () => {
|
|
43
37
|
vi.clearAllMocks();
|
|
44
38
|
|
|
45
39
|
mockAddress = "0x1234567890123456789012345678901234567890" as Address;
|
|
46
|
-
mockReferrerAddress =
|
|
47
|
-
"0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address;
|
|
48
40
|
|
|
49
41
|
mockClient = {
|
|
50
42
|
openPanel: {
|
|
@@ -64,11 +56,6 @@ describe("processReferral", () => {
|
|
|
64
56
|
wallet: mockAddress,
|
|
65
57
|
};
|
|
66
58
|
|
|
67
|
-
mockFrakContext = {
|
|
68
|
-
r: mockReferrerAddress,
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
// Mock window.location
|
|
72
59
|
Object.defineProperty(window, "location", {
|
|
73
60
|
value: {
|
|
74
61
|
href: "https://example.com/test",
|
|
@@ -81,15 +68,6 @@ describe("processReferral", () => {
|
|
|
81
68
|
vi.clearAllMocks();
|
|
82
69
|
});
|
|
83
70
|
|
|
84
|
-
it("should return 'no-referrer' when frakContext has no referrer", async () => {
|
|
85
|
-
const result = await processReferral(mockClient, {
|
|
86
|
-
walletStatus: mockWalletStatus,
|
|
87
|
-
frakContext: {},
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
expect(result).toBe("no-referrer");
|
|
91
|
-
});
|
|
92
|
-
|
|
93
71
|
it("should return 'no-referrer' when frakContext is null", async () => {
|
|
94
72
|
const result = await processReferral(mockClient, {
|
|
95
73
|
walletStatus: mockWalletStatus,
|
|
@@ -99,128 +77,148 @@ describe("processReferral", () => {
|
|
|
99
77
|
expect(result).toBe("no-referrer");
|
|
100
78
|
});
|
|
101
79
|
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
expect(result).toBe("self-referral");
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it("should successfully process referral when all conditions are met", async () => {
|
|
114
|
-
const utils = await import("../../utils");
|
|
80
|
+
describe("V2 context", () => {
|
|
81
|
+
const v2Context: FrakContextV2 = {
|
|
82
|
+
v: 2,
|
|
83
|
+
c: "referrer-client-id",
|
|
84
|
+
m: "merchant-uuid",
|
|
85
|
+
t: 1709654400,
|
|
86
|
+
};
|
|
115
87
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
88
|
+
it("should successfully process v2 referral", async () => {
|
|
89
|
+
const utils = await import("../../utils");
|
|
90
|
+
const { sendInteraction } = await import("../sendInteraction");
|
|
91
|
+
|
|
92
|
+
const result = await processReferral(mockClient, {
|
|
93
|
+
walletStatus: mockWalletStatus,
|
|
94
|
+
frakContext: v2Context,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
expect(result).toBe("success");
|
|
98
|
+
|
|
99
|
+
expect(utils.trackEvent).toHaveBeenCalledWith(
|
|
100
|
+
mockClient,
|
|
101
|
+
"user_referred_started",
|
|
102
|
+
{
|
|
103
|
+
properties: {
|
|
104
|
+
referrerClientId: "referrer-client-id",
|
|
105
|
+
walletStatus: "connected",
|
|
106
|
+
},
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
expect(sendInteraction).toHaveBeenCalledWith(mockClient, {
|
|
111
|
+
type: "arrival",
|
|
112
|
+
referrerClientId: "referrer-client-id",
|
|
113
|
+
referrerMerchantId: "merchant-uuid",
|
|
114
|
+
referralTimestamp: 1709654400,
|
|
115
|
+
landingUrl: "https://example.com/test",
|
|
116
|
+
});
|
|
119
117
|
});
|
|
120
118
|
|
|
121
|
-
|
|
119
|
+
it("should return 'self-referral' when v2 context has same clientId as current user", async () => {
|
|
120
|
+
const utils = await import("../../utils");
|
|
121
|
+
vi.mocked(utils.getClientId).mockReturnValue("referrer-client-id");
|
|
122
122
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
walletStatus: "connected",
|
|
130
|
-
},
|
|
131
|
-
}
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
expect(utils.trackEvent).toHaveBeenCalledWith(
|
|
135
|
-
mockClient,
|
|
136
|
-
"user_referred_completed",
|
|
137
|
-
{
|
|
138
|
-
properties: {
|
|
139
|
-
status: "success",
|
|
140
|
-
referrer: mockReferrerAddress,
|
|
141
|
-
wallet: mockAddress,
|
|
142
|
-
},
|
|
143
|
-
}
|
|
144
|
-
);
|
|
145
|
-
});
|
|
123
|
+
const v2SelfReferralContext: FrakContextV2 = {
|
|
124
|
+
v: 2,
|
|
125
|
+
c: "referrer-client-id",
|
|
126
|
+
m: "merchant-uuid",
|
|
127
|
+
t: 1709654400,
|
|
128
|
+
};
|
|
146
129
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
130
|
+
const result = await processReferral(mockClient, {
|
|
131
|
+
walletStatus: mockWalletStatus,
|
|
132
|
+
frakContext: v2SelfReferralContext,
|
|
133
|
+
});
|
|
151
134
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
wallet: mockAddress,
|
|
155
|
-
} as any);
|
|
156
|
-
|
|
157
|
-
const result = await processReferral(mockClient, {
|
|
158
|
-
walletStatus: undefined,
|
|
159
|
-
frakContext: mockFrakContext,
|
|
135
|
+
expect(result).toBe("self-referral");
|
|
136
|
+
vi.mocked(utils.getClientId).mockReturnValue("test-client-id");
|
|
160
137
|
});
|
|
161
|
-
|
|
162
|
-
expect(result).toBe("success");
|
|
163
|
-
expect(displayEmbeddedWallet).toHaveBeenCalled();
|
|
164
138
|
});
|
|
165
139
|
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
"
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const error = new FrakRpcError(
|
|
172
|
-
RpcErrorCodes.walletNotConnected,
|
|
173
|
-
"Wallet not connected"
|
|
174
|
-
);
|
|
175
|
-
vi.mocked(displayEmbeddedWallet).mockRejectedValue(error);
|
|
140
|
+
describe("V1 context (backward compat)", () => {
|
|
141
|
+
const v1Context: FrakContext = {
|
|
142
|
+
r: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd" as Address,
|
|
143
|
+
};
|
|
176
144
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
145
|
+
it("should successfully process v1 referral", async () => {
|
|
146
|
+
const utils = await import("../../utils");
|
|
147
|
+
|
|
148
|
+
const result = await processReferral(mockClient, {
|
|
149
|
+
walletStatus: mockWalletStatus,
|
|
150
|
+
frakContext: v1Context,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
expect(result).toBe("success");
|
|
154
|
+
|
|
155
|
+
expect(utils.trackEvent).toHaveBeenCalledWith(
|
|
156
|
+
mockClient,
|
|
157
|
+
"user_referred_started",
|
|
158
|
+
{
|
|
159
|
+
properties: {
|
|
160
|
+
referrer: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
|
|
161
|
+
walletStatus: "connected",
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
);
|
|
180
165
|
});
|
|
181
166
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const error = new Error("Unknown error");
|
|
191
|
-
vi.mocked(displayEmbeddedWallet).mockRejectedValue(error);
|
|
167
|
+
it("should return 'self-referral' when v1 referrer matches current wallet", async () => {
|
|
168
|
+
const result = await processReferral(mockClient, {
|
|
169
|
+
walletStatus: mockWalletStatus,
|
|
170
|
+
frakContext: {
|
|
171
|
+
r: mockAddress,
|
|
172
|
+
},
|
|
173
|
+
});
|
|
192
174
|
|
|
193
|
-
|
|
194
|
-
walletStatus: undefined,
|
|
195
|
-
frakContext: mockFrakContext,
|
|
175
|
+
expect(result).toBe("self-referral");
|
|
196
176
|
});
|
|
197
|
-
|
|
198
|
-
expect(result).toBe("error");
|
|
199
177
|
});
|
|
200
178
|
|
|
201
179
|
it("should update URL context when alwaysAppendUrl is true", async () => {
|
|
202
180
|
const utils = await import("../../utils");
|
|
203
181
|
|
|
182
|
+
const v2Context: FrakContextV2 = {
|
|
183
|
+
v: 2,
|
|
184
|
+
c: "referrer-client-id",
|
|
185
|
+
m: "merchant-uuid",
|
|
186
|
+
t: 1709654400,
|
|
187
|
+
};
|
|
188
|
+
|
|
204
189
|
await processReferral(mockClient, {
|
|
205
190
|
walletStatus: mockWalletStatus,
|
|
206
|
-
frakContext:
|
|
191
|
+
frakContext: v2Context,
|
|
207
192
|
options: {
|
|
208
193
|
alwaysAppendUrl: true,
|
|
209
194
|
},
|
|
210
195
|
});
|
|
211
196
|
|
|
197
|
+
expect(utils.getClientId()).toBe("test-client-id");
|
|
198
|
+
|
|
212
199
|
expect(utils.FrakContextManager.replaceUrl).toHaveBeenCalledWith({
|
|
213
200
|
url: window.location.href,
|
|
214
|
-
context: {
|
|
201
|
+
context: expect.objectContaining({
|
|
202
|
+
v: 2,
|
|
203
|
+
c: "test-client-id",
|
|
204
|
+
m: "merchant-uuid",
|
|
205
|
+
}),
|
|
215
206
|
});
|
|
216
207
|
});
|
|
217
208
|
|
|
218
209
|
it("should remove URL context when alwaysAppendUrl is false", async () => {
|
|
219
210
|
const utils = await import("../../utils");
|
|
220
211
|
|
|
212
|
+
const v2Context: FrakContextV2 = {
|
|
213
|
+
v: 2,
|
|
214
|
+
c: "referrer-client-id",
|
|
215
|
+
m: "merchant-uuid",
|
|
216
|
+
t: 1709654400,
|
|
217
|
+
};
|
|
218
|
+
|
|
221
219
|
await processReferral(mockClient, {
|
|
222
220
|
walletStatus: mockWalletStatus,
|
|
223
|
-
frakContext:
|
|
221
|
+
frakContext: v2Context,
|
|
224
222
|
options: {
|
|
225
223
|
alwaysAppendUrl: false,
|
|
226
224
|
},
|
|
@@ -231,18 +229,4 @@ describe("processReferral", () => {
|
|
|
231
229
|
context: null,
|
|
232
230
|
});
|
|
233
231
|
});
|
|
234
|
-
|
|
235
|
-
it("should remove URL context by default", async () => {
|
|
236
|
-
const utils = await import("../../utils");
|
|
237
|
-
|
|
238
|
-
await processReferral(mockClient, {
|
|
239
|
-
walletStatus: mockWalletStatus,
|
|
240
|
-
frakContext: mockFrakContext,
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
expect(utils.FrakContextManager.replaceUrl).toHaveBeenCalledWith({
|
|
244
|
-
url: window.location.href,
|
|
245
|
-
context: null,
|
|
246
|
-
});
|
|
247
|
-
});
|
|
248
232
|
});
|