@adland/react 0.15.3 → 0.16.0
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 +11 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +11 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -245,6 +245,7 @@ function useFetch(key, fetcher, opts) {
|
|
|
245
245
|
|
|
246
246
|
// src/utils/ad-actions.ts
|
|
247
247
|
var import_miniapp_sdk = __toESM(require("@farcaster/miniapp-sdk"), 1);
|
|
248
|
+
var import_viem2 = require("viem");
|
|
248
249
|
var _isMiniApp = null;
|
|
249
250
|
var _miniAppPromise = import_miniapp_sdk.default.isInMiniApp().then((v) => {
|
|
250
251
|
_isMiniApp = v;
|
|
@@ -269,9 +270,13 @@ function performAdAction(adData) {
|
|
|
269
270
|
case "miniapp":
|
|
270
271
|
import_miniapp_sdk.default.actions.openMiniApp({ url: adData.data.url });
|
|
271
272
|
break;
|
|
272
|
-
case "token":
|
|
273
|
-
|
|
273
|
+
case "token": {
|
|
274
|
+
const address = adData.data.address;
|
|
275
|
+
const chainId = adData.data.chainId;
|
|
276
|
+
const buyToken = `eip155:${chainId}/erc20:${(0, import_viem2.getAddress)(address)}`;
|
|
277
|
+
import_miniapp_sdk.default.actions.swapToken({ buyToken });
|
|
274
278
|
break;
|
|
279
|
+
}
|
|
275
280
|
case "farcasterProfile":
|
|
276
281
|
import_miniapp_sdk.default.actions.viewProfile({
|
|
277
282
|
fid: Number.parseInt(adData.data.fid, 10)
|
|
@@ -378,7 +383,10 @@ function Ad({
|
|
|
378
383
|
async () => {
|
|
379
384
|
if (!client || !slot) throw new Error("NO_AD" /* NO_AD */);
|
|
380
385
|
const uri = await fetchMetadataURI(client, slot);
|
|
381
|
-
if (!uri)
|
|
386
|
+
if (!uri) {
|
|
387
|
+
console.info("[Ad] no metadata URI found for slot", slot);
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
382
390
|
return fetchAdFromURI(uri);
|
|
383
391
|
},
|
|
384
392
|
{ enabled: !!slot && !staticData }
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/components/Ad.tsx","../src/fetch.ts","../src/hooks/useAdContext.ts","../src/hooks/useFetch.ts","../src/utils/fetchCache.ts","../src/utils/ad-actions.ts","../src/utils/ad-fields.ts","../src/utils/constants.ts"],"sourcesContent":["// Compound Ad components\nexport {\n Ad,\n AdBadge,\n AdDescription,\n AdEmpty,\n AdError,\n AdImage,\n AdLabel,\n AdLoaded,\n AdLoading,\n AdTitle,\n} from \"./components/Ad\";\n\nexport type {\n AdBadgeProps,\n AdDescriptionProps,\n AdImageProps,\n AdLabelProps,\n AdStatusProps,\n AdTitleProps,\n} from \"./components/Ad\";\n\n// Context hook\nexport { useAd } from \"./hooks/useAdContext\";\nexport type { AdContextValue } from \"./hooks/useAdContext\";\n\n// Field helpers\nexport { getAdDescription, getAdImage, getAdTitle, getAdType } from \"./utils/ad-fields\";\n\n// Types\nexport type { AdProps, AdDataQueryError } from \"./types\";\n\n// Constants\nexport { adCardIcon, adCardLabel } from \"./utils/constants\";\n","import { SlotsChain } from \"@0xslots/sdk\";\nimport type { AdData } from \"@adland/data\";\nimport { useCallback, useMemo, useRef } from \"react\";\n\nimport { createReadClient, fetchAdFromURI, fetchMetadataURI } from \"../fetch\";\nimport { AdContext, useAd } from \"../hooks/useAdContext\";\nimport { useFetch } from \"../hooks/useFetch\";\nimport { AdDataQueryError, type AdProps } from \"../types\";\nimport { performAdAction, performEmptyAdAction } from \"../utils/ad-actions\";\nimport { getAdDescription, getAdImage, getAdTitle, getAdType } from \"../utils/ad-fields\";\nimport { adCardIcon, adCardLabel } from \"../utils/constants\";\n\n// ─── Root component ──────────────────────────────────────────────────────────\n\n/**\n * Root Ad component — compound pattern.\n *\n * @example\n * ```tsx\n * <Ad slot=\"0xabc...123\" className=\"rounded-md border p-3\">\n * <AdImage className=\"size-10 rounded-md\" />\n * <AdTitle className=\"text-sm font-medium\" />\n * <AdDescription className=\"text-xs text-muted-foreground\" />\n * <AdBadge />\n * </Ad>\n * ```\n */\nexport function Ad({\n slot,\n data: staticData,\n chainId = SlotsChain.BASE,\n rpcUrl,\n baseLinkUrl = \"https://app.0xslots.org\",\n children,\n ...props\n}: AdProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n const client = useMemo(\n () => (slot ? createReadClient(chainId, rpcUrl) : null),\n [slot, chainId, rpcUrl],\n );\n\n const {\n data: fetchedData,\n isLoading,\n error,\n } = useFetch<AdData>(\n `ad-data-${slot}`,\n async () => {\n if (!client || !slot) throw new Error(AdDataQueryError.NO_AD);\n const uri = await fetchMetadataURI(client, slot);\n if (!uri) throw new Error(AdDataQueryError.NO_AD);\n return fetchAdFromURI(uri);\n },\n { enabled: !!slot && !staticData },\n );\n\n const adData = staticData ?? fetchedData;\n\n const isEmpty =\n !adData &&\n !isLoading &&\n (error instanceof Error\n ? error.message === AdDataQueryError.NO_AD\n : !error);\n\n const onClick = useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n const target = e.target as HTMLElement;\n const isInteractive =\n target.tagName === \"A\" ||\n target.tagName === \"BUTTON\" ||\n target.closest(\"a\") !== null ||\n target.closest(\"button\") !== null;\n if (isInteractive) return;\n\n if (adData) {\n performAdAction(adData);\n } else if (isEmpty && slot) {\n performEmptyAdAction(slot, chainId, baseLinkUrl);\n }\n },\n [adData, isEmpty, slot, chainId, baseLinkUrl],\n );\n\n return (\n <AdContext.Provider\n value={{\n data: adData ?? null,\n isLoading: !!slot && !staticData && isLoading,\n error,\n isEmpty,\n slot,\n baseLinkUrl,\n chainId,\n }}\n >\n <div ref={ref} onClick={onClick} {...props}>\n {children}\n </div>\n </AdContext.Provider>\n );\n}\n\n// ─── Sub-components ──────────────────────────────────────────────────────────\n\nexport interface AdImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {\n fallback?: React.ReactNode;\n}\n\nexport function AdImage({ fallback, ...props }: AdImageProps) {\n const { data } = useAd();\n const src = getAdImage(data);\n if (!src) return fallback ? <>{fallback}</> : null;\n return <img src={src} alt=\"\" {...props} />;\n}\n\nexport interface AdTitleProps extends React.HTMLAttributes<HTMLParagraphElement> {\n fallback?: React.ReactNode;\n}\n\nexport function AdTitle({ fallback, children, ...props }: AdTitleProps) {\n const { data } = useAd();\n const title = getAdTitle(data);\n if (!title) return fallback ? <>{fallback}</> : null;\n return <p {...props}>{children ?? title}</p>;\n}\n\nexport interface AdDescriptionProps extends React.HTMLAttributes<HTMLParagraphElement> {\n fallback?: React.ReactNode;\n}\n\nexport function AdDescription({ fallback, children, ...props }: AdDescriptionProps) {\n const { data } = useAd();\n const description = getAdDescription(data);\n if (!description) return fallback ? <>{fallback}</> : null;\n return <p {...props}>{children ?? description}</p>;\n}\n\nexport interface AdBadgeProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nexport function AdBadge({ children, ...props }: AdBadgeProps) {\n const { data } = useAd();\n const type = getAdType(data);\n if (!type) return null;\n const Icon = adCardIcon[type];\n const label = adCardLabel[type];\n return (\n <span {...props}>\n {children ?? (\n <>\n {Icon && <Icon className=\"size-3\" />}\n {label}\n </>\n )}\n </span>\n );\n}\n\nexport interface AdLabelProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nexport function AdLabel({ children, ...props }: AdLabelProps) {\n return <span {...props}>{children ?? \"AD\"}</span>;\n}\n\n// ─── State components ────────────────────────────────────────────────────────\n\nexport interface AdStatusProps extends React.HTMLAttributes<HTMLDivElement> {\n children?: React.ReactNode;\n}\n\nexport function AdLoading({ children, ...props }: AdStatusProps) {\n const { isLoading } = useAd();\n if (!isLoading) return null;\n return <div {...props}>{children ?? \"Loading...\"}</div>;\n}\n\nexport function AdEmpty({ children, ...props }: AdStatusProps) {\n const { isEmpty } = useAd();\n if (!isEmpty) return null;\n return <div {...props}>{children ?? \"Your ad here\"}</div>;\n}\n\nexport function AdError({ children, ...props }: AdStatusProps) {\n const { error, isEmpty } = useAd();\n if (!error || isEmpty) return null;\n return <div {...props}>{children ?? \"Error loading ad\"}</div>;\n}\n\nexport function AdLoaded({ children, ...props }: AdStatusProps) {\n const { data } = useAd();\n if (!data) return null;\n return <div {...props}>{children}</div>;\n}\n","import { SlotsClient, type SlotsChain } from \"@0xslots/sdk\";\nimport { type Address, createPublicClient, http } from \"viem\";\nimport { base, baseSepolia } from \"viem/chains\";\n\nimport { AdDataQueryError } from \"./types\";\n\nconst IPFS_GATEWAY = \"https://amethyst-representative-mandrill-369.mypinata.cloud/ipfs/\";\n\nconst viemChains: Record<number, typeof base> = {\n 8453: base,\n 84532: baseSepolia,\n};\n\n/**\n * Create a read-only SlotsClient for a given chain.\n */\nexport function createReadClient(\n chainId: SlotsChain,\n rpcUrl?: string,\n): SlotsClient {\n const chain = viemChains[chainId];\n if (!chain) throw new Error(`Unsupported chain: ${chainId}`);\n\n const publicClient = createPublicClient({\n chain,\n transport: http(rpcUrl),\n });\n\n return new SlotsClient({ chainId, publicClient });\n}\n\n/**\n * Fetch ad content from a metadata URI (IPFS or HTTP)\n */\nexport const fetchAdFromURI = async (uri: string) => {\n if (!uri) throw new Error(AdDataQueryError.NO_AD);\n\n const url = uri.startsWith(\"ipfs://\")\n ? `${IPFS_GATEWAY}${uri.slice(7)}`\n : uri;\n\n const res = await fetch(url, {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n });\n\n if (!res.ok) {\n if (res.status === 404) throw new Error(AdDataQueryError.NO_AD);\n throw new Error(AdDataQueryError.ERROR);\n }\n\n const data = await res.json();\n if (data.error) throw new Error(data.error);\n\n return data;\n};\n\n/**\n * Fetch the metadata URI for a slot using the SDK.\n */\nexport const fetchMetadataURI = async (\n client: SlotsClient,\n slotAddress: string,\n): Promise<string> => {\n const info = await client.getSlotInfo(slotAddress as Address);\n const moduleAddress = (info as { module: Address }).module;\n\n if (\n !moduleAddress ||\n moduleAddress === \"0x0000000000000000000000000000000000000000\"\n ) {\n return \"\";\n }\n\n return client.modules.metadata.getURI(\n moduleAddress,\n slotAddress as Address,\n );\n};\n","import type { SlotsChain } from \"@0xslots/sdk\";\nimport type { AdData } from \"@adland/data\";\nimport { createContext, useContext } from \"react\";\n\nexport interface AdContextValue {\n data: AdData | null;\n isLoading: boolean;\n error: unknown;\n isEmpty: boolean;\n slot?: string;\n baseLinkUrl: string;\n chainId: SlotsChain;\n}\n\nexport const AdContext = createContext<AdContextValue | null>(null);\n\nexport function useAd(): AdContextValue {\n const ctx = useContext(AdContext);\n if (!ctx) throw new Error(\"useAd must be used within an <Ad> component\");\n return ctx;\n}\n","import { useEffect, useState } from \"react\";\nimport FetchCache from \"../utils/fetchCache\";\n\ntype Status = \"idle\" | \"loading\" | \"success\" | \"error\";\n\nconst globalCache = new FetchCache();\n\nexport const fetchCache = {\n clear: () => globalCache.clear(),\n};\n\nexport function useFetch<T>(\n key: string,\n fetcher: () => Promise<T>,\n opts?: {\n enabled?: boolean;\n ttl?: number; // ms\n },\n) {\n const { enabled = true, ttl = 0 } = opts ?? {};\n\n // Get cached data from global cache\n const getCachedData = (): T | null => {\n return globalCache.get<T>(key, ttl || undefined);\n };\n\n const hasCachedData = () => {\n return globalCache.has(key, ttl || undefined);\n };\n\n // Check if there's an active fetch for this key (dedupe concurrent requests)\n const getActiveFetch = (): Promise<T> | undefined => {\n return globalCache.getActiveFetch<T>(key);\n };\n\n const cachedData = getCachedData();\n const [data, setData] = useState<T | null>(cachedData);\n const [error, setError] = useState<unknown>(null);\n // If we have cached data, start with success status to avoid showing loader\n const [status, setStatus] = useState<Status>(cachedData ? \"success\" : \"idle\");\n\n const refetch = async () => {\n // ALWAYS check cache first - never show loading if we have valid cached data\n const cached = getCachedData();\n if (cached) {\n // Already have valid cached data, ensure state is correct\n setData(cached);\n setStatus(\"success\");\n return cached;\n }\n\n // Check if there's already an active fetch for this key (dedupe)\n const activeFetch = getActiveFetch();\n if (activeFetch) {\n try {\n const res = await activeFetch;\n setData(res);\n setStatus(\"success\");\n return res;\n } catch (e) {\n setError(e);\n setStatus(\"error\");\n throw e;\n }\n }\n\n // Only set loading if we actually need to fetch\n setStatus(\"loading\");\n setError(null);\n\n try {\n // Create fetch promise and store it for deduplication\n const fetchPromise = fetcher();\n globalCache.setActiveFetch(key, fetchPromise);\n\n const res = await fetchPromise;\n globalCache.set(key, res);\n setData(res);\n setStatus(\"success\");\n return res;\n } catch (e) {\n setError(e);\n setStatus(\"error\");\n throw e;\n }\n };\n\n useEffect(() => {\n if (!enabled) return;\n\n const cached = getCachedData();\n\n if (cached) {\n setData(cached);\n setStatus(\"success\");\n return;\n }\n\n const activeFetch = getActiveFetch();\n if (activeFetch) {\n setStatus(\"loading\");\n activeFetch\n .then((res) => {\n setData(res);\n setStatus(\"success\");\n })\n .catch((e) => {\n setError(e);\n setStatus(\"error\");\n });\n return;\n }\n\n if (status !== \"loading\" && status !== \"success\") {\n refetch();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [key, enabled]);\n\n const hasValidCache = hasCachedData();\n const isLoading = status === \"loading\" && !hasValidCache;\n\n return {\n data,\n error,\n status,\n isIdle: status === \"idle\",\n isLoading,\n isSuccess: status === \"success\",\n isError: status === \"error\",\n refetch,\n };\n}\n","class FetchCache {\n private cache = new Map<string, { data: unknown; ts: number }>();\n private activeFetches = new Map<string, Promise<unknown>>();\n\n get<T>(key: string, ttl?: number): T | null {\n const cached = this.cache.get(key);\n if (!cached) return null;\n\n if (ttl && Date.now() - cached.ts > ttl) {\n // Cache expired, remove it\n this.cache.delete(key);\n return null;\n }\n\n return cached.data as T;\n }\n\n has(key: string, ttl?: number): boolean {\n const cached = this.cache.get(key);\n if (!cached) return false;\n\n if (ttl && Date.now() - cached.ts > ttl) {\n this.cache.delete(key);\n return false;\n }\n\n return true;\n }\n\n set<T>(key: string, data: T): void {\n this.cache.set(key, { data, ts: Date.now() });\n }\n\n getActiveFetch<T>(key: string): Promise<T> | undefined {\n return this.activeFetches.get(key) as Promise<T> | undefined;\n }\n\n setActiveFetch<T>(key: string, promise: Promise<T>): void {\n this.activeFetches.set(key, promise);\n promise.finally(() => {\n this.activeFetches.delete(key);\n });\n }\n\n clear(): void {\n this.cache.clear();\n this.activeFetches.clear();\n }\n}\n\nexport default FetchCache;\n","import type { SlotsChain } from \"@0xslots/sdk\";\nimport type { AdData } from \"@adland/data\";\nimport sdk from \"@farcaster/miniapp-sdk\";\n\n// Cache the miniapp check at module level — resolved once, sync thereafter\nlet _isMiniApp: boolean | null = null;\nconst _miniAppPromise = sdk.isInMiniApp().then((v) => {\n _isMiniApp = v;\n return v;\n}).catch(() => {\n _isMiniApp = false;\n return false;\n});\n\nasync function isMiniApp(): Promise<boolean> {\n if (_isMiniApp !== null) return _isMiniApp;\n return _miniAppPromise;\n}\n\nexport function performAdAction(adData: AdData) {\n try {\n switch (adData.type) {\n case \"link\":\n sdk.actions.openUrl(adData.data.url);\n break;\n case \"cast\":\n sdk.actions.viewCast({ hash: adData.data.hash });\n break;\n case \"miniapp\":\n sdk.actions.openMiniApp({ url: adData.data.url });\n break;\n case \"token\":\n sdk.actions.viewToken({ token: adData.data.address });\n break;\n case \"farcasterProfile\":\n sdk.actions.viewProfile({\n fid: Number.parseInt(adData.data.fid, 10),\n });\n break;\n }\n } catch (err) {\n // Fallback for web (non-miniapp) context\n if (adData.type === \"link\" || adData.type === \"miniapp\") {\n window.open(adData.data.url, \"_blank\");\n } else {\n console.error(\"[@adland/react] Failed to perform ad action:\", err);\n }\n }\n}\n\nexport async function performEmptyAdAction(\n slot: string,\n chainId: SlotsChain,\n baseLinkUrl: string,\n) {\n const url = `${baseLinkUrl}/slots/${slot}?chain=${chainId}`;\n if (await isMiniApp()) {\n sdk.actions.openMiniApp({ url });\n } else {\n window.open(url, \"_blank\");\n }\n}\n","import type { AdData, AdType } from \"@adland/data\";\n\nconst IMAGE_KEYS = [\"image\", \"icon\", \"pfpUrl\", \"logoURI\", \"imageUrl\"] as const;\nconst TITLE_KEYS = [\"title\", \"displayName\", \"username\", \"name\", \"symbol\"] as const;\nconst DESC_KEYS = [\"description\", \"bio\", \"text\", \"name\"] as const;\n\nfunction flatFields(data: AdData): Record<string, unknown> {\n return { ...data.data, ...(data.metadata ?? {}) };\n}\n\nexport function getAdImage(data: AdData | null): string | null {\n if (!data) return null;\n const fields = flatFields(data);\n for (const key of IMAGE_KEYS) {\n const v = fields[key];\n if (typeof v === \"string\" && v) return v;\n }\n return null;\n}\n\nexport function getAdTitle(data: AdData | null): string | null {\n if (!data) return null;\n const fields = flatFields(data);\n for (const key of TITLE_KEYS) {\n const v = fields[key];\n if (typeof v === \"string\" && v) return v;\n }\n return null;\n}\n\nexport function getAdDescription(data: AdData | null): string | null {\n if (!data) return null;\n const fields = flatFields(data);\n const title = getAdTitle(data);\n for (const key of DESC_KEYS) {\n const v = fields[key];\n if (typeof v === \"string\" && v && v !== title) return v;\n }\n return null;\n}\n\nexport function getAdType(data: AdData | null): AdType | null {\n if (!data) return null;\n return data.type as AdType;\n}\n","import { AdType } from \"@adland/data\";\nimport { ForwardRefExoticComponent, RefAttributes } from \"react\";\nimport {\n Link,\n MessageCircle,\n LayoutGrid,\n LucideProps,\n Coins,\n User,\n} from \"lucide-react\";\n\nexport const adCardIcon: Record<\n AdType,\n ForwardRefExoticComponent<\n Omit<LucideProps, \"ref\"> & RefAttributes<SVGSVGElement>\n >\n> = {\n link: Link,\n cast: MessageCircle,\n miniapp: LayoutGrid,\n token: Coins,\n farcasterProfile: User,\n};\n\nexport const adCardLabel: Record<AdType, string> = {\n link: \"Link\",\n cast: \"Cast\",\n miniapp: \"Miniapp\",\n token: \"Token\",\n farcasterProfile: \"Profile\",\n};\n\nexport const adlandApiUrl =\n process.env.NODE_ENV === \"development\"\n ? \"http://localhost:3069\"\n : \"https://api.adland.space\";\n"],"mappings":"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","names":["import_sdk","import_react","import_react","sdk"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/components/Ad.tsx","../src/fetch.ts","../src/hooks/useAdContext.ts","../src/hooks/useFetch.ts","../src/utils/fetchCache.ts","../src/utils/ad-actions.ts","../src/utils/ad-fields.ts","../src/utils/constants.ts"],"sourcesContent":["// Compound Ad components\nexport {\n Ad,\n AdBadge,\n AdDescription,\n AdEmpty,\n AdError,\n AdImage,\n AdLabel,\n AdLoaded,\n AdLoading,\n AdTitle,\n} from \"./components/Ad\";\n\nexport type {\n AdBadgeProps,\n AdDescriptionProps,\n AdImageProps,\n AdLabelProps,\n AdStatusProps,\n AdTitleProps,\n} from \"./components/Ad\";\n\n// Context hook\nexport { useAd } from \"./hooks/useAdContext\";\nexport type { AdContextValue } from \"./hooks/useAdContext\";\n\n// Field helpers\nexport { getAdDescription, getAdImage, getAdTitle, getAdType } from \"./utils/ad-fields\";\n\n// Types\nexport type { AdProps, AdDataQueryError } from \"./types\";\n\n// Constants\nexport { adCardIcon, adCardLabel } from \"./utils/constants\";\n","import { SlotsChain } from \"@0xslots/sdk\";\nimport type { AdData } from \"@adland/data\";\nimport { useCallback, useMemo, useRef } from \"react\";\n\nimport { createReadClient, fetchAdFromURI, fetchMetadataURI } from \"../fetch\";\nimport { AdContext, useAd } from \"../hooks/useAdContext\";\nimport { useFetch } from \"../hooks/useFetch\";\nimport { AdDataQueryError, type AdProps } from \"../types\";\nimport { performAdAction, performEmptyAdAction } from \"../utils/ad-actions\";\nimport { getAdDescription, getAdImage, getAdTitle, getAdType } from \"../utils/ad-fields\";\nimport { adCardIcon, adCardLabel } from \"../utils/constants\";\n\n// ─── Root component ──────────────────────────────────────────────────────────\n\n/**\n * Root Ad component — compound pattern.\n *\n * @example\n * ```tsx\n * <Ad slot=\"0xabc...123\" className=\"rounded-md border p-3\">\n * <AdImage className=\"size-10 rounded-md\" />\n * <AdTitle className=\"text-sm font-medium\" />\n * <AdDescription className=\"text-xs text-muted-foreground\" />\n * <AdBadge />\n * </Ad>\n * ```\n */\nexport function Ad({\n slot,\n data: staticData,\n chainId = SlotsChain.BASE,\n rpcUrl,\n baseLinkUrl = \"https://app.0xslots.org\",\n children,\n ...props\n}: AdProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n const client = useMemo(\n () => (slot ? createReadClient(chainId, rpcUrl) : null),\n [slot, chainId, rpcUrl],\n );\n\n const {\n data: fetchedData,\n isLoading,\n error,\n } = useFetch<AdData>(\n `ad-data-${slot}`,\n async () => {\n if (!client || !slot) throw new Error(AdDataQueryError.NO_AD);\n const uri = await fetchMetadataURI(client, slot);\n if (!uri) {\n console.info(\"[Ad] no metadata URI found for slot\", slot);\n return null;\n }\n return fetchAdFromURI(uri);\n },\n { enabled: !!slot && !staticData },\n );\n\n const adData = staticData ?? fetchedData;\n\n const isEmpty =\n !adData &&\n !isLoading &&\n (error instanceof Error\n ? error.message === AdDataQueryError.NO_AD\n : !error);\n\n const onClick = useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n const target = e.target as HTMLElement;\n const isInteractive =\n target.tagName === \"A\" ||\n target.tagName === \"BUTTON\" ||\n target.closest(\"a\") !== null ||\n target.closest(\"button\") !== null;\n if (isInteractive) return;\n\n if (adData) {\n performAdAction(adData);\n } else if (isEmpty && slot) {\n performEmptyAdAction(slot, chainId, baseLinkUrl);\n }\n },\n [adData, isEmpty, slot, chainId, baseLinkUrl],\n );\n\n return (\n <AdContext.Provider\n value={{\n data: adData ?? null,\n isLoading: !!slot && !staticData && isLoading,\n error,\n isEmpty,\n slot,\n baseLinkUrl,\n chainId,\n }}\n >\n <div ref={ref} onClick={onClick} {...props}>\n {children}\n </div>\n </AdContext.Provider>\n );\n}\n\n// ─── Sub-components ──────────────────────────────────────────────────────────\n\nexport interface AdImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {\n fallback?: React.ReactNode;\n}\n\nexport function AdImage({ fallback, ...props }: AdImageProps) {\n const { data } = useAd();\n const src = getAdImage(data);\n if (!src) return fallback ? <>{fallback}</> : null;\n return <img src={src} alt=\"\" {...props} />;\n}\n\nexport interface AdTitleProps extends React.HTMLAttributes<HTMLParagraphElement> {\n fallback?: React.ReactNode;\n}\n\nexport function AdTitle({ fallback, children, ...props }: AdTitleProps) {\n const { data } = useAd();\n const title = getAdTitle(data);\n if (!title) return fallback ? <>{fallback}</> : null;\n return <p {...props}>{children ?? title}</p>;\n}\n\nexport interface AdDescriptionProps extends React.HTMLAttributes<HTMLParagraphElement> {\n fallback?: React.ReactNode;\n}\n\nexport function AdDescription({ fallback, children, ...props }: AdDescriptionProps) {\n const { data } = useAd();\n const description = getAdDescription(data);\n if (!description) return fallback ? <>{fallback}</> : null;\n return <p {...props}>{children ?? description}</p>;\n}\n\nexport interface AdBadgeProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nexport function AdBadge({ children, ...props }: AdBadgeProps) {\n const { data } = useAd();\n const type = getAdType(data);\n if (!type) return null;\n const Icon = adCardIcon[type];\n const label = adCardLabel[type];\n return (\n <span {...props}>\n {children ?? (\n <>\n {Icon && <Icon className=\"size-3\" />}\n {label}\n </>\n )}\n </span>\n );\n}\n\nexport interface AdLabelProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nexport function AdLabel({ children, ...props }: AdLabelProps) {\n return <span {...props}>{children ?? \"AD\"}</span>;\n}\n\n// ─── State components ────────────────────────────────────────────────────────\n\nexport interface AdStatusProps extends React.HTMLAttributes<HTMLDivElement> {\n children?: React.ReactNode;\n}\n\nexport function AdLoading({ children, ...props }: AdStatusProps) {\n const { isLoading } = useAd();\n if (!isLoading) return null;\n return <div {...props}>{children ?? \"Loading...\"}</div>;\n}\n\nexport function AdEmpty({ children, ...props }: AdStatusProps) {\n const { isEmpty } = useAd();\n if (!isEmpty) return null;\n return <div {...props}>{children ?? \"Your ad here\"}</div>;\n}\n\nexport function AdError({ children, ...props }: AdStatusProps) {\n const { error, isEmpty } = useAd();\n if (!error || isEmpty) return null;\n return <div {...props}>{children ?? \"Error loading ad\"}</div>;\n}\n\nexport function AdLoaded({ children, ...props }: AdStatusProps) {\n const { data } = useAd();\n if (!data) return null;\n return <div {...props}>{children}</div>;\n}\n","import { SlotsClient, type SlotsChain } from \"@0xslots/sdk\";\nimport { type Address, createPublicClient, http } from \"viem\";\nimport { base, baseSepolia } from \"viem/chains\";\n\nimport { AdDataQueryError } from \"./types\";\n\nconst IPFS_GATEWAY = \"https://amethyst-representative-mandrill-369.mypinata.cloud/ipfs/\";\n\nconst viemChains: Record<number, typeof base> = {\n 8453: base,\n 84532: baseSepolia,\n};\n\n/**\n * Create a read-only SlotsClient for a given chain.\n */\nexport function createReadClient(\n chainId: SlotsChain,\n rpcUrl?: string,\n): SlotsClient {\n const chain = viemChains[chainId];\n if (!chain) throw new Error(`Unsupported chain: ${chainId}`);\n\n const publicClient = createPublicClient({\n chain,\n transport: http(rpcUrl),\n });\n\n return new SlotsClient({ chainId, publicClient });\n}\n\n/**\n * Fetch ad content from a metadata URI (IPFS or HTTP)\n */\nexport const fetchAdFromURI = async (uri: string) => {\n if (!uri) throw new Error(AdDataQueryError.NO_AD);\n\n const url = uri.startsWith(\"ipfs://\")\n ? `${IPFS_GATEWAY}${uri.slice(7)}`\n : uri;\n\n const res = await fetch(url, {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n });\n\n if (!res.ok) {\n if (res.status === 404) throw new Error(AdDataQueryError.NO_AD);\n throw new Error(AdDataQueryError.ERROR);\n }\n\n const data = await res.json();\n if (data.error) throw new Error(data.error);\n\n return data;\n};\n\n/**\n * Fetch the metadata URI for a slot using the SDK.\n */\nexport const fetchMetadataURI = async (\n client: SlotsClient,\n slotAddress: string,\n): Promise<string> => {\n const info = await client.getSlotInfo(slotAddress as Address);\n const moduleAddress = (info as { module: Address }).module;\n\n if (\n !moduleAddress ||\n moduleAddress === \"0x0000000000000000000000000000000000000000\"\n ) {\n return \"\";\n }\n\n return client.modules.metadata.getURI(\n moduleAddress,\n slotAddress as Address,\n );\n};\n","import type { SlotsChain } from \"@0xslots/sdk\";\nimport type { AdData } from \"@adland/data\";\nimport { createContext, useContext } from \"react\";\n\nexport interface AdContextValue {\n data: AdData | null;\n isLoading: boolean;\n error: unknown;\n isEmpty: boolean;\n slot?: string;\n baseLinkUrl: string;\n chainId: SlotsChain;\n}\n\nexport const AdContext = createContext<AdContextValue | null>(null);\n\nexport function useAd(): AdContextValue {\n const ctx = useContext(AdContext);\n if (!ctx) throw new Error(\"useAd must be used within an <Ad> component\");\n return ctx;\n}\n","import { useEffect, useState } from \"react\";\nimport FetchCache from \"../utils/fetchCache\";\n\ntype Status = \"idle\" | \"loading\" | \"success\" | \"error\";\n\nconst globalCache = new FetchCache();\n\nexport const fetchCache = {\n clear: () => globalCache.clear(),\n};\n\nexport function useFetch<T>(\n key: string,\n fetcher: () => Promise<T>,\n opts?: {\n enabled?: boolean;\n ttl?: number; // ms\n },\n) {\n const { enabled = true, ttl = 0 } = opts ?? {};\n\n // Get cached data from global cache\n const getCachedData = (): T | null => {\n return globalCache.get<T>(key, ttl || undefined);\n };\n\n const hasCachedData = () => {\n return globalCache.has(key, ttl || undefined);\n };\n\n // Check if there's an active fetch for this key (dedupe concurrent requests)\n const getActiveFetch = (): Promise<T> | undefined => {\n return globalCache.getActiveFetch<T>(key);\n };\n\n const cachedData = getCachedData();\n const [data, setData] = useState<T | null>(cachedData);\n const [error, setError] = useState<unknown>(null);\n // If we have cached data, start with success status to avoid showing loader\n const [status, setStatus] = useState<Status>(cachedData ? \"success\" : \"idle\");\n\n const refetch = async () => {\n // ALWAYS check cache first - never show loading if we have valid cached data\n const cached = getCachedData();\n if (cached) {\n // Already have valid cached data, ensure state is correct\n setData(cached);\n setStatus(\"success\");\n return cached;\n }\n\n // Check if there's already an active fetch for this key (dedupe)\n const activeFetch = getActiveFetch();\n if (activeFetch) {\n try {\n const res = await activeFetch;\n setData(res);\n setStatus(\"success\");\n return res;\n } catch (e) {\n setError(e);\n setStatus(\"error\");\n throw e;\n }\n }\n\n // Only set loading if we actually need to fetch\n setStatus(\"loading\");\n setError(null);\n\n try {\n // Create fetch promise and store it for deduplication\n const fetchPromise = fetcher();\n globalCache.setActiveFetch(key, fetchPromise);\n\n const res = await fetchPromise;\n globalCache.set(key, res);\n setData(res);\n setStatus(\"success\");\n return res;\n } catch (e) {\n setError(e);\n setStatus(\"error\");\n throw e;\n }\n };\n\n useEffect(() => {\n if (!enabled) return;\n\n const cached = getCachedData();\n\n if (cached) {\n setData(cached);\n setStatus(\"success\");\n return;\n }\n\n const activeFetch = getActiveFetch();\n if (activeFetch) {\n setStatus(\"loading\");\n activeFetch\n .then((res) => {\n setData(res);\n setStatus(\"success\");\n })\n .catch((e) => {\n setError(e);\n setStatus(\"error\");\n });\n return;\n }\n\n if (status !== \"loading\" && status !== \"success\") {\n refetch();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [key, enabled]);\n\n const hasValidCache = hasCachedData();\n const isLoading = status === \"loading\" && !hasValidCache;\n\n return {\n data,\n error,\n status,\n isIdle: status === \"idle\",\n isLoading,\n isSuccess: status === \"success\",\n isError: status === \"error\",\n refetch,\n };\n}\n","class FetchCache {\n private cache = new Map<string, { data: unknown; ts: number }>();\n private activeFetches = new Map<string, Promise<unknown>>();\n\n get<T>(key: string, ttl?: number): T | null {\n const cached = this.cache.get(key);\n if (!cached) return null;\n\n if (ttl && Date.now() - cached.ts > ttl) {\n // Cache expired, remove it\n this.cache.delete(key);\n return null;\n }\n\n return cached.data as T;\n }\n\n has(key: string, ttl?: number): boolean {\n const cached = this.cache.get(key);\n if (!cached) return false;\n\n if (ttl && Date.now() - cached.ts > ttl) {\n this.cache.delete(key);\n return false;\n }\n\n return true;\n }\n\n set<T>(key: string, data: T): void {\n this.cache.set(key, { data, ts: Date.now() });\n }\n\n getActiveFetch<T>(key: string): Promise<T> | undefined {\n return this.activeFetches.get(key) as Promise<T> | undefined;\n }\n\n setActiveFetch<T>(key: string, promise: Promise<T>): void {\n this.activeFetches.set(key, promise);\n promise.finally(() => {\n this.activeFetches.delete(key);\n });\n }\n\n clear(): void {\n this.cache.clear();\n this.activeFetches.clear();\n }\n}\n\nexport default FetchCache;\n","import type { SlotsChain } from \"@0xslots/sdk\";\nimport type { AdData } from \"@adland/data\";\nimport sdk from \"@farcaster/miniapp-sdk\";\nimport { getAddress } from \"viem\";\n\n// Cache the miniapp check at module level — resolved once, sync thereafter\nlet _isMiniApp: boolean | null = null;\nconst _miniAppPromise = sdk\n .isInMiniApp()\n .then((v) => {\n _isMiniApp = v;\n return v;\n })\n .catch(() => {\n _isMiniApp = false;\n return false;\n });\n\nasync function isMiniApp(): Promise<boolean> {\n if (_isMiniApp !== null) return _isMiniApp;\n return _miniAppPromise;\n}\n\nexport function performAdAction(adData: AdData) {\n try {\n switch (adData.type) {\n case \"link\":\n sdk.actions.openUrl(adData.data.url);\n break;\n case \"cast\":\n sdk.actions.viewCast({ hash: adData.data.hash });\n break;\n case \"miniapp\":\n sdk.actions.openMiniApp({ url: adData.data.url });\n break;\n case \"token\": {\n const address = adData.data.address;\n const chainId = adData.data.chainId;\n const buyToken = `eip155:${chainId}/erc20:${getAddress(address)}`;\n sdk.actions.swapToken({ buyToken });\n break;\n }\n case \"farcasterProfile\":\n sdk.actions.viewProfile({\n fid: Number.parseInt(adData.data.fid, 10),\n });\n break;\n }\n } catch (err) {\n // Fallback for web (non-miniapp) context\n if (adData.type === \"link\" || adData.type === \"miniapp\") {\n window.open(adData.data.url, \"_blank\");\n } else {\n console.error(\"[@adland/react] Failed to perform ad action:\", err);\n }\n }\n}\n\nexport async function performEmptyAdAction(\n slot: string,\n chainId: SlotsChain,\n baseLinkUrl: string,\n) {\n const url = `${baseLinkUrl}/slots/${slot}?chain=${chainId}`;\n if (await isMiniApp()) {\n sdk.actions.openMiniApp({ url });\n } else {\n window.open(url, \"_blank\");\n }\n}\n","import type { AdData, AdType } from \"@adland/data\";\n\nconst IMAGE_KEYS = [\"image\", \"icon\", \"pfpUrl\", \"logoURI\", \"imageUrl\"] as const;\nconst TITLE_KEYS = [\"title\", \"displayName\", \"username\", \"name\", \"symbol\"] as const;\nconst DESC_KEYS = [\"description\", \"bio\", \"text\", \"name\"] as const;\n\nfunction flatFields(data: AdData): Record<string, unknown> {\n return { ...data.data, ...(data.metadata ?? {}) };\n}\n\nexport function getAdImage(data: AdData | null): string | null {\n if (!data) return null;\n const fields = flatFields(data);\n for (const key of IMAGE_KEYS) {\n const v = fields[key];\n if (typeof v === \"string\" && v) return v;\n }\n return null;\n}\n\nexport function getAdTitle(data: AdData | null): string | null {\n if (!data) return null;\n const fields = flatFields(data);\n for (const key of TITLE_KEYS) {\n const v = fields[key];\n if (typeof v === \"string\" && v) return v;\n }\n return null;\n}\n\nexport function getAdDescription(data: AdData | null): string | null {\n if (!data) return null;\n const fields = flatFields(data);\n const title = getAdTitle(data);\n for (const key of DESC_KEYS) {\n const v = fields[key];\n if (typeof v === \"string\" && v && v !== title) return v;\n }\n return null;\n}\n\nexport function getAdType(data: AdData | null): AdType | null {\n if (!data) return null;\n return data.type as AdType;\n}\n","import { AdType } from \"@adland/data\";\nimport { ForwardRefExoticComponent, RefAttributes } from \"react\";\nimport {\n Link,\n MessageCircle,\n LayoutGrid,\n LucideProps,\n Coins,\n User,\n} from \"lucide-react\";\n\nexport const adCardIcon: Record<\n AdType,\n ForwardRefExoticComponent<\n Omit<LucideProps, \"ref\"> & RefAttributes<SVGSVGElement>\n >\n> = {\n link: Link,\n cast: MessageCircle,\n miniapp: LayoutGrid,\n token: Coins,\n farcasterProfile: User,\n};\n\nexport const adCardLabel: Record<AdType, string> = {\n link: \"Link\",\n cast: \"Cast\",\n miniapp: \"Miniapp\",\n token: \"Token\",\n farcasterProfile: \"Profile\",\n};\n\nexport const adlandApiUrl =\n process.env.NODE_ENV === \"development\"\n ? \"http://localhost:3069\"\n : \"https://api.adland.space\";\n"],"mappings":"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","names":["import_sdk","import_react","import_react","import_viem","sdk"]}
|
package/dist/index.js
CHANGED
|
@@ -193,6 +193,7 @@ function useFetch(key, fetcher, opts) {
|
|
|
193
193
|
|
|
194
194
|
// src/utils/ad-actions.ts
|
|
195
195
|
import sdk from "@farcaster/miniapp-sdk";
|
|
196
|
+
import { getAddress } from "viem";
|
|
196
197
|
var _isMiniApp = null;
|
|
197
198
|
var _miniAppPromise = sdk.isInMiniApp().then((v) => {
|
|
198
199
|
_isMiniApp = v;
|
|
@@ -217,9 +218,13 @@ function performAdAction(adData) {
|
|
|
217
218
|
case "miniapp":
|
|
218
219
|
sdk.actions.openMiniApp({ url: adData.data.url });
|
|
219
220
|
break;
|
|
220
|
-
case "token":
|
|
221
|
-
|
|
221
|
+
case "token": {
|
|
222
|
+
const address = adData.data.address;
|
|
223
|
+
const chainId = adData.data.chainId;
|
|
224
|
+
const buyToken = `eip155:${chainId}/erc20:${getAddress(address)}`;
|
|
225
|
+
sdk.actions.swapToken({ buyToken });
|
|
222
226
|
break;
|
|
227
|
+
}
|
|
223
228
|
case "farcasterProfile":
|
|
224
229
|
sdk.actions.viewProfile({
|
|
225
230
|
fid: Number.parseInt(adData.data.fid, 10)
|
|
@@ -332,7 +337,10 @@ function Ad({
|
|
|
332
337
|
async () => {
|
|
333
338
|
if (!client || !slot) throw new Error("NO_AD" /* NO_AD */);
|
|
334
339
|
const uri = await fetchMetadataURI(client, slot);
|
|
335
|
-
if (!uri)
|
|
340
|
+
if (!uri) {
|
|
341
|
+
console.info("[Ad] no metadata URI found for slot", slot);
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
336
344
|
return fetchAdFromURI(uri);
|
|
337
345
|
},
|
|
338
346
|
{ enabled: !!slot && !staticData }
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Ad.tsx","../src/fetch.ts","../src/hooks/useAdContext.ts","../src/hooks/useFetch.ts","../src/utils/fetchCache.ts","../src/utils/ad-actions.ts","../src/utils/ad-fields.ts","../src/utils/constants.ts"],"sourcesContent":["import { SlotsChain } from \"@0xslots/sdk\";\nimport type { AdData } from \"@adland/data\";\nimport { useCallback, useMemo, useRef } from \"react\";\n\nimport { createReadClient, fetchAdFromURI, fetchMetadataURI } from \"../fetch\";\nimport { AdContext, useAd } from \"../hooks/useAdContext\";\nimport { useFetch } from \"../hooks/useFetch\";\nimport { AdDataQueryError, type AdProps } from \"../types\";\nimport { performAdAction, performEmptyAdAction } from \"../utils/ad-actions\";\nimport { getAdDescription, getAdImage, getAdTitle, getAdType } from \"../utils/ad-fields\";\nimport { adCardIcon, adCardLabel } from \"../utils/constants\";\n\n// ─── Root component ──────────────────────────────────────────────────────────\n\n/**\n * Root Ad component — compound pattern.\n *\n * @example\n * ```tsx\n * <Ad slot=\"0xabc...123\" className=\"rounded-md border p-3\">\n * <AdImage className=\"size-10 rounded-md\" />\n * <AdTitle className=\"text-sm font-medium\" />\n * <AdDescription className=\"text-xs text-muted-foreground\" />\n * <AdBadge />\n * </Ad>\n * ```\n */\nexport function Ad({\n slot,\n data: staticData,\n chainId = SlotsChain.BASE,\n rpcUrl,\n baseLinkUrl = \"https://app.0xslots.org\",\n children,\n ...props\n}: AdProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n const client = useMemo(\n () => (slot ? createReadClient(chainId, rpcUrl) : null),\n [slot, chainId, rpcUrl],\n );\n\n const {\n data: fetchedData,\n isLoading,\n error,\n } = useFetch<AdData>(\n `ad-data-${slot}`,\n async () => {\n if (!client || !slot) throw new Error(AdDataQueryError.NO_AD);\n const uri = await fetchMetadataURI(client, slot);\n if (!uri) throw new Error(AdDataQueryError.NO_AD);\n return fetchAdFromURI(uri);\n },\n { enabled: !!slot && !staticData },\n );\n\n const adData = staticData ?? fetchedData;\n\n const isEmpty =\n !adData &&\n !isLoading &&\n (error instanceof Error\n ? error.message === AdDataQueryError.NO_AD\n : !error);\n\n const onClick = useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n const target = e.target as HTMLElement;\n const isInteractive =\n target.tagName === \"A\" ||\n target.tagName === \"BUTTON\" ||\n target.closest(\"a\") !== null ||\n target.closest(\"button\") !== null;\n if (isInteractive) return;\n\n if (adData) {\n performAdAction(adData);\n } else if (isEmpty && slot) {\n performEmptyAdAction(slot, chainId, baseLinkUrl);\n }\n },\n [adData, isEmpty, slot, chainId, baseLinkUrl],\n );\n\n return (\n <AdContext.Provider\n value={{\n data: adData ?? null,\n isLoading: !!slot && !staticData && isLoading,\n error,\n isEmpty,\n slot,\n baseLinkUrl,\n chainId,\n }}\n >\n <div ref={ref} onClick={onClick} {...props}>\n {children}\n </div>\n </AdContext.Provider>\n );\n}\n\n// ─── Sub-components ──────────────────────────────────────────────────────────\n\nexport interface AdImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {\n fallback?: React.ReactNode;\n}\n\nexport function AdImage({ fallback, ...props }: AdImageProps) {\n const { data } = useAd();\n const src = getAdImage(data);\n if (!src) return fallback ? <>{fallback}</> : null;\n return <img src={src} alt=\"\" {...props} />;\n}\n\nexport interface AdTitleProps extends React.HTMLAttributes<HTMLParagraphElement> {\n fallback?: React.ReactNode;\n}\n\nexport function AdTitle({ fallback, children, ...props }: AdTitleProps) {\n const { data } = useAd();\n const title = getAdTitle(data);\n if (!title) return fallback ? <>{fallback}</> : null;\n return <p {...props}>{children ?? title}</p>;\n}\n\nexport interface AdDescriptionProps extends React.HTMLAttributes<HTMLParagraphElement> {\n fallback?: React.ReactNode;\n}\n\nexport function AdDescription({ fallback, children, ...props }: AdDescriptionProps) {\n const { data } = useAd();\n const description = getAdDescription(data);\n if (!description) return fallback ? <>{fallback}</> : null;\n return <p {...props}>{children ?? description}</p>;\n}\n\nexport interface AdBadgeProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nexport function AdBadge({ children, ...props }: AdBadgeProps) {\n const { data } = useAd();\n const type = getAdType(data);\n if (!type) return null;\n const Icon = adCardIcon[type];\n const label = adCardLabel[type];\n return (\n <span {...props}>\n {children ?? (\n <>\n {Icon && <Icon className=\"size-3\" />}\n {label}\n </>\n )}\n </span>\n );\n}\n\nexport interface AdLabelProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nexport function AdLabel({ children, ...props }: AdLabelProps) {\n return <span {...props}>{children ?? \"AD\"}</span>;\n}\n\n// ─── State components ────────────────────────────────────────────────────────\n\nexport interface AdStatusProps extends React.HTMLAttributes<HTMLDivElement> {\n children?: React.ReactNode;\n}\n\nexport function AdLoading({ children, ...props }: AdStatusProps) {\n const { isLoading } = useAd();\n if (!isLoading) return null;\n return <div {...props}>{children ?? \"Loading...\"}</div>;\n}\n\nexport function AdEmpty({ children, ...props }: AdStatusProps) {\n const { isEmpty } = useAd();\n if (!isEmpty) return null;\n return <div {...props}>{children ?? \"Your ad here\"}</div>;\n}\n\nexport function AdError({ children, ...props }: AdStatusProps) {\n const { error, isEmpty } = useAd();\n if (!error || isEmpty) return null;\n return <div {...props}>{children ?? \"Error loading ad\"}</div>;\n}\n\nexport function AdLoaded({ children, ...props }: AdStatusProps) {\n const { data } = useAd();\n if (!data) return null;\n return <div {...props}>{children}</div>;\n}\n","import { SlotsClient, type SlotsChain } from \"@0xslots/sdk\";\nimport { type Address, createPublicClient, http } from \"viem\";\nimport { base, baseSepolia } from \"viem/chains\";\n\nimport { AdDataQueryError } from \"./types\";\n\nconst IPFS_GATEWAY = \"https://amethyst-representative-mandrill-369.mypinata.cloud/ipfs/\";\n\nconst viemChains: Record<number, typeof base> = {\n 8453: base,\n 84532: baseSepolia,\n};\n\n/**\n * Create a read-only SlotsClient for a given chain.\n */\nexport function createReadClient(\n chainId: SlotsChain,\n rpcUrl?: string,\n): SlotsClient {\n const chain = viemChains[chainId];\n if (!chain) throw new Error(`Unsupported chain: ${chainId}`);\n\n const publicClient = createPublicClient({\n chain,\n transport: http(rpcUrl),\n });\n\n return new SlotsClient({ chainId, publicClient });\n}\n\n/**\n * Fetch ad content from a metadata URI (IPFS or HTTP)\n */\nexport const fetchAdFromURI = async (uri: string) => {\n if (!uri) throw new Error(AdDataQueryError.NO_AD);\n\n const url = uri.startsWith(\"ipfs://\")\n ? `${IPFS_GATEWAY}${uri.slice(7)}`\n : uri;\n\n const res = await fetch(url, {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n });\n\n if (!res.ok) {\n if (res.status === 404) throw new Error(AdDataQueryError.NO_AD);\n throw new Error(AdDataQueryError.ERROR);\n }\n\n const data = await res.json();\n if (data.error) throw new Error(data.error);\n\n return data;\n};\n\n/**\n * Fetch the metadata URI for a slot using the SDK.\n */\nexport const fetchMetadataURI = async (\n client: SlotsClient,\n slotAddress: string,\n): Promise<string> => {\n const info = await client.getSlotInfo(slotAddress as Address);\n const moduleAddress = (info as { module: Address }).module;\n\n if (\n !moduleAddress ||\n moduleAddress === \"0x0000000000000000000000000000000000000000\"\n ) {\n return \"\";\n }\n\n return client.modules.metadata.getURI(\n moduleAddress,\n slotAddress as Address,\n );\n};\n","import type { SlotsChain } from \"@0xslots/sdk\";\nimport type { AdData } from \"@adland/data\";\nimport { createContext, useContext } from \"react\";\n\nexport interface AdContextValue {\n data: AdData | null;\n isLoading: boolean;\n error: unknown;\n isEmpty: boolean;\n slot?: string;\n baseLinkUrl: string;\n chainId: SlotsChain;\n}\n\nexport const AdContext = createContext<AdContextValue | null>(null);\n\nexport function useAd(): AdContextValue {\n const ctx = useContext(AdContext);\n if (!ctx) throw new Error(\"useAd must be used within an <Ad> component\");\n return ctx;\n}\n","import { useEffect, useState } from \"react\";\nimport FetchCache from \"../utils/fetchCache\";\n\ntype Status = \"idle\" | \"loading\" | \"success\" | \"error\";\n\nconst globalCache = new FetchCache();\n\nexport const fetchCache = {\n clear: () => globalCache.clear(),\n};\n\nexport function useFetch<T>(\n key: string,\n fetcher: () => Promise<T>,\n opts?: {\n enabled?: boolean;\n ttl?: number; // ms\n },\n) {\n const { enabled = true, ttl = 0 } = opts ?? {};\n\n // Get cached data from global cache\n const getCachedData = (): T | null => {\n return globalCache.get<T>(key, ttl || undefined);\n };\n\n const hasCachedData = () => {\n return globalCache.has(key, ttl || undefined);\n };\n\n // Check if there's an active fetch for this key (dedupe concurrent requests)\n const getActiveFetch = (): Promise<T> | undefined => {\n return globalCache.getActiveFetch<T>(key);\n };\n\n const cachedData = getCachedData();\n const [data, setData] = useState<T | null>(cachedData);\n const [error, setError] = useState<unknown>(null);\n // If we have cached data, start with success status to avoid showing loader\n const [status, setStatus] = useState<Status>(cachedData ? \"success\" : \"idle\");\n\n const refetch = async () => {\n // ALWAYS check cache first - never show loading if we have valid cached data\n const cached = getCachedData();\n if (cached) {\n // Already have valid cached data, ensure state is correct\n setData(cached);\n setStatus(\"success\");\n return cached;\n }\n\n // Check if there's already an active fetch for this key (dedupe)\n const activeFetch = getActiveFetch();\n if (activeFetch) {\n try {\n const res = await activeFetch;\n setData(res);\n setStatus(\"success\");\n return res;\n } catch (e) {\n setError(e);\n setStatus(\"error\");\n throw e;\n }\n }\n\n // Only set loading if we actually need to fetch\n setStatus(\"loading\");\n setError(null);\n\n try {\n // Create fetch promise and store it for deduplication\n const fetchPromise = fetcher();\n globalCache.setActiveFetch(key, fetchPromise);\n\n const res = await fetchPromise;\n globalCache.set(key, res);\n setData(res);\n setStatus(\"success\");\n return res;\n } catch (e) {\n setError(e);\n setStatus(\"error\");\n throw e;\n }\n };\n\n useEffect(() => {\n if (!enabled) return;\n\n const cached = getCachedData();\n\n if (cached) {\n setData(cached);\n setStatus(\"success\");\n return;\n }\n\n const activeFetch = getActiveFetch();\n if (activeFetch) {\n setStatus(\"loading\");\n activeFetch\n .then((res) => {\n setData(res);\n setStatus(\"success\");\n })\n .catch((e) => {\n setError(e);\n setStatus(\"error\");\n });\n return;\n }\n\n if (status !== \"loading\" && status !== \"success\") {\n refetch();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [key, enabled]);\n\n const hasValidCache = hasCachedData();\n const isLoading = status === \"loading\" && !hasValidCache;\n\n return {\n data,\n error,\n status,\n isIdle: status === \"idle\",\n isLoading,\n isSuccess: status === \"success\",\n isError: status === \"error\",\n refetch,\n };\n}\n","class FetchCache {\n private cache = new Map<string, { data: unknown; ts: number }>();\n private activeFetches = new Map<string, Promise<unknown>>();\n\n get<T>(key: string, ttl?: number): T | null {\n const cached = this.cache.get(key);\n if (!cached) return null;\n\n if (ttl && Date.now() - cached.ts > ttl) {\n // Cache expired, remove it\n this.cache.delete(key);\n return null;\n }\n\n return cached.data as T;\n }\n\n has(key: string, ttl?: number): boolean {\n const cached = this.cache.get(key);\n if (!cached) return false;\n\n if (ttl && Date.now() - cached.ts > ttl) {\n this.cache.delete(key);\n return false;\n }\n\n return true;\n }\n\n set<T>(key: string, data: T): void {\n this.cache.set(key, { data, ts: Date.now() });\n }\n\n getActiveFetch<T>(key: string): Promise<T> | undefined {\n return this.activeFetches.get(key) as Promise<T> | undefined;\n }\n\n setActiveFetch<T>(key: string, promise: Promise<T>): void {\n this.activeFetches.set(key, promise);\n promise.finally(() => {\n this.activeFetches.delete(key);\n });\n }\n\n clear(): void {\n this.cache.clear();\n this.activeFetches.clear();\n }\n}\n\nexport default FetchCache;\n","import type { SlotsChain } from \"@0xslots/sdk\";\nimport type { AdData } from \"@adland/data\";\nimport sdk from \"@farcaster/miniapp-sdk\";\n\n// Cache the miniapp check at module level — resolved once, sync thereafter\nlet _isMiniApp: boolean | null = null;\nconst _miniAppPromise = sdk.isInMiniApp().then((v) => {\n _isMiniApp = v;\n return v;\n}).catch(() => {\n _isMiniApp = false;\n return false;\n});\n\nasync function isMiniApp(): Promise<boolean> {\n if (_isMiniApp !== null) return _isMiniApp;\n return _miniAppPromise;\n}\n\nexport function performAdAction(adData: AdData) {\n try {\n switch (adData.type) {\n case \"link\":\n sdk.actions.openUrl(adData.data.url);\n break;\n case \"cast\":\n sdk.actions.viewCast({ hash: adData.data.hash });\n break;\n case \"miniapp\":\n sdk.actions.openMiniApp({ url: adData.data.url });\n break;\n case \"token\":\n sdk.actions.viewToken({ token: adData.data.address });\n break;\n case \"farcasterProfile\":\n sdk.actions.viewProfile({\n fid: Number.parseInt(adData.data.fid, 10),\n });\n break;\n }\n } catch (err) {\n // Fallback for web (non-miniapp) context\n if (adData.type === \"link\" || adData.type === \"miniapp\") {\n window.open(adData.data.url, \"_blank\");\n } else {\n console.error(\"[@adland/react] Failed to perform ad action:\", err);\n }\n }\n}\n\nexport async function performEmptyAdAction(\n slot: string,\n chainId: SlotsChain,\n baseLinkUrl: string,\n) {\n const url = `${baseLinkUrl}/slots/${slot}?chain=${chainId}`;\n if (await isMiniApp()) {\n sdk.actions.openMiniApp({ url });\n } else {\n window.open(url, \"_blank\");\n }\n}\n","import type { AdData, AdType } from \"@adland/data\";\n\nconst IMAGE_KEYS = [\"image\", \"icon\", \"pfpUrl\", \"logoURI\", \"imageUrl\"] as const;\nconst TITLE_KEYS = [\"title\", \"displayName\", \"username\", \"name\", \"symbol\"] as const;\nconst DESC_KEYS = [\"description\", \"bio\", \"text\", \"name\"] as const;\n\nfunction flatFields(data: AdData): Record<string, unknown> {\n return { ...data.data, ...(data.metadata ?? {}) };\n}\n\nexport function getAdImage(data: AdData | null): string | null {\n if (!data) return null;\n const fields = flatFields(data);\n for (const key of IMAGE_KEYS) {\n const v = fields[key];\n if (typeof v === \"string\" && v) return v;\n }\n return null;\n}\n\nexport function getAdTitle(data: AdData | null): string | null {\n if (!data) return null;\n const fields = flatFields(data);\n for (const key of TITLE_KEYS) {\n const v = fields[key];\n if (typeof v === \"string\" && v) return v;\n }\n return null;\n}\n\nexport function getAdDescription(data: AdData | null): string | null {\n if (!data) return null;\n const fields = flatFields(data);\n const title = getAdTitle(data);\n for (const key of DESC_KEYS) {\n const v = fields[key];\n if (typeof v === \"string\" && v && v !== title) return v;\n }\n return null;\n}\n\nexport function getAdType(data: AdData | null): AdType | null {\n if (!data) return null;\n return data.type as AdType;\n}\n","import { AdType } from \"@adland/data\";\nimport { ForwardRefExoticComponent, RefAttributes } from \"react\";\nimport {\n Link,\n MessageCircle,\n LayoutGrid,\n LucideProps,\n Coins,\n User,\n} from \"lucide-react\";\n\nexport const adCardIcon: Record<\n AdType,\n ForwardRefExoticComponent<\n Omit<LucideProps, \"ref\"> & RefAttributes<SVGSVGElement>\n >\n> = {\n link: Link,\n cast: MessageCircle,\n miniapp: LayoutGrid,\n token: Coins,\n farcasterProfile: User,\n};\n\nexport const adCardLabel: Record<AdType, string> = {\n link: \"Link\",\n cast: \"Cast\",\n miniapp: \"Miniapp\",\n token: \"Token\",\n farcasterProfile: \"Profile\",\n};\n\nexport const adlandApiUrl =\n process.env.NODE_ENV === \"development\"\n ? \"http://localhost:3069\"\n : \"https://api.adland.space\";\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/components/Ad.tsx","../src/fetch.ts","../src/hooks/useAdContext.ts","../src/hooks/useFetch.ts","../src/utils/fetchCache.ts","../src/utils/ad-actions.ts","../src/utils/ad-fields.ts","../src/utils/constants.ts"],"sourcesContent":["import { SlotsChain } from \"@0xslots/sdk\";\nimport type { AdData } from \"@adland/data\";\nimport { useCallback, useMemo, useRef } from \"react\";\n\nimport { createReadClient, fetchAdFromURI, fetchMetadataURI } from \"../fetch\";\nimport { AdContext, useAd } from \"../hooks/useAdContext\";\nimport { useFetch } from \"../hooks/useFetch\";\nimport { AdDataQueryError, type AdProps } from \"../types\";\nimport { performAdAction, performEmptyAdAction } from \"../utils/ad-actions\";\nimport { getAdDescription, getAdImage, getAdTitle, getAdType } from \"../utils/ad-fields\";\nimport { adCardIcon, adCardLabel } from \"../utils/constants\";\n\n// ─── Root component ──────────────────────────────────────────────────────────\n\n/**\n * Root Ad component — compound pattern.\n *\n * @example\n * ```tsx\n * <Ad slot=\"0xabc...123\" className=\"rounded-md border p-3\">\n * <AdImage className=\"size-10 rounded-md\" />\n * <AdTitle className=\"text-sm font-medium\" />\n * <AdDescription className=\"text-xs text-muted-foreground\" />\n * <AdBadge />\n * </Ad>\n * ```\n */\nexport function Ad({\n slot,\n data: staticData,\n chainId = SlotsChain.BASE,\n rpcUrl,\n baseLinkUrl = \"https://app.0xslots.org\",\n children,\n ...props\n}: AdProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n const client = useMemo(\n () => (slot ? createReadClient(chainId, rpcUrl) : null),\n [slot, chainId, rpcUrl],\n );\n\n const {\n data: fetchedData,\n isLoading,\n error,\n } = useFetch<AdData>(\n `ad-data-${slot}`,\n async () => {\n if (!client || !slot) throw new Error(AdDataQueryError.NO_AD);\n const uri = await fetchMetadataURI(client, slot);\n if (!uri) {\n console.info(\"[Ad] no metadata URI found for slot\", slot);\n return null;\n }\n return fetchAdFromURI(uri);\n },\n { enabled: !!slot && !staticData },\n );\n\n const adData = staticData ?? fetchedData;\n\n const isEmpty =\n !adData &&\n !isLoading &&\n (error instanceof Error\n ? error.message === AdDataQueryError.NO_AD\n : !error);\n\n const onClick = useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n const target = e.target as HTMLElement;\n const isInteractive =\n target.tagName === \"A\" ||\n target.tagName === \"BUTTON\" ||\n target.closest(\"a\") !== null ||\n target.closest(\"button\") !== null;\n if (isInteractive) return;\n\n if (adData) {\n performAdAction(adData);\n } else if (isEmpty && slot) {\n performEmptyAdAction(slot, chainId, baseLinkUrl);\n }\n },\n [adData, isEmpty, slot, chainId, baseLinkUrl],\n );\n\n return (\n <AdContext.Provider\n value={{\n data: adData ?? null,\n isLoading: !!slot && !staticData && isLoading,\n error,\n isEmpty,\n slot,\n baseLinkUrl,\n chainId,\n }}\n >\n <div ref={ref} onClick={onClick} {...props}>\n {children}\n </div>\n </AdContext.Provider>\n );\n}\n\n// ─── Sub-components ──────────────────────────────────────────────────────────\n\nexport interface AdImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {\n fallback?: React.ReactNode;\n}\n\nexport function AdImage({ fallback, ...props }: AdImageProps) {\n const { data } = useAd();\n const src = getAdImage(data);\n if (!src) return fallback ? <>{fallback}</> : null;\n return <img src={src} alt=\"\" {...props} />;\n}\n\nexport interface AdTitleProps extends React.HTMLAttributes<HTMLParagraphElement> {\n fallback?: React.ReactNode;\n}\n\nexport function AdTitle({ fallback, children, ...props }: AdTitleProps) {\n const { data } = useAd();\n const title = getAdTitle(data);\n if (!title) return fallback ? <>{fallback}</> : null;\n return <p {...props}>{children ?? title}</p>;\n}\n\nexport interface AdDescriptionProps extends React.HTMLAttributes<HTMLParagraphElement> {\n fallback?: React.ReactNode;\n}\n\nexport function AdDescription({ fallback, children, ...props }: AdDescriptionProps) {\n const { data } = useAd();\n const description = getAdDescription(data);\n if (!description) return fallback ? <>{fallback}</> : null;\n return <p {...props}>{children ?? description}</p>;\n}\n\nexport interface AdBadgeProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nexport function AdBadge({ children, ...props }: AdBadgeProps) {\n const { data } = useAd();\n const type = getAdType(data);\n if (!type) return null;\n const Icon = adCardIcon[type];\n const label = adCardLabel[type];\n return (\n <span {...props}>\n {children ?? (\n <>\n {Icon && <Icon className=\"size-3\" />}\n {label}\n </>\n )}\n </span>\n );\n}\n\nexport interface AdLabelProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nexport function AdLabel({ children, ...props }: AdLabelProps) {\n return <span {...props}>{children ?? \"AD\"}</span>;\n}\n\n// ─── State components ────────────────────────────────────────────────────────\n\nexport interface AdStatusProps extends React.HTMLAttributes<HTMLDivElement> {\n children?: React.ReactNode;\n}\n\nexport function AdLoading({ children, ...props }: AdStatusProps) {\n const { isLoading } = useAd();\n if (!isLoading) return null;\n return <div {...props}>{children ?? \"Loading...\"}</div>;\n}\n\nexport function AdEmpty({ children, ...props }: AdStatusProps) {\n const { isEmpty } = useAd();\n if (!isEmpty) return null;\n return <div {...props}>{children ?? \"Your ad here\"}</div>;\n}\n\nexport function AdError({ children, ...props }: AdStatusProps) {\n const { error, isEmpty } = useAd();\n if (!error || isEmpty) return null;\n return <div {...props}>{children ?? \"Error loading ad\"}</div>;\n}\n\nexport function AdLoaded({ children, ...props }: AdStatusProps) {\n const { data } = useAd();\n if (!data) return null;\n return <div {...props}>{children}</div>;\n}\n","import { SlotsClient, type SlotsChain } from \"@0xslots/sdk\";\nimport { type Address, createPublicClient, http } from \"viem\";\nimport { base, baseSepolia } from \"viem/chains\";\n\nimport { AdDataQueryError } from \"./types\";\n\nconst IPFS_GATEWAY = \"https://amethyst-representative-mandrill-369.mypinata.cloud/ipfs/\";\n\nconst viemChains: Record<number, typeof base> = {\n 8453: base,\n 84532: baseSepolia,\n};\n\n/**\n * Create a read-only SlotsClient for a given chain.\n */\nexport function createReadClient(\n chainId: SlotsChain,\n rpcUrl?: string,\n): SlotsClient {\n const chain = viemChains[chainId];\n if (!chain) throw new Error(`Unsupported chain: ${chainId}`);\n\n const publicClient = createPublicClient({\n chain,\n transport: http(rpcUrl),\n });\n\n return new SlotsClient({ chainId, publicClient });\n}\n\n/**\n * Fetch ad content from a metadata URI (IPFS or HTTP)\n */\nexport const fetchAdFromURI = async (uri: string) => {\n if (!uri) throw new Error(AdDataQueryError.NO_AD);\n\n const url = uri.startsWith(\"ipfs://\")\n ? `${IPFS_GATEWAY}${uri.slice(7)}`\n : uri;\n\n const res = await fetch(url, {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n });\n\n if (!res.ok) {\n if (res.status === 404) throw new Error(AdDataQueryError.NO_AD);\n throw new Error(AdDataQueryError.ERROR);\n }\n\n const data = await res.json();\n if (data.error) throw new Error(data.error);\n\n return data;\n};\n\n/**\n * Fetch the metadata URI for a slot using the SDK.\n */\nexport const fetchMetadataURI = async (\n client: SlotsClient,\n slotAddress: string,\n): Promise<string> => {\n const info = await client.getSlotInfo(slotAddress as Address);\n const moduleAddress = (info as { module: Address }).module;\n\n if (\n !moduleAddress ||\n moduleAddress === \"0x0000000000000000000000000000000000000000\"\n ) {\n return \"\";\n }\n\n return client.modules.metadata.getURI(\n moduleAddress,\n slotAddress as Address,\n );\n};\n","import type { SlotsChain } from \"@0xslots/sdk\";\nimport type { AdData } from \"@adland/data\";\nimport { createContext, useContext } from \"react\";\n\nexport interface AdContextValue {\n data: AdData | null;\n isLoading: boolean;\n error: unknown;\n isEmpty: boolean;\n slot?: string;\n baseLinkUrl: string;\n chainId: SlotsChain;\n}\n\nexport const AdContext = createContext<AdContextValue | null>(null);\n\nexport function useAd(): AdContextValue {\n const ctx = useContext(AdContext);\n if (!ctx) throw new Error(\"useAd must be used within an <Ad> component\");\n return ctx;\n}\n","import { useEffect, useState } from \"react\";\nimport FetchCache from \"../utils/fetchCache\";\n\ntype Status = \"idle\" | \"loading\" | \"success\" | \"error\";\n\nconst globalCache = new FetchCache();\n\nexport const fetchCache = {\n clear: () => globalCache.clear(),\n};\n\nexport function useFetch<T>(\n key: string,\n fetcher: () => Promise<T>,\n opts?: {\n enabled?: boolean;\n ttl?: number; // ms\n },\n) {\n const { enabled = true, ttl = 0 } = opts ?? {};\n\n // Get cached data from global cache\n const getCachedData = (): T | null => {\n return globalCache.get<T>(key, ttl || undefined);\n };\n\n const hasCachedData = () => {\n return globalCache.has(key, ttl || undefined);\n };\n\n // Check if there's an active fetch for this key (dedupe concurrent requests)\n const getActiveFetch = (): Promise<T> | undefined => {\n return globalCache.getActiveFetch<T>(key);\n };\n\n const cachedData = getCachedData();\n const [data, setData] = useState<T | null>(cachedData);\n const [error, setError] = useState<unknown>(null);\n // If we have cached data, start with success status to avoid showing loader\n const [status, setStatus] = useState<Status>(cachedData ? \"success\" : \"idle\");\n\n const refetch = async () => {\n // ALWAYS check cache first - never show loading if we have valid cached data\n const cached = getCachedData();\n if (cached) {\n // Already have valid cached data, ensure state is correct\n setData(cached);\n setStatus(\"success\");\n return cached;\n }\n\n // Check if there's already an active fetch for this key (dedupe)\n const activeFetch = getActiveFetch();\n if (activeFetch) {\n try {\n const res = await activeFetch;\n setData(res);\n setStatus(\"success\");\n return res;\n } catch (e) {\n setError(e);\n setStatus(\"error\");\n throw e;\n }\n }\n\n // Only set loading if we actually need to fetch\n setStatus(\"loading\");\n setError(null);\n\n try {\n // Create fetch promise and store it for deduplication\n const fetchPromise = fetcher();\n globalCache.setActiveFetch(key, fetchPromise);\n\n const res = await fetchPromise;\n globalCache.set(key, res);\n setData(res);\n setStatus(\"success\");\n return res;\n } catch (e) {\n setError(e);\n setStatus(\"error\");\n throw e;\n }\n };\n\n useEffect(() => {\n if (!enabled) return;\n\n const cached = getCachedData();\n\n if (cached) {\n setData(cached);\n setStatus(\"success\");\n return;\n }\n\n const activeFetch = getActiveFetch();\n if (activeFetch) {\n setStatus(\"loading\");\n activeFetch\n .then((res) => {\n setData(res);\n setStatus(\"success\");\n })\n .catch((e) => {\n setError(e);\n setStatus(\"error\");\n });\n return;\n }\n\n if (status !== \"loading\" && status !== \"success\") {\n refetch();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [key, enabled]);\n\n const hasValidCache = hasCachedData();\n const isLoading = status === \"loading\" && !hasValidCache;\n\n return {\n data,\n error,\n status,\n isIdle: status === \"idle\",\n isLoading,\n isSuccess: status === \"success\",\n isError: status === \"error\",\n refetch,\n };\n}\n","class FetchCache {\n private cache = new Map<string, { data: unknown; ts: number }>();\n private activeFetches = new Map<string, Promise<unknown>>();\n\n get<T>(key: string, ttl?: number): T | null {\n const cached = this.cache.get(key);\n if (!cached) return null;\n\n if (ttl && Date.now() - cached.ts > ttl) {\n // Cache expired, remove it\n this.cache.delete(key);\n return null;\n }\n\n return cached.data as T;\n }\n\n has(key: string, ttl?: number): boolean {\n const cached = this.cache.get(key);\n if (!cached) return false;\n\n if (ttl && Date.now() - cached.ts > ttl) {\n this.cache.delete(key);\n return false;\n }\n\n return true;\n }\n\n set<T>(key: string, data: T): void {\n this.cache.set(key, { data, ts: Date.now() });\n }\n\n getActiveFetch<T>(key: string): Promise<T> | undefined {\n return this.activeFetches.get(key) as Promise<T> | undefined;\n }\n\n setActiveFetch<T>(key: string, promise: Promise<T>): void {\n this.activeFetches.set(key, promise);\n promise.finally(() => {\n this.activeFetches.delete(key);\n });\n }\n\n clear(): void {\n this.cache.clear();\n this.activeFetches.clear();\n }\n}\n\nexport default FetchCache;\n","import type { SlotsChain } from \"@0xslots/sdk\";\nimport type { AdData } from \"@adland/data\";\nimport sdk from \"@farcaster/miniapp-sdk\";\nimport { getAddress } from \"viem\";\n\n// Cache the miniapp check at module level — resolved once, sync thereafter\nlet _isMiniApp: boolean | null = null;\nconst _miniAppPromise = sdk\n .isInMiniApp()\n .then((v) => {\n _isMiniApp = v;\n return v;\n })\n .catch(() => {\n _isMiniApp = false;\n return false;\n });\n\nasync function isMiniApp(): Promise<boolean> {\n if (_isMiniApp !== null) return _isMiniApp;\n return _miniAppPromise;\n}\n\nexport function performAdAction(adData: AdData) {\n try {\n switch (adData.type) {\n case \"link\":\n sdk.actions.openUrl(adData.data.url);\n break;\n case \"cast\":\n sdk.actions.viewCast({ hash: adData.data.hash });\n break;\n case \"miniapp\":\n sdk.actions.openMiniApp({ url: adData.data.url });\n break;\n case \"token\": {\n const address = adData.data.address;\n const chainId = adData.data.chainId;\n const buyToken = `eip155:${chainId}/erc20:${getAddress(address)}`;\n sdk.actions.swapToken({ buyToken });\n break;\n }\n case \"farcasterProfile\":\n sdk.actions.viewProfile({\n fid: Number.parseInt(adData.data.fid, 10),\n });\n break;\n }\n } catch (err) {\n // Fallback for web (non-miniapp) context\n if (adData.type === \"link\" || adData.type === \"miniapp\") {\n window.open(adData.data.url, \"_blank\");\n } else {\n console.error(\"[@adland/react] Failed to perform ad action:\", err);\n }\n }\n}\n\nexport async function performEmptyAdAction(\n slot: string,\n chainId: SlotsChain,\n baseLinkUrl: string,\n) {\n const url = `${baseLinkUrl}/slots/${slot}?chain=${chainId}`;\n if (await isMiniApp()) {\n sdk.actions.openMiniApp({ url });\n } else {\n window.open(url, \"_blank\");\n }\n}\n","import type { AdData, AdType } from \"@adland/data\";\n\nconst IMAGE_KEYS = [\"image\", \"icon\", \"pfpUrl\", \"logoURI\", \"imageUrl\"] as const;\nconst TITLE_KEYS = [\"title\", \"displayName\", \"username\", \"name\", \"symbol\"] as const;\nconst DESC_KEYS = [\"description\", \"bio\", \"text\", \"name\"] as const;\n\nfunction flatFields(data: AdData): Record<string, unknown> {\n return { ...data.data, ...(data.metadata ?? {}) };\n}\n\nexport function getAdImage(data: AdData | null): string | null {\n if (!data) return null;\n const fields = flatFields(data);\n for (const key of IMAGE_KEYS) {\n const v = fields[key];\n if (typeof v === \"string\" && v) return v;\n }\n return null;\n}\n\nexport function getAdTitle(data: AdData | null): string | null {\n if (!data) return null;\n const fields = flatFields(data);\n for (const key of TITLE_KEYS) {\n const v = fields[key];\n if (typeof v === \"string\" && v) return v;\n }\n return null;\n}\n\nexport function getAdDescription(data: AdData | null): string | null {\n if (!data) return null;\n const fields = flatFields(data);\n const title = getAdTitle(data);\n for (const key of DESC_KEYS) {\n const v = fields[key];\n if (typeof v === \"string\" && v && v !== title) return v;\n }\n return null;\n}\n\nexport function getAdType(data: AdData | null): AdType | null {\n if (!data) return null;\n return data.type as AdType;\n}\n","import { AdType } from \"@adland/data\";\nimport { ForwardRefExoticComponent, RefAttributes } from \"react\";\nimport {\n Link,\n MessageCircle,\n LayoutGrid,\n LucideProps,\n Coins,\n User,\n} from \"lucide-react\";\n\nexport const adCardIcon: Record<\n AdType,\n ForwardRefExoticComponent<\n Omit<LucideProps, \"ref\"> & RefAttributes<SVGSVGElement>\n >\n> = {\n link: Link,\n cast: MessageCircle,\n miniapp: LayoutGrid,\n token: Coins,\n farcasterProfile: User,\n};\n\nexport const adCardLabel: Record<AdType, string> = {\n link: \"Link\",\n cast: \"Cast\",\n miniapp: \"Miniapp\",\n token: \"Token\",\n farcasterProfile: \"Profile\",\n};\n\nexport const adlandApiUrl =\n process.env.NODE_ENV === \"development\"\n ? \"http://localhost:3069\"\n : \"https://api.adland.space\";\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adland/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"lucide-react": "0.561.0",
|
|
38
38
|
"tsup": "^8.0.1",
|
|
39
39
|
"viem": "^2.0.0",
|
|
40
|
-
"@
|
|
41
|
-
"@
|
|
40
|
+
"@adland/data": "0.14.2",
|
|
41
|
+
"@0xslots/sdk": "0.11.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@typescript-eslint/eslint-plugin": "^7.13.1",
|