@frak-labs/core-sdk 0.1.1-beta.f2691749 → 0.2.0-beta.514ef378
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/cdn/bundle.js +3 -3
- 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 -4
- package/dist/bundle.d.ts +4 -4
- package/dist/bundle.js +1 -1
- package/dist/{computeLegacyProductId-CSSiQO4V.d.ts → computeLegacyProductId-BkyJ4rEY.d.ts} +3 -3
- package/dist/{computeLegacyProductId-fl_Sx8v5.d.cts → computeLegacyProductId-Raks6FXg.d.cts} +3 -3
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/{openSso-CC1-loUk.d.cts → openSso-BCJGchIb.d.cts} +10 -7
- package/dist/{openSso-tkqaDQLV.d.ts → openSso-DG-_9CED.d.ts} +10 -7
- package/dist/setupClient-BEiAE56h.js +13 -0
- package/dist/setupClient-Ls3vKSlH.cjs +13 -0
- package/dist/{siweAuthenticate-CRMIfmna.d.ts → siweAuthenticate-BH7Dn7nZ.d.cts} +34 -4
- package/dist/siweAuthenticate-BJHbtty4.js +1 -0
- package/dist/{siweAuthenticate-BPqJTadR.d.cts → siweAuthenticate-Btem4QHs.d.ts} +34 -4
- package/dist/siweAuthenticate-Cwj3HP0m.cjs +1 -0
- package/dist/trackEvent-M2RLTQ2p.js +1 -0
- package/dist/trackEvent-T_R9ER2S.cjs +1 -0
- package/package.json +3 -3
- package/src/actions/ensureIdentity.ts +68 -0
- package/src/actions/index.ts +1 -0
- package/src/actions/openSso.ts +2 -0
- package/src/actions/sendInteraction.ts +2 -1
- package/src/actions/trackPurchaseStatus.test.ts +354 -141
- package/src/actions/trackPurchaseStatus.ts +45 -11
- package/src/actions/watchWalletStatus.ts +2 -2
- package/src/clients/createIFrameFrakClient.ts +3 -1
- package/src/clients/transports/iframeLifecycleManager.test.ts +2 -2
- package/src/clients/transports/iframeLifecycleManager.ts +50 -3
- package/src/types/lifecycle/client.ts +5 -5
- package/src/types/rpc.ts +6 -2
- package/src/utils/clientId.ts +3 -0
- package/src/utils/iframeHelper.test.ts +18 -5
- package/src/utils/iframeHelper.ts +4 -1
- package/src/utils/merchantId.test.ts +90 -1
- package/src/utils/merchantId.ts +22 -1
- package/src/utils/sso.ts +4 -5
- package/dist/setupClient-B-LPXmJS.js +0 -13
- package/dist/setupClient-CksNcHQl.cjs +0 -13
- package/dist/siweAuthenticate-B_Z2OZmj.cjs +0 -1
- package/dist/siweAuthenticate-CQ4OfPuA.js +0 -1
- package/dist/trackEvent-CGIryq5h.cjs +0 -1
- package/dist/trackEvent-YfUh4jrx.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as SiweAuthenticateReturnType, D as SendTransactionReturnType, E as SendTransactionModalStepType, F as PrepareSsoParamsType, I as PrepareSsoReturnType, M as LoginModalStepType, R as FinalActionType, S as ModalRpcMetadata, T as ModalStepTypes, a as FrakClient, d as GetMerchantInformationReturnType, g as DisplayEmbeddedWalletResultType, h as DisplayEmbeddedWalletParamsType, i as FrakContext, j as SiweAuthenticationParams, l as WalletStatusReturnType, m as SendInteractionParamsType, w as ModalRpcStepsResultType, x as DisplayModalParamsType, z as FinalModalStepType } from "./openSso-
|
|
1
|
+
import { A as SiweAuthenticateReturnType, D as SendTransactionReturnType, E as SendTransactionModalStepType, F as PrepareSsoParamsType, I as PrepareSsoReturnType, M as LoginModalStepType, R as FinalActionType, S as ModalRpcMetadata, T as ModalStepTypes, a as FrakClient, d as GetMerchantInformationReturnType, g as DisplayEmbeddedWalletResultType, h as DisplayEmbeddedWalletParamsType, i as FrakContext, j as SiweAuthenticationParams, l as WalletStatusReturnType, m as SendInteractionParamsType, w as ModalRpcStepsResultType, x as DisplayModalParamsType, z as FinalModalStepType } from "./openSso-BCJGchIb.cjs";
|
|
2
2
|
|
|
3
3
|
//#region src/actions/displayEmbeddedWallet.d.ts
|
|
4
4
|
/**
|
|
@@ -117,6 +117,31 @@ declare function displayModal<T extends ModalStepTypes[] = ModalStepTypes[]>(cli
|
|
|
117
117
|
metadata
|
|
118
118
|
}: DisplayModalParamsType<T>): Promise<ModalRpcStepsResultType<T>>;
|
|
119
119
|
//#endregion
|
|
120
|
+
//#region src/actions/ensureIdentity.d.ts
|
|
121
|
+
/**
|
|
122
|
+
* Ensure the current wallet ↔ clientId link exists on the backend.
|
|
123
|
+
*
|
|
124
|
+
* Called automatically by {@link watchWalletStatus} when a connected wallet
|
|
125
|
+
* status is received. Acts as a failsafe: if the primary merge (SSO, pairing,
|
|
126
|
+
* login/register) missed or silently failed, this ensures the link is
|
|
127
|
+
* eventually established.
|
|
128
|
+
*
|
|
129
|
+
* The call is:
|
|
130
|
+
* - **Idempotent** — if already linked, backend returns immediately
|
|
131
|
+
* - **Deduplicated** — only fires once per browser session per merchant
|
|
132
|
+
* - **Fire-and-forget** — errors are logged but never thrown
|
|
133
|
+
*
|
|
134
|
+
* @param interactionToken - The SDK JWT from wallet status (x-wallet-sdk-auth)
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```ts
|
|
138
|
+
* // Usually called automatically via watchWalletStatus side effect.
|
|
139
|
+
* // Can also be called manually if needed:
|
|
140
|
+
* await ensureIdentity("eyJhbGciOi...");
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
declare function ensureIdentity(interactionToken: string): Promise<void>;
|
|
144
|
+
//#endregion
|
|
120
145
|
//#region src/actions/getMerchantInformation.d.ts
|
|
121
146
|
/**
|
|
122
147
|
* Fetch the current merchant information (name, rewards, tiers) from the wallet iframe
|
|
@@ -284,6 +309,7 @@ declare function sendInteraction(client: FrakClient, params: SendInteractionPara
|
|
|
284
309
|
* @param args.customerId - The customer id that made the purchase (on your side)
|
|
285
310
|
* @param args.orderId - The order id of the purchase (on your side)
|
|
286
311
|
* @param args.token - The token of the purchase
|
|
312
|
+
* @param args.merchantId - Optional explicit merchant id to use for the tracking request
|
|
287
313
|
*
|
|
288
314
|
* @description This function will send a request to the backend to listen for the purchase status.
|
|
289
315
|
*
|
|
@@ -293,19 +319,23 @@ declare function sendInteraction(client: FrakClient, params: SendInteractionPara
|
|
|
293
319
|
* customerId: checkout.order.customer.id,
|
|
294
320
|
* orderId: checkout.order.id,
|
|
295
321
|
* token: checkout.token,
|
|
322
|
+
* merchantId: "your-merchant-id",
|
|
296
323
|
* };
|
|
297
324
|
*
|
|
298
325
|
* await trackPurchaseStatus(payload);
|
|
299
326
|
* }
|
|
300
327
|
*
|
|
301
328
|
* @remarks
|
|
302
|
-
* -
|
|
303
|
-
* - This function
|
|
329
|
+
* - Merchant id is resolved in this order: explicit `args.merchantId`, `frak-merchant-id` from session storage, then `fetchMerchantId()`.
|
|
330
|
+
* - This function supports anonymous users and will use the `x-frak-client-id` header when available.
|
|
331
|
+
* - At least one identity source must exist (`frak-wallet-interaction-token` or `x-frak-client-id`), otherwise the tracking request is skipped.
|
|
332
|
+
* - This function will print a warning if used in a non-browser environment or if no identity / merchant id can be resolved.
|
|
304
333
|
*/
|
|
305
334
|
declare function trackPurchaseStatus(args: {
|
|
306
335
|
customerId: string | number;
|
|
307
336
|
orderId: string | number;
|
|
308
337
|
token: string;
|
|
338
|
+
merchantId?: string;
|
|
309
339
|
}): Promise<void>;
|
|
310
340
|
//#endregion
|
|
311
341
|
//#region src/actions/watchWalletStatus.d.ts
|
|
@@ -503,4 +533,4 @@ declare function siweAuthenticate(client: FrakClient, {
|
|
|
503
533
|
metadata
|
|
504
534
|
}: SiweAuthenticateModalParams): Promise<SiweAuthenticateReturnType>;
|
|
505
535
|
//#endregion
|
|
506
|
-
export {
|
|
536
|
+
export { displayModal as _, ModalBuilder as a, watchWalletStatus as c, referralInteraction as d, ProcessReferralOptions as f, ensureIdentity as g, getMerchantInformation as h, sendTransaction as i, trackPurchaseStatus as l, prepareSso as m, siweAuthenticate as n, ModalStepBuilder as o, processReferral as p, SendTransactionParams as r, modalBuilder as s, SiweAuthenticateModalParams as t, sendInteraction as u, displayEmbeddedWallet as v };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as e,h as t,o as n,r,t as i}from"./trackEvent-M2RLTQ2p.js";import{isAddressEqual as a}from"viem";import{Deferred as o,FrakRpcError as s,RpcErrorCodes as c}from"@frak-labs/frame-connector";import{generateSiweNonce as l}from"viem/siwe";async function u(e,t){return await e.request({method:`frak_displayEmbeddedWallet`,params:[t,e.config.metadata]})}async function d(e,{steps:t,metadata:n}){return await e.request({method:`frak_displayModal`,params:[t,n,e.config.metadata]})}async function f(e){if(typeof window>`u`)return;let i=t();if(!i)return;let a=await r();if(!a)return;let o=`frak-identity-ensured-${a}`;if(!window.sessionStorage.getItem(o))try{let t=n();(await fetch(`${t}/user/identity/ensure`,{method:`POST`,headers:{Accept:`application/json`,"Content-Type":`application/json`,"x-wallet-sdk-auth":e,"x-frak-client-id":i},body:JSON.stringify({merchantId:a})})).ok&&window.sessionStorage.setItem(o,`1`)}catch{}}async function p(e){return await e.request({method:`frak_getMerchantInformation`})}async function m(e,t){let{metadata:n,customizations:r}=e.config;return await e.request({method:`frak_prepareSso`,params:[t,n.name,r?.css]})}async function h(e,n){try{await e.request({method:`frak_sendInteraction`,params:[n,{clientId:t()}]})}catch{console.warn(`[Frak SDK] Failed to send interaction:`,n.type)}}async function g(t,{walletStatus:n,frakContext:r,modalConfig:a,options:o}){if(!r?.r)return`no-referrer`;i(t,`user_referred_started`,{properties:{referrer:r?.r,walletStatus:n?.key}}),h(t,{type:`arrival`,referrerWallet:r.r,landingUrl:typeof window<`u`?window.location.href:void 0});let c=!1;async function l(){if(!c)return c=!0,v(t,{modalConfig:{...a,loggedIn:{action:{key:`referred`}}},walletStatus:n})}try{let{status:a,currentWallet:s}=await _({initialWalletStatus:n,getFreshWalletStatus:l,frakContext:r});return e.replaceUrl({url:window.location?.href,context:o?.alwaysAppendUrl?{r:s}:null}),i(t,`user_referred_completed`,{properties:{status:a,referrer:r?.r,wallet:s}}),a}catch(a){return console.log(`Error processing referral`,{error:a}),i(t,`user_referred_error`,{properties:{referrer:r?.r,error:a instanceof s?`[${a.code}] ${a.name} - ${a.message}`:a instanceof Error?a.message:`undefined`}}),e.replaceUrl({url:window.location?.href,context:o?.alwaysAppendUrl?{r:n?.wallet}:null}),y(a)}}async function _({initialWalletStatus:e,getFreshWalletStatus:t,frakContext:n}){let r=e?.wallet;return r||=await t(),r&&a(n.r,r)?{status:`self-referral`,currentWallet:r}:{status:`success`,currentWallet:r}}async function v(e,{modalConfig:t,walletStatus:n}){return n?.key===`connected`?n.wallet??void 0:(await u(e,t??{}))?.wallet??void 0}function y(e){if(e instanceof s)switch(e.code){case c.walletNotConnected:return`no-wallet`;default:return`error`}return`error`}async function b(t,{modalConfig:n,options:r}={}){let i=e.parse({url:window.location.href}),a=await S(t);try{return await g(t,{walletStatus:a,frakContext:i,modalConfig:n,options:r})}catch(e){console.warn(`Error processing referral`,{error:e})}}async function x(e){if(typeof window>`u`){console.warn(`[Frak] No window found, can't track purchase`);return}let i=window.sessionStorage.getItem(`frak-wallet-interaction-token`),a=t();if(!i&&!a){console.warn(`[Frak] No identity found, skipping purchase check`);return}let o=window.sessionStorage.getItem(`frak-merchant-id`),s=e.merchantId??o??await r();if(!s){console.warn(`[Frak] No merchant id found, skipping purchase check`);return}let c={Accept:`application/json`,"Content-Type":`application/json`};i&&(c[`x-wallet-sdk-auth`]=i),a&&(c[`x-frak-client-id`]=a);let l=n();await fetch(`${l}/user/track/purchase`,{method:`POST`,headers:c,body:JSON.stringify({customerId:e.customerId,orderId:e.orderId,token:e.token,merchantId:s})})}function S(e,t){if(!t)return e.request({method:`frak_listenToWalletStatus`}).then(t=>(C(e,t),t));let n=new o,r=!1;return e.listenerRequest({method:`frak_listenToWalletStatus`},i=>{C(e,i),t(i),r||=(n.resolve(i),!0)}),n.promise}function C(e,t){typeof window>`u`||(e.openPanel?.setGlobalProperties({wallet:t.wallet??null}),t.interactionToken?(window.sessionStorage.setItem(`frak-wallet-interaction-token`,t.interactionToken),f(t.interactionToken)):window.sessionStorage.removeItem(`frak-wallet-interaction-token`))}function w(e,{metadata:t,login:n}){return T(e,{steps:{login:n??{}},metadata:t})}function T(e,t){function n(n){return T(e,{...t,steps:{...t.steps,sendTransaction:n}})}function r(n){return T(e,{...t,steps:{...t.steps,final:{...n,action:{key:`reward`}}}})}function i(n,r){return T(e,{...t,steps:{...t.steps,final:{...r,action:{key:`sharing`,options:n}}}})}async function a(n){return n&&(t.metadata=n(t.metadata??{})),await d(e,t)}return{params:t,sendTx:n,reward:r,sharing:i,display:a}}async function E(e,{tx:t,metadata:n}){return(await d(e,{metadata:n,steps:{login:{},sendTransaction:{tx:t}}})).sendTransaction}async function D(e,{siwe:t,metadata:n}){let r=e.config?.domain??window.location.host,i=t?.statement??`I confirm that I want to use my Frak wallet on: ${e.config.metadata.name}`;return(await d(e,{metadata:n,steps:{login:{},siweAuthenticate:{siwe:{...t,statement:i,nonce:t?.nonce??l(),uri:t?.uri??`https://${r}`,version:t?.version??`1`,domain:r}}}})).siweAuthenticate}export{x as a,h as c,f as d,d as f,S as i,m as l,E as n,b as o,u as p,w as r,g as s,D as t,p as u};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as SiweAuthenticateReturnType, D as SendTransactionReturnType, E as SendTransactionModalStepType, F as PrepareSsoParamsType, I as PrepareSsoReturnType, M as LoginModalStepType, R as FinalActionType, S as ModalRpcMetadata, T as ModalStepTypes, a as FrakClient, d as GetMerchantInformationReturnType, g as DisplayEmbeddedWalletResultType, h as DisplayEmbeddedWalletParamsType, i as FrakContext, j as SiweAuthenticationParams, l as WalletStatusReturnType, m as SendInteractionParamsType, w as ModalRpcStepsResultType, x as DisplayModalParamsType, z as FinalModalStepType } from "./openSso-
|
|
1
|
+
import { A as SiweAuthenticateReturnType, D as SendTransactionReturnType, E as SendTransactionModalStepType, F as PrepareSsoParamsType, I as PrepareSsoReturnType, M as LoginModalStepType, R as FinalActionType, S as ModalRpcMetadata, T as ModalStepTypes, a as FrakClient, d as GetMerchantInformationReturnType, g as DisplayEmbeddedWalletResultType, h as DisplayEmbeddedWalletParamsType, i as FrakContext, j as SiweAuthenticationParams, l as WalletStatusReturnType, m as SendInteractionParamsType, w as ModalRpcStepsResultType, x as DisplayModalParamsType, z as FinalModalStepType } from "./openSso-DG-_9CED.js";
|
|
2
2
|
|
|
3
3
|
//#region src/actions/displayEmbeddedWallet.d.ts
|
|
4
4
|
/**
|
|
@@ -117,6 +117,31 @@ declare function displayModal<T extends ModalStepTypes[] = ModalStepTypes[]>(cli
|
|
|
117
117
|
metadata
|
|
118
118
|
}: DisplayModalParamsType<T>): Promise<ModalRpcStepsResultType<T>>;
|
|
119
119
|
//#endregion
|
|
120
|
+
//#region src/actions/ensureIdentity.d.ts
|
|
121
|
+
/**
|
|
122
|
+
* Ensure the current wallet ↔ clientId link exists on the backend.
|
|
123
|
+
*
|
|
124
|
+
* Called automatically by {@link watchWalletStatus} when a connected wallet
|
|
125
|
+
* status is received. Acts as a failsafe: if the primary merge (SSO, pairing,
|
|
126
|
+
* login/register) missed or silently failed, this ensures the link is
|
|
127
|
+
* eventually established.
|
|
128
|
+
*
|
|
129
|
+
* The call is:
|
|
130
|
+
* - **Idempotent** — if already linked, backend returns immediately
|
|
131
|
+
* - **Deduplicated** — only fires once per browser session per merchant
|
|
132
|
+
* - **Fire-and-forget** — errors are logged but never thrown
|
|
133
|
+
*
|
|
134
|
+
* @param interactionToken - The SDK JWT from wallet status (x-wallet-sdk-auth)
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```ts
|
|
138
|
+
* // Usually called automatically via watchWalletStatus side effect.
|
|
139
|
+
* // Can also be called manually if needed:
|
|
140
|
+
* await ensureIdentity("eyJhbGciOi...");
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
declare function ensureIdentity(interactionToken: string): Promise<void>;
|
|
144
|
+
//#endregion
|
|
120
145
|
//#region src/actions/getMerchantInformation.d.ts
|
|
121
146
|
/**
|
|
122
147
|
* Fetch the current merchant information (name, rewards, tiers) from the wallet iframe
|
|
@@ -284,6 +309,7 @@ declare function sendInteraction(client: FrakClient, params: SendInteractionPara
|
|
|
284
309
|
* @param args.customerId - The customer id that made the purchase (on your side)
|
|
285
310
|
* @param args.orderId - The order id of the purchase (on your side)
|
|
286
311
|
* @param args.token - The token of the purchase
|
|
312
|
+
* @param args.merchantId - Optional explicit merchant id to use for the tracking request
|
|
287
313
|
*
|
|
288
314
|
* @description This function will send a request to the backend to listen for the purchase status.
|
|
289
315
|
*
|
|
@@ -293,19 +319,23 @@ declare function sendInteraction(client: FrakClient, params: SendInteractionPara
|
|
|
293
319
|
* customerId: checkout.order.customer.id,
|
|
294
320
|
* orderId: checkout.order.id,
|
|
295
321
|
* token: checkout.token,
|
|
322
|
+
* merchantId: "your-merchant-id",
|
|
296
323
|
* };
|
|
297
324
|
*
|
|
298
325
|
* await trackPurchaseStatus(payload);
|
|
299
326
|
* }
|
|
300
327
|
*
|
|
301
328
|
* @remarks
|
|
302
|
-
* -
|
|
303
|
-
* - This function
|
|
329
|
+
* - Merchant id is resolved in this order: explicit `args.merchantId`, `frak-merchant-id` from session storage, then `fetchMerchantId()`.
|
|
330
|
+
* - This function supports anonymous users and will use the `x-frak-client-id` header when available.
|
|
331
|
+
* - At least one identity source must exist (`frak-wallet-interaction-token` or `x-frak-client-id`), otherwise the tracking request is skipped.
|
|
332
|
+
* - This function will print a warning if used in a non-browser environment or if no identity / merchant id can be resolved.
|
|
304
333
|
*/
|
|
305
334
|
declare function trackPurchaseStatus(args: {
|
|
306
335
|
customerId: string | number;
|
|
307
336
|
orderId: string | number;
|
|
308
337
|
token: string;
|
|
338
|
+
merchantId?: string;
|
|
309
339
|
}): Promise<void>;
|
|
310
340
|
//#endregion
|
|
311
341
|
//#region src/actions/watchWalletStatus.d.ts
|
|
@@ -503,4 +533,4 @@ declare function siweAuthenticate(client: FrakClient, {
|
|
|
503
533
|
metadata
|
|
504
534
|
}: SiweAuthenticateModalParams): Promise<SiweAuthenticateReturnType>;
|
|
505
535
|
//#endregion
|
|
506
|
-
export {
|
|
536
|
+
export { displayModal as _, ModalBuilder as a, watchWalletStatus as c, referralInteraction as d, ProcessReferralOptions as f, ensureIdentity as g, getMerchantInformation as h, sendTransaction as i, trackPurchaseStatus as l, prepareSso as m, siweAuthenticate as n, ModalStepBuilder as o, processReferral as p, SendTransactionParams as r, modalBuilder as s, SiweAuthenticateModalParams as t, sendInteraction as u, displayEmbeddedWallet as v };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=require(`./trackEvent-T_R9ER2S.cjs`);let t=require(`viem`),n=require(`@frak-labs/frame-connector`),r=require(`viem/siwe`);async function i(e,t){return await e.request({method:`frak_displayEmbeddedWallet`,params:[t,e.config.metadata]})}async function a(e,{steps:t,metadata:n}){return await e.request({method:`frak_displayModal`,params:[t,n,e.config.metadata]})}async function o(t){if(typeof window>`u`)return;let n=e.h();if(!n)return;let r=await e.r();if(!r)return;let i=`frak-identity-ensured-${r}`;if(!window.sessionStorage.getItem(i))try{let a=e.o();(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.h()}]})}catch{console.warn(`[Frak SDK] Failed to send interaction:`,n.type)}}async function u(t,{walletStatus:r,frakContext:i,modalConfig:a,options:o}){if(!i?.r)return`no-referrer`;e.t(t,`user_referred_started`,{properties:{referrer:i?.r,walletStatus:r?.key}}),l(t,{type:`arrival`,referrerWallet:i.r,landingUrl:typeof window<`u`?window.location.href:void 0});let s=!1;async function c(){if(!s)return s=!0,f(t,{modalConfig:{...a,loggedIn:{action:{key:`referred`}}},walletStatus:r})}try{let{status:n,currentWallet:a}=await d({initialWalletStatus:r,getFreshWalletStatus:c,frakContext:i});return e.a.replaceUrl({url:window.location?.href,context:o?.alwaysAppendUrl?{r:a}:null}),e.t(t,`user_referred_completed`,{properties:{status:n,referrer:i?.r,wallet:a}}),n}catch(a){return console.log(`Error processing referral`,{error:a}),e.t(t,`user_referred_error`,{properties:{referrer:i?.r,error:a instanceof n.FrakRpcError?`[${a.code}] ${a.name} - ${a.message}`:a instanceof Error?a.message:`undefined`}}),e.a.replaceUrl({url:window.location?.href,context:o?.alwaysAppendUrl?{r:r?.wallet}:null}),p(a)}}async function d({initialWalletStatus:e,getFreshWalletStatus:n,frakContext:r}){let i=e?.wallet;return i||=await n(),i&&(0,t.isAddressEqual)(r.r,i)?{status:`self-referral`,currentWallet:i}:{status:`success`,currentWallet:i}}async function f(e,{modalConfig:t,walletStatus:n}){return n?.key===`connected`?n.wallet??void 0:(await i(e,t??{}))?.wallet??void 0}function p(e){if(e instanceof n.FrakRpcError)switch(e.code){case n.RpcErrorCodes.walletNotConnected:return`no-wallet`;default:return`error`}return`error`}async function m(t,{modalConfig:n,options:r}={}){let i=e.a.parse({url:window.location.href}),a=await g(t);try{return await u(t,{walletStatus:a,frakContext:i,modalConfig:n,options:r})}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.h();if(!n&&!r){console.warn(`[Frak] No identity found, skipping purchase check`);return}let i=window.sessionStorage.getItem(`frak-merchant-id`),a=t.merchantId??i??await e.r();if(!a){console.warn(`[Frak] No merchant id found, skipping purchase check`);return}let o={Accept:`application/json`,"Content-Type":`application/json`};n&&(o[`x-wallet-sdk-auth`]=n),r&&(o[`x-frak-client-id`]=r);let s=e.o();await fetch(`${s}/user/track/purchase`,{method:`POST`,headers:o,body:JSON.stringify({customerId:t.customerId,orderId:t.orderId,token:t.token,merchantId:a})})}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){return n&&(t.metadata=n(t.metadata??{})),await a(e,t)}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 u}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return s}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{bytesToHex as e,hexToBytes as t,keccak256 as n,toHex as r}from"viem";import{jsonEncode as i}from"@frak-labs/frame-connector";const a=`frak-client-id`;function o(){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 s(){if(typeof window>`u`||!window.localStorage)return console.warn(`[Frak SDK] No Window / localStorage available to save the clientId`),o();let e=localStorage.getItem(a);return e||(e=o(),localStorage.setItem(a,e)),e}function c({domain:e}={}){return n(r((e??window.location.host).replace(`www.`,``)))}function l(e){return btoa(Array.from(e,e=>String.fromCharCode(e)).join(``)).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}function u(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 d(e){return l(i(e))}function f(e,t,n,r,i,a){let o=d(p({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 p(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 m=`menubar=no,status=no,scrollbars=no,fullscreen=no,width=500, height=800`,h=`frak-sso`;async function g(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??f(i??`https://wallet.frak.id`,t,c(),n.name,s(),r?.css),o=window.open(a,h,m);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 _=`https://backend.frak.id`;function v(e){return e.includes(`localhost:3000`)||e.includes(`localhost:3010`)}function y(e){return v(e)?`http://localhost:3030`:e.includes(`wallet-dev.frak.id`)||e.includes(`wallet.gcp-dev.frak.id`)?`https://backend.gcp-dev.frak.id`:_}function b(e){if(e)return y(e);if(typeof window<`u`){let e=window.FrakSetup?.client?.config?.walletUrl;if(e)return y(e)}return _}const x=`fCtx`;function S(e){if(e?.r)try{return l(t(e.r))}catch(t){console.error(`Error compressing Frak context`,{e:t,context:e})}}function C(t){if(!(!t||t.length===0))try{return{r:e(u(t),{size:20})}}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=w({url:e}),r=n?{...n,...t}:t;if(!r.r)return null;let i=S(r);if(!i)return null;let a=new URL(e);return a.searchParams.set(x,i),a.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=`frak-merchant-id`;let A,j;async function M(e,t){if(A)return A;if(typeof window<`u`){let e=window.sessionStorage.getItem(k);if(e)return A=e,e}if(j)return j;j=N(e,t);let n=await j;return j=void 0,n}async function N(e,t){let n=e??(typeof window<`u`?window.location.hostname:``);if(n)try{let e=b(t),r=await fetch(`${e}/user/merchant/resolve?domain=${encodeURIComponent(n)}`);if(!r.ok){console.warn(`[Frak SDK] Merchant lookup failed for domain ${n}: ${r.status}`);return}let i=await r.json();return A=i.merchantId,typeof window<`u`&&window.sessionStorage.setItem(k,i.merchantId),A}catch(e){console.warn(`[Frak SDK] Failed to fetch merchantId:`,e);return}}function P(){A=void 0,j=void 0,typeof window<`u`&&window.sessionStorage.removeItem(k)}async function F(e,t){return e.metadata?.merchantId?e.metadata.merchantId:M(void 0,t)}function I(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{O as a,m as c,d,u as f,s as h,F as i,h as l,c as m,P as n,b as o,l as p,M as r,g as s,I as t,f 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)?`http://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}const v=`fCtx`;function y(t){if(t?.r)try{return o((0,e.hexToBytes)(t.r))}catch(e){console.error(`Error compressing Frak context`,{e,context:t})}}function b(t){if(!(!t||t.length===0))try{return{r:(0,e.bytesToHex)(s(t),{size:20})}}catch(e){console.error(`Error decompressing Frak context`,{e,context:t})}}function x({url:e}){if(!e)return null;let t=new URL(e).searchParams.get(v);return t?b(t):null}function S({url:e,context:t}){if(!e)return null;let n=x({url:e}),r=n?{...n,...t}:t;if(!r.r)return null;let i=y(r);if(!i)return null;let a=new URL(e);return a.searchParams.set(v,i),a.toString()}function C(e){let t=new URL(e);return t.searchParams.delete(v),t.toString()}function w({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?C(n):S({url:n,context:t}),r&&window.history.replaceState(null,``,r.toString())}const T={compress:y,decompress:b,parse:x,update:S,remove:C,replaceUrl:w},E=`frak-merchant-id`;let D,O;async function k(e,t){if(D)return D;if(typeof window<`u`){let e=window.sessionStorage.getItem(E);if(e)return D=e,e}if(O)return O;O=A(e,t);let n=await O;return O=void 0,n}async function A(e,t){let n=e??(typeof window<`u`?window.location.hostname:``);if(n)try{let e=_(t),r=await fetch(`${e}/user/merchant/resolve?domain=${encodeURIComponent(n)}`);if(!r.ok){console.warn(`[Frak SDK] Merchant lookup failed for domain ${n}: ${r.status}`);return}let i=await r.json();return D=i.merchantId,typeof window<`u`&&window.sessionStorage.setItem(E,i.merchantId),D}catch(e){console.warn(`[Frak SDK] Failed to fetch merchantId:`,e);return}}function j(){D=void 0,O=void 0,typeof window<`u`&&window.sessionStorage.removeItem(E)}async function M(e,t){return e.metadata?.merchantId?e.metadata.merchantId:k(void 0,t)}function N(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 T}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return M}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return N}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return l}});
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"url": "https://twitter.com/QNivelais"
|
|
12
12
|
}
|
|
13
13
|
],
|
|
14
|
-
"version": "0.
|
|
14
|
+
"version": "0.2.0-beta.514ef378",
|
|
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",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"build": "tsdown",
|
|
81
81
|
"build:watch": "tsdown --watch",
|
|
82
82
|
"check-exports": "attw --pack --profile node16 .",
|
|
83
|
-
"typecheck": "
|
|
83
|
+
"typecheck": "tsgo --noEmit",
|
|
84
84
|
"test": "vitest",
|
|
85
85
|
"test:ui": "vitest --ui",
|
|
86
86
|
"test:coverage": "vitest --coverage",
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"viem": "^2.x"
|
|
92
92
|
},
|
|
93
93
|
"dependencies": {
|
|
94
|
-
"@frak-labs/frame-connector": "0.
|
|
94
|
+
"@frak-labs/frame-connector": "0.2.0-beta.514ef378",
|
|
95
95
|
"@openpanel/web": "^1.0.7"
|
|
96
96
|
},
|
|
97
97
|
"devDependencies": {
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { getBackendUrl } from "../utils/backendUrl";
|
|
2
|
+
import { getClientId } from "../utils/clientId";
|
|
3
|
+
import { fetchMerchantId } from "../utils/merchantId";
|
|
4
|
+
|
|
5
|
+
const ENSURE_STORAGE_PREFIX = "frak-identity-ensured-";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Ensure the current wallet ↔ clientId link exists on the backend.
|
|
9
|
+
*
|
|
10
|
+
* Called automatically by {@link watchWalletStatus} when a connected wallet
|
|
11
|
+
* status is received. Acts as a failsafe: if the primary merge (SSO, pairing,
|
|
12
|
+
* login/register) missed or silently failed, this ensures the link is
|
|
13
|
+
* eventually established.
|
|
14
|
+
*
|
|
15
|
+
* The call is:
|
|
16
|
+
* - **Idempotent** — if already linked, backend returns immediately
|
|
17
|
+
* - **Deduplicated** — only fires once per browser session per merchant
|
|
18
|
+
* - **Fire-and-forget** — errors are logged but never thrown
|
|
19
|
+
*
|
|
20
|
+
* @param interactionToken - The SDK JWT from wallet status (x-wallet-sdk-auth)
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* // Usually called automatically via watchWalletStatus side effect.
|
|
25
|
+
* // Can also be called manually if needed:
|
|
26
|
+
* await ensureIdentity("eyJhbGciOi...");
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export async function ensureIdentity(interactionToken: string): Promise<void> {
|
|
30
|
+
if (typeof window === "undefined") {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const clientId = getClientId();
|
|
35
|
+
if (!clientId) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const merchantId = await fetchMerchantId();
|
|
40
|
+
if (!merchantId) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const storageKey = `${ENSURE_STORAGE_PREFIX}${merchantId}`;
|
|
45
|
+
if (window.sessionStorage.getItem(storageKey)) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const backendUrl = getBackendUrl();
|
|
51
|
+
const response = await fetch(`${backendUrl}/user/identity/ensure`, {
|
|
52
|
+
method: "POST",
|
|
53
|
+
headers: {
|
|
54
|
+
Accept: "application/json",
|
|
55
|
+
"Content-Type": "application/json",
|
|
56
|
+
"x-wallet-sdk-auth": interactionToken,
|
|
57
|
+
"x-frak-client-id": clientId,
|
|
58
|
+
},
|
|
59
|
+
body: JSON.stringify({ merchantId }),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (response.ok) {
|
|
63
|
+
window.sessionStorage.setItem(storageKey, "1");
|
|
64
|
+
}
|
|
65
|
+
} catch {
|
|
66
|
+
// Fire-and-forget — retry on next session
|
|
67
|
+
}
|
|
68
|
+
}
|
package/src/actions/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { displayEmbeddedWallet } from "./displayEmbeddedWallet";
|
|
2
2
|
export { displayModal } from "./displayModal";
|
|
3
|
+
export { ensureIdentity } from "./ensureIdentity";
|
|
3
4
|
export { getMerchantInformation } from "./getMerchantInformation";
|
|
4
5
|
export { openSso } from "./openSso";
|
|
5
6
|
export { prepareSso } from "./prepareSso";
|
package/src/actions/openSso.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
OpenSsoParamsType,
|
|
4
4
|
OpenSsoReturnType,
|
|
5
5
|
} from "../types";
|
|
6
|
+
import { getClientId } from "../utils/clientId";
|
|
6
7
|
import { computeLegacyProductId } from "../utils/computeLegacyProductId";
|
|
7
8
|
import { generateSsoUrl } from "../utils/sso";
|
|
8
9
|
|
|
@@ -93,6 +94,7 @@ export async function openSso(
|
|
|
93
94
|
args,
|
|
94
95
|
computeLegacyProductId(),
|
|
95
96
|
metadata.name,
|
|
97
|
+
getClientId(),
|
|
96
98
|
customizations?.css
|
|
97
99
|
);
|
|
98
100
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { FrakClient } from "../types";
|
|
2
2
|
import type { SendInteractionParamsType } from "../types/rpc/interaction";
|
|
3
|
+
import { getClientId } from "../utils/clientId";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Send an interaction to the backend via the listener RPC.
|
|
@@ -46,7 +47,7 @@ export async function sendInteraction(
|
|
|
46
47
|
try {
|
|
47
48
|
await client.request({
|
|
48
49
|
method: "frak_sendInteraction",
|
|
49
|
-
params: [params],
|
|
50
|
+
params: [params, { clientId: getClientId() }],
|
|
50
51
|
});
|
|
51
52
|
} catch {
|
|
52
53
|
// Silent failure - fire-and-forget
|