From 0930b72bf42c518703de3e0837ef2785d3cd48f3 Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Tue, 24 Mar 2026 09:23:59 +0000 Subject: [PATCH 1/2] [#478] Restrict Farcaster SDK to platform === 'farcaster' only Base App migrates to standard web app (April 2026). SDK actions (ready, composeCast, swapToken) now only fire in Farcaster clients. Base App and web users get standard wallet + Uniswap experience. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/components/FarcasterMiniApp.tsx | 16 +++++++------- src/components/ShareToFarcaster.tsx | 29 +++++--------------------- src/components/token/SwapInterface.tsx | 6 +++--- 3 files changed, 15 insertions(+), 36 deletions(-) diff --git a/src/components/FarcasterMiniApp.tsx b/src/components/FarcasterMiniApp.tsx index 1a16a949..3fb6554c 100644 --- a/src/components/FarcasterMiniApp.tsx +++ b/src/components/FarcasterMiniApp.tsx @@ -1,26 +1,24 @@ "use client"; import { useEffect } from "react"; +import { usePlatformDetection } from "../hooks/usePlatformDetection"; /** - * Detects whether the app is running inside a Farcaster client via sdk.context - * and calls `sdk.actions.ready()` to dismiss the splash screen. + * Calls `sdk.actions.ready()` to dismiss the splash screen — only in Farcaster clients. + * After Base App migration (April 2026), Base App operates as standard web app. * * Renders nothing — mount once near the root of the component tree. */ export function FarcasterMiniApp() { + const { platform, isLoading } = usePlatformDetection(); + useEffect(() => { - if (typeof window === "undefined") return; + if (isLoading || platform !== "farcaster") return; let cancelled = false; import("@farcaster/miniapp-sdk").then(async ({ sdk }) => { if (cancelled) return; - - // sdk.context is only available when running inside a Farcaster client - const context = await sdk.context; - if (!context || cancelled) return; - sdk.actions.ready(); }).catch(() => { // Not in a Farcaster context — silently ignore @@ -29,7 +27,7 @@ export function FarcasterMiniApp() { return () => { cancelled = true; }; - }, []); + }, [platform, isLoading]); return null; } diff --git a/src/components/ShareToFarcaster.tsx b/src/components/ShareToFarcaster.tsx index 7c031a07..40707d13 100644 --- a/src/components/ShareToFarcaster.tsx +++ b/src/components/ShareToFarcaster.tsx @@ -1,9 +1,10 @@ "use client"; -import { useEffect, useState, useCallback } from "react"; +import { useCallback } from "react"; +import { usePlatformDetection } from "../hooks/usePlatformDetection"; /** - * "Share to Farcaster" button — only renders inside a Farcaster Mini App context. + * "Share to Farcaster" button — only renders when platform === 'farcaster'. * Calls sdk.actions.composeCast() with pre-filled text and story URL as embed. */ export function ShareToFarcaster({ @@ -13,27 +14,7 @@ export function ShareToFarcaster({ storylineId: number; title: string; }) { - const [visible, setVisible] = useState(false); - - useEffect(() => { - if (typeof window === "undefined") return; - - let cancelled = false; - - import("@farcaster/miniapp-sdk") - .then(async ({ sdk }) => { - if (cancelled) return; - const ctx = await sdk.context; - if (ctx && !cancelled) setVisible(true); - }) - .catch(() => { - // Not in a Farcaster context - }); - - return () => { - cancelled = true; - }; - }, []); + const { platform, isLoading } = usePlatformDetection(); const handleShare = useCallback(async () => { const { sdk } = await import("@farcaster/miniapp-sdk"); @@ -48,7 +29,7 @@ export function ShareToFarcaster({ }); }, [storylineId, title]); - if (!visible) return null; + if (isLoading || platform !== "farcaster") return null; return (