UNPKG

create-web3-dapp-dev

Version:

<p align="center"> <br /> <a href="https://createweb3dapp.alchemy.com"> <img src=".github/images/cw3d-logo.png" width="200" alt=""/></a> <br /> </p>

384 lines (367 loc) 9.71 kB
import open from "open"; import path from "path"; import prompts from "prompts"; import context from "../../core/context.js"; import { LogLevel, selfDestroy, setRoot } from "../../core/selfDestroy.js"; import { smartContractWizard } from "../../smartContractsWizard/smartContractWizard.js"; import { generateDapp } from "../generateDapp.js"; import { validateProjectName } from "../../utils/validation.js"; import { getTestnet } from "../../utils/getTestnet.js"; import { getTemplateSpecs, supportsTypescript, } from "../../templates_records/templatesDB.js"; import { v4 as uuidv4 } from "uuid"; import axios from "axios"; export async function startStandardWorkflow() { let step = 0; let quit = false; let projectPath = ""; while (!quit) { let exit = 0; switch (step) { case 0: if (context.projectName && context.resolvedProjectPath) { step++; break; } try { projectPath = ""; if (typeof projectPath === "string") { projectPath = projectPath.trim(); } context.projectName = ""; while (!context.projectName?.length) { if (exit >= 2) { selfDestroy(); } exit++; const projectPath = await prompts({ type: "text", name: "projectPath", message: "Project name", initial: "my-create-web3-dapp", validate: (value: string) => validateProjectName(value), }).then((data) => data.projectPath.trim()); if (projectPath) { context.resolvedProjectPath = path.resolve(projectPath); context.projectName = path.basename( context.resolvedProjectPath ); setRoot(context.resolvedProjectPath); } } } catch (e) { selfDestroy(e, LogLevel.ERROR); } step++; break; case 1: try { if ( !context.dappInfo.isTemplate && !context.dappInfo.template ) { const template: Number | String = await prompts({ type: "select", name: "template", message: "Choose how to start", choices: [ { title: "Boilerplates dapp", value: "new", message: "Start building your application from scratch", }, { title: "NFT Explorer", value: "nft-explorer", message: "A template to build NFTs explorers", }, { title: "Back", value: "back", }, ], initial: 0, hint: "- Create a default app ", }).then((data) => data.template); if (template == "new") { context.dappInfo.isTemplate = false; context.dappInfo.template = "new"; } else if (template == "back") { context.projectName = null; context.resolvedProjectPath = null; step--; break; } else { await getTemplateSpecs(template as string); } } if (!context.dappInfo.isTypescript) { if ( supportsTypescript( context.dappInfo.template as string ) || context.dappInfo.template == "new" ) { if (!context.dappInfo.isTypescript) { const isTypescript: Number | String = await prompts({ type: "toggle", name: "isTypescript", message: "Do you want to use Typescript?", initial: true, active: "Typescript", inactive: "Javascript", }).then( (data) => (context.dappInfo.isTypescript = data.isTypescript) ); } } } step++; } catch (e) { selfDestroy(e, LogLevel.ERROR); } break; case 2: if (context.dappInfo.chain) { step++; break; } await prompts({ type: "select", name: "chain", message: "Choose your chain", choices: [ { title: "Ethereum", value: "ETH_MAINNET" }, { title: "Polygon", value: "MATIC_MAINNET" }, { title: "Polygon zkEVM", value: "POLYGON_ZKEVM_MAINNET", }, { title: "Arbitrum", value: "ARB_MAINNET" }, { title: "Optimism", value: "OPT_MAINNET" }, { title: "Back", value: "back" }, ], initial: 0, hint: "- You can change this later", }).then((data) => (context.dappInfo.chain = data.chain)); if (context.dappInfo.chain == "back") { context.dappInfo.chain = ""; context.dappInfo.isTypescript = false; context.dappInfo.isTemplate = false; context.dappInfo.template = ""; step -= 2; break; } if (!context.dappInfo.chain?.length) { process.exit(); } getTestnet(); step++; break; case 3: if ( context.dappInfo.useBackend && context.dappInfo.backendProvider ) { step++; break; } try { const backendProvider = await prompts({ type: "select", name: "backendProvider", message: "[Optional] Choose your blockchain development environment:", hint: "- Used to create, build, deploy and test smart contracts", choices: [ { title: "Hardhat", message: "- Learn more at hardhat.org", value: "hardhat", }, { title: "Foundry (coming soon)", value: "foundry", disabled: true, }, { title: "Skip", value: "skip", message: "- If you're not creating smart contracts", }, { title: "Back", value: "back" }, ], initial: 0, }).then((data) => data.backendProvider); if (backendProvider == "back") { step--; context.dappInfo.chain = ""; break; } else if (backendProvider == "skip") { context.dappInfo.useBackend = false; context.dappInfo.backendProvider = undefined; step = 5; break; } else if (typeof backendProvider == "string") { context.dappInfo.useBackend = true; context.dappInfo.backendProvider = backendProvider; step++; } else { selfDestroy(); } } catch (e) { selfDestroy(e, LogLevel.ERROR); } break; case 4: if (context.dappInfo.useBackend) { if ( context.dappInfo.hasSmartContract && context.contractInfo?.name && context.contractInfo?.symbol ) { step++; break; } const hasContract: boolean = await prompts({ type: "select", name: "hasContract", message: "Do you want to create a smart contract?", choices: [ { title: "Yes", description: "This will start the smart contract creation wizard", value: true, }, { title: "No", value: false, message: "You can always create custom smart contracts later ", }, { title: "Back", value: "back" }, ], initial: 0, hint: "- Create smart contracts directly from the CLI.", }).then((data) => data.hasContract); if (typeof hasContract == "string") { step--; context.dappInfo.useBackend = false; context.dappInfo.backendProvider = ""; break; } else if (typeof hasContract == "boolean") { context.dappInfo.hasSmartContract = hasContract; if (hasContract) { context.contractInfo = await smartContractWizard(); if (!context.contractInfo?.name) { break; } } else { step++; } } else { process.exit(); } } step++; break; case 5: if (context.dappInfo.apiKeys.ALCHEMY_API_KEY) { step = 7; break; } try { const hasAccount: string = await prompts({ type: "toggle", name: "hasAccount", message: "Do you already have an Alchemy account?", initial: true, active: "yes", inactive: "no", }).then((data) => data.hasAccount); if (typeof hasAccount == "boolean") { open("https://auth.alchemy.com/?a=create-web3-dapp"); step++; break; } else { process.exit(); } } catch (e) { selfDestroy(e, LogLevel.ERROR); } break; case 6: try { const alchemyAPIKey: string = await prompts({ type: "text", name: "apiKey", message: "Insert your Alchemy API Key (Copy from https://auth.alchemy.com/?a=create-web3-dapp):", initial: "", }).then((data) => data.apiKey); if ( alchemyAPIKey?.length < 32 || alchemyAPIKey?.length > 33 ) { break; } if (!alchemyAPIKey) { process.exit(); } context.dappInfo.apiKeys.ALCHEMY_API_KEY = alchemyAPIKey.length ? alchemyAPIKey : "demo"; step++; break; } catch (e) { selfDestroy(e, LogLevel.ERROR); } case 7: { const helpUs: Number | String = await prompts({ type: "toggle", name: "storeAnonymisedData", message: "Help us improve create-web3-dapp with anonymous crash & basic usage data?", initial: true, active: "yes", inactive: "no", }).then( (data) => (context.dappInfo.storeAnonymisedData = data.storeAnonymisedData) ); } quit = true; break; } } if (context.dappInfo.storeAnonymisedData) await saveSessionData(); if (context.resolvedProjectPath && context.projectName) generateDapp(); } const saveSessionData = async () => { const url = "https://p85vbvjhtk.execute-api.eu-central-1.amazonaws.com/Stage/save-session-data"; const duDappInfoContext = { ...context.dappInfo }; delete (duDappInfoContext as any)?.apiKeys; const data = { sessionId: uuidv4(), dappInfo: duDappInfoContext, }; try { const response = await axios.post(url, data); } catch (error) { console.error("Error:", error); } };