mirror of
https://github.com/neynarxyz/create-farcaster-mini-app.git
synced 2025-11-16 08:08:56 -05:00
fix: build failure
This commit is contained in:
parent
f14493e35b
commit
ccd27f53b3
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@neynar/create-farcaster-mini-app",
|
"name": "@neynar/create-farcaster-mini-app",
|
||||||
"version": "1.8.11",
|
"version": "1.8.12",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": false,
|
"private": false,
|
||||||
"access": "public",
|
"access": "public",
|
||||||
|
|||||||
@ -115,80 +115,143 @@ async function checkRequiredEnvVars(): Promise<void> {
|
|||||||
`${newLine}${varConfig.name}="${value.trim()}"`,
|
`${newLine}${varConfig.name}="${value.trim()}"`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Ask about SIWN if SEED_PHRASE is provided
|
// Ask about SIWN if SEED_PHRASE is provided (moved outside the loop)
|
||||||
if (process.env.SEED_PHRASE && !process.env.SPONSOR_SIGNER) {
|
if (process.env.SEED_PHRASE && !process.env.SPONSOR_SIGNER) {
|
||||||
const { sponsorSigner } = await inquirer.prompt([
|
const { sponsorSigner } = await inquirer.prompt([
|
||||||
{
|
|
||||||
type: 'confirm',
|
|
||||||
name: 'sponsorSigner',
|
|
||||||
message:
|
|
||||||
'You have provided a seed phrase, which enables Sign In With Neynar (SIWN).\n' +
|
|
||||||
'Do you want to sponsor the signer? (This will be used in Sign In With Neynar)\n' +
|
|
||||||
'Note: If you choose to sponsor the signer, Neynar will sponsor it for you and you will be charged in CUs.\n' +
|
|
||||||
'For more information, see https://docs.neynar.com/docs/two-ways-to-sponsor-a-farcaster-signer-via-neynar#sponsor-signers',
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
process.env.SPONSOR_SIGNER = sponsorSigner.toString();
|
|
||||||
|
|
||||||
fs.appendFileSync(
|
|
||||||
'.env.local',
|
|
||||||
`\nSPONSOR_SIGNER="${sponsorSigner}"`,
|
|
||||||
);
|
|
||||||
console.log('✅ Sponsor signer preference stored in .env.local');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ask about required chains
|
|
||||||
const { useRequiredChains } = await inquirer.prompt([
|
|
||||||
{
|
{
|
||||||
type: 'confirm',
|
type: 'confirm',
|
||||||
name: 'useRequiredChains',
|
name: 'sponsorSigner',
|
||||||
message:
|
message:
|
||||||
'Does your mini app require support for specific blockchains?\n' +
|
'You have provided a seed phrase, which enables Sign In With Neynar (SIWN).\n' +
|
||||||
'If yes, the host will only render your mini app if it supports all the chains you specify.\n' +
|
'Do you want to sponsor the signer? (This will be used in Sign In With Neynar)\n' +
|
||||||
'If no, the mini app will be rendered regardless of chain support.',
|
'Note: If you choose to sponsor the signer, Neynar will sponsor it for you and you will be charged in CUs.\n' +
|
||||||
|
'For more information, see https://docs.neynar.com/docs/two-ways-to-sponsor-a-farcaster-signer-via-neynar#sponsor-signers',
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let requiredChains: string[] = [];
|
process.env.SPONSOR_SIGNER = sponsorSigner.toString();
|
||||||
if (useRequiredChains) {
|
|
||||||
const { selectedChains } = await inquirer.prompt([
|
|
||||||
{
|
|
||||||
type: 'checkbox',
|
|
||||||
name: 'selectedChains',
|
|
||||||
message: 'Select the required chains (CAIP-2 identifiers):',
|
|
||||||
choices: [
|
|
||||||
{ name: 'Ethereum Mainnet (eip155:1)', value: 'eip155:1' },
|
|
||||||
{ name: 'Polygon (eip155:137)', value: 'eip155:137' },
|
|
||||||
{ name: 'Arbitrum One (eip155:42161)', value: 'eip155:42161' },
|
|
||||||
{ name: 'Optimism (eip155:10)', value: 'eip155:10' },
|
|
||||||
{ name: 'Base (eip155:8453)', value: 'eip155:8453' },
|
|
||||||
{ name: 'Solana (solana:mainnet)', value: 'solana:mainnet' },
|
|
||||||
{ name: 'Solana Devnet (solana:devnet)', value: 'solana:devnet' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
requiredChains = selectedChains;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update constants.ts with required chains
|
fs.appendFileSync(
|
||||||
const constantsPath = path.join(projectRoot, 'src', 'lib', 'constants.ts');
|
'.env.local',
|
||||||
|
`\nSPONSOR_SIGNER="${sponsorSigner}"`,
|
||||||
|
);
|
||||||
|
console.log('✅ Sponsor signer preference stored in .env.local');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ask about required chains (moved outside the loop)
|
||||||
|
const { useRequiredChains } = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
type: 'confirm',
|
||||||
|
name: 'useRequiredChains',
|
||||||
|
message:
|
||||||
|
'Does your mini app require support for specific blockchains?\n' +
|
||||||
|
'If yes, the host will only render your mini app if it supports all the chains you specify.\n' +
|
||||||
|
'If no, the mini app will be rendered regardless of chain support.',
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
let requiredChains: string[] = [];
|
||||||
|
if (useRequiredChains) {
|
||||||
|
const { selectedChains } = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
type: 'checkbox',
|
||||||
|
name: 'selectedChains',
|
||||||
|
message: 'Select the required chains (CAIP-2 identifiers):',
|
||||||
|
choices: [
|
||||||
|
{ name: 'Ethereum Mainnet (eip155:1)', value: 'eip155:1' },
|
||||||
|
{ name: 'Polygon (eip155:137)', value: 'eip155:137' },
|
||||||
|
{ name: 'Arbitrum One (eip155:42161)', value: 'eip155:42161' },
|
||||||
|
{ name: 'Optimism (eip155:10)', value: 'eip155:10' },
|
||||||
|
{ name: 'Base (eip155:8453)', value: 'eip155:8453' },
|
||||||
|
{ name: 'Solana (solana:mainnet)', value: 'solana:mainnet' },
|
||||||
|
{ name: 'Solana Devnet (solana:devnet)', value: 'solana:devnet' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
requiredChains = selectedChains;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update constants.ts with required chains
|
||||||
|
const constantsPath = path.join(projectRoot, 'src', 'lib', 'constants.ts');
|
||||||
|
if (fs.existsSync(constantsPath)) {
|
||||||
|
let constantsContent = fs.readFileSync(constantsPath, 'utf8');
|
||||||
|
|
||||||
|
// Replace the APP_REQUIRED_CHAINS line
|
||||||
|
const requiredChainsString = JSON.stringify(requiredChains);
|
||||||
|
constantsContent = constantsContent.replace(
|
||||||
|
/^export const APP_REQUIRED_CHAINS\s*:\s*string\[\]\s*=\s*\[[^\]]*\];$/m,
|
||||||
|
`export const APP_REQUIRED_CHAINS: string[] = ${requiredChainsString};`,
|
||||||
|
);
|
||||||
|
|
||||||
|
fs.writeFileSync(constantsPath, constantsContent);
|
||||||
|
console.log('✅ Required chains updated in constants.ts');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ask for account association
|
||||||
|
console.log(
|
||||||
|
`\n⚠️ To complete your mini app manifest, you need to sign it using the Farcaster developer portal.`,
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
'1. Go to: https://farcaster.xyz/~/developers/mini-apps/manifest',
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
'2. Enter your app domain (you\'ll get this after deployment)',
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
'3. Click "Transfer Ownership" and follow the instructions to sign the manifest.',
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
'4. Copy the resulting accountAssociation JSON.',
|
||||||
|
);
|
||||||
|
console.log('5. Paste it below when prompted.');
|
||||||
|
console.log(
|
||||||
|
'\nNote: If you don\'t have the accountAssociation yet, you can press Ctrl+C to skip and add it later.',
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { userAccountAssociation } = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
type: 'editor',
|
||||||
|
name: 'userAccountAssociation',
|
||||||
|
message: 'Paste the accountAssociation JSON here (or press Ctrl+C to skip):',
|
||||||
|
validate: (input: string) => {
|
||||||
|
if (!input.trim()) {
|
||||||
|
return 'You can press Ctrl+C to skip this step';
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(input);
|
||||||
|
if (parsed.header && parsed.payload && parsed.signature) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return 'Invalid accountAssociation: must have header, payload, and signature';
|
||||||
|
} catch (e) {
|
||||||
|
return 'Invalid JSON';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const parsedAccountAssociation = JSON.parse(userAccountAssociation);
|
||||||
|
|
||||||
|
// Write APP_ACCOUNT_ASSOCIATION to constants.ts
|
||||||
if (fs.existsSync(constantsPath)) {
|
if (fs.existsSync(constantsPath)) {
|
||||||
let constantsContent = fs.readFileSync(constantsPath, 'utf8');
|
let constantsContent = fs.readFileSync(constantsPath, 'utf8');
|
||||||
|
|
||||||
// Replace the APP_REQUIRED_CHAINS line
|
// Replace the APP_ACCOUNT_ASSOCIATION line
|
||||||
const requiredChainsString = JSON.stringify(requiredChains);
|
const newAccountAssociation = `export const APP_ACCOUNT_ASSOCIATION: AccountAssociation | undefined = ${JSON.stringify(parsedAccountAssociation, null, 2)};`;
|
||||||
constantsContent = constantsContent.replace(
|
constantsContent = constantsContent.replace(
|
||||||
/^export const APP_REQUIRED_CHAINS\s*:\s*string\[\]\s*=\s*\[[^\]]*\];$/m,
|
/^export const APP_ACCOUNT_ASSOCIATION\s*:\s*AccountAssociation \| undefined\s*=\s*[^;]*;/m,
|
||||||
`export const APP_REQUIRED_CHAINS: string[] = ${requiredChainsString};`,
|
newAccountAssociation,
|
||||||
);
|
);
|
||||||
|
|
||||||
fs.writeFileSync(constantsPath, constantsContent);
|
fs.writeFileSync(constantsPath, constantsContent);
|
||||||
console.log('✅ Required chains updated in constants.ts');
|
console.log('✅ APP_ACCOUNT_ASSOCIATION updated in constants.ts');
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log('\nℹ️ Skipping account association for now. You can add it later by updating APP_ACCOUNT_ASSOCIATION in src/lib/constants.ts');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -879,54 +942,16 @@ async function deployToVercel(useGitHub = false): Promise<void> {
|
|||||||
'\n📝 You can manage your project at https://vercel.com/dashboard',
|
'\n📝 You can manage your project at https://vercel.com/dashboard',
|
||||||
);
|
);
|
||||||
|
|
||||||
// Prompt user to sign manifest in browser and paste accountAssociation
|
// Remind user about account association if not already set
|
||||||
console.log(
|
console.log(
|
||||||
`\n⚠️ To complete your mini app manifest, you must sign it using the Farcaster developer portal.`,
|
`\n💡 Remember: If you haven't already signed your manifest, go to:`,
|
||||||
);
|
);
|
||||||
console.log(
|
console.log(
|
||||||
'1. Go to: https://farcaster.xyz/~/developers/mini-apps/manifest?domain=' +
|
` https://farcaster.xyz/~/developers/mini-apps/manifest?domain=${domain}`,
|
||||||
domain,
|
|
||||||
);
|
);
|
||||||
console.log(
|
console.log(
|
||||||
'2. Click "Transfer Ownership" and follow the instructions to sign the manifest.',
|
' to complete the ownership transfer and update APP_ACCOUNT_ASSOCIATION in src/lib/constants.ts',
|
||||||
);
|
);
|
||||||
console.log(
|
|
||||||
'3. Copy the resulting accountAssociation JSON from the browser.',
|
|
||||||
);
|
|
||||||
console.log('4. Paste it below when prompted.');
|
|
||||||
|
|
||||||
const { userAccountAssociation } = await inquirer.prompt([
|
|
||||||
{
|
|
||||||
type: 'editor',
|
|
||||||
name: 'userAccountAssociation',
|
|
||||||
message: 'Paste the accountAssociation JSON here:',
|
|
||||||
validate: (input: string) => {
|
|
||||||
try {
|
|
||||||
const parsed = JSON.parse(input);
|
|
||||||
if (parsed.header && parsed.payload && parsed.signature) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return 'Invalid accountAssociation: must have header, payload, and signature';
|
|
||||||
} catch (e) {
|
|
||||||
return 'Invalid JSON';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
const parsedAccountAssociation = JSON.parse(userAccountAssociation);
|
|
||||||
|
|
||||||
// Write APP_ACCOUNT_ASSOCIATION to src/lib/constants.ts
|
|
||||||
const constantsPath = path.join(projectRoot, 'src', 'lib', 'constants.ts');
|
|
||||||
let constantsContent = fs.readFileSync(constantsPath, 'utf8');
|
|
||||||
|
|
||||||
// Replace the APP_ACCOUNT_ASSOCIATION line using a robust, anchored, multiline regex
|
|
||||||
const newAccountAssociation = `export const APP_ACCOUNT_ASSOCIATION: AccountAssociation | undefined = ${JSON.stringify(parsedAccountAssociation, null, 2)};`;
|
|
||||||
constantsContent = constantsContent.replace(
|
|
||||||
/^export const APP_ACCOUNT_ASSOCIATION\s*:\s*AccountAssociation \| undefined\s*=\s*[^;]*;/m,
|
|
||||||
newAccountAssociation,
|
|
||||||
);
|
|
||||||
fs.writeFileSync(constantsPath, constantsContent);
|
|
||||||
console.log('\n✅ APP_ACCOUNT_ASSOCIATION updated in src/lib/constants.ts');
|
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
console.error('\n❌ Deployment failed:', error.message);
|
console.error('\n❌ Deployment failed:', error.message);
|
||||||
|
|||||||
@ -7,6 +7,7 @@ export async function GET() {
|
|||||||
return NextResponse.json(config);
|
return NextResponse.json(config);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error generating metadata:', error);
|
console.error('Error generating metadata:', error);
|
||||||
return NextResponse.json({ error: error.message }, { status: 500 });
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
||||||
|
return NextResponse.json({ error: errorMessage }, { status: 500 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user