diff --git a/biome.json b/biome.json index 386d247b..7fd9d543 100644 --- a/biome.json +++ b/biome.json @@ -22,6 +22,7 @@ "rules": { "recommended": true, "complexity": { + "noBannedTypes": "off", "noUselessFragments": "off" }, "suspicious": { diff --git a/bun.lockb b/bun.lockb index 88d3a329..aa450a8d 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/src/index.tsx b/src/index.tsx index 2ff6765f..da71f149 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -11,7 +11,12 @@ import { type Context, Hono } from 'hono' import { ImageResponse } from 'hono-og' import { type JSXNode } from 'hono/jsx' import { jsxRenderer } from 'hono/jsx-renderer' +import type { Env, Schema } from 'hono/types' import { type HtmlEscapedString } from 'hono/utils/html' +import { + compressToEncodedURIComponent, + decompressFromEncodedURIComponent, +} from 'lz-string' import { Preview, previewStyles } from './preview.js' import { @@ -33,22 +38,24 @@ type FrameHandlerReturnType = { image: JSX.Element intents?: Intents | undefined } - -export class Farc extends Hono { - frame( - path: string, +export class Farc< + E extends Env = Env, + S extends Schema = {}, + BasePath extends string = '/', +> extends Hono { + frame

( + path: P, handler: ( - context: FrameContext, + context: FrameContext

, previousContext?: PreviousFrameContext | undefined, ) => FrameHandlerReturnType | Promise, ) { // Frame Route (implements GET & POST). this.use(path, async (c) => { const query = c.req.query() - const previousContext = - query.previousContext && query.previousContext !== 'undefined' - ? deserializeJson(query.previousContext) - : undefined + const previousContext = query.previousContext + ? deserializeJson(query.previousContext) + : undefined const context = await getFrameContext(c, previousContext) const { intents } = await handler(context, previousContext) @@ -60,31 +67,30 @@ export class Farc extends Hono { intents: parsedIntents, }) + const ogSearch = new URLSearchParams() + if (query.previousContext) + ogSearch.set('previousContext', query.previousContext) + if (serializedContext) ogSearch.set('context', serializedContext) + + const postSearch = new URLSearchParams() + if (serializedPreviousContext) + postSearch.set('previousContext', serializedPreviousContext) + return c.render( {parsedIntents} @@ -104,11 +110,13 @@ export class Farc extends Hono { this.get(`${toBaseUrl(path)}/image`, async (c) => { const query = c.req.query() const parsedContext = deserializeJson(query.context) - const parsedPreviousContext = - query.previousContext && query.previousContext !== 'undefined' - ? deserializeJson(query.previousContext) - : undefined - const { image } = await handler(parsedContext, parsedPreviousContext) + const parsedPreviousContext = query.previousContext + ? deserializeJson(query.previousContext) + : undefined + const { image } = await handler( + { ...parsedContext, request: c.req }, + parsedPreviousContext, + ) return new ImageResponse(image) }) @@ -401,6 +409,7 @@ async function getFrameContext( buttonIndex, buttonValue, inputText, + request: req, status, trustedData, untrustedData, @@ -450,13 +459,13 @@ function toBaseUrl(path_: string) { return path } -function deserializeJson(data = '{}'): returnType { +function deserializeJson(data = ''): returnType { if (data === 'undefined') return {} as returnType - return JSON.parse(decodeURIComponent(data)) + return JSON.parse(decompressFromEncodedURIComponent(data)) } function serializeJson(data: unknown = {}) { - return encodeURIComponent(JSON.stringify(data)) + return compressToEncodedURIComponent(JSON.stringify(data)) } export function htmlToMetaTags(html: string, selector: string) { diff --git a/src/package.json b/src/package.json index cf3c41de..73e946da 100644 --- a/src/package.json +++ b/src/package.json @@ -16,6 +16,7 @@ "@farcaster/core": "^0.13.7", "@noble/curves": "^1.3.0", "happy-dom": "^13.3.8", - "hono-og": "~0.0.2" + "hono-og": "~0.0.2", + "lz-string": "^1.5.0" } } diff --git a/src/preview.tsx b/src/preview.tsx index 2a489c32..5429bba8 100644 --- a/src/preview.tsx +++ b/src/preview.tsx @@ -63,7 +63,7 @@ function Frame(props: FrameProps) { return (

diff --git a/src/types.ts b/src/types.ts index e8838c91..65f34a81 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,12 +1,13 @@ // TODO: TSDoc -import { type Context } from 'hono' +import { type Context, type Env } from 'hono' import { type JSXNode } from 'hono/jsx' -export type FrameContext = { +export type FrameContext

= { buttonIndex?: number buttonValue?: string inputText?: string + request: Context['req'] /** * Status of the frame in the frame lifecycle. * - `initial` - The frame has not yet been interacted with.