Skip to content

Commit 0bbcc19

Browse files
feat: handle multi protocol result in render package
1 parent 199d535 commit 0bbcc19

File tree

20 files changed

+340
-152
lines changed

20 files changed

+340
-152
lines changed

packages/debugger/app/debugger-page.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
type OnSignatureFunc,
1111
type FrameActionBodyPayload,
1212
type OnConnectWalletFunc,
13+
type FarcasterFrameContext,
1314
} from "@frames.js/render";
1415
import { attribution } from "@frames.js/render/farcaster";
1516
import { useFrame } from "@frames.js/render/use-frame";
@@ -174,7 +175,7 @@ export default function DebuggerPage({
174175

175176
const searchParams = new URLSearchParams({
176177
url: newUrl || url,
177-
specification: protocolConfiguration?.specification,
178+
specification: protocolConfiguration.specification,
178179
actions: "true",
179180
});
180181
const proxiedUrl = `/frames?${searchParams.toString()}`;
@@ -196,7 +197,7 @@ export default function DebuggerPage({
196197
setInitialAction(json);
197198
setInitialFrame(undefined);
198199
} else if (json.type === "frame") {
199-
setInitialFrame(json);
200+
setInitialFrame(json[protocolConfiguration.specification]);
200201
setInitialAction(undefined);
201202
}
202203
})
@@ -573,7 +574,8 @@ export default function DebuggerPage({
573574

574575
const farcasterFrameConfig: UseFrameOptions<
575576
FarcasterSigner | null,
576-
FrameActionBodyPayload
577+
FrameActionBodyPayload,
578+
FarcasterFrameContext
577579
> = useMemo(() => {
578580
const attributionData = process.env.NEXT_PUBLIC_FARCASTER_ATTRIBUTION_FID
579581
? attribution(parseInt(process.env.NEXT_PUBLIC_FARCASTER_ATTRIBUTION_FID))

packages/debugger/app/frames/route.ts

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
import { type FrameActionPayload, getFrame } from "frames.js";
1+
import { type FrameActionPayload } from "frames.js";
22
import { type NextRequest } from "next/server";
33
import { getAction } from "../actions/getAction";
44
import { persistMockResponsesForDebugHubRequests } from "../utils/mock-hub-utils";
55
import type { SupportedParsingSpecification } from "frames.js";
6+
import { parseFramesWithReports } from "frames.js/parseFramesWithReports";
67
import { z } from "zod";
78
import type { ParseActionResult } from "../actions/types";
8-
import type { ParseResult } from "frames.js/frame-parsers";
9+
import type { ParseFramesWithReportsResult } from "frames.js/frame-parsers";
10+
import type { JsonObject } from "frames.js/types";
911

1012
const castActionMessageParser = z.object({
1113
type: z.literal("message"),
@@ -43,7 +45,7 @@ export type CastActionDefinitionResponse = ParseActionResult & {
4345
url: string;
4446
};
4547

46-
export type FrameDefinitionResponse = ParseResult & {
48+
export type FrameDefinitionResponse = ParseFramesWithReportsResult & {
4749
type: "frame";
4850
};
4951

@@ -91,17 +93,16 @@ export async function GET(request: NextRequest): Promise<Response> {
9193
} satisfies CastActionDefinitionResponse);
9294
}
9395

94-
const htmlString = await urlRes.text();
96+
const html = await urlRes.text();
9597

96-
const result = getFrame({
97-
htmlString,
98-
url,
99-
specification,
98+
const parseResult = parseFramesWithReports({
99+
html,
100+
fallbackPostUrl: url,
100101
fromRequestMethod: "GET",
101102
});
102103

103104
return Response.json({
104-
...result,
105+
...parseResult,
105106
type: "frame",
106107
} satisfies FrameDefinitionResponse);
107108
} catch (err) {
@@ -138,7 +139,7 @@ export async function POST(req: NextRequest): Promise<Response> {
138139
}
139140

140141
if (!postUrl) {
141-
return Response.error();
142+
return Response.json({ message: "Invalid post URL" }, { status: 400 });
142143
}
143144

144145
try {
@@ -197,7 +198,7 @@ export async function POST(req: NextRequest): Promise<Response> {
197198
}
198199

199200
if (isTransactionRequest) {
200-
const transaction = (await r.json()) as JSON;
201+
const transaction = (await r.json()) as JsonObject;
201202
return Response.json(transaction);
202203
}
203204

@@ -221,19 +222,26 @@ export async function POST(req: NextRequest): Promise<Response> {
221222
});
222223
}
223224

224-
const htmlString = await r.text();
225+
const html = await r.text();
225226

226-
const result = getFrame({
227-
htmlString,
228-
url: body.untrustedData.url,
229-
specification,
227+
const parseResult = parseFramesWithReports({
228+
html,
229+
fallbackPostUrl: body.untrustedData.url,
230230
fromRequestMethod: "POST",
231231
});
232232

233-
return Response.json(result);
233+
return Response.json({
234+
type: "frame",
235+
...parseResult,
236+
} satisfies FrameDefinitionResponse);
234237
} catch (err) {
235238
// eslint-disable-next-line no-console -- provide feedback to the user
236239
console.error(err);
237-
return Response.error();
240+
return Response.json(
241+
{
242+
message: String(err),
243+
},
244+
{ status: 500 }
245+
);
238246
}
239247
}

packages/render/src/collapsed-frame-ui.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export function CollapsedFrameUI({
138138
cursor: isLoading ? undefined : "pointer",
139139
}}
140140
>
141-
{frame.buttons.length === 1 && frame.buttons[0].label.length < 12
141+
{!!frame.buttons[0] && frame.buttons[0].label.length < 12
142142
? frame.buttons[0].label
143143
: "View"}
144144
</button>

packages/render/src/fallback-frame-context.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { FarcasterFrameContext } from "./farcaster";
1+
import type { FarcasterFrameContext } from "./farcaster/types";
22

33
export const fallbackFrameContext: FarcasterFrameContext = {
44
castId: {

packages/render/src/farcaster/frames.tsx

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,14 @@ import type {
1616
SignFrameActionFunc,
1717
} from "../types";
1818
import type { FarcasterSigner } from "./signers";
19-
20-
export type FarcasterFrameContext = {
21-
/** Connected address of user, only sent with transaction data request */
22-
address?: `0x${string}`;
23-
castId: { hash: `0x${string}`; fid: number };
24-
};
19+
import type { FarcasterFrameContext } from "./types";
2520

2621
/** Creates a frame action for use with `useFrame` and a proxy */
27-
export const signFrameAction: SignFrameActionFunc<FarcasterSigner> = async (
28-
actionContext
29-
) => {
22+
export const signFrameAction: SignFrameActionFunc<
23+
FarcasterSigner,
24+
FrameActionBodyPayload,
25+
FarcasterFrameContext
26+
> = async (actionContext) => {
3027
const {
3128
frameButton,
3229
signer,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from "./frames";
22
export * from "./signers";
33
export * from "./attribution";
4+
export * from "./types";

packages/render/src/farcaster/signers.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
import type { SignerStateInstance } from "..";
1+
import type { FrameActionBodyPayload, SignerStateInstance } from "../types";
2+
import type { FarcasterFrameContext } from "./types";
23

34
export type FarcasterSignerState<TSignerType = FarcasterSigner | null> =
4-
SignerStateInstance<TSignerType>;
5+
SignerStateInstance<
6+
TSignerType,
7+
FrameActionBodyPayload,
8+
FarcasterFrameContext
9+
>;
510

611
export type FarcasterSignerPendingApproval = {
712
status: "pending_approval";
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export type FarcasterFrameContext = {
2+
/** Connected address of user, only sent with transaction data request */
3+
address?: `0x${string}`;
4+
castId: { hash: `0x${string}`; fid: number };
5+
};

packages/render/src/helpers.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { ParseFramesWithReportsResult } from "frames.js/frame-parsers";
2+
13
export async function tryCallAsync<TResult>(
24
promiseFn: () => Promise<TResult>
35
): Promise<TResult | Error> {
@@ -25,3 +27,14 @@ export function tryCall<TReturn>(fn: () => TReturn): TReturn | Error {
2527
return new TypeError("Unexpected error, check the console for details");
2628
}
2729
}
30+
31+
export function isParseFramesWithReportsResult(
32+
value: unknown
33+
): value is ParseFramesWithReportsResult {
34+
return (
35+
typeof value === "object" &&
36+
value !== null &&
37+
"openframes" in value &&
38+
"farcaster" in value
39+
);
40+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { useRef } from "react";
2+
3+
export function useFreshRef<T>(value: T): React.MutableRefObject<T> {
4+
const ref = useRef(value);
5+
ref.current = value;
6+
return ref;
7+
}

0 commit comments

Comments
 (0)