mirror of
https://github.com/neynarxyz/create-farcaster-mini-app.git
synced 2025-11-16 08:08:56 -05:00
feat: add primary category and tags
This commit is contained in:
parent
5fe54a80da
commit
f350aaa897
41
bin/init.js
41
bin/init.js
@ -185,7 +185,44 @@ export async function init() {
|
||||
type: 'input',
|
||||
name: 'description',
|
||||
message: 'Give a one-line description of your mini app (optional):',
|
||||
default: 'A Farcaster mini-app created with Neynar'
|
||||
default: 'A Farcaster mini app created with Neynar'
|
||||
},
|
||||
{
|
||||
type: 'list',
|
||||
name: 'primaryCategory',
|
||||
message: 'It is strongly recommended to choose a primary category and tags to help users discover your mini app.\n\nSelect a primary category:',
|
||||
choices: [
|
||||
{ name: 'Games', value: 'games' },
|
||||
{ name: 'Social', value: 'social' },
|
||||
{ name: 'Finance', value: 'finance' },
|
||||
{ name: 'Utility', value: 'utility' },
|
||||
{ name: 'Productivity', value: 'productivity' },
|
||||
{ name: 'Health & Fitness', value: 'health-fitness' },
|
||||
{ name: 'News & Media', value: 'news-media' },
|
||||
{ name: 'Music', value: 'music' },
|
||||
{ name: 'Shopping', value: 'shopping' },
|
||||
{ name: 'Education', value: 'education' },
|
||||
{ name: 'Developer Tools', value: 'developer-tools' },
|
||||
{ name: 'Entertainment', value: 'entertainment' },
|
||||
{ name: 'Art & Creativity', value: 'art-creativity' },
|
||||
new inquirer.Separator(),
|
||||
{ name: 'Skip (not recommended)', value: null }
|
||||
],
|
||||
default: 'social'
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'tags',
|
||||
message: 'Enter tags for your mini app (separate with spaces or commas, optional):',
|
||||
default: '',
|
||||
filter: (input) => {
|
||||
if (!input.trim()) return [];
|
||||
// Split by both spaces and commas, trim whitespace, and filter out empty strings
|
||||
return input
|
||||
.split(/[,\s]+/)
|
||||
.map(tag => tag.trim())
|
||||
.filter(tag => tag.length > 0);
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
@ -333,6 +370,8 @@ export async function init() {
|
||||
// Append all remaining environment variables
|
||||
fs.appendFileSync(envPath, `\nNEXT_PUBLIC_FRAME_NAME="${answers.projectName}"`);
|
||||
fs.appendFileSync(envPath, `\nNEXT_PUBLIC_FRAME_DESCRIPTION="${answers.description}"`);
|
||||
fs.appendFileSync(envPath, `\nNEXT_PUBLIC_FRAME_PRIMARY_CATEGORY="${answers.primaryCategory}"`);
|
||||
fs.appendFileSync(envPath, `\nNEXT_PUBLIC_FRAME_TAGS="${answers.tags.join(',')}"`);
|
||||
fs.appendFileSync(envPath, `\nNEXT_PUBLIC_FRAME_BUTTON_TEXT="${answers.buttonText}"`);
|
||||
fs.appendFileSync(envPath, `\nNEXTAUTH_SECRET="${crypto.randomBytes(32).toString('hex')}"`);
|
||||
if (useNeynar && neynarApiKey && neynarClientId) {
|
||||
|
||||
2
index.d.ts
vendored
2
index.d.ts
vendored
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Initialize a new Farcaster mini-app project
|
||||
* Initialize a new Farcaster mini app project
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
export function init(): Promise<void>;
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@neynar/create-farcaster-mini-app",
|
||||
"version": "1.2.24",
|
||||
"version": "1.2.25",
|
||||
"type": "module",
|
||||
"private": false,
|
||||
"access": "public",
|
||||
@ -22,6 +22,9 @@
|
||||
"frame",
|
||||
"frames-v2",
|
||||
"farcaster-frames",
|
||||
"miniapps",
|
||||
"miniapp",
|
||||
"mini-apps",
|
||||
"mini-app",
|
||||
"neynar",
|
||||
"web3"
|
||||
|
||||
@ -161,6 +161,8 @@ async function generateFarcasterMetadata(domain, fid, accountAddress, seedPhrase
|
||||
});
|
||||
const encodedSignature = Buffer.from(signature, 'utf-8').toString('base64url');
|
||||
|
||||
const tags = process.env.NEXT_PUBLIC_FRAME_TAGS?.split(',');
|
||||
|
||||
return {
|
||||
accountAssociation: {
|
||||
header: encodedHeader,
|
||||
@ -177,6 +179,9 @@ async function generateFarcasterMetadata(domain, fid, accountAddress, seedPhrase
|
||||
splashImageUrl: `https://${domain}/splash.png`,
|
||||
splashBackgroundColor: "#f7f7f7",
|
||||
webhookUrl,
|
||||
description: process.env.NEXT_PUBLIC_FRAME_DESCRIPTION,
|
||||
primaryCategory: process.env.NEXT_PUBLIC_FRAME_PRIMARY_CATEGORY,
|
||||
tags,
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -346,6 +351,8 @@ async function main() {
|
||||
// Frame metadata
|
||||
`NEXT_PUBLIC_FRAME_NAME="${frameName}"`,
|
||||
`NEXT_PUBLIC_FRAME_DESCRIPTION="${process.env.NEXT_PUBLIC_FRAME_DESCRIPTION || ''}"`,
|
||||
`NEXT_PUBLIC_FRAME_PRIMARY_CATEGORY="${process.env.NEXT_PUBLIC_FRAME_PRIMARY_CATEGORY || ''}"`,
|
||||
`NEXT_PUBLIC_FRAME_TAGS="${process.env.NEXT_PUBLIC_FRAME_TAGS || ''}"`,
|
||||
`NEXT_PUBLIC_FRAME_BUTTON_TEXT="${buttonText}"`,
|
||||
|
||||
// Neynar configuration (if it exists in current env)
|
||||
|
||||
@ -72,6 +72,8 @@ async function generateFarcasterMetadata(domain, fid, accountAddress, seedPhrase
|
||||
});
|
||||
const encodedSignature = Buffer.from(signature, 'utf-8').toString('base64url');
|
||||
|
||||
const tags = process.env.NEXT_PUBLIC_FRAME_TAGS?.split(',');
|
||||
|
||||
return {
|
||||
accountAssociation: {
|
||||
header: encodedHeader,
|
||||
@ -80,14 +82,17 @@ async function generateFarcasterMetadata(domain, fid, accountAddress, seedPhrase
|
||||
},
|
||||
frame: {
|
||||
version: "1",
|
||||
name: process.env.NEXT_PUBLIC_FRAME_NAME?.trim(),
|
||||
name: process.env.NEXT_PUBLIC_FRAME_NAME,
|
||||
iconUrl: `https://${trimmedDomain}/icon.png`,
|
||||
homeUrl: `https://${trimmedDomain}`,
|
||||
imageUrl: `https://${trimmedDomain}/api/opengraph-image`,
|
||||
buttonTitle: process.env.NEXT_PUBLIC_FRAME_BUTTON_TEXT?.trim(),
|
||||
buttonTitle: process.env.NEXT_PUBLIC_FRAME_BUTTON_TEXT,
|
||||
splashImageUrl: `https://${trimmedDomain}/splash.png`,
|
||||
splashBackgroundColor: "#f7f7f7",
|
||||
webhookUrl: webhookUrl?.trim(),
|
||||
description: process.env.NEXT_PUBLIC_FRAME_DESCRIPTION,
|
||||
primaryCategory: process.env.NEXT_PUBLIC_FRAME_PRIMARY_CATEGORY,
|
||||
tags,
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -113,6 +118,8 @@ async function loadEnvLocal() {
|
||||
'SEED_PHRASE',
|
||||
'NEXT_PUBLIC_FRAME_NAME',
|
||||
'NEXT_PUBLIC_FRAME_DESCRIPTION',
|
||||
'NEXT_PUBLIC_FRAME_PRIMARY_CATEGORY',
|
||||
'NEXT_PUBLIC_FRAME_TAGS',
|
||||
'NEXT_PUBLIC_FRAME_BUTTON_TEXT',
|
||||
'NEYNAR_API_KEY',
|
||||
'NEYNAR_CLIENT_ID'
|
||||
|
||||
@ -101,7 +101,7 @@ async function startDev() {
|
||||
1. Open the localtunnel URL in your browser: ${tunnel.url}
|
||||
2. Enter your IP address in the password field${ip ? `: ${ip}` : ''} (note that this IP may be incorrect if you are using a VPN)
|
||||
3. Click "Click to Submit" -- your mini app should now load in the browser
|
||||
4. Navigate to the Warpcast Mini App Developer Tools: https://warpcast.com/~/developers/mini-apps
|
||||
4. Navigate to the Warpcast Mini App Developer Tools: https://warpcast.com/~/developers
|
||||
5. Enter your mini app URL: ${tunnel.url}
|
||||
6. Click "Preview" to launch your mini app within Warpcast (note that it may take ~10 seconds to load)
|
||||
|
||||
@ -120,7 +120,7 @@ async function startDev() {
|
||||
frameUrl = 'http://localhost:3000';
|
||||
console.log(`
|
||||
💻 To test your mini app:
|
||||
1. Open the Warpcast Mini App Developer Tools: https://warpcast.com/~/developers/mini-apps
|
||||
1. Open the Warpcast Mini App Developer Tools: https://warpcast.com/~/developers
|
||||
2. Scroll down to the "Preview Mini App" tool
|
||||
3. Enter this URL: ${frameUrl}
|
||||
4. Click "Preview" to test your mini app (note that it may take ~5 seconds to load the first time)
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
export const APP_URL = process.env.NEXT_PUBLIC_URL!;
|
||||
export const APP_NAME = process.env.NEXT_PUBLIC_FRAME_NAME;
|
||||
export const APP_DESCRIPTION = process.env.NEXT_PUBLIC_FRAME_DESCRIPTION;
|
||||
export const APP_PRIMARY_CATEGORY = process.env.NEXT_PUBLIC_FRAME_PRIMARY_CATEGORY;
|
||||
export const APP_TAGS = process.env.NEXT_PUBLIC_FRAME_TAGS?.split(',');
|
||||
export const APP_ICON_URL = `${APP_URL}/icon.png`;
|
||||
export const APP_OG_IMAGE_URL = `${APP_URL}/api/opengraph-image`;
|
||||
export const APP_SPLASH_URL = `${APP_URL}/splash.png`;
|
||||
|
||||
@ -1,26 +1,31 @@
|
||||
import { type ClassValue, clsx } from 'clsx';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
import { mnemonicToAccount } from 'viem/accounts';
|
||||
import { APP_BUTTON_TEXT, APP_ICON_URL, APP_NAME, APP_OG_IMAGE_URL, APP_SPLASH_BACKGROUND_COLOR, APP_URL, APP_WEBHOOK_URL } from './constants';
|
||||
import { APP_BUTTON_TEXT, APP_DESCRIPTION, APP_ICON_URL, APP_NAME, APP_OG_IMAGE_URL, APP_PRIMARY_CATEGORY, APP_SPLASH_BACKGROUND_COLOR, APP_TAGS, APP_URL, APP_WEBHOOK_URL } from './constants';
|
||||
import { APP_SPLASH_URL } from './constants';
|
||||
|
||||
interface FrameMetadata {
|
||||
version: string;
|
||||
name: string;
|
||||
iconUrl: string;
|
||||
homeUrl: string;
|
||||
imageUrl?: string;
|
||||
buttonTitle?: string;
|
||||
splashImageUrl?: string;
|
||||
splashBackgroundColor?: string;
|
||||
webhookUrl?: string;
|
||||
description?: string;
|
||||
primaryCategory?: string;
|
||||
tags?: string[];
|
||||
};
|
||||
|
||||
interface FrameManifest {
|
||||
accountAssociation?: {
|
||||
header: string;
|
||||
payload: string;
|
||||
signature: string;
|
||||
};
|
||||
frame: {
|
||||
version: string;
|
||||
name: string;
|
||||
iconUrl: string;
|
||||
homeUrl: string;
|
||||
imageUrl: string;
|
||||
buttonTitle: string;
|
||||
splashImageUrl: string;
|
||||
splashBackgroundColor: string;
|
||||
webhookUrl: string;
|
||||
};
|
||||
frame: FrameMetadata;
|
||||
}
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
@ -51,12 +56,15 @@ export function getFrameEmbedMetadata(ogImageUrl?: string) {
|
||||
splashImageUrl: APP_SPLASH_URL,
|
||||
iconUrl: APP_ICON_URL,
|
||||
splashBackgroundColor: APP_SPLASH_BACKGROUND_COLOR,
|
||||
description: APP_DESCRIPTION,
|
||||
primaryCategory: APP_PRIMARY_CATEGORY,
|
||||
tags: APP_TAGS,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export async function getFarcasterMetadata(): Promise<FrameMetadata> {
|
||||
export async function getFarcasterMetadata(): Promise<FrameManifest> {
|
||||
// First check for FRAME_METADATA in .env and use that if it exists
|
||||
if (process.env.FRAME_METADATA) {
|
||||
try {
|
||||
@ -123,6 +131,9 @@ export async function getFarcasterMetadata(): Promise<FrameMetadata> {
|
||||
splashImageUrl: APP_SPLASH_URL,
|
||||
splashBackgroundColor: APP_SPLASH_BACKGROUND_COLOR,
|
||||
webhookUrl: APP_WEBHOOK_URL,
|
||||
description: APP_DESCRIPTION,
|
||||
primaryCategory: APP_PRIMARY_CATEGORY,
|
||||
tags: APP_TAGS,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user