@turtleclub/turtle-basic 0.1.0-beta.17 → 0.1.0-beta.19
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/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var react=require('react'),reactQuery=require('@tanstack/react-query'),multichain=require('@turtleclub/multichain'),hooks=require('@turtleclub/hooks'),jsxRuntime=require('react/jsx-runtime');var
|
|
1
|
+
'use strict';var react=require('react'),reactQuery=require('@tanstack/react-query'),multichain=require('@turtleclub/multichain'),hooks=require('@turtleclub/hooks'),jsxRuntime=require('react/jsx-runtime');var n={TurtleWeb:"turtle-web",Lemon:"lemon",Worldcoin:"worldcoin"};var v=null,U="turtle-platform-detection";function q(){if(typeof window>"u"||typeof sessionStorage>"u")return null;try{let r=sessionStorage.getItem(U);if(r)return JSON.parse(r)}catch(r){console.warn("[Platform Detection] Failed to load cached detection:",r);}return null}function B(r){if(!(typeof window>"u"||typeof sessionStorage>"u"))try{sessionStorage.setItem(U,JSON.stringify(r));}catch(e){console.warn("[Platform Detection] Failed to save cached detection:",e);}}function G(){if(typeof window>"u")return null;let r=window.location.hostname;return r.includes("worldcoin.")?n.Worldcoin:r.includes("lemon.")?n.Lemon:null}function L(r=false){if(!r){if(v)return v;let t=q();if(t)return v=t,t}let e=t=>(v=t,B(t),t),i=G();return e(i?{platformId:i,detectionMethod:"subdomain",isValidated:true}:{platformId:n.TurtleWeb,detectionMethod:"default",isValidated:true})}var R={deposit:()=>({success:false,error:"Deposit not implemented yet"}),getOpportunity:()=>Promise.reject(new Error("getOpportunity not implemented yet"))};function I(r){let e=multichain.useMultichainAccount(),{connect:i}=multichain.useMultichainConnect(),{disconnect:t}=multichain.useMultichainDisconnect(),{signMessage:g}=multichain.useMultichainSignMessage(),u=react.useCallback(async l=>{throw console.error(`[useTurtleWebAdapter] Membership error (${l.type}): ${l.message}`),l},[]),{isMember:s,isLoading:o,refetch:m}=hooks.useTurtleMembershipFlow({address:e.address,walletEcosystem:"evm",signMessage:g,chainId:"1",enabled:false,onError:u}),f=e.isConnected&&!!e.address&&s===false,b=react.useCallback(async()=>{await m();},[m]),{data:d,isLoading:P}=hooks.useOpportunitiesPaginated({params:{page:1,featured:true,limit:1e3},enabled:r}),y=react.useCallback(()=>typeof window<"u",[]),c=react.useCallback(async()=>{try{return e.isConnected&&e.address?{success:!0,user:{id:e.address,metadata:{chainId:e.chainId,status:e.status}}}:(await i("evm"),{success:!0})}catch(l){return console.error("[useTurtleWebAdapter] Authentication error:",l),{success:false,error:l instanceof Error?l.message:"Unknown authentication error"}}},[e.isConnected,e.address,e.chainId,e.status,i]),C=react.useCallback(async()=>{try{await t();}catch(l){throw console.error("[useTurtleWebAdapter] Disconnect error:",l),l}},[t]),a=react.useCallback(()=>!e.isConnected||!e.address?null:{id:e.address,metadata:{chainId:e.chainId,status:e.status,ecosystem:e.ecosystem,isMember:s,isMembershipLoading:o}},[e.isConnected,e.address,e.chainId,e.status,e.ecosystem,s,o]),E=react.useCallback(async l=>R.deposit(),[]),A=react.useCallback(()=>({canChangeNetwork:true,canDisconnect:true,showNetworkSelector:true,showGasEstimate:true,showUsername:false,requiresGasPayment:true,supportsNotifications:false,canConnectWallet:true}),[]),O=react.useCallback(async()=>Promise.resolve(d?.opportunities||[]),[d]),W=react.useCallback(async l=>R.getOpportunity(),[]);return react.useMemo(()=>({platformId:n.TurtleWeb,platformName:"Turtle Web",isAvailable:y,authenticate:c,disconnect:C,getUser:a,depositToOpportunity:E,getCapabilities:A,getOpportunities:O,getOpportunity:W,isLoadingOpportunities:P,isLoadingUser:o,opportunities:d?.opportunities||[],shouldShowMembershipModal:f,triggerMembershipFlow:b}),[y,c,C,a,E,A,O,W,P,o,d,f,b])}function x(r){let[e,i]=react.useState(null),[t,g]=react.useState(false);react.useEffect(()=>{if(typeof window<"u"){let c=!!window.ReactNativeWebView;g(c);}},[]);let{data:u}=hooks.useOpportunitiesPaginated({params:{page:1,receiptTokenChainSlug:"ethereum,solana,base,polygon,arbitrum,optimism,avalanche",limit:100},enabled:r}),s=react.useCallback(()=>t,[t]),o=react.useCallback(async c=>t?{success:false,error:"Lemon authentication not implemented yet"}:{success:false,error:"Not running in Lemon Cash WebView environment"},[t]),m=react.useCallback(async()=>{i(null);},[]),f=react.useCallback(()=>e,[e]),b=react.useCallback(async c=>t?R.deposit():{success:false,error:"Not running in Lemon Cash WebView environment"},[t]),d=react.useCallback(()=>({canChangeNetwork:false,canDisconnect:false,showNetworkSelector:false,showGasEstimate:false,showUsername:true,requiresGasPayment:false,supportsNotifications:true,canConnectWallet:true}),[]),P=react.useCallback(async()=>Promise.resolve(u?.opportunities||[]),[u]),y=react.useCallback(async c=>R.getOpportunity(),[]);return react.useMemo(()=>({platformId:n.Lemon,platformName:"Lemon Cash",isAvailable:s,authenticate:o,disconnect:m,getUser:f,depositToOpportunity:b,getCapabilities:d,getOpportunities:P,getOpportunity:y}),[s,o,m,f,b,d,P,y])}var F=react.createContext(null);function D({children:r,loadingComponent:e,errorComponent:i,forcePlatform:t,membershipModal:g}){let[u,s]=react.useState(null),[o,m]=react.useState(null),[f,b]=react.useState(false);react.useEffect(()=>{let a=setTimeout(()=>{b(true);},2e3);return ()=>clearTimeout(a)},[]);let d=o?.platformId,P=I(d===n.TurtleWeb),y=x(d===n.Lemon);react.useEffect(()=>{try{let a;t?a={platformId:t,detectionMethod:"forced",isValidated:!1,warnings:["Platform was manually forced via forcePlatform prop"]}:a=L(),m(a);}catch(a){console.error("[PlatformProvider] Error during platform detection:",a),s(a instanceof Error?a:new Error("Unknown error during platform detection"));}},[t]);let c=react.useMemo(()=>{if(!o)return null;switch(o.platformId){case n.TurtleWeb:return P;case n.Lemon:return y;case n.Worldcoin:return console.warn("[PlatformProvider] Worldcoin adapter not implemented yet"),s(new Error("Worldcoin platform not implemented yet")),null;default:return console.warn("[PlatformProvider] Unknown platform:",o.platformId),s(new Error(`Unknown platform: ${o.platformId}`)),null}},[o,P,y]),C=react.useMemo(()=>!o||!c?null:{adapter:c,detection:o,isReady:true},[c,o]);if(u){let a=()=>{s(null),m(null);};return i?jsxRuntime.jsx(jsxRuntime.Fragment,{children:i(u,a)}):jsxRuntime.jsxs("main",{className:"flex flex-col items-center justify-center h-screen",children:[jsxRuntime.jsx("div",{className:"text-lg font-bold",children:"There was an error initializing the platform"}),jsxRuntime.jsx("span",{className:"text-sm text-gray-500",children:u.message}),jsxRuntime.jsx("span",{className:"text-xs text-gray-500",children:"Please provide an Error component to the PlatformProvider."})]})}return !C||!f?e?jsxRuntime.jsx(jsxRuntime.Fragment,{children:e}):jsxRuntime.jsxs("main",{className:"flex flex-col items-center justify-center h-screen",children:[jsxRuntime.jsx("span",{className:"text-lg font-bold",children:"Detecting platform..."}),jsxRuntime.jsx("span",{className:"text-xs text-gray-500",children:"Please provide a Loading component to the PlatformProvider."})]}):jsxRuntime.jsxs(F.Provider,{value:C,children:[r,g]})}function re(){let r=react.useContext(F);if(!r)throw new Error("usePlatform must be used within a PlatformProvider");return r}function le({children:r,walletConnectProjectId:e,metadata:i,tonManifestUrl:t="/tonconnect-manifest.json",loadingComponent:g,errorComponent:u,forcePlatform:s,queryClientConfig:o,membershipModal:m}){let[f]=react.useState(()=>new reactQuery.QueryClient(o||{defaultOptions:{queries:{staleTime:6e4,refetchOnWindowFocus:false}}}));return multichain.initializeMultiChain({projectId:e,metadata:i}),jsxRuntime.jsx(reactQuery.QueryClientProvider,{client:f,children:jsxRuntime.jsx(multichain.MultiChainProvider,{tonManifestUrl:t,children:jsxRuntime.jsx(D,{loadingComponent:g,errorComponent:u,forcePlatform:s,membershipModal:m,children:r})})})}exports.PlatformId=n;exports.PlatformProvider=D;exports.TurtleBasicProvider=le;exports.useLemonAdapter=x;exports.usePlatform=re;exports.useTurtleWebAdapter=I;//# sourceMappingURL=index.cjs.map
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/platform/core/types.ts","../src/platform/core/detector.ts","../src/platform/core/errors.ts","../src/platform/adapters/useTurtleWebAdapter.ts","../src/platform/adapters/useLemonAdapter.ts","../src/platform/core/PlatformProvider.tsx","../src/TurtleBasicProvider.tsx"],"names":["PlatformId","cachedDetectionResult","CACHE_KEY","loadCachedDetection","cached","error","saveCachedDetection","result","detectFromSubdomain","hostname","detectPlatform","forceRedetect","sessionCached","cacheAndReturn","subdomainPlatform","UNIMPLEMENTED_ERRORS","useTurtleWebAdapter","isActive","account","useMultichainAccount","connect","useMultichainConnect","disconnect","useMultichainDisconnect","signMessage","useMultichainSignMessage","handleMembershipError","useCallback","isMember","isMembershipLoading","refetchMembership","useTurtleMembershipFlow","shouldShowMembershipModal","triggerMembershipFlow","opportunitiesData","isLoadingOpportunities","useOpportunitiesPaginated","isAvailable","authenticate","disconnectWallet","getUser","depositToOpportunity","_params","getCapabilities","getOpportunities","getOpportunity","_opportunityId","useMemo","useLemonAdapter","user","setUser","useState","isWebView","setIsWebView","useEffect","hasReactNativeWebView","_nonce","PlatformContext","createContext","PlatformProvider","children","loadingComponent","errorComponent","forcePlatform","membershipModal","setError","detection","setDetection","activePlatformId","turtleWebAdapter","lemonAdapter","detectionResult","err","adapter","contextValue","retry","jsx","Fragment","jsxs","usePlatform","context","useContext","TurtleBasicProvider","walletConnectProjectId","metadata","tonManifestUrl","queryClientConfig","queryClient","QueryClient","initializeMultiChain","QueryClientProvider","MultiChainProvider"],"mappings":"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","file":"index.cjs","sourcesContent":["import { Opportunity } from \"@turtleclub/hooks\";\n\nexport const PlatformId = {\n TurtleWeb: 'turtle-web',\n Lemon: 'lemon',\n Worldcoin: 'worldcoin',\n} as const;\n\n/**\n * Platform identifier type\n */\nexport type PlatformId = typeof PlatformId[keyof typeof PlatformId];\n\n/**\n * User information from platform authentication\n */\n//Probably will be changed later.\nexport interface User {\n id: string;\n username?: string;\n email?: string;\n avatar?: string;\n metadata?: Record<string, any>;\n}\n\n/**\n * Result of authentication attempt\n */\nexport interface AuthResult {\n success: boolean;\n user?: User;\n error?: string;\n metadata?: Record<string, any>;\n}\n\n/**\n * Parameters for depositing to an opportunity\n */\n//This will be changed later.\nexport interface DepositParams {\n opportunityAddress: string;\n tokenAddress: string;\n amount: string;\n chainId: number;\n}\n\n/**\n * Result of a transaction attempt\n */\nexport interface TransactionResult {\n success: boolean;\n txHash?: string;\n error?: string;\n metadata?: Record<string, any>;\n}\n\n/**\n * Platform capabilities - what features are available/should be shown\n */\nexport interface PlatformCapabilities {\n canChangeNetwork: boolean;\n canDisconnect: boolean;\n showNetworkSelector: boolean;\n showGasEstimate: boolean;\n showUsername: boolean;\n requiresGasPayment: boolean;\n supportsNotifications: boolean;\n canConnectWallet: boolean;\n}\n\n/**\n * Platform adapter interface - implemented by each platform's hook\n * Returned by platform-specific adapter hooks (useTurtleWebAdapter, useLemonAdapter, etc.)\n */\nexport interface PlatformAdapter {\n readonly platformId: PlatformId;\n readonly platformName: string;\n isAvailable(): boolean;\n authenticate(nonce?: string): Promise<AuthResult>;\n disconnect(): Promise<void>;\n getUser(): User | null;\n depositToOpportunity(params: DepositParams): Promise<TransactionResult>;\n getOpportunities(): Promise<Opportunity[]>;\n getOpportunity(opportunityId: string): Promise<Opportunity>;\n getCapabilities(): PlatformCapabilities;\n\n // Reactive loading states - available when adapter is a hook\n readonly isLoadingOpportunities?: boolean;\n readonly isLoadingUser?: boolean;\n\n // Reactive data - available when adapter is a hook\n readonly opportunities?: Opportunity[];\n\n // Membership flow - available when adapter requires membership verification\n readonly shouldShowMembershipModal?: boolean;\n readonly triggerMembershipFlow?: () => Promise<void>;\n}\n\n/**\n * Result of platform detection\n */\nexport interface DetectionResult {\n platformId: PlatformId;\n detectionMethod: 'subdomain' | 'sdk' | 'forced' | 'default';\n isValidated: boolean;\n warnings?: string[];\n}\n","import { PlatformId } from './types';\nimport type { DetectionResult } from './types';\n\n// Cached detection result (singleton pattern)\nlet cachedDetectionResult: DetectionResult | null = null;\n\n// SessionStorage key for caching\nconst CACHE_KEY = 'turtle-platform-detection';\n\n/**\n * Load cached detection result from sessionStorage\n */\nfunction loadCachedDetection(): DetectionResult | null {\n if (typeof window === 'undefined' || typeof sessionStorage === 'undefined') {\n return null;\n }\n\n try {\n const cached = sessionStorage.getItem(CACHE_KEY);\n if (cached) {\n return JSON.parse(cached) as DetectionResult;\n }\n } catch (error) {\n console.warn('[Platform Detection] Failed to load cached detection:', error);\n }\n\n return null;\n}\n\n/**\n * Save detection result to sessionStorage\n */\nfunction saveCachedDetection(result: DetectionResult): void {\n if (typeof window === 'undefined' || typeof sessionStorage === 'undefined') {\n return;\n }\n\n try {\n sessionStorage.setItem(CACHE_KEY, JSON.stringify(result));\n } catch (error) {\n console.warn('[Platform Detection] Failed to save cached detection:', error);\n }\n}\n\n\n/**\n * Detect platform from subdomain\n */\nfunction detectFromSubdomain(): typeof PlatformId[keyof typeof PlatformId] | null {\n if (typeof window === 'undefined') return null;\n\n const hostname = window.location.hostname;\n\n // Check for platform-specific subdomains\n if (hostname.includes('worldcoin.')) {\n return PlatformId.Worldcoin;\n }\n if (hostname.includes('lemon.')) {\n return PlatformId.Lemon;\n }\n\n return null;\n}\n\n\n/**\n * Main platform detection function\n * Detects platform based on subdomain\n * @param forceRedetect - Force re-detection even if cached result exists\n */\nexport function detectPlatform(forceRedetect = false): DetectionResult {\n // Return cached result if available and not forcing re-detection\n if (!forceRedetect) {\n // Check in-memory cache first (fastest)\n if (cachedDetectionResult) {\n return cachedDetectionResult;\n }\n\n // Check sessionStorage cache\n const sessionCached = loadCachedDetection();\n if (sessionCached) {\n cachedDetectionResult = sessionCached;\n return sessionCached;\n }\n }\n\n const cacheAndReturn = (result: DetectionResult): DetectionResult => {\n cachedDetectionResult = result;\n saveCachedDetection(result);\n return result;\n };\n\n // Priority 1: Subdomain detection\n const subdomainPlatform = detectFromSubdomain();\n if (subdomainPlatform) {\n return cacheAndReturn({\n platformId: subdomainPlatform,\n detectionMethod: 'subdomain',\n isValidated: true,\n });\n }\n\n // Priority 2: Default to turtle-web\n return cacheAndReturn({\n platformId: PlatformId.TurtleWeb,\n detectionMethod: 'default',\n isValidated: true,\n });\n}\n","import type { TransactionResult } from './types';\n\n/**\n * Standard error responses for unimplemented features\n */\nexport const UNIMPLEMENTED_ERRORS = {\n deposit: (): TransactionResult => ({\n success: false,\n error: 'Deposit not implemented yet',\n }),\n\n getOpportunity: (): Promise<never> => {\n return Promise.reject(new Error('getOpportunity not implemented yet'));\n },\n} as const;\n","import { useCallback, useMemo } from 'react';\nimport {\n useMultichainAccount,\n useMultichainConnect,\n useMultichainDisconnect,\n useMultichainSignMessage\n} from '@turtleclub/multichain';\nimport { Opportunity, useOpportunitiesPaginated, useTurtleMembershipFlow } from '@turtleclub/hooks';\nimport { PlatformId } from '../core/types';\nimport type {\n PlatformAdapter,\n User,\n AuthResult,\n DepositParams,\n TransactionResult,\n PlatformCapabilities,\n} from '../core/types';\nimport { UNIMPLEMENTED_ERRORS } from '../core/errors';\n\n/**\n * Turtle Web Adapter Hook - for standard web browsers\n * Uses multichain wallet abstraction with EVM support\n *\n * This is a hook-based adapter that works reactively with React state.\n * Methods always have access to the latest wallet state through React hooks.\n * Automatically handles membership authentication when wallet connects.\n *\n * @param isActive - Whether this adapter is the currently active platform (used to conditionally enable queries)\n */\nexport function useTurtleWebAdapter(isActive: boolean): PlatformAdapter {\n const account = useMultichainAccount();\n const { connect } = useMultichainConnect();\n const { disconnect } = useMultichainDisconnect();\n const { signMessage } = useMultichainSignMessage();\n\n const handleMembershipError = useCallback(\n async (error: { type: 'signature_rejected' | 'membership_failed'; message: string }) => {\n console.error(\n `[useTurtleWebAdapter] Membership error (${error.type}): ${error.message}`\n );\n // Don't auto-disconnect - let the UI handle the error\n throw error;\n },\n []\n );\n\n // Membership flow - disabled auto-trigger, will be triggered manually via modal\n const { isMember, isLoading: isMembershipLoading, refetch: refetchMembership } = useTurtleMembershipFlow({\n address: account.address,\n walletEcosystem: \"evm\",\n signMessage,\n chainId: \"1\",\n enabled: false, // Disabled - will trigger manually from modal\n onError: handleMembershipError,\n });\n\n // Show membership modal when: connected + not a member (keep open during loading)\n const shouldShowMembershipModal =\n account.isConnected &&\n !!account.address &&\n isMember === false;\n\n // Trigger membership flow manually (called from modal \"Sign\" button)\n const triggerMembershipFlow = useCallback(async () => {\n await refetchMembership();\n }, [refetchMembership]);\n\n // Fetch featured opportunities for Turtle Web\n const { data: opportunitiesData, isLoading: isLoadingOpportunities } = useOpportunitiesPaginated({\n params: {\n page: 1,\n featured: true,\n limit: 1000,\n },\n enabled: isActive,\n });\n\n\n /**\n * Check if platform is available\n * Web is always available in browser\n */\n const isAvailable = useCallback((): boolean => {\n return typeof window !== 'undefined';\n }, []);\n\n /**\n * Authenticate user via wallet connection (EVM only)\n * Opens wallet connection modal and returns immediately\n * The UI will update reactively when the user connects\n */\n const authenticate = useCallback(\n async (): Promise<AuthResult> => {\n try {\n if (account.isConnected && account.address) {\n return {\n success: true,\n user: {\n id: account.address,\n metadata: {\n chainId: account.chainId,\n status: account.status,\n },\n },\n };\n }\n\n await connect(\"evm\");\n\n return {\n success: true,\n };\n } catch (error) {\n console.error('[useTurtleWebAdapter] Authentication error:', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown authentication error',\n };\n }\n },\n [account.isConnected, account.address, account.chainId, account.status, connect]\n );\n\n /**\n * Disconnect the wallet\n */\n const disconnectWallet = useCallback(async (): Promise<void> => {\n try {\n await disconnect();\n } catch (error) {\n console.error('[useTurtleWebAdapter] Disconnect error:', error);\n throw error;\n }\n }, [disconnect]);\n\n /**\n * Get currently authenticated user\n */\n const getUser = useCallback((): User | null => {\n if (!account.isConnected || !account.address) {\n return null;\n }\n\n return {\n id: account.address,\n metadata: {\n chainId: account.chainId,\n status: account.status,\n ecosystem: account.ecosystem,\n isMember,\n isMembershipLoading,\n },\n };\n }, [account.isConnected, account.address, account.chainId, account.status, account.ecosystem, isMember, isMembershipLoading]);\n\n /**\n * Deposit tokens to an opportunity\n * TODO: Implement\n */\n const depositToOpportunity = useCallback(\n async (_params: DepositParams): Promise<TransactionResult> => {\n return UNIMPLEMENTED_ERRORS.deposit();\n },\n []\n );\n\n /**\n * Get platform capabilities\n */\n const getCapabilities = useCallback((): PlatformCapabilities => {\n return {\n canChangeNetwork: true,\n canDisconnect: true,\n showNetworkSelector: true,\n showGasEstimate: true,\n showUsername: false,\n requiresGasPayment: true,\n supportsNotifications: false,\n canConnectWallet: true,\n };\n }, []);\n\n /**\n * Get all opportunities\n * Returns featured opportunities from the query data\n */\n const getOpportunities = useCallback(async (): Promise<Opportunity[]> => {\n return Promise.resolve(opportunitiesData?.opportunities || []);\n }, [opportunitiesData]);\n\n /**\n * Get a single opportunity\n * TODO: Implement\n */\n const getOpportunity = useCallback(async (_opportunityId: string): Promise<Opportunity> => {\n return UNIMPLEMENTED_ERRORS.getOpportunity();\n }, []);\n\n // Return adapter object\n return useMemo(\n () => ({\n platformId: PlatformId.TurtleWeb,\n platformName: 'Turtle Web',\n isAvailable,\n authenticate,\n disconnect: disconnectWallet,\n getUser,\n depositToOpportunity,\n getCapabilities,\n getOpportunities,\n getOpportunity,\n // Reactive loading states\n isLoadingOpportunities,\n isLoadingUser: isMembershipLoading,\n // Reactive data\n opportunities: opportunitiesData?.opportunities || [],\n // Membership flow\n shouldShowMembershipModal,\n triggerMembershipFlow,\n }),\n [\n isAvailable,\n authenticate,\n disconnectWallet,\n getUser,\n depositToOpportunity,\n getCapabilities,\n getOpportunities,\n getOpportunity,\n isLoadingOpportunities,\n isMembershipLoading,\n opportunitiesData,\n shouldShowMembershipModal,\n triggerMembershipFlow,\n ]\n );\n}\n","import { useCallback, useMemo, useState, useEffect } from 'react';\nimport { Opportunity, useOpportunitiesPaginated } from '@turtleclub/hooks';\nimport { PlatformId } from '../core/types';\nimport type {\n PlatformAdapter,\n User,\n AuthResult,\n DepositParams,\n TransactionResult,\n PlatformCapabilities,\n} from '../core/types';\nimport { UNIMPLEMENTED_ERRORS } from '../core/errors';\n\n/**\n * Lemon Adapter Hook - for Lemon Cash WebView mini apps\n * Communicates with Lemon Cash mobile app via WebView postMessage\n *\n * @see https://lemoncash.mintlify.app/functions/authenticate\n *\n * NOTE: This is a stub implementation for architectural demonstration.\n * Full implementation will be added when integrating with Lemon Cash.\n *\n * @param isActive - Whether this adapter is the currently active platform (used to conditionally enable queries)\n */\nexport function useLemonAdapter(isActive: boolean): PlatformAdapter {\n const [user, setUser] = useState<User | null>(null);\n const [isWebView, setIsWebView] = useState(false);\n\n // Detect if running in Lemon WebView environment\n useEffect(() => {\n if (typeof window !== 'undefined') {\n const hasReactNativeWebView = !!(window as any).ReactNativeWebView;\n setIsWebView(hasReactNativeWebView);\n }\n }, []);\n\n // TODO: Confirm the exact chain slugs with Lemon team\n const { data: opportunitiesData } = useOpportunitiesPaginated({\n params: {\n page: 1,\n receiptTokenChainSlug: 'ethereum,solana,base,polygon,arbitrum,optimism,avalanche',\n limit: 100,\n },\n enabled: isActive,\n });\n\n /**\n * Check if platform is available\n * Lemon is available only in React Native WebView\n */\n const isAvailable = useCallback((): boolean => {\n return isWebView;\n }, [isWebView]);\n\n /**\n * Authenticate user via Lemon SIWE (Sign In With Ethereum)\n * TODO: Implement using Lemon SDK\n * @see https://lemoncash.mintlify.app/functions/authenticate\n */\n const authenticate = useCallback(\n async (_nonce?: string): Promise<AuthResult> => {\n if (!isWebView) {\n return {\n success: false,\n error: 'Not running in Lemon Cash WebView environment',\n };\n }\n\n return {\n success: false,\n error: 'Lemon authentication not implemented yet',\n };\n },\n [isWebView]\n );\n\n /**\n * Disconnect the wallet\n * TODO: Implement\n */\n const disconnect = useCallback(async (): Promise<void> => {\n setUser(null);\n }, []);\n\n /**\n * Get currently authenticated user\n */\n const getUser = useCallback((): User | null => {\n return user;\n }, [user]);\n\n /**\n * Deposit tokens to an opportunity\n * TODO: Implement using Lemon SDK\n * @see https://lemoncash.mintlify.app/functions/deposit\n */\n const depositToOpportunity = useCallback(\n async (_params: DepositParams): Promise<TransactionResult> => {\n if (!isWebView) {\n return {\n success: false,\n error: 'Not running in Lemon Cash WebView environment',\n };\n }\n\n return UNIMPLEMENTED_ERRORS.deposit();\n },\n [isWebView]\n );\n\n /**\n * Get platform capabilities\n */\n const getCapabilities = useCallback((): PlatformCapabilities => {\n return {\n canChangeNetwork: false, // Lemon controls the network\n canDisconnect: false, // Lemon handles session\n showNetworkSelector: false,\n showGasEstimate: false, // Lemon abstracts gas\n showUsername: true, // Lemon provides user info\n requiresGasPayment: false, // Lemon covers gas\n supportsNotifications: true,\n canConnectWallet: true,\n };\n }, []);\n\n /**\n * Get all opportunities\n * Returns opportunities from supported chains\n */\n const getOpportunities = useCallback(async (): Promise<Opportunity[]> => {\n return Promise.resolve(opportunitiesData?.opportunities || []);\n }, [opportunitiesData]);\n\n /**\n * Get a single opportunity\n * TODO: Implement\n */\n const getOpportunity = useCallback(async (_opportunityId: string): Promise<Opportunity> => {\n return UNIMPLEMENTED_ERRORS.getOpportunity();\n }, []);\n\n // Return adapter object\n return useMemo(\n () => ({\n platformId: PlatformId.Lemon,\n platformName: 'Lemon Cash',\n isAvailable,\n authenticate,\n disconnect,\n getUser,\n depositToOpportunity,\n getCapabilities,\n getOpportunities,\n getOpportunity,\n }),\n [\n isAvailable,\n authenticate,\n disconnect,\n getUser,\n depositToOpportunity,\n getCapabilities,\n getOpportunities,\n getOpportunity,\n ]\n );\n}\n","\"use client\";\n\nimport React, { createContext, useContext, useEffect, useState, useMemo } from \"react\";\nimport { PlatformId } from \"./types\";\nimport type { PlatformAdapter, DetectionResult } from \"./types\";\nimport { detectPlatform } from \"./detector\";\nimport { useTurtleWebAdapter } from \"../adapters/useTurtleWebAdapter\";\nimport { useLemonAdapter } from \"../adapters/useLemonAdapter\";\n\ninterface PlatformContextValue {\n /** The platform adapter instance */\n adapter: PlatformAdapter;\n /** Platform detection result */\n detection: DetectionResult;\n /** Whether platform is ready */\n isReady: boolean;\n}\n\nconst PlatformContext = createContext<PlatformContextValue | null>(null);\n\ninterface PlatformProviderProps {\n children: React.ReactNode;\n /** Custom loading component to show while platform is being detected */\n loadingComponent?: React.ReactNode;\n /** Custom error component to show if initialization fails. Receives error and retry function */\n errorComponent?: (error: Error, retry: () => void) => React.ReactNode;\n /** Force a specific platform (useful for testing/debugging) */\n forcePlatform?: PlatformId;\n /** Custom membership verification modal component */\n membershipModal?: React.ReactNode;\n}\n\n/**\n * Platform Provider component\n * Detects the platform and provides the appropriate adapter via React hooks\n *\n * All adapter hooks are called unconditionally (React rules of hooks),\n * but only the detected platform's adapter is exposed through context.\n */\nfunction PlatformProvider({\n children,\n loadingComponent,\n errorComponent,\n forcePlatform,\n membershipModal,\n}: PlatformProviderProps) {\n const [error, setError] = useState<Error | null>(null);\n const [detection, setDetection] = useState<DetectionResult | null>(null);\n\n\n const activePlatformId = detection?.platformId;\n\n const turtleWebAdapter = useTurtleWebAdapter(activePlatformId === PlatformId.TurtleWeb);\n const lemonAdapter = useLemonAdapter(activePlatformId === PlatformId.Lemon);\n\n\n useEffect(() => {\n try {\n let detectionResult: DetectionResult;\n if (forcePlatform) {\n detectionResult = {\n platformId: forcePlatform,\n detectionMethod: \"forced\",\n isValidated: false,\n warnings: [\"Platform was manually forced via forcePlatform prop\"],\n };\n } else {\n detectionResult = detectPlatform();\n }\n setDetection(detectionResult);\n } catch (err) {\n console.error(\"[PlatformProvider] Error during platform detection:\", err);\n setError(err instanceof Error ? err : new Error(\"Unknown error during platform detection\"));\n }\n }, [forcePlatform]);\n\n\n const adapter = useMemo((): PlatformAdapter | null => {\n if (!detection) return null;\n\n switch (detection.platformId) {\n case PlatformId.TurtleWeb:\n return turtleWebAdapter;\n case PlatformId.Lemon:\n return lemonAdapter;\n case PlatformId.Worldcoin:\n // TODO: Implement worldcoin adapter\n console.warn(\"[PlatformProvider] Worldcoin adapter not implemented yet\");\n setError(new Error(\"Worldcoin platform not implemented yet\"));\n return null;\n default:\n console.warn(\"[PlatformProvider] Unknown platform:\", detection.platformId);\n setError(new Error(`Unknown platform: ${detection.platformId}`));\n return null;\n }\n }, [detection, turtleWebAdapter, lemonAdapter]);\n\n\n const contextValue = useMemo(() => {\n if (!detection || !adapter) return null;\n\n return {\n adapter,\n detection,\n isReady: true,\n };\n }, [adapter, detection]);\n\n if (error) {\n const retry = () => {\n setError(null);\n setDetection(null);\n };\n\n if (errorComponent) {\n return <>{errorComponent(error, retry)}</>;\n }\n return (\n <main className=\"flex flex-col items-center justify-center h-screen\">\n <div className=\"text-lg font-bold\">There was an error initializing the platform</div>\n <span className=\"text-sm text-gray-500\">{error.message}</span>\n <span className=\"text-xs text-gray-500\">\n Please provide an Error component to the PlatformProvider.\n </span>\n </main>\n );\n }\n\n\n if (!contextValue) {\n if (loadingComponent) {\n return <>{loadingComponent}</>;\n }\n return (\n <main className=\"flex flex-col items-center justify-center h-screen\">\n <span className=\"text-lg font-bold\">Detecting platform...</span>\n <span className=\"text-xs text-gray-500\">\n Please provide a Loading component to the PlatformProvider.\n </span>\n </main>\n );\n }\n\n return (\n <PlatformContext.Provider value={contextValue}>\n {children}\n {membershipModal}\n </PlatformContext.Provider>\n );\n}\n\nexport { PlatformProvider };\n\n/**\n * Hook to access platform context\n * @throws Error if used outside PlatformProvider\n */\nexport function usePlatform(): PlatformContextValue {\n const context = useContext(PlatformContext);\n\n if (!context) {\n throw new Error(\"usePlatform must be used within a PlatformProvider\");\n }\n\n return context;\n}\n","\"use client\";\n\nimport { useState } from \"react\";\n\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { initializeMultiChain } from \"@turtleclub/multichain\";\n\nimport { PlatformProvider } from \"./platform/core/PlatformProvider\";\nimport type { PlatformId } from \"./platform/core/types\";\n\nimport { MultiChainProvider } from \"@turtleclub/multichain\";\nexport interface TurtleBasicProviderProps {\n children: React.ReactNode;\n walletConnectProjectId: string;\n metadata: {\n name: string;\n description: string;\n url: string;\n icons: string[];\n };\n tonManifestUrl?: string;\n loadingComponent?: React.ReactNode;\n errorComponent?: (error: Error, retry: () => void) => React.ReactNode;\n forcePlatform?: PlatformId; // for testing/debugging\n queryClientConfig?: ConstructorParameters<typeof QueryClient>[0];\n membershipModal?: React.ReactNode;\n}\n\n\nexport function TurtleBasicProvider({\n children,\n walletConnectProjectId,\n metadata,\n tonManifestUrl = \"/tonconnect-manifest.json\",\n loadingComponent,\n errorComponent,\n forcePlatform,\n queryClientConfig,\n membershipModal,\n}: TurtleBasicProviderProps) {\n\n const [queryClient] = useState(\n () =>\n new QueryClient(\n queryClientConfig || {\n defaultOptions: {\n queries: {\n staleTime: 60 * 1000,\n refetchOnWindowFocus: false,\n },\n },\n }\n )\n );\n\n initializeMultiChain({\n projectId: walletConnectProjectId,\n metadata\n });\n \n\n return (\n <QueryClientProvider client={queryClient}>\n <MultiChainProvider tonManifestUrl={tonManifestUrl}>\n <PlatformProvider\n loadingComponent={loadingComponent}\n errorComponent={errorComponent}\n forcePlatform={forcePlatform}\n membershipModal={membershipModal}\n >\n {children}\n </PlatformProvider>\n </MultiChainProvider>\n </QueryClientProvider>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/platform/core/types.ts","../src/platform/core/detector.ts","../src/platform/core/errors.ts","../src/platform/adapters/useTurtleWebAdapter.ts","../src/platform/adapters/useLemonAdapter.ts","../src/platform/core/PlatformProvider.tsx","../src/TurtleBasicProvider.tsx"],"names":["PlatformId","cachedDetectionResult","CACHE_KEY","loadCachedDetection","cached","error","saveCachedDetection","result","detectFromSubdomain","hostname","detectPlatform","forceRedetect","sessionCached","cacheAndReturn","subdomainPlatform","UNIMPLEMENTED_ERRORS","useTurtleWebAdapter","isActive","account","useMultichainAccount","connect","useMultichainConnect","disconnect","useMultichainDisconnect","signMessage","useMultichainSignMessage","handleMembershipError","useCallback","isMember","isMembershipLoading","refetchMembership","useTurtleMembershipFlow","shouldShowMembershipModal","triggerMembershipFlow","opportunitiesData","isLoadingOpportunities","useOpportunitiesPaginated","isAvailable","authenticate","disconnectWallet","getUser","depositToOpportunity","_params","getCapabilities","getOpportunities","getOpportunity","_opportunityId","useMemo","useLemonAdapter","user","setUser","useState","isWebView","setIsWebView","useEffect","hasReactNativeWebView","_nonce","PlatformContext","createContext","PlatformProvider","children","loadingComponent","errorComponent","forcePlatform","membershipModal","setError","detection","setDetection","minLoadingTimeElapsed","setMinLoadingTimeElapsed","timer","activePlatformId","turtleWebAdapter","lemonAdapter","detectionResult","err","adapter","contextValue","retry","jsx","Fragment","jsxs","usePlatform","context","useContext","TurtleBasicProvider","walletConnectProjectId","metadata","tonManifestUrl","queryClientConfig","queryClient","QueryClient","initializeMultiChain","QueryClientProvider","MultiChainProvider"],"mappings":"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","file":"index.cjs","sourcesContent":["import { Opportunity } from \"@turtleclub/hooks\";\n\nexport const PlatformId = {\n TurtleWeb: 'turtle-web',\n Lemon: 'lemon',\n Worldcoin: 'worldcoin',\n} as const;\n\n/**\n * Platform identifier type\n */\nexport type PlatformId = typeof PlatformId[keyof typeof PlatformId];\n\n/**\n * User information from platform authentication\n */\n//Probably will be changed later.\nexport interface User {\n id: string;\n username?: string;\n email?: string;\n avatar?: string;\n metadata?: Record<string, any>;\n}\n\n/**\n * Result of authentication attempt\n */\nexport interface AuthResult {\n success: boolean;\n user?: User;\n error?: string;\n metadata?: Record<string, any>;\n}\n\n/**\n * Parameters for depositing to an opportunity\n */\n//This will be changed later.\nexport interface DepositParams {\n opportunityAddress: string;\n tokenAddress: string;\n amount: string;\n chainId: number;\n}\n\n/**\n * Result of a transaction attempt\n */\nexport interface TransactionResult {\n success: boolean;\n txHash?: string;\n error?: string;\n metadata?: Record<string, any>;\n}\n\n/**\n * Platform capabilities - what features are available/should be shown\n */\nexport interface PlatformCapabilities {\n canChangeNetwork: boolean;\n canDisconnect: boolean;\n showNetworkSelector: boolean;\n showGasEstimate: boolean;\n showUsername: boolean;\n requiresGasPayment: boolean;\n supportsNotifications: boolean;\n canConnectWallet: boolean;\n}\n\n/**\n * Platform adapter interface - implemented by each platform's hook\n * Returned by platform-specific adapter hooks (useTurtleWebAdapter, useLemonAdapter, etc.)\n */\nexport interface PlatformAdapter {\n readonly platformId: PlatformId;\n readonly platformName: string;\n isAvailable(): boolean;\n authenticate(nonce?: string): Promise<AuthResult>;\n disconnect(): Promise<void>;\n getUser(): User | null;\n depositToOpportunity(params: DepositParams): Promise<TransactionResult>;\n getOpportunities(): Promise<Opportunity[]>;\n getOpportunity(opportunityId: string): Promise<Opportunity>;\n getCapabilities(): PlatformCapabilities;\n\n // Reactive loading states - available when adapter is a hook\n readonly isLoadingOpportunities?: boolean;\n readonly isLoadingUser?: boolean;\n\n // Reactive data - available when adapter is a hook\n readonly opportunities?: Opportunity[];\n\n // Membership flow - available when adapter requires membership verification\n readonly shouldShowMembershipModal?: boolean;\n readonly triggerMembershipFlow?: () => Promise<void>;\n}\n\n/**\n * Result of platform detection\n */\nexport interface DetectionResult {\n platformId: PlatformId;\n detectionMethod: 'subdomain' | 'sdk' | 'forced' | 'default';\n isValidated: boolean;\n warnings?: string[];\n}\n","import { PlatformId } from './types';\nimport type { DetectionResult } from './types';\n\n// Cached detection result (singleton pattern)\nlet cachedDetectionResult: DetectionResult | null = null;\n\n// SessionStorage key for caching\nconst CACHE_KEY = 'turtle-platform-detection';\n\n/**\n * Load cached detection result from sessionStorage\n */\nfunction loadCachedDetection(): DetectionResult | null {\n if (typeof window === 'undefined' || typeof sessionStorage === 'undefined') {\n return null;\n }\n\n try {\n const cached = sessionStorage.getItem(CACHE_KEY);\n if (cached) {\n return JSON.parse(cached) as DetectionResult;\n }\n } catch (error) {\n console.warn('[Platform Detection] Failed to load cached detection:', error);\n }\n\n return null;\n}\n\n/**\n * Save detection result to sessionStorage\n */\nfunction saveCachedDetection(result: DetectionResult): void {\n if (typeof window === 'undefined' || typeof sessionStorage === 'undefined') {\n return;\n }\n\n try {\n sessionStorage.setItem(CACHE_KEY, JSON.stringify(result));\n } catch (error) {\n console.warn('[Platform Detection] Failed to save cached detection:', error);\n }\n}\n\n\n/**\n * Detect platform from subdomain\n */\nfunction detectFromSubdomain(): typeof PlatformId[keyof typeof PlatformId] | null {\n if (typeof window === 'undefined') return null;\n\n const hostname = window.location.hostname;\n\n // Check for platform-specific subdomains\n if (hostname.includes('worldcoin.')) {\n return PlatformId.Worldcoin;\n }\n if (hostname.includes('lemon.')) {\n return PlatformId.Lemon;\n }\n\n return null;\n}\n\n\n/**\n * Main platform detection function\n * Detects platform based on subdomain\n * @param forceRedetect - Force re-detection even if cached result exists\n */\nexport function detectPlatform(forceRedetect = false): DetectionResult {\n // Return cached result if available and not forcing re-detection\n if (!forceRedetect) {\n // Check in-memory cache first (fastest)\n if (cachedDetectionResult) {\n return cachedDetectionResult;\n }\n\n // Check sessionStorage cache\n const sessionCached = loadCachedDetection();\n if (sessionCached) {\n cachedDetectionResult = sessionCached;\n return sessionCached;\n }\n }\n\n const cacheAndReturn = (result: DetectionResult): DetectionResult => {\n cachedDetectionResult = result;\n saveCachedDetection(result);\n return result;\n };\n\n // Priority 1: Subdomain detection\n const subdomainPlatform = detectFromSubdomain();\n if (subdomainPlatform) {\n return cacheAndReturn({\n platformId: subdomainPlatform,\n detectionMethod: 'subdomain',\n isValidated: true,\n });\n }\n\n // Priority 2: Default to turtle-web\n return cacheAndReturn({\n platformId: PlatformId.TurtleWeb,\n detectionMethod: 'default',\n isValidated: true,\n });\n}\n","import type { TransactionResult } from './types';\n\n/**\n * Standard error responses for unimplemented features\n */\nexport const UNIMPLEMENTED_ERRORS = {\n deposit: (): TransactionResult => ({\n success: false,\n error: 'Deposit not implemented yet',\n }),\n\n getOpportunity: (): Promise<never> => {\n return Promise.reject(new Error('getOpportunity not implemented yet'));\n },\n} as const;\n","import { useCallback, useMemo } from 'react';\nimport {\n useMultichainAccount,\n useMultichainConnect,\n useMultichainDisconnect,\n useMultichainSignMessage\n} from '@turtleclub/multichain';\nimport { Opportunity, useOpportunitiesPaginated, useTurtleMembershipFlow } from '@turtleclub/hooks';\nimport { PlatformId } from '../core/types';\nimport type {\n PlatformAdapter,\n User,\n AuthResult,\n DepositParams,\n TransactionResult,\n PlatformCapabilities,\n} from '../core/types';\nimport { UNIMPLEMENTED_ERRORS } from '../core/errors';\n\n/**\n * Turtle Web Adapter Hook - for standard web browsers\n * Uses multichain wallet abstraction with EVM support\n *\n * This is a hook-based adapter that works reactively with React state.\n * Methods always have access to the latest wallet state through React hooks.\n * Automatically handles membership authentication when wallet connects.\n *\n * @param isActive - Whether this adapter is the currently active platform (used to conditionally enable queries)\n */\nexport function useTurtleWebAdapter(isActive: boolean): PlatformAdapter {\n const account = useMultichainAccount();\n const { connect } = useMultichainConnect();\n const { disconnect } = useMultichainDisconnect();\n const { signMessage } = useMultichainSignMessage();\n\n const handleMembershipError = useCallback(\n async (error: { type: 'signature_rejected' | 'membership_failed'; message: string }) => {\n console.error(\n `[useTurtleWebAdapter] Membership error (${error.type}): ${error.message}`\n );\n // Don't auto-disconnect - let the UI handle the error\n throw error;\n },\n []\n );\n\n // Membership flow - disabled auto-trigger, will be triggered manually via modal\n const { isMember, isLoading: isMembershipLoading, refetch: refetchMembership } = useTurtleMembershipFlow({\n address: account.address,\n walletEcosystem: \"evm\",\n signMessage,\n chainId: \"1\",\n enabled: false, // Disabled - will trigger manually from modal\n onError: handleMembershipError,\n });\n\n // Show membership modal when: connected + not a member (keep open during loading)\n const shouldShowMembershipModal =\n account.isConnected &&\n !!account.address &&\n isMember === false;\n\n // Trigger membership flow manually (called from modal \"Sign\" button)\n const triggerMembershipFlow = useCallback(async () => {\n await refetchMembership();\n }, [refetchMembership]);\n\n // Fetch featured opportunities for Turtle Web\n const { data: opportunitiesData, isLoading: isLoadingOpportunities } = useOpportunitiesPaginated({\n params: {\n page: 1,\n featured: true,\n limit: 1000,\n },\n enabled: isActive,\n });\n\n\n /**\n * Check if platform is available\n * Web is always available in browser\n */\n const isAvailable = useCallback((): boolean => {\n return typeof window !== 'undefined';\n }, []);\n\n /**\n * Authenticate user via wallet connection (EVM only)\n * Opens wallet connection modal and returns immediately\n * The UI will update reactively when the user connects\n */\n const authenticate = useCallback(\n async (): Promise<AuthResult> => {\n try {\n if (account.isConnected && account.address) {\n return {\n success: true,\n user: {\n id: account.address,\n metadata: {\n chainId: account.chainId,\n status: account.status,\n },\n },\n };\n }\n\n await connect(\"evm\");\n\n return {\n success: true,\n };\n } catch (error) {\n console.error('[useTurtleWebAdapter] Authentication error:', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown authentication error',\n };\n }\n },\n [account.isConnected, account.address, account.chainId, account.status, connect]\n );\n\n /**\n * Disconnect the wallet\n */\n const disconnectWallet = useCallback(async (): Promise<void> => {\n try {\n await disconnect();\n } catch (error) {\n console.error('[useTurtleWebAdapter] Disconnect error:', error);\n throw error;\n }\n }, [disconnect]);\n\n /**\n * Get currently authenticated user\n */\n const getUser = useCallback((): User | null => {\n if (!account.isConnected || !account.address) {\n return null;\n }\n\n return {\n id: account.address,\n metadata: {\n chainId: account.chainId,\n status: account.status,\n ecosystem: account.ecosystem,\n isMember,\n isMembershipLoading,\n },\n };\n }, [account.isConnected, account.address, account.chainId, account.status, account.ecosystem, isMember, isMembershipLoading]);\n\n /**\n * Deposit tokens to an opportunity\n * TODO: Implement\n */\n const depositToOpportunity = useCallback(\n async (_params: DepositParams): Promise<TransactionResult> => {\n return UNIMPLEMENTED_ERRORS.deposit();\n },\n []\n );\n\n /**\n * Get platform capabilities\n */\n const getCapabilities = useCallback((): PlatformCapabilities => {\n return {\n canChangeNetwork: true,\n canDisconnect: true,\n showNetworkSelector: true,\n showGasEstimate: true,\n showUsername: false,\n requiresGasPayment: true,\n supportsNotifications: false,\n canConnectWallet: true,\n };\n }, []);\n\n /**\n * Get all opportunities\n * Returns featured opportunities from the query data\n */\n const getOpportunities = useCallback(async (): Promise<Opportunity[]> => {\n return Promise.resolve(opportunitiesData?.opportunities || []);\n }, [opportunitiesData]);\n\n /**\n * Get a single opportunity\n * TODO: Implement\n */\n const getOpportunity = useCallback(async (_opportunityId: string): Promise<Opportunity> => {\n return UNIMPLEMENTED_ERRORS.getOpportunity();\n }, []);\n\n // Return adapter object\n return useMemo(\n () => ({\n platformId: PlatformId.TurtleWeb,\n platformName: 'Turtle Web',\n isAvailable,\n authenticate,\n disconnect: disconnectWallet,\n getUser,\n depositToOpportunity,\n getCapabilities,\n getOpportunities,\n getOpportunity,\n // Reactive loading states\n isLoadingOpportunities,\n isLoadingUser: isMembershipLoading,\n // Reactive data\n opportunities: opportunitiesData?.opportunities || [],\n // Membership flow\n shouldShowMembershipModal,\n triggerMembershipFlow,\n }),\n [\n isAvailable,\n authenticate,\n disconnectWallet,\n getUser,\n depositToOpportunity,\n getCapabilities,\n getOpportunities,\n getOpportunity,\n isLoadingOpportunities,\n isMembershipLoading,\n opportunitiesData,\n shouldShowMembershipModal,\n triggerMembershipFlow,\n ]\n );\n}\n","import { useCallback, useMemo, useState, useEffect } from 'react';\nimport { Opportunity, useOpportunitiesPaginated } from '@turtleclub/hooks';\nimport { PlatformId } from '../core/types';\nimport type {\n PlatformAdapter,\n User,\n AuthResult,\n DepositParams,\n TransactionResult,\n PlatformCapabilities,\n} from '../core/types';\nimport { UNIMPLEMENTED_ERRORS } from '../core/errors';\n\n/**\n * Lemon Adapter Hook - for Lemon Cash WebView mini apps\n * Communicates with Lemon Cash mobile app via WebView postMessage\n *\n * @see https://lemoncash.mintlify.app/functions/authenticate\n *\n * NOTE: This is a stub implementation for architectural demonstration.\n * Full implementation will be added when integrating with Lemon Cash.\n *\n * @param isActive - Whether this adapter is the currently active platform (used to conditionally enable queries)\n */\nexport function useLemonAdapter(isActive: boolean): PlatformAdapter {\n const [user, setUser] = useState<User | null>(null);\n const [isWebView, setIsWebView] = useState(false);\n\n // Detect if running in Lemon WebView environment\n useEffect(() => {\n if (typeof window !== 'undefined') {\n const hasReactNativeWebView = !!(window as any).ReactNativeWebView;\n setIsWebView(hasReactNativeWebView);\n }\n }, []);\n\n // TODO: Confirm the exact chain slugs with Lemon team\n const { data: opportunitiesData } = useOpportunitiesPaginated({\n params: {\n page: 1,\n receiptTokenChainSlug: 'ethereum,solana,base,polygon,arbitrum,optimism,avalanche',\n limit: 100,\n },\n enabled: isActive,\n });\n\n /**\n * Check if platform is available\n * Lemon is available only in React Native WebView\n */\n const isAvailable = useCallback((): boolean => {\n return isWebView;\n }, [isWebView]);\n\n /**\n * Authenticate user via Lemon SIWE (Sign In With Ethereum)\n * TODO: Implement using Lemon SDK\n * @see https://lemoncash.mintlify.app/functions/authenticate\n */\n const authenticate = useCallback(\n async (_nonce?: string): Promise<AuthResult> => {\n if (!isWebView) {\n return {\n success: false,\n error: 'Not running in Lemon Cash WebView environment',\n };\n }\n\n return {\n success: false,\n error: 'Lemon authentication not implemented yet',\n };\n },\n [isWebView]\n );\n\n /**\n * Disconnect the wallet\n * TODO: Implement\n */\n const disconnect = useCallback(async (): Promise<void> => {\n setUser(null);\n }, []);\n\n /**\n * Get currently authenticated user\n */\n const getUser = useCallback((): User | null => {\n return user;\n }, [user]);\n\n /**\n * Deposit tokens to an opportunity\n * TODO: Implement using Lemon SDK\n * @see https://lemoncash.mintlify.app/functions/deposit\n */\n const depositToOpportunity = useCallback(\n async (_params: DepositParams): Promise<TransactionResult> => {\n if (!isWebView) {\n return {\n success: false,\n error: 'Not running in Lemon Cash WebView environment',\n };\n }\n\n return UNIMPLEMENTED_ERRORS.deposit();\n },\n [isWebView]\n );\n\n /**\n * Get platform capabilities\n */\n const getCapabilities = useCallback((): PlatformCapabilities => {\n return {\n canChangeNetwork: false, // Lemon controls the network\n canDisconnect: false, // Lemon handles session\n showNetworkSelector: false,\n showGasEstimate: false, // Lemon abstracts gas\n showUsername: true, // Lemon provides user info\n requiresGasPayment: false, // Lemon covers gas\n supportsNotifications: true,\n canConnectWallet: true,\n };\n }, []);\n\n /**\n * Get all opportunities\n * Returns opportunities from supported chains\n */\n const getOpportunities = useCallback(async (): Promise<Opportunity[]> => {\n return Promise.resolve(opportunitiesData?.opportunities || []);\n }, [opportunitiesData]);\n\n /**\n * Get a single opportunity\n * TODO: Implement\n */\n const getOpportunity = useCallback(async (_opportunityId: string): Promise<Opportunity> => {\n return UNIMPLEMENTED_ERRORS.getOpportunity();\n }, []);\n\n // Return adapter object\n return useMemo(\n () => ({\n platformId: PlatformId.Lemon,\n platformName: 'Lemon Cash',\n isAvailable,\n authenticate,\n disconnect,\n getUser,\n depositToOpportunity,\n getCapabilities,\n getOpportunities,\n getOpportunity,\n }),\n [\n isAvailable,\n authenticate,\n disconnect,\n getUser,\n depositToOpportunity,\n getCapabilities,\n getOpportunities,\n getOpportunity,\n ]\n );\n}\n","\"use client\";\n\nimport React, { createContext, useContext, useEffect, useState, useMemo } from \"react\";\nimport { PlatformId } from \"./types\";\nimport type { PlatformAdapter, DetectionResult } from \"./types\";\nimport { detectPlatform } from \"./detector\";\nimport { useTurtleWebAdapter } from \"../adapters/useTurtleWebAdapter\";\nimport { useLemonAdapter } from \"../adapters/useLemonAdapter\";\n\ninterface PlatformContextValue {\n /** The platform adapter instance */\n adapter: PlatformAdapter;\n /** Platform detection result */\n detection: DetectionResult;\n /** Whether platform is ready */\n isReady: boolean;\n}\n\nconst PlatformContext = createContext<PlatformContextValue | null>(null);\n\ninterface PlatformProviderProps {\n children: React.ReactNode;\n /** Custom loading component to show while platform is being detected */\n loadingComponent?: React.ReactNode;\n /** Custom error component to show if initialization fails. Receives error and retry function */\n errorComponent?: (error: Error, retry: () => void) => React.ReactNode;\n /** Force a specific platform (useful for testing/debugging) */\n forcePlatform?: PlatformId;\n /** Custom membership verification modal component */\n membershipModal?: React.ReactNode;\n}\n\n/**\n * Platform Provider component\n * Detects the platform and provides the appropriate adapter via React hooks\n *\n * All adapter hooks are called unconditionally (React rules of hooks),\n * but only the detected platform's adapter is exposed through context.\n */\nfunction PlatformProvider({\n children,\n loadingComponent,\n errorComponent,\n forcePlatform,\n membershipModal,\n}: PlatformProviderProps) {\n const [error, setError] = useState<Error | null>(null);\n const [detection, setDetection] = useState<DetectionResult | null>(null);\n const [minLoadingTimeElapsed, setMinLoadingTimeElapsed] = useState(false);\n\n // Ensure loading screen shows for at least 1.5 seconds\n useEffect(() => {\n const timer = setTimeout(() => {\n setMinLoadingTimeElapsed(true);\n }, 2000);\n\n return () => clearTimeout(timer);\n }, []);\n\n const activePlatformId = detection?.platformId;\n\n const turtleWebAdapter = useTurtleWebAdapter(activePlatformId === PlatformId.TurtleWeb);\n const lemonAdapter = useLemonAdapter(activePlatformId === PlatformId.Lemon);\n\n\n useEffect(() => {\n try {\n let detectionResult: DetectionResult;\n if (forcePlatform) {\n detectionResult = {\n platformId: forcePlatform,\n detectionMethod: \"forced\",\n isValidated: false,\n warnings: [\"Platform was manually forced via forcePlatform prop\"],\n };\n } else {\n detectionResult = detectPlatform();\n }\n setDetection(detectionResult);\n } catch (err) {\n console.error(\"[PlatformProvider] Error during platform detection:\", err);\n setError(err instanceof Error ? err : new Error(\"Unknown error during platform detection\"));\n }\n }, [forcePlatform]);\n\n\n const adapter = useMemo((): PlatformAdapter | null => {\n if (!detection) return null;\n\n switch (detection.platformId) {\n case PlatformId.TurtleWeb:\n return turtleWebAdapter;\n case PlatformId.Lemon:\n return lemonAdapter;\n case PlatformId.Worldcoin:\n // TODO: Implement worldcoin adapter\n console.warn(\"[PlatformProvider] Worldcoin adapter not implemented yet\");\n setError(new Error(\"Worldcoin platform not implemented yet\"));\n return null;\n default:\n console.warn(\"[PlatformProvider] Unknown platform:\", detection.platformId);\n setError(new Error(`Unknown platform: ${detection.platformId}`));\n return null;\n }\n }, [detection, turtleWebAdapter, lemonAdapter]);\n\n\n const contextValue = useMemo(() => {\n if (!detection || !adapter) return null;\n\n return {\n adapter,\n detection,\n isReady: true,\n };\n }, [adapter, detection]);\n\n if (error) {\n const retry = () => {\n setError(null);\n setDetection(null);\n };\n\n if (errorComponent) {\n return <>{errorComponent(error, retry)}</>;\n }\n return (\n <main className=\"flex flex-col items-center justify-center h-screen\">\n <div className=\"text-lg font-bold\">There was an error initializing the platform</div>\n <span className=\"text-sm text-gray-500\">{error.message}</span>\n <span className=\"text-xs text-gray-500\">\n Please provide an Error component to the PlatformProvider.\n </span>\n </main>\n );\n }\n\n // Show loading until both context is ready AND minimum loading time has elapsed\n if (!contextValue || !minLoadingTimeElapsed) {\n if (loadingComponent) {\n return <>{loadingComponent}</>;\n }\n return (\n <main className=\"flex flex-col items-center justify-center h-screen\">\n <span className=\"text-lg font-bold\">Detecting platform...</span>\n <span className=\"text-xs text-gray-500\">\n Please provide a Loading component to the PlatformProvider.\n </span>\n </main>\n );\n }\n\n return (\n <PlatformContext.Provider value={contextValue}>\n {children}\n {membershipModal}\n </PlatformContext.Provider>\n );\n}\n\nexport { PlatformProvider };\n\n/**\n * Hook to access platform context\n * @throws Error if used outside PlatformProvider\n */\nexport function usePlatform(): PlatformContextValue {\n const context = useContext(PlatformContext);\n\n if (!context) {\n throw new Error(\"usePlatform must be used within a PlatformProvider\");\n }\n\n return context;\n}\n","\"use client\";\n\nimport { useState } from \"react\";\n\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { initializeMultiChain } from \"@turtleclub/multichain\";\n\nimport { PlatformProvider } from \"./platform/core/PlatformProvider\";\nimport type { PlatformId } from \"./platform/core/types\";\n\nimport { MultiChainProvider } from \"@turtleclub/multichain\";\nexport interface TurtleBasicProviderProps {\n children: React.ReactNode;\n walletConnectProjectId: string;\n metadata: {\n name: string;\n description: string;\n url: string;\n icons: string[];\n };\n tonManifestUrl?: string;\n loadingComponent?: React.ReactNode;\n errorComponent?: (error: Error, retry: () => void) => React.ReactNode;\n forcePlatform?: PlatformId; // for testing/debugging\n queryClientConfig?: ConstructorParameters<typeof QueryClient>[0];\n membershipModal?: React.ReactNode;\n}\n\n\nexport function TurtleBasicProvider({\n children,\n walletConnectProjectId,\n metadata,\n tonManifestUrl = \"/tonconnect-manifest.json\",\n loadingComponent,\n errorComponent,\n forcePlatform,\n queryClientConfig,\n membershipModal,\n}: TurtleBasicProviderProps) {\n\n const [queryClient] = useState(\n () =>\n new QueryClient(\n queryClientConfig || {\n defaultOptions: {\n queries: {\n staleTime: 60 * 1000,\n refetchOnWindowFocus: false,\n },\n },\n }\n )\n );\n\n initializeMultiChain({\n projectId: walletConnectProjectId,\n metadata\n });\n \n\n return (\n <QueryClientProvider client={queryClient}>\n <MultiChainProvider tonManifestUrl={tonManifestUrl}>\n <PlatformProvider\n loadingComponent={loadingComponent}\n errorComponent={errorComponent}\n forcePlatform={forcePlatform}\n membershipModal={membershipModal}\n >\n {children}\n </PlatformProvider>\n </MultiChainProvider>\n </QueryClientProvider>\n );\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {createContext,useCallback,useMemo,useState,useEffect,useContext}from'react';import {QueryClient,QueryClientProvider}from'@tanstack/react-query';import {useMultichainAccount,useMultichainConnect,useMultichainDisconnect,useMultichainSignMessage,initializeMultiChain,MultiChainProvider}from'@turtleclub/multichain';import {useTurtleMembershipFlow,useOpportunitiesPaginated}from'@turtleclub/hooks';import {jsx,Fragment,jsxs}from'react/jsx-runtime';var
|
|
1
|
+
import {createContext,useCallback,useMemo,useState,useEffect,useContext}from'react';import {QueryClient,QueryClientProvider}from'@tanstack/react-query';import {useMultichainAccount,useMultichainConnect,useMultichainDisconnect,useMultichainSignMessage,initializeMultiChain,MultiChainProvider}from'@turtleclub/multichain';import {useTurtleMembershipFlow,useOpportunitiesPaginated}from'@turtleclub/hooks';import {jsx,Fragment,jsxs}from'react/jsx-runtime';var n={TurtleWeb:"turtle-web",Lemon:"lemon",Worldcoin:"worldcoin"};var v=null,U="turtle-platform-detection";function q(){if(typeof window>"u"||typeof sessionStorage>"u")return null;try{let r=sessionStorage.getItem(U);if(r)return JSON.parse(r)}catch(r){console.warn("[Platform Detection] Failed to load cached detection:",r);}return null}function B(r){if(!(typeof window>"u"||typeof sessionStorage>"u"))try{sessionStorage.setItem(U,JSON.stringify(r));}catch(e){console.warn("[Platform Detection] Failed to save cached detection:",e);}}function G(){if(typeof window>"u")return null;let r=window.location.hostname;return r.includes("worldcoin.")?n.Worldcoin:r.includes("lemon.")?n.Lemon:null}function L(r=false){if(!r){if(v)return v;let t=q();if(t)return v=t,t}let e=t=>(v=t,B(t),t),i=G();return e(i?{platformId:i,detectionMethod:"subdomain",isValidated:true}:{platformId:n.TurtleWeb,detectionMethod:"default",isValidated:true})}var R={deposit:()=>({success:false,error:"Deposit not implemented yet"}),getOpportunity:()=>Promise.reject(new Error("getOpportunity not implemented yet"))};function I(r){let e=useMultichainAccount(),{connect:i}=useMultichainConnect(),{disconnect:t}=useMultichainDisconnect(),{signMessage:g}=useMultichainSignMessage(),u=useCallback(async l=>{throw console.error(`[useTurtleWebAdapter] Membership error (${l.type}): ${l.message}`),l},[]),{isMember:s,isLoading:o,refetch:m}=useTurtleMembershipFlow({address:e.address,walletEcosystem:"evm",signMessage:g,chainId:"1",enabled:false,onError:u}),f=e.isConnected&&!!e.address&&s===false,b=useCallback(async()=>{await m();},[m]),{data:d,isLoading:P}=useOpportunitiesPaginated({params:{page:1,featured:true,limit:1e3},enabled:r}),y=useCallback(()=>typeof window<"u",[]),c=useCallback(async()=>{try{return e.isConnected&&e.address?{success:!0,user:{id:e.address,metadata:{chainId:e.chainId,status:e.status}}}:(await i("evm"),{success:!0})}catch(l){return console.error("[useTurtleWebAdapter] Authentication error:",l),{success:false,error:l instanceof Error?l.message:"Unknown authentication error"}}},[e.isConnected,e.address,e.chainId,e.status,i]),C=useCallback(async()=>{try{await t();}catch(l){throw console.error("[useTurtleWebAdapter] Disconnect error:",l),l}},[t]),a=useCallback(()=>!e.isConnected||!e.address?null:{id:e.address,metadata:{chainId:e.chainId,status:e.status,ecosystem:e.ecosystem,isMember:s,isMembershipLoading:o}},[e.isConnected,e.address,e.chainId,e.status,e.ecosystem,s,o]),E=useCallback(async l=>R.deposit(),[]),A=useCallback(()=>({canChangeNetwork:true,canDisconnect:true,showNetworkSelector:true,showGasEstimate:true,showUsername:false,requiresGasPayment:true,supportsNotifications:false,canConnectWallet:true}),[]),O=useCallback(async()=>Promise.resolve(d?.opportunities||[]),[d]),W=useCallback(async l=>R.getOpportunity(),[]);return useMemo(()=>({platformId:n.TurtleWeb,platformName:"Turtle Web",isAvailable:y,authenticate:c,disconnect:C,getUser:a,depositToOpportunity:E,getCapabilities:A,getOpportunities:O,getOpportunity:W,isLoadingOpportunities:P,isLoadingUser:o,opportunities:d?.opportunities||[],shouldShowMembershipModal:f,triggerMembershipFlow:b}),[y,c,C,a,E,A,O,W,P,o,d,f,b])}function x(r){let[e,i]=useState(null),[t,g]=useState(false);useEffect(()=>{if(typeof window<"u"){let c=!!window.ReactNativeWebView;g(c);}},[]);let{data:u}=useOpportunitiesPaginated({params:{page:1,receiptTokenChainSlug:"ethereum,solana,base,polygon,arbitrum,optimism,avalanche",limit:100},enabled:r}),s=useCallback(()=>t,[t]),o=useCallback(async c=>t?{success:false,error:"Lemon authentication not implemented yet"}:{success:false,error:"Not running in Lemon Cash WebView environment"},[t]),m=useCallback(async()=>{i(null);},[]),f=useCallback(()=>e,[e]),b=useCallback(async c=>t?R.deposit():{success:false,error:"Not running in Lemon Cash WebView environment"},[t]),d=useCallback(()=>({canChangeNetwork:false,canDisconnect:false,showNetworkSelector:false,showGasEstimate:false,showUsername:true,requiresGasPayment:false,supportsNotifications:true,canConnectWallet:true}),[]),P=useCallback(async()=>Promise.resolve(u?.opportunities||[]),[u]),y=useCallback(async c=>R.getOpportunity(),[]);return useMemo(()=>({platformId:n.Lemon,platformName:"Lemon Cash",isAvailable:s,authenticate:o,disconnect:m,getUser:f,depositToOpportunity:b,getCapabilities:d,getOpportunities:P,getOpportunity:y}),[s,o,m,f,b,d,P,y])}var F=createContext(null);function D({children:r,loadingComponent:e,errorComponent:i,forcePlatform:t,membershipModal:g}){let[u,s]=useState(null),[o,m]=useState(null),[f,b]=useState(false);useEffect(()=>{let a=setTimeout(()=>{b(true);},2e3);return ()=>clearTimeout(a)},[]);let d=o?.platformId,P=I(d===n.TurtleWeb),y=x(d===n.Lemon);useEffect(()=>{try{let a;t?a={platformId:t,detectionMethod:"forced",isValidated:!1,warnings:["Platform was manually forced via forcePlatform prop"]}:a=L(),m(a);}catch(a){console.error("[PlatformProvider] Error during platform detection:",a),s(a instanceof Error?a:new Error("Unknown error during platform detection"));}},[t]);let c=useMemo(()=>{if(!o)return null;switch(o.platformId){case n.TurtleWeb:return P;case n.Lemon:return y;case n.Worldcoin:return console.warn("[PlatformProvider] Worldcoin adapter not implemented yet"),s(new Error("Worldcoin platform not implemented yet")),null;default:return console.warn("[PlatformProvider] Unknown platform:",o.platformId),s(new Error(`Unknown platform: ${o.platformId}`)),null}},[o,P,y]),C=useMemo(()=>!o||!c?null:{adapter:c,detection:o,isReady:true},[c,o]);if(u){let a=()=>{s(null),m(null);};return i?jsx(Fragment,{children:i(u,a)}):jsxs("main",{className:"flex flex-col items-center justify-center h-screen",children:[jsx("div",{className:"text-lg font-bold",children:"There was an error initializing the platform"}),jsx("span",{className:"text-sm text-gray-500",children:u.message}),jsx("span",{className:"text-xs text-gray-500",children:"Please provide an Error component to the PlatformProvider."})]})}return !C||!f?e?jsx(Fragment,{children:e}):jsxs("main",{className:"flex flex-col items-center justify-center h-screen",children:[jsx("span",{className:"text-lg font-bold",children:"Detecting platform..."}),jsx("span",{className:"text-xs text-gray-500",children:"Please provide a Loading component to the PlatformProvider."})]}):jsxs(F.Provider,{value:C,children:[r,g]})}function re(){let r=useContext(F);if(!r)throw new Error("usePlatform must be used within a PlatformProvider");return r}function le({children:r,walletConnectProjectId:e,metadata:i,tonManifestUrl:t="/tonconnect-manifest.json",loadingComponent:g,errorComponent:u,forcePlatform:s,queryClientConfig:o,membershipModal:m}){let[f]=useState(()=>new QueryClient(o||{defaultOptions:{queries:{staleTime:6e4,refetchOnWindowFocus:false}}}));return initializeMultiChain({projectId:e,metadata:i}),jsx(QueryClientProvider,{client:f,children:jsx(MultiChainProvider,{tonManifestUrl:t,children:jsx(D,{loadingComponent:g,errorComponent:u,forcePlatform:s,membershipModal:m,children:r})})})}export{n as PlatformId,D as PlatformProvider,le as TurtleBasicProvider,x as useLemonAdapter,re as usePlatform,I as useTurtleWebAdapter};//# sourceMappingURL=index.js.map
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/platform/core/types.ts","../src/platform/core/detector.ts","../src/platform/core/errors.ts","../src/platform/adapters/useTurtleWebAdapter.ts","../src/platform/adapters/useLemonAdapter.ts","../src/platform/core/PlatformProvider.tsx","../src/TurtleBasicProvider.tsx"],"names":["PlatformId","cachedDetectionResult","CACHE_KEY","loadCachedDetection","cached","error","saveCachedDetection","result","detectFromSubdomain","hostname","detectPlatform","forceRedetect","sessionCached","cacheAndReturn","subdomainPlatform","UNIMPLEMENTED_ERRORS","useTurtleWebAdapter","isActive","account","useMultichainAccount","connect","useMultichainConnect","disconnect","useMultichainDisconnect","signMessage","useMultichainSignMessage","handleMembershipError","useCallback","isMember","isMembershipLoading","refetchMembership","useTurtleMembershipFlow","shouldShowMembershipModal","triggerMembershipFlow","opportunitiesData","isLoadingOpportunities","useOpportunitiesPaginated","isAvailable","authenticate","disconnectWallet","getUser","depositToOpportunity","_params","getCapabilities","getOpportunities","getOpportunity","_opportunityId","useMemo","useLemonAdapter","user","setUser","useState","isWebView","setIsWebView","useEffect","hasReactNativeWebView","_nonce","PlatformContext","createContext","PlatformProvider","children","loadingComponent","errorComponent","forcePlatform","membershipModal","setError","detection","setDetection","activePlatformId","turtleWebAdapter","lemonAdapter","detectionResult","err","adapter","contextValue","retry","jsx","Fragment","jsxs","usePlatform","context","useContext","TurtleBasicProvider","walletConnectProjectId","metadata","tonManifestUrl","queryClientConfig","queryClient","QueryClient","initializeMultiChain","QueryClientProvider","MultiChainProvider"],"mappings":"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","file":"index.js","sourcesContent":["import { Opportunity } from \"@turtleclub/hooks\";\n\nexport const PlatformId = {\n TurtleWeb: 'turtle-web',\n Lemon: 'lemon',\n Worldcoin: 'worldcoin',\n} as const;\n\n/**\n * Platform identifier type\n */\nexport type PlatformId = typeof PlatformId[keyof typeof PlatformId];\n\n/**\n * User information from platform authentication\n */\n//Probably will be changed later.\nexport interface User {\n id: string;\n username?: string;\n email?: string;\n avatar?: string;\n metadata?: Record<string, any>;\n}\n\n/**\n * Result of authentication attempt\n */\nexport interface AuthResult {\n success: boolean;\n user?: User;\n error?: string;\n metadata?: Record<string, any>;\n}\n\n/**\n * Parameters for depositing to an opportunity\n */\n//This will be changed later.\nexport interface DepositParams {\n opportunityAddress: string;\n tokenAddress: string;\n amount: string;\n chainId: number;\n}\n\n/**\n * Result of a transaction attempt\n */\nexport interface TransactionResult {\n success: boolean;\n txHash?: string;\n error?: string;\n metadata?: Record<string, any>;\n}\n\n/**\n * Platform capabilities - what features are available/should be shown\n */\nexport interface PlatformCapabilities {\n canChangeNetwork: boolean;\n canDisconnect: boolean;\n showNetworkSelector: boolean;\n showGasEstimate: boolean;\n showUsername: boolean;\n requiresGasPayment: boolean;\n supportsNotifications: boolean;\n canConnectWallet: boolean;\n}\n\n/**\n * Platform adapter interface - implemented by each platform's hook\n * Returned by platform-specific adapter hooks (useTurtleWebAdapter, useLemonAdapter, etc.)\n */\nexport interface PlatformAdapter {\n readonly platformId: PlatformId;\n readonly platformName: string;\n isAvailable(): boolean;\n authenticate(nonce?: string): Promise<AuthResult>;\n disconnect(): Promise<void>;\n getUser(): User | null;\n depositToOpportunity(params: DepositParams): Promise<TransactionResult>;\n getOpportunities(): Promise<Opportunity[]>;\n getOpportunity(opportunityId: string): Promise<Opportunity>;\n getCapabilities(): PlatformCapabilities;\n\n // Reactive loading states - available when adapter is a hook\n readonly isLoadingOpportunities?: boolean;\n readonly isLoadingUser?: boolean;\n\n // Reactive data - available when adapter is a hook\n readonly opportunities?: Opportunity[];\n\n // Membership flow - available when adapter requires membership verification\n readonly shouldShowMembershipModal?: boolean;\n readonly triggerMembershipFlow?: () => Promise<void>;\n}\n\n/**\n * Result of platform detection\n */\nexport interface DetectionResult {\n platformId: PlatformId;\n detectionMethod: 'subdomain' | 'sdk' | 'forced' | 'default';\n isValidated: boolean;\n warnings?: string[];\n}\n","import { PlatformId } from './types';\nimport type { DetectionResult } from './types';\n\n// Cached detection result (singleton pattern)\nlet cachedDetectionResult: DetectionResult | null = null;\n\n// SessionStorage key for caching\nconst CACHE_KEY = 'turtle-platform-detection';\n\n/**\n * Load cached detection result from sessionStorage\n */\nfunction loadCachedDetection(): DetectionResult | null {\n if (typeof window === 'undefined' || typeof sessionStorage === 'undefined') {\n return null;\n }\n\n try {\n const cached = sessionStorage.getItem(CACHE_KEY);\n if (cached) {\n return JSON.parse(cached) as DetectionResult;\n }\n } catch (error) {\n console.warn('[Platform Detection] Failed to load cached detection:', error);\n }\n\n return null;\n}\n\n/**\n * Save detection result to sessionStorage\n */\nfunction saveCachedDetection(result: DetectionResult): void {\n if (typeof window === 'undefined' || typeof sessionStorage === 'undefined') {\n return;\n }\n\n try {\n sessionStorage.setItem(CACHE_KEY, JSON.stringify(result));\n } catch (error) {\n console.warn('[Platform Detection] Failed to save cached detection:', error);\n }\n}\n\n\n/**\n * Detect platform from subdomain\n */\nfunction detectFromSubdomain(): typeof PlatformId[keyof typeof PlatformId] | null {\n if (typeof window === 'undefined') return null;\n\n const hostname = window.location.hostname;\n\n // Check for platform-specific subdomains\n if (hostname.includes('worldcoin.')) {\n return PlatformId.Worldcoin;\n }\n if (hostname.includes('lemon.')) {\n return PlatformId.Lemon;\n }\n\n return null;\n}\n\n\n/**\n * Main platform detection function\n * Detects platform based on subdomain\n * @param forceRedetect - Force re-detection even if cached result exists\n */\nexport function detectPlatform(forceRedetect = false): DetectionResult {\n // Return cached result if available and not forcing re-detection\n if (!forceRedetect) {\n // Check in-memory cache first (fastest)\n if (cachedDetectionResult) {\n return cachedDetectionResult;\n }\n\n // Check sessionStorage cache\n const sessionCached = loadCachedDetection();\n if (sessionCached) {\n cachedDetectionResult = sessionCached;\n return sessionCached;\n }\n }\n\n const cacheAndReturn = (result: DetectionResult): DetectionResult => {\n cachedDetectionResult = result;\n saveCachedDetection(result);\n return result;\n };\n\n // Priority 1: Subdomain detection\n const subdomainPlatform = detectFromSubdomain();\n if (subdomainPlatform) {\n return cacheAndReturn({\n platformId: subdomainPlatform,\n detectionMethod: 'subdomain',\n isValidated: true,\n });\n }\n\n // Priority 2: Default to turtle-web\n return cacheAndReturn({\n platformId: PlatformId.TurtleWeb,\n detectionMethod: 'default',\n isValidated: true,\n });\n}\n","import type { TransactionResult } from './types';\n\n/**\n * Standard error responses for unimplemented features\n */\nexport const UNIMPLEMENTED_ERRORS = {\n deposit: (): TransactionResult => ({\n success: false,\n error: 'Deposit not implemented yet',\n }),\n\n getOpportunity: (): Promise<never> => {\n return Promise.reject(new Error('getOpportunity not implemented yet'));\n },\n} as const;\n","import { useCallback, useMemo } from 'react';\nimport {\n useMultichainAccount,\n useMultichainConnect,\n useMultichainDisconnect,\n useMultichainSignMessage\n} from '@turtleclub/multichain';\nimport { Opportunity, useOpportunitiesPaginated, useTurtleMembershipFlow } from '@turtleclub/hooks';\nimport { PlatformId } from '../core/types';\nimport type {\n PlatformAdapter,\n User,\n AuthResult,\n DepositParams,\n TransactionResult,\n PlatformCapabilities,\n} from '../core/types';\nimport { UNIMPLEMENTED_ERRORS } from '../core/errors';\n\n/**\n * Turtle Web Adapter Hook - for standard web browsers\n * Uses multichain wallet abstraction with EVM support\n *\n * This is a hook-based adapter that works reactively with React state.\n * Methods always have access to the latest wallet state through React hooks.\n * Automatically handles membership authentication when wallet connects.\n *\n * @param isActive - Whether this adapter is the currently active platform (used to conditionally enable queries)\n */\nexport function useTurtleWebAdapter(isActive: boolean): PlatformAdapter {\n const account = useMultichainAccount();\n const { connect } = useMultichainConnect();\n const { disconnect } = useMultichainDisconnect();\n const { signMessage } = useMultichainSignMessage();\n\n const handleMembershipError = useCallback(\n async (error: { type: 'signature_rejected' | 'membership_failed'; message: string }) => {\n console.error(\n `[useTurtleWebAdapter] Membership error (${error.type}): ${error.message}`\n );\n // Don't auto-disconnect - let the UI handle the error\n throw error;\n },\n []\n );\n\n // Membership flow - disabled auto-trigger, will be triggered manually via modal\n const { isMember, isLoading: isMembershipLoading, refetch: refetchMembership } = useTurtleMembershipFlow({\n address: account.address,\n walletEcosystem: \"evm\",\n signMessage,\n chainId: \"1\",\n enabled: false, // Disabled - will trigger manually from modal\n onError: handleMembershipError,\n });\n\n // Show membership modal when: connected + not a member (keep open during loading)\n const shouldShowMembershipModal =\n account.isConnected &&\n !!account.address &&\n isMember === false;\n\n // Trigger membership flow manually (called from modal \"Sign\" button)\n const triggerMembershipFlow = useCallback(async () => {\n await refetchMembership();\n }, [refetchMembership]);\n\n // Fetch featured opportunities for Turtle Web\n const { data: opportunitiesData, isLoading: isLoadingOpportunities } = useOpportunitiesPaginated({\n params: {\n page: 1,\n featured: true,\n limit: 1000,\n },\n enabled: isActive,\n });\n\n\n /**\n * Check if platform is available\n * Web is always available in browser\n */\n const isAvailable = useCallback((): boolean => {\n return typeof window !== 'undefined';\n }, []);\n\n /**\n * Authenticate user via wallet connection (EVM only)\n * Opens wallet connection modal and returns immediately\n * The UI will update reactively when the user connects\n */\n const authenticate = useCallback(\n async (): Promise<AuthResult> => {\n try {\n if (account.isConnected && account.address) {\n return {\n success: true,\n user: {\n id: account.address,\n metadata: {\n chainId: account.chainId,\n status: account.status,\n },\n },\n };\n }\n\n await connect(\"evm\");\n\n return {\n success: true,\n };\n } catch (error) {\n console.error('[useTurtleWebAdapter] Authentication error:', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown authentication error',\n };\n }\n },\n [account.isConnected, account.address, account.chainId, account.status, connect]\n );\n\n /**\n * Disconnect the wallet\n */\n const disconnectWallet = useCallback(async (): Promise<void> => {\n try {\n await disconnect();\n } catch (error) {\n console.error('[useTurtleWebAdapter] Disconnect error:', error);\n throw error;\n }\n }, [disconnect]);\n\n /**\n * Get currently authenticated user\n */\n const getUser = useCallback((): User | null => {\n if (!account.isConnected || !account.address) {\n return null;\n }\n\n return {\n id: account.address,\n metadata: {\n chainId: account.chainId,\n status: account.status,\n ecosystem: account.ecosystem,\n isMember,\n isMembershipLoading,\n },\n };\n }, [account.isConnected, account.address, account.chainId, account.status, account.ecosystem, isMember, isMembershipLoading]);\n\n /**\n * Deposit tokens to an opportunity\n * TODO: Implement\n */\n const depositToOpportunity = useCallback(\n async (_params: DepositParams): Promise<TransactionResult> => {\n return UNIMPLEMENTED_ERRORS.deposit();\n },\n []\n );\n\n /**\n * Get platform capabilities\n */\n const getCapabilities = useCallback((): PlatformCapabilities => {\n return {\n canChangeNetwork: true,\n canDisconnect: true,\n showNetworkSelector: true,\n showGasEstimate: true,\n showUsername: false,\n requiresGasPayment: true,\n supportsNotifications: false,\n canConnectWallet: true,\n };\n }, []);\n\n /**\n * Get all opportunities\n * Returns featured opportunities from the query data\n */\n const getOpportunities = useCallback(async (): Promise<Opportunity[]> => {\n return Promise.resolve(opportunitiesData?.opportunities || []);\n }, [opportunitiesData]);\n\n /**\n * Get a single opportunity\n * TODO: Implement\n */\n const getOpportunity = useCallback(async (_opportunityId: string): Promise<Opportunity> => {\n return UNIMPLEMENTED_ERRORS.getOpportunity();\n }, []);\n\n // Return adapter object\n return useMemo(\n () => ({\n platformId: PlatformId.TurtleWeb,\n platformName: 'Turtle Web',\n isAvailable,\n authenticate,\n disconnect: disconnectWallet,\n getUser,\n depositToOpportunity,\n getCapabilities,\n getOpportunities,\n getOpportunity,\n // Reactive loading states\n isLoadingOpportunities,\n isLoadingUser: isMembershipLoading,\n // Reactive data\n opportunities: opportunitiesData?.opportunities || [],\n // Membership flow\n shouldShowMembershipModal,\n triggerMembershipFlow,\n }),\n [\n isAvailable,\n authenticate,\n disconnectWallet,\n getUser,\n depositToOpportunity,\n getCapabilities,\n getOpportunities,\n getOpportunity,\n isLoadingOpportunities,\n isMembershipLoading,\n opportunitiesData,\n shouldShowMembershipModal,\n triggerMembershipFlow,\n ]\n );\n}\n","import { useCallback, useMemo, useState, useEffect } from 'react';\nimport { Opportunity, useOpportunitiesPaginated } from '@turtleclub/hooks';\nimport { PlatformId } from '../core/types';\nimport type {\n PlatformAdapter,\n User,\n AuthResult,\n DepositParams,\n TransactionResult,\n PlatformCapabilities,\n} from '../core/types';\nimport { UNIMPLEMENTED_ERRORS } from '../core/errors';\n\n/**\n * Lemon Adapter Hook - for Lemon Cash WebView mini apps\n * Communicates with Lemon Cash mobile app via WebView postMessage\n *\n * @see https://lemoncash.mintlify.app/functions/authenticate\n *\n * NOTE: This is a stub implementation for architectural demonstration.\n * Full implementation will be added when integrating with Lemon Cash.\n *\n * @param isActive - Whether this adapter is the currently active platform (used to conditionally enable queries)\n */\nexport function useLemonAdapter(isActive: boolean): PlatformAdapter {\n const [user, setUser] = useState<User | null>(null);\n const [isWebView, setIsWebView] = useState(false);\n\n // Detect if running in Lemon WebView environment\n useEffect(() => {\n if (typeof window !== 'undefined') {\n const hasReactNativeWebView = !!(window as any).ReactNativeWebView;\n setIsWebView(hasReactNativeWebView);\n }\n }, []);\n\n // TODO: Confirm the exact chain slugs with Lemon team\n const { data: opportunitiesData } = useOpportunitiesPaginated({\n params: {\n page: 1,\n receiptTokenChainSlug: 'ethereum,solana,base,polygon,arbitrum,optimism,avalanche',\n limit: 100,\n },\n enabled: isActive,\n });\n\n /**\n * Check if platform is available\n * Lemon is available only in React Native WebView\n */\n const isAvailable = useCallback((): boolean => {\n return isWebView;\n }, [isWebView]);\n\n /**\n * Authenticate user via Lemon SIWE (Sign In With Ethereum)\n * TODO: Implement using Lemon SDK\n * @see https://lemoncash.mintlify.app/functions/authenticate\n */\n const authenticate = useCallback(\n async (_nonce?: string): Promise<AuthResult> => {\n if (!isWebView) {\n return {\n success: false,\n error: 'Not running in Lemon Cash WebView environment',\n };\n }\n\n return {\n success: false,\n error: 'Lemon authentication not implemented yet',\n };\n },\n [isWebView]\n );\n\n /**\n * Disconnect the wallet\n * TODO: Implement\n */\n const disconnect = useCallback(async (): Promise<void> => {\n setUser(null);\n }, []);\n\n /**\n * Get currently authenticated user\n */\n const getUser = useCallback((): User | null => {\n return user;\n }, [user]);\n\n /**\n * Deposit tokens to an opportunity\n * TODO: Implement using Lemon SDK\n * @see https://lemoncash.mintlify.app/functions/deposit\n */\n const depositToOpportunity = useCallback(\n async (_params: DepositParams): Promise<TransactionResult> => {\n if (!isWebView) {\n return {\n success: false,\n error: 'Not running in Lemon Cash WebView environment',\n };\n }\n\n return UNIMPLEMENTED_ERRORS.deposit();\n },\n [isWebView]\n );\n\n /**\n * Get platform capabilities\n */\n const getCapabilities = useCallback((): PlatformCapabilities => {\n return {\n canChangeNetwork: false, // Lemon controls the network\n canDisconnect: false, // Lemon handles session\n showNetworkSelector: false,\n showGasEstimate: false, // Lemon abstracts gas\n showUsername: true, // Lemon provides user info\n requiresGasPayment: false, // Lemon covers gas\n supportsNotifications: true,\n canConnectWallet: true,\n };\n }, []);\n\n /**\n * Get all opportunities\n * Returns opportunities from supported chains\n */\n const getOpportunities = useCallback(async (): Promise<Opportunity[]> => {\n return Promise.resolve(opportunitiesData?.opportunities || []);\n }, [opportunitiesData]);\n\n /**\n * Get a single opportunity\n * TODO: Implement\n */\n const getOpportunity = useCallback(async (_opportunityId: string): Promise<Opportunity> => {\n return UNIMPLEMENTED_ERRORS.getOpportunity();\n }, []);\n\n // Return adapter object\n return useMemo(\n () => ({\n platformId: PlatformId.Lemon,\n platformName: 'Lemon Cash',\n isAvailable,\n authenticate,\n disconnect,\n getUser,\n depositToOpportunity,\n getCapabilities,\n getOpportunities,\n getOpportunity,\n }),\n [\n isAvailable,\n authenticate,\n disconnect,\n getUser,\n depositToOpportunity,\n getCapabilities,\n getOpportunities,\n getOpportunity,\n ]\n );\n}\n","\"use client\";\n\nimport React, { createContext, useContext, useEffect, useState, useMemo } from \"react\";\nimport { PlatformId } from \"./types\";\nimport type { PlatformAdapter, DetectionResult } from \"./types\";\nimport { detectPlatform } from \"./detector\";\nimport { useTurtleWebAdapter } from \"../adapters/useTurtleWebAdapter\";\nimport { useLemonAdapter } from \"../adapters/useLemonAdapter\";\n\ninterface PlatformContextValue {\n /** The platform adapter instance */\n adapter: PlatformAdapter;\n /** Platform detection result */\n detection: DetectionResult;\n /** Whether platform is ready */\n isReady: boolean;\n}\n\nconst PlatformContext = createContext<PlatformContextValue | null>(null);\n\ninterface PlatformProviderProps {\n children: React.ReactNode;\n /** Custom loading component to show while platform is being detected */\n loadingComponent?: React.ReactNode;\n /** Custom error component to show if initialization fails. Receives error and retry function */\n errorComponent?: (error: Error, retry: () => void) => React.ReactNode;\n /** Force a specific platform (useful for testing/debugging) */\n forcePlatform?: PlatformId;\n /** Custom membership verification modal component */\n membershipModal?: React.ReactNode;\n}\n\n/**\n * Platform Provider component\n * Detects the platform and provides the appropriate adapter via React hooks\n *\n * All adapter hooks are called unconditionally (React rules of hooks),\n * but only the detected platform's adapter is exposed through context.\n */\nfunction PlatformProvider({\n children,\n loadingComponent,\n errorComponent,\n forcePlatform,\n membershipModal,\n}: PlatformProviderProps) {\n const [error, setError] = useState<Error | null>(null);\n const [detection, setDetection] = useState<DetectionResult | null>(null);\n\n\n const activePlatformId = detection?.platformId;\n\n const turtleWebAdapter = useTurtleWebAdapter(activePlatformId === PlatformId.TurtleWeb);\n const lemonAdapter = useLemonAdapter(activePlatformId === PlatformId.Lemon);\n\n\n useEffect(() => {\n try {\n let detectionResult: DetectionResult;\n if (forcePlatform) {\n detectionResult = {\n platformId: forcePlatform,\n detectionMethod: \"forced\",\n isValidated: false,\n warnings: [\"Platform was manually forced via forcePlatform prop\"],\n };\n } else {\n detectionResult = detectPlatform();\n }\n setDetection(detectionResult);\n } catch (err) {\n console.error(\"[PlatformProvider] Error during platform detection:\", err);\n setError(err instanceof Error ? err : new Error(\"Unknown error during platform detection\"));\n }\n }, [forcePlatform]);\n\n\n const adapter = useMemo((): PlatformAdapter | null => {\n if (!detection) return null;\n\n switch (detection.platformId) {\n case PlatformId.TurtleWeb:\n return turtleWebAdapter;\n case PlatformId.Lemon:\n return lemonAdapter;\n case PlatformId.Worldcoin:\n // TODO: Implement worldcoin adapter\n console.warn(\"[PlatformProvider] Worldcoin adapter not implemented yet\");\n setError(new Error(\"Worldcoin platform not implemented yet\"));\n return null;\n default:\n console.warn(\"[PlatformProvider] Unknown platform:\", detection.platformId);\n setError(new Error(`Unknown platform: ${detection.platformId}`));\n return null;\n }\n }, [detection, turtleWebAdapter, lemonAdapter]);\n\n\n const contextValue = useMemo(() => {\n if (!detection || !adapter) return null;\n\n return {\n adapter,\n detection,\n isReady: true,\n };\n }, [adapter, detection]);\n\n if (error) {\n const retry = () => {\n setError(null);\n setDetection(null);\n };\n\n if (errorComponent) {\n return <>{errorComponent(error, retry)}</>;\n }\n return (\n <main className=\"flex flex-col items-center justify-center h-screen\">\n <div className=\"text-lg font-bold\">There was an error initializing the platform</div>\n <span className=\"text-sm text-gray-500\">{error.message}</span>\n <span className=\"text-xs text-gray-500\">\n Please provide an Error component to the PlatformProvider.\n </span>\n </main>\n );\n }\n\n\n if (!contextValue) {\n if (loadingComponent) {\n return <>{loadingComponent}</>;\n }\n return (\n <main className=\"flex flex-col items-center justify-center h-screen\">\n <span className=\"text-lg font-bold\">Detecting platform...</span>\n <span className=\"text-xs text-gray-500\">\n Please provide a Loading component to the PlatformProvider.\n </span>\n </main>\n );\n }\n\n return (\n <PlatformContext.Provider value={contextValue}>\n {children}\n {membershipModal}\n </PlatformContext.Provider>\n );\n}\n\nexport { PlatformProvider };\n\n/**\n * Hook to access platform context\n * @throws Error if used outside PlatformProvider\n */\nexport function usePlatform(): PlatformContextValue {\n const context = useContext(PlatformContext);\n\n if (!context) {\n throw new Error(\"usePlatform must be used within a PlatformProvider\");\n }\n\n return context;\n}\n","\"use client\";\n\nimport { useState } from \"react\";\n\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { initializeMultiChain } from \"@turtleclub/multichain\";\n\nimport { PlatformProvider } from \"./platform/core/PlatformProvider\";\nimport type { PlatformId } from \"./platform/core/types\";\n\nimport { MultiChainProvider } from \"@turtleclub/multichain\";\nexport interface TurtleBasicProviderProps {\n children: React.ReactNode;\n walletConnectProjectId: string;\n metadata: {\n name: string;\n description: string;\n url: string;\n icons: string[];\n };\n tonManifestUrl?: string;\n loadingComponent?: React.ReactNode;\n errorComponent?: (error: Error, retry: () => void) => React.ReactNode;\n forcePlatform?: PlatformId; // for testing/debugging\n queryClientConfig?: ConstructorParameters<typeof QueryClient>[0];\n membershipModal?: React.ReactNode;\n}\n\n\nexport function TurtleBasicProvider({\n children,\n walletConnectProjectId,\n metadata,\n tonManifestUrl = \"/tonconnect-manifest.json\",\n loadingComponent,\n errorComponent,\n forcePlatform,\n queryClientConfig,\n membershipModal,\n}: TurtleBasicProviderProps) {\n\n const [queryClient] = useState(\n () =>\n new QueryClient(\n queryClientConfig || {\n defaultOptions: {\n queries: {\n staleTime: 60 * 1000,\n refetchOnWindowFocus: false,\n },\n },\n }\n )\n );\n\n initializeMultiChain({\n projectId: walletConnectProjectId,\n metadata\n });\n \n\n return (\n <QueryClientProvider client={queryClient}>\n <MultiChainProvider tonManifestUrl={tonManifestUrl}>\n <PlatformProvider\n loadingComponent={loadingComponent}\n errorComponent={errorComponent}\n forcePlatform={forcePlatform}\n membershipModal={membershipModal}\n >\n {children}\n </PlatformProvider>\n </MultiChainProvider>\n </QueryClientProvider>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/platform/core/types.ts","../src/platform/core/detector.ts","../src/platform/core/errors.ts","../src/platform/adapters/useTurtleWebAdapter.ts","../src/platform/adapters/useLemonAdapter.ts","../src/platform/core/PlatformProvider.tsx","../src/TurtleBasicProvider.tsx"],"names":["PlatformId","cachedDetectionResult","CACHE_KEY","loadCachedDetection","cached","error","saveCachedDetection","result","detectFromSubdomain","hostname","detectPlatform","forceRedetect","sessionCached","cacheAndReturn","subdomainPlatform","UNIMPLEMENTED_ERRORS","useTurtleWebAdapter","isActive","account","useMultichainAccount","connect","useMultichainConnect","disconnect","useMultichainDisconnect","signMessage","useMultichainSignMessage","handleMembershipError","useCallback","isMember","isMembershipLoading","refetchMembership","useTurtleMembershipFlow","shouldShowMembershipModal","triggerMembershipFlow","opportunitiesData","isLoadingOpportunities","useOpportunitiesPaginated","isAvailable","authenticate","disconnectWallet","getUser","depositToOpportunity","_params","getCapabilities","getOpportunities","getOpportunity","_opportunityId","useMemo","useLemonAdapter","user","setUser","useState","isWebView","setIsWebView","useEffect","hasReactNativeWebView","_nonce","PlatformContext","createContext","PlatformProvider","children","loadingComponent","errorComponent","forcePlatform","membershipModal","setError","detection","setDetection","minLoadingTimeElapsed","setMinLoadingTimeElapsed","timer","activePlatformId","turtleWebAdapter","lemonAdapter","detectionResult","err","adapter","contextValue","retry","jsx","Fragment","jsxs","usePlatform","context","useContext","TurtleBasicProvider","walletConnectProjectId","metadata","tonManifestUrl","queryClientConfig","queryClient","QueryClient","initializeMultiChain","QueryClientProvider","MultiChainProvider"],"mappings":"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","file":"index.js","sourcesContent":["import { Opportunity } from \"@turtleclub/hooks\";\n\nexport const PlatformId = {\n TurtleWeb: 'turtle-web',\n Lemon: 'lemon',\n Worldcoin: 'worldcoin',\n} as const;\n\n/**\n * Platform identifier type\n */\nexport type PlatformId = typeof PlatformId[keyof typeof PlatformId];\n\n/**\n * User information from platform authentication\n */\n//Probably will be changed later.\nexport interface User {\n id: string;\n username?: string;\n email?: string;\n avatar?: string;\n metadata?: Record<string, any>;\n}\n\n/**\n * Result of authentication attempt\n */\nexport interface AuthResult {\n success: boolean;\n user?: User;\n error?: string;\n metadata?: Record<string, any>;\n}\n\n/**\n * Parameters for depositing to an opportunity\n */\n//This will be changed later.\nexport interface DepositParams {\n opportunityAddress: string;\n tokenAddress: string;\n amount: string;\n chainId: number;\n}\n\n/**\n * Result of a transaction attempt\n */\nexport interface TransactionResult {\n success: boolean;\n txHash?: string;\n error?: string;\n metadata?: Record<string, any>;\n}\n\n/**\n * Platform capabilities - what features are available/should be shown\n */\nexport interface PlatformCapabilities {\n canChangeNetwork: boolean;\n canDisconnect: boolean;\n showNetworkSelector: boolean;\n showGasEstimate: boolean;\n showUsername: boolean;\n requiresGasPayment: boolean;\n supportsNotifications: boolean;\n canConnectWallet: boolean;\n}\n\n/**\n * Platform adapter interface - implemented by each platform's hook\n * Returned by platform-specific adapter hooks (useTurtleWebAdapter, useLemonAdapter, etc.)\n */\nexport interface PlatformAdapter {\n readonly platformId: PlatformId;\n readonly platformName: string;\n isAvailable(): boolean;\n authenticate(nonce?: string): Promise<AuthResult>;\n disconnect(): Promise<void>;\n getUser(): User | null;\n depositToOpportunity(params: DepositParams): Promise<TransactionResult>;\n getOpportunities(): Promise<Opportunity[]>;\n getOpportunity(opportunityId: string): Promise<Opportunity>;\n getCapabilities(): PlatformCapabilities;\n\n // Reactive loading states - available when adapter is a hook\n readonly isLoadingOpportunities?: boolean;\n readonly isLoadingUser?: boolean;\n\n // Reactive data - available when adapter is a hook\n readonly opportunities?: Opportunity[];\n\n // Membership flow - available when adapter requires membership verification\n readonly shouldShowMembershipModal?: boolean;\n readonly triggerMembershipFlow?: () => Promise<void>;\n}\n\n/**\n * Result of platform detection\n */\nexport interface DetectionResult {\n platformId: PlatformId;\n detectionMethod: 'subdomain' | 'sdk' | 'forced' | 'default';\n isValidated: boolean;\n warnings?: string[];\n}\n","import { PlatformId } from './types';\nimport type { DetectionResult } from './types';\n\n// Cached detection result (singleton pattern)\nlet cachedDetectionResult: DetectionResult | null = null;\n\n// SessionStorage key for caching\nconst CACHE_KEY = 'turtle-platform-detection';\n\n/**\n * Load cached detection result from sessionStorage\n */\nfunction loadCachedDetection(): DetectionResult | null {\n if (typeof window === 'undefined' || typeof sessionStorage === 'undefined') {\n return null;\n }\n\n try {\n const cached = sessionStorage.getItem(CACHE_KEY);\n if (cached) {\n return JSON.parse(cached) as DetectionResult;\n }\n } catch (error) {\n console.warn('[Platform Detection] Failed to load cached detection:', error);\n }\n\n return null;\n}\n\n/**\n * Save detection result to sessionStorage\n */\nfunction saveCachedDetection(result: DetectionResult): void {\n if (typeof window === 'undefined' || typeof sessionStorage === 'undefined') {\n return;\n }\n\n try {\n sessionStorage.setItem(CACHE_KEY, JSON.stringify(result));\n } catch (error) {\n console.warn('[Platform Detection] Failed to save cached detection:', error);\n }\n}\n\n\n/**\n * Detect platform from subdomain\n */\nfunction detectFromSubdomain(): typeof PlatformId[keyof typeof PlatformId] | null {\n if (typeof window === 'undefined') return null;\n\n const hostname = window.location.hostname;\n\n // Check for platform-specific subdomains\n if (hostname.includes('worldcoin.')) {\n return PlatformId.Worldcoin;\n }\n if (hostname.includes('lemon.')) {\n return PlatformId.Lemon;\n }\n\n return null;\n}\n\n\n/**\n * Main platform detection function\n * Detects platform based on subdomain\n * @param forceRedetect - Force re-detection even if cached result exists\n */\nexport function detectPlatform(forceRedetect = false): DetectionResult {\n // Return cached result if available and not forcing re-detection\n if (!forceRedetect) {\n // Check in-memory cache first (fastest)\n if (cachedDetectionResult) {\n return cachedDetectionResult;\n }\n\n // Check sessionStorage cache\n const sessionCached = loadCachedDetection();\n if (sessionCached) {\n cachedDetectionResult = sessionCached;\n return sessionCached;\n }\n }\n\n const cacheAndReturn = (result: DetectionResult): DetectionResult => {\n cachedDetectionResult = result;\n saveCachedDetection(result);\n return result;\n };\n\n // Priority 1: Subdomain detection\n const subdomainPlatform = detectFromSubdomain();\n if (subdomainPlatform) {\n return cacheAndReturn({\n platformId: subdomainPlatform,\n detectionMethod: 'subdomain',\n isValidated: true,\n });\n }\n\n // Priority 2: Default to turtle-web\n return cacheAndReturn({\n platformId: PlatformId.TurtleWeb,\n detectionMethod: 'default',\n isValidated: true,\n });\n}\n","import type { TransactionResult } from './types';\n\n/**\n * Standard error responses for unimplemented features\n */\nexport const UNIMPLEMENTED_ERRORS = {\n deposit: (): TransactionResult => ({\n success: false,\n error: 'Deposit not implemented yet',\n }),\n\n getOpportunity: (): Promise<never> => {\n return Promise.reject(new Error('getOpportunity not implemented yet'));\n },\n} as const;\n","import { useCallback, useMemo } from 'react';\nimport {\n useMultichainAccount,\n useMultichainConnect,\n useMultichainDisconnect,\n useMultichainSignMessage\n} from '@turtleclub/multichain';\nimport { Opportunity, useOpportunitiesPaginated, useTurtleMembershipFlow } from '@turtleclub/hooks';\nimport { PlatformId } from '../core/types';\nimport type {\n PlatformAdapter,\n User,\n AuthResult,\n DepositParams,\n TransactionResult,\n PlatformCapabilities,\n} from '../core/types';\nimport { UNIMPLEMENTED_ERRORS } from '../core/errors';\n\n/**\n * Turtle Web Adapter Hook - for standard web browsers\n * Uses multichain wallet abstraction with EVM support\n *\n * This is a hook-based adapter that works reactively with React state.\n * Methods always have access to the latest wallet state through React hooks.\n * Automatically handles membership authentication when wallet connects.\n *\n * @param isActive - Whether this adapter is the currently active platform (used to conditionally enable queries)\n */\nexport function useTurtleWebAdapter(isActive: boolean): PlatformAdapter {\n const account = useMultichainAccount();\n const { connect } = useMultichainConnect();\n const { disconnect } = useMultichainDisconnect();\n const { signMessage } = useMultichainSignMessage();\n\n const handleMembershipError = useCallback(\n async (error: { type: 'signature_rejected' | 'membership_failed'; message: string }) => {\n console.error(\n `[useTurtleWebAdapter] Membership error (${error.type}): ${error.message}`\n );\n // Don't auto-disconnect - let the UI handle the error\n throw error;\n },\n []\n );\n\n // Membership flow - disabled auto-trigger, will be triggered manually via modal\n const { isMember, isLoading: isMembershipLoading, refetch: refetchMembership } = useTurtleMembershipFlow({\n address: account.address,\n walletEcosystem: \"evm\",\n signMessage,\n chainId: \"1\",\n enabled: false, // Disabled - will trigger manually from modal\n onError: handleMembershipError,\n });\n\n // Show membership modal when: connected + not a member (keep open during loading)\n const shouldShowMembershipModal =\n account.isConnected &&\n !!account.address &&\n isMember === false;\n\n // Trigger membership flow manually (called from modal \"Sign\" button)\n const triggerMembershipFlow = useCallback(async () => {\n await refetchMembership();\n }, [refetchMembership]);\n\n // Fetch featured opportunities for Turtle Web\n const { data: opportunitiesData, isLoading: isLoadingOpportunities } = useOpportunitiesPaginated({\n params: {\n page: 1,\n featured: true,\n limit: 1000,\n },\n enabled: isActive,\n });\n\n\n /**\n * Check if platform is available\n * Web is always available in browser\n */\n const isAvailable = useCallback((): boolean => {\n return typeof window !== 'undefined';\n }, []);\n\n /**\n * Authenticate user via wallet connection (EVM only)\n * Opens wallet connection modal and returns immediately\n * The UI will update reactively when the user connects\n */\n const authenticate = useCallback(\n async (): Promise<AuthResult> => {\n try {\n if (account.isConnected && account.address) {\n return {\n success: true,\n user: {\n id: account.address,\n metadata: {\n chainId: account.chainId,\n status: account.status,\n },\n },\n };\n }\n\n await connect(\"evm\");\n\n return {\n success: true,\n };\n } catch (error) {\n console.error('[useTurtleWebAdapter] Authentication error:', error);\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown authentication error',\n };\n }\n },\n [account.isConnected, account.address, account.chainId, account.status, connect]\n );\n\n /**\n * Disconnect the wallet\n */\n const disconnectWallet = useCallback(async (): Promise<void> => {\n try {\n await disconnect();\n } catch (error) {\n console.error('[useTurtleWebAdapter] Disconnect error:', error);\n throw error;\n }\n }, [disconnect]);\n\n /**\n * Get currently authenticated user\n */\n const getUser = useCallback((): User | null => {\n if (!account.isConnected || !account.address) {\n return null;\n }\n\n return {\n id: account.address,\n metadata: {\n chainId: account.chainId,\n status: account.status,\n ecosystem: account.ecosystem,\n isMember,\n isMembershipLoading,\n },\n };\n }, [account.isConnected, account.address, account.chainId, account.status, account.ecosystem, isMember, isMembershipLoading]);\n\n /**\n * Deposit tokens to an opportunity\n * TODO: Implement\n */\n const depositToOpportunity = useCallback(\n async (_params: DepositParams): Promise<TransactionResult> => {\n return UNIMPLEMENTED_ERRORS.deposit();\n },\n []\n );\n\n /**\n * Get platform capabilities\n */\n const getCapabilities = useCallback((): PlatformCapabilities => {\n return {\n canChangeNetwork: true,\n canDisconnect: true,\n showNetworkSelector: true,\n showGasEstimate: true,\n showUsername: false,\n requiresGasPayment: true,\n supportsNotifications: false,\n canConnectWallet: true,\n };\n }, []);\n\n /**\n * Get all opportunities\n * Returns featured opportunities from the query data\n */\n const getOpportunities = useCallback(async (): Promise<Opportunity[]> => {\n return Promise.resolve(opportunitiesData?.opportunities || []);\n }, [opportunitiesData]);\n\n /**\n * Get a single opportunity\n * TODO: Implement\n */\n const getOpportunity = useCallback(async (_opportunityId: string): Promise<Opportunity> => {\n return UNIMPLEMENTED_ERRORS.getOpportunity();\n }, []);\n\n // Return adapter object\n return useMemo(\n () => ({\n platformId: PlatformId.TurtleWeb,\n platformName: 'Turtle Web',\n isAvailable,\n authenticate,\n disconnect: disconnectWallet,\n getUser,\n depositToOpportunity,\n getCapabilities,\n getOpportunities,\n getOpportunity,\n // Reactive loading states\n isLoadingOpportunities,\n isLoadingUser: isMembershipLoading,\n // Reactive data\n opportunities: opportunitiesData?.opportunities || [],\n // Membership flow\n shouldShowMembershipModal,\n triggerMembershipFlow,\n }),\n [\n isAvailable,\n authenticate,\n disconnectWallet,\n getUser,\n depositToOpportunity,\n getCapabilities,\n getOpportunities,\n getOpportunity,\n isLoadingOpportunities,\n isMembershipLoading,\n opportunitiesData,\n shouldShowMembershipModal,\n triggerMembershipFlow,\n ]\n );\n}\n","import { useCallback, useMemo, useState, useEffect } from 'react';\nimport { Opportunity, useOpportunitiesPaginated } from '@turtleclub/hooks';\nimport { PlatformId } from '../core/types';\nimport type {\n PlatformAdapter,\n User,\n AuthResult,\n DepositParams,\n TransactionResult,\n PlatformCapabilities,\n} from '../core/types';\nimport { UNIMPLEMENTED_ERRORS } from '../core/errors';\n\n/**\n * Lemon Adapter Hook - for Lemon Cash WebView mini apps\n * Communicates with Lemon Cash mobile app via WebView postMessage\n *\n * @see https://lemoncash.mintlify.app/functions/authenticate\n *\n * NOTE: This is a stub implementation for architectural demonstration.\n * Full implementation will be added when integrating with Lemon Cash.\n *\n * @param isActive - Whether this adapter is the currently active platform (used to conditionally enable queries)\n */\nexport function useLemonAdapter(isActive: boolean): PlatformAdapter {\n const [user, setUser] = useState<User | null>(null);\n const [isWebView, setIsWebView] = useState(false);\n\n // Detect if running in Lemon WebView environment\n useEffect(() => {\n if (typeof window !== 'undefined') {\n const hasReactNativeWebView = !!(window as any).ReactNativeWebView;\n setIsWebView(hasReactNativeWebView);\n }\n }, []);\n\n // TODO: Confirm the exact chain slugs with Lemon team\n const { data: opportunitiesData } = useOpportunitiesPaginated({\n params: {\n page: 1,\n receiptTokenChainSlug: 'ethereum,solana,base,polygon,arbitrum,optimism,avalanche',\n limit: 100,\n },\n enabled: isActive,\n });\n\n /**\n * Check if platform is available\n * Lemon is available only in React Native WebView\n */\n const isAvailable = useCallback((): boolean => {\n return isWebView;\n }, [isWebView]);\n\n /**\n * Authenticate user via Lemon SIWE (Sign In With Ethereum)\n * TODO: Implement using Lemon SDK\n * @see https://lemoncash.mintlify.app/functions/authenticate\n */\n const authenticate = useCallback(\n async (_nonce?: string): Promise<AuthResult> => {\n if (!isWebView) {\n return {\n success: false,\n error: 'Not running in Lemon Cash WebView environment',\n };\n }\n\n return {\n success: false,\n error: 'Lemon authentication not implemented yet',\n };\n },\n [isWebView]\n );\n\n /**\n * Disconnect the wallet\n * TODO: Implement\n */\n const disconnect = useCallback(async (): Promise<void> => {\n setUser(null);\n }, []);\n\n /**\n * Get currently authenticated user\n */\n const getUser = useCallback((): User | null => {\n return user;\n }, [user]);\n\n /**\n * Deposit tokens to an opportunity\n * TODO: Implement using Lemon SDK\n * @see https://lemoncash.mintlify.app/functions/deposit\n */\n const depositToOpportunity = useCallback(\n async (_params: DepositParams): Promise<TransactionResult> => {\n if (!isWebView) {\n return {\n success: false,\n error: 'Not running in Lemon Cash WebView environment',\n };\n }\n\n return UNIMPLEMENTED_ERRORS.deposit();\n },\n [isWebView]\n );\n\n /**\n * Get platform capabilities\n */\n const getCapabilities = useCallback((): PlatformCapabilities => {\n return {\n canChangeNetwork: false, // Lemon controls the network\n canDisconnect: false, // Lemon handles session\n showNetworkSelector: false,\n showGasEstimate: false, // Lemon abstracts gas\n showUsername: true, // Lemon provides user info\n requiresGasPayment: false, // Lemon covers gas\n supportsNotifications: true,\n canConnectWallet: true,\n };\n }, []);\n\n /**\n * Get all opportunities\n * Returns opportunities from supported chains\n */\n const getOpportunities = useCallback(async (): Promise<Opportunity[]> => {\n return Promise.resolve(opportunitiesData?.opportunities || []);\n }, [opportunitiesData]);\n\n /**\n * Get a single opportunity\n * TODO: Implement\n */\n const getOpportunity = useCallback(async (_opportunityId: string): Promise<Opportunity> => {\n return UNIMPLEMENTED_ERRORS.getOpportunity();\n }, []);\n\n // Return adapter object\n return useMemo(\n () => ({\n platformId: PlatformId.Lemon,\n platformName: 'Lemon Cash',\n isAvailable,\n authenticate,\n disconnect,\n getUser,\n depositToOpportunity,\n getCapabilities,\n getOpportunities,\n getOpportunity,\n }),\n [\n isAvailable,\n authenticate,\n disconnect,\n getUser,\n depositToOpportunity,\n getCapabilities,\n getOpportunities,\n getOpportunity,\n ]\n );\n}\n","\"use client\";\n\nimport React, { createContext, useContext, useEffect, useState, useMemo } from \"react\";\nimport { PlatformId } from \"./types\";\nimport type { PlatformAdapter, DetectionResult } from \"./types\";\nimport { detectPlatform } from \"./detector\";\nimport { useTurtleWebAdapter } from \"../adapters/useTurtleWebAdapter\";\nimport { useLemonAdapter } from \"../adapters/useLemonAdapter\";\n\ninterface PlatformContextValue {\n /** The platform adapter instance */\n adapter: PlatformAdapter;\n /** Platform detection result */\n detection: DetectionResult;\n /** Whether platform is ready */\n isReady: boolean;\n}\n\nconst PlatformContext = createContext<PlatformContextValue | null>(null);\n\ninterface PlatformProviderProps {\n children: React.ReactNode;\n /** Custom loading component to show while platform is being detected */\n loadingComponent?: React.ReactNode;\n /** Custom error component to show if initialization fails. Receives error and retry function */\n errorComponent?: (error: Error, retry: () => void) => React.ReactNode;\n /** Force a specific platform (useful for testing/debugging) */\n forcePlatform?: PlatformId;\n /** Custom membership verification modal component */\n membershipModal?: React.ReactNode;\n}\n\n/**\n * Platform Provider component\n * Detects the platform and provides the appropriate adapter via React hooks\n *\n * All adapter hooks are called unconditionally (React rules of hooks),\n * but only the detected platform's adapter is exposed through context.\n */\nfunction PlatformProvider({\n children,\n loadingComponent,\n errorComponent,\n forcePlatform,\n membershipModal,\n}: PlatformProviderProps) {\n const [error, setError] = useState<Error | null>(null);\n const [detection, setDetection] = useState<DetectionResult | null>(null);\n const [minLoadingTimeElapsed, setMinLoadingTimeElapsed] = useState(false);\n\n // Ensure loading screen shows for at least 1.5 seconds\n useEffect(() => {\n const timer = setTimeout(() => {\n setMinLoadingTimeElapsed(true);\n }, 2000);\n\n return () => clearTimeout(timer);\n }, []);\n\n const activePlatformId = detection?.platformId;\n\n const turtleWebAdapter = useTurtleWebAdapter(activePlatformId === PlatformId.TurtleWeb);\n const lemonAdapter = useLemonAdapter(activePlatformId === PlatformId.Lemon);\n\n\n useEffect(() => {\n try {\n let detectionResult: DetectionResult;\n if (forcePlatform) {\n detectionResult = {\n platformId: forcePlatform,\n detectionMethod: \"forced\",\n isValidated: false,\n warnings: [\"Platform was manually forced via forcePlatform prop\"],\n };\n } else {\n detectionResult = detectPlatform();\n }\n setDetection(detectionResult);\n } catch (err) {\n console.error(\"[PlatformProvider] Error during platform detection:\", err);\n setError(err instanceof Error ? err : new Error(\"Unknown error during platform detection\"));\n }\n }, [forcePlatform]);\n\n\n const adapter = useMemo((): PlatformAdapter | null => {\n if (!detection) return null;\n\n switch (detection.platformId) {\n case PlatformId.TurtleWeb:\n return turtleWebAdapter;\n case PlatformId.Lemon:\n return lemonAdapter;\n case PlatformId.Worldcoin:\n // TODO: Implement worldcoin adapter\n console.warn(\"[PlatformProvider] Worldcoin adapter not implemented yet\");\n setError(new Error(\"Worldcoin platform not implemented yet\"));\n return null;\n default:\n console.warn(\"[PlatformProvider] Unknown platform:\", detection.platformId);\n setError(new Error(`Unknown platform: ${detection.platformId}`));\n return null;\n }\n }, [detection, turtleWebAdapter, lemonAdapter]);\n\n\n const contextValue = useMemo(() => {\n if (!detection || !adapter) return null;\n\n return {\n adapter,\n detection,\n isReady: true,\n };\n }, [adapter, detection]);\n\n if (error) {\n const retry = () => {\n setError(null);\n setDetection(null);\n };\n\n if (errorComponent) {\n return <>{errorComponent(error, retry)}</>;\n }\n return (\n <main className=\"flex flex-col items-center justify-center h-screen\">\n <div className=\"text-lg font-bold\">There was an error initializing the platform</div>\n <span className=\"text-sm text-gray-500\">{error.message}</span>\n <span className=\"text-xs text-gray-500\">\n Please provide an Error component to the PlatformProvider.\n </span>\n </main>\n );\n }\n\n // Show loading until both context is ready AND minimum loading time has elapsed\n if (!contextValue || !minLoadingTimeElapsed) {\n if (loadingComponent) {\n return <>{loadingComponent}</>;\n }\n return (\n <main className=\"flex flex-col items-center justify-center h-screen\">\n <span className=\"text-lg font-bold\">Detecting platform...</span>\n <span className=\"text-xs text-gray-500\">\n Please provide a Loading component to the PlatformProvider.\n </span>\n </main>\n );\n }\n\n return (\n <PlatformContext.Provider value={contextValue}>\n {children}\n {membershipModal}\n </PlatformContext.Provider>\n );\n}\n\nexport { PlatformProvider };\n\n/**\n * Hook to access platform context\n * @throws Error if used outside PlatformProvider\n */\nexport function usePlatform(): PlatformContextValue {\n const context = useContext(PlatformContext);\n\n if (!context) {\n throw new Error(\"usePlatform must be used within a PlatformProvider\");\n }\n\n return context;\n}\n","\"use client\";\n\nimport { useState } from \"react\";\n\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { initializeMultiChain } from \"@turtleclub/multichain\";\n\nimport { PlatformProvider } from \"./platform/core/PlatformProvider\";\nimport type { PlatformId } from \"./platform/core/types\";\n\nimport { MultiChainProvider } from \"@turtleclub/multichain\";\nexport interface TurtleBasicProviderProps {\n children: React.ReactNode;\n walletConnectProjectId: string;\n metadata: {\n name: string;\n description: string;\n url: string;\n icons: string[];\n };\n tonManifestUrl?: string;\n loadingComponent?: React.ReactNode;\n errorComponent?: (error: Error, retry: () => void) => React.ReactNode;\n forcePlatform?: PlatformId; // for testing/debugging\n queryClientConfig?: ConstructorParameters<typeof QueryClient>[0];\n membershipModal?: React.ReactNode;\n}\n\n\nexport function TurtleBasicProvider({\n children,\n walletConnectProjectId,\n metadata,\n tonManifestUrl = \"/tonconnect-manifest.json\",\n loadingComponent,\n errorComponent,\n forcePlatform,\n queryClientConfig,\n membershipModal,\n}: TurtleBasicProviderProps) {\n\n const [queryClient] = useState(\n () =>\n new QueryClient(\n queryClientConfig || {\n defaultOptions: {\n queries: {\n staleTime: 60 * 1000,\n refetchOnWindowFocus: false,\n },\n },\n }\n )\n );\n\n initializeMultiChain({\n projectId: walletConnectProjectId,\n metadata\n });\n \n\n return (\n <QueryClientProvider client={queryClient}>\n <MultiChainProvider tonManifestUrl={tonManifestUrl}>\n <PlatformProvider\n loadingComponent={loadingComponent}\n errorComponent={errorComponent}\n forcePlatform={forcePlatform}\n membershipModal={membershipModal}\n >\n {children}\n </PlatformProvider>\n </MultiChainProvider>\n </QueryClientProvider>\n );\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@turtleclub/turtle-basic",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.19",
|
|
4
4
|
"description": "Multi-platform mini-app adapter system for Turtle Basic",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@turtleclub/hooks": "0.5.0-beta.44",
|
|
36
36
|
"@turtleclub/multichain": "0.5.0-beta.1",
|
|
37
|
-
"@turtleclub/opportunities": "0.1.0-beta.
|
|
38
|
-
"@turtleclub/ui": "0.7.0-beta.
|
|
37
|
+
"@turtleclub/opportunities": "0.1.0-beta.63",
|
|
38
|
+
"@turtleclub/ui": "0.7.0-beta.24",
|
|
39
39
|
"@turtleclub/utils": "0.4.0-beta.0"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
@@ -58,5 +58,5 @@
|
|
|
58
58
|
"publishConfig": {
|
|
59
59
|
"access": "public"
|
|
60
60
|
},
|
|
61
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "71a3c5dac4d7ea659a6c0a2098f35386450958b8"
|
|
62
62
|
}
|