@frak-labs/core-sdk 0.2.1-beta.d2556d47 → 0.2.1-beta.eb3cff34
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 -55
- package/dist/actions-D4aBXbdp.cjs +1 -0
- package/dist/actions-Dq_uN-wn.js +1 -0
- package/dist/actions.cjs +1 -1
- package/dist/actions.d.cts +3 -3
- package/dist/actions.d.ts +3 -3
- package/dist/actions.js +1 -1
- package/dist/bundle.cjs +1 -1
- package/dist/bundle.d.cts +4 -4
- package/dist/bundle.d.ts +4 -4
- package/dist/bundle.js +1 -1
- package/dist/{computeLegacyProductId-BP-ciVsp.d.cts → index-BV5D9DsW.d.ts} +71 -3
- package/dist/{siweAuthenticate-yITE-iKh.d.cts → index-BphwTmKA.d.cts} +115 -4
- package/dist/{computeLegacyProductId-DiJd7RNo.d.ts → index-Dwmo109y.d.cts} +71 -3
- package/dist/{siweAuthenticate-CDCsp8EJ.d.ts → index-_f8EuN_1.d.ts} +115 -4
- 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-B8v3Vtnh.d.ts → openSso-BwEK2M98.d.cts} +174 -7
- package/dist/{openSso-n_B4LSuW.d.cts → openSso-C1Wzl5-i.d.ts} +174 -7
- package/dist/src-B3Dusips.cjs +13 -0
- package/dist/src-CnnhYPyK.js +13 -0
- package/dist/trackEvent-BqJqRZ-u.cjs +1 -0
- package/dist/trackEvent-Bqq4jd6R.js +1 -0
- package/package.json +9 -10
- package/src/actions/displaySharingPage.ts +49 -0
- package/src/actions/getMerchantInformation.test.ts +13 -1
- package/src/actions/getMerchantInformation.ts +20 -5
- package/src/actions/getMergeToken.ts +33 -0
- package/src/actions/getUserReferralStatus.ts +42 -0
- package/src/actions/index.ts +8 -1
- package/src/actions/referral/setupReferral.test.ts +79 -0
- package/src/actions/referral/setupReferral.ts +32 -0
- package/src/clients/createIFrameFrakClient.ts +5 -2
- package/src/clients/transports/iframeLifecycleManager.test.ts +14 -14
- package/src/clients/transports/iframeLifecycleManager.ts +35 -9
- package/src/index.ts +12 -1
- package/src/stubs/rrweb.ts +9 -0
- package/src/types/index.ts +7 -0
- package/src/types/lifecycle/iframe.ts +7 -0
- package/src/types/resolvedConfig.ts +26 -2
- package/src/types/rpc/displaySharingPage.ts +82 -0
- package/src/types/rpc/embedded/index.ts +1 -1
- package/src/types/rpc/userReferralStatus.ts +20 -0
- package/src/types/rpc.ts +47 -0
- package/src/utils/cache/index.ts +7 -0
- package/src/utils/cache/lruMap.test.ts +55 -0
- package/src/utils/cache/lruMap.ts +38 -0
- package/src/utils/cache/withCache.test.ts +168 -0
- package/src/utils/cache/withCache.ts +124 -0
- package/src/utils/inAppBrowser.ts +60 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/sdkConfigStore.ts +21 -35
- package/dist/setupClient-Dr_UYfTD.cjs +0 -13
- package/dist/setupClient-TuhDjVJx.js +0 -13
- package/dist/siweAuthenticate-0UPcUqI1.js +0 -1
- package/dist/siweAuthenticate-CfQibjZR.cjs +0 -1
- package/dist/trackEvent-5j5kkOCj.js +0 -1
- package/dist/trackEvent-B2uom25e.cjs +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { OpenPanel } from "@openpanel/web";
|
|
2
|
-
import { LifecycleMessage, RpcClient } from "@frak-labs/frame-connector";
|
|
3
1
|
import { Address, Hex } from "viem";
|
|
2
|
+
import { LifecycleMessage, RpcClient } from "@frak-labs/frame-connector";
|
|
3
|
+
import { OpenPanel } from "@openpanel/web";
|
|
4
4
|
import { SiweMessage } from "viem/siwe";
|
|
5
5
|
|
|
6
6
|
//#region src/types/config.d.ts
|
|
@@ -147,18 +147,37 @@ type ResolvedPlacement = {
|
|
|
147
147
|
buttonShare?: {
|
|
148
148
|
text?: string;
|
|
149
149
|
noRewardText?: string;
|
|
150
|
-
clickAction?: "embedded-wallet" | "share-modal";
|
|
150
|
+
clickAction?: "embedded-wallet" | "share-modal" | "sharing-page";
|
|
151
151
|
useReward?: boolean;
|
|
152
152
|
css?: string;
|
|
153
153
|
};
|
|
154
154
|
buttonWallet?: {
|
|
155
|
-
position?: "
|
|
155
|
+
position?: "right" | "left";
|
|
156
156
|
css?: string;
|
|
157
157
|
};
|
|
158
158
|
openInApp?: {
|
|
159
159
|
text?: string;
|
|
160
160
|
css?: string;
|
|
161
161
|
};
|
|
162
|
+
postPurchase?: {
|
|
163
|
+
badgeText?: string;
|
|
164
|
+
refereeText?: string;
|
|
165
|
+
refereeNoRewardText?: string;
|
|
166
|
+
referrerText?: string;
|
|
167
|
+
referrerNoRewardText?: string;
|
|
168
|
+
ctaText?: string;
|
|
169
|
+
ctaNoRewardText?: string;
|
|
170
|
+
css?: string;
|
|
171
|
+
};
|
|
172
|
+
banner?: {
|
|
173
|
+
referralTitle?: string;
|
|
174
|
+
referralDescription?: string;
|
|
175
|
+
referralCta?: string;
|
|
176
|
+
inappTitle?: string;
|
|
177
|
+
inappDescription?: string;
|
|
178
|
+
inappCta?: string;
|
|
179
|
+
css?: string;
|
|
180
|
+
};
|
|
162
181
|
};
|
|
163
182
|
targetInteraction?: string; /** Already flattened: default + lang-specific merged into one record */
|
|
164
183
|
translations?: Record<string, string>; /** Global placement CSS (applied to modals/listener) */
|
|
@@ -178,7 +197,8 @@ type ResolvedSdkConfig = {
|
|
|
178
197
|
hidden?: boolean;
|
|
179
198
|
css?: string;
|
|
180
199
|
translations?: Record<string, string>;
|
|
181
|
-
placements?: Record<string, ResolvedPlacement>;
|
|
200
|
+
placements?: Record<string, ResolvedPlacement>; /** Global component defaults (used when no placement override exists) */
|
|
201
|
+
components?: ResolvedPlacement["components"];
|
|
182
202
|
};
|
|
183
203
|
/**
|
|
184
204
|
* Internal SDK config store state
|
|
@@ -200,7 +220,8 @@ type SdkResolvedConfig = {
|
|
|
200
220
|
hidden?: boolean; /** Global CSS from backend config (passed to iframe) */
|
|
201
221
|
css?: string; /** Global translations (for reference / component fallback) */
|
|
202
222
|
translations?: Record<string, string>; /** Named placements (keyed by placement ID) */
|
|
203
|
-
placements?: Record<string, ResolvedPlacement>;
|
|
223
|
+
placements?: Record<string, ResolvedPlacement>; /** Global component defaults (fallback for placement-level overrides) */
|
|
224
|
+
components?: ResolvedPlacement["components"];
|
|
204
225
|
};
|
|
205
226
|
//#endregion
|
|
206
227
|
//#region src/types/lifecycle/client.d.ts
|
|
@@ -288,6 +309,13 @@ type RedirectRequestEvent = {
|
|
|
288
309
|
* Used when redirecting out of social browsers to preserve identity across contexts
|
|
289
310
|
*/
|
|
290
311
|
mergeToken?: string;
|
|
312
|
+
/**
|
|
313
|
+
* When true, open the URL in a new tab via window.open(_blank)
|
|
314
|
+
* instead of navigating the current page.
|
|
315
|
+
* Requires the postMessage to include user activation delegation
|
|
316
|
+
* (includeUserActivation: true) so Safari allows the popup.
|
|
317
|
+
*/
|
|
318
|
+
openInNewTab?: boolean;
|
|
291
319
|
};
|
|
292
320
|
};
|
|
293
321
|
//#endregion
|
|
@@ -604,6 +632,85 @@ type DisplayModalParamsType<T extends ModalStepTypes[]> = {
|
|
|
604
632
|
metadata?: ModalRpcMetadata;
|
|
605
633
|
};
|
|
606
634
|
//#endregion
|
|
635
|
+
//#region src/types/rpc/displaySharingPage.d.ts
|
|
636
|
+
/**
|
|
637
|
+
* Product information to display on the sharing page
|
|
638
|
+
* @group Sharing Page
|
|
639
|
+
*/
|
|
640
|
+
type SharingPageProduct = {
|
|
641
|
+
/**
|
|
642
|
+
* The product title / name
|
|
643
|
+
*/
|
|
644
|
+
title: string;
|
|
645
|
+
/**
|
|
646
|
+
* Optional product image URL
|
|
647
|
+
*/
|
|
648
|
+
imageUrl?: string;
|
|
649
|
+
/**
|
|
650
|
+
* Optional product-specific sharing link
|
|
651
|
+
* When provided and the product is selected, this link is used instead of the default sharing link
|
|
652
|
+
*/
|
|
653
|
+
link?: string;
|
|
654
|
+
};
|
|
655
|
+
/**
|
|
656
|
+
* Parameters to display the sharing page
|
|
657
|
+
* @group Sharing Page
|
|
658
|
+
* @group RPC Schema
|
|
659
|
+
*/
|
|
660
|
+
type DisplaySharingPageParamsType = {
|
|
661
|
+
/**
|
|
662
|
+
* Products to showcase on the sharing page
|
|
663
|
+
* If provided, they will be displayed in a product card section
|
|
664
|
+
*/
|
|
665
|
+
products?: SharingPageProduct[];
|
|
666
|
+
/**
|
|
667
|
+
* Optional link override for sharing
|
|
668
|
+
* If not provided, the sharing link will be generated from the current page URL + merchant context
|
|
669
|
+
*/
|
|
670
|
+
link?: string;
|
|
671
|
+
/**
|
|
672
|
+
* Optional metadata overrides for the sharing page
|
|
673
|
+
*/
|
|
674
|
+
metadata?: {
|
|
675
|
+
/**
|
|
676
|
+
* Logo override for the sharing page header
|
|
677
|
+
*/
|
|
678
|
+
logo?: string;
|
|
679
|
+
/**
|
|
680
|
+
* Link to the homepage of the calling website
|
|
681
|
+
*/
|
|
682
|
+
homepageLink?: string;
|
|
683
|
+
/**
|
|
684
|
+
* The target interaction behind this sharing page
|
|
685
|
+
*/
|
|
686
|
+
targetInteraction?: InteractionTypeKey;
|
|
687
|
+
/**
|
|
688
|
+
* i18n overrides for the sharing page
|
|
689
|
+
*/
|
|
690
|
+
i18n?: I18nConfig;
|
|
691
|
+
};
|
|
692
|
+
};
|
|
693
|
+
/**
|
|
694
|
+
* Result of the sharing page display
|
|
695
|
+
* @group Sharing Page
|
|
696
|
+
* @group RPC Schema
|
|
697
|
+
*/
|
|
698
|
+
type DisplaySharingPageResultType = {
|
|
699
|
+
/**
|
|
700
|
+
* The action the user took
|
|
701
|
+
* - "shared": User used the native share dialog
|
|
702
|
+
* - "copied": User copied the link to clipboard
|
|
703
|
+
* - "dismissed": User dismissed the sharing page without acting
|
|
704
|
+
*/
|
|
705
|
+
action: "shared" | "copied" | "dismissed";
|
|
706
|
+
/**
|
|
707
|
+
* The install URL for the Frak app
|
|
708
|
+
* Can be used as a fallback to redirect the user to the install page
|
|
709
|
+
* from the merchant's top-level page (e.g. via `window.location.href`)
|
|
710
|
+
*/
|
|
711
|
+
installUrl?: string;
|
|
712
|
+
};
|
|
713
|
+
//#endregion
|
|
607
714
|
//#region src/types/rpc/embedded/loggedIn.d.ts
|
|
608
715
|
/**
|
|
609
716
|
* The different type of action we can have on the embedded view (once the user is logged in)
|
|
@@ -841,6 +948,28 @@ type GetMerchantInformationReturnType = {
|
|
|
841
948
|
}[];
|
|
842
949
|
};
|
|
843
950
|
//#endregion
|
|
951
|
+
//#region src/types/rpc/userReferralStatus.d.ts
|
|
952
|
+
/**
|
|
953
|
+
* User referral status returned by `frak_getUserReferralStatus`.
|
|
954
|
+
*
|
|
955
|
+
* Generic referral context for the current user on a merchant.
|
|
956
|
+
* Used by components like `<frak-post-purchase>` and `<frak-referred-banner>`
|
|
957
|
+
* to adapt their display based on the user's referral relationship.
|
|
958
|
+
*
|
|
959
|
+
* Returns `null` when the user's identity cannot be resolved
|
|
960
|
+
* (e.g. no clientId and no wallet session).
|
|
961
|
+
*
|
|
962
|
+
* @group RPC Schema
|
|
963
|
+
*/
|
|
964
|
+
type UserReferralStatusType = {
|
|
965
|
+
/**
|
|
966
|
+
* Whether the user was referred to this merchant by someone else.
|
|
967
|
+
*
|
|
968
|
+
* `true` means a referral link exists where this user is the referee.
|
|
969
|
+
*/
|
|
970
|
+
isReferred: boolean;
|
|
971
|
+
};
|
|
972
|
+
//#endregion
|
|
844
973
|
//#region src/types/rpc/walletStatus.d.ts
|
|
845
974
|
/**
|
|
846
975
|
* RPC Response for the method `frak_listenToWalletStatus`
|
|
@@ -905,6 +1034,11 @@ type WalletNotConnected = {
|
|
|
905
1034
|
* - Params: [request: {@link DisplayEmbeddedWalletParamsType}, metadata: {@link FrakWalletSdkConfig}["metadata"], placement?: string]
|
|
906
1035
|
* - Returns: {@link DisplayEmbeddedWalletResultType}
|
|
907
1036
|
* - Response Type: promise (one-shot)
|
|
1037
|
+
*
|
|
1038
|
+
* #### frak_displaySharingPage
|
|
1039
|
+
* - Params: [request: {@link DisplaySharingPageParamsType}, configMetadata: {@link FrakWalletSdkConfig}["metadata"], placement?: string]
|
|
1040
|
+
* - Returns: {@link DisplaySharingPageResultType}
|
|
1041
|
+
* - Response Type: promise (one-shot)
|
|
908
1042
|
*/
|
|
909
1043
|
type IFrameRpcSchema = [
|
|
910
1044
|
/**
|
|
@@ -979,6 +1113,39 @@ type IFrameRpcSchema = [
|
|
|
979
1113
|
clientId?: string;
|
|
980
1114
|
}];
|
|
981
1115
|
ReturnType: undefined;
|
|
1116
|
+
},
|
|
1117
|
+
/**
|
|
1118
|
+
* Method to get the current user's referral status on this merchant.
|
|
1119
|
+
* Returns whether the user was referred (has a referral link as referee).
|
|
1120
|
+
* Returns null when the user's identity cannot be resolved.
|
|
1121
|
+
* This is a one-shot request.
|
|
1122
|
+
*/
|
|
1123
|
+
{
|
|
1124
|
+
Method: "frak_getUserReferralStatus";
|
|
1125
|
+
Parameters?: undefined;
|
|
1126
|
+
ReturnType: UserReferralStatusType | null;
|
|
1127
|
+
},
|
|
1128
|
+
/**
|
|
1129
|
+
* Method to display a sharing page with product info and sharing buttons
|
|
1130
|
+
* Resolves on first user action (share/copy) but the page stays visible
|
|
1131
|
+
* This is a one-shot request
|
|
1132
|
+
*/
|
|
1133
|
+
{
|
|
1134
|
+
Method: "frak_displaySharingPage";
|
|
1135
|
+
Parameters: [request: DisplaySharingPageParamsType, configMetadata: FrakWalletSdkConfig["metadata"], placement?: string];
|
|
1136
|
+
ReturnType: DisplaySharingPageResultType;
|
|
1137
|
+
},
|
|
1138
|
+
/**
|
|
1139
|
+
* Method to get a merge token for the current anonymous identity.
|
|
1140
|
+
* Used by in-app browser redirect flows to preserve identity
|
|
1141
|
+
* when switching from a WebView to the system browser.
|
|
1142
|
+
* Returns the merge token string, or null if unavailable.
|
|
1143
|
+
* This is a one-shot request.
|
|
1144
|
+
*/
|
|
1145
|
+
{
|
|
1146
|
+
Method: "frak_getMergeToken";
|
|
1147
|
+
Parameters?: undefined;
|
|
1148
|
+
ReturnType: string | null;
|
|
982
1149
|
}];
|
|
983
1150
|
//#endregion
|
|
984
1151
|
//#region src/types/transport.d.ts
|
|
@@ -1124,4 +1291,4 @@ declare const ssoPopupName = "frak-sso";
|
|
|
1124
1291
|
*/
|
|
1125
1292
|
declare function openSso(client: FrakClient, args: OpenSsoParamsType): Promise<OpenSsoReturnType>;
|
|
1126
1293
|
//#endregion
|
|
1127
|
-
export {
|
|
1294
|
+
export { ResolvedPlacement as $, ModalRpcMetadata as A, LoginModalStepType as B, EmbeddedViewActionReferred as C, DisplaySharingPageResultType as D, DisplaySharingPageParamsType as E, SendTransactionReturnType as F, SsoMetadata as G, OpenSsoReturnType as H, SendTransactionTxType as I, ModalStepMetadata as J, FinalActionType as K, SiweAuthenticateModalStepType as L, ModalRpcStepsResultType as M, ModalStepTypes as N, SharingPageProduct as O, SendTransactionModalStepType as P, MerchantConfigResponse as Q, SiweAuthenticateReturnType as R, LoggedOutEmbeddedView as S, LoggedInEmbeddedView as T, PrepareSsoParamsType as U, OpenSsoParamsType as V, PrepareSsoReturnType as W, IFrameLifecycleEvent as X, InteractionTypeKey as Y, ClientLifecycleEvent as Z, RewardTier as _, FrakContextV1 as a, Language as at, DisplayEmbeddedWalletParamsType as b, isV2Context as c, IFrameTransport as d, ResolvedSdkConfig as et, IFrameRpcSchema as f, GetMerchantInformationReturnType as g, EstimatedReward as h, FrakContext as i, I18nConfig as it, ModalRpcStepsInput as j, DisplayModalParamsType as k, FrakClient as l, UserReferralStatusType as m, ssoPopupFeatures as n, Currency as nt, FrakContextV2 as o, LocalizedI18nConfig as ot, WalletStatusReturnType as p, FinalModalStepType as q, ssoPopupName as r, FrakWalletSdkConfig as rt, isV1Context as s, openSso as t, SdkResolvedConfig as tt, FrakLifecycleEvent as u, TokenAmountType as v, EmbeddedViewActionSharing as w, DisplayEmbeddedWalletResultType as x, SendInteractionParamsType as y, SiweAuthenticationParams as z };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const e=require(`./trackEvent-BqJqRZ-u.cjs`);let t=require(`@frak-labs/frame-connector`),n=require(`@openpanel/web`);const r=`nexus-wallet-backup`,i=`frakwallet://`;function a(){let e=navigator.userAgent;return/Android/i.test(e)&&/Chrome\/\d+/i.test(e)}function o(e){return`intent://${e.slice(13)}#Intent;scheme=frakwallet;end`}function s(e,t){let n=t?.timeout??2500,r=!1,i=()=>{document.hidden&&(r=!0)};document.addEventListener(`visibilitychange`,i);let s=a()&&c(e)?o(e):e;window.location.href=s,setTimeout(()=>{document.removeEventListener(`visibilitychange`,i),r||t?.onFallback?.()},n)}function c(e){return e.startsWith(i)}const l={eur:`fr-FR`,usd:`en-US`,gbp:`en-GB`};function u(e){return e&&e in l?e:`eur`}function d(e){return e?l[e]??l.eur:l.eur}function f(e,t){let n=d(t),r=u(t);return e.toLocaleString(n,{style:`currency`,currency:r,minimumFractionDigits:0,maximumFractionDigits:2})}function p(e){return e?`${e}Amount`:`eurAmount`}const m={id:`frak-wallet`,name:`frak-wallet`,title:`Frak Wallet`,allow:`publickey-credentials-get *; clipboard-write; web-share *`,style:{width:`0`,height:`0`,border:`0`,position:`absolute`,zIndex:2000001,top:`-1000px`,left:`-1000px`,colorScheme:`auto`}};function h({walletBaseUrl:t,config:n}){let r=document.querySelector(`#frak-wallet`);r&&r.remove();let i=document.createElement(`iframe`);i.id=m.id,i.name=m.name,i.allow=m.allow,i.style.zIndex=m.style.zIndex.toString(),g({iframe:i,isVisible:!1});let a=n?.walletUrl??t??`https://wallet.frak.id`,o=e.y();return i.src=`${a}/listener?clientId=${encodeURIComponent(o)}`,new Promise(e=>{i.addEventListener(`load`,()=>e(i)),document.body.appendChild(i)})}function g({iframe:e,isVisible:t}){if(!t){e.style.width=`0`,e.style.height=`0`,e.style.border=`0`,e.style.position=`fixed`,e.style.top=`-1000px`,e.style.left=`-1000px`;return}e.style.position=`fixed`,e.style.top=`0`,e.style.left=`0`,e.style.width=`100%`,e.style.height=`100%`,e.style.pointerEvents=`auto`}function _(e=`/listener`){if(!window.opener)return null;let t=t=>{try{return t.location.origin===window.location.origin&&t.location.pathname===e}catch{return!1}};if(t(window.opener))return window.opener;try{let e=window.opener.frames;for(let n=0;n<e.length;n++)if(t(e[n]))return e[n];return null}catch(t){return console.error(`[findIframeInOpener] Error finding iframe with pathname ${e}:`,t),null}}function v(){if(typeof navigator>`u`)return!1;let e=navigator.userAgent;return!!(/iPhone|iPad|iPod/i.test(e)||/Macintosh/i.test(e)&&navigator.maxTouchPoints>1)}const y=v();function b(){if(typeof navigator>`u`)return!1;let e=navigator.userAgent.toLowerCase();return e.includes(`instagram`)||e.includes(`fban`)||e.includes(`fbav`)||e.includes(`facebook`)}const x=b();function S(e){y&&e.startsWith(`https://`)?window.location.href=`x-safari-https://${e.slice(8)}`:y&&e.startsWith(`http://`)?window.location.href=`x-safari-http://${e.slice(7)}`:window.location.href=`https://backend.frak.id/common/social?u=${encodeURIComponent(e)}`}function C(e,t){if(typeof window>`u`)return;let n=new URL(window.location.href),r=n.searchParams.get(`sso`);r&&(t.then(()=>{e.sendLifecycle({clientLifecycle:`sso-redirect-complete`,data:{compressed:r}}),console.log(`[SSO URL Listener] Forwarded compressed SSO data to iframe`)}).catch(e=>{console.error(`[SSO URL Listener] Failed to forward SSO data:`,e)}),n.searchParams.delete(`sso`),window.history.replaceState({},``,n.toString()),console.log(`[SSO URL Listener] SSO parameter detected and URL cleaned`))}var w=class e{config;iframe;isSetupDone=!1;lastResponse=null;lastRequest=null;constructor(e,t){this.config=e,this.iframe=t,this.lastRequest=null,this.lastResponse=null}setLastResponse(e,t){this.lastResponse={message:e,response:t,timestamp:Date.now()}}setLastRequest(e){this.lastRequest={event:e,timestamp:Date.now()}}updateSetupStatus(e){this.isSetupDone=e}base64Encode(e){try{return btoa(JSON.stringify(e))}catch(e){return console.warn(`Failed to encode debug data`,e),btoa(`Failed to encode data`)}}getIframeStatus(){return this.iframe?{loading:this.iframe.hasAttribute(`loading`),url:this.iframe.src,readyState:this.iframe.contentDocument?.readyState?+(this.iframe.contentDocument.readyState===`complete`):-1,contentWindow:!!this.iframe.contentWindow,isConnected:this.iframe.isConnected}:null}getNavigatorInfo(){return navigator?{userAgent:navigator.userAgent,language:navigator.language,onLine:navigator.onLine,screenWidth:window.screen.width,screenHeight:window.screen.height,pixelRatio:window.devicePixelRatio}:null}gatherDebugInfo(e){let n=this.getIframeStatus(),r=this.getNavigatorInfo(),i=`Unknown`;return e instanceof t.FrakRpcError?i=`FrakRpcError: ${e.code} '${e.message}'`:e instanceof Error?i=e.message:typeof e==`string`&&(i=e),{timestamp:new Date().toISOString(),encodedUrl:btoa(window.location.href),encodedConfig:this.config?this.base64Encode(this.config):`no-config`,navigatorInfo:r?this.base64Encode(r):`no-navigator`,iframeStatus:n?this.base64Encode(n):`not-iframe`,lastRequest:this.lastRequest?this.base64Encode(this.lastRequest):`No Frak request logged`,lastResponse:this.lastResponse?this.base64Encode(this.lastResponse):`No Frak response logged`,clientStatus:this.isSetupDone?`setup`:`not-setup`,error:i}}static empty(){return new e}formatDebugInfo(e){let t=this.gatherDebugInfo(e);return`
|
|
2
|
+
Debug Information:
|
|
3
|
+
-----------------
|
|
4
|
+
Timestamp: ${t.timestamp}
|
|
5
|
+
URL: ${t.encodedUrl}
|
|
6
|
+
Config: ${t.encodedConfig}
|
|
7
|
+
Navigator Info: ${t.navigatorInfo}
|
|
8
|
+
IFrame Status: ${t.iframeStatus}
|
|
9
|
+
Last Request: ${t.lastRequest}
|
|
10
|
+
Last Response: ${t.lastResponse}
|
|
11
|
+
Client Status: ${t.clientStatus}
|
|
12
|
+
Error: ${t.error}
|
|
13
|
+
`.trim()}};const T=(()=>{if(typeof navigator>`u`)return!1;let e=navigator.userAgent;if(!(/iPhone|iPad|iPod/i.test(e)||/Macintosh/i.test(e)&&navigator.maxTouchPoints>1))return!1;let t=e.toLowerCase();return t.includes(`instagram`)||t.includes(`fban`)||t.includes(`fbav`)||t.includes(`facebook`)})();function E(e){e?localStorage.setItem(r,e):localStorage.removeItem(r)}function D(e,t){try{let n=new URL(e);if(!n.searchParams.has(`u`))return e;let r=A(window.location.href,t);return n.searchParams.delete(`u`),n.searchParams.append(`u`,r),n.toString()}catch{return e}}function O(e){let t=new URL(window.location.href);e&&t.searchParams.set(`fmt`,e);let n=t.protocol===`http:`?`x-safari-http`:`x-safari-https`;window.location.href=`${n}://${t.host}${t.pathname}${t.search}${t.hash}`}function k(e){return e.includes(`/common/social`)}function A(e,t){if(!t)return e;try{let n=new URL(e);return n.searchParams.set(`fmt`,t),n.toString()}catch{return`${e}${e.includes(`?`)?`&`:`?`}fmt=${encodeURIComponent(t)}`}}function j(e,t,n,r,i){if(i){let e=D(t,r);window.open(e,`_blank`);return}if(c(t)){let i=D(t,r);s(i,{onFallback:()=>{e.contentWindow?.postMessage({clientLifecycle:`deep-link-failed`,data:{originalUrl:i}},n)}})}else if(T&&k(t))O(r);else{let e=D(t,r);window.location.href=e}}function M({iframe:e,targetOrigin:n}){let i=new t.Deferred;return{handleEvent:t=>{if(!(`iframeLifecycle`in t))return;let{iframeLifecycle:a,data:o}=t;switch(a){case`connected`:i.resolve(!0);break;case`do-backup`:E(o.backup);break;case`remove-backup`:localStorage.removeItem(r);break;case`show`:case`hide`:g({iframe:e,isVisible:a===`show`});break;case`redirect`:j(e,o.baseRedirectUrl,n,o.mergeToken,o.openInNewTab);break}},isConnected:i.promise}}function N({config:r,iframe:i}){let a=r?.walletUrl??`https://wallet.frak.id`,o=typeof navigator<`u`?navigator.language?.split(`-`)[0]:void 0,s=r.metadata.lang??(o===`en`||o===`fr`?o:void 0),c=r.domain??(typeof window<`u`?window.location.hostname:``);e.n.setCacheScope(c,s),e.n.reset();let l=e.n.isCacheFresh?void 0:e.n.resolve(r.domain,r.walletUrl,s),u=M({iframe:i,targetOrigin:a}),d=new t.Deferred,f=new w(r,i);if(!i.contentWindow)throw new t.FrakRpcError(t.RpcErrorCodes.configError,`The iframe does not have a content window`);let p=(0,t.createRpcClient)({emittingTransport:i.contentWindow,listeningTransport:window,targetOrigin:a,middleware:[{async onRequest(e,n){if(!await u.isConnected)throw new t.FrakRpcError(t.RpcErrorCodes.clientNotConnected,`The iframe provider isn't connected yet`);return await d.promise,n}},{onRequest(e,t){return f.setLastRequest(e),t},onResponse(e,t){return f.setLastResponse(e,t),t}}],lifecycleHandlers:{iframeLifecycle:(e,t)=>{u.handleEvent(e)}}}),m=P(p,u),h=async()=>{m(),p.cleanup(),i.remove(),e.s(),e.n.clearCache(),e.n.reset()},g;console.log(`[Frak SDK] Initializing OpenPanel`),g=new n.OpenPanel({apiUrl:`https://op-api.gcp.frak.id`,clientId:`6eacc8d7-49ac-4936-95e9-81ef29449570`,trackScreenViews:!0,trackOutgoingLinks:!0,trackAttributes:!1,filter:({type:t,payload:n})=>(t!==`track`||!n?.properties||`sdkVersion`in n.properties||(n.properties={...n.properties,sdkVersion:`0.2.1`,userAnonymousClientId:e.y()}),!0)}),g.setGlobalProperties({sdkVersion:`0.2.1`,userAnonymousClientId:e.y()}),g.init();let _=F({config:r,rpcClient:p,lifecycleManager:u,configPromise:l,contextSent:d}).then(()=>f.updateSetupStatus(!0)).catch(e=>{throw d.reject(e),e});return{config:r,debugInfo:f,waitForConnection:u.isConnected,waitForSetup:_,request:p.request,listenerRequest:p.listen,destroy:h,openPanel:g}}function P(e,t){let n,r,i=()=>e.sendLifecycle({clientLifecycle:`heartbeat`});async function a(){i(),n=setInterval(i,1e3),r=setTimeout(()=>{o(),console.log(`Heartbeat timeout: connection failed`)},3e4),await t.isConnected,o()}function o(){n&&clearInterval(n),r&&clearTimeout(r)}return a(),o}async function F({config:t,rpcClient:n,lifecycleManager:i,configPromise:a,contextSent:o}){await i.isConnected,C(n,i.isConnected);let s=new URL(window.location.href),c=s.searchParams.get(`fmt`)??void 0;c&&(s.searchParams.delete(`fmt`),window.history.replaceState({},``,s.toString()));let l=n=>{let r=n?.merchantId??t.metadata.merchantId??``,i=n?.domain??``,a=n?.allowedDomains??[],o=n?.sdkConfig;e.n.setConfig(o?{isResolved:!0,merchantId:r,domain:i,allowedDomains:a,hasRawSdkConfig:!0,name:o.name??t.metadata.name,logoUrl:o.logoUrl??t.metadata.logoUrl,homepageLink:o.homepageLink??t.metadata.homepageLink,lang:o.lang??t.metadata.lang,currency:o.currency??t.metadata.currency,hidden:o.hidden,css:o.css,translations:o.translations,placements:o.placements,components:o.components}:{isResolved:!0,merchantId:r,domain:i,allowedDomains:a,name:t.metadata.name,logoUrl:t.metadata.logoUrl,homepageLink:t.metadata.homepageLink,lang:t.metadata.lang,currency:t.metadata.currency})},u=!1,d=e=>{let t=u?void 0:c;u=!0;let r=e.hasRawSdkConfig?{name:e.name,logoUrl:e.logoUrl,homepageLink:e.homepageLink,lang:e.lang,currency:e.currency,hidden:e.hidden,css:e.css,translations:e.translations,placements:e.placements}:void 0;n.sendLifecycle({clientLifecycle:`resolved-config`,data:{merchantId:e.merchantId,domain:e.domain??``,allowedDomains:e.allowedDomains??[],sourceUrl:window.location.href,...t&&{pendingMergeToken:t},...r&&{sdkConfig:r}}})};e.n.isResolved&&(d(e.n.getConfig()),o.resolve()),a&&(l(await a),d(e.n.getConfig()),o.resolve());async function f(){let e=t.customizations?.css;e&&n.sendLifecycle({clientLifecycle:`modal-css`,data:{cssLink:e}})}async function p(){let e=t.customizations?.i18n;e&&n.sendLifecycle({clientLifecycle:`modal-i18n`,data:{i18n:e}})}async function m(){if(typeof window>`u`)return;let e=window.localStorage.getItem(r);e&&n.sendLifecycle({clientLifecycle:`restore-backup`,data:{backup:e}})}await Promise.allSettled([f(),p(),m()])}async function I({config:e}){let t=L(e),n=await h({config:t});if(!n){console.error(`Failed to create iframe`);return}let r=N({config:t,iframe:n});if(await r.waitForSetup,!await r.waitForConnection){console.error(`Failed to connect to client`);return}return r}function L(e){let t=u(e.metadata?.currency);return{...e,metadata:{...e.metadata,currency:t}}}Object.defineProperty(exports,`_`,{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,`g`,{enumerable:!0,get:function(){return c}}),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 _}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return N}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return I}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,`v`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`y`,{enumerable:!0,get:function(){return i}});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import{n as e,s as t,y as n}from"./trackEvent-Bqq4jd6R.js";import{Deferred as r,FrakRpcError as i,RpcErrorCodes as a,createRpcClient as o}from"@frak-labs/frame-connector";import{OpenPanel as s}from"@openpanel/web";const c=`nexus-wallet-backup`,l=`frakwallet://`;function u(){let e=navigator.userAgent;return/Android/i.test(e)&&/Chrome\/\d+/i.test(e)}function d(e){return`intent://${e.slice(13)}#Intent;scheme=frakwallet;end`}function f(e,t){let n=t?.timeout??2500,r=!1,i=()=>{document.hidden&&(r=!0)};document.addEventListener(`visibilitychange`,i);let a=u()&&p(e)?d(e):e;window.location.href=a,setTimeout(()=>{document.removeEventListener(`visibilitychange`,i),r||t?.onFallback?.()},n)}function p(e){return e.startsWith(l)}const m={eur:`fr-FR`,usd:`en-US`,gbp:`en-GB`};function h(e){return e&&e in m?e:`eur`}function g(e){return e?m[e]??m.eur:m.eur}function _(e,t){let n=g(t),r=h(t);return e.toLocaleString(n,{style:`currency`,currency:r,minimumFractionDigits:0,maximumFractionDigits:2})}function v(e){return e?`${e}Amount`:`eurAmount`}const y={id:`frak-wallet`,name:`frak-wallet`,title:`Frak Wallet`,allow:`publickey-credentials-get *; clipboard-write; web-share *`,style:{width:`0`,height:`0`,border:`0`,position:`absolute`,zIndex:2000001,top:`-1000px`,left:`-1000px`,colorScheme:`auto`}};function b({walletBaseUrl:e,config:t}){let r=document.querySelector(`#frak-wallet`);r&&r.remove();let i=document.createElement(`iframe`);i.id=y.id,i.name=y.name,i.allow=y.allow,i.style.zIndex=y.style.zIndex.toString(),x({iframe:i,isVisible:!1});let a=t?.walletUrl??e??`https://wallet.frak.id`,o=n();return i.src=`${a}/listener?clientId=${encodeURIComponent(o)}`,new Promise(e=>{i.addEventListener(`load`,()=>e(i)),document.body.appendChild(i)})}function x({iframe:e,isVisible:t}){if(!t){e.style.width=`0`,e.style.height=`0`,e.style.border=`0`,e.style.position=`fixed`,e.style.top=`-1000px`,e.style.left=`-1000px`;return}e.style.position=`fixed`,e.style.top=`0`,e.style.left=`0`,e.style.width=`100%`,e.style.height=`100%`,e.style.pointerEvents=`auto`}function S(e=`/listener`){if(!window.opener)return null;let t=t=>{try{return t.location.origin===window.location.origin&&t.location.pathname===e}catch{return!1}};if(t(window.opener))return window.opener;try{let e=window.opener.frames;for(let n=0;n<e.length;n++)if(t(e[n]))return e[n];return null}catch(t){return console.error(`[findIframeInOpener] Error finding iframe with pathname ${e}:`,t),null}}function C(){if(typeof navigator>`u`)return!1;let e=navigator.userAgent;return!!(/iPhone|iPad|iPod/i.test(e)||/Macintosh/i.test(e)&&navigator.maxTouchPoints>1)}const w=C();function T(){if(typeof navigator>`u`)return!1;let e=navigator.userAgent.toLowerCase();return e.includes(`instagram`)||e.includes(`fban`)||e.includes(`fbav`)||e.includes(`facebook`)}const E=T();function D(e){w&&e.startsWith(`https://`)?window.location.href=`x-safari-https://${e.slice(8)}`:w&&e.startsWith(`http://`)?window.location.href=`x-safari-http://${e.slice(7)}`:window.location.href=`https://backend.frak.id/common/social?u=${encodeURIComponent(e)}`}function O(e,t){if(typeof window>`u`)return;let n=new URL(window.location.href),r=n.searchParams.get(`sso`);r&&(t.then(()=>{e.sendLifecycle({clientLifecycle:`sso-redirect-complete`,data:{compressed:r}}),console.log(`[SSO URL Listener] Forwarded compressed SSO data to iframe`)}).catch(e=>{console.error(`[SSO URL Listener] Failed to forward SSO data:`,e)}),n.searchParams.delete(`sso`),window.history.replaceState({},``,n.toString()),console.log(`[SSO URL Listener] SSO parameter detected and URL cleaned`))}var k=class e{config;iframe;isSetupDone=!1;lastResponse=null;lastRequest=null;constructor(e,t){this.config=e,this.iframe=t,this.lastRequest=null,this.lastResponse=null}setLastResponse(e,t){this.lastResponse={message:e,response:t,timestamp:Date.now()}}setLastRequest(e){this.lastRequest={event:e,timestamp:Date.now()}}updateSetupStatus(e){this.isSetupDone=e}base64Encode(e){try{return btoa(JSON.stringify(e))}catch(e){return console.warn(`Failed to encode debug data`,e),btoa(`Failed to encode data`)}}getIframeStatus(){return this.iframe?{loading:this.iframe.hasAttribute(`loading`),url:this.iframe.src,readyState:this.iframe.contentDocument?.readyState?+(this.iframe.contentDocument.readyState===`complete`):-1,contentWindow:!!this.iframe.contentWindow,isConnected:this.iframe.isConnected}:null}getNavigatorInfo(){return navigator?{userAgent:navigator.userAgent,language:navigator.language,onLine:navigator.onLine,screenWidth:window.screen.width,screenHeight:window.screen.height,pixelRatio:window.devicePixelRatio}:null}gatherDebugInfo(e){let t=this.getIframeStatus(),n=this.getNavigatorInfo(),r=`Unknown`;return e instanceof i?r=`FrakRpcError: ${e.code} '${e.message}'`:e instanceof Error?r=e.message:typeof e==`string`&&(r=e),{timestamp:new Date().toISOString(),encodedUrl:btoa(window.location.href),encodedConfig:this.config?this.base64Encode(this.config):`no-config`,navigatorInfo:n?this.base64Encode(n):`no-navigator`,iframeStatus:t?this.base64Encode(t):`not-iframe`,lastRequest:this.lastRequest?this.base64Encode(this.lastRequest):`No Frak request logged`,lastResponse:this.lastResponse?this.base64Encode(this.lastResponse):`No Frak response logged`,clientStatus:this.isSetupDone?`setup`:`not-setup`,error:r}}static empty(){return new e}formatDebugInfo(e){let t=this.gatherDebugInfo(e);return`
|
|
2
|
+
Debug Information:
|
|
3
|
+
-----------------
|
|
4
|
+
Timestamp: ${t.timestamp}
|
|
5
|
+
URL: ${t.encodedUrl}
|
|
6
|
+
Config: ${t.encodedConfig}
|
|
7
|
+
Navigator Info: ${t.navigatorInfo}
|
|
8
|
+
IFrame Status: ${t.iframeStatus}
|
|
9
|
+
Last Request: ${t.lastRequest}
|
|
10
|
+
Last Response: ${t.lastResponse}
|
|
11
|
+
Client Status: ${t.clientStatus}
|
|
12
|
+
Error: ${t.error}
|
|
13
|
+
`.trim()}};const A=(()=>{if(typeof navigator>`u`)return!1;let e=navigator.userAgent;if(!(/iPhone|iPad|iPod/i.test(e)||/Macintosh/i.test(e)&&navigator.maxTouchPoints>1))return!1;let t=e.toLowerCase();return t.includes(`instagram`)||t.includes(`fban`)||t.includes(`fbav`)||t.includes(`facebook`)})();function j(e){e?localStorage.setItem(c,e):localStorage.removeItem(c)}function M(e,t){try{let n=new URL(e);if(!n.searchParams.has(`u`))return e;let r=F(window.location.href,t);return n.searchParams.delete(`u`),n.searchParams.append(`u`,r),n.toString()}catch{return e}}function N(e){let t=new URL(window.location.href);e&&t.searchParams.set(`fmt`,e);let n=t.protocol===`http:`?`x-safari-http`:`x-safari-https`;window.location.href=`${n}://${t.host}${t.pathname}${t.search}${t.hash}`}function P(e){return e.includes(`/common/social`)}function F(e,t){if(!t)return e;try{let n=new URL(e);return n.searchParams.set(`fmt`,t),n.toString()}catch{return`${e}${e.includes(`?`)?`&`:`?`}fmt=${encodeURIComponent(t)}`}}function I(e,t,n,r,i){if(i){let e=M(t,r);window.open(e,`_blank`);return}if(p(t)){let i=M(t,r);f(i,{onFallback:()=>{e.contentWindow?.postMessage({clientLifecycle:`deep-link-failed`,data:{originalUrl:i}},n)}})}else if(A&&P(t))N(r);else{let e=M(t,r);window.location.href=e}}function L({iframe:e,targetOrigin:t}){let n=new r;return{handleEvent:r=>{if(!(`iframeLifecycle`in r))return;let{iframeLifecycle:i,data:a}=r;switch(i){case`connected`:n.resolve(!0);break;case`do-backup`:j(a.backup);break;case`remove-backup`:localStorage.removeItem(c);break;case`show`:case`hide`:x({iframe:e,isVisible:i===`show`});break;case`redirect`:I(e,a.baseRedirectUrl,t,a.mergeToken,a.openInNewTab);break}},isConnected:n.promise}}function R({config:c,iframe:l}){let u=c?.walletUrl??`https://wallet.frak.id`,d=typeof navigator<`u`?navigator.language?.split(`-`)[0]:void 0,f=c.metadata.lang??(d===`en`||d===`fr`?d:void 0),p=c.domain??(typeof window<`u`?window.location.hostname:``);e.setCacheScope(p,f),e.reset();let m=e.isCacheFresh?void 0:e.resolve(c.domain,c.walletUrl,f),h=L({iframe:l,targetOrigin:u}),g=new r,_=new k(c,l);if(!l.contentWindow)throw new i(a.configError,`The iframe does not have a content window`);let v=o({emittingTransport:l.contentWindow,listeningTransport:window,targetOrigin:u,middleware:[{async onRequest(e,t){if(!await h.isConnected)throw new i(a.clientNotConnected,`The iframe provider isn't connected yet`);return await g.promise,t}},{onRequest(e,t){return _.setLastRequest(e),t},onResponse(e,t){return _.setLastResponse(e,t),t}}],lifecycleHandlers:{iframeLifecycle:(e,t)=>{h.handleEvent(e)}}}),y=z(v,h),b=async()=>{y(),v.cleanup(),l.remove(),t(),e.clearCache(),e.reset()},x;console.log(`[Frak SDK] Initializing OpenPanel`),x=new s({apiUrl:`https://op-api.gcp.frak.id`,clientId:`6eacc8d7-49ac-4936-95e9-81ef29449570`,trackScreenViews:!0,trackOutgoingLinks:!0,trackAttributes:!1,filter:({type:e,payload:t})=>(e!==`track`||!t?.properties||`sdkVersion`in t.properties||(t.properties={...t.properties,sdkVersion:`0.2.1`,userAnonymousClientId:n()}),!0)}),x.setGlobalProperties({sdkVersion:`0.2.1`,userAnonymousClientId:n()}),x.init();let S=B({config:c,rpcClient:v,lifecycleManager:h,configPromise:m,contextSent:g}).then(()=>_.updateSetupStatus(!0)).catch(e=>{throw g.reject(e),e});return{config:c,debugInfo:_,waitForConnection:h.isConnected,waitForSetup:S,request:v.request,listenerRequest:v.listen,destroy:b,openPanel:x}}function z(e,t){let n,r,i=()=>e.sendLifecycle({clientLifecycle:`heartbeat`});async function a(){i(),n=setInterval(i,1e3),r=setTimeout(()=>{o(),console.log(`Heartbeat timeout: connection failed`)},3e4),await t.isConnected,o()}function o(){n&&clearInterval(n),r&&clearTimeout(r)}return a(),o}async function B({config:t,rpcClient:n,lifecycleManager:r,configPromise:i,contextSent:a}){await r.isConnected,O(n,r.isConnected);let o=new URL(window.location.href),s=o.searchParams.get(`fmt`)??void 0;s&&(o.searchParams.delete(`fmt`),window.history.replaceState({},``,o.toString()));let l=n=>{let r=n?.merchantId??t.metadata.merchantId??``,i=n?.domain??``,a=n?.allowedDomains??[],o=n?.sdkConfig;e.setConfig(o?{isResolved:!0,merchantId:r,domain:i,allowedDomains:a,hasRawSdkConfig:!0,name:o.name??t.metadata.name,logoUrl:o.logoUrl??t.metadata.logoUrl,homepageLink:o.homepageLink??t.metadata.homepageLink,lang:o.lang??t.metadata.lang,currency:o.currency??t.metadata.currency,hidden:o.hidden,css:o.css,translations:o.translations,placements:o.placements,components:o.components}:{isResolved:!0,merchantId:r,domain:i,allowedDomains:a,name:t.metadata.name,logoUrl:t.metadata.logoUrl,homepageLink:t.metadata.homepageLink,lang:t.metadata.lang,currency:t.metadata.currency})},u=!1,d=e=>{let t=u?void 0:s;u=!0;let r=e.hasRawSdkConfig?{name:e.name,logoUrl:e.logoUrl,homepageLink:e.homepageLink,lang:e.lang,currency:e.currency,hidden:e.hidden,css:e.css,translations:e.translations,placements:e.placements}:void 0;n.sendLifecycle({clientLifecycle:`resolved-config`,data:{merchantId:e.merchantId,domain:e.domain??``,allowedDomains:e.allowedDomains??[],sourceUrl:window.location.href,...t&&{pendingMergeToken:t},...r&&{sdkConfig:r}}})};e.isResolved&&(d(e.getConfig()),a.resolve()),i&&(l(await i),d(e.getConfig()),a.resolve());async function f(){let e=t.customizations?.css;e&&n.sendLifecycle({clientLifecycle:`modal-css`,data:{cssLink:e}})}async function p(){let e=t.customizations?.i18n;e&&n.sendLifecycle({clientLifecycle:`modal-i18n`,data:{i18n:e}})}async function m(){if(typeof window>`u`)return;let e=window.localStorage.getItem(c);e&&n.sendLifecycle({clientLifecycle:`restore-backup`,data:{backup:e}})}await Promise.allSettled([f(),p(),m()])}async function V({config:e}){let t=H(e),n=await b({config:t});if(!n){console.error(`Failed to create iframe`);return}let r=R({config:t,iframe:n});if(await r.waitForSetup,!await r.waitForConnection){console.error(`Failed to connect to client`);return}return r}function H(e){let t=h(e.metadata?.currency);return{...e,metadata:{...e.metadata,currency:t}}}export{d as _,E as a,b as c,_ as d,g as f,p as g,u as h,w as i,S as l,m,R as n,D as o,h as p,k as r,y as s,V as t,v as u,f as v,l as y};
|
|
@@ -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}var v=class extends Map{maxSize;constructor(e){super(),this.maxSize=e}get(e){let t=super.get(e);return super.has(e)&&(super.delete(e),super.set(e,t)),t}set(e,t){if(super.has(e)&&super.delete(e),super.set(e,t),this.maxSize&&this.size>this.maxSize){let e=super.keys().next().value;e!==void 0&&super.delete(e)}return this}};const y=new v(1024),b=new v(1024),x=3e4,S=new v(1024);async function C(e,{cacheKey:t,cacheTime:n=x}){if(n>0){let e=b.get(t);if(e&&Date.now()-e.created<n)return e.data}let r=S.get(t);if(r&&Date.now()-r<1e3)throw Error(`Cache: ${t} recently failed, backing off`);let i=y.get(t);i||(i=e(),y.set(t,i));try{let e=await i;return b.set(t,{data:e,created:Date.now()}),S.delete(t),e}catch(e){throw S.set(t,Date.now()),e}finally{y.delete(t)}}function w(e){return{clear:()=>{y.delete(e),b.delete(e)},has:(t=x)=>{let n=b.get(e);return n?Date.now()-n.created<t:!1}}}function T(){y.clear(),b.clear(),S.clear()}function E(e){return(0,t.jsonDecode)(s(e))}function D(e){return`r`in e&&!(`v`in e)}function O(e){return`v`in e&&e.v===2}const k=`fCtx`;function A(t){if(t)try{return O(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 j(t){if(!(!t||t.length===0))try{let n=E(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 M({url:e}){if(!e)return null;let t=new URL(e).searchParams.get(k);return t?j(t):null}function N({url:e,context:t}){if(!e)return null;let n=A(t);if(!n)return null;let r=new URL(e);return r.searchParams.set(k,n),r.toString()}function P(e){let t=new URL(e);return t.searchParams.delete(k),t.toString()}function ee({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?P(n):N({url:n,context:t}),r&&window.history.replaceState(null,``,r.toString())}const F={compress:A,decompress:j,parse:M,update:N,remove:P,replaceUrl:ee},I=`__frakSdkConfig`,L=`frak-config-cache`,R=`frak-merchant-id`,z={key:L},B=typeof window<`u`;function V(){return{isResolved:!1,merchantId:``}}let H=null;function U(){if(!B)return null;try{let e=localStorage.getItem(z.key);if(!e)return null;let t=JSON.parse(e);return t.config?.isResolved?(H=t,t):null}catch{return null}}function W(){return(H??U())?.config}function G(){let e=H??U();return e?Date.now()-e.timestamp<3e4:!1}function K(e){if(!(!B||!e.isResolved))try{let t={config:e,timestamp:Date.now()};localStorage.setItem(z.key,JSON.stringify(t)),H=t}catch{}}function q(){if(B){H=null;try{localStorage.removeItem(z.key)}catch{}}}function J(){B&&(window[I]||(window[I]=W()??V()))}J();function Y(){return B?window[I]??V():V()}function X(e){B&&window.dispatchEvent(new CustomEvent(`frak:config`,{detail:e}))}function Z(e){return e??(B?window.location.hostname:``)}async function Q(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();if(B)try{sessionStorage.setItem(R,o.merchantId)}catch{}return o}catch(e){console.warn(`[Frak SDK] Failed to fetch merchant config:`,e);return}}const $={getConfig:Y,get isResolved(){return Y().isResolved},get isCacheFresh(){return G()},setCacheScope(e,t){z.key=`${L}:${`${e}:${t??``}`}`,H=null},setConfig(e){if(B&&(window[I]=e),K(e),X(e),B&&e.merchantId)try{sessionStorage.setItem(R,e.merchantId)}catch{}},reset(){let e=W()??V();B&&(window[I]=e),X(e)},clearCache(){if(q(),T(),B)try{sessionStorage.removeItem(R)}catch{}},resolve(e,t,n){let r=Z(e);return r?C(async()=>{let e=await Q(r,t,n);if(!e)throw Error(`Config resolution returned empty`);return e},{cacheKey:`sdkConfig:${r}:${n??``}`,cacheTime:1/0}).catch(()=>void 0):Promise.resolve(void 0)},getMerchantId(){let e=Y();if(e.isResolved&&e.merchantId)return e.merchantId;if(B)try{return sessionStorage.getItem(R)??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)}}Object.defineProperty(exports,`_`,{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,`g`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return D}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return $}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return F}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return te}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`v`,{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,`y`,{enumerable:!0,get:function(){return i}});
|
|
@@ -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 te(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 _=`https://backend.frak.id`;function v(e){return e.includes(`localhost:3000`)||e.includes(`localhost:3010`)}function y(e){return v(e)?`https://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 _}var x=class extends Map{maxSize;constructor(e){super(),this.maxSize=e}get(e){let t=super.get(e);return super.has(e)&&(super.delete(e),super.set(e,t)),t}set(e,t){if(super.has(e)&&super.delete(e),super.set(e,t),this.maxSize&&this.size>this.maxSize){let e=super.keys().next().value;e!==void 0&&super.delete(e)}return this}};const S=new x(1024),C=new x(1024),w=3e4,T=new x(1024);async function E(e,{cacheKey:t,cacheTime:n=w}){if(n>0){let e=C.get(t);if(e&&Date.now()-e.created<n)return e.data}let r=T.get(t);if(r&&Date.now()-r<1e3)throw Error(`Cache: ${t} recently failed, backing off`);let i=S.get(t);i||(i=e(),S.set(t,i));try{let e=await i;return C.set(t,{data:e,created:Date.now()}),T.delete(t),e}catch(e){throw T.set(t,Date.now()),e}finally{S.delete(t)}}function D(e){return{clear:()=>{S.delete(e),C.delete(e)},has:(t=w)=>{let n=C.get(e);return n?Date.now()-n.created<t:!1}}}function O(){S.clear(),C.clear(),T.clear()}function k(e){return a(f(e))}function ne(e){return`r`in e&&!(`v`in e)}function A(e){return`v`in e&&e.v===2}const j=`fCtx`;function M(e){if(e)try{return A(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 N(t){if(!(!t||t.length===0))try{let r=k(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 P({url:e}){if(!e)return null;let t=new URL(e).searchParams.get(j);return t?N(t):null}function F({url:e,context:t}){if(!e)return null;let n=M(t);if(!n)return null;let r=new URL(e);return r.searchParams.set(j,n),r.toString()}function I(e){let t=new URL(e);return t.searchParams.delete(j),t.toString()}function L({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?I(n):F({url:n,context:t}),r&&window.history.replaceState(null,``,r.toString())}const R={compress:M,decompress:N,parse:P,update:F,remove:I,replaceUrl:L},z=`__frakSdkConfig`,B=`frak-config-cache`,V=`frak-merchant-id`,H={key:B},U=typeof window<`u`;function W(){return{isResolved:!1,merchantId:``}}let G=null;function K(){if(!U)return null;try{let e=localStorage.getItem(H.key);if(!e)return null;let t=JSON.parse(e);return t.config?.isResolved?(G=t,t):null}catch{return null}}function q(){return(G??K())?.config}function J(){let e=G??K();return e?Date.now()-e.timestamp<3e4:!1}function Y(e){if(!(!U||!e.isResolved))try{let t={config:e,timestamp:Date.now()};localStorage.setItem(H.key,JSON.stringify(t)),G=t}catch{}}function X(){if(U){G=null;try{localStorage.removeItem(H.key)}catch{}}}function re(){U&&(window[z]||(window[z]=q()??W()))}re();function Z(){return U?window[z]??W():W()}function Q(e){U&&window.dispatchEvent(new CustomEvent(`frak:config`,{detail:e}))}function ie(e){return e??(U?window.location.hostname:``)}async function ae(e,t,n){try{let r=b(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();if(U)try{sessionStorage.setItem(V,o.merchantId)}catch{}return o}catch(e){console.warn(`[Frak SDK] Failed to fetch merchant config:`,e);return}}const $={getConfig:Z,get isResolved(){return Z().isResolved},get isCacheFresh(){return J()},setCacheScope(e,t){H.key=`${B}:${`${e}:${t??``}`}`,G=null},setConfig(e){if(U&&(window[z]=e),Y(e),Q(e),U&&e.merchantId)try{sessionStorage.setItem(V,e.merchantId)}catch{}},reset(){let e=q()??W();U&&(window[z]=e),Q(e)},clearCache(){if(X(),O(),U)try{sessionStorage.removeItem(V)}catch{}},resolve(e,t,n){let r=ie(e);return r?E(async()=>{let e=await ae(r,t,n);if(!e)throw Error(`Config resolution returned empty`);return e},{cacheKey:`sdkConfig:${r}:${n??``}`,cacheTime:1/0}).catch(()=>void 0):Promise.resolve(void 0)},getMerchantId(){let e=Z();if(e.isResolved&&e.merchantId)return e.merchantId;if(U)try{return sessionStorage.getItem(V)??void 0}catch{}},async resolveMerchantId(e,t){return $.getMerchantId()||(await $.resolve(e,t))?.merchantId}};function oe(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{d as _,A as a,D as c,te as d,h as f,f as g,p as h,ne as i,E as l,m,$ as n,k as o,g as p,R as r,O as s,oe as t,b as u,u as v,l as y};
|
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.eb3cff34",
|
|
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,21 @@
|
|
|
91
91
|
"viem": "^2.x"
|
|
92
92
|
},
|
|
93
93
|
"dependencies": {
|
|
94
|
-
"@frak-labs/frame-connector": "0.2.0-beta.
|
|
94
|
+
"@frak-labs/frame-connector": "0.2.0-beta.eb3cff34",
|
|
95
95
|
"@openpanel/web": "^1.2.0"
|
|
96
96
|
},
|
|
97
97
|
"devDependencies": {
|
|
98
98
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
99
|
-
"@frak-labs/dev-tooling": "0.0.0",
|
|
100
99
|
"@frak-labs/test-foundation": "0.1.0",
|
|
101
100
|
"@rolldown/plugin-node-polyfills": "^1.0.3",
|
|
102
101
|
"@types/jsdom": "^28.0.0",
|
|
103
|
-
"@types/node": "^
|
|
104
|
-
"@vitest/coverage-v8": "^4.1.
|
|
105
|
-
"@vitest/ui": "^4.1.
|
|
102
|
+
"@types/node": "^25.6.0",
|
|
103
|
+
"@vitest/coverage-v8": "^4.1.4",
|
|
104
|
+
"@vitest/ui": "^4.1.4",
|
|
106
105
|
"jsdom": "^29.0.0",
|
|
107
|
-
"tsdown": "^0.
|
|
108
|
-
"typescript": "^
|
|
109
|
-
"viem": "^2.
|
|
110
|
-
"vitest": "^4.1.
|
|
106
|
+
"tsdown": "^0.21.8",
|
|
107
|
+
"typescript": "^6.0.2",
|
|
108
|
+
"viem": "^2.47.16",
|
|
109
|
+
"vitest": "^4.1.4"
|
|
111
110
|
}
|
|
112
111
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DisplaySharingPageParamsType,
|
|
3
|
+
DisplaySharingPageResultType,
|
|
4
|
+
FrakClient,
|
|
5
|
+
} from "../types";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Function used to display a sharing page
|
|
9
|
+
* @param client - The current Frak Client
|
|
10
|
+
* @param params - The parameters to customize the sharing page (products, link override, metadata)
|
|
11
|
+
* @param placement - Optional placement ID to associate with this display request
|
|
12
|
+
* @returns The result indicating the user's action (shared, copied, or dismissed)
|
|
13
|
+
*
|
|
14
|
+
* @description This function will display a full-page sharing UI to the user,
|
|
15
|
+
* showing product info, estimated rewards, sharing steps, FAQ, and share/copy buttons.
|
|
16
|
+
* The sharing link is generated from the user's wallet context + merchant info.
|
|
17
|
+
*
|
|
18
|
+
* @remarks
|
|
19
|
+
* - The promise resolves on the first user action (share or copy) but the page stays visible
|
|
20
|
+
* - The user can continue to share/copy multiple times after the initial resolution
|
|
21
|
+
* - Dismissing the page after a share/copy action is a no-op (promise already resolved)
|
|
22
|
+
* - If the user dismisses without any action, the promise resolves with `{ action: "dismissed" }`
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const result = await displaySharingPage(frakClient, {
|
|
27
|
+
* products: [
|
|
28
|
+
* {
|
|
29
|
+
* title: "Babies camel cuir velours bout carré",
|
|
30
|
+
* imageUrl: "https://example.com/product.jpg",
|
|
31
|
+
* },
|
|
32
|
+
* ],
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* console.log("User action:", result.action); // "shared" | "copied" | "dismissed"
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export async function displaySharingPage(
|
|
39
|
+
client: FrakClient,
|
|
40
|
+
params: DisplaySharingPageParamsType,
|
|
41
|
+
placement?: string
|
|
42
|
+
): Promise<DisplaySharingPageResultType> {
|
|
43
|
+
return await client.request({
|
|
44
|
+
method: "frak_displaySharingPage",
|
|
45
|
+
params: placement
|
|
46
|
+
? [params, client.config.metadata, placement]
|
|
47
|
+
: [params, client.config.metadata],
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
import type { Address, Hex } from "viem";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
beforeEach,
|
|
4
|
+
describe,
|
|
5
|
+
expect,
|
|
6
|
+
it,
|
|
7
|
+
vi,
|
|
8
|
+
} from "../../tests/vitest-fixtures";
|
|
3
9
|
import type { FrakClient, GetMerchantInformationReturnType } from "../types";
|
|
10
|
+
import { clearAllCache } from "../utils/cache";
|
|
4
11
|
import { getMerchantInformation } from "./getMerchantInformation";
|
|
5
12
|
|
|
6
13
|
describe("getMerchantInformation", () => {
|
|
14
|
+
// Clear cache between tests to ensure isolation
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
clearAllCache();
|
|
17
|
+
});
|
|
18
|
+
|
|
7
19
|
describe("success cases", () => {
|
|
8
20
|
it("should call client.request with correct method", async () => {
|
|
9
21
|
const mockResponse: GetMerchantInformationReturnType = {
|
|
@@ -1,16 +1,31 @@
|
|
|
1
1
|
import type { FrakClient, GetMerchantInformationReturnType } from "../types";
|
|
2
|
+
import { withCache } from "../utils/cache";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
|
-
* Fetch the current merchant information (name, rewards, tiers) from the wallet iframe
|
|
5
|
+
* Fetch the current merchant information (name, rewards, tiers) from the wallet iframe.
|
|
6
|
+
*
|
|
7
|
+
* Results are cached in memory for 30 seconds by default. Concurrent calls
|
|
8
|
+
* while a request is in-flight are deduplicated automatically.
|
|
9
|
+
*
|
|
5
10
|
* @param client - The current Frak Client
|
|
11
|
+
* @param options - Optional cache configuration
|
|
12
|
+
* @param options.cacheTime - Time in ms to cache the result. Default: 30_000 (30s). Set to 0 to disable.
|
|
6
13
|
* @returns The merchant information including available reward tiers
|
|
7
14
|
*
|
|
8
15
|
* @see {@link @frak-labs/core-sdk!index.GetMerchantInformationReturnType | `GetMerchantInformationReturnType`} for the return type shape
|
|
9
16
|
*/
|
|
10
17
|
export async function getMerchantInformation(
|
|
11
|
-
client: FrakClient
|
|
18
|
+
client: FrakClient,
|
|
19
|
+
options?: { cacheTime?: number }
|
|
12
20
|
): Promise<GetMerchantInformationReturnType> {
|
|
13
|
-
return
|
|
14
|
-
|
|
15
|
-
|
|
21
|
+
return withCache(
|
|
22
|
+
() =>
|
|
23
|
+
client.request({
|
|
24
|
+
method: "frak_getMerchantInformation",
|
|
25
|
+
}),
|
|
26
|
+
{
|
|
27
|
+
cacheKey: "frak_getMerchantInformation",
|
|
28
|
+
cacheTime: options?.cacheTime,
|
|
29
|
+
}
|
|
30
|
+
);
|
|
16
31
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { FrakClient } from "../types";
|
|
2
|
+
import { withCache } from "../utils/cache";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Fetch a merge token for the current anonymous identity.
|
|
6
|
+
*
|
|
7
|
+
* Used by in-app browser redirect flows to preserve identity
|
|
8
|
+
* when switching from a WebView to the system browser.
|
|
9
|
+
* The token is appended as `?fmt=` to the redirect URL.
|
|
10
|
+
*
|
|
11
|
+
* Results are cached in memory for 30 seconds by default. Concurrent calls
|
|
12
|
+
* while a request is in-flight are deduplicated automatically.
|
|
13
|
+
*
|
|
14
|
+
* @param client - The current Frak Client
|
|
15
|
+
* @param options - Optional cache configuration
|
|
16
|
+
* @param options.cacheTime - Time in ms to cache the result. Default: 30_000 (30s). Set to 0 to disable.
|
|
17
|
+
* @returns The merge token string, or null if unavailable
|
|
18
|
+
*/
|
|
19
|
+
export async function getMergeToken(
|
|
20
|
+
client: FrakClient,
|
|
21
|
+
options?: { cacheTime?: number }
|
|
22
|
+
): Promise<string | null> {
|
|
23
|
+
return withCache(
|
|
24
|
+
() =>
|
|
25
|
+
client.request({
|
|
26
|
+
method: "frak_getMergeToken",
|
|
27
|
+
}),
|
|
28
|
+
{
|
|
29
|
+
cacheKey: "frak_getMergeToken",
|
|
30
|
+
cacheTime: options?.cacheTime,
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { FrakClient, UserReferralStatusType } from "../types";
|
|
2
|
+
import { withCache } from "../utils/cache";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Fetch the current user's referral status on the current merchant.
|
|
6
|
+
*
|
|
7
|
+
* The listener resolves the user's identity (via clientId or wallet session)
|
|
8
|
+
* and checks whether a referral link exists where the user is the referee.
|
|
9
|
+
*
|
|
10
|
+
* Results are cached in memory for 30 seconds by default. Concurrent calls
|
|
11
|
+
* while a request is in-flight are deduplicated automatically.
|
|
12
|
+
*
|
|
13
|
+
* Returns `null` when the user's identity cannot be resolved.
|
|
14
|
+
*
|
|
15
|
+
* @param client - The current Frak Client
|
|
16
|
+
* @param options - Optional cache configuration
|
|
17
|
+
* @param options.cacheTime - Time in ms to cache the result. Default: 30_000 (30s). Set to 0 to disable.
|
|
18
|
+
* @returns The user's referral status, or `null` if identity cannot be resolved
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* const status = await getUserReferralStatus(client);
|
|
23
|
+
* if (status?.isReferred) {
|
|
24
|
+
* console.log("User was referred to this merchant");
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export async function getUserReferralStatus(
|
|
29
|
+
client: FrakClient,
|
|
30
|
+
options?: { cacheTime?: number }
|
|
31
|
+
): Promise<UserReferralStatusType | null> {
|
|
32
|
+
return withCache(
|
|
33
|
+
() =>
|
|
34
|
+
client.request({
|
|
35
|
+
method: "frak_getUserReferralStatus",
|
|
36
|
+
}),
|
|
37
|
+
{
|
|
38
|
+
cacheKey: "frak_getUserReferralStatus",
|
|
39
|
+
cacheTime: options?.cacheTime,
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
}
|
package/src/actions/index.ts
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
export { displayEmbeddedWallet } from "./displayEmbeddedWallet";
|
|
2
2
|
export { displayModal } from "./displayModal";
|
|
3
|
+
export { displaySharingPage } from "./displaySharingPage";
|
|
3
4
|
export { ensureIdentity } from "./ensureIdentity";
|
|
4
5
|
export { getMerchantInformation } from "./getMerchantInformation";
|
|
6
|
+
export { getMergeToken } from "./getMergeToken";
|
|
7
|
+
export { getUserReferralStatus } from "./getUserReferralStatus";
|
|
5
8
|
export { openSso } from "./openSso";
|
|
6
9
|
export { prepareSso } from "./prepareSso";
|
|
7
10
|
export {
|
|
8
11
|
type ProcessReferralOptions,
|
|
9
12
|
processReferral,
|
|
10
13
|
} from "./referral/processReferral";
|
|
11
|
-
// Referral
|
|
14
|
+
// Referral
|
|
12
15
|
export { referralInteraction } from "./referral/referralInteraction";
|
|
16
|
+
export {
|
|
17
|
+
REFERRAL_SUCCESS_EVENT,
|
|
18
|
+
setupReferral,
|
|
19
|
+
} from "./referral/setupReferral";
|
|
13
20
|
export { sendInteraction } from "./sendInteraction";
|
|
14
21
|
// Helper to track the purchase status
|
|
15
22
|
export { trackPurchaseStatus } from "./trackPurchaseStatus";
|