From 70d92c4bd7305a9c037c12a953fb23039213cb60 Mon Sep 17 00:00:00 2001 From: lucas-neynar Date: Wed, 2 Apr 2025 11:47:24 -0700 Subject: [PATCH 1/2] feat: update script to make it easier to understand for beginners --- bin/init.js | 95 +++--------------------------------------------- scripts/build.js | 13 +++++-- scripts/dev.js | 4 +- 3 files changed, 17 insertions(+), 95 deletions(-) diff --git a/bin/init.js b/bin/init.js index 01813da..a99d272 100644 --- a/bin/init.js +++ b/bin/init.js @@ -20,8 +20,6 @@ const blue = '\x1b[34m'; const reset = '\x1b[0m'; const dim = '\x1b[2m'; const bright = '\x1b[1m'; -const yellow = '\x1b[33m'; -const italic = '\x1b[3m'; function printWelcomeMessage() { console.log(` @@ -193,7 +191,7 @@ export async function init() { { type: 'input', name: 'projectName', - message: '⚠️ Note: choosing a longer, more unique project name will help avoid conflicts with other existing domains\nWhat is the name of your frame?', + message: 'What is the name of your frame?', default: defaultFrameName, validate: (input) => { if (input.trim() === '') { @@ -206,7 +204,7 @@ export async function init() { type: 'input', name: 'description', message: 'Give a one-line description of your frame (optional):', - default: 'A Farcaster mini-app created with @neynar/create-farcaster-mini-app' + default: 'A Farcaster mini-app created with Neynar' }, { type: 'input', @@ -227,81 +225,14 @@ export async function init() { { type: 'confirm', name: 'useTunnel', - message: 'Would you like to use a tunnel for development?\n\n' + - 'Using a tunnel:\n' + - '- No sudo privileges required\n' + - '- Works with all Warpcast Frame Developer Tools\n' + - '- Possible to test on mobile devices\n\n' + - 'Using localhost:\n' + - '- Requires sudo privileges to enable HTTPS\n' + - '- Only works with the "Preview Frame" Warpcast tool\n' + - '- Cannot test frame embeds or mobile devices\n\n' + - 'Note: You can always switch between localhost and tunnel by editing the USE_TUNNEL environment variable in .env.local\n\n' + - 'Use tunnel?', + message: 'Would you like to test on mobile, or through a desktop browser?\n' + + 'Mobile testing requires setting up a tunnel to serve your app from localhost to the broader internet.\n' + + 'Configure mobile testing?', default: false } ]); answers.useTunnel = hostingAnswer.useTunnel; - // Ask for seed phrase last - const seedPhraseAnswer = await inquirer.prompt([ - { - type: 'password', - name: 'seedPhrase', - message: `Enter your Farcaster custody account seed phrase to generate a signed manifest for your frame\n(optional -- leave blank to create an unsigned frame)\n⚠️ ${yellow}${italic}seed phrase is only ever stored in .env.local${reset} ⚠️\nSeed phrase:`, - default: null - } - ]); - answers.seedPhrase = seedPhraseAnswer.seedPhrase; - - let account; - let custodyAddress; - let fid; - - if (answers.seedPhrase) { - let fidLookupSuccessful = false; - while (!fidLookupSuccessful) { - try { - // Generate custody address from seed phrase - account = mnemonicToAccount(answers.seedPhrase); - custodyAddress = account.address; - - // Look up FID using custody address - console.log('\nUsing seed phrase to look up FID by custody address...'); - fid = await lookupFidByCustodyAddress(custodyAddress, neynarApiKey ?? 'FARCASTER_V2_FRAMES_DEMO'); - - if (!fid) { - throw new Error('No FID found for this custody address'); - } - - fidLookupSuccessful = true; - console.log(`\n✅ Successfully found FID ${fid} for custody address ${custodyAddress}`); - } catch (error) { - console.error('\n❌ Error:', error.message); - console.log('\n⚠️ Could not find an FID for this seed phrase. This usually means:'); - console.log('1. The seed phrase might be incorrect'); - console.log('2. The account might not be registered on Farcaster'); - console.log('3. The custody address might not be linked to a Farcaster account\n'); - - // Ask for seed phrase again - const retryAnswer = await inquirer.prompt([ - { - type: 'password', - name: 'seedPhrase', - message: 'Please enter your seed phrase again (or leave empty to continue without signing):\n', - default: null - } - ]); - - if (!retryAnswer.seedPhrase) { - console.log('\n⚠️ Continuing without frame signing...'); - break; - } - answers.seedPhrase = retryAnswer.seedPhrase; - } - } - } - const projectName = answers.projectName; const projectDirName = projectName.replace(/\s+/g, '-').toLowerCase(); const projectPath = path.join(process.cwd(), projectDirName); @@ -402,22 +333,6 @@ export async function init() { const envExampleContent = fs.readFileSync(envExamplePath, 'utf8'); // Write it to .env.local fs.writeFileSync(envPath, envExampleContent); - - // Generate custody address from seed phrase - if (answers.seedPhrase) { - const account = mnemonicToAccount(answers.seedPhrase); - const custodyAddress = account.address; - - // Look up FID using custody address - if (!fid) { - console.log('\nLooking up FID...'); - fid = await lookupFidByCustodyAddress(custodyAddress, neynarApiKey ?? 'FARCASTER_V2_FRAMES_DEMO'); - } - - // Write seed phrase and FID to .env.local for manifest signature generation - fs.appendFileSync(envPath, `\nSEED_PHRASE="${answers.seedPhrase}"`); - fs.appendFileSync(envPath, `\nFID="${fid}"`); - } // Append all remaining environment variables fs.appendFileSync(envPath, `\nNEXT_PUBLIC_FRAME_NAME="${answers.projectName}"`); diff --git a/scripts/build.js b/scripts/build.js index 256fbcf..43ebb80 100755 --- a/scripts/build.js +++ b/scripts/build.js @@ -7,6 +7,11 @@ import inquirer from 'inquirer'; import dotenv from 'dotenv'; import crypto from 'crypto'; +// ANSI color codes +const yellow = '\x1b[33m'; +const italic = '\x1b[3m'; +const reset = '\x1b[0m'; + // Load environment variables in specific order // First load .env for main config dotenv.config({ path: '.env' }); @@ -45,7 +50,7 @@ async function loadEnvLocal() { { type: 'confirm', name: 'loadLocal', - message: 'Found .env.local - would you like to load its values? (except for SEED_PHRASE, values will be written to .env)', + message: 'Found .env.local, likely created by the install script - would you like to load its values?', default: false } ]); @@ -286,14 +291,16 @@ async function main() { } } - // Get seed phrase from user if not already in .env.local + // Get seed phrase from user let seedPhrase = process.env.SEED_PHRASE; if (!seedPhrase) { const { seedPhrase: inputSeedPhrase } = await inquirer.prompt([ { type: 'password', name: 'seedPhrase', - message: 'Enter your seed phrase (this will only be used to sign the frame manifest):', + message: 'Your farcaster custody account seed phrase is required to create a signature proving this app was created by you.\n' + + `⚠️ ${yellow}${italic}seed phrase is only used to sign the frame manifest, then discarded${reset} ⚠️\n` + + 'Seed phrase:', validate: async (input) => { try { await validateSeedPhrase(input); diff --git a/scripts/dev.js b/scripts/dev.js index c9ba273..e4ba3cf 100755 --- a/scripts/dev.js +++ b/scripts/dev.js @@ -119,7 +119,7 @@ async function startDev() { 5. Click "Preview" (note that it may take ~10 seconds to load) `); } else { - frameUrl = 'https://localhost:3000'; + frameUrl = 'http://localhost:3000'; console.log(` 💻 To test your frame: 1. Open the Warpcast Frame Developer Tools: https://warpcast.com/~/developers/frames @@ -136,7 +136,7 @@ Note: You may need to accept the self-signed certificate in your browser when fi ? path.join(projectRoot, 'node_modules', '.bin', 'next.cmd') : path.join(projectRoot, 'node_modules', '.bin', 'next'); - nextDev = spawn(nextBin, ['dev', ...(useTunnel ? [] : ['--experimental-https'])], { + nextDev = spawn(nextBin, ['dev'], { stdio: 'inherit', env: { ...process.env, NEXT_PUBLIC_URL: frameUrl, NEXTAUTH_URL: frameUrl }, cwd: projectRoot From 99556cbac020c6d321bdc53f1d603d5f0c510692 Mon Sep 17 00:00:00 2001 From: lucas-neynar Date: Mon, 7 Apr 2025 16:45:22 -0700 Subject: [PATCH 2/2] fix: add nextauth cookies --- package.json | 2 +- src/auth.ts | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 5bc697d..2f90164 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@neynar/create-farcaster-mini-app", - "version": "1.2.10", + "version": "1.2.11", "type": "module", "private": false, "access": "public", diff --git a/src/auth.ts b/src/auth.ts index 65f3c5f..cf3a653 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -89,6 +89,34 @@ export const authOptions: AuthOptions = { } return session; }, + }, + cookies: { + sessionToken: { + name: `next-auth.session-token`, + options: { + httpOnly: true, + sameSite: "none", + path: "/", + secure: true + } + }, + callbackUrl: { + name: `next-auth.callback-url`, + options: { + sameSite: "none", + path: "/", + secure: true + } + }, + csrfToken: { + name: `next-auth.csrf-token`, + options: { + httpOnly: true, + sameSite: "none", + path: "/", + secure: true + } + } } }