Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/wevm/framework
Browse files Browse the repository at this point in the history
  • Loading branch information
tmm committed Feb 15, 2024
2 parents 0e38db5 + cd75c95 commit 8d5997e
Show file tree
Hide file tree
Showing 9 changed files with 383 additions and 8 deletions.
2 changes: 1 addition & 1 deletion src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type HtmlEscapedString } from 'hono/utils/html'
import type { HtmlEscapedString } from 'hono/utils/html'

export type ButtonProps = {
children: string
Expand Down
2 changes: 1 addition & 1 deletion src/dev/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { validator } from 'hono/validator'

import { type FarcBase } from '../farc-base.js'
import { parsePath } from '../utils/parsePath.js'
import { Preview, Scripts, Styles, type PreviewProps } from './components.js'
import { Preview, type PreviewProps, Scripts, Styles } from './components.js'
import {
fetchFrame,
getCodeHtml,
Expand Down
22 changes: 21 additions & 1 deletion src/farc-base.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@ export type FarcConstructorParameters<
> = {
basePath?: basePath | string | undefined
honoOptions?: HonoOptions<env> | undefined
hubApiUrl?: string | undefined
initialState?: state | undefined
verify?: boolean | undefined
}

export type FrameOptions = {
verify?: boolean
}

export type FrameHandlerReturnType = {
Expand All @@ -47,17 +53,25 @@ export class FarcBase<

basePath: string
hono: Hono<env, schema, basePath>
hubApiUrl = 'https://api.hub.wevm.dev'
fetch: Hono<env, schema, basePath>['fetch']
get: Hono<env, schema, basePath>['get']
post: Hono<env, schema, basePath>['post']
// TODO: default to `true` once devtools has auth.
verify: boolean = process.env.NODE_ENV !== 'development'

constructor({
basePath,
honoOptions,
hubApiUrl,
initialState,
verify,
}: FarcConstructorParameters<state, env, basePath> = {}) {
this.hono = new Hono<env, schema, basePath>(honoOptions)
if (basePath) this.hono = this.hono.basePath(basePath)
if (hubApiUrl) this.hubApiUrl = hubApiUrl
if (typeof verify !== 'undefined') this.verify = verify

this.basePath = basePath ?? '/'
this.fetch = this.hono.fetch.bind(this.hono)
this.get = this.hono.get.bind(this.hono)
Expand All @@ -71,13 +85,19 @@ export class FarcBase<
handler: (
context: FrameContext<path, state>,
) => FrameHandlerReturnType | Promise<FrameHandlerReturnType>,
options: FrameOptions = {},
) {
const { verify = this.verify } = options

// Frame Route (implements GET & POST).
this.hono.use(parsePath(path), async (c) => {
const url = new URL(c.req.url)

const context = await getFrameContext<state>({
context: await requestToContext(c.req),
context: await requestToContext(c.req, {
hubApiUrl: this.hubApiUrl,
verify,
}),
initialState: this.#initialState,
request: c.req,
})
Expand Down
9 changes: 7 additions & 2 deletions src/farc.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { type Env, type Schema } from 'hono'

import { routes as devRoutes } from './dev/routes.js'
import { FarcBase, type FrameHandlerReturnType } from './farc-base.js'
import {
FarcBase,
type FrameHandlerReturnType,
type FrameOptions,
} from './farc-base.js'
import { type FrameContext } from './types.js'

export class Farc<
Expand All @@ -15,8 +19,9 @@ export class Farc<
handler: (
context: FrameContext<path, state>,
) => FrameHandlerReturnType | Promise<FrameHandlerReturnType>,
options: FrameOptions = {},
) {
super.frame(path, handler)
super.frame(path, handler, options)

devRoutes(this, path)
}
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type FrameContext<path extends string = string, state = unknown> = {
* - `response` - The frame has been interacted with (user presses button).
*/
status: 'initial' | 'redirect' | 'response'
verified: boolean
url: Context['req']['url']
}

Expand Down
4 changes: 3 additions & 1 deletion src/utils/getFrameContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type GetFrameContextParameters<state = unknown> = {
| 'frameData'
| 'status'
| 'url'
| 'verified'
>
initialState?: state
request: Context['req']
Expand All @@ -22,7 +23,7 @@ export async function getFrameContext<state>(
options: GetFrameContextParameters<state>,
): Promise<FrameContext<string, state>> {
const { context, request } = options
const { frameData, initialUrl, previousIntentData } = context || {}
const { frameData, initialUrl, previousIntentData, verified } = context || {}

const { buttonValue, inputText, redirect, reset } = getIntentState(
frameData,
Expand Down Expand Up @@ -58,5 +59,6 @@ export async function getFrameContext<state>(
request,
status,
url,
verified,
}
}
27 changes: 25 additions & 2 deletions src/utils/requestToContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import type { Context } from 'hono'
import type { FrameContext } from '../types.js'
import { fromQuery } from './fromQuery.js'
import { parsePath } from './parsePath.js'
import { verifyFrame } from './verifyFrame.js'

type RequestToContextOptions = {
hubApiUrl: string
verify?: boolean
}

type RequestToContextReturnType<state = unknown> = Pick<
FrameContext<string, state>,
Expand All @@ -11,23 +17,40 @@ type RequestToContextReturnType<state = unknown> = Pick<
| 'frameData'
| 'status'
| 'url'
| 'verified'
>

export async function requestToContext<state>(
request: Context['req'],
{ hubApiUrl, verify = true }: RequestToContextOptions,
): Promise<RequestToContextReturnType<state>> {
const { trustedData: _trustedData, untrustedData } =
const { trustedData, untrustedData } =
(await request.json().catch(() => {})) || {}
const { initialUrl, previousState, previousIntentData } = fromQuery<
FrameContext<string, state>
>(request.query())

const message = await (() => {
if (!verify) return
if (!trustedData) return
return verifyFrame({
hubApiUrl,
trustedData,
url: request.url,
}).catch((err) => {
if (verify) throw err
})
})()

const frameData = message?.data?.frameActionBody ?? untrustedData

return {
initialUrl: initialUrl ? initialUrl : parsePath(request.url),
previousState,
previousIntentData,
frameData: untrustedData,
frameData,
status: request.method === 'POST' ? 'response' : 'initial',
url: request.url,
verified: Boolean(message),
}
}
Loading

0 comments on commit 8d5997e

Please sign in to comment.