UNPKG

@frak-labs/core-sdk

Version:

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

109 lines (95 loc) 3.69 kB
import { DEEP_LINK_SCHEME } from "../../constants"; /** * Options for deep link with fallback */ export type DeepLinkFallbackOptions = { /** Timeout in ms before triggering fallback (default: 2500ms) */ timeout?: number; /** Callback invoked when fallback is triggered (app not installed) */ onFallback?: () => void; }; /** * Check if running on a Chromium-based Android browser. * * On Chrome Android, custom scheme deep links (e.g. frakwallet://) trigger * a confirmation bar ("Continue to Frak Wallet?"). Using intent:// URLs * instead bypasses this for Chromium browsers while keeping custom scheme * fallback for non-Chromium browsers (e.g. Firefox) where it works fine. */ export function isChromiumAndroid(): boolean { const ua = navigator.userAgent; return /Android/i.test(ua) && /Chrome\/\d+/i.test(ua); } /** * Convert a Frak deep link to an Android intent:// URL. * * Intent URLs let Chromium browsers open the app directly without * showing the "Continue to app?" confirmation bar. * * Note: We intentionally omit the `package` parameter. Including it * causes Chrome to redirect to the Play Store when the app is not * installed, which breaks the visibility-based fallback detection. * Without `package`, Chrome simply does nothing when the app is * missing, allowing the fallback mechanism to fire correctly. * * The scheme is derived from `DEEP_LINK_SCHEME` so the dev variant * (`frakwallet-dev://`) routes to the dev app shell, not prod. * * Format: intent://path#Intent;scheme=<scheme>;end */ const DEEP_LINK_SCHEME_NAME = DEEP_LINK_SCHEME.replace("://", ""); export function toAndroidIntentUrl(deepLink: string): string { // Extract everything after the scheme (e.g. "frakwallet://" or "frakwallet-dev://") const path = deepLink.slice(DEEP_LINK_SCHEME.length); return `intent://${path}#Intent;scheme=${DEEP_LINK_SCHEME_NAME};end`; } /** * Trigger a deep link with visibility-based fallback detection. * * Uses the Page Visibility API to detect if the app opened (page goes hidden). * If the page remains visible after the timeout, assumes app is not installed * and invokes the onFallback callback. * * On Chromium Android, converts custom scheme to intent:// URL to avoid * the "Continue to app?" confirmation bar. * * @param deepLink - The deep link URL to trigger (e.g., "frakwallet://wallet") * @param options - Optional configuration (timeout, onFallback callback) */ export function triggerDeepLinkWithFallback( deepLink: string, options?: DeepLinkFallbackOptions ): void { const timeout = options?.timeout ?? 2500; // Track if the app opened (page went to background) let appOpened = false; const onVisibilityChange = () => { if (document.hidden) { appOpened = true; } }; // Start listening for visibility changes document.addEventListener("visibilitychange", onVisibilityChange); // On Chromium Android, use intent:// to avoid confirmation bar const url = isChromiumAndroid() && isFrakDeepLink(deepLink) ? toAndroidIntentUrl(deepLink) : deepLink; // Trigger the deep link window.location.href = url; // Check after timeout if app opened setTimeout(() => { // Clean up listener document.removeEventListener("visibilitychange", onVisibilityChange); if (!appOpened) { // App didn't open - trigger fallback callback options?.onFallback?.(); } }, timeout); } /** * Check if a URL is a Frak deep link */ export function isFrakDeepLink(url: string): boolean { return url.startsWith(DEEP_LINK_SCHEME); }