diff --git a/.changeset/ten-ducks-applaud.md b/.changeset/ten-ducks-applaud.md new file mode 100644 index 00000000..ee6ad1a7 --- /dev/null +++ b/.changeset/ten-ducks-applaud.md @@ -0,0 +1,5 @@ +--- +"@xmtp/frames-client": minor +--- + +Use new Frames Proxy with support for frameInfo field diff --git a/packages/frames-client/package.json b/packages/frames-client/package.json index 0cd5506a..2fd1800b 100644 --- a/packages/frames-client/package.json +++ b/packages/frames-client/package.json @@ -9,11 +9,7 @@ "js", "ts", "javascript", - "typescript", - "react", - "reactjs", - "react-hooks", - "hooks" + "typescript" ], "homepage": "https://github.com/xmtp/xmtp-web", "bugs": { @@ -67,11 +63,13 @@ }, "dependencies": { "@noble/hashes": "^1.3.3", + "@open-frames/proxy-client": "^0.1.2", "@xmtp/proto": "3.41.0-beta.5", "long": "^5.2.3" }, "devDependencies": { - "@open-frames/types": "^0.0.5", + "@open-frames/proxy": "^0.0.3", + "@open-frames/types": "^0.0.6", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.6", "@xmtp/tsconfig": "workspace:*", diff --git a/packages/frames-client/src/constants.ts b/packages/frames-client/src/constants.ts index 2817cfed..24c94df5 100644 --- a/packages/frames-client/src/constants.ts +++ b/packages/frames-client/src/constants.ts @@ -1,3 +1,3 @@ -export const OPEN_FRAMES_PROXY_URL = "https://open-frames-proxy.fly.dev/"; +export const OPEN_FRAMES_PROXY_URL = "https://frames.xmtp.chat/"; export const PROTOCOL_VERSION = "2024-02-09"; diff --git a/packages/frames-client/src/index.test.ts b/packages/frames-client/src/index.test.ts index def05b14..b6657c43 100644 --- a/packages/frames-client/src/index.test.ts +++ b/packages/frames-client/src/index.test.ts @@ -75,9 +75,27 @@ describe("signFrameAction", () => { async () => { const frameUrl = "https://fc-polls-five.vercel.app/polls/01032f47-e976-42ee-9e3d-3aac1324f4b8"; - const metadata = await framesClient.proxy.readMetadata(frameUrl); expect(metadata).toBeDefined(); + expect(metadata.frameInfo).toMatchObject({ + acceptedClients: { + farcaster: "vNext", + }, + buttons: { + "1": { + label: "Yes", + }, + "2": { + label: "No", + }, + }, + image: { + content: + "https://fc-polls-five.vercel.app/api/image?id=01032f47-e976-42ee-9e3d-3aac1324f4b8", + }, + postUrl: + "https://fc-polls-five.vercel.app/api/vote?id=01032f47-e976-42ee-9e3d-3aac1324f4b8", + }); const signedPayload = await framesClient.signFrameAction({ frameUrl, buttonIndex: 1, diff --git a/packages/frames-client/src/proxy.ts b/packages/frames-client/src/proxy.ts index 1af5b05c..7a7970a9 100644 --- a/packages/frames-client/src/proxy.ts +++ b/packages/frames-client/src/proxy.ts @@ -1,5 +1,5 @@ +import { OpenFramesProxy as BaseProxy } from "@open-frames/proxy-client"; import { OPEN_FRAMES_PROXY_URL } from "./constants"; -import { ApiError } from "./errors"; import type { FramePostPayload, FramesApiRedirectResponse, @@ -7,73 +7,28 @@ import type { } from "./types"; export default class OpenFramesProxy { - baseUrl: string; + inner: BaseProxy; constructor(baseUrl: string = OPEN_FRAMES_PROXY_URL) { - this.baseUrl = baseUrl; + this.inner = new BaseProxy(baseUrl); } - async readMetadata(url: string): Promise { - const response = await fetch( - `${this.baseUrl}?url=${encodeURIComponent(url)}`, - ); - - if (!response.ok) { - throw new ApiError(`Failed to read metadata for ${url}`, response.status); - } - - return (await response.json()) as FramesApiResponse; + readMetadata(url: string) { + return this.inner.readMetadata(url); } - async post( - url: string, - payload: FramePostPayload, - ): Promise { - const response = await fetch( - `${this.baseUrl}?url=${encodeURIComponent(url)}`, - { - method: "POST", - body: JSON.stringify(payload), - headers: { - "Content-Type": "application/json", - }, - }, - ); - - if (!response.ok) { - throw new Error( - `Failed to post to frame: ${response.status} ${response.statusText}`, - ); - } - - return (await response.json()) as FramesApiResponse; + post(url: string, payload: FramePostPayload): Promise { + return this.inner.post(url, payload); } - async postRedirect( + postRedirect( url: string, payload: FramePostPayload, ): Promise { - const response = await fetch( - `${this.baseUrl}redirect?url=${encodeURIComponent(url)}`, - { - method: "POST", - body: JSON.stringify(payload), - headers: { - "Content-Type": "application/json", - }, - }, - ); - - if (!response.ok) { - throw new Error( - `Failed to post to frame: ${response.status} ${response.statusText}`, - ); - } - - return (await response.json()) as FramesApiRedirectResponse; + return this.inner.postRedirect(url, payload); } mediaUrl(url: string): string { - return `${this.baseUrl}media?url=${encodeURIComponent(url)}`; + return this.inner.mediaUrl(url); } } diff --git a/packages/frames-client/src/types.ts b/packages/frames-client/src/types.ts index 4732bd7b..f53041ba 100644 --- a/packages/frames-client/src/types.ts +++ b/packages/frames-client/src/types.ts @@ -1,14 +1,12 @@ import type { OpenFramesUntrustedData } from "@open-frames/types"; +import type { + GetMetadataResponse, + PostRedirectResponse, +} from "@open-frames/proxy-client"; -export type FramesApiResponse = { - url: string; - extractedTags: { [k: string]: string }; -}; +export type FramesApiResponse = GetMetadataResponse; -export type FramesApiRedirectResponse = { - originalUrl: string; - redirectedTo: string; -}; +export type FramesApiRedirectResponse = PostRedirectResponse; export type FramePostUntrustedData = OpenFramesUntrustedData & { walletAddress: string; // Untrusted version of the wallet address diff --git a/packages/frames-client/tsconfig.json b/packages/frames-client/tsconfig.json index 56054a9a..1d523acc 100644 --- a/packages/frames-client/tsconfig.json +++ b/packages/frames-client/tsconfig.json @@ -1,9 +1,4 @@ { "extends": "@xmtp/tsconfig/react-sdk.json", "include": ["src", ".eslintrc.cjs", "vitest.config.ts", "vitest.setup.ts"], - "compilerOptions": { - "paths": { - "@/*": ["./src/*"], - }, - }, } diff --git a/yarn.lock b/yarn.lock index c5a61ed3..bed8a10d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2264,10 +2264,29 @@ __metadata: languageName: node linkType: hard -"@open-frames/types@npm:^0.0.5": - version: 0.0.5 - resolution: "@open-frames/types@npm:0.0.5" - checksum: 256a7e6bea4450616257d7b2207a05bb1cb1124679adc598dac6647f8276dbb273eed73d024e9e51d1302c4dda4f89b1fa8267b21fd4ef17392c4cf4406c7e46 +"@open-frames/proxy-client@npm:^0.1.2": + version: 0.1.2 + resolution: "@open-frames/proxy-client@npm:0.1.2" + checksum: 41c3fe31ac2e8b64b99d88791062a051c87fd0ca1322f4c381a496f6f17beb93adfc91673e015e1d0e465849a33300532840041c23f15bd2839a4bf61c77cab8 + languageName: node + linkType: hard + +"@open-frames/proxy@npm:^0.0.3": + version: 0.0.3 + resolution: "@open-frames/proxy@npm:0.0.3" + dependencies: + cheerio: "npm:^1.0.0-rc.12" + mime: "npm:^4.0.1" + peerDependencies: + typescript: ^5.3.3 + checksum: 5ae3d08cce54c091ad3983021b00ecf314a69128f8217b25d869a81716ecf88b3ec2e5c0ef997ecc2c9fdc19c6f40afcce4229f25a3f07b3ef1d15fc4f69023f + languageName: node + linkType: hard + +"@open-frames/types@npm:^0.0.6": + version: 0.0.6 + resolution: "@open-frames/types@npm:0.0.6" + checksum: 4a4b6d7850c9322dbf8a7df9a7dfddab5096cb1624161f011586c6cd302e3ee789b7e6f0430254249e50dc7e71fbe635a4a76cc053eba114dfd8983879ffbd19 languageName: node linkType: hard @@ -4331,7 +4350,9 @@ __metadata: resolution: "@xmtp/frames-client@workspace:packages/frames-client" dependencies: "@noble/hashes": "npm:^1.3.3" - "@open-frames/types": "npm:^0.0.5" + "@open-frames/proxy": "npm:^0.0.3" + "@open-frames/proxy-client": "npm:^0.1.2" + "@open-frames/types": "npm:^0.0.6" "@rollup/plugin-terser": "npm:^0.4.4" "@rollup/plugin-typescript": "npm:^11.1.6" "@xmtp/proto": "npm:3.41.0-beta.5" @@ -5173,6 +5194,13 @@ __metadata: languageName: node linkType: hard +"boolbase@npm:^1.0.0": + version: 1.0.0 + resolution: "boolbase@npm:1.0.0" + checksum: 3e25c80ef626c3a3487c73dbfc70ac322ec830666c9ad915d11b701142fab25ec1e63eff2c450c74347acfd2de854ccde865cd79ef4db1683f7c7b046ea43bb0 + languageName: node + linkType: hard + "borsh@npm:^0.7.0": version: 0.7.0 resolution: "borsh@npm:0.7.0" @@ -5569,6 +5597,35 @@ __metadata: languageName: node linkType: hard +"cheerio-select@npm:^2.1.0": + version: 2.1.0 + resolution: "cheerio-select@npm:2.1.0" + dependencies: + boolbase: "npm:^1.0.0" + css-select: "npm:^5.1.0" + css-what: "npm:^6.1.0" + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.3" + domutils: "npm:^3.0.1" + checksum: b5d89208c23468c3a32d1e04f88b9e8c6e332e3649650c5cd29255e2cebc215071ae18563f58c3dc3f6ef4c234488fc486035490fceb78755572288245e2931a + languageName: node + linkType: hard + +"cheerio@npm:^1.0.0-rc.12": + version: 1.0.0-rc.12 + resolution: "cheerio@npm:1.0.0-rc.12" + dependencies: + cheerio-select: "npm:^2.1.0" + dom-serializer: "npm:^2.0.0" + domhandler: "npm:^5.0.3" + domutils: "npm:^3.0.1" + htmlparser2: "npm:^8.0.1" + parse5: "npm:^7.0.0" + parse5-htmlparser2-tree-adapter: "npm:^7.0.0" + checksum: 812fed61aa4b669bbbdd057d0d7f73ba4649cabfd4fc3a8f1d5c7499e4613b430636102716369cbd6bbed8f1bdcb06387ae8342289fb908b2743184775f94f18 + languageName: node + linkType: hard + "chokidar@npm:^3.5.3": version: 3.5.3 resolution: "chokidar@npm:3.5.3" @@ -5856,6 +5913,19 @@ __metadata: languageName: node linkType: hard +"css-select@npm:^5.1.0": + version: 5.1.0 + resolution: "css-select@npm:5.1.0" + dependencies: + boolbase: "npm:^1.0.0" + css-what: "npm:^6.1.0" + domhandler: "npm:^5.0.2" + domutils: "npm:^3.0.1" + nth-check: "npm:^2.0.1" + checksum: d486b1e7eb140468218a5ab5af53257e01f937d2173ac46981f6b7de9c5283d55427a36715dc8decfc0c079cf89259ac5b41ef58f6e1a422eee44ab8bfdc78da + languageName: node + linkType: hard + "css-what@npm:^6.1.0": version: 6.1.0 resolution: "css-what@npm:6.1.0" @@ -6247,6 +6317,44 @@ __metadata: languageName: node linkType: hard +"dom-serializer@npm:^2.0.0": + version: 2.0.0 + resolution: "dom-serializer@npm:2.0.0" + dependencies: + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.2" + entities: "npm:^4.2.0" + checksum: e3bf9027a64450bca0a72297ecdc1e3abb7a2912268a9f3f5d33a2e29c1e2c3502c6e9f860fc6625940bfe0cfb57a44953262b9e94df76872fdfb8151097eeb3 + languageName: node + linkType: hard + +"domelementtype@npm:^2.3.0": + version: 2.3.0 + resolution: "domelementtype@npm:2.3.0" + checksum: ee837a318ff702622f383409d1f5b25dd1024b692ef64d3096ff702e26339f8e345820f29a68bcdcea8cfee3531776b3382651232fbeae95612d6f0a75efb4f6 + languageName: node + linkType: hard + +"domhandler@npm:^5.0.2, domhandler@npm:^5.0.3": + version: 5.0.3 + resolution: "domhandler@npm:5.0.3" + dependencies: + domelementtype: "npm:^2.3.0" + checksum: 809b805a50a9c6884a29f38aec0a4e1b4537f40e1c861950ed47d10b049febe6b79ab72adaeeebb3cc8fc1cd33f34e97048a72a9265103426d93efafa78d3e96 + languageName: node + linkType: hard + +"domutils@npm:^3.0.1": + version: 3.1.0 + resolution: "domutils@npm:3.1.0" + dependencies: + dom-serializer: "npm:^2.0.0" + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.3" + checksum: 9a169a6e57ac4c738269a73ab4caf785114ed70e46254139c1bbc8144ac3102aacb28a6149508395ae34aa5d6a40081f4fa5313855dc8319c6d8359866b6dfea + languageName: node + linkType: hard + "duplexer@npm:0.1.1": version: 0.1.1 resolution: "duplexer@npm:0.1.1" @@ -6364,7 +6472,7 @@ __metadata: languageName: node linkType: hard -"entities@npm:^4.5.0": +"entities@npm:^4.2.0, entities@npm:^4.4.0, entities@npm:^4.5.0": version: 4.5.0 resolution: "entities@npm:4.5.0" checksum: ede2a35c9bce1aeccd055a1b445d41c75a14a2bb1cd22e242f20cf04d236cdcd7f9c859eb83f76885327bfae0c25bf03303665ee1ce3d47c5927b98b0e3e3d48 @@ -8164,6 +8272,18 @@ __metadata: languageName: node linkType: hard +"htmlparser2@npm:^8.0.1": + version: 8.0.2 + resolution: "htmlparser2@npm:8.0.2" + dependencies: + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.3" + domutils: "npm:^3.0.1" + entities: "npm:^4.4.0" + checksum: ea5512956eee06f5835add68b4291d313c745e8407efa63848f4b8a90a2dee45f498a698bca8614e436f1ee0cfdd609938b71d67c693794545982b76e53e6f11 + languageName: node + linkType: hard + "http-cache-semantics@npm:^4.1.0, http-cache-semantics@npm:^4.1.1": version: 4.1.1 resolution: "http-cache-semantics@npm:4.1.1" @@ -9622,6 +9742,15 @@ __metadata: languageName: node linkType: hard +"mime@npm:^4.0.1": + version: 4.0.1 + resolution: "mime@npm:4.0.1" + bin: + mime: bin/cli.js + checksum: 4598030457488c240a4ba30561a619cfb627f96271ecced5d715eb5c44d33105e3f28d28fe46d72eeadb78d7de5aeb1f8e62d448c14b0e518a7ace76d2af5f2d + languageName: node + linkType: hard + "mimic-fn@npm:^2.1.0": version: 2.1.0 resolution: "mimic-fn@npm:2.1.0" @@ -10229,6 +10358,15 @@ __metadata: languageName: node linkType: hard +"nth-check@npm:^2.0.1": + version: 2.1.1 + resolution: "nth-check@npm:2.1.1" + dependencies: + boolbase: "npm:^1.0.0" + checksum: 5afc3dafcd1573b08877ca8e6148c52abd565f1d06b1eb08caf982e3fa289a82f2cae697ffb55b5021e146d60443f1590a5d6b944844e944714a5b549675bcd3 + languageName: node + linkType: hard + "object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" @@ -10573,6 +10711,25 @@ __metadata: languageName: node linkType: hard +"parse5-htmlparser2-tree-adapter@npm:^7.0.0": + version: 7.0.0 + resolution: "parse5-htmlparser2-tree-adapter@npm:7.0.0" + dependencies: + domhandler: "npm:^5.0.2" + parse5: "npm:^7.0.0" + checksum: 23dbe45fdd338fe726cf5c55b236e1f403aeb0c1b926e18ab8ef0aa580980a25f8492d160fe2ed0ec906c3c8e38b51e68ef5620a3b9460d9458ea78946a3f7c0 + languageName: node + linkType: hard + +"parse5@npm:^7.0.0": + version: 7.1.2 + resolution: "parse5@npm:7.1.2" + dependencies: + entities: "npm:^4.4.0" + checksum: 3c86806bb0fb1e9a999ff3a4c883b1ca243d99f45a619a0898dbf021a95a0189ed955c31b07fe49d342b54e814f33f2c9d7489198e8630dacd5477d413ec5782 + languageName: node + linkType: hard + "path-exists@npm:^4.0.0": version: 4.0.0 resolution: "path-exists@npm:4.0.0"