UNPKG

@frak-labs/core-sdk

Version:

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

126 lines (116 loc) 4.1 kB
import { getClientId } from "../config/clientId"; import { sdkConfigStore } from "../config/sdkConfigStore"; import type { FrakClient, OpenSsoParamsType, OpenSsoReturnType, } from "../types"; import { generateSsoUrl } from "../utils/sso/sso"; // SSO popup configuration export const ssoPopupFeatures = "menubar=no,status=no,scrollbars=no,fullscreen=no,width=500, height=800"; export 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`, * }); * ``` * ::: */ export async function openSso( client: FrakClient, inputArgs: OpenSsoParamsType ): Promise<OpenSsoReturnType> { const { metadata, customizations, walletUrl } = client.config; // Apply default: when no redirectUrl is provided we want the SSO popup // to close itself after completion. Without this default the popup // sticks on the success screen and the "Redirect now" button is a no-op. const args: OpenSsoParamsType = { ...inputArgs, directExit: inputArgs.directExit ?? !inputArgs.redirectUrl, }; // Check if redirect mode (default to true if redirectUrl present) const isRedirectMode = args.openInSameWindow ?? !!args.redirectUrl; if (isRedirectMode) { // Redirect flow: Wallet generates URL and triggers redirect via lifecycle event // This must happen on wallet side because only the iframe can trigger the redirect return await client.request({ method: "frak_openSso", params: [args, metadata.name, customizations?.css], }); } // Popup flow: Generate URL on SDK side and open synchronously // This ensures window.open() is called in same tick as user gesture (no popup blocker) // Step 1: Generate or use provided SSO URL const ssoUrl = args.ssoPopupUrl ?? generateSsoUrl( walletUrl ?? "https://wallet.frak.id", args, (await sdkConfigStore.resolveMerchantId()) ?? "", metadata.name, getClientId(), customizations?.css ); // Step 2: Open popup synchronously (critical for popup blocker prevention) const popup = window.open(ssoUrl, ssoPopupName, ssoPopupFeatures); if (!popup) { throw new Error( "Popup was blocked. Please allow popups for this site." ); } popup.focus(); // Step 3: Wait for SSO completion via RPC // The wallet iframe will resolve this when SSO page sends sso_complete message const result = await client.request({ method: "frak_openSso", params: [args, metadata.name, customizations?.css], }); return result ?? {}; }