Skip to content

Commit

Permalink
refactor: createNeynar
Browse files Browse the repository at this point in the history
  • Loading branch information
tmm committed May 16, 2024
1 parent a9123a0 commit 1012bd5
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 51 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"changeset": "changeset",
"changeset:release": "pnpm build && changeset publish",
"changeset:version": "changeset version && pnpm install --lockfile-only && bun .scripts/postversion.ts",
"clean": "rimraf src/_lib src/ui/icons.ts src/ui/.frog src/tsconfig.build.tsbuildinfo",
"clean": "rimraf src/_lib src/protobufs/generated src/ui/icons/index.ts src/ui/icons/**/index.ts src/ui/icons/**/package.json src/ui/.frog src/tsconfig.build.tsbuildinfo",
"create-frog": "node --import tsx ./create-frog/bin.ts",
"docs:dev": "pnpm --filter site dev",
"docs:build": "pnpm --filter site build",
Expand Down
24 changes: 14 additions & 10 deletions playground/src/middleware.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Frog } from 'frog'
import type { MiddlewareHandler } from 'hono'

import { neynarMiddleware } from './neynar.js'
import { neynar } from './neynar.js'

type EchoMiddlewareVariables = {
echo: (str: string) => string
Expand All @@ -25,12 +25,16 @@ export const app = new Frog()
),
})
})
.frame('/neynar', neynarMiddleware, (c) => {
return c.res({
image: (
<div style={{ color: 'white', display: 'flex', fontSize: 60 }}>
{c.var.interactor?.displayName}
</div>
),
})
})
.frame(
'/neynar',
neynar.middleware({ features: ['cast', 'interactor'] }),
(c) => {
return c.res({
image: (
<div style={{ color: 'white', display: 'flex', fontSize: 60 }}>
{c.var.interactor?.displayName}
</div>
),
})
},
)
52 changes: 28 additions & 24 deletions playground/src/neynar.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Button, Frog } from 'frog'
import { createNeynar } from 'frog/middlewares'

const neynar = createNeynar({ apiKey: 'NEYNAR_FROG_FM' })
export const neynar = createNeynar({ apiKey: 'NEYNAR_FROG_FM' })

export const app = new Frog({ hub: neynar.hub })
export const app = new Frog({ hub: neynar.hub() })
.frame('/', (c) => {
return c.res({
action: '/guess',
Expand All @@ -25,25 +25,29 @@ export const app = new Frog({ hub: neynar.hub })
intents: [<Button>Go on</Button>],
})
})
.frame('/guess', neynar.middleware, (c) => {
const { displayName, followerCount } = c.var.interactor || {}
console.log('interactor: ', c.var.interactor)
console.log('cast: ', c.var.cast)
return c.res({
image: (
<div
style={{
alignItems: 'center',
color: 'white',
display: 'flex',
justifyContent: 'center',
fontSize: 48,
height: '100%',
width: '100%',
}}
>
Greetings {displayName}, you have {followerCount} followers.
</div>
),
})
})
.frame(
'/guess',
neynar.middleware({ features: ['cast', 'interactor'] }),
(c) => {
const { displayName, followerCount } = c.var.interactor || {}
console.log('interactor: ', c.var.interactor)
console.log('cast: ', c.var.cast)
return c.res({
image: (
<div
style={{
alignItems: 'center',
color: 'white',
display: 'flex',
justifyContent: 'center',
fontSize: 48,
height: '100%',
width: '100%',
}}
>
Greetings {displayName}, you have {followerCount} followers.
</div>
),
})
},
)
143 changes: 143 additions & 0 deletions site/pages/middlewares/neynar.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# Neynar

[Neynar](https://neynar.com/) is a Farcaster development platform that provides intuitive APIs to build on Farcaster.

## Import

```ts twoslash
import { neynar } from 'frog/middlewares'
```

## Usage

```tsx twoslash
// @noErrors
/** @jsxImportSource frog/jsx */
// ---cut---
import { Frog } from 'frog'
import { neynar } from 'frog/middlewares' // [!code focus]
export const app = new Frog()
.use( // [!code focus]
neynar({ // [!code focus]
apiKey: 'NEYNAR_FROG_FM', // [!code focus]
features: ['interactor', 'cast'], // [!code focus]
}), // [!code focus]
) // [!code focus]
```

:::warning
Feel free to use our Neynar API Key: `"NEYNAR_FROG_FM"`.

However, please note that this API Key is for development purposes only – it is prone to rate-limiting.
It is recommended to use your own API Key in production. [See more](https://neynar.com/#get-started).
:::

## Parameters

### apiKey

- **Type**: `string`

Neynar API key.

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

export const app = new Frog()
.use(
neynar({
apiKey: 'NEYNAR_FROG_FM', // [!code focus]
features: ['interactor', 'cast'],
}),
)
```

### features

- **Type**: `('interactor' | 'cast')[]`

Set of features to enable and inject into context.

- `'interactor'`: Fetches the user who interacted with the frame.
- `'cast'`: Fetches the cast of the frame.

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

export const app = new Frog()
.use(
neynar({
apiKey: 'NEYNAR_FROG_FM',
features: ['interactor', 'cast'], // [!code focus]
}),
)
```

---

## createNeynar

Convenience utility to setup a Neynar [hub](/hubs/neynar) and middleware with a single `apiKey`.

### Import

```ts twoslash
import { createNeynar } from 'frog/middlewares'
```

### Usage

```tsx twoslash
// @noErrors
/** @jsxImportSource frog/jsx */
// ---cut---
import { Frog } from 'frog'
import { createNeynar } from 'frog/middlewares' // [!code focus]
const neynar = createNeynar({ apiKey: 'NEYNAR_FROG_FM' }) // [!code focus]

export const app = new Frog({
hub: neynar.hub(), // [!code focus]
})
.use(
neynar.middleware({ features: ['interactor', 'cast'] }), // [!code focus]
)
```

### Parameters

```ts twoslash
import { type CreateNeynarParameters } from 'frog/middlewares'
```

#### apiKey

- **Type**: `string`

Neynar API key.

### Return Type

```ts twoslash
import { type CreateNeynarReturnType } from 'frog/middlewares'
// ^?










```
9 changes: 9 additions & 0 deletions site/vocs.config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,15 @@ export default defineConfig({
{ text: 'Frog.hono', link: '/reference/frog-hono' },
],
},
{
text: 'Middlewares',
items: [
{
text: 'Neynar',
link: '/middlewares/neynar',
},
],
},
{
text: 'Dev Reference',
items: [{ text: 'devtools', link: '/dev/devtools' }],
Expand Down
1 change: 1 addition & 0 deletions src/middlewares/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export {
createNeynar,
neynar,
type CreateNeynarParameters,
type CreateNeynarReturnType,
type NeynarVariables,
type NeynarCast,
type NeynarMiddlewareParameters,
Expand Down
42 changes: 26 additions & 16 deletions src/middlewares/neynar.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import type { MiddlewareHandler } from 'hono'
import { hexToBytes } from 'viem'

import { Message } from '../protobufs/generated/message_pb.js'
import type { Pretty } from '../types/utils.js'
import { messageToFrameData } from '../utils/verifyFrame.js'
import {
neynar as neynarHub,
type NeynarHubParameters,
neynar as neynarHub,
} from '../hubs/neynar.js'
import { Message } from '../protobufs/generated/message_pb.js'
import type { Pretty } from '../types/utils.js'
import { messageToFrameData } from '../utils/verifyFrame.js'
import type { Hub } from '../types/hub.js'

export type NeynarVariables = {
/**
Expand All @@ -28,8 +29,8 @@ export type NeynarMiddlewareParameters = {
/**
* Set of features to enable and inject into context.
*
* - `interactor`: Fetches the user who interacted with the frame.
* - `cast`: Fetches the cast of the frame.
* - `'interactor'`: Fetches the user who interacted with the frame.
* - `'cast'`: Fetches the cast of the frame.
*/
features: ('interactor' | 'cast')[]
}
Expand Down Expand Up @@ -195,18 +196,27 @@ export type NeynarUser = {

export type CreateNeynarParameters = {
apiKey: string
hub?: NeynarHubParameters | undefined
middleware?: NeynarMiddlewareParameters | undefined
}

export function createNeynar(parameters: CreateNeynarParameters) {
const {
apiKey,
hub = { apiKey },
middleware = { apiKey, features: ['cast', 'interactor'] },
} = parameters
export type CreateNeynarReturnType = {
hub: (parameters?: Pretty<Omit<NeynarHubParameters, 'apiKey'>>) => Hub
middleware: (
parameters: Pretty<Omit<NeynarMiddlewareParameters, 'apiKey'>>,
) => MiddlewareHandler<{
Variables: NeynarVariables
}>
}

export function createNeynar(
parameters: CreateNeynarParameters,
): CreateNeynarReturnType {
const { apiKey } = parameters
return {
hub: neynarHub(hub),
middleware: neynar(middleware),
hub(parameters = {}) {
return neynarHub({ ...parameters, apiKey })
},
middleware(parameters) {
return neynar({ ...parameters, apiKey })
},
}
}

0 comments on commit 1012bd5

Please sign in to comment.