diff --git a/.changeset/dull-toys-yawn.md b/.changeset/dull-toys-yawn.md new file mode 100644 index 0000000..d554c65 --- /dev/null +++ b/.changeset/dull-toys-yawn.md @@ -0,0 +1,5 @@ +--- +"create-better-t-stack": patch +--- + +refactor(cli): improve Turso database setup workflow diff --git a/apps/cli/src/helpers/db-setup.ts b/apps/cli/src/helpers/db-setup.ts index f8908ba..1d8ae4c 100644 --- a/apps/cli/src/helpers/db-setup.ts +++ b/apps/cli/src/helpers/db-setup.ts @@ -7,6 +7,11 @@ import ora, { type Ora } from "ora"; import { logger } from "../utils/logger"; import { isTursoInstalled, isTursoLoggedIn } from "../utils/turso-cli"; +interface TursoConfig { + dbUrl: string; + authToken: string; +} + async function loginToTurso(spinner: Ora) { try { spinner.start("Logging in to Turso..."); @@ -25,74 +30,74 @@ async function installTursoCLI(isMac: boolean, spinner: Ora) { if (isMac) { await execa("brew", ["install", "tursodatabase/tap/turso"]); } else { - const installScript = await execa("curl", [ + const { stdout: installScript } = await execa("curl", [ "-sSfL", "https://get.tur.so/install.sh", ]); - await execa("bash", [], { input: installScript.stdout }); + await execa("bash", [], { input: installScript }); } spinner.succeed("Turso CLI installed successfully!"); } catch (error) { if (error instanceof Error && error.message.includes("User force closed")) { spinner.stop(); - console.log("\n"); - logger.warn("Turso CLI installation cancelled by user"); - throw error; + logger.warn("\nTurso CLI installation cancelled by user"); + throw new Error("Installation cancelled"); } spinner.fail("Failed to install Turso CLI"); throw error; } } -async function createTursoDatabase(projectDir: string, spinner: Ora) { +async function createTursoDatabase(dbName: string): Promise { try { - const defaultDbName = path.basename(projectDir); - const dbName = await input({ - message: `Enter database name (default: ${defaultDbName}):`, - default: defaultDbName, - }); - - spinner.start(`Creating Turso database "${dbName}"...`); await execa("turso", ["db", "create", dbName]); - - const { stdout: dbUrl } = await execa("turso", [ - "db", - "show", - dbName, - "--url", - ]); - const { stdout: authToken } = await execa("turso", [ - "db", - "tokens", - "create", - dbName, - ]); - - const envPath = path.join(projectDir, "packages/server", ".env"); - const envContent = `TURSO_DATABASE_URL="${dbUrl.trim()}" -TURSO_AUTH_TOKEN="${authToken.trim()}"`; - - await fs.writeFile(envPath, envContent); - spinner.succeed("Turso database configured successfully!"); } catch (error) { - spinner.fail("Failed to create Turso database"); + if (error instanceof Error && error.message.includes("already exists")) { + throw new Error("DATABASE_EXISTS"); + } throw error; } + + const { stdout: dbUrl } = await execa("turso", [ + "db", + "show", + dbName, + "--url", + ]); + + const { stdout: authToken } = await execa("turso", [ + "db", + "tokens", + "create", + dbName, + ]); + + return { + dbUrl: dbUrl.trim(), + authToken: authToken.trim(), + }; } -async function setupManualConfig(projectDir: string) { +async function writeEnvFile(projectDir: string, config?: TursoConfig) { const envPath = path.join(projectDir, "packages/server", ".env"); - const envContent = `TURSO_DATABASE_URL= + const envContent = config + ? `TURSO_DATABASE_URL="${config.dbUrl}" +TURSO_AUTH_TOKEN="${config.authToken}"` + : `TURSO_DATABASE_URL= TURSO_AUTH_TOKEN=`; await fs.writeFile(envPath, envContent); +} +function displayManualSetupInstructions() { logger.info("\nšŸ“ Manual Turso Setup Instructions:"); logger.info("1. Visit https://turso.tech and create an account"); logger.info("2. Create a new database from the dashboard"); logger.info("3. Get your database URL and authentication token"); - logger.info("4. Add these credentials to the .env file in your project root"); + logger.info( + "4. Add these credentials to the .env file in packages/server/.env", + ); logger.info("\nThe .env file has been created with placeholder variables:"); logger.info("TURSO_DATABASE_URL=your_database_url"); logger.info("TURSO_AUTH_TOKEN=your_auth_token"); @@ -105,7 +110,8 @@ export async function setupTurso(projectDir: string) { const canInstallCLI = platform !== "win32"; if (!canInstallCLI) { - await setupManualConfig(projectDir); + await writeEnvFile(projectDir); + displayManualSetupInstructions(); return; } @@ -119,7 +125,8 @@ export async function setupTurso(projectDir: string) { }); if (!shouldInstall) { - await setupManualConfig(projectDir); + await writeEnvFile(projectDir); + displayManualSetupInstructions(); return; } @@ -131,9 +138,35 @@ export async function setupTurso(projectDir: string) { await loginToTurso(spinner); } - await createTursoDatabase(projectDir, spinner); + const defaultDbName = path.basename(projectDir); + let dbName = await input({ + message: `Enter database name (default: ${defaultDbName}):`, + default: defaultDbName, + }); + + let success = false; + while (!success) { + try { + spinner.start(`Creating Turso database "${dbName}"...`); + const config = await createTursoDatabase(dbName); + await writeEnvFile(projectDir, config); + spinner.succeed("Turso database configured successfully!"); + success = true; + } catch (error) { + if (error instanceof Error && error.message === "DATABASE_EXISTS") { + spinner.warn(`Database "${dbName}" already exists`); + dbName = await input({ + message: "Please enter a different database name:", + default: `${dbName}-${Math.floor(Math.random() * 1000)}`, + }); + } else { + throw error; + } + } + } } catch (error) { logger.error("Error during Turso setup:", error); - await setupManualConfig(projectDir); + await writeEnvFile(projectDir); + displayManualSetupInstructions(); } }