From 9f668cbdaf4021983c129d0bc538b6fcc68d3c9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Kvasnic=CC=8Ca=CC=81k?= Date: Tue, 7 Jan 2025 12:14:23 +0100 Subject: [PATCH] feat: update dependencies, add new methods --- .../app/components/frame-app-debugger.tsx | 16 ++++ packages/debugger/package.json | 4 +- packages/frames.js/package.json | 6 +- packages/render/package.json | 10 +- packages/render/src/frame-app/types.ts | 33 +++++-- packages/render/src/use-frame-app.ts | 82 ++++++++++++----- yarn.lock | 91 +++++++++++-------- 7 files changed, 161 insertions(+), 81 deletions(-) diff --git a/packages/debugger/app/components/frame-app-debugger.tsx b/packages/debugger/app/components/frame-app-debugger.tsx index e86b1940..7149fb44 100644 --- a/packages/debugger/app/components/frame-app-debugger.tsx +++ b/packages/debugger/app/components/frame-app-debugger.tsx @@ -23,6 +23,8 @@ import type { FramePrimaryButton, ResolveClientFunction, } from "@frames.js/render/frame-app/types"; +import { useConfig } from "wagmi"; +import type { EIP6963ProviderInfo } from "@farcaster/frame-sdk"; type TabValues = "events" | "console" | "notifications"; @@ -52,6 +54,7 @@ export function FrameAppDebugger({ farcasterSigner, onClose, }: FrameAppDebuggerProps) { + const config = useConfig(); const farcasterSignerRef = useRef(farcasterSigner); farcasterSignerRef.current = farcasterSigner; const frameAppNotificationManager = useFrameAppNotificationsManager({ @@ -122,6 +125,7 @@ export function FrameAppDebugger({ } : { type: "cast_embed", + embed: "", cast: fallbackFrameContext.castId, }, farcasterSigner, @@ -233,6 +237,18 @@ export function FrameAppDebugger({ throw e; } }, + onEIP6963RequestProviderRequested({ endpoint }) { + if (!config._internal.mipd) { + return; + } + + config._internal.mipd.getProviders().map((providerInfo) => { + endpoint.emit({ + event: "eip6963:announceProvider", + info: providerInfo.info as EIP6963ProviderInfo, + }); + }); + }, }); return ( diff --git a/packages/debugger/package.json b/packages/debugger/package.json index ccfe419e..335699eb 100644 --- a/packages/debugger/package.json +++ b/packages/debugger/package.json @@ -18,14 +18,14 @@ "dependencies": { "@upstash/redis": "^1.34.3", "@lens-protocol/client": "^2.3.2", - "@farcaster/frame-sdk": "^0.0.20", + "@farcaster/frame-sdk": "^0.0.26", "@xmtp/xmtp-js": "^12.0.0", "is-port-reachable": "^4.0.0", "next": "14.1.4", "open": "^10.0.3", "react": "^18.2.0", "react-dom": "^18.2.0", - "zod": "^3.23.8", + "zod": "^3.24.1", "yargs": "^17.7.2" }, "engines": { diff --git a/packages/frames.js/package.json b/packages/frames.js/package.json index ec0ad213..57e62fe6 100644 --- a/packages/frames.js/package.json +++ b/packages/frames.js/package.json @@ -419,13 +419,13 @@ "react-dom": "^18.2.0" }, "dependencies": { - "@farcaster/frame-core": "^0.0.19", - "@farcaster/frame-node": "^0.0.8", + "@farcaster/frame-core": "^0.0.24", + "@farcaster/frame-node": "^0.0.13", "@vercel/og": "^0.6.3", "cheerio": "^1.0.0-rc.12", "protobufjs": "^7.2.6", "viem": "^2.7.8", "type-fest": "^4.28.1", - "zod": "^3.23.8" + "zod": "^3.24.1" } } diff --git a/packages/render/package.json b/packages/render/package.json index 472eb571..86b07aad 100644 --- a/packages/render/package.json +++ b/packages/render/package.json @@ -336,7 +336,7 @@ "src" ], "devDependencies": { - "@farcaster/frame-host-react-native": "^0.0.14", + "@farcaster/frame-host-react-native": "^0.0.19", "@lens-protocol/client": "^2.3.2", "@rainbow-me/rainbowkit": "^2.1.2", "@remix-run/node": "^2.8.1", @@ -352,7 +352,7 @@ }, "license": "MIT", "peerDependencies": { - "@farcaster/frame-host-react-native": "^0.0.14", + "@farcaster/frame-host-react-native": "^0.0.19", "@lens-protocol/client": "^2.0.0", "@rainbow-me/rainbowkit": "^2.1.2", "@types/react": "^18.2.0", @@ -368,10 +368,10 @@ }, "dependencies": { "@farcaster/core": "^0.15.6", - "@farcaster/frame-host": "^0.0.19", + "@farcaster/frame-host": "^0.0.24", "@noble/ed25519": "^2.0.0", "frames.js": "^0.21.0", - "ox": "^0.4.0", - "zod": "^3.23.8" + "ox": "^0.4.4", + "zod": "^3.24.1" } } diff --git a/packages/render/src/frame-app/types.ts b/packages/render/src/frame-app/types.ts index 500f0b58..73a00211 100644 --- a/packages/render/src/frame-app/types.ts +++ b/packages/render/src/frame-app/types.ts @@ -1,14 +1,15 @@ -import type { HostEndpoint } from "@farcaster/frame-host"; import type { - AddFrameResult, - FrameContext, - SetPrimaryButton, -} from "@farcaster/frame-sdk"; + HostEndpoint, + Context, + SetPrimaryButtonOptions, + AddFrame, + FrameHost, +} from "@farcaster/frame-host"; import type { ParseFramesV2ResultWithFrameworkDetails } from "frames.js/frame-parsers"; import type { Provider } from "ox/Provider"; import type { Default as DefaultRpcSchema, ExtractRequest } from "ox/RpcSchema"; -export type FrameClientConfig = FrameContext["client"]; +export type FrameClientConfig = Context.ClientContext; export type SendTransactionRpcRequest = ExtractRequest< DefaultRpcSchema, @@ -62,16 +63,32 @@ export type SharedEthProviderEventHandlers = { onSignTypedDataRequest: OnSignTypedDataRequestFunction; }; -export type FramePrimaryButton = Parameters[0]; +export type FramePrimaryButton = SetPrimaryButtonOptions; export type OnPrimaryButtonSetFunction = ( options: FramePrimaryButton, pressedCallback: () => void ) => void; +/** + * Returns false if user rejected the request, otherwise it returns the notification details + */ export type OnAddFrameRequestedFunction = ( frame: ParseFramesV2ResultWithFrameworkDetails -) => Promise>; +) => Promise>; + +export type OnEIP6963RequestProviderRequestedFunctionOptions = { + endpoint: HostEndpoint; +}; + +/** + * Function that must emit eip6963:announceProvider event on endpoint to announce available providers + */ +export type OnEIP6963RequestProviderRequestedFunction = ( + options: OnEIP6963RequestProviderRequestedFunctionOptions +) => unknown; + +export type OnViewProfileFunction = FrameHost["viewProfile"]; /** * Function called when the frame app is being loaded and we need to resolve the client that renders the frame app diff --git a/packages/render/src/use-frame-app.ts b/packages/render/src/use-frame-app.ts index 90efcbd9..a892d207 100644 --- a/packages/render/src/use-frame-app.ts +++ b/packages/render/src/use-frame-app.ts @@ -1,10 +1,6 @@ -import type { - FrameHost, - FrameLocationContext, - FrameLocationContextLauncher, -} from "@farcaster/frame-sdk"; import type { ParseFramesV2ResultWithFrameworkDetails } from "frames.js/frame-parsers"; -import type { HostEndpoint } from "@farcaster/frame-host"; +import type { FrameHost, HostEndpoint, Context } from "@farcaster/frame-host"; +import { AddFrame } from "@farcaster/frame-host"; import { useMemo } from "react"; import { useFreshRef } from "./hooks/use-fresh-ref"; import type { FarcasterSignerState } from "./farcaster"; @@ -14,10 +10,12 @@ import type { FrameClientConfig, HostEndpointEmitter, OnAddFrameRequestedFunction, + OnEIP6963RequestProviderRequestedFunction, OnPrimaryButtonSetFunction, OnSendTransactionRequestFunction, OnSignMessageRequestFunction, OnSignTypedDataRequestFunction, + OnViewProfileFunction, ResolveClientFunction, } from "./frame-app/types"; import { assertNever } from "./assert-never"; @@ -69,6 +67,25 @@ const defaultOnSignTypedDataRequest: OnSignTypedDataRequestFunction = () => { return Promise.resolve(true); }; +const defaultViewProfile: OnViewProfileFunction = () => { + // eslint-disable-next-line no-console -- provide feedback to the developer + console.warn( + "@frames.js/render/use-frame-app", + "onViewProfile not implemented" + ); + + return Promise.reject(new Error("onViewProfile not implemented")); +}; + +const defaultEIP6963RequestProviderRequested: OnEIP6963RequestProviderRequestedFunction = + () => { + // eslint-disable-next-line no-console -- provide feedback to the developer + console.warn( + "@frames.js/render/use-frame-app", + "onEIP6963RequestProviderRequested not implemented" + ); + }; + export type UseFrameAppOptions = { /** * @example @@ -100,7 +117,7 @@ export type UseFrameAppOptions = { * * @defaultValue launcher context */ - location?: FrameLocationContext; + location?: Context.LocationContext; /** * Either: * @@ -164,6 +181,16 @@ export type UseFrameAppOptions = { * If the method has been called during the session more than once it immediatelly rejects */ onAddFrameRequested?: OnAddFrameRequestedFunction; + /** + * Called when app calls `viewProfile` method. + */ + onViewProfile?: OnViewProfileFunction; + /** + * Called when app calls `eip6963RequestProvider` method. + * + * It will announce the provider to the frame app once this function returns the info + */ + onEIP6963RequestProviderRequested?: OnEIP6963RequestProviderRequestedFunction; /** * Enabled debugging * @@ -201,7 +228,7 @@ export type UseFrameAppReturn = status: "error"; }; -const defaultLocation: FrameLocationContextLauncher = { +const defaultLocation: Context.LauncherLocationContext = { type: "launcher", }; @@ -226,6 +253,8 @@ export function useFrameApp({ onSendTransactionRequest = defaultOnSendTransactionRequest, onSignMessageRequest = defaultOnSignMessageRequest, onSignTypedDataRequest = defaultOnSignTypedDataRequest, + onViewProfile = defaultViewProfile, + onEIP6963RequestProviderRequested = defaultEIP6963RequestProviderRequested, }: UseFrameAppOptions): UseFrameAppReturn { const providerRef = useFreshRef(provider); const debugRef = useFreshRef(debug); @@ -234,6 +263,10 @@ export function useFrameApp({ const closeRef = useFreshRef(onClose); const onOpenUrlRef = useFreshRef(onOpenUrl); const onPrimaryButtonSetRef = useFreshRef(onPrimaryButtonSet); + const onViewProfileRef = useFreshRef(onViewProfile); + const onEIP6963RequestProviderRequestedRef = useFreshRef( + onEIP6963RequestProviderRequested + ); const farcasterSignerRef = useFreshRef(farcasterSigner); const onAddFrameRequestedRef = useFreshRef(onAddFrameRequested); const addFrameRequestsCacheRef = useFreshRef(addFrameRequestsCache); @@ -307,10 +340,7 @@ export function useFrameApp({ reason: "invalid_domain_manifest", }); - return { - added: false, - reason: "invalid_domain_manifest", - }; + throw new AddFrame.InvalidDomainManifest(); } if ( @@ -325,21 +355,18 @@ export function useFrameApp({ reason: "rejected_by_user", }); - return { - added: false, - reason: "rejected_by_user", - }; + throw new AddFrame.RejectedByUser(); } - const added = await onAddFrameRequestedRef.current(frame); + const result = await onAddFrameRequestedRef.current(frame); - logDebug("onAddFrameRequested() called", added); + logDebug("onAddFrameRequested() called", result); addFrameRequestsCacheRef.current.add( frame.frame.button.action.url ); - if (!added) { + if (!result) { logDebug("Frame add request rejected by user"); endpoint.emit({ @@ -347,18 +374,15 @@ export function useFrameApp({ reason: "rejected_by_user", }); - return { - added: false, - reason: "rejected_by_user", - }; + throw new AddFrame.RejectedByUser(); } endpoint.emit({ event: "frame_added", - notificationDetails: added.notificationDetails, + notificationDetails: result.notificationDetails, }); - return added; + return result; }, close() { logDebug("sdk.close() called"); @@ -373,6 +397,9 @@ export function useFrameApp({ // @ts-expect-error -- type mismatch return providerRef.current.request(parameters); }, + eip6963RequestProvider() { + onEIP6963RequestProviderRequestedRef.current({ endpoint }); + }, openUrl(url) { logDebug("sdk.openUrl() called", url); @@ -398,6 +425,9 @@ export function useFrameApp({ // @todo implement throw new Error("not implemented"); }, + viewProfile(options) { + return onViewProfileRef.current(options); + }, }), status: "success", frame: frameResolutionState.frame, @@ -431,5 +461,7 @@ export function useFrameApp({ onOpenUrlRef, readyRef, onPrimaryButtonSetRef, + onViewProfileRef, + onEIP6963RequestProviderRequestedRef, ]); } diff --git a/yarn.lock b/yarn.lock index afa990d1..a493b2df 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2403,47 +2403,50 @@ neverthrow "^6.0.0" viem "^2.17.4" -"@farcaster/frame-core@^0.0.19": - version "0.0.19" - resolved "https://registry.yarnpkg.com/@farcaster/frame-core/-/frame-core-0.0.19.tgz#76621fe6e207c3a5c78a22aa679bbbd7beafdd11" - integrity sha512-/0XjVZa/rUuUR16GVhhKnAQI33SXI61bB24jNA1DD0L0ytcKsM14wBptW9CF4RDiYIXxtt4mXmnQ+rMhO38RcA== +"@farcaster/frame-core@0.0.24", "@farcaster/frame-core@^0.0.24": + version "0.0.24" + resolved "https://registry.yarnpkg.com/@farcaster/frame-core/-/frame-core-0.0.24.tgz#35c2403f561a74b6551e3032d6d57a730c3dc413" + integrity sha512-iO/Jxz6mZBVUoLIY753Id5Yhn6DHBakQkIBXf0mreAcnjPGCMvKx/0xKEM3ns3M801PqoX7VLYO4q+kKxYzQ0A== dependencies: - ox "^0.4.0" - zod "^3.23.8" + ox "^0.4.4" + zod "^3.24.1" -"@farcaster/frame-host-react-native@^0.0.14": - version "0.0.14" - resolved "https://registry.yarnpkg.com/@farcaster/frame-host-react-native/-/frame-host-react-native-0.0.14.tgz#0919eb1466dfd497a29d0965a5e5c6e7e25336b1" - integrity sha512-iPjysnQ5H8aoWJWIdJIWPaBP9wo7s9fLNPy56RZXMsrqrkWDskOYfgND5CRZJzA9JDvvgLjqJ+XYdGPVXlKyGQ== +"@farcaster/frame-host-react-native@^0.0.19": + version "0.0.19" + resolved "https://registry.yarnpkg.com/@farcaster/frame-host-react-native/-/frame-host-react-native-0.0.19.tgz#7e809d5cd9f6a264aac165360cadc90bf650c79b" + integrity sha512-WH5nQSGPiu99lE0L64tIa6BcfVelbT34XzYo89eEgsAqPmlGRnnHJwQAxlWSAXTHYhaXWpIQMC3u1a6KsQBQCw== dependencies: - "@farcaster/frame-host" "^0.0.19" - ox "^0.4.0" + "@farcaster/frame-core" "0.0.24" + "@farcaster/frame-host" "0.0.24" + ox "^0.4.4" -"@farcaster/frame-host@^0.0.19": - version "0.0.19" - resolved "https://registry.yarnpkg.com/@farcaster/frame-host/-/frame-host-0.0.19.tgz#7e44bc6df2d86bb6f210b51189676558ffe414ef" - integrity sha512-4Svhipw24PAcux4vCHlXA6L3sVi248Ad4bDuXVgqvOEgQ3Ue1Ic4iDQ/bgF+LG3/hLh5UvYJ4csz0xOEwRNT0Q== +"@farcaster/frame-host@0.0.24", "@farcaster/frame-host@^0.0.24": + version "0.0.24" + resolved "https://registry.yarnpkg.com/@farcaster/frame-host/-/frame-host-0.0.24.tgz#8e97b3476443c25b33e8f4cd1948ad912e4deb21" + integrity sha512-4l9FS7LjEYRjOmNnGFvYXnnQnsW8VGrQ6ECIYZjxdAglP63B9nCBmH0UhhkeKrQA+z/HmwIqOneh8LRjj4J5Bg== dependencies: - "@farcaster/frame-core" "^0.0.19" - ox "^0.4.0" + "@farcaster/frame-core" "0.0.24" + ox "^0.4.4" -"@farcaster/frame-node@^0.0.8": - version "0.0.8" - resolved "https://registry.yarnpkg.com/@farcaster/frame-node/-/frame-node-0.0.8.tgz#14c5c8c527a793eefbffac5b03570ed3925c95fd" - integrity sha512-AE3xFVj7Tu2nfVASka0wagR9plaZ2UA1ezzh9aHA4f6GU/gVl+SdfZzAn4uOqgEPl3D2g7W4p0tPRYZVwMJfdg== +"@farcaster/frame-node@^0.0.13": + version "0.0.13" + resolved "https://registry.yarnpkg.com/@farcaster/frame-node/-/frame-node-0.0.13.tgz#ba9d37358589b263aa9566cf1763b1eb528672e6" + integrity sha512-99rhLSpyhKKnWFh8eWx8N5tTYEToFkIzg9r5lRm2bvfsZaT0zXr/cA+G9pWDFZyodfoyS/cLHS46Qsm8P52uTg== dependencies: - "@farcaster/frame-core" "^0.0.19" - ox "^0.4.0" + "@farcaster/frame-core" "0.0.24" + "@noble/curves" "^1.7.0" + ox "^0.4.4" + zod "^3.24.1" -"@farcaster/frame-sdk@^0.0.20": - version "0.0.20" - resolved "https://registry.yarnpkg.com/@farcaster/frame-sdk/-/frame-sdk-0.0.20.tgz#253dba9a1aba23c63e01617720835fe6b2b0880b" - integrity sha512-9EbB3A9V1ZSH4NvhHVbylcDVNevJqpuGkwz4I+0bKF2936qxvMlcWclDZVEmfO/woYH0ZQgy47YYRIiS3YpIQw== +"@farcaster/frame-sdk@^0.0.26": + version "0.0.26" + resolved "https://registry.yarnpkg.com/@farcaster/frame-sdk/-/frame-sdk-0.0.26.tgz#2cf5c5e9e8ecdbdbc244e55f41129fc1caa9b88c" + integrity sha512-tOoJcJLXXezjmP0gg/MOU/mCjNdWyL+j99XMylYCovel1etDQjLovGamVex8A6eELryLZ4LElV9AIbxP/i9IfA== dependencies: - "@farcaster/frame-core" "^0.0.19" + "@farcaster/frame-core" "0.0.24" comlink "^4.4.2" eventemitter3 "^5.0.1" - ox "^0.4.0" + ox "^0.4.4" "@fastify/busboy@^2.0.0": version "2.1.1" @@ -3549,6 +3552,13 @@ dependencies: "@noble/hashes" "1.6.0" +"@noble/curves@^1.7.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.8.0.tgz#fe035a23959e6aeadf695851b51a87465b5ba8f7" + integrity sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ== + dependencies: + "@noble/hashes" "1.7.0" + "@noble/curves@~1.4.0": version "1.4.2" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.2.tgz#40309198c76ed71bc6dbf7ba24e81ceb4d0d1fe9" @@ -3586,6 +3596,11 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.6.1.tgz#df6e5943edcea504bac61395926d6fd67869a0d5" integrity sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w== +"@noble/hashes@1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.0.tgz#5d9e33af2c7d04fee35de1519b80c958b2e35e39" + integrity sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w== + "@noble/secp256k1@1.7.1": version "1.7.1" resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" @@ -14854,10 +14869,10 @@ ox@0.1.2: abitype "^1.0.6" eventemitter3 "5.0.1" -ox@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/ox/-/ox-0.4.0.tgz#6c73b27a9f45912888917304d7a81c894856a980" - integrity sha512-F+Q8R/7SZ8AvBcejIV6QUcACLjRuFtSShCkwTuCFWLAN5DoS8dSwiFsDBltvQplEXXNGmAEZCV4HDe7orEDSxA== +ox@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/ox/-/ox-0.4.4.tgz#9d1757c026406e60097680d98ffedf9e3bc1fa0b" + integrity sha512-oJPEeCDs9iNiPs6J0rTx+Y0KGeCGyCAA3zo94yZhm8G5WpOxrwUtn2Ie/Y8IyARSqqY/j9JTKA3Fc1xs1DvFnw== dependencies: "@adraffy/ens-normalize" "^1.10.1" "@noble/curves" "^1.6.0" @@ -19063,10 +19078,10 @@ zod@^3.20.6, zod@^3.22.4: resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff" integrity sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg== -zod@^3.23.8: - version "3.23.8" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d" - integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g== +zod@^3.24.1: + version "3.24.1" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.1.tgz#27445c912738c8ad1e9de1bea0359fa44d9d35ee" + integrity sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A== zustand@4.4.1: version "4.4.1"