Skip to content

Commit

Permalink
feat: composer action metadata (#431)
Browse files Browse the repository at this point in the history
* feat: composer action metadata

* chore: changesets

* docs: up

* nit: lint
  • Loading branch information
dalechyn authored Jul 22, 2024
1 parent 302bef8 commit c1f5be4
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 42 deletions.
26 changes: 26 additions & 0 deletions .changeset/mighty-pears-collect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
"frog": minor
---

**Breaking Change**. Composer Action Handlers now require a third argument to define metadata.

```diff
export const app = new Frog({
title: 'Composer Action',
}).composerAction(
'/',
async (c) => {
if (Math.random() > 0.5) return c.error({ message: 'Action failed :(' })
return c.res({
title: 'Some Composer Action',
url: 'https://example.com',
})
},
+ {
+ name: 'Some Composer Action',
+ description: 'Cool Composer Action',
+ icon: 'image',
+ imageUrl: 'https://frog.fm/logo-light.svg',
+ },
)
```
28 changes: 16 additions & 12 deletions playground/src/composerAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@ import { vars } from './ui.js'
export const app = new Frog({
ui: { vars },
title: 'Composer Action',
}).composerAction('/', async (c) => {
console.log(
`Composer Action call ${JSON.stringify(c.actionData, null, 2)} from ${
c.actionData.fid
}`,
)
// if (Math.random() > 0.5) return c.error({ message: 'Action failed :(' })
return c.res({
title: 'Some Composer Action',
url: 'https://example.com',
})
})
}).composerAction(
'/',
async (c) => {
if (Math.random() > 0.5) return c.error({ message: 'Action failed :(' })
return c.res({
title: 'Some Composer Action',
url: 'https://example.com',
})
},
{
name: 'Some Composer Action',
description: 'Cool Composer Action',
icon: 'image',
imageUrl: 'https://frog.fm/logo-light.svg',
},
)
8 changes: 8 additions & 0 deletions site/pages/concepts/composer-actions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ app.composerAction(
title: 'My Composer Action',
url: 'https://example.com'
})
},
{
/* Name of the action – 14 characters max. */
name: 'Some Composer Action',
/* Description of the action – 20 characters max. */
description: 'Cool Composer Action',
icon: 'image',
imageUrl: 'https://frog.fm/logo-light.svg',
}
)
```
Expand Down
3 changes: 3 additions & 0 deletions site/pages/reference/frog-composer-action-response.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ app.composerAction('/', (c) => {
// ... // [!code focus]
}) // [!code focus]
},
{ /* options */ }
)
```

Expand All @@ -35,6 +36,7 @@ app.composerAction('/', (c) => {
url: 'https://example.com'
})
},
{ /* options */ }
)
```

Expand All @@ -57,5 +59,6 @@ app.composerAction('/', (c) => {
url: 'https://example.com' // [!code focus]
})
},
{ /* options */ }
)
```
63 changes: 57 additions & 6 deletions site/pages/reference/frog-composer-action.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,21 @@ import { Frog } from 'frog'

const app = new Frog({ title: 'Frog Frame' })

app.composerAction('/', (c) => { // [!code focus]
return c.res({
title: 'My Composr Action', // [!code focus]
url: 'https://example.com' // [!code focus]
}) // [!code focus]
}) // [!code focus]
app.composerAction( // [!code focus]
'/', // [!code focus]
(c) => { // [!code focus]
return c.res({
title: 'My Composr Action', // [!code focus]
url: 'https://example.com' // [!code focus]
}) // [!code focus]
}, // [!code focus]
{ // [!code focus]
name: 'Some Composer Action', // [!code focus]
description: 'Cool Composer Action', // [!code focus]
icon: 'image', // [!code focus]
imageUrl: 'https://frog.fm/logo-light.svg', // [!code focus]
} // [!code focus]
) // [!code focus]
```

## Parameters
Expand All @@ -47,6 +56,12 @@ app.composerAction(
title: 'My Composr Action',
url: 'https://example.com'
})
},
{
name: 'Some Composer Action',
description: 'Cool Composer Action',
icon: 'image',
imageUrl: 'https://frog.fm/logo-light.svg',
}
)
```
Expand All @@ -71,6 +86,42 @@ app.composerAction(
title: 'My Composr Action', // [!code focus]
url: 'https://example.com' // [!code focus]
}) // [!code focus]
}, // [!code focus]
{
name: 'Some Composer Action',
description: 'Cool Composer Action',
icon: 'image',
imageUrl: 'https://frog.fm/logo-light.svg',
}
)
```

### options

- **Type:** `RouteOptions<'composerAction'>`

Options for Composer Action

```tsx twoslash
/** @jsxImportSource frog/jsx */
// ---cut---
import { Frog } from 'frog'

const app = new Frog({ title: 'Frog Frame' })

app.composerAction(
'/',
(c) => {
return c.res({
title: 'My Composr Action',
url: 'https://example.com'
})
},
{ // [!code focus]
name: 'Some Composer Action', // [!code focus]
description: 'Cool Composer Action', // [!code focus]
icon: 'image', // [!code focus]
imageUrl: 'https://frog.fm/logo-light.svg', // [!code focus]
} // [!code focus]
)
```
Expand Down
50 changes: 48 additions & 2 deletions src/frog-base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import lz from 'lz-string'
import { default as p } from 'path-browserify'

import type { CastActionOptions } from './types/castAction.js'
import type { ComposerActionOptions } from './types/composerAction.js'
import type { Env } from './types/env.js'
import type {
FrameImageAspectRatio,
Expand Down Expand Up @@ -209,7 +210,19 @@ export type RouteOptions<
c: Context<E, P, I>,
) => Promise<CastActionOptions> | CastActionOptions
}
: {})
: method extends 'composerAction'
?
| ComposerActionOptions
| {
/**
* Custom handler for Composer Action `GET` response.
* One can use that if something needs to be derived from the `Context`.
*/
handler: (
c: Context<E, P, I>,
) => Promise<ComposerActionOptions> | ComposerActionOptions
}
: {})

/**
* A Frog instance.
Expand Down Expand Up @@ -436,14 +449,47 @@ export class FrogBase<
composerAction: HandlerInterface<env, 'composerAction', schema, basePath> = (
...parameters: any[]
) => {
const [path, middlewares, handler, options = {}] = getRouteParameters<
const [path, middlewares, handler, options] = getRouteParameters<
env,
ComposerActionHandler<env>,
'composerAction'
>(...parameters)

const { verify = this.verify } = options

// Composer Action Route (implements GET).
if ('handler' in options) {
this.hono.get(parseHonoPath(path), ...middlewares, async (c) => {
const { aboutUrl, name, description, icon, imageUrl } =
await options.handler(c)
return c.json({
aboutUrl,
action: {
type: 'post',
},
description,
icon,
imageUrl,
name,
})
})
} else {
const { aboutUrl, name, description, icon, imageUrl } = options

this.hono.get(parseHonoPath(path), ...middlewares, async (c) => {
return c.json({
aboutUrl,
action: {
type: 'post',
},
description,
icon,
imageUrl,
name,
})
})
}

// Composer Action Route (implements POST).
this.hono.post(parseHonoPath(path), ...middlewares, async (c) => {
const { context } = getComposerActionContext<env, string>({
Expand Down
32 changes: 32 additions & 0 deletions src/types/composerAction.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,37 @@
import type { CastActionOptions } from './castAction.js'
import type { TypedResponse } from './response.js'

export type ComposerActionOptions = {
/**
* Optional external link to an "about" page.
* You should only include this if you can't fully describe your
* action using the `description` field.
* Must be http or https protocol.
*
* @example `'https://somewhere.com'`
*/
aboutUrl?: CastActionOptions['aboutUrl']
/**
* A short description up to 20 characters.
*
* @example `'My awesome action description.'`
*/
description: NonNullable<CastActionOptions['description']>
icon: CastActionOptions['icon']
/**
* Remote image URL.
*
* @example `'https://somewhere.com/image.png'`
*/
imageUrl: string
/**
* An action name up to 14 characters.
*
* @example `'My action.'`
*/
name: CastActionOptions['name']
}

export type ComposerActionResponse = {
/**
* Title of the action.
Expand Down
Loading

0 comments on commit c1f5be4

Please sign in to comment.