From 0bffc817fd5ed405b86a9d73dd9dbd86f268d84b Mon Sep 17 00:00:00 2001 From: Vladyslav Dalechyn Date: Sat, 20 Apr 2024 14:06:33 +0300 Subject: [PATCH 01/10] fix: delete `frog:image` meta tag (#272) * fix: delete `frog:image` meta tag Reverted changes from #222 that have ultimately caused issues in wrangler and edge environments. * chore: changesets --- .changeset/quick-rivers-own.md | 5 +++++ src/frog-base.tsx | 40 +++------------------------------- 2 files changed, 8 insertions(+), 37 deletions(-) create mode 100644 .changeset/quick-rivers-own.md diff --git a/.changeset/quick-rivers-own.md b/.changeset/quick-rivers-own.md new file mode 100644 index 00000000..0e722640 --- /dev/null +++ b/.changeset/quick-rivers-own.md @@ -0,0 +1,5 @@ +--- +"frog": patch +--- + +Reverted changes from #222 that have caused issues in wrangler and edge environments. Intentionally introduced regression with "refreshing frame images" as #222 focused on bringing those work. diff --git a/src/frog-base.tsx b/src/frog-base.tsx index ebbca396..ef941c2a 100644 --- a/src/frog-base.tsx +++ b/src/frog-base.tsx @@ -352,25 +352,6 @@ export class FrogBase< const imagePaths = getImagePaths(parseHonoPath(path)) for (const imagePath of imagePaths) { this.hono.get(imagePath, async (c) => { - const url = getRequestUrl(c.req) - - const query = c.req.query() - if (!query.image) { - // If the query is doesn't have an image, it is an initial request to a frame. - // Therefore we need to get the link to fetch the original image and jump once again in this method to resolve the options, - // but now with query params set. - const metadata = await getFrameMetadata(url.href.slice(0, -6)) // Stripping `/image` (6 characters) from the end of the url. - const frogImage = metadata.find( - ({ property }) => property === 'frog:image', - ) - if (!frogImage) - throw new Error( - 'Unexpected error: frog:image meta tag is not present in the frame.', - ) - // Redirect to this route but now with search params and return the response - return c.redirect(frogImage.content) - } - const defaultImageOptions = await (async () => { if (typeof this.imageOptions === 'function') return await this.imageOptions() @@ -389,7 +370,7 @@ export class FrogBase< headers = this.headers, image, imageOptions = defaultImageOptions, - } = fromQuery(query) + } = fromQuery(c.req.query()) const image_ = JSON.parse(lz.decompressFromEncodedURIComponent(image)) return new ImageResponse(image_, { width: 1200, @@ -672,22 +653,8 @@ export class FrogBase< property="fc:frame:image:aspect_ratio" content={imageAspectRatio} /> - - + + )} - From db15b8758416b2b636dbd02f300bf0e77c0ae7ee Mon Sep 17 00:00:00 2001 From: "moxey.eth" Date: Sat, 20 Apr 2024 21:08:17 +1000 Subject: [PATCH 02/10] fix: types --- src/frog-base.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/frog-base.tsx b/src/frog-base.tsx index ef941c2a..93164327 100644 --- a/src/frog-base.tsx +++ b/src/frog-base.tsx @@ -28,7 +28,6 @@ import { fromQuery } from './utils/fromQuery.js' import { getButtonValues } from './utils/getButtonValues.js' import { getCastActionContext } from './utils/getCastActionContext.js' import { getFrameContext } from './utils/getFrameContext.js' -import { getFrameMetadata } from './utils/getFrameMetadata.js' import { getImagePaths } from './utils/getImagePaths.js' import { getRequestUrl } from './utils/getRequestUrl.js' import { getRouteParameters } from './utils/getRouteParameters.js' From 41fcd12341db685a221311ca301ffb68248cd17a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 20 Apr 2024 21:10:54 +1000 Subject: [PATCH 03/10] chore: version packages (#273) Co-authored-by: github-actions[bot] --- .changeset/quick-rivers-own.md | 5 ----- src/CHANGELOG.md | 6 ++++++ src/package.json | 2 +- src/version.ts | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) delete mode 100644 .changeset/quick-rivers-own.md diff --git a/.changeset/quick-rivers-own.md b/.changeset/quick-rivers-own.md deleted file mode 100644 index 0e722640..00000000 --- a/.changeset/quick-rivers-own.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"frog": patch ---- - -Reverted changes from #222 that have caused issues in wrangler and edge environments. Intentionally introduced regression with "refreshing frame images" as #222 focused on bringing those work. diff --git a/src/CHANGELOG.md b/src/CHANGELOG.md index 07dbf7f2..2f8efac7 100644 --- a/src/CHANGELOG.md +++ b/src/CHANGELOG.md @@ -1,5 +1,11 @@ # frog +## 0.8.6 + +### Patch Changes + +- [#272](https://github.com/wevm/frog/pull/272) [`0bffc81`](https://github.com/wevm/frog/commit/0bffc817fd5ed405b86a9d73dd9dbd86f268d84b) Thanks [@dalechyn](https://github.com/dalechyn)! - Reverted changes from #222 that have caused issues in wrangler and edge environments. Intentionally introduced regression with "refreshing frame images" as #222 focused on bringing those work. + ## 0.8.5 ### Patch Changes diff --git a/src/package.json b/src/package.json index 85d9af0e..5ca7b868 100644 --- a/src/package.json +++ b/src/package.json @@ -1,7 +1,7 @@ { "name": "frog", "description": "Framework for Farcaster Frames", - "version": "0.8.5", + "version": "0.8.6", "type": "module", "module": "_lib/index.js", "types": "_lib/index.d.ts", diff --git a/src/version.ts b/src/version.ts index 21f965f4..4718f493 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const version = '0.8.5' +export const version = '0.8.6' From 75f46a4c75e2ded0fe7875481e996cdc05a366f7 Mon Sep 17 00:00:00 2001 From: Vladyslav Dalechyn Date: Fri, 26 Apr 2024 04:00:40 +0300 Subject: [PATCH 04/10] feat: `~` root action paths (#237) * feat: relative path actions * chore: changeset * feat: jump to top of the route tree via `@` * tweaks * tweaks * tweaks * nit: `@` to `~` * Update frog-base.tsx Co-authored-by: jxom * nit: tweak Co-authored-by: jxom * fix: bad slice * nit: changesets * nit: unnecessary replace --------- Co-authored-by: jxom --- .changeset/old-crabs-join.md | 5 ++++ playground/src/routing.tsx | 55 ++++++++++++++++++++++++++++-------- src/frog-base.tsx | 25 ++++++++++++++-- src/utils/parseIntents.ts | 11 ++++++-- 4 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 .changeset/old-crabs-join.md diff --git a/.changeset/old-crabs-join.md b/.changeset/old-crabs-join.md new file mode 100644 index 00000000..677ab20e --- /dev/null +++ b/.changeset/old-crabs-join.md @@ -0,0 +1,5 @@ +--- +"frog": patch +--- + +Added root path support in `action` to jump into the root Frog instance via `'~'` symbol. Useful for code-splitting via `app.route`. diff --git a/playground/src/routing.tsx b/playground/src/routing.tsx index 394344c0..71578af5 100644 --- a/playground/src/routing.tsx +++ b/playground/src/routing.tsx @@ -1,14 +1,47 @@ -import { Frog } from 'frog' +import { Button, Frog } from 'frog' export const app = new Frog() -app.frame('/:name?', (c) => { - const name = c.req.param('name') - return c.res({ - image: ( -
- gm, {name ?? 'froggie'} -
- ), - }) -}) +app + .frame('/jump-to-root', (c) => { + return c.res({ + action: '~/', + image: ( +
+ Press a button to jump back! +
+ ), + intents: [], + }) + }) + .frame('/jump-to-clock', (c) => { + return c.res({ + action: '~/clock', + image: ( +
+ Press a button to jump back! +
+ ), + intents: [], + }) + }) + .frame('/jump-to-root-from-button', (c) => { + return c.res({ + image: ( +
+ Press a button to jump back! +
+ ), + intents: [], + }) + }) + .frame('/:name?', (c) => { + const name = c.req.param('name') + return c.res({ + image: ( +
+ gm, {name ?? 'froggie'} +
+ ), + }) + }) diff --git a/src/frog-base.tsx b/src/frog-base.tsx index 93164327..d4077dc9 100644 --- a/src/frog-base.tsx +++ b/src/frog-base.tsx @@ -277,6 +277,8 @@ export class FrogBase< if (typeof verify !== 'undefined') this.verify = verify this.basePath = basePath ?? '/' + // @ts-ignore - private + this.initialBasePath = this.basePath this.assetsPath = assetsPath ?? this.basePath this.fetch = this.hono.fetch.bind(this.hono) this.get = this.hono.get.bind(this.hono) @@ -388,6 +390,12 @@ export class FrogBase< const origin = this.origin ?? url.origin const assetsUrl = origin + parsePath(this.assetsPath) const baseUrl = origin + parsePath(this.basePath) + const initialBaseUrl = + origin + + parsePath( + // @ts-ignore - private + this.initialBasePath, + ) const { context, getState } = getFrameContext({ context: await requestBodyToContext(c, { @@ -421,7 +429,13 @@ export class FrogBase< ogImage, title = 'Frog Frame', } = response.data - const buttonValues = getButtonValues(parseIntents(intents)) + + const buttonValues = getButtonValues( + parseIntents(intents, { + baseUrl, + initialBaseUrl, + }), + ) if (context.status === 'redirect' && context.buttonIndex) { const buttonValue = buttonValues[context.buttonIndex - 1] @@ -537,10 +551,14 @@ export class FrogBase< const postUrl = (() => { if (!action) return context.url if (action.startsWith('http')) return action + if (action.startsWith('~')) + return initialBaseUrl + parsePath(action.slice(1)) + return baseUrl + parsePath(action) })() const parsedIntents = parseIntents(intents, { + initialBaseUrl, baseUrl, search: context.status === 'initial' @@ -703,8 +721,11 @@ export class FrogBase< subBasePath extends string, >(path: subPath, frog: FrogBase) { if (frog.assetsPath === '/') frog.assetsPath = this.assetsPath - if (frog.basePath === '/') + if (frog.basePath === '/') { + // @ts-ignore - private + frog.initialBasePath = this.initialBasePath ?? parsePath(this.basePath) frog.basePath = parsePath(this.basePath) + parsePath(path) + } if (!frog.browserLocation) frog.browserLocation = this.browserLocation if (!frog.dev) frog.dev = this.dev if (!frog.headers) frog.headers = this.headers diff --git a/src/utils/parseIntents.ts b/src/utils/parseIntents.ts index f6b83e6f..0fcd0f40 100644 --- a/src/utils/parseIntents.ts +++ b/src/utils/parseIntents.ts @@ -7,13 +7,14 @@ import { parsePath } from './parsePath.js' type Counter = { button: number } type ParseIntentsOptions = { - baseUrl?: string + baseUrl: string + initialBaseUrl: string | undefined search?: string } export function parseIntents( intents_: FrameIntent | FrameIntent[] | undefined, - options: ParseIntentsOptions = {}, + options: ParseIntentsOptions, counter: Counter = { button: 1 }, ): JSXNode[] { if (!intents_) return [] @@ -53,7 +54,11 @@ function parseIntent( action: node.props.action ? node.props.action.startsWith('http') ? node.props.action - : parsePath(options.baseUrl + node.props.action) + + : parsePath( + node.props.action.startsWith('~') + ? options.initialBaseUrl + node.props.action.slice(1) + : options.baseUrl + node.props.action, + ) + (options.search && !value?.startsWith(buttonPrefix.addCastAction) ? `?${options.search}` : '') From 89feed6f104f4818018923916d2ec673adb0c59f Mon Sep 17 00:00:00 2001 From: Vladyslav Dalechyn Date: Fri, 26 Apr 2024 14:04:07 +0300 Subject: [PATCH 05/10] nit: fix tests (#283) --- src/next/getFrameMetadata.test.ts | 5 ++--- src/utils/getFrameMetadata.test.ts | 8 ++------ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/next/getFrameMetadata.test.ts b/src/next/getFrameMetadata.test.ts index 6e3d1239..7b98f278 100644 --- a/src/next/getFrameMetadata.test.ts +++ b/src/next/getFrameMetadata.test.ts @@ -17,11 +17,10 @@ test('default', async () => { "fc:frame:button:3": "GitHub", "fc:frame:button:3:action": "link", "fc:frame:button:3:target": "https://github.com/wevm/frog", - "fc:frame:image": "https://frame.frog.fm/api/image", + "fc:frame:image": "https://frame.frog.fm/og.png", "fc:frame:image:aspect_ratio": "1.91:1", "fc:frame:post_url": "https://frame.frog.fm/api?initialPath=%252Fapi&previousButtonValues=%2523A_%252C_l%252C_l", - "frog:image": "https://frame.frog.fm/og.png", - "og:image": "https://frame.frog.fm/api/image", + "og:image": "https://frame.frog.fm/og.png", "og:title": "Frog Frame", } `) diff --git a/src/utils/getFrameMetadata.test.ts b/src/utils/getFrameMetadata.test.ts index 82b7aaec..71f1a409 100644 --- a/src/utils/getFrameMetadata.test.ts +++ b/src/utils/getFrameMetadata.test.ts @@ -16,11 +16,11 @@ test('default', async () => { "property": "fc:frame:image:aspect_ratio", }, { - "content": "https://frame.frog.fm/api/image", + "content": "https://frame.frog.fm/og.png", "property": "fc:frame:image", }, { - "content": "https://frame.frog.fm/api/image", + "content": "https://frame.frog.fm/og.png", "property": "og:image", }, { @@ -67,10 +67,6 @@ test('default', async () => { "content": "https://github.com/wevm/frog", "property": "fc:frame:button:3:target", }, - { - "content": "https://frame.frog.fm/og.png", - "property": "frog:image", - }, ] `) }) From 0d41ddfd63397df502bf5e636609bf68e8c11ee9 Mon Sep 17 00:00:00 2001 From: Vladyslav Dalechyn Date: Fri, 26 Apr 2024 17:16:32 +0300 Subject: [PATCH 06/10] fix: devtools watch mode (#257) * fix(devtools): disable watch for standalone mode * chore: changesets --- .changeset/wild-ladybugs-double.md | 5 +++++ src/cli/vite/dev.ts | 9 ++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 .changeset/wild-ladybugs-double.md diff --git a/.changeset/wild-ladybugs-double.md b/.changeset/wild-ladybugs-double.md new file mode 100644 index 00000000..26cd7532 --- /dev/null +++ b/.changeset/wild-ladybugs-double.md @@ -0,0 +1,5 @@ +--- +"frog": patch +--- + +Disabled watch process when frog CLI is called outside of a project directory. diff --git a/src/cli/vite/dev.ts b/src/cli/vite/dev.ts index 42e9e100..f0314c34 100644 --- a/src/cli/vite/dev.ts +++ b/src/cli/vite/dev.ts @@ -164,9 +164,12 @@ export function devServer(options?: DevServerOptions): VitePlugin { config: () => { return { server: { - watch: { - ignored: options?.ignoreWatching ?? defaultOptions.ignoreWatching, - }, + watch: options?.injectClientScript + ? { + ignored: + options?.ignoreWatching ?? defaultOptions.ignoreWatching, + } + : null, }, } }, From 268ee0de2e0a310684b1f0a062fcf95a818a5f8c Mon Sep 17 00:00:00 2001 From: Vladyslav Dalechyn Date: Sun, 28 Apr 2024 23:56:39 +0300 Subject: [PATCH 07/10] feat: add degen chain (#287) * feat: add degen chain * chore: changesets --- .changeset/wild-fishes-speak.md | 5 ++++ pnpm-lock.yaml | 48 ++++++++++++++++++++++++--------- src/types/transaction.ts | 3 ++- ui/package.json | 2 +- ui/src/lib/wagmi.ts | 5 ++-- 5 files changed, 47 insertions(+), 16 deletions(-) create mode 100644 .changeset/wild-fishes-speak.md diff --git a/.changeset/wild-fishes-speak.md b/.changeset/wild-fishes-speak.md new file mode 100644 index 00000000..7421d352 --- /dev/null +++ b/.changeset/wild-fishes-speak.md @@ -0,0 +1,5 @@ +--- +"frog": patch +--- + +Added degen chain support. [See more](https://warpcast.com/horsefacts.eth/0xd4fede11). diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 82df7eba..0cb125dd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -418,14 +418,14 @@ importers: specifier: 5.3.3 version: 5.3.3 viem: - specifier: ^2.7.10 - version: 2.7.11(typescript@5.3.3) + specifier: ^2.9.28 + version: 2.9.28(typescript@5.3.3) vite: specifier: ^5.1.6 version: 5.1.6(@types/node@20.11.19) wagmi: specifier: ^2.5.11 - version: 2.5.11(@tanstack/react-query@5.28.4)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)(viem@2.7.11) + version: 2.5.11(@tanstack/react-query@5.28.4)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)(viem@2.9.28) zustand: specifier: ^4.5.2 version: 4.5.2(@types/react@18.2.65)(react@18.2.0) @@ -4786,7 +4786,7 @@ packages: pretty-format: 29.7.0 dev: true - /@wagmi/connectors@4.1.18(@types/react@18.2.65)(@wagmi/core@2.6.9)(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)(viem@2.7.11): + /@wagmi/connectors@4.1.18(@types/react@18.2.65)(@wagmi/core@2.6.9)(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)(viem@2.9.28): resolution: {integrity: sha512-K/iLH/Z8jwvgPAYESU/uCQtQBvcIR1Jrqk+t2uCDSxew/tYtkOo2yOjtaPuOb+xJ5OrMGg+0tVHhGChYXry9Ow==} peerDependencies: '@wagmi/core': 2.6.9 @@ -4800,11 +4800,11 @@ packages: '@metamask/sdk': 0.14.3(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0) '@safe-global/safe-apps-provider': 0.18.1(typescript@5.3.3) '@safe-global/safe-apps-sdk': 8.1.0(typescript@5.3.3) - '@wagmi/core': 2.6.9(@types/react@18.2.65)(react@18.2.0)(typescript@5.3.3)(viem@2.7.11) + '@wagmi/core': 2.6.9(@types/react@18.2.65)(react@18.2.0)(typescript@5.3.3)(viem@2.9.28) '@walletconnect/ethereum-provider': 2.11.2(@types/react@18.2.65)(react@18.2.0) '@walletconnect/modal': 2.6.2(@types/react@18.2.65)(react@18.2.0) typescript: 5.3.3 - viem: 2.7.11(typescript@5.3.3) + viem: 2.9.28(typescript@5.3.3) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -4832,7 +4832,7 @@ packages: - zod dev: true - /@wagmi/core@2.6.9(@types/react@18.2.65)(react@18.2.0)(typescript@5.3.3)(viem@2.7.11): + /@wagmi/core@2.6.9(@types/react@18.2.65)(react@18.2.0)(typescript@5.3.3)(viem@2.9.28): resolution: {integrity: sha512-AbNbHK+m60mfMTds0flv5YYJGp+JSz8O8ikzX+T7MdemFrYA9tZr6G+iSEnf+JLtcgiaCgQqUwac/WmmTkDiMA==} peerDependencies: '@tanstack/query-core': '>=5.0.0' @@ -4847,7 +4847,7 @@ packages: eventemitter3: 5.0.1 mipd: 0.0.5(typescript@5.3.3) typescript: 5.3.3 - viem: 2.7.11(typescript@5.3.3) + viem: 2.9.28(typescript@5.3.3) zustand: 4.4.1(@types/react@18.2.65)(react@18.2.0) transitivePeerDependencies: - '@types/react' @@ -12309,6 +12309,30 @@ packages: - bufferutil - utf-8-validate - zod + dev: false + + /viem@2.9.28(typescript@5.3.3): + resolution: {integrity: sha512-/1iTg8yQlCNJ+7wSmdsBNB/vhjWqFJtTH6XZXHjGXrZnlBxAtHR5ZAr5TvTJc/2nhVIVE4BkCe5JCrIiSuZodg==} + peerDependencies: + typescript: 5.3.3 + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@adraffy/ens-normalize': 1.10.0 + '@noble/curves': 1.2.0 + '@noble/hashes': 1.3.2 + '@scure/bip32': 1.3.2 + '@scure/bip39': 1.2.1 + abitype: 1.0.0(typescript@5.3.3) + isows: 1.0.3(ws@8.13.0) + typescript: 5.3.3 + ws: 8.13.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + dev: true /vite-node@1.3.0(@types/node@20.11.19): resolution: {integrity: sha512-D/oiDVBw75XMnjAXne/4feCkCEwcbr2SU1bjAhCcfI5Bq3VoOHji8/wCPAfUkDIeohJ5nSZ39fNxM3dNZ6OBOA==} @@ -12547,7 +12571,7 @@ packages: engines: {node: '>=0.10.0'} dev: true - /wagmi@2.5.11(@tanstack/react-query@5.28.4)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)(viem@2.7.11): + /wagmi@2.5.11(@tanstack/react-query@5.28.4)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)(viem@2.9.28): resolution: {integrity: sha512-uugglHWhd7j432q5ga75F3YB7yeGjNmiOKztByWCyEA9EqLAqA2RML8/koN/0pgFmZKG9xzP+0zoo2l9vTrTsw==} peerDependencies: '@tanstack/react-query': '>=5.0.0' @@ -12559,12 +12583,12 @@ packages: optional: true dependencies: '@tanstack/react-query': 5.28.4(react@18.2.0) - '@wagmi/connectors': 4.1.18(@types/react@18.2.65)(@wagmi/core@2.6.9)(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)(viem@2.7.11) - '@wagmi/core': 2.6.9(@types/react@18.2.65)(react@18.2.0)(typescript@5.3.3)(viem@2.7.11) + '@wagmi/connectors': 4.1.18(@types/react@18.2.65)(@wagmi/core@2.6.9)(react-dom@18.2.0)(react@18.2.0)(typescript@5.3.3)(viem@2.9.28) + '@wagmi/core': 2.6.9(@types/react@18.2.65)(react@18.2.0)(typescript@5.3.3)(viem@2.9.28) react: 18.2.0 typescript: 5.3.3 use-sync-external-store: 1.2.0(react@18.2.0) - viem: 2.7.11(typescript@5.3.3) + viem: 2.9.28(typescript@5.3.3) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' diff --git a/src/types/transaction.ts b/src/types/transaction.ts index 9ba60f2c..7dd0b1e5 100644 --- a/src/types/transaction.ts +++ b/src/types/transaction.ts @@ -21,8 +21,9 @@ export type ChainNamespace = 'eip155' * - 8453: Base * - 84532: Base Sepolia * - 7777777: Zora + * - 666666666: Degen */ -export type ChainIdEip155 = 1 | 10 | 8453 | 84532 | 7777777 +export type ChainIdEip155 = 1 | 10 | 8453 | 84532 | 7777777 | 666666666 export type TransactionParameters = { /** A CAIP-2 Chain ID to identify the transaction network. */ diff --git a/ui/package.json b/ui/package.json index e49f8cba..8e33dc0c 100644 --- a/ui/package.json +++ b/ui/package.json @@ -28,7 +28,7 @@ "shiki": "^1.1.7", "tailwindcss": "^3.4.1", "typescript": "^5.2.2", - "viem": "^2.7.10", + "viem": "^2.9.28", "vite": "^5.1.6", "wagmi": "^2.5.11", "zustand": "^4.5.2" diff --git a/ui/src/lib/wagmi.ts b/ui/src/lib/wagmi.ts index 4f2fb254..68c1041a 100644 --- a/ui/src/lib/wagmi.ts +++ b/ui/src/lib/wagmi.ts @@ -1,10 +1,10 @@ import { QueryClient } from '@tanstack/react-query' import { http, createConfig, createStorage } from 'wagmi' -import { base, baseSepolia, mainnet, optimism, zora } from 'wagmi/chains' +import { base, baseSepolia, degen, mainnet, optimism, zora } from 'wagmi/chains' import { coinbaseWallet, walletConnect } from 'wagmi/connectors' export const config = createConfig({ - chains: [mainnet, base, baseSepolia, optimism, zora], + chains: [mainnet, base, baseSepolia, degen, optimism, zora], connectors: [ coinbaseWallet({ appName: 'Frog Devtools', headlessMode: true }), walletConnect({ @@ -17,6 +17,7 @@ export const config = createConfig({ [mainnet.id]: http(), [base.id]: http(), [baseSepolia.id]: http(), + [degen.id]: http(), [optimism.id]: http(), [zora.id]: http(), }, From 39d098d55d7c841f31dc021a51e270630bd4d14b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 28 Apr 2024 16:58:57 -0400 Subject: [PATCH 08/10] chore: version packages (#284) Co-authored-by: github-actions[bot] --- .changeset/old-crabs-join.md | 5 ----- .changeset/wild-fishes-speak.md | 5 ----- .changeset/wild-ladybugs-double.md | 5 ----- src/CHANGELOG.md | 10 ++++++++++ src/package.json | 2 +- src/version.ts | 2 +- 6 files changed, 12 insertions(+), 17 deletions(-) delete mode 100644 .changeset/old-crabs-join.md delete mode 100644 .changeset/wild-fishes-speak.md delete mode 100644 .changeset/wild-ladybugs-double.md diff --git a/.changeset/old-crabs-join.md b/.changeset/old-crabs-join.md deleted file mode 100644 index 677ab20e..00000000 --- a/.changeset/old-crabs-join.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"frog": patch ---- - -Added root path support in `action` to jump into the root Frog instance via `'~'` symbol. Useful for code-splitting via `app.route`. diff --git a/.changeset/wild-fishes-speak.md b/.changeset/wild-fishes-speak.md deleted file mode 100644 index 7421d352..00000000 --- a/.changeset/wild-fishes-speak.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"frog": patch ---- - -Added degen chain support. [See more](https://warpcast.com/horsefacts.eth/0xd4fede11). diff --git a/.changeset/wild-ladybugs-double.md b/.changeset/wild-ladybugs-double.md deleted file mode 100644 index 26cd7532..00000000 --- a/.changeset/wild-ladybugs-double.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"frog": patch ---- - -Disabled watch process when frog CLI is called outside of a project directory. diff --git a/src/CHANGELOG.md b/src/CHANGELOG.md index 2f8efac7..1c6a3557 100644 --- a/src/CHANGELOG.md +++ b/src/CHANGELOG.md @@ -1,5 +1,15 @@ # frog +## 0.8.7 + +### Patch Changes + +- [#237](https://github.com/wevm/frog/pull/237) [`75f46a4`](https://github.com/wevm/frog/commit/75f46a4c75e2ded0fe7875481e996cdc05a366f7) Thanks [@dalechyn](https://github.com/dalechyn)! - Added root path support in `action` to jump into the root Frog instance via `'~'` symbol. Useful for code-splitting via `app.route`. + +- [#287](https://github.com/wevm/frog/pull/287) [`268ee0d`](https://github.com/wevm/frog/commit/268ee0de2e0a310684b1f0a062fcf95a818a5f8c) Thanks [@dalechyn](https://github.com/dalechyn)! - Added degen chain support. [See more](https://warpcast.com/horsefacts.eth/0xd4fede11). + +- [#257](https://github.com/wevm/frog/pull/257) [`0d41ddf`](https://github.com/wevm/frog/commit/0d41ddfd63397df502bf5e636609bf68e8c11ee9) Thanks [@dalechyn](https://github.com/dalechyn)! - Disabled watch process when frog CLI is called outside of a project directory. + ## 0.8.6 ### Patch Changes diff --git a/src/package.json b/src/package.json index 5ca7b868..f17e75cd 100644 --- a/src/package.json +++ b/src/package.json @@ -1,7 +1,7 @@ { "name": "frog", "description": "Framework for Farcaster Frames", - "version": "0.8.6", + "version": "0.8.7", "type": "module", "module": "_lib/index.js", "types": "_lib/index.d.ts", diff --git a/src/version.ts b/src/version.ts index 4718f493..3a8f748f 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const version = '0.8.6' +export const version = '0.8.7' From f841edc49614a4fd67e5feaae7161f1592ea8c6d Mon Sep 17 00:00:00 2001 From: Vladyslav Dalechyn Date: Mon, 29 Apr 2024 01:56:23 +0300 Subject: [PATCH 09/10] feat: cast actions deeplink v2 (#251) * feat: cast actions deeplink v2 * chore: changesets * docs: update * chore: update changesets * nit: drop console.log * refactor: apply changes from code review * docs: fix * docs: nit * docs: fix --- .changeset/old-buses-poke.md | 9 + playground/src/castAction.tsx | 30 ++-- site/pages/concepts/cast-actions.mdx | 74 ++++---- .../reference/frog-cast-action-context.mdx | 12 +- src/components/Button.tsx | 9 +- src/frog-base.tsx | 53 ++++-- src/types/octicon.ts | 166 +++++++++--------- src/types/response.ts | 2 +- src/types/routes.ts | 46 +++-- src/utils/getCastActionContext.ts | 4 +- src/utils/getRouteParameters.ts | 21 ++- 11 files changed, 248 insertions(+), 178 deletions(-) create mode 100644 .changeset/old-buses-poke.md diff --git a/.changeset/old-buses-poke.md b/.changeset/old-buses-poke.md new file mode 100644 index 00000000..46bb9393 --- /dev/null +++ b/.changeset/old-buses-poke.md @@ -0,0 +1,9 @@ +--- +"frog": minor +--- + +Deprecated the Cast Actions Deeplink V1 format in favor of V2. [See more](https://warpcast.notion.site/Spec-Farcaster-Actions-84d5a85d479a43139ea883f6823d8caa). + +Breaking changes have affected `Button.AddCastAction` and `.castAction` handler: +- `Button.AddCastAction` now only accepts `action` property; +- `.castAction` handler now requries a third parameter (`options`) to be set. Properties that were removed from `Button.AddCastAction` have migrated here, and `aboutUrl` and `description` were added along. diff --git a/playground/src/castAction.tsx b/playground/src/castAction.tsx index 2d3926a2..76cce0be 100644 --- a/playground/src/castAction.tsx +++ b/playground/src/castAction.tsx @@ -36,18 +36,24 @@ export const app = new Frog() ), intents: [ - - Add - , + Add, ], }), ) - .castAction('/action', async (c) => { - console.log( - `Cast Action to ${JSON.stringify(c.actionData.castId)} from ${ - c.actionData.fid - }`, - ) - if (Math.random() > 0.5) return c.error({ message: 'Action failed :(' }) - return c.res({ message: 'Action Succeeded' }) - }) + .castAction( + '/action', + async (c) => { + console.log( + `Cast Action to ${JSON.stringify(c.actionData.castId)} from ${ + c.actionData.fid + }`, + ) + if (Math.random() > 0.5) return c.error({ message: 'Action failed :(' }) + return c.res({ message: 'Action Succeeded' }) + }, + { + name: 'Log This!', + icon: 'log', + description: 'This cast action will log something!', + }, + ) diff --git a/site/pages/concepts/cast-actions.mdx b/site/pages/concepts/cast-actions.mdx index b5740049..d94a3acc 100644 --- a/site/pages/concepts/cast-actions.mdx +++ b/site/pages/concepts/cast-actions.mdx @@ -33,25 +33,25 @@ app.frame('/', (c) => { ), intents: [ - + Add , ] }) }) -app.castAction('/log-this', (c) => { - console.log( - `Cast Action to ${JSON.stringify(c.actionData.castId)} from ${ - c.actionData.fid - }`, - ) - return c.res({ message:'Action Succeeded' }) -}) +app.castAction( + '/log-this', + (c) => { + console.log( + `Cast Action to ${JSON.stringify(c.actionData.castId)} from ${ + c.actionData.fid + }`, + ) + return c.res({ message: 'Action Succeeded' }) + }, + { name: "Log This!", icon: "log" }) +) ``` ::: @@ -62,9 +62,7 @@ app.castAction('/log-this', (c) => { In the example above, we are rendering Add Action intent: -1. `action` property is used to set the path to the cast action route. -2. `name` property is used to set the name of the action. It must be less than 30 characters -3. `icon` property is used to associate your Cast Action with one of the Octicons. You can see the supported list [here](https://warpcast.notion.site/Spec-Farcaster-Actions-84d5a85d479a43139ea883f6823d8caa). +`action` property is used to set the path to the cast action route. ```tsx twoslash [src/index.tsx] // @noErrors @@ -82,11 +80,7 @@ app.frame('/', (c) => { ), intents: [ - + Add , ] @@ -101,7 +95,13 @@ app.frame('/', (c) => { Without a route handler to handle the Action request, the Cast Action will be meaningless. -Thus, let's define a `/log-this` route to handle the the Cast Action: +To specify the name and icon for your action, the next properties are used in the action handler definition: +1. `name` property is used to set the name of the action. It must be less than 30 characters +2. `icon` property is used to associate your Cast Action with one of the Octicons. You can see the supported list [here](https://warpcast.notion.site/Spec-Farcaster-Actions-84d5a85d479a43139ea883f6823d8caa). +3. (optional) `description` property is used to describe your action, up to 80 characters. +4. (optional) `aboutUrl` property is used to show an "About" link when installing an action. + +Let's define a `/log-this` route to handle the the Cast Action: ```tsx twoslash [src/index.tsx] // @noErrors @@ -119,25 +119,25 @@ app.frame('/', (c) => { ), intents: [ - + Add , ] }) }) -app.castAction('/log-this', (c) => { // [!code focus] - console.log( // [!code focus] - `Cast Action to ${JSON.stringify(c.actionData.castId)} from ${ // [!code focus] - c.actionData.fid // [!code focus] - }`, // [!code focus] - ) // [!code focus] - return c.res({ message: 'Action Succeeded' }) // [!code focus] -}) // [!code focus] +app.castAction( + '/log-this', // [!code focus] + (c) => { // [!code focus] + console.log( // [!code focus] + `Cast Action to ${JSON.stringify(c.actionData.castId)} from ${ // [!code focus] + c.actionData.fid // [!code focus] + }`, // [!code focus] + ) // [!code focus] + return c.res({ message: 'Action Succeeded' }) // [!code focus] + }, // [!code focus] + { name: "Log This!", icon: "log" }) // [!code focus] +) // [!code focus] ``` A breakdown of the `/log-this` route handler: @@ -146,9 +146,7 @@ A breakdown of the `/log-this` route handler: - We are responding with a `c.res` response and specifying a `message` that will appear in the success toast. -::: - -### 5. Bonus: Learn the API +### 3. Bonus: Learn the API You can learn more about the transaction APIs here: diff --git a/site/pages/reference/frog-cast-action-context.mdx b/site/pages/reference/frog-cast-action-context.mdx index 8bf8a5dc..a73a1038 100644 --- a/site/pages/reference/frog-cast-action-context.mdx +++ b/site/pages/reference/frog-cast-action-context.mdx @@ -10,7 +10,7 @@ export const app = new Frog() app.castAction('/', (c) => { // [!code focus] return c.res({/* ... */}) -}) +}, {/**/}) ``` :::tip[Tip] @@ -35,7 +35,7 @@ app.castAction('/', (c) => { const { actionData } = c const { castId, fid, messageHash, network, timestamp, url } = actionData // [!code focus] return c.res({/* ... */}) -}) +}, {/**/}) ``` ## error @@ -74,7 +74,7 @@ export const app = new Frog() app.castAction('/', (c) => { const { req } = c // [!code focus] return c.res({/* ... */}) -}) +}, {/**/}) ``` ## res @@ -93,7 +93,7 @@ export const app = new Frog() app.castAction('/', (c) => { return c.res({/* ... */}) // [!code focus] -}) +}, {/**/}) ``` ## var @@ -118,7 +118,7 @@ app.use(async (c, next) => { app.castAction('/', (c) => { const message = c.var.message // [!code focus] return c.res({/* ... */}) -}) +}, {/**/}) ``` ## verified @@ -138,5 +138,5 @@ export const app = new Frog() app.castAction('/', (c) => { const { verified } = c // [!code focus] return c.res({/* ... */}) -}) +}, {/**/}) ``` diff --git a/src/components/Button.tsx b/src/components/Button.tsx index 49a2ff14..16cbe677 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -1,5 +1,4 @@ import type { HtmlEscapedString } from 'hono/utils/html' -import type { Octicon } from '../types/octicon.js' export const buttonPrefix = { addCastAction: '_a', @@ -43,18 +42,12 @@ export function ButtonRoot({ export type ButtonAddCastActionProps = ButtonProps & { /** Action path */ action: string - /** Name of the action. 30 characters maximum */ - name: string - /** Octicon name. @see https://primer.style/foundations/icons */ - icon: Octicon } ButtonAddCastAction.__type = 'button' export function ButtonAddCastAction({ action, children, - name, - icon, // @ts-ignore - private index = 1, }: ButtonAddCastActionProps) { @@ -67,7 +60,7 @@ export function ButtonAddCastAction({ , , ] as unknown as HtmlEscapedString } diff --git a/src/frog-base.tsx b/src/frog-base.tsx index d4077dc9..81b2084c 100644 --- a/src/frog-base.tsx +++ b/src/frog-base.tsx @@ -16,6 +16,7 @@ import type { ImageOptions, } from './types/frame.js' import type { Hub } from './types/hub.js' +import type { Octicon } from './types/octicon.js' import type { CastActionHandler, FrameHandler, @@ -168,9 +169,22 @@ export type FrogConstructorParameters< verify?: boolean | 'silent' | undefined } -export type RouteOptions = Pick & { - fonts?: ImageOptions['fonts'] | (() => Promise) -} +export type RouteOptions = Pick< + FrogConstructorParameters, + 'verify' +> & + (method extends 'frame' + ? { + fonts?: ImageOptions['fonts'] | (() => Promise) + } + : method extends 'castAction' + ? { + name: string + icon: Octicon + description?: string + aboutUrl?: string + } + : {}) /** * A Frog instance. @@ -298,18 +312,33 @@ export class FrogBase< }) } - castAction: HandlerInterface = ( + castAction: HandlerInterface = ( ...parameters: any[] ) => { - const [path, middlewares, handler, options = {}] = getRouteParameters< + const [path, middlewares, handler, options] = getRouteParameters< env, - CastActionHandler + CastActionHandler, + 'castAction' >(...parameters) - const { verify = this.verify } = options + const { verify = this.verify, ...installParameters } = options + + // Cast Action Route (implements GET and POST). + this.hono.use(parseHonoPath(path), ...middlewares, async (c) => { + const url = getRequestUrl(c.req) + const origin = this.origin ?? url.origin + const baseUrl = origin + parsePath(this.basePath) + + if (c.req.method === 'GET') { + return c.json({ + ...installParameters, + postUrl: baseUrl + parsePath(path), + action: { + type: 'post', + }, + }) + } - // Cast Action Route (implements POST). - this.hono.post(parseHonoPath(path), ...middlewares, async (c) => { const { context } = getCastActionContext({ context: await requestBodyToContext(c, { hub: @@ -344,7 +373,8 @@ export class FrogBase< ) => { const [path, middlewares, handler, options = {}] = getRouteParameters< env, - FrameHandler + FrameHandler, + 'frame' >(...parameters) const { verify = this.verify } = options @@ -747,7 +777,8 @@ export class FrogBase< ) => { const [path, middlewares, handler, options = {}] = getRouteParameters< env, - TransactionHandler + TransactionHandler, + 'transaction' >(...parameters) const { verify = this.verify } = options diff --git a/src/types/octicon.ts b/src/types/octicon.ts index cc0b42e6..48a00157 100644 --- a/src/types/octicon.ts +++ b/src/types/octicon.ts @@ -1,126 +1,126 @@ export type Octicon = - | 'number' - | 'search' - | 'image' + | 'accessibility' | 'alert' - | 'code' - | 'meter' - | 'ruby' - | 'video' - | 'filter' - | 'stop' - | 'plus' - | 'info' - | 'check' - | 'book' - | 'question' - | 'mail' - | 'home' - | 'star' - | 'inbox' - | 'lock' - | 'eye' - | 'heart' - | 'unlock' - | 'play' - | 'tag' - | 'calendar' - | 'database' - | 'hourglass' - | 'key' - | 'gift' - | 'sync' | 'archive' + | 'beaker' | 'bell' - | 'bookmark' - | 'briefcase' - | 'bug' - | 'clock' - | 'credit-card' - | 'globe' - | 'infinity' - | 'light-bulb' - | 'location' - | 'megaphone' - | 'moon' - | 'note' - | 'pencil' - | 'pin' - | 'quote' - | 'reply' - | 'rocket' - | 'shield' - | 'stopwatch' - | 'tools' - | 'trash' - | 'comment' - | 'gear' - | 'file' - | 'hash' - | 'square' - | 'sun' - | 'zap' - | 'sign-out' - | 'sign-in' - | 'paste' - | 'mortar-board' - | 'history' - | 'plug' | 'bell-slash' - | 'diamond' - | 'id-badge' - | 'person' - | 'smiley' - | 'pulse' - | 'beaker' - | 'flame' - | 'people' - | 'person-add' - | 'broadcast' - | 'graph' - | 'shield-check' - | 'shield-lock' - | 'telescope' - | 'webhook' - | 'accessibility' - | 'report' - | 'verified' | 'blocked' + | 'book' + | 'bookmark' | 'bookmark-slash' + | 'briefcase' + | 'broadcast' + | 'bug' + | 'calendar' + | 'check' | 'checklist' | 'circle-slash' + | 'clock' + | 'code' + | 'comment' + | 'credit-card' | 'cross-reference' + | 'database' | 'dependabot' | 'device-camera' | 'device-camera-video' | 'device-desktop' | 'device-mobile' + | 'diamond' | 'dot' + | 'eye' | 'eye-closed' + | 'file' + | 'filter' + | 'flame' + | 'gear' + | 'gift' + | 'globe' + | 'graph' + | 'hash' + | 'heart' + | 'history' + | 'home' + | 'hourglass' + | 'id-badge' + | 'image' + | 'inbox' + | 'infinity' + | 'info' | 'iterations' + | 'key' | 'key-asterisk' | 'law' + | 'light-bulb' | 'link-external' | 'list-ordered' | 'list-unordered' + | 'location' + | 'lock' | 'log' + | 'mail' + | 'megaphone' | 'mention' + | 'meter' | 'milestone' + | 'moon' + | 'mortar-board' | 'mute' | 'no-entry' | 'north-star' + | 'note' + | 'number' | 'organization' | 'paintbrush' | 'paper-airplane' + | 'paste' + | 'pencil' + | 'people' + | 'person' + | 'person-add' + | 'pin' + | 'play' + | 'plug' + | 'plus' | 'project' + | 'pulse' + | 'question' + | 'quote' + | 'reply' + | 'report' + | 'rocket' + | 'ruby' + | 'search' + | 'shield' + | 'shield-check' + | 'shield-lock' | 'shield-x' + | 'sign-in' + | 'sign-out' | 'skip' + | 'smiley' + | 'square' | 'squirrel' | 'stack' + | 'star' + | 'stop' + | 'stopwatch' + | 'sun' + | 'sync' + | 'tag' | 'tasklist' + | 'telescope' | 'thumbsdown' | 'thumbsup' + | 'tools' + | 'trash' | 'typography' + | 'unlock' | 'unmute' - | 'workflow' + | 'verified' | 'versions' + | 'video' + | 'webhook' + | 'workflow' + | 'zap' diff --git a/src/types/response.ts b/src/types/response.ts index f28620be..7d155844 100644 --- a/src/types/response.ts +++ b/src/types/response.ts @@ -6,7 +6,7 @@ export type BaseError = { message: string; statusCode?: ClientErrorStatusCode } export type BaseErrorResponseFn = (response: BaseError) => TypedResponse export type TypedResponse = { - format: 'cast-action' | 'frame' | 'transaction' + format: 'castAction' | 'frame' | 'transaction' } & OneOf< { data: data; status: 'success' } | { error: BaseError; status: 'error' } > diff --git a/src/types/routes.ts b/src/types/routes.ts index be33e1b7..3334a830 100644 --- a/src/types/routes.ts +++ b/src/types/routes.ts @@ -83,7 +83,7 @@ export type H< ? FrameHandler : M extends 'transaction' ? TransactionHandler - : M extends 'cast-action' + : M extends 'castAction' ? CastActionHandler : Handler @@ -93,12 +93,12 @@ export type H< ////// ////// //////////////////////////////////////// -export interface HandlerInterface< +export type HandlerInterface< E extends Env = Env, M extends string = string, S extends Schema = {}, BasePath extends string = '/', -> { +> = { // app.get(path, handler, options) < P extends string, @@ -109,7 +109,9 @@ export interface HandlerInterface< >( path: P, handler: H, - options?: RouteOptions, + ...rest: M extends 'castAction' + ? [options: RouteOptions] + : [options?: RouteOptions] ): FrogBase< E, S & ToSchema, I['in'], MergeTypedResponseData>, @@ -129,7 +131,9 @@ export interface HandlerInterface< path: P, middleware: MiddlewareHandler, handler: H, - options?: RouteOptions, + ...rest: M extends 'castAction' + ? [options: RouteOptions] + : [options?: RouteOptions] ): FrogBase< E, S & @@ -153,7 +157,9 @@ export interface HandlerInterface< middleware: MiddlewareHandler, middleware_2: MiddlewareHandler, handler: H, - options?: RouteOptions, + ...rest: M extends 'castAction' + ? [options: RouteOptions] + : [options?: RouteOptions] ): FrogBase< E, S & @@ -180,7 +186,9 @@ export interface HandlerInterface< middleware_2: MiddlewareHandler, middleware_3: MiddlewareHandler, handler: H, - options?: RouteOptions, + ...rest: M extends 'castAction' + ? [options: RouteOptions] + : [options?: RouteOptions] ): FrogBase< E, S & @@ -210,7 +218,9 @@ export interface HandlerInterface< middleware_3: MiddlewareHandler, middleware_4: MiddlewareHandler, handler: H, - options?: RouteOptions, + ...rest: M extends 'castAction' + ? [options: RouteOptions] + : [options?: RouteOptions] ): FrogBase< E, S & @@ -243,7 +253,9 @@ export interface HandlerInterface< middleware_4: MiddlewareHandler, middleware_5: MiddlewareHandler, handler: H, - options?: RouteOptions, + ...rest: M extends 'castAction' + ? [options: RouteOptions] + : [options?: RouteOptions] ): FrogBase< E, S & @@ -279,7 +291,9 @@ export interface HandlerInterface< middleware_5: MiddlewareHandler, middleware_6: MiddlewareHandler, handler: H, - options?: RouteOptions, + ...rest: M extends 'castAction' + ? [options: RouteOptions] + : [options?: RouteOptions] ): FrogBase< E, S & @@ -318,7 +332,9 @@ export interface HandlerInterface< middleware_6: MiddlewareHandler, middleware_7: MiddlewareHandler, handler: H, - options?: RouteOptions, + ...rest: M extends 'castAction' + ? [options: RouteOptions] + : [options?: RouteOptions] ): FrogBase< E, S & @@ -360,7 +376,9 @@ export interface HandlerInterface< middleware_7: MiddlewareHandler, middleware_8: MiddlewareHandler, handler: H, - options?: RouteOptions, + ...rest: M extends 'castAction' + ? [options: RouteOptions] + : [options?: RouteOptions] ): FrogBase< E, S & @@ -407,7 +425,9 @@ export interface HandlerInterface< middleware_8: MiddlewareHandler, middleware_9: MiddlewareHandler, handler: H, - options?: RouteOptions, + ...rest: M extends 'castAction' + ? [options: RouteOptions] + : [options?: RouteOptions] ): FrogBase< E, S & diff --git a/src/utils/getCastActionContext.ts b/src/utils/getCastActionContext.ts index 91332337..4a2f17e9 100644 --- a/src/utils/getCastActionContext.ts +++ b/src/utils/getCastActionContext.ts @@ -36,7 +36,7 @@ export function getCastActionContext< env, error: (data) => ({ error: data, - format: 'cast-action', + format: 'castAction', status: 'error', }), actionData: { @@ -51,7 +51,7 @@ export function getCastActionContext< req, res: (data) => ({ data, - format: 'cast-action', + format: 'castAction', status: 'success', }), var: context.var, diff --git a/src/utils/getRouteParameters.ts b/src/utils/getRouteParameters.ts index b126fa10..4e8d1d64 100644 --- a/src/utils/getRouteParameters.ts +++ b/src/utils/getRouteParameters.ts @@ -2,10 +2,23 @@ import type { RouteOptions } from '../frog-base.js' import type { Env } from '../types/env.js' import type { MiddlewareHandler } from '../types/routes.js' -export function getRouteParameters( +export function getRouteParameters< + env extends Env, + handler, + method extends string, +>( ...parameters: any[] -): [string, MiddlewareHandler[], handler, RouteOptions] { - const options: RouteOptions | undefined = +): [ + string, + MiddlewareHandler[], + handler, + method extends 'castAction' + ? RouteOptions + : RouteOptions | undefined, +] { + const options: method extends 'castAction' + ? RouteOptions + : RouteOptions | undefined = typeof parameters[parameters.length - 1] === 'object' ? parameters[parameters.length - 1] : undefined @@ -17,5 +30,5 @@ export function getRouteParameters( else middlewares.push(parameters[i]) } - return [parameters[0], middlewares, handler!, options ?? {}] + return [parameters[0], middlewares, handler!, options] as const } From bfb2f702734314399412b446dbe943f962de0450 Mon Sep 17 00:00:00 2001 From: Vladyslav Dalechyn Date: Mon, 29 Apr 2024 01:57:24 +0300 Subject: [PATCH 10/10] feat: add `gas` parameter to transaction response (#286) * feat: add `gas` parameter to transaction response * chore: changesets * Update src/types/transaction.ts * Update frog-transaction-response.mdx --------- Co-authored-by: awkweb Co-authored-by: jxom --- .changeset/fair-lions-vanish.md | 5 ++ .../reference/frog-transaction-response.mdx | 50 +++++++++++++++++-- src/types/transaction.ts | 2 + src/utils/getTransactionContext.ts | 3 +- 4 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 .changeset/fair-lions-vanish.md diff --git a/.changeset/fair-lions-vanish.md b/.changeset/fair-lions-vanish.md new file mode 100644 index 00000000..bd654544 --- /dev/null +++ b/.changeset/fair-lions-vanish.md @@ -0,0 +1,5 @@ +--- +"frog": patch +--- + +Added `gas` parameter to transaction response to specify the gas limit. [See more](https://warpcast.com/horsefacts.eth/0xd6390bb3). diff --git a/site/pages/reference/frog-transaction-response.mdx b/site/pages/reference/frog-transaction-response.mdx index a97e4a04..b2073723 100644 --- a/site/pages/reference/frog-transaction-response.mdx +++ b/site/pages/reference/frog-transaction-response.mdx @@ -81,6 +81,28 @@ app.transaction('/send-ether', (c) => { }) ``` +### gas (optional) + +- **Type:** `BigInt` + +Gas limit of the transaction to send. + +```tsx twoslash +// @noErrors +import { Frog, parseEther } from 'frog' + +export const app = new Frog() + +app.transaction('/send-ether', (c) => { + return c.send({ + chainId: 'eip155:10', + gas: 100_000n, // [!code focus] + to: '0xd2135CfB216b74109775236E36d4b433F1DF507B', + value: parseEther('1'), + }) +}) +``` + ### to - **Type:** `Address` @@ -104,7 +126,7 @@ app.transaction('/send-ether', (c) => { ### value -- **Type:** `Address` +- **Type:** `Bigint` Value (in wei) to send with the transaction. @@ -256,6 +278,28 @@ app.transaction('/mint', (c) => { }) ``` +### gas (optional) + +- **Type:** `Bigint` + +Gas limit of the transaction to send. + +```tsx twoslash +// @noErrors +import { Frog, parseEther } from 'frog' + +export const app = new Frog() + +app.transaction('/send-ether', (c) => { + return c.send({ + chainId: 'eip155:10', + gas: 100_000n, // [!code focus] + to: '0xd2135CfB216b74109775236E36d4b433F1DF507B', + value: parseEther('1'), + }) +}) +``` + ### args - **Type:** `unknown` @@ -328,7 +372,7 @@ app.transaction('/mint', (c) => { ### value (optional) -- **Type:** `Address` +- **Type:** `Bigint` Value to send with the transaction. @@ -448,4 +492,4 @@ app.transaction('/raw-send', (c) => { attribution: true, // [!code focus] }) }) -``` \ No newline at end of file +``` diff --git a/src/types/transaction.ts b/src/types/transaction.ts index 7dd0b1e5..77eac328 100644 --- a/src/types/transaction.ts +++ b/src/types/transaction.ts @@ -55,6 +55,8 @@ export type EthSendTransactionParameters = { attribution?: boolean | undefined /** Transaction calldata. */ data?: Hex | undefined + /** Gas limit for the transaction. */ + gas?: quantity | undefined /** Transaction target address. */ to: Hex /** Value to send with transaction (in wei). */ diff --git a/src/utils/getTransactionContext.ts b/src/utils/getTransactionContext.ts index 1b38e5d1..6676e616 100644 --- a/src/utils/getTransactionContext.ts +++ b/src/utils/getTransactionContext.ts @@ -107,7 +107,7 @@ export function getTransactionContext< req, res(parameters) { const { attribution, chainId, method, params } = parameters - const { abi, data, to, value } = params + const { abi, data, gas, to, value } = params const response: TransactionResponse = { attribution, chainId, @@ -118,6 +118,7 @@ export function getTransactionContext< to, }, } + if (gas) response.params.gas = gas.toString() if (value) response.params.value = value.toString() return { data: response, format: 'transaction', status: 'success' } },