Skip to content

Commit 628c6e5

Browse files
chore: update to new dep
1 parent df7bb10 commit 628c6e5

File tree

9 files changed

+124
-191
lines changed

9 files changed

+124
-191
lines changed

templates/next-starter-with-examples/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"@xmtp/frames-validator": "^0.5.0",
1616
"class-variance-authority": "^0.7.0",
1717
"clsx": "^2.1.0",
18-
"frames.js": "^0.8.0",
18+
"frames.js": "^0.9.1",
1919
"lucide-react": "^0.331.0",
2020
"next": "14.1.0",
2121
"react": "^18.2.0",
@@ -26,7 +26,7 @@
2626
"node": ">=18.17.0"
2727
},
2828
"devDependencies": {
29-
"@frames.js/debugger": "^0.1.5",
29+
"@frames.js/debugger": "^0.1.8",
3030
"@types/node": "^18.17.0",
3131
"@types/react": "^18.2.0",
3232
"@types/react-dom": "^18.2.0",

templates/next-utils-starter/app/api/frame/route.ts

-55
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import {
2+
getFrameMessageFromRequestBody,
3+
validateFrameMessage,
4+
} from "frames.js";
5+
import { redirect } from "frames.js/core";
6+
import { createFrames, Button } from "frames.js/next";
7+
8+
const frames = createFrames();
9+
10+
const handleRequest = frames(async (ctx) => {
11+
const body = await ctx.request.clone().json();
12+
13+
const untrustedMessage = getFrameMessageFromRequestBody(body);
14+
15+
if (untrustedMessage.data?.frameActionBody?.buttonIndex === 2) {
16+
return redirect(new URL("/redirect", ctx.url), { status: 302 });
17+
}
18+
19+
const result = await validateFrameMessage(body);
20+
21+
const { isValid, message } = result;
22+
23+
if (!isValid || !message) {
24+
return {
25+
image: <span>Invalid message</span>,
26+
};
27+
}
28+
29+
const randomInt = Math.floor(Math.random() * 100);
30+
const imageUrl = `https://picsum.photos/seed/${randomInt}/1146/600`;
31+
32+
return {
33+
image: imageUrl,
34+
buttons: [
35+
<Button action="post" key="1">
36+
{`Next (pressed by ${message?.data.fid.toString()})`}
37+
</Button>,
38+
<Button action="link" key="2" target={"https://framesjs.org"}>
39+
Visit frames.js
40+
</Button>,
41+
],
42+
};
43+
});
44+
45+
export const GET = handleRequest;
46+
export const POST = handleRequest;

templates/next-utils-starter/app/layout.tsx

+6-40
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,23 @@
1-
import { type FrameFlattened, getFrameFlattened } from "frames.js";
1+
import { fetchMetadata } from "frames.js/next";
22
import type { Metadata } from "next";
33
import { Inter } from "next/font/google";
4-
import { framePostUrl } from "./constants";
4+
import { framePostUrl, ogImage } from "./constants";
55

66
const inter = Inter({ subsets: ["latin"] });
77

8-
const imageUrl = "https://picsum.photos/seed/frames.js/1146/600";
9-
10-
/**
11-
* Stripes undefined values from a `FrameFlattened` object and returns a new object with only the defined values
12-
*/
13-
function convertFlattenedFrameToMetadata(
14-
frame: FrameFlattened
15-
): Metadata["other"] {
16-
const metadata: Metadata["other"] = {};
17-
18-
for (const [key, value] of Object.entries(frame)) {
19-
if (value != null) {
20-
metadata[key] = value;
21-
}
22-
}
23-
24-
return metadata;
25-
}
26-
278
export const metadata: Metadata = {
289
title: "Random Image Frame",
2910
description: "This is an example of a simple frame using frames.js",
3011
openGraph: {
3112
images: [
3213
{
33-
url: imageUrl,
14+
url: ogImage,
3415
},
3516
],
3617
},
37-
other: convertFlattenedFrameToMetadata(
38-
getFrameFlattened({
39-
image: imageUrl,
40-
version: "vNext",
41-
buttons: [
42-
{
43-
label: "Next",
44-
action: "post",
45-
},
46-
{
47-
label: "Visit frames.js",
48-
action: "post_redirect",
49-
},
50-
],
51-
inputText: "Type something",
52-
postUrl: framePostUrl,
53-
})
54-
),
18+
other: {
19+
...(await fetchMetadata(new URL("/frames", framePostUrl))),
20+
},
5521
};
5622

5723
export default function RootLayout({

templates/next-utils-starter/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99
"lint": "next lint"
1010
},
1111
"dependencies": {
12-
"frames.js": "^0.8.0",
12+
"frames.js": "^0.9.1",
1313
"next": "^14.0.4",
1414
"react": "^18.2.0",
1515
"react-dom": "^18.2.0"
1616
},
1717
"devDependencies": {
1818
"@next/eslint-plugin-next": "^14.0.4",
19-
"@frames.js/debugger": "^0.1.5",
19+
"@frames.js/debugger": "^0.1.8",
2020
"@types/eslint": "^8.56.1",
2121
"@types/node": "^20.10.6",
2222
"@types/react": "^18.2.46",

templates/next/app/frames/route.ts

-1
This file was deleted.

templates/next/app/frames/route.tsx

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { farcasterHubContext } from "frames.js/middleware";
2+
import { createFrames, Button } from "frames.js/next";
3+
4+
const frames = createFrames({
5+
middleware: [
6+
farcasterHubContext({
7+
// remove if you aren't using @frames.js/debugger or you just don't want to use the debugger hub
8+
...(process.env.NODE_ENV === "production"
9+
? {}
10+
: {
11+
hubHttpUrl: "http://localhost:3010/hub",
12+
}),
13+
}),
14+
],
15+
});
16+
17+
const handleRequest = frames(async (ctx) => {
18+
return {
19+
image: ctx.message ? (
20+
<div
21+
style={{
22+
display: "flex",
23+
flexDirection: "column",
24+
}}
25+
>
26+
GM, {ctx.message.requesterUserData?.displayName}! Your FID is{" "}
27+
{ctx.message.requesterFid}
28+
{", "}
29+
{ctx.message.requesterFid < 20_000
30+
? "you're OG!"
31+
: "welcome to the Farcaster!"}
32+
</div>
33+
) : (
34+
<div
35+
style={{
36+
display: "flex",
37+
flexDirection: "column",
38+
}}
39+
>
40+
Say GM
41+
</div>
42+
),
43+
buttons: ctx.url.searchParams.has("saidGm")
44+
? [
45+
<Button action="post" target={{ query: { saidGm: true } }}>
46+
Say GM
47+
</Button>,
48+
]
49+
: [],
50+
};
51+
});
52+
53+
export const GET = handleRequest;
54+
export const POST = handleRequest;

templates/next/app/page.tsx

+12-89
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,17 @@
1-
import {
2-
FrameButton,
3-
FrameContainer,
4-
FrameImage,
5-
FrameReducer,
6-
NextServerPageProps,
7-
getFrameMessage,
8-
getPreviousFrame,
9-
useFramesReducer,
10-
} from "frames.js/next/server";
1+
import { fetchMetadata } from "frames.js/next";
2+
import { Metadata } from "next";
113

12-
type State = {
13-
saidGm: boolean;
14-
};
15-
16-
const initialState: State = { saidGm: false };
17-
18-
const reducer: FrameReducer<State> = (state, action) => {
4+
export async function generateMetadata(): Promise<Metadata> {
195
return {
20-
saidGm: true,
6+
title: "Frames Next.js Example",
7+
other: {
8+
...(await fetchMetadata(
9+
new URL("/frames", process.env.VERCEL_URL || "http://localhost:3000")
10+
)),
11+
},
2112
};
22-
};
23-
24-
// This is a react server component only
25-
export default async function Home({
26-
params,
27-
searchParams,
28-
}: NextServerPageProps) {
29-
const previousFrame = getPreviousFrame<State>(searchParams);
30-
31-
const frameMessage = await getFrameMessage(previousFrame.postBody, {
32-
// remove if you aren't using @frames.js/debugger or you just don't want to use the debugger hub
33-
...(process.env.NODE_ENV === "production"
34-
? {}
35-
: {
36-
hubHttpUrl: "http://localhost:3010/hub",
37-
}),
38-
});
39-
40-
if (frameMessage && !frameMessage?.isValid) {
41-
throw new Error("Invalid frame payload");
42-
}
43-
44-
const [state, dispatch] = useFramesReducer<State>(
45-
reducer,
46-
initialState,
47-
previousFrame
48-
);
49-
50-
// Here: do a server side side effect either sync or async (using await), such as minting an NFT if you want.
51-
// example: load the users credentials & check they have an NFT
52-
console.log("info: state is:", state);
13+
}
5314

54-
// then, when done, return next frame
55-
return (
56-
<div>
57-
GM user data example.
58-
<FrameContainer
59-
pathname="/"
60-
postUrl="/frames"
61-
state={state}
62-
previousFrame={previousFrame}
63-
>
64-
<FrameImage>
65-
{frameMessage ? (
66-
<div
67-
style={{
68-
display: "flex",
69-
flexDirection: "column",
70-
}}
71-
>
72-
GM, {frameMessage.requesterUserData?.displayName}! Your FID is{" "}
73-
{frameMessage.requesterFid}
74-
{", "}
75-
{frameMessage.requesterFid < 20_000
76-
? "you're OG!"
77-
: "welcome to the Farcaster!"}
78-
</div>
79-
) : (
80-
<div
81-
style={{
82-
display: "flex",
83-
flexDirection: "column",
84-
}}
85-
>
86-
Say GM
87-
</div>
88-
)}
89-
</FrameImage>
90-
{!state.saidGm ? <FrameButton>Say GM</FrameButton> : null}
91-
</FrameContainer>
92-
</div>
93-
);
15+
export default async function Home() {
16+
return <div>GM user data example.</div>;
9417
}

templates/next/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"private": true,
55
"type": "module",
66
"dependencies": {
7-
"frames.js": "^0.8.0",
7+
"frames.js": "^0.9.1",
88
"next": "^14.1.2",
99
"react": "^18.2.0",
1010
"react-dom": "^18.2.0"
@@ -13,7 +13,7 @@
1313
"@types/node": "^18.17.0",
1414
"@types/react": "^18.2.0",
1515
"@types/react-dom": "^18.2.0",
16-
"@frames.js/debugger": "^0.1.5",
16+
"@frames.js/debugger": "^0.1.8",
1717
"concurrently": "^8.2.2",
1818
"typescript": "^5.3.3"
1919
},

0 commit comments

Comments
 (0)