mirror of
https://github.com/neynarxyz/create-farcaster-mini-app.git
synced 2025-11-19 17:36:09 -05:00
feat: auto-generate manifest
This commit is contained in:
@@ -1,17 +1,24 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
export async function GET() {
|
||||
const appUrl = process.env.NEXT_PUBLIC_URL;
|
||||
|
||||
let accountAssociation; // TODO: add type
|
||||
try {
|
||||
const manifestPath = join(process.cwd(), 'public/manifest.json');
|
||||
const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
|
||||
accountAssociation = manifest;
|
||||
} catch (error) {
|
||||
console.warn('Warning: manifest.json not found or invalid. Frame will not be associated with an account.');
|
||||
accountAssociation = null;
|
||||
}
|
||||
|
||||
const config = {
|
||||
accountAssociation: {
|
||||
header:
|
||||
"eyJmaWQiOjM2MjEsInR5cGUiOiJjdXN0b2R5Iiwia2V5IjoiMHgyY2Q4NWEwOTMyNjFmNTkyNzA4MDRBNkVBNjk3Q2VBNENlQkVjYWZFIn0",
|
||||
payload: "eyJkb21haW4iOiJmcmFtZXMtdjIudmVyY2VsLmFwcCJ9",
|
||||
signature:
|
||||
"MHhiNDIwMzQ1MGZkNzgzYTExZjRiOTllZTFlYjA3NmMwOTdjM2JkOTY1NGM2ODZjYjkyZTAyMzk2Y2Q0YjU2MWY1MjY5NjI5ZGQ5NTliYjU0YzEwOGI4OGVmNjdjMTVlZTdjZDc2YTRiMGU5NzkzNzA3YzkxYzFkOWFjNTg0YmQzNjFi",
|
||||
},
|
||||
...(accountAssociation && { accountAssociation }),
|
||||
frame: {
|
||||
version: "1",
|
||||
name: "Frames v2 Demo",
|
||||
name: process.env.NEXT_PUBLIC_FRAME_NAME || "Frames v2 Demo",
|
||||
iconUrl: `${appUrl}/icon.png`,
|
||||
homeUrl: appUrl,
|
||||
imageUrl: `${appUrl}/frames/hello/opengraph-image`,
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
|
||||
// note: dynamic import is required for components that use the Frame SDK
|
||||
const Demo = dynamic(() => import("~/components/Demo"), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
title: "Launch Frame",
|
||||
action: {
|
||||
type: "launch_frame",
|
||||
name: "Farcaster Frames v2 Demo",
|
||||
name: process.env.NEXT_PUBLIC_FRAME_NAME || "Frames v2 Demo",
|
||||
url: `${appUrl}/frames/hello/${name}/`,
|
||||
splashImageUrl: `${appUrl}/splash.png`,
|
||||
splashBackgroundColor: "#f7f7f7",
|
||||
|
||||
@@ -10,7 +10,7 @@ const frame = {
|
||||
title: "Launch Frame",
|
||||
action: {
|
||||
type: "launch_frame",
|
||||
name: "Farcaster Frames v2 Demo",
|
||||
name: process.env.NEXT_PUBLIC_FRAME_NAME || "Frames v2 Demo",
|
||||
url: `${appUrl}/frames/hello/`,
|
||||
splashImageUrl: `${appUrl}/splash.png`,
|
||||
splashBackgroundColor: "#f7f7f7",
|
||||
|
||||
@@ -5,8 +5,8 @@ import "~/app/globals.css";
|
||||
import { Providers } from "~/app/providers";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Farcaster Frames v2 Demo",
|
||||
description: "A Farcaster Frames v2 demo app",
|
||||
title: process.env.NEXT_PUBLIC_FRAME_NAME || "Frames v2 Demo",
|
||||
description: process.env.NEXT_PUBLIC_FRAME_DESCRIPTION || "A Farcaster Frames v2 demo app",
|
||||
};
|
||||
|
||||
export default async function RootLayout({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ImageResponse } from "next/og";
|
||||
|
||||
export const alt = "Farcaster Frames V2 Demo";
|
||||
export const alt = process.env.NEXT_PUBLIC_FRAME_NAME || "Frames V2 Demo";
|
||||
export const size = {
|
||||
width: 600,
|
||||
height: 400,
|
||||
@@ -8,11 +8,13 @@ export const size = {
|
||||
|
||||
export const contentType = "image/png";
|
||||
|
||||
// dynamically generated OG image for frame preview
|
||||
// TODO: make this dynamic with user info (like robin's example)
|
||||
export default async function Image() {
|
||||
return new ImageResponse(
|
||||
(
|
||||
<div tw="h-full w-full flex flex-col justify-center items-center relative bg-white">
|
||||
<h1 tw="text-6xl">Frames v2 Demo</h1>
|
||||
<h1 tw="text-6xl">{alt}</h1>
|
||||
</div>
|
||||
),
|
||||
{
|
||||
|
||||
@@ -3,6 +3,9 @@ import App from "./app";
|
||||
|
||||
const appUrl = process.env.NEXT_PUBLIC_URL;
|
||||
|
||||
// frame preview metadata
|
||||
const appName = process.env.NEXT_PUBLIC_FRAME_NAME || "Frames v2 Demo";
|
||||
|
||||
const frame = {
|
||||
version: "next",
|
||||
imageUrl: `${appUrl}/opengraph-image`,
|
||||
@@ -10,7 +13,7 @@ const frame = {
|
||||
title: "Launch Frame",
|
||||
action: {
|
||||
type: "launch_frame",
|
||||
name: "Farcaster Frames v2 Demo",
|
||||
name: appName,
|
||||
url: appUrl,
|
||||
splashImageUrl: `${appUrl}/splash.png`,
|
||||
splashBackgroundColor: "#f7f7f7",
|
||||
@@ -22,10 +25,10 @@ export const revalidate = 300;
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
return {
|
||||
title: "Farcaster Frames v2 Demo",
|
||||
title: appName,
|
||||
openGraph: {
|
||||
title: "Farcaster Frames v2 Demo",
|
||||
description: "A Farcaster Frames v2 demo app.",
|
||||
title: appName,
|
||||
description: process.env.NEXT_PUBLIC_FRAME_DESCRIPTION || "A Farcaster Frames v2 demo app.",
|
||||
},
|
||||
other: {
|
||||
"fc:frame": JSON.stringify(frame),
|
||||
|
||||
@@ -29,6 +29,7 @@ export const authOptions: AuthOptions = {
|
||||
// In a production app with a server, these should be fetched from
|
||||
// your Farcaster data indexer rather than have them accepted as part
|
||||
// of credentials.
|
||||
// question: should these natively use the Neynar API?
|
||||
name: {
|
||||
label: "Name",
|
||||
type: "text",
|
||||
@@ -49,6 +50,7 @@ export const authOptions: AuthOptions = {
|
||||
const verifyResponse = await appClient.verifySignInMessage({
|
||||
message: credentials?.message as string,
|
||||
signature: credentials?.signature as `0x${string}`,
|
||||
// question: what domain should this be?
|
||||
domain: new URL(process.env.NEXTAUTH_URL ?? '').hostname,
|
||||
nonce: csrfToken,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user