UNPKG

@frak-labs/core-sdk

Version:

Core SDK of the Frak wallet, low level library to interact directly with the frak ecosystem.

1,390 lines (1,389 loc) 43.1 kB
import { OpenPanel } from "@openpanel/web"; import { Address, Hex } from "viem"; import { LifecycleMessage, RpcClient } from "@frak-labs/frame-connector"; import { SiweMessage } from "viem/siwe"; //#region src/types/tracking.d.ts type UtmParams = { source?: string; medium?: string; campaign?: string; term?: string; content?: string; }; /** * Attribution parameters appended to outbound sharing URLs. * * Defaults are derived from the V2 Frak context when available: * - `utmSource`: `"frak"` * - `utmMedium`: `"referral"` * - `utmCampaign`: merchantId (`context.m`) * - `via`: `"frak"` * - `ref`: clientId (`context.c`) * * Fields explicitly set here override the defaults. Existing params on the * base URL are preserved (gap-fill policy) to respect merchant-provided UTMs. */ type AttributionParams = { utmSource?: string; utmMedium?: string; utmCampaign?: string; utmContent?: string; utmTerm?: string; via?: string; ref?: string; }; /** * Merchant-level attribution defaults. * * Same shape as {@link AttributionParams} minus `utmContent`, because * `utm_content` describes the specific content/creative being shared and is * inherently per-call or per-product (never a merchant-wide default). * * Used as the shape for both: * - `FrakWalletSdkConfig.attribution` (SDK-side compile-time defaults) * - Backend merchant-config attribution (dashboard-driven defaults) */ type AttributionDefaults = Omit<AttributionParams, "utmContent">; type TrackArrivalParams = { /** Sharer wallet address. Accepted in both V1 (legacy) and V2 (authenticated sharer) contexts. */referrerWallet?: Address; referrerClientId?: string; referrerMerchantId?: string; /** Epoch seconds timestamp from the referral link creation */ referralTimestamp?: number; }; type TrackArrivalResult = { success: boolean; identityGroupId?: string; referralLinkId?: string; error?: string; }; //#endregion //#region src/types/config.d.ts /** * All the currencies available * @category Config */ type Currency = "eur" | "usd" | "gbp"; /** * All the languages available * @category Config */ type Language = "fr" | "en"; /** * Configuration for the Frak Wallet SDK * @category Config */ type FrakWalletSdkConfig = { /** * The Frak wallet url * @defaultValue "https://wallet.frak.id" */ walletUrl?: string; /** * Some metadata about your implementation of the Frak SDK */ metadata: { /** * Your application name (will be displayed in a few modals and in SSO) */ name?: string; /** * Your merchant ID from the Frak dashboard (UUID format) * Used for referral tracking and analytics * If not provided, will be auto-fetched from the backend using your domain */ merchantId?: string; /** * Language to display in the modal * If undefined, will default to the browser language */ lang?: Language; /** * The currency to display in the modal * @defaultValue `"eur"` */ currency?: Currency; /** * The logo URL that will be displayed in a few components */ logoUrl?: string; /** * The homepage link that could be displayed in a few components */ homepageLink?: string; }; /** * Some customization for the modal */ customizations?: { /** * Custom CSS styles to apply to the modals and components */ css?: `${string}.css`; /** * Custom i18n configuration for the modal */ i18n?: I18nConfig; }; /** * The domain name of your application * @defaultValue window.location.host */ domain?: string; /** * Wait for backend config before rendering components. * When true (default), components show a spinner until backend config is resolved. * When false, components render immediately with SDK static config / HTML attributes. * @defaultValue true */ waitForBackendConfig?: boolean; /** * Default attribution params (UTM / via / ref) appended to outbound * sharing URLs. Per-call `displaySharingPage` overrides win, then backend * config, then this SDK-level default. `utm_content` is intentionally * excluded — it is per-content/per-product, never a merchant-wide default. */ attribution?: AttributionDefaults; /** * Preload specific UI views inside the listener iframe for better UX. * Default: ["sharing"] */ preload?: ListenerPreloadOption[]; }; /** * Custom i18n configuration for the modal * See [i18next json format](https://www.i18next.com/misc/json-format#i18next-json-v4) * * Available variables * - `{{ productName }}` : The name of your website (`metadata.name`) * - `{{ productOrigin }}` : The origin url of your website * - `{{ estimatedReward }}` : The estimated reward for the user (based on the specific `targetInteraction` you can specify, or the max referrer reward if no target interaction is specified) * * Context of the translation [see i18n context](https://www.i18next.com/translation-function/context) * - For modal display, the key of the final action (`sharing`, `reward`, or undefined) * - For embedded wallet display, the key of the logged in action (`sharing` or undefined) * * @example * ```ts * // Multi language config * const multiI18n = { * fr: { * "sdk.modal.title": "Titre de modal", * "sdk.modal.description": "Description de modal, avec {{ estimatedReward }} de gains possible", * }, * en: "https://example.com/en.json" * } * * // Single language config * const singleI18n = { * "sdk.modal.title": "Modal title", * "sdk.modal.description": "Modal description, with {{ estimatedReward }} of gains possible", * } * ``` * * @category Config */ type I18nConfig = Record<Language, LocalizedI18nConfig> | LocalizedI18nConfig; /** * Options for preloading the listener UI * @category Config */ type ListenerPreloadOption = "modal" | "sharing"; /** * A localized i18n config (inline objects only — URL-based i18n removed) * @category Config */ type LocalizedI18nConfig = { [key: string]: string; }; //#endregion //#region src/types/resolvedConfig.d.ts /** * Response from the merchant resolve endpoint * @category Config */ type MerchantConfigResponse = { merchantId: string; name: string; domain: string; allowedDomains: string[]; sdkConfig?: ResolvedSdkConfig; }; /** * Resolved placement config from backend * Translations already flattened: default + lang-specific merged into one record * @category Config */ type ResolvedPlacement = { /** Per-component configuration within this placement */components?: { buttonShare?: { text?: string; noRewardText?: string; clickAction?: "embedded-wallet" | "share-modal" | "sharing-page"; css?: string; }; buttonWallet?: { position?: "right" | "left"; css?: string; }; openInApp?: { text?: string; css?: string; }; postPurchase?: { badgeText?: string; refereeText?: string; refereeNoRewardText?: string; referrerText?: string; referrerNoRewardText?: string; ctaText?: string; ctaNoRewardText?: string; css?: string; }; banner?: { referralTitle?: string; referralDescription?: string; referralCta?: string; inappTitle?: string; inappDescription?: string; inappCta?: string; css?: string; }; }; targetInteraction?: string; /** Already flattened: default + lang-specific merged into one record */ translations?: Record<string, string>; /** Global placement CSS (applied to modals/listener) */ css?: string; }; /** * Resolved SDK config from backend `/resolve` endpoint * Language resolution and translation merging already applied * @category Config */ type ResolvedSdkConfig = { name?: string; logoUrl?: string; homepageLink?: string; currency?: Currency; lang?: Language; /** When true, all SDK components should be hidden */ hidden?: boolean; css?: string; translations?: Record<string, string>; placements?: Record<string, ResolvedPlacement>; /** Global component defaults (used when no placement override exists) */ components?: ResolvedPlacement["components"]; /** * Default attribution params applied when building outbound sharing URLs. * Per-call overrides win over these backend defaults; `utm_content` is * intentionally excluded (per-content/per-product, never a merchant default). */ attribution?: AttributionDefaults; }; /** * Internal SDK config store state * Merged config: backend > SDK static > defaults * Components subscribe to this reactively * @category Config */ type SdkResolvedConfig = { /** Whether the backend config has been resolved */isResolved: boolean; /** Merchant ID from resolution */ merchantId: string; /** Domain returned by the resolve endpoint */ domain?: string; /** Domains allowed for this merchant (used by iframe trust check) */ allowedDomains?: string[]; /** Whether the resolve returned a backend sdkConfig object */ hasRawSdkConfig?: boolean; /** Merged metadata fields */ name?: string; logoUrl?: string; homepageLink?: string; lang?: Language; currency?: Currency; /** When true, all SDK components should be hidden */ hidden?: boolean; /** Global CSS from backend config (passed to iframe) */ css?: string; /** Global translations (for reference / component fallback) */ translations?: Record<string, string>; /** Named placements (keyed by placement ID) */ placements?: Record<string, ResolvedPlacement>; /** Global component defaults (fallback for placement-level overrides) */ components?: ResolvedPlacement["components"]; /** Merged attribution defaults: backend > SDK static config */ attribution?: AttributionDefaults; }; //#endregion //#region src/types/lifecycle/client.d.ts /** * Event related to the iframe lifecycle * @ignore */ type ClientLifecycleEvent = CustomCssEvent | CustomI18nEvent | RestoreBackupEvent | HearbeatEvent | SsoRedirectCompleteEvent | DeepLinkFailedEvent | ResolvedConfigEvent; type CustomCssEvent = { clientLifecycle: "modal-css"; data: { cssLink: string; }; }; type CustomI18nEvent = { clientLifecycle: "modal-i18n"; data: { i18n: I18nConfig; }; }; type RestoreBackupEvent = { clientLifecycle: "restore-backup"; data: { backup: string; }; }; type HearbeatEvent = { clientLifecycle: "heartbeat"; data?: never; }; type SsoRedirectCompleteEvent = { clientLifecycle: "sso-redirect-complete"; data: { compressed: string; }; }; type DeepLinkFailedEvent = { clientLifecycle: "deep-link-failed"; data: { originalUrl: string; }; }; type ResolvedConfigEvent = { clientLifecycle: "resolved-config"; data: { merchantId: string; /** The domain the backend resolved this config for */ domain: string; /** All domains registered for this merchant (for domain proof) */ allowedDomains: string[]; /** Full URL of the parent page (for interaction tracking) */ sourceUrl: string; /** * Pending merge token extracted from URL (?fmt= parameter). * When present, listener should execute identity merge in background. */ pendingMergeToken?: string; /** * Persistent per-origin anonymous id generated on the partner site * (SDK-side localStorage). Propagated here so the listener can * set it as an OpenPanel global property and stitch SDK events * with listener events in the same funnel. */ sdkAnonymousId?: string; sdkConfig?: ResolvedSdkConfig; }; }; //#endregion //#region src/types/lifecycle/iframe.d.ts /** * Event related to the iframe lifecycle * @ignore */ type IFrameLifecycleEvent = { iframeLifecycle: "connected" | "show" | "hide" | "remove-backup"; data?: never; } | DoBackupEvent | RedirectRequestEvent; type DoBackupEvent = { iframeLifecycle: "do-backup"; data: { backup?: string; }; }; type RedirectRequestEvent = { iframeLifecycle: "redirect"; data: { /** * The base url to redirect to * If it contain a query param `u`, the client need will suffix the current url to the base url */ baseRedirectUrl: string; /** * Optional merge token for anonymous identity merging * When provided, appended as ?fmt= query parameter to the final redirect URL * Used when redirecting out of social browsers to preserve identity across contexts */ mergeToken?: string; /** * When true, open the URL in a new tab via window.open(_blank) * instead of navigating the current page. * Requires the postMessage to include user activation delegation * (includeUserActivation: true) so Safari allows the popup. */ openInNewTab?: boolean; }; }; //#endregion //#region src/constants/interactionTypes.d.ts /** * The supported interaction type keys * * - `referral` - User arrived via a referral link * - `create_referral_link` - User created/shared a referral link * - `purchase` - User completed a purchase * - `custom.${string}` - Custom interaction type defined per campaign * * @inline */ type InteractionTypeKey = "referral" | "create_referral_link" | "purchase" | `custom.${string}`; //#endregion //#region src/types/rpc/modal/generic.d.ts /** * Represent a generic modal step type * @ignore * @inline */ type GenericModalStepType<TKey, TParams, TReturns> = { key: TKey; params: TParams extends never ? ModalStepMetadata : ModalStepMetadata & TParams; returns: TReturns; }; /** * Metadata that can be used to customize a modal step * @group Modal Display * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead */ type ModalStepMetadata = { metadata?: { /** * Custom title for the step * If none provided, it will use an internationalized text * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead */ title?: string; /** * Custom description for the step * If none provided, it will use an internationalized text * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead */ description?: string; /** * Custom text for the primary action of the step * If none provided, it will use an internationalized text * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead */ primaryActionText?: string; /** * Custom text for the secondary action of the step * If none provided, it will use an internationalized text * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead */ secondaryActionText?: string; }; }; //#endregion //#region src/types/rpc/modal/final.d.ts /** * The final modal step type, could be used to display sharing options or a success reward screen. * * **Input**: What type final step to display? * **Output**: None * * @group Modal Display */ type FinalModalStepType = GenericModalStepType<"final", { dismissedMetadata?: ModalStepMetadata["metadata"]; action: FinalActionType; autoSkip?: boolean; }, object>; /** * The different types of final actions we can display in the final step * @group Modal Display */ type FinalActionType = { key: "sharing"; options?: { /** * @deprecated Use the top level `config.metadata.i18n` instead */ popupTitle?: string; /** * @deprecated Use the top level `config.metadata.i18n` instead */ text?: string; link?: string; }; } | { key: "reward"; options?: never; }; //#endregion //#region src/types/rpc/sso.d.ts /** * SSO Metadata */ type SsoMetadata = { /** * URL to your client, if provided will be displayed in the SSO header */ logoUrl?: string; /** * Link to your homepage, if referenced your app name will contain a link on the sso page */ homepageLink?: string; }; /** * Params for preparing SSO (generating URL) * Same as OpenSsoParamsType but without openInSameWindow (popup-only operation) * @group RPC Schema */ type PrepareSsoParamsType = { /** * Redirect URL after the SSO (optional) */ redirectUrl?: string; /** * If the SSO should directly exit (close the popup) after completion. * * Defaults to `true` when `redirectUrl` is omitted, `false` otherwise. * The default is applied by {@link @frak-labs/core-sdk!actions.openSso | `openSso()`} * before the SSO URL is generated and by the wallet SSO route as a fallback * for older SDK callers. */ directExit?: boolean; /** * Language of the SSO page (optional) * It will default to the current user language (or "en" if unsupported language) */ lang?: "en" | "fr"; /** * Custom SSO metadata */ metadata?: SsoMetadata; }; /** * Response after preparing SSO * @group RPC Schema */ type PrepareSsoReturnType = { /** * The SSO URL that should be opened in a popup */ ssoUrl: string; }; /** * Response after an SSO has been openned */ type OpenSsoReturnType = { /** * Optional wallet address, returned when SSO completes via postMessage * Note: Only present when SSO flow completes (not immediately on open) */ wallet?: Hex; }; /** * Params to start a SSO * @group RPC Schema */ type OpenSsoParamsType = PrepareSsoParamsType & { /** * Indicate whether we want todo the flow within the same window context, or if we want to do it with an external popup window openned * Note: Default true if redirectUrl is present, otherwise, false */ openInSameWindow?: boolean; /** * Custom SSO popup url if user want additionnal customisation */ ssoPopupUrl?: string; }; //#endregion //#region src/types/rpc/modal/login.d.ts /** @inline */ type LoginWithSso = { allowSso: true; ssoMetadata?: SsoMetadata; }; /** @inline */ type LoginWithoutSso = { allowSso?: false; ssoMetadata?: never; }; /** * The login step for a Modal * * **Input**: Do we allow SSO or not? Is yes then the SSO metadata * **Output**: The logged in wallet address * * @group Modal Display */ type LoginModalStepType = GenericModalStepType<"login", LoginWithSso | LoginWithoutSso, { wallet: Address; webauthnProof?: { challenge: Hex; authenticatorResponse: string; }; }>; //#endregion //#region src/types/rpc/modal/siweAuthenticate.d.ts /** * Parameters used send a SIWE rpc request */ type SiweAuthenticationParams = Omit<SiweMessage, "address" | "chainId" | "expirationTime" | "issuedAt" | "notBefore"> & { expirationTimeTimestamp?: number; notBeforeTimestamp?: number; }; /** * Return type of the Siwe transaction rpc request * @inline */ type SiweAuthenticateReturnType = { signature: Hex; message: string; }; /** * The SIWE authentication step for a Modal * * **Input**: SIWE message parameters * **Output**: SIWE result (message signed and wallet signature) * * @group Modal Display */ type SiweAuthenticateModalStepType = GenericModalStepType<"siweAuthenticate", { siwe: SiweAuthenticationParams; }, SiweAuthenticateReturnType>; //#endregion //#region src/types/rpc/modal/transaction.d.ts /** * Generic format representing a tx to be sent */ type SendTransactionTxType = { to: Address; data?: Hex; value?: Hex; }; /** * Return type of the send transaction rpc request * @inline */ type SendTransactionReturnType = { hash: Hex; }; /** * The send transaction step for a Modal * * **Input**: Either a single tx or an array of tx to be sent * **Output**: The hash of the tx(s) hash (in case of multiple tx, still returns a single hash because it's bundled on the wallet level) * * @group Modal Display */ type SendTransactionModalStepType = GenericModalStepType<"sendTransaction", { tx: SendTransactionTxType | SendTransactionTxType[]; }, SendTransactionReturnType>; //#endregion //#region src/types/rpc/displayModal.d.ts /** * Generic type of steps we will display in the modal to the end user * @group Modal Display */ type ModalStepTypes = LoginModalStepType | SiweAuthenticateModalStepType | SendTransactionModalStepType | FinalModalStepType; /** * Type for the result of a modal request * Just the `returns` type of each `ModalStepTypes` * @typeParam T - The list of modal steps we expect to have in the modal * @group Modal Display * @group RPC Schema */ type ModalRpcStepsResultType<T extends ModalStepTypes[] = ModalStepTypes[]> = { [K in T[number]["key"]]: Extract<T[number], { key: K; }>["returns"] }; /** * Type for the RPC input of a modal * Just the `params` type of each `ModalStepTypes` * @typeParam T - The list of modal steps we expect to have in the modal * @group Modal Display * @group RPC Schema */ type ModalRpcStepsInput<T extends ModalStepTypes[] = ModalStepTypes[]> = { [K in T[number]["key"]]?: Extract<T[number], { key: K; }>["params"] }; /** * RPC metadata for the modal, used on top level modal configuration * @group Modal Display * @group RPC Schema */ type ModalRpcMetadata = { header?: { title?: string; icon?: string; }; targetInteraction?: InteractionTypeKey; /** * Some i18n override for the displayed modal (i.e. update the displayed text only for this modal) */ i18n?: I18nConfig; } & ({ isDismissible: true; /** * @deprecated Use `config.customizations.i18n` or `metadata.i18n` instead */ dismissActionTxt?: string; } | { isDismissible?: false; dismissActionTxt?: never; }); /** * Params used to display a modal * @typeParam T - The list of modal steps we expect to have in the modal * @group Modal Display */ type DisplayModalParamsType<T extends ModalStepTypes[]> = { steps: ModalRpcStepsInput<T>; metadata?: ModalRpcMetadata; }; //#endregion //#region src/types/rpc/displaySharingPage.d.ts /** * Product information to display on the sharing page * @group Sharing Page */ type SharingPageProduct = { /** * The product title / name */ title: string; /** * Optional product image URL */ imageUrl?: string; /** * Optional product-specific sharing link * When provided and the product is selected, this link is used instead of the default sharing link */ link?: string; /** * Optional `utm_content` value to apply when this product is selected. * Falls back to the page-level `attribution.utmContent` when omitted. */ utmContent?: string; }; /** * Parameters to display the sharing page * @group Sharing Page * @group RPC Schema */ type DisplaySharingPageParamsType = { /** * Products to showcase on the sharing page * If provided, they will be displayed in a product card section */ products?: SharingPageProduct[]; /** * Optional link override for sharing * If not provided, the sharing link will be generated from the current page URL + merchant context */ link?: string; /** * Optional attribution overrides for the outbound sharing URL. * * When provided (even as an empty object), Frak adds standard affiliation * params (`utm_source=frak`, `utm_medium=referral`, `utm_campaign=<merchantId>`, * `ref=<clientId>`, `via=frak`) alongside `fCtx`. Existing UTMs on the base * URL are preserved (gap-fill). Set this to `null` to disable attribution * params entirely (only `fCtx` is added). * * @default {} — defaults applied */ attribution?: AttributionParams | null; /** * Optional metadata overrides for the sharing page */ metadata?: { /** * Logo override for the sharing page header */ logo?: string; /** * Link to the homepage of the calling website */ homepageLink?: string; /** * The target interaction behind this sharing page */ targetInteraction?: InteractionTypeKey; /** * i18n overrides for the sharing page */ i18n?: I18nConfig; }; }; /** * Result of the sharing page display * @group Sharing Page * @group RPC Schema */ type DisplaySharingPageResultType = { /** * The action the user took * - "shared": User used the native share dialog * - "copied": User copied the link to clipboard * - "dismissed": User dismissed the sharing page without acting */ action: "shared" | "copied" | "dismissed"; /** * The install URL for the Frak app * Can be used as a fallback to redirect the user to the install page * from the merchant's top-level page (e.g. via `window.location.href`) */ installUrl?: string; }; //#endregion //#region src/types/rpc/embedded/loggedIn.d.ts /** * The different type of action we can have on the embedded view (once the user is logged in) * * @group Embedded wallet */ type EmbeddedViewActionSharing = { key: "sharing"; /** * Some sharing options */ options?: { /** * The title that will be displayed on the system popup once the system sharing window is open * @deprecated Use the top level `config.metadata.i18n` instead */ popupTitle?: string; /** * The text that will be shared alongside the link. * Can contain the variable `{LINK}` to specify where the link is placed, otherwise it will be added at the end * @deprecated Use the top level `config.metadata.i18n` instead */ text?: string; /** * The link to be shared (will be suffixed with the Frak sharing context) */ link?: string; }; }; /** * The action to display on the logged out embedded view when the user is referred * * @group Embedded wallet */ type EmbeddedViewActionReferred = { key: "referred"; /** * No options for a referred action */ options?: never; }; /** * Some configuration options for the embedded view * * @group Embedded wallet */ type LoggedInEmbeddedView = { /** * The main action to display on the logged in embedded view */ action?: EmbeddedViewActionSharing | EmbeddedViewActionReferred; }; //#endregion //#region src/types/rpc/embedded/loggedOut.d.ts /** * The view when a user is logged out * @group Embedded wallet */ type LoggedOutEmbeddedView = { /** * Metadata option when displaying the embedded view */ metadata?: { /** * The main CTA for the logged out view * - can include some variable, available ones are: * - `{REWARD}` -> The maximum reward a user can receive when interacting on your website * - can be formatted in markdown * * If not set, it will default to a internationalized message * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead */ text?: string; /** * The text that will be displayed on the login button * * If not set, it will default to a internationalized message * @deprecated Use the top level `config.customizations.i18n`, or `metadata.i18n` instead */ buttonText?: string; }; }; //#endregion //#region src/types/rpc/embedded/index.d.ts /** * The params used to display the embedded wallet * * @group Embedded wallet */ type DisplayEmbeddedWalletParamsType = { /** * The embedded view to display once the user is logged in */ loggedIn?: LoggedInEmbeddedView; /** * The embedded view to display once the user is logged out */ loggedOut?: LoggedOutEmbeddedView; /** * Some metadata to customize the embedded view */ metadata?: { /** * The logo to display on the embedded wallet * If undefined, will default to no logo displayed */ logo?: string; /** * Link to the homepage of the calling website * If undefined, will default to the domain of the calling website */ homepageLink?: string; /** * The target interaction behind this modal */ targetInteraction?: InteractionTypeKey; /** * The position of the component */ position?: "left" | "right"; /** * Some i18n override for the displayed modal (i.e. update the displayed text only for this modal) */ i18n?: I18nConfig; }; }; /** * The result of the display embedded wallet rpc request * * @group Embedded wallet */ type DisplayEmbeddedWalletResultType = { wallet: Address; }; //#endregion //#region src/types/rpc/interaction.d.ts /** * Parameters for sending interactions via RPC * * Note: merchantId and clientId come from WalletRpcContext * and are NOT included in the params - they are resolved by the listener * * @group RPC Schema */ type SendInteractionParamsType = { type: "arrival"; /** Sharer wallet address. Accepted in both wallet-only legacy contexts and merchant-context (V2) contexts. */ referrerWallet?: Address; referrerClientId?: string; referrerMerchantId?: string; /** Epoch seconds timestamp from the referral link creation */ referralTimestamp?: number; } | { type: "sharing"; /** Epoch seconds timestamp matching the V2 context `t` field embedded in the referral link URL, used for backend correlation */ sharingTimestamp?: number; /** Merchant order ID linking this sharing event to a purchase (stays server-side, never in URL) */ purchaseId?: string; } | { type: "custom"; customType: string; data?: Record<string, unknown>; idempotencyKey?: string; }; //#endregion //#region src/types/rpc/merchantInformation.d.ts /** * The type for the amount of tokens */ type TokenAmountType = { amount: number; eurAmount: number; usdAmount: number; gbpAmount: number; }; /** * A tier definition for tiered rewards */ type RewardTier = { minValue: number; maxValue?: number; amount: TokenAmountType; }; /** * Estimated reward amount — discriminated union by payout type * * - `fixed`: A known token amount (with fiat equivalents) * - `percentage`: A percent of a purchase field (e.g. 5% of purchase_amount), with optional min/max caps * - `tiered`: Amount depends on a field value matching tier brackets */ type EstimatedReward = { payoutType: "fixed"; amount: TokenAmountType; } | { payoutType: "percentage"; percent: number; percentOf: string; maxAmount?: TokenAmountType; minAmount?: TokenAmountType; } | { payoutType: "tiered"; tierField: string; tiers: RewardTier[]; }; /** * Response of the `frak_getMerchantInformation` RPC method * @group RPC Schema */ type GetMerchantInformationReturnType = { /** * Current merchant id */ id: string; /** * Some metadata */ onChainMetadata: { /** * Name of the merchant on-chain */ name: string; /** * Domain of the merchant on-chain */ domain: string; }; rewards: { token?: Address; campaignId: string; interactionTypeKey: InteractionTypeKey; referrer?: EstimatedReward; referee?: EstimatedReward; }[]; }; //#endregion //#region src/types/rpc/userReferralStatus.d.ts /** * User referral status returned by `frak_getUserReferralStatus`. * * Generic referral context for the current user on a merchant. * Used by components like `<frak-post-purchase>` and `<frak-referred-banner>` * to adapt their display based on the user's referral relationship. * * Returns `null` when the user's identity cannot be resolved * (e.g. no clientId and no wallet session). * * @group RPC Schema */ type UserReferralStatusType = { /** * Whether the user was referred to this merchant by someone else. * * `true` means a referral link exists where this user is the referee. */ isReferred: boolean; }; //#endregion //#region src/types/rpc/walletStatus.d.ts /** * RPC Response for the method `frak_listenToWalletStatus` * @group RPC Schema */ type WalletStatusReturnType = WalletConnected | WalletNotConnected; /** * @ignore * @inline */ type WalletConnected = { key: "connected"; wallet: Address; interactionToken?: string; }; /** * @ignore * @inline */ type WalletNotConnected = { key: "not-connected"; wallet?: never; interactionToken?: never; }; //#endregion //#region src/types/rpc.d.ts /** * RPC interface that's used for the iframe communication * * Define all the methods available within the iFrame RPC client with response type annotations * * @group RPC Schema * * @remarks * Each method in the schema now includes a ResponseType field that indicates: * - "promise": One-shot request that resolves once * - "stream": Streaming request that can emit multiple values * * ### Methods: * * #### frak_listenToWalletStatus * - Params: None * - Returns: {@link WalletStatusReturnType} * - Response Type: stream (emits updates when wallet status changes) * * #### frak_displayModal * - Params: [requests: {@link ModalRpcStepsInput}, metadata?: {@link ModalRpcMetadata}, configMetadata: {@link FrakWalletSdkConfig}["metadata"], placement?: string] * - Returns: {@link ModalRpcStepsResultType} * - Response Type: promise (one-shot) * * #### frak_sso * - Params: [params: {@link OpenSsoParamsType}, name: string, customCss?: string] * - Returns: {@link OpenSsoReturnType} * - Response Type: promise (one-shot) * * #### frak_getMerchantInformation * - Params: None * - Returns: {@link GetMerchantInformationReturnType} * - Response Type: promise (one-shot) * * #### frak_displayEmbeddedWallet * - Params: [request: {@link DisplayEmbeddedWalletParamsType}, metadata: {@link FrakWalletSdkConfig}["metadata"], placement?: string] * - Returns: {@link DisplayEmbeddedWalletResultType} * - Response Type: promise (one-shot) * * #### frak_displaySharingPage * - Params: [request: {@link DisplaySharingPageParamsType}, configMetadata: {@link FrakWalletSdkConfig}["metadata"], placement?: string] * - Returns: {@link DisplaySharingPageResultType} * - Response Type: promise (one-shot) */ type IFrameRpcSchema = [ /** * Method used to listen to the wallet status * This is a streaming method that emits updates when wallet status changes */ { Method: "frak_listenToWalletStatus"; Parameters?: undefined; ReturnType: WalletStatusReturnType; }, /** * Method to display a modal with the provided steps * This is a one-shot request */ { Method: "frak_displayModal"; Parameters: [requests: ModalRpcStepsInput, metadata: ModalRpcMetadata | undefined, configMetadata: FrakWalletSdkConfig["metadata"], placement?: string]; ReturnType: ModalRpcStepsResultType; }, /** * Method to prepare SSO (generate URL for popup) * Returns the SSO URL that should be opened in a popup * Only used for popup flows (not redirect flows) */ { Method: "frak_prepareSso"; Parameters: [params: PrepareSsoParamsType, name?: string, customCss?: string]; ReturnType: PrepareSsoReturnType; }, /** * Method to open/trigger SSO * Either triggers redirect (if openInSameWindow/redirectUrl) * Or waits for popup completion (if popup mode) * This method handles BOTH redirect and popup flows */ { Method: "frak_openSso"; Parameters: [params: OpenSsoParamsType, name?: string, customCss?: string]; ReturnType: OpenSsoReturnType; }, /** * Method to get current merchant information * - Is merchant registered? * - Does it have running campaign? * - Estimated reward on actions * This is a one-shot request */ { Method: "frak_getMerchantInformation"; Parameters?: undefined; ReturnType: GetMerchantInformationReturnType; }, /** * Method to show the embedded wallet, with potential customization * This is a one-shot request */ { Method: "frak_displayEmbeddedWallet"; Parameters: [request: DisplayEmbeddedWalletParamsType, metadata: FrakWalletSdkConfig["metadata"], placement?: string]; ReturnType: DisplayEmbeddedWalletResultType; }, /** * Method to send interactions (arrival, sharing, custom events) * Fire-and-forget method - no return value expected * merchantId is resolved from context * clientId is passed via metadata as safeguard against race conditions */ { Method: "frak_sendInteraction"; Parameters: [interaction: SendInteractionParamsType, metadata?: { clientId?: string; }]; ReturnType: undefined; }, /** * Method to get the current user's referral status on this merchant. * Returns whether the user was referred (has a referral link as referee). * Returns null when the user's identity cannot be resolved. * This is a one-shot request. */ { Method: "frak_getUserReferralStatus"; Parameters?: undefined; ReturnType: UserReferralStatusType | null; }, /** * Method to display a sharing page with product info and sharing buttons * Resolves on first user action (share/copy) but the page stays visible * This is a one-shot request */ { Method: "frak_displaySharingPage"; Parameters: [request: DisplaySharingPageParamsType, configMetadata: FrakWalletSdkConfig["metadata"], placement?: string]; ReturnType: DisplaySharingPageResultType; }, /** * Method to get a merge token for the current anonymous identity. * Used by in-app browser redirect flows to preserve identity * when switching from a WebView to the system browser. * Returns the merge token string, or null if unavailable. * This is a one-shot request. */ { Method: "frak_getMergeToken"; Parameters?: undefined; ReturnType: string | null; }]; //#endregion //#region src/types/transport.d.ts /** * IFrame transport interface */ type IFrameTransport = { /** * Wait for the connection to be established */ waitForConnection: Promise<boolean>; /** * Wait for the setup to be done */ waitForSetup: Promise<void>; /** * Function used to perform a single request via the iframe transport */ request: RpcClient<IFrameRpcSchema, LifecycleMessage>["request"]; /** * Function used to listen to a request response via the iframe transport */ listenerRequest: RpcClient<IFrameRpcSchema, LifecycleMessage>["listen"]; /** * Function used to destroy the iframe transport */ destroy: () => Promise<void>; }; /** * Represent an iframe event */ type FrakLifecycleEvent = IFrameLifecycleEvent | ClientLifecycleEvent; //#endregion //#region src/types/client.d.ts /** * Representing a Frak client, used to interact with the Frak Wallet */ type FrakClient = { config: FrakWalletSdkConfig; openPanel?: OpenPanel; } & IFrameTransport; //#endregion //#region src/types/context.d.ts /** * V1 (legacy) Frak Context — contains only the referrer wallet address. * Used for backward compatibility with old sharing links. * @ignore */ type FrakContextV1 = { /** Referrer wallet address */r: Address; }; /** * V2 Frak Context — anonymous-first referral context with optional wallet. * * Carries merchant context (`m`) and creation timestamp (`t`) unconditionally. * Identifies the sharer via either the anonymous clientId (`c`) or, when the * sharer is authenticated, the stronger wallet identifier (`w`). A valid V2 * context MUST contain at least one of `c` or `w`; both may be present when * a logged-in user shares a link (best attribution signal). * * `w` takes precedence as the source of truth because the wallet is bound to * the user's WebAuthn credential, survives localStorage clears, and is global * across merchants — unlike `c`, which is a per-browser UUID. * * @ignore */ type FrakContextV2 = { /** Version discriminator */v: 2; /** Merchant ID (UUID) */ m: string; /** Link creation timestamp (epoch seconds) */ t: number; /** Sharer's anonymous clientId (UUID from localStorage). Optional when `w` is provided. */ c?: string; /** Sharer's wallet address. Preferred source of truth when the sharer is authenticated. Optional when `c` is provided. */ w?: Address; }; /** * The current Frak Context — union of all versions. * * - No `v` field → V1 (legacy wallet address) * - `v: 2` → V2 (anonymous clientId-based) * * @ignore */ type FrakContext = FrakContextV1 | FrakContextV2; //#endregion //#region src/actions/openSso.d.ts declare const ssoPopupFeatures = "menubar=no,status=no,scrollbars=no,fullscreen=no,width=500, height=800"; declare const ssoPopupName = "frak-sso"; /** * Function used to open the SSO * @param client - The current Frak Client * @param args - The SSO parameters * * @description Two SSO flow modes: * * **Redirect Mode** (openInSameWindow: true): * - Wallet generates URL and triggers redirect * - Used when redirectUrl is provided * * **Popup Mode** (openInSameWindow: false/omitted): * - SDK generates URL client-side (or uses provided ssoPopupUrl) * - Opens popup synchronously (prevents popup blockers) * - Waits for SSO completion via postMessage * * @example * First we build the sso metadata * ```ts * // Build the metadata * const metadata: SsoMetadata = { * logoUrl: "https://my-app.com/logo.png", * homepageLink: "https://my-app.com", * }; * ``` * * Then, either use it with direct exit (and so user is directly redirected to your website), or a custom redirect URL * :::code-group * ```ts [Popup (default)] * // Opens in popup, SDK generates URL automatically * await openSso(frakConfig, { * directExit: true, * metadata, * }); * ``` * ```ts [Redirect] * // Opens in same window with redirect * await openSso(frakConfig, { * redirectUrl: "https://my-app.com/frak-sso", * metadata, * openInSameWindow: true, * }); * ``` * ```ts [Custom popup URL] * // Advanced: provide custom SSO URL * const { ssoUrl } = await prepareSso(frakConfig, { metadata }); * await openSso(frakConfig, { * metadata, * ssoPopupUrl: `${ssoUrl}&custom=param`, * }); * ``` * ::: */ declare function openSso(client: FrakClient, inputArgs: OpenSsoParamsType): Promise<OpenSsoReturnType>; //#endregion export { SdkResolvedConfig as $, ModalRpcStepsResultType as A, OpenSsoReturnType as B, LoggedInEmbeddedView as C, DisplayModalParamsType as D, SharingPageProduct as E, SiweAuthenticateModalStepType as F, FinalModalStepType as G, PrepareSsoReturnType as H, SiweAuthenticateReturnType as I, IFrameLifecycleEvent as J, ModalStepMetadata as K, SiweAuthenticationParams as L, SendTransactionModalStepType as M, SendTransactionReturnType as N, ModalRpcMetadata as O, SendTransactionTxType as P, ResolvedSdkConfig as Q, LoginModalStepType as R, EmbeddedViewActionSharing as S, DisplaySharingPageResultType as T, SsoMetadata as U, PrepareSsoParamsType as V, FinalActionType as W, MerchantConfigResponse as X, ClientLifecycleEvent as Y, ResolvedPlacement as Z, SendInteractionParamsType as _, FrakContextV1 as a, LocalizedI18nConfig as at, LoggedOutEmbeddedView as b, FrakLifecycleEvent as c, TrackArrivalParams as ct, WalletStatusReturnType as d, Currency as et, UserReferralStatusType as f, TokenAmountType as g, RewardTier as h, FrakContext as i, ListenerPreloadOption as it, ModalStepTypes as j, ModalRpcStepsInput as k, IFrameTransport as l, TrackArrivalResult as lt, GetMerchantInformationReturnType as m, ssoPopupFeatures as n, I18nConfig as nt, FrakContextV2 as o, AttributionDefaults as ot, EstimatedReward as p, InteractionTypeKey as q, ssoPopupName as r, Language as rt, FrakClient as s, AttributionParams as st, openSso as t, FrakWalletSdkConfig as tt, IFrameRpcSchema as u, UtmParams as ut, DisplayEmbeddedWalletParamsType as v, DisplaySharingPageParamsType as w, EmbeddedViewActionReferred as x, DisplayEmbeddedWalletResultType as y, OpenSsoParamsType as z };