@turtleclub/turtle-basic 0.1.0-beta.13 → 0.1.0-beta.15

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 CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var react=require('react'),jsxRuntime=require('react/jsx-runtime');var R=Object.defineProperty;var b=(e,t,o)=>t in e?R(e,t,{enumerable:true,configurable:true,writable:true,value:o}):e[t]=o;var l=(e,t,o)=>b(e,typeof t!="symbol"?t+"":t,o);var s=null,m="turtle-platform-detection";function D(){if(typeof window>"u"||typeof sessionStorage>"u")return null;try{let e=sessionStorage.getItem(m);if(e)return JSON.parse(e)}catch(e){console.warn("[Platform Detection] Failed to load cached detection:",e);}return null}function E(e){if(!(typeof window>"u"||typeof sessionStorage>"u"))try{sessionStorage.setItem(m,JSON.stringify(e));}catch(t){console.warn("[Platform Detection] Failed to save cached detection:",t);}}function N(){if(typeof window>"u")return null;let e=window.location.hostname;return e.includes("worldcoin.")?"worldcoin":e.includes("lemon.")?"lemon":null}function f(e=false){if(!e){if(s)return s;let r=D();if(r)return s=r,r}let t=r=>(s=r,E(r),r),o=N();return t(o?{platformId:o,detectionMethod:"subdomain",isValidated:true}:{platformId:"turtle-web",detectionMethod:"default",isValidated:true})}var i=class{constructor(){l(this,"platformId","turtle-web");l(this,"platformName","Turtle Web");l(this,"user",null);}isAvailable(){return typeof window<"u"}async authenticate(t){return console.log("[TurtleWebAdapter] authenticate() called - NOT IMPLEMENTED",{nonce:t}),{success:false,error:"Authentication not implemented yet"}}getUser(){return this.user}async depositToOpportunity(t){return console.log("[TurtleWebAdapter] depositToOpportunity() called - NOT IMPLEMENTED",t),{success:false,error:"Deposit not implemented yet"}}getCapabilities(){return {canChangeNetwork:true,canDisconnect:true,showNetworkSelector:true,showGasEstimate:true,showUsername:false,requiresGasPayment:true,supportsNotifications:false}}getOpportunities(){return console.log("[TurtleWebAdapter] getOpportunities() called - NOT IMPLEMENTED"),Promise.resolve([])}getOpportunity(t){return console.log("[TurtleWebAdapter] getOpportunity() called - NOT IMPLEMENTED",{opportunityId:t}),Promise.reject(new Error("getOpportunity not implemented yet"))}};function P(e){switch(e){case "turtle-web":return new i;case "lemon":return console.warn("[createAdapter] Lemon adapter not implemented yet, falling back to turtle-web"),new i;case "worldcoin":return console.warn("[createAdapter] WorldCoin adapter not implemented yet, falling back to turtle-web"),new i;default:return console.warn("[createAdapter] Unknown platform, falling back to turtle-web"),new i}}var g=react.createContext(null);function M({children:e,loadingComponent:t,errorComponent:o,forcePlatform:r}){let[d,x]=react.useState(null),[c,p]=react.useState(null),u=react.useCallback(()=>{try{p(null);let n;r?n={platformId:r,detectionMethod:"forced",isValidated:!1,warnings:["Platform was manually forced via forcePlatform prop"]}:n=f();let A=P(n.platformId);x({adapter:A,detection:n,isReady:!0});}catch(n){console.error("[PlatformProvider] Error during platform initialization:",n),p(n instanceof Error?n:new Error("Unknown error during platform initialization"));}},[r]);return react.useEffect(()=>{u();},[u]),c?o?jsxRuntime.jsx(jsxRuntime.Fragment,{children:o(c,u)}):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:c.message}),jsxRuntime.jsx("span",{className:"text-xs text-gray-500",children:"Please provide an Error component to the PlatformProvider."})]}):d?jsxRuntime.jsx(g.Provider,{value:d,children:e}):t?jsxRuntime.jsx(jsxRuntime.Fragment,{children:t}):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."})]})}function O(){let e=react.useContext(g);if(!e)throw new Error("usePlatform must be used within a PlatformProvider");return e}exports.PlatformProvider=M;exports.usePlatform=O;//# sourceMappingURL=index.cjs.map
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 a={TurtleWeb:"turtle-web",Lemon:"lemon",Worldcoin:"worldcoin"};var R=null,W="turtle-platform-detection";function F(){if(typeof window>"u"||typeof sessionStorage>"u")return null;try{let r=sessionStorage.getItem(W);if(r)return JSON.parse(r)}catch(r){console.warn("[Platform Detection] Failed to load cached detection:",r);}return null}function q(r){if(!(typeof window>"u"||typeof sessionStorage>"u"))try{sessionStorage.setItem(W,JSON.stringify(r));}catch(e){console.warn("[Platform Detection] Failed to save cached detection:",e);}}function B(){if(typeof window>"u")return null;let r=window.location.hostname;return r.includes("worldcoin.")?a.Worldcoin:r.includes("lemon.")?a.Lemon:null}function U(r=false){if(!r){if(R)return R;let t=F();if(t)return R=t,t}let e=t=>(R=t,q(t),t),i=B();return e(i?{platformId:i,detectionMethod:"subdomain",isValidated:true}:{platformId:a.TurtleWeb,detectionMethod:"default",isValidated:true})}var w={deposit:()=>({success:false,error:"Deposit not implemented yet"}),getOpportunity:()=>Promise.reject(new Error("getOpportunity not implemented yet"))};function C(r){let e=multichain.useMultichainAccount(),{connect:i}=multichain.useMultichainConnect(),{disconnect:t}=multichain.useMultichainDisconnect(),{signMessage:g}=multichain.useMultichainSignMessage(),c=react.useCallback(async l=>{throw console.error(`[useTurtleWebAdapter] Membership error (${l.type}): ${l.message}`),l},[]),{isMember:s,isLoading:o,refetch:u}=hooks.useTurtleMembershipFlow({address:e.address,walletEcosystem:"evm",signMessage:g,chainId:"1",enabled:false,onError:c}),m=e.isConnected&&!!e.address&&s===false,P=react.useCallback(async()=>{await u();},[u]),{data:d,isLoading:f}=hooks.useOpportunitiesPaginated({params:{page:1,featured:true,limit:1e3},enabled:r}),y=react.useCallback(()=>typeof window<"u",[]),n=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]),M=react.useCallback(async()=>{try{await t();}catch(l){throw console.error("[useTurtleWebAdapter] Disconnect error:",l),l}},[t]),N=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]),T=react.useCallback(async l=>w.deposit(),[]),A=react.useCallback(()=>({canChangeNetwork:true,canDisconnect:true,showNetworkSelector:true,showGasEstimate:true,showUsername:false,requiresGasPayment:true,supportsNotifications:false,canConnectWallet:true}),[]),E=react.useCallback(async()=>Promise.resolve(d?.opportunities||[]),[d]),O=react.useCallback(async l=>w.getOpportunity(),[]);return react.useMemo(()=>({platformId:a.TurtleWeb,platformName:"Turtle Web",isAvailable:y,authenticate:n,disconnect:M,getUser:N,depositToOpportunity:T,getCapabilities:A,getOpportunities:E,getOpportunity:O,isLoadingOpportunities:f,isLoadingUser:o,opportunities:d?.opportunities||[],shouldShowMembershipModal:m,triggerMembershipFlow:P}),[y,n,M,N,T,A,E,O,f,o,d,m,P])}function v(r){let[e,i]=react.useState(null),[t,g]=react.useState(false);react.useEffect(()=>{if(typeof window<"u"){let n=!!window.ReactNativeWebView;g(n);}},[]);let{data:c}=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 n=>t?{success:false,error:"Lemon authentication not implemented yet"}:{success:false,error:"Not running in Lemon Cash WebView environment"},[t]),u=react.useCallback(async()=>{i(null);},[]),m=react.useCallback(()=>e,[e]),P=react.useCallback(async n=>t?w.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}),[]),f=react.useCallback(async()=>Promise.resolve(c?.opportunities||[]),[c]),y=react.useCallback(async n=>w.getOpportunity(),[]);return react.useMemo(()=>({platformId:a.Lemon,platformName:"Lemon Cash",isAvailable:s,authenticate:o,disconnect:u,getUser:m,depositToOpportunity:P,getCapabilities:d,getOpportunities:f,getOpportunity:y}),[s,o,u,m,P,d,f,y])}var _=react.createContext(null);function x({children:r,loadingComponent:e,errorComponent:i,forcePlatform:t,membershipModal:g}){let[c,s]=react.useState(null),[o,u]=react.useState(null),m=o?.platformId,P=C(m===a.TurtleWeb),d=v(m===a.Lemon);react.useEffect(()=>{try{let n;t?n={platformId:t,detectionMethod:"forced",isValidated:!1,warnings:["Platform was manually forced via forcePlatform prop"]}:n=U(),u(n);}catch(n){console.error("[PlatformProvider] Error during platform detection:",n),s(n instanceof Error?n:new Error("Unknown error during platform detection"));}},[t]);let f=react.useMemo(()=>{if(!o)return null;switch(o.platformId){case a.TurtleWeb:return P;case a.Lemon:return d;case a.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,d]),y=react.useMemo(()=>!o||!f?null:{adapter:f,detection:o,isReady:true},[f,o]);if(c){let n=()=>{s(null),u(null);};return i?jsxRuntime.jsx(jsxRuntime.Fragment,{children:i(c,n)}):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:c.message}),jsxRuntime.jsx("span",{className:"text-xs text-gray-500",children:"Please provide an Error component to the PlatformProvider."})]})}return y?jsxRuntime.jsxs(_.Provider,{value:y,children:[r,g]}):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."})]})}function re(){let r=react.useContext(_);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:c,forcePlatform:s,queryClientConfig:o,membershipModal:u}){let[m]=react.useState(()=>new reactQuery.QueryClient(o||{defaultOptions:{queries:{staleTime:6e4,refetchOnWindowFocus:false}}}));return multichain.initializeMultiChain({projectId:e,metadata:i}),jsxRuntime.jsx(reactQuery.QueryClientProvider,{client:m,children:jsxRuntime.jsx(multichain.MultiChainProvider,{tonManifestUrl:t,children:jsxRuntime.jsx(x,{loadingComponent:g,errorComponent:c,forcePlatform:s,membershipModal:u,children:r})})})}exports.PlatformId=a;exports.PlatformProvider=x;exports.TurtleBasicProvider=le;exports.useLemonAdapter=v;exports.usePlatform=re;exports.useTurtleWebAdapter=C;//# sourceMappingURL=index.cjs.map
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/platform/core/PlatformProvider.tsx","../src/platform/core/detector.ts","../src/platform/adapters/turtle-web-adapter.ts","../src/platform/adapters/index.ts"],"names":["cachedDetectionResult","CACHE_KEY","loadCachedDetection","cached","error","saveCachedDetection","result","detectFromSubdomain","hostname","detectPlatform","forceRedetect","sessionCached","cacheAndReturn","subdomainPlatform","TurtleWebAdapter","__publicField","nonce","params","opportunityId","createAdapter","platformId","PlatformContext","createContext","PlatformProvider","children","loadingComponent","errorComponent","forcePlatform","contextValue","setContextValue","useState","setError","initializePlatform","useCallback","detection","adapter","err","useEffect","jsx","Fragment","jsxs","usePlatform","context","useContext"],"mappings":"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","file":"index.cjs","sourcesContent":["\"use client\";\n\nimport React, { createContext, useContext, useEffect, useState, useCallback } from \"react\";\nimport type { MiniAppAdapter, DetectionResult, PlatformId } from \"./types\";\nimport { detectPlatform } from \"./detector\";\nimport { createAdapter } from \"../adapters\";\n\ninterface PlatformContextValue {\n /** The platform adapter instance */\n adapter: MiniAppAdapter;\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}\n\n/**\n * Platform Provider - handles platform detection and adapter creation\n */\nexport function PlatformProvider({\n children,\n loadingComponent,\n errorComponent,\n forcePlatform,\n}: PlatformProviderProps) {\n const [contextValue, setContextValue] = useState<PlatformContextValue | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const initializePlatform = useCallback(() => {\n try {\n setError(null);\n let detection: DetectionResult;\n //For local testing only.\n if (forcePlatform) {\n detection = {\n platformId: forcePlatform,\n detectionMethod: \"forced\",\n isValidated: false,\n warnings: [\"Platform was manually forced via forcePlatform prop\"],\n };\n } else {\n detection = detectPlatform();\n }\n\n const adapter = createAdapter(detection.platformId);\n\n setContextValue({\n adapter,\n detection,\n isReady: true,\n });\n } catch (err) {\n console.error(\"[PlatformProvider] Error during platform initialization:\", err);\n setError(\n err instanceof Error ? err : new Error(\"Unknown error during platform initialization\")\n );\n }\n }, [forcePlatform]);\n\n useEffect(() => {\n initializePlatform();\n }, [initializePlatform]);\n\n // Show error state if initialization failed\n if (error) {\n if (errorComponent) {\n return <>{errorComponent(error, initializePlatform)}</>;\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 state while detecting\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 <PlatformContext.Provider value={contextValue}>{children}</PlatformContext.Provider>;\n}\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","import type { PlatformId, 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(): 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 'worldcoin';\n }\n if (hostname.includes('lemon.')) {\n return '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: 'turtle-web',\n detectionMethod: 'default',\n isValidated: true,\n });\n}\n","import { Opportunity } from '@turtleclub/hooks';\nimport type {\n MiniAppAdapter,\n User,\n AuthResult,\n DepositParams,\n TransactionResult,\n PlatformCapabilities,\n} from '../core/types';\n\n/**\n * Turtle Web Adapter - for standard web browsers\n */\nexport class TurtleWebAdapter implements MiniAppAdapter {\n readonly platformId = 'turtle-web';\n readonly platformName = 'Turtle Web';\n\n private user: User | null = null;\n\n /**\n * Check if platform is available\n * Web is always available in browser\n */\n isAvailable(): boolean {\n return typeof window !== 'undefined';\n }\n\n /**\n * Authenticate user via wallet connection\n * TODO: Implement\n */\n async authenticate(nonce?: string): Promise<AuthResult> {\n console.log('[TurtleWebAdapter] authenticate() called - NOT IMPLEMENTED', { nonce });\n return {\n success: false,\n error: 'Authentication not implemented yet',\n };\n }\n\n /**\n * Get currently authenticated user\n */\n getUser(): User | null {\n return this.user;\n }\n\n /**\n * Deposit tokens to an opportunity\n * TODO: Implement\n */\n async depositToOpportunity(params: DepositParams): Promise<TransactionResult> {\n console.log('[TurtleWebAdapter] depositToOpportunity() called - NOT IMPLEMENTED', params);\n\n\n return {\n success: false,\n error: 'Deposit not implemented yet',\n };\n }\n\n /**\n * Get platform capabilities\n */\n getCapabilities(): 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 };\n }\n\n /**\n * Get all opportunities\n * TODO: Implement\n */\n getOpportunities(): Promise<Opportunity[]> {\n console.log('[TurtleWebAdapter] getOpportunities() called - NOT IMPLEMENTED');\n return Promise.resolve([]);\n }\n\n /**\n * Get a single opportunity\n * TODO: Implement\n */\n getOpportunity(opportunityId: string): Promise<Opportunity> {\n console.log('[TurtleWebAdapter] getOpportunity() called - NOT IMPLEMENTED', { opportunityId });\n return Promise.reject(new Error('getOpportunity not implemented yet'));\n }\n}\n","import type { PlatformId, MiniAppAdapter } from '../core/types';\nimport { TurtleWebAdapter } from './turtle-web-adapter';\n\n/**\n * Create the appropriate adapter for the given platform\n */\nexport function createAdapter(platformId: PlatformId): MiniAppAdapter {\n switch (platformId) {\n case 'turtle-web':\n return new TurtleWebAdapter();\n\n // For now, we are always going to return the TurtleWebAdapter.\n case 'lemon':\n console.warn('[createAdapter] Lemon adapter not implemented yet, falling back to turtle-web');\n return new TurtleWebAdapter();\n\n case 'worldcoin':\n console.warn('[createAdapter] WorldCoin adapter not implemented yet, falling back to turtle-web');\n return new TurtleWebAdapter();\n\n default:\n console.warn('[createAdapter] Unknown platform, falling back to turtle-web');\n return new TurtleWebAdapter();\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","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":"4MAEO,IAAMA,CAAAA,CAAa,CACxB,UAAW,YAAA,CACX,KAAA,CAAO,OAAA,CACP,SAAA,CAAW,WACb,ECFA,IAAIC,CAAAA,CAAgD,IAAA,CAG9CC,CAAAA,CAAY,2BAAA,CAKlB,SAASC,CAAAA,EAA8C,CACrD,GAAI,OAAO,MAAA,CAAW,GAAA,EAAe,OAAO,cAAA,CAAmB,GAAA,CAC7D,OAAO,IAAA,CAGT,GAAI,CACF,IAAMC,CAAAA,CAAS,cAAA,CAAe,QAAQF,CAAS,CAAA,CAC/C,GAAIE,CAAAA,CACF,OAAO,IAAA,CAAK,KAAA,CAAMA,CAAM,CAE5B,OAASC,CAAAA,CAAO,CACd,OAAA,CAAQ,IAAA,CAAK,wDAAyDA,CAAK,EAC7E,CAEA,OAAO,IACT,CAKA,SAASC,CAAAA,CAAoBC,EAA+B,CAC1D,GAAI,EAAA,OAAO,MAAA,CAAW,KAAe,OAAO,cAAA,CAAmB,GAAA,CAAA,CAI/D,GAAI,CACF,cAAA,CAAe,OAAA,CAAQL,CAAAA,CAAW,IAAA,CAAK,SAAA,CAAUK,CAAM,CAAC,EAC1D,OAASF,CAAAA,CAAO,CACd,OAAA,CAAQ,IAAA,CAAK,wDAAyDA,CAAK,EAC7E,CACF,CAMA,SAASG,CAAAA,EAAyE,CAChF,GAAI,OAAO,MAAA,CAAW,GAAA,CAAa,OAAO,IAAA,CAE1C,IAAMC,CAAAA,CAAW,MAAA,CAAO,QAAA,CAAS,QAAA,CAGjC,OAAIA,CAAAA,CAAS,QAAA,CAAS,YAAY,CAAA,CACzBT,EAAW,SAAA,CAEhBS,CAAAA,CAAS,QAAA,CAAS,QAAQ,EACrBT,CAAAA,CAAW,KAAA,CAGb,IACT,CAQO,SAASU,CAAAA,CAAeC,CAAAA,CAAgB,KAAA,CAAwB,CAErE,GAAI,CAACA,CAAAA,CAAe,CAElB,GAAIV,EACF,OAAOA,CAAAA,CAIT,IAAMW,CAAAA,CAAgBT,CAAAA,EAAoB,CAC1C,GAAIS,CAAAA,CACF,OAAAX,CAAAA,CAAwBW,CAAAA,CACjBA,CAEX,CAEA,IAAMC,CAAAA,CAAkBN,CAAAA,GACtBN,CAAAA,CAAwBM,CAAAA,CACxBD,EAAoBC,CAAM,CAAA,CACnBA,CAAAA,CAAAA,CAIHO,CAAAA,CAAoBN,CAAAA,EAAoB,CAC9C,OACSK,CAAAA,CADLC,EACoB,CACpB,UAAA,CAAYA,CAAAA,CACZ,eAAA,CAAiB,YACjB,WAAA,CAAa,IACf,CAAA,CAIoB,CACpB,WAAYd,CAAAA,CAAW,SAAA,CACvB,eAAA,CAAiB,SAAA,CACjB,WAAA,CAAa,IACf,CARG,CASL,CCvGO,IAAMe,CAAAA,CAAuB,CAClC,OAAA,CAAS,KAA0B,CACjC,OAAA,CAAS,MACT,KAAA,CAAO,6BACT,CAAA,CAAA,CAEA,cAAA,CAAgB,IACP,OAAA,CAAQ,MAAA,CAAO,IAAI,MAAM,oCAAoC,CAAC,CAEzE,CAAA,CCeO,SAASC,CAAAA,CAAoBC,CAAAA,CAAoC,CACtE,IAAMC,EAAUC,+BAAAA,EAAqB,CAC/B,CAAE,OAAA,CAAAC,CAAQ,CAAA,CAAIC,+BAAAA,EAAqB,CACnC,CAAE,WAAAC,CAAW,CAAA,CAAIC,kCAAAA,EAAwB,CACzC,CAAE,WAAA,CAAAC,CAAY,CAAA,CAAIC,mCAAAA,GAElBC,CAAAA,CAAwBC,iBAAAA,CAC5B,MAAOtB,CAAAA,EAAiF,CACtF,MAAA,OAAA,CAAQ,KAAA,CACN,CAAA,wCAAA,EAA2CA,EAAM,IAAI,CAAA,GAAA,EAAMA,CAAAA,CAAM,OAAO,EAC1E,CAAA,CAEMA,CACR,CAAA,CACA,EACF,CAAA,CAGM,CAAE,QAAA,CAAAuB,CAAAA,CAAU,UAAWC,CAAAA,CAAqB,OAAA,CAASC,CAAkB,CAAA,CAAIC,8BAAwB,CACvG,OAAA,CAASb,CAAAA,CAAQ,OAAA,CACjB,gBAAiB,KAAA,CACjB,WAAA,CAAAM,CAAAA,CACA,OAAA,CAAS,IACT,OAAA,CAAS,KAAA,CACT,OAAA,CAASE,CACX,CAAC,CAAA,CAGKM,CAAAA,CACJd,CAAAA,CAAQ,aACR,CAAC,CAACA,CAAAA,CAAQ,OAAA,EACVU,IAAa,KAAA,CAGTK,CAAAA,CAAwBN,iBAAAA,CAAY,SAAY,CACpD,MAAMG,CAAAA,GACR,CAAA,CAAG,CAACA,CAAiB,CAAC,CAAA,CAGhB,CAAE,IAAA,CAAMI,CAAAA,CAAmB,SAAA,CAAWC,CAAuB,EAAIC,+BAAAA,CAA0B,CAC/F,MAAA,CAAQ,CACN,KAAM,CAAA,CACN,QAAA,CAAU,IAAA,CACV,KAAA,CAAO,GACT,CAAA,CACA,OAAA,CAASnB,CACX,CAAC,CAAA,CAOKoB,CAAAA,CAAcV,iBAAAA,CAAY,IACvB,OAAO,MAAA,CAAW,GAAA,CACxB,EAAE,EAOCW,CAAAA,CAAeX,iBAAAA,CACnB,SAAiC,CAC/B,GAAI,CACF,OAAIT,CAAAA,CAAQ,WAAA,EAAeA,EAAQ,OAAA,CAC1B,CACL,OAAA,CAAS,CAAA,CAAA,CACT,KAAM,CACJ,EAAA,CAAIA,CAAAA,CAAQ,OAAA,CACZ,SAAU,CACR,OAAA,CAASA,CAAAA,CAAQ,OAAA,CACjB,MAAA,CAAQA,CAAAA,CAAQ,MAClB,CACF,CACF,CAAA,EAGF,MAAME,CAAAA,CAAQ,KAAK,EAEZ,CACL,OAAA,CAAS,CAAA,CACX,CAAA,CACF,OAASf,CAAAA,CAAO,CACd,OAAA,OAAA,CAAQ,KAAA,CAAM,6CAAA,CAA+CA,CAAK,CAAA,CAC3D,CACL,QAAS,KAAA,CACT,KAAA,CAAOA,CAAAA,YAAiB,KAAA,CAAQA,EAAM,OAAA,CAAU,8BAClD,CACF,CACF,EACA,CAACa,CAAAA,CAAQ,WAAA,CAAaA,CAAAA,CAAQ,OAAA,CAASA,CAAAA,CAAQ,OAAA,CAASA,CAAAA,CAAQ,OAAQE,CAAO,CACjF,CAAA,CAKMmB,CAAAA,CAAmBZ,kBAAY,SAA2B,CAC9D,GAAI,CACF,MAAML,CAAAA,GACR,CAAA,MAASjB,CAAAA,CAAO,CACd,MAAA,OAAA,CAAQ,KAAA,CAAM,yCAAA,CAA2CA,CAAK,EACxDA,CACR,CACF,CAAA,CAAG,CAACiB,CAAU,CAAC,CAAA,CAKTkB,CAAAA,CAAUb,iBAAAA,CAAY,IACtB,CAACT,CAAAA,CAAQ,WAAA,EAAe,CAACA,CAAAA,CAAQ,OAAA,CAC5B,IAAA,CAGF,CACL,GAAIA,CAAAA,CAAQ,OAAA,CACZ,QAAA,CAAU,CACR,QAASA,CAAAA,CAAQ,OAAA,CACjB,MAAA,CAAQA,CAAAA,CAAQ,OAChB,SAAA,CAAWA,CAAAA,CAAQ,SAAA,CACnB,QAAA,CAAAU,CAAAA,CACA,mBAAA,CAAAC,CACF,CACF,EACC,CAACX,CAAAA,CAAQ,WAAA,CAAaA,CAAAA,CAAQ,QAASA,CAAAA,CAAQ,OAAA,CAASA,CAAAA,CAAQ,MAAA,CAAQA,EAAQ,SAAA,CAAWU,CAAAA,CAAUC,CAAmB,CAAC,CAAA,CAMtHY,CAAAA,CAAuBd,iBAAAA,CAC3B,MAAOe,GACE3B,CAAAA,CAAqB,OAAA,EAAQ,CAEtC,EACF,CAAA,CAKM4B,CAAAA,CAAkBhB,iBAAAA,CAAY,KAC3B,CACL,gBAAA,CAAkB,IAAA,CAClB,aAAA,CAAe,IAAA,CACf,oBAAqB,IAAA,CACrB,eAAA,CAAiB,IAAA,CACjB,YAAA,CAAc,MACd,kBAAA,CAAoB,IAAA,CACpB,qBAAA,CAAuB,KAAA,CACvB,iBAAkB,IACpB,CAAA,CAAA,CACC,EAAE,EAMCiB,CAAAA,CAAmBjB,iBAAAA,CAAY,SAC5B,OAAA,CAAQ,OAAA,CAAQO,CAAAA,EAAmB,aAAA,EAAiB,EAAE,CAAA,CAC5D,CAACA,CAAiB,CAAC,EAMhBW,CAAAA,CAAiBlB,iBAAAA,CAAY,MAAOmB,CAAAA,EACjC/B,EAAqB,cAAA,EAAe,CAC1C,EAAE,EAGL,OAAOgC,aAAAA,CACL,KAAO,CACL,WAAY/C,CAAAA,CAAW,SAAA,CACvB,YAAA,CAAc,YAAA,CACd,YAAAqC,CAAAA,CACA,YAAA,CAAAC,CAAAA,CACA,UAAA,CAAYC,EACZ,OAAA,CAAAC,CAAAA,CACA,oBAAA,CAAAC,CAAAA,CACA,eAAA,CAAAE,CAAAA,CACA,gBAAA,CAAAC,CAAAA,CACA,eAAAC,CAAAA,CAEA,sBAAA,CAAAV,CAAAA,CACA,aAAA,CAAeN,EAEf,aAAA,CAAeK,CAAAA,EAAmB,aAAA,EAAiB,GAEnD,yBAAA,CAAAF,CAAAA,CACA,qBAAA,CAAAC,CACF,GACA,CACEI,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,EACAC,CAAAA,CACAE,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAV,EACAN,CAAAA,CACAK,CAAAA,CACAF,CAAAA,CACAC,CACF,CACF,CACF,CCpNO,SAASe,CAAAA,CAAgB/B,EAAoC,CAClE,GAAM,CAACgC,CAAAA,CAAMC,CAAO,CAAA,CAAIC,cAAAA,CAAsB,IAAI,EAC5C,CAACC,CAAAA,CAAWC,CAAY,CAAA,CAAIF,eAAS,KAAK,CAAA,CAGhDG,eAAAA,CAAU,IAAM,CACd,GAAI,OAAO,MAAA,CAAW,GAAA,CAAa,CACjC,IAAMC,CAAAA,CAAwB,CAAC,CAAE,MAAA,CAAe,kBAAA,CAChDF,CAAAA,CAAaE,CAAqB,EACpC,CACF,CAAA,CAAG,EAAE,EAGL,GAAM,CAAE,IAAA,CAAMrB,CAAkB,EAAIE,+BAAAA,CAA0B,CAC5D,MAAA,CAAQ,CACN,KAAM,CAAA,CACN,qBAAA,CAAuB,0DAAA,CACvB,KAAA,CAAO,GACT,CAAA,CACA,OAAA,CAASnB,CACX,CAAC,EAMKoB,CAAAA,CAAcV,iBAAAA,CAAY,IACvByB,CAAAA,CACN,CAACA,CAAS,CAAC,CAAA,CAORd,EAAeX,iBAAAA,CACnB,MAAO6B,CAAAA,EACAJ,CAAAA,CAOE,CACL,OAAA,CAAS,KAAA,CACT,KAAA,CAAO,0CACT,EATS,CACL,OAAA,CAAS,KAAA,CACT,KAAA,CAAO,+CACT,CAAA,CAQJ,CAACA,CAAS,CACZ,CAAA,CAMM9B,CAAAA,CAAaK,iBAAAA,CAAY,SAA2B,CACxDuB,CAAAA,CAAQ,IAAI,EACd,CAAA,CAAG,EAAE,CAAA,CAKCV,CAAAA,CAAUb,iBAAAA,CAAY,IACnBsB,CAAAA,CACN,CAACA,CAAI,CAAC,CAAA,CAOHR,CAAAA,CAAuBd,iBAAAA,CAC3B,MAAOe,GACAU,CAAAA,CAOErC,CAAAA,CAAqB,OAAA,EAAQ,CAN3B,CACL,OAAA,CAAS,KAAA,CACT,KAAA,CAAO,+CACT,EAKJ,CAACqC,CAAS,CACZ,CAAA,CAKMT,EAAkBhB,iBAAAA,CAAY,KAC3B,CACL,gBAAA,CAAkB,MAClB,aAAA,CAAe,KAAA,CACf,mBAAA,CAAqB,KAAA,CACrB,gBAAiB,KAAA,CACjB,YAAA,CAAc,IAAA,CACd,kBAAA,CAAoB,KAAA,CACpB,qBAAA,CAAuB,IAAA,CACvB,gBAAA,CAAkB,IACpB,CAAA,CAAA,CACC,EAAE,CAAA,CAMCiB,EAAmBjB,iBAAAA,CAAY,SAC5B,OAAA,CAAQ,OAAA,CAAQO,GAAmB,aAAA,EAAiB,EAAE,CAAA,CAC5D,CAACA,CAAiB,CAAC,CAAA,CAMhBW,EAAiBlB,iBAAAA,CAAY,MAAOmB,CAAAA,EACjC/B,CAAAA,CAAqB,gBAAe,CAC1C,EAAE,CAAA,CAGL,OAAOgC,aAAAA,CACL,KAAO,CACL,UAAA,CAAY/C,CAAAA,CAAW,KAAA,CACvB,YAAA,CAAc,YAAA,CACd,YAAAqC,CAAAA,CACA,YAAA,CAAAC,CAAAA,CACA,UAAA,CAAAhB,EACA,OAAA,CAAAkB,CAAAA,CACA,oBAAA,CAAAC,CAAAA,CACA,gBAAAE,CAAAA,CACA,gBAAA,CAAAC,CAAAA,CACA,cAAA,CAAAC,CACF,CAAA,CAAA,CACA,CACER,CAAAA,CACAC,CAAAA,CACAhB,EACAkB,CAAAA,CACAC,CAAAA,CACAE,CAAAA,CACAC,CAAAA,CACAC,CACF,CACF,CACF,CCrJA,IAAMY,CAAAA,CAAkBC,mBAAAA,CAA2C,IAAI,CAAA,CAqBvE,SAASC,CAAAA,CAAiB,CACxB,SAAAC,CAAAA,CACA,gBAAA,CAAAC,CAAAA,CACA,cAAA,CAAAC,EACA,aAAA,CAAAC,CAAAA,CACA,eAAA,CAAAC,CACF,EAA0B,CACxB,GAAM,CAAC3D,CAAAA,CAAO4D,CAAQ,CAAA,CAAId,cAAAA,CAAuB,IAAI,CAAA,CAC/C,CAACe,CAAAA,CAAWC,CAAY,CAAA,CAAIhB,cAAAA,CAAiC,IAAI,CAAA,CAGjEiB,CAAAA,CAAmBF,CAAAA,EAAW,UAAA,CAE9BG,CAAAA,CAAmBrD,CAAAA,CAAoBoD,CAAAA,GAAqBpE,CAAAA,CAAW,SAAS,CAAA,CAChFsE,CAAAA,CAAetB,CAAAA,CAAgBoB,CAAAA,GAAqBpE,EAAW,KAAK,CAAA,CAG1EsD,eAAAA,CAAU,IAAM,CACd,GAAI,CACF,IAAIiB,CAAAA,CACAR,EACFQ,CAAAA,CAAkB,CAChB,UAAA,CAAYR,CAAAA,CACZ,gBAAiB,QAAA,CACjB,WAAA,CAAa,CAAA,CAAA,CACb,QAAA,CAAU,CAAC,qDAAqD,CAClE,CAAA,CAEAQ,CAAAA,CAAkB7D,GAAe,CAEnCyD,CAAAA,CAAaI,CAAe,EAC9B,CAAA,MAASC,CAAAA,CAAK,CACZ,OAAA,CAAQ,MAAM,qDAAA,CAAuDA,CAAG,CAAA,CACxEP,CAAAA,CAASO,aAAe,KAAA,CAAQA,CAAAA,CAAM,IAAI,KAAA,CAAM,yCAAyC,CAAC,EAC5F,CACF,CAAA,CAAG,CAACT,CAAa,CAAC,CAAA,CAGlB,IAAMU,CAAAA,CAAU1B,aAAAA,CAAQ,IAA8B,CACpD,GAAI,CAACmB,CAAAA,CAAW,OAAO,IAAA,CAEvB,OAAQA,CAAAA,CAAU,UAAA,EAChB,KAAKlE,CAAAA,CAAW,SAAA,CACd,OAAOqE,CAAAA,CACT,KAAKrE,CAAAA,CAAW,KAAA,CACd,OAAOsE,CAAAA,CACT,KAAKtE,CAAAA,CAAW,SAAA,CAEd,OAAA,OAAA,CAAQ,IAAA,CAAK,0DAA0D,CAAA,CACvEiE,CAAAA,CAAS,IAAI,KAAA,CAAM,wCAAwC,CAAC,CAAA,CACrD,IAAA,CACT,QACE,eAAQ,IAAA,CAAK,sCAAA,CAAwCC,CAAAA,CAAU,UAAU,EACzED,CAAAA,CAAS,IAAI,KAAA,CAAM,CAAA,kBAAA,EAAqBC,EAAU,UAAU,CAAA,CAAE,CAAC,CAAA,CACxD,IACX,CACF,CAAA,CAAG,CAACA,EAAWG,CAAAA,CAAkBC,CAAY,CAAC,CAAA,CAGxCI,EAAe3B,aAAAA,CAAQ,IACvB,CAACmB,CAAAA,EAAa,CAACO,CAAAA,CAAgB,IAAA,CAE5B,CACL,OAAA,CAAAA,EACA,SAAA,CAAAP,CAAAA,CACA,OAAA,CAAS,IACX,EACC,CAACO,CAAAA,CAASP,CAAS,CAAC,EAEvB,GAAI7D,CAAAA,CAAO,CACT,IAAMsE,EAAQ,IAAM,CAClBV,CAAAA,CAAS,IAAI,CAAA,CACbE,CAAAA,CAAa,IAAI,EACnB,EAEA,OAAIL,CAAAA,CACKc,cAAAA,CAAAC,mBAAAA,CAAA,CAAG,QAAA,CAAAf,CAAAA,CAAezD,CAAAA,CAAOsE,CAAK,EAAE,CAAA,CAGvCG,eAAAA,CAAC,MAAA,CAAA,CAAK,SAAA,CAAU,qDACd,QAAA,CAAA,CAAAF,cAAAA,CAAC,KAAA,CAAA,CAAI,SAAA,CAAU,oBAAoB,QAAA,CAAA,8CAAA,CAA4C,CAAA,CAC/EA,cAAAA,CAAC,MAAA,CAAA,CAAK,UAAU,uBAAA,CAAyB,QAAA,CAAAvE,CAAAA,CAAM,OAAA,CAAQ,EACvDuE,cAAAA,CAAC,MAAA,CAAA,CAAK,SAAA,CAAU,uBAAA,CAAwB,QAAA,CAAA,4DAAA,CAExC,CAAA,CAAA,CACF,CAEJ,CAGA,OAAKF,CAAAA,CAeHI,eAAAA,CAACrB,CAAAA,CAAgB,QAAA,CAAhB,CAAyB,KAAA,CAAOiB,CAAAA,CAC9B,QAAA,CAAA,CAAAd,CAAAA,CACAI,GACH,CAAA,CAjBIH,CAAAA,CACKe,cAAAA,CAAAC,mBAAAA,CAAA,CAAG,QAAA,CAAAhB,CAAAA,CAAiB,CAAA,CAG3BiB,gBAAC,MAAA,CAAA,CAAK,SAAA,CAAU,oDAAA,CACd,QAAA,CAAA,CAAAF,eAAC,MAAA,CAAA,CAAK,SAAA,CAAU,mBAAA,CAAoB,QAAA,CAAA,uBAAA,CAAqB,EACzDA,cAAAA,CAAC,MAAA,CAAA,CAAK,SAAA,CAAU,uBAAA,CAAwB,QAAA,CAAA,6DAAA,CAExC,CAAA,CAAA,CACF,CAUN,CAQO,SAASG,EAAAA,EAAoC,CAClD,IAAMC,CAAAA,CAAUC,iBAAWxB,CAAe,CAAA,CAE1C,GAAI,CAACuB,EACH,MAAM,IAAI,KAAA,CAAM,oDAAoD,EAGtE,OAAOA,CACT,CCxIO,SAASE,EAAAA,CAAoB,CAClC,QAAA,CAAAtB,EACA,sBAAA,CAAAuB,CAAAA,CACA,QAAA,CAAAC,CAAAA,CACA,cAAA,CAAAC,CAAAA,CAAiB,2BAAA,CACjB,gBAAA,CAAAxB,EACA,cAAA,CAAAC,CAAAA,CACA,aAAA,CAAAC,CAAAA,CACA,kBAAAuB,CAAAA,CACA,eAAA,CAAAtB,CACF,CAAA,CAA6B,CAE3B,GAAM,CAACuB,CAAW,CAAA,CAAIpC,eACpB,IACE,IAAIqC,sBAAAA,CACFF,CAAAA,EAAqB,CACnB,cAAA,CAAgB,CACd,OAAA,CAAS,CACP,UAAW,GAAA,CACX,oBAAA,CAAsB,KACxB,CACF,CACF,CACF,CACJ,CAAA,CAEE,OAAAG,+BAAAA,CAAqB,CACnB,SAAA,CAAWN,CAAAA,CACT,SAAAC,CACF,CAAC,CAAA,CAIHR,cAAAA,CAACc,+BAAA,CAAoB,MAAA,CAAQH,CAAAA,CAC3B,QAAA,CAAAX,eAACe,6BAAAA,CAAA,CAAmB,cAAA,CAAgBN,CAAAA,CAClC,SAAAT,cAAAA,CAACjB,CAAAA,CAAA,CACC,gBAAA,CAAkBE,EAClB,cAAA,CAAgBC,CAAAA,CAChB,aAAA,CAAeC,CAAAA,CACf,gBAAiBC,CAAAA,CAEhB,QAAA,CAAAJ,CAAAA,CACH,CAAA,CACF,EACF,CAEJ","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"]}
package/dist/index.d.cts CHANGED
@@ -1,11 +1,17 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import React from 'react';
2
+ import { QueryClient } from '@tanstack/react-query';
3
3
  import { Opportunity } from '@turtleclub/hooks';
4
+ import React$1 from 'react';
4
5
 
6
+ declare const PlatformId: {
7
+ readonly TurtleWeb: "turtle-web";
8
+ readonly Lemon: "lemon";
9
+ readonly Worldcoin: "worldcoin";
10
+ };
5
11
  /**
6
- * Platform identifier type union
12
+ * Platform identifier type
7
13
  */
8
- type PlatformId = 'turtle-web' | 'lemon' | 'worldcoin';
14
+ type PlatformId = typeof PlatformId[keyof typeof PlatformId];
9
15
  /**
10
16
  * User information from platform authentication
11
17
  */
@@ -54,20 +60,28 @@ interface PlatformCapabilities {
54
60
  showUsername: boolean;
55
61
  requiresGasPayment: boolean;
56
62
  supportsNotifications: boolean;
63
+ canConnectWallet: boolean;
57
64
  }
58
65
  /**
59
- * Main adapter interface - implemented by each platform
66
+ * Platform adapter interface - implemented by each platform's hook
67
+ * Returned by platform-specific adapter hooks (useTurtleWebAdapter, useLemonAdapter, etc.)
60
68
  */
61
- interface MiniAppAdapter {
69
+ interface PlatformAdapter {
62
70
  readonly platformId: PlatformId;
63
71
  readonly platformName: string;
64
72
  isAvailable(): boolean;
65
73
  authenticate(nonce?: string): Promise<AuthResult>;
74
+ disconnect(): Promise<void>;
66
75
  getUser(): User | null;
67
76
  depositToOpportunity(params: DepositParams): Promise<TransactionResult>;
68
77
  getOpportunities(): Promise<Opportunity[]>;
69
78
  getOpportunity(opportunityId: string): Promise<Opportunity>;
70
79
  getCapabilities(): PlatformCapabilities;
80
+ readonly isLoadingOpportunities?: boolean;
81
+ readonly isLoadingUser?: boolean;
82
+ readonly opportunities?: Opportunity[];
83
+ readonly shouldShowMembershipModal?: boolean;
84
+ readonly triggerMembershipFlow?: () => Promise<void>;
71
85
  }
72
86
  /**
73
87
  * Result of platform detection
@@ -79,31 +93,81 @@ interface DetectionResult {
79
93
  warnings?: string[];
80
94
  }
81
95
 
96
+ interface TurtleBasicProviderProps {
97
+ children: React.ReactNode;
98
+ walletConnectProjectId: string;
99
+ metadata: {
100
+ name: string;
101
+ description: string;
102
+ url: string;
103
+ icons: string[];
104
+ };
105
+ tonManifestUrl?: string;
106
+ loadingComponent?: React.ReactNode;
107
+ errorComponent?: (error: Error, retry: () => void) => React.ReactNode;
108
+ forcePlatform?: PlatformId;
109
+ queryClientConfig?: ConstructorParameters<typeof QueryClient>[0];
110
+ membershipModal?: React.ReactNode;
111
+ }
112
+ declare function TurtleBasicProvider({ children, walletConnectProjectId, metadata, tonManifestUrl, loadingComponent, errorComponent, forcePlatform, queryClientConfig, membershipModal, }: TurtleBasicProviderProps): react_jsx_runtime.JSX.Element;
113
+
82
114
  interface PlatformContextValue {
83
115
  /** The platform adapter instance */
84
- adapter: MiniAppAdapter;
116
+ adapter: PlatformAdapter;
85
117
  /** Platform detection result */
86
118
  detection: DetectionResult;
87
119
  /** Whether platform is ready */
88
120
  isReady: boolean;
89
121
  }
90
122
  interface PlatformProviderProps {
91
- children: React.ReactNode;
123
+ children: React$1.ReactNode;
92
124
  /** Custom loading component to show while platform is being detected */
93
- loadingComponent?: React.ReactNode;
125
+ loadingComponent?: React$1.ReactNode;
94
126
  /** Custom error component to show if initialization fails. Receives error and retry function */
95
- errorComponent?: (error: Error, retry: () => void) => React.ReactNode;
127
+ errorComponent?: (error: Error, retry: () => void) => React$1.ReactNode;
96
128
  /** Force a specific platform (useful for testing/debugging) */
97
129
  forcePlatform?: PlatformId;
130
+ /** Custom membership verification modal component */
131
+ membershipModal?: React$1.ReactNode;
98
132
  }
99
133
  /**
100
- * Platform Provider - handles platform detection and adapter creation
134
+ * Platform Provider component
135
+ * Detects the platform and provides the appropriate adapter via React hooks
136
+ *
137
+ * All adapter hooks are called unconditionally (React rules of hooks),
138
+ * but only the detected platform's adapter is exposed through context.
101
139
  */
102
- declare function PlatformProvider({ children, loadingComponent, errorComponent, forcePlatform, }: PlatformProviderProps): react_jsx_runtime.JSX.Element;
140
+ declare function PlatformProvider({ children, loadingComponent, errorComponent, forcePlatform, membershipModal, }: PlatformProviderProps): react_jsx_runtime.JSX.Element;
141
+
103
142
  /**
104
143
  * Hook to access platform context
105
144
  * @throws Error if used outside PlatformProvider
106
145
  */
107
146
  declare function usePlatform(): PlatformContextValue;
108
147
 
109
- export { type AuthResult, type DepositParams, type DetectionResult, type MiniAppAdapter, type PlatformCapabilities, type PlatformId, PlatformProvider, type TransactionResult, type User, usePlatform };
148
+ /**
149
+ * Turtle Web Adapter Hook - for standard web browsers
150
+ * Uses multichain wallet abstraction with EVM support
151
+ *
152
+ * This is a hook-based adapter that works reactively with React state.
153
+ * Methods always have access to the latest wallet state through React hooks.
154
+ * Automatically handles membership authentication when wallet connects.
155
+ *
156
+ * @param isActive - Whether this adapter is the currently active platform (used to conditionally enable queries)
157
+ */
158
+ declare function useTurtleWebAdapter(isActive: boolean): PlatformAdapter;
159
+
160
+ /**
161
+ * Lemon Adapter Hook - for Lemon Cash WebView mini apps
162
+ * Communicates with Lemon Cash mobile app via WebView postMessage
163
+ *
164
+ * @see https://lemoncash.mintlify.app/functions/authenticate
165
+ *
166
+ * NOTE: This is a stub implementation for architectural demonstration.
167
+ * Full implementation will be added when integrating with Lemon Cash.
168
+ *
169
+ * @param isActive - Whether this adapter is the currently active platform (used to conditionally enable queries)
170
+ */
171
+ declare function useLemonAdapter(isActive: boolean): PlatformAdapter;
172
+
173
+ export { type AuthResult, type DepositParams, type DetectionResult, type PlatformAdapter, type PlatformCapabilities, PlatformId, PlatformProvider, type TransactionResult, TurtleBasicProvider, type TurtleBasicProviderProps, type User, useLemonAdapter, usePlatform, useTurtleWebAdapter };
package/dist/index.d.ts CHANGED
@@ -1,11 +1,17 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import React from 'react';
2
+ import { QueryClient } from '@tanstack/react-query';
3
3
  import { Opportunity } from '@turtleclub/hooks';
4
+ import React$1 from 'react';
4
5
 
6
+ declare const PlatformId: {
7
+ readonly TurtleWeb: "turtle-web";
8
+ readonly Lemon: "lemon";
9
+ readonly Worldcoin: "worldcoin";
10
+ };
5
11
  /**
6
- * Platform identifier type union
12
+ * Platform identifier type
7
13
  */
8
- type PlatformId = 'turtle-web' | 'lemon' | 'worldcoin';
14
+ type PlatformId = typeof PlatformId[keyof typeof PlatformId];
9
15
  /**
10
16
  * User information from platform authentication
11
17
  */
@@ -54,20 +60,28 @@ interface PlatformCapabilities {
54
60
  showUsername: boolean;
55
61
  requiresGasPayment: boolean;
56
62
  supportsNotifications: boolean;
63
+ canConnectWallet: boolean;
57
64
  }
58
65
  /**
59
- * Main adapter interface - implemented by each platform
66
+ * Platform adapter interface - implemented by each platform's hook
67
+ * Returned by platform-specific adapter hooks (useTurtleWebAdapter, useLemonAdapter, etc.)
60
68
  */
61
- interface MiniAppAdapter {
69
+ interface PlatformAdapter {
62
70
  readonly platformId: PlatformId;
63
71
  readonly platformName: string;
64
72
  isAvailable(): boolean;
65
73
  authenticate(nonce?: string): Promise<AuthResult>;
74
+ disconnect(): Promise<void>;
66
75
  getUser(): User | null;
67
76
  depositToOpportunity(params: DepositParams): Promise<TransactionResult>;
68
77
  getOpportunities(): Promise<Opportunity[]>;
69
78
  getOpportunity(opportunityId: string): Promise<Opportunity>;
70
79
  getCapabilities(): PlatformCapabilities;
80
+ readonly isLoadingOpportunities?: boolean;
81
+ readonly isLoadingUser?: boolean;
82
+ readonly opportunities?: Opportunity[];
83
+ readonly shouldShowMembershipModal?: boolean;
84
+ readonly triggerMembershipFlow?: () => Promise<void>;
71
85
  }
72
86
  /**
73
87
  * Result of platform detection
@@ -79,31 +93,81 @@ interface DetectionResult {
79
93
  warnings?: string[];
80
94
  }
81
95
 
96
+ interface TurtleBasicProviderProps {
97
+ children: React.ReactNode;
98
+ walletConnectProjectId: string;
99
+ metadata: {
100
+ name: string;
101
+ description: string;
102
+ url: string;
103
+ icons: string[];
104
+ };
105
+ tonManifestUrl?: string;
106
+ loadingComponent?: React.ReactNode;
107
+ errorComponent?: (error: Error, retry: () => void) => React.ReactNode;
108
+ forcePlatform?: PlatformId;
109
+ queryClientConfig?: ConstructorParameters<typeof QueryClient>[0];
110
+ membershipModal?: React.ReactNode;
111
+ }
112
+ declare function TurtleBasicProvider({ children, walletConnectProjectId, metadata, tonManifestUrl, loadingComponent, errorComponent, forcePlatform, queryClientConfig, membershipModal, }: TurtleBasicProviderProps): react_jsx_runtime.JSX.Element;
113
+
82
114
  interface PlatformContextValue {
83
115
  /** The platform adapter instance */
84
- adapter: MiniAppAdapter;
116
+ adapter: PlatformAdapter;
85
117
  /** Platform detection result */
86
118
  detection: DetectionResult;
87
119
  /** Whether platform is ready */
88
120
  isReady: boolean;
89
121
  }
90
122
  interface PlatformProviderProps {
91
- children: React.ReactNode;
123
+ children: React$1.ReactNode;
92
124
  /** Custom loading component to show while platform is being detected */
93
- loadingComponent?: React.ReactNode;
125
+ loadingComponent?: React$1.ReactNode;
94
126
  /** Custom error component to show if initialization fails. Receives error and retry function */
95
- errorComponent?: (error: Error, retry: () => void) => React.ReactNode;
127
+ errorComponent?: (error: Error, retry: () => void) => React$1.ReactNode;
96
128
  /** Force a specific platform (useful for testing/debugging) */
97
129
  forcePlatform?: PlatformId;
130
+ /** Custom membership verification modal component */
131
+ membershipModal?: React$1.ReactNode;
98
132
  }
99
133
  /**
100
- * Platform Provider - handles platform detection and adapter creation
134
+ * Platform Provider component
135
+ * Detects the platform and provides the appropriate adapter via React hooks
136
+ *
137
+ * All adapter hooks are called unconditionally (React rules of hooks),
138
+ * but only the detected platform's adapter is exposed through context.
101
139
  */
102
- declare function PlatformProvider({ children, loadingComponent, errorComponent, forcePlatform, }: PlatformProviderProps): react_jsx_runtime.JSX.Element;
140
+ declare function PlatformProvider({ children, loadingComponent, errorComponent, forcePlatform, membershipModal, }: PlatformProviderProps): react_jsx_runtime.JSX.Element;
141
+
103
142
  /**
104
143
  * Hook to access platform context
105
144
  * @throws Error if used outside PlatformProvider
106
145
  */
107
146
  declare function usePlatform(): PlatformContextValue;
108
147
 
109
- export { type AuthResult, type DepositParams, type DetectionResult, type MiniAppAdapter, type PlatformCapabilities, type PlatformId, PlatformProvider, type TransactionResult, type User, usePlatform };
148
+ /**
149
+ * Turtle Web Adapter Hook - for standard web browsers
150
+ * Uses multichain wallet abstraction with EVM support
151
+ *
152
+ * This is a hook-based adapter that works reactively with React state.
153
+ * Methods always have access to the latest wallet state through React hooks.
154
+ * Automatically handles membership authentication when wallet connects.
155
+ *
156
+ * @param isActive - Whether this adapter is the currently active platform (used to conditionally enable queries)
157
+ */
158
+ declare function useTurtleWebAdapter(isActive: boolean): PlatformAdapter;
159
+
160
+ /**
161
+ * Lemon Adapter Hook - for Lemon Cash WebView mini apps
162
+ * Communicates with Lemon Cash mobile app via WebView postMessage
163
+ *
164
+ * @see https://lemoncash.mintlify.app/functions/authenticate
165
+ *
166
+ * NOTE: This is a stub implementation for architectural demonstration.
167
+ * Full implementation will be added when integrating with Lemon Cash.
168
+ *
169
+ * @param isActive - Whether this adapter is the currently active platform (used to conditionally enable queries)
170
+ */
171
+ declare function useLemonAdapter(isActive: boolean): PlatformAdapter;
172
+
173
+ export { type AuthResult, type DepositParams, type DetectionResult, type PlatformAdapter, type PlatformCapabilities, PlatformId, PlatformProvider, type TransactionResult, TurtleBasicProvider, type TurtleBasicProviderProps, type User, useLemonAdapter, usePlatform, useTurtleWebAdapter };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import {createContext,useState,useCallback,useEffect,useContext}from'react';import {jsx,jsxs,Fragment}from'react/jsx-runtime';var R=Object.defineProperty;var b=(e,t,o)=>t in e?R(e,t,{enumerable:true,configurable:true,writable:true,value:o}):e[t]=o;var l=(e,t,o)=>b(e,typeof t!="symbol"?t+"":t,o);var s=null,m="turtle-platform-detection";function D(){if(typeof window>"u"||typeof sessionStorage>"u")return null;try{let e=sessionStorage.getItem(m);if(e)return JSON.parse(e)}catch(e){console.warn("[Platform Detection] Failed to load cached detection:",e);}return null}function E(e){if(!(typeof window>"u"||typeof sessionStorage>"u"))try{sessionStorage.setItem(m,JSON.stringify(e));}catch(t){console.warn("[Platform Detection] Failed to save cached detection:",t);}}function N(){if(typeof window>"u")return null;let e=window.location.hostname;return e.includes("worldcoin.")?"worldcoin":e.includes("lemon.")?"lemon":null}function f(e=false){if(!e){if(s)return s;let r=D();if(r)return s=r,r}let t=r=>(s=r,E(r),r),o=N();return t(o?{platformId:o,detectionMethod:"subdomain",isValidated:true}:{platformId:"turtle-web",detectionMethod:"default",isValidated:true})}var i=class{constructor(){l(this,"platformId","turtle-web");l(this,"platformName","Turtle Web");l(this,"user",null);}isAvailable(){return typeof window<"u"}async authenticate(t){return console.log("[TurtleWebAdapter] authenticate() called - NOT IMPLEMENTED",{nonce:t}),{success:false,error:"Authentication not implemented yet"}}getUser(){return this.user}async depositToOpportunity(t){return console.log("[TurtleWebAdapter] depositToOpportunity() called - NOT IMPLEMENTED",t),{success:false,error:"Deposit not implemented yet"}}getCapabilities(){return {canChangeNetwork:true,canDisconnect:true,showNetworkSelector:true,showGasEstimate:true,showUsername:false,requiresGasPayment:true,supportsNotifications:false}}getOpportunities(){return console.log("[TurtleWebAdapter] getOpportunities() called - NOT IMPLEMENTED"),Promise.resolve([])}getOpportunity(t){return console.log("[TurtleWebAdapter] getOpportunity() called - NOT IMPLEMENTED",{opportunityId:t}),Promise.reject(new Error("getOpportunity not implemented yet"))}};function P(e){switch(e){case "turtle-web":return new i;case "lemon":return console.warn("[createAdapter] Lemon adapter not implemented yet, falling back to turtle-web"),new i;case "worldcoin":return console.warn("[createAdapter] WorldCoin adapter not implemented yet, falling back to turtle-web"),new i;default:return console.warn("[createAdapter] Unknown platform, falling back to turtle-web"),new i}}var g=createContext(null);function M({children:e,loadingComponent:t,errorComponent:o,forcePlatform:r}){let[d,x]=useState(null),[c,p]=useState(null),u=useCallback(()=>{try{p(null);let n;r?n={platformId:r,detectionMethod:"forced",isValidated:!1,warnings:["Platform was manually forced via forcePlatform prop"]}:n=f();let A=P(n.platformId);x({adapter:A,detection:n,isReady:!0});}catch(n){console.error("[PlatformProvider] Error during platform initialization:",n),p(n instanceof Error?n:new Error("Unknown error during platform initialization"));}},[r]);return useEffect(()=>{u();},[u]),c?o?jsx(Fragment,{children:o(c,u)}):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:c.message}),jsx("span",{className:"text-xs text-gray-500",children:"Please provide an Error component to the PlatformProvider."})]}):d?jsx(g.Provider,{value:d,children:e}):t?jsx(Fragment,{children:t}):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."})]})}function O(){let e=useContext(g);if(!e)throw new Error("usePlatform must be used within a PlatformProvider");return e}export{M as PlatformProvider,O as usePlatform};//# sourceMappingURL=index.js.map
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 a={TurtleWeb:"turtle-web",Lemon:"lemon",Worldcoin:"worldcoin"};var R=null,W="turtle-platform-detection";function F(){if(typeof window>"u"||typeof sessionStorage>"u")return null;try{let r=sessionStorage.getItem(W);if(r)return JSON.parse(r)}catch(r){console.warn("[Platform Detection] Failed to load cached detection:",r);}return null}function q(r){if(!(typeof window>"u"||typeof sessionStorage>"u"))try{sessionStorage.setItem(W,JSON.stringify(r));}catch(e){console.warn("[Platform Detection] Failed to save cached detection:",e);}}function B(){if(typeof window>"u")return null;let r=window.location.hostname;return r.includes("worldcoin.")?a.Worldcoin:r.includes("lemon.")?a.Lemon:null}function U(r=false){if(!r){if(R)return R;let t=F();if(t)return R=t,t}let e=t=>(R=t,q(t),t),i=B();return e(i?{platformId:i,detectionMethod:"subdomain",isValidated:true}:{platformId:a.TurtleWeb,detectionMethod:"default",isValidated:true})}var w={deposit:()=>({success:false,error:"Deposit not implemented yet"}),getOpportunity:()=>Promise.reject(new Error("getOpportunity not implemented yet"))};function C(r){let e=useMultichainAccount(),{connect:i}=useMultichainConnect(),{disconnect:t}=useMultichainDisconnect(),{signMessage:g}=useMultichainSignMessage(),c=useCallback(async l=>{throw console.error(`[useTurtleWebAdapter] Membership error (${l.type}): ${l.message}`),l},[]),{isMember:s,isLoading:o,refetch:u}=useTurtleMembershipFlow({address:e.address,walletEcosystem:"evm",signMessage:g,chainId:"1",enabled:false,onError:c}),m=e.isConnected&&!!e.address&&s===false,P=useCallback(async()=>{await u();},[u]),{data:d,isLoading:f}=useOpportunitiesPaginated({params:{page:1,featured:true,limit:1e3},enabled:r}),y=useCallback(()=>typeof window<"u",[]),n=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]),M=useCallback(async()=>{try{await t();}catch(l){throw console.error("[useTurtleWebAdapter] Disconnect error:",l),l}},[t]),N=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]),T=useCallback(async l=>w.deposit(),[]),A=useCallback(()=>({canChangeNetwork:true,canDisconnect:true,showNetworkSelector:true,showGasEstimate:true,showUsername:false,requiresGasPayment:true,supportsNotifications:false,canConnectWallet:true}),[]),E=useCallback(async()=>Promise.resolve(d?.opportunities||[]),[d]),O=useCallback(async l=>w.getOpportunity(),[]);return useMemo(()=>({platformId:a.TurtleWeb,platformName:"Turtle Web",isAvailable:y,authenticate:n,disconnect:M,getUser:N,depositToOpportunity:T,getCapabilities:A,getOpportunities:E,getOpportunity:O,isLoadingOpportunities:f,isLoadingUser:o,opportunities:d?.opportunities||[],shouldShowMembershipModal:m,triggerMembershipFlow:P}),[y,n,M,N,T,A,E,O,f,o,d,m,P])}function v(r){let[e,i]=useState(null),[t,g]=useState(false);useEffect(()=>{if(typeof window<"u"){let n=!!window.ReactNativeWebView;g(n);}},[]);let{data:c}=useOpportunitiesPaginated({params:{page:1,receiptTokenChainSlug:"ethereum,solana,base,polygon,arbitrum,optimism,avalanche",limit:100},enabled:r}),s=useCallback(()=>t,[t]),o=useCallback(async n=>t?{success:false,error:"Lemon authentication not implemented yet"}:{success:false,error:"Not running in Lemon Cash WebView environment"},[t]),u=useCallback(async()=>{i(null);},[]),m=useCallback(()=>e,[e]),P=useCallback(async n=>t?w.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}),[]),f=useCallback(async()=>Promise.resolve(c?.opportunities||[]),[c]),y=useCallback(async n=>w.getOpportunity(),[]);return useMemo(()=>({platformId:a.Lemon,platformName:"Lemon Cash",isAvailable:s,authenticate:o,disconnect:u,getUser:m,depositToOpportunity:P,getCapabilities:d,getOpportunities:f,getOpportunity:y}),[s,o,u,m,P,d,f,y])}var _=createContext(null);function x({children:r,loadingComponent:e,errorComponent:i,forcePlatform:t,membershipModal:g}){let[c,s]=useState(null),[o,u]=useState(null),m=o?.platformId,P=C(m===a.TurtleWeb),d=v(m===a.Lemon);useEffect(()=>{try{let n;t?n={platformId:t,detectionMethod:"forced",isValidated:!1,warnings:["Platform was manually forced via forcePlatform prop"]}:n=U(),u(n);}catch(n){console.error("[PlatformProvider] Error during platform detection:",n),s(n instanceof Error?n:new Error("Unknown error during platform detection"));}},[t]);let f=useMemo(()=>{if(!o)return null;switch(o.platformId){case a.TurtleWeb:return P;case a.Lemon:return d;case a.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,d]),y=useMemo(()=>!o||!f?null:{adapter:f,detection:o,isReady:true},[f,o]);if(c){let n=()=>{s(null),u(null);};return i?jsx(Fragment,{children:i(c,n)}):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:c.message}),jsx("span",{className:"text-xs text-gray-500",children:"Please provide an Error component to the PlatformProvider."})]})}return y?jsxs(_.Provider,{value:y,children:[r,g]}):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."})]})}function re(){let r=useContext(_);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:c,forcePlatform:s,queryClientConfig:o,membershipModal:u}){let[m]=useState(()=>new QueryClient(o||{defaultOptions:{queries:{staleTime:6e4,refetchOnWindowFocus:false}}}));return initializeMultiChain({projectId:e,metadata:i}),jsx(QueryClientProvider,{client:m,children:jsx(MultiChainProvider,{tonManifestUrl:t,children:jsx(x,{loadingComponent:g,errorComponent:c,forcePlatform:s,membershipModal:u,children:r})})})}export{a as PlatformId,x as PlatformProvider,le as TurtleBasicProvider,v as useLemonAdapter,re as usePlatform,C 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/PlatformProvider.tsx","../src/platform/core/detector.ts","../src/platform/adapters/turtle-web-adapter.ts","../src/platform/adapters/index.ts"],"names":["cachedDetectionResult","CACHE_KEY","loadCachedDetection","cached","error","saveCachedDetection","result","detectFromSubdomain","hostname","detectPlatform","forceRedetect","sessionCached","cacheAndReturn","subdomainPlatform","TurtleWebAdapter","__publicField","nonce","params","opportunityId","createAdapter","platformId","PlatformContext","createContext","PlatformProvider","children","loadingComponent","errorComponent","forcePlatform","contextValue","setContextValue","useState","setError","initializePlatform","useCallback","detection","adapter","err","useEffect","jsx","Fragment","jsxs","usePlatform","context","useContext"],"mappings":"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","file":"index.js","sourcesContent":["\"use client\";\n\nimport React, { createContext, useContext, useEffect, useState, useCallback } from \"react\";\nimport type { MiniAppAdapter, DetectionResult, PlatformId } from \"./types\";\nimport { detectPlatform } from \"./detector\";\nimport { createAdapter } from \"../adapters\";\n\ninterface PlatformContextValue {\n /** The platform adapter instance */\n adapter: MiniAppAdapter;\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}\n\n/**\n * Platform Provider - handles platform detection and adapter creation\n */\nexport function PlatformProvider({\n children,\n loadingComponent,\n errorComponent,\n forcePlatform,\n}: PlatformProviderProps) {\n const [contextValue, setContextValue] = useState<PlatformContextValue | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const initializePlatform = useCallback(() => {\n try {\n setError(null);\n let detection: DetectionResult;\n //For local testing only.\n if (forcePlatform) {\n detection = {\n platformId: forcePlatform,\n detectionMethod: \"forced\",\n isValidated: false,\n warnings: [\"Platform was manually forced via forcePlatform prop\"],\n };\n } else {\n detection = detectPlatform();\n }\n\n const adapter = createAdapter(detection.platformId);\n\n setContextValue({\n adapter,\n detection,\n isReady: true,\n });\n } catch (err) {\n console.error(\"[PlatformProvider] Error during platform initialization:\", err);\n setError(\n err instanceof Error ? err : new Error(\"Unknown error during platform initialization\")\n );\n }\n }, [forcePlatform]);\n\n useEffect(() => {\n initializePlatform();\n }, [initializePlatform]);\n\n // Show error state if initialization failed\n if (error) {\n if (errorComponent) {\n return <>{errorComponent(error, initializePlatform)}</>;\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 state while detecting\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 <PlatformContext.Provider value={contextValue}>{children}</PlatformContext.Provider>;\n}\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","import type { PlatformId, 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(): 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 'worldcoin';\n }\n if (hostname.includes('lemon.')) {\n return '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: 'turtle-web',\n detectionMethod: 'default',\n isValidated: true,\n });\n}\n","import { Opportunity } from '@turtleclub/hooks';\nimport type {\n MiniAppAdapter,\n User,\n AuthResult,\n DepositParams,\n TransactionResult,\n PlatformCapabilities,\n} from '../core/types';\n\n/**\n * Turtle Web Adapter - for standard web browsers\n */\nexport class TurtleWebAdapter implements MiniAppAdapter {\n readonly platformId = 'turtle-web';\n readonly platformName = 'Turtle Web';\n\n private user: User | null = null;\n\n /**\n * Check if platform is available\n * Web is always available in browser\n */\n isAvailable(): boolean {\n return typeof window !== 'undefined';\n }\n\n /**\n * Authenticate user via wallet connection\n * TODO: Implement\n */\n async authenticate(nonce?: string): Promise<AuthResult> {\n console.log('[TurtleWebAdapter] authenticate() called - NOT IMPLEMENTED', { nonce });\n return {\n success: false,\n error: 'Authentication not implemented yet',\n };\n }\n\n /**\n * Get currently authenticated user\n */\n getUser(): User | null {\n return this.user;\n }\n\n /**\n * Deposit tokens to an opportunity\n * TODO: Implement\n */\n async depositToOpportunity(params: DepositParams): Promise<TransactionResult> {\n console.log('[TurtleWebAdapter] depositToOpportunity() called - NOT IMPLEMENTED', params);\n\n\n return {\n success: false,\n error: 'Deposit not implemented yet',\n };\n }\n\n /**\n * Get platform capabilities\n */\n getCapabilities(): 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 };\n }\n\n /**\n * Get all opportunities\n * TODO: Implement\n */\n getOpportunities(): Promise<Opportunity[]> {\n console.log('[TurtleWebAdapter] getOpportunities() called - NOT IMPLEMENTED');\n return Promise.resolve([]);\n }\n\n /**\n * Get a single opportunity\n * TODO: Implement\n */\n getOpportunity(opportunityId: string): Promise<Opportunity> {\n console.log('[TurtleWebAdapter] getOpportunity() called - NOT IMPLEMENTED', { opportunityId });\n return Promise.reject(new Error('getOpportunity not implemented yet'));\n }\n}\n","import type { PlatformId, MiniAppAdapter } from '../core/types';\nimport { TurtleWebAdapter } from './turtle-web-adapter';\n\n/**\n * Create the appropriate adapter for the given platform\n */\nexport function createAdapter(platformId: PlatformId): MiniAppAdapter {\n switch (platformId) {\n case 'turtle-web':\n return new TurtleWebAdapter();\n\n // For now, we are always going to return the TurtleWebAdapter.\n case 'lemon':\n console.warn('[createAdapter] Lemon adapter not implemented yet, falling back to turtle-web');\n return new TurtleWebAdapter();\n\n case 'worldcoin':\n console.warn('[createAdapter] WorldCoin adapter not implemented yet, falling back to turtle-web');\n return new TurtleWebAdapter();\n\n default:\n console.warn('[createAdapter] Unknown platform, falling back to turtle-web');\n return new TurtleWebAdapter();\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","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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@turtleclub/turtle-basic",
3
- "version": "0.1.0-beta.13",
3
+ "version": "0.1.0-beta.15",
4
4
  "description": "Multi-platform mini-app adapter system for Turtle Basic",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -32,9 +32,10 @@
32
32
  "lint": "eslint . --max-warnings 0"
33
33
  },
34
34
  "dependencies": {
35
- "@turtleclub/hooks": "0.5.0-beta.41",
36
- "@turtleclub/opportunities": "0.1.0-beta.57",
37
- "@turtleclub/ui": "0.7.0-beta.21",
35
+ "@turtleclub/hooks": "0.5.0-beta.43",
36
+ "@turtleclub/multichain": "0.5.0-beta.0",
37
+ "@turtleclub/opportunities": "0.1.0-beta.59",
38
+ "@turtleclub/ui": "0.7.0-beta.22",
38
39
  "@turtleclub/utils": "0.4.0-beta.0"
39
40
  },
40
41
  "peerDependencies": {
@@ -57,5 +58,5 @@
57
58
  "publishConfig": {
58
59
  "access": "public"
59
60
  },
60
- "gitHead": "4752e7b695cd8733bc41b21a79ffaa33b82aa7a0"
61
+ "gitHead": "11cf816a868a361c6745919cee9883c5dbedb788"
61
62
  }