From b7ac81d496cf95a9ac08296857661a6fcf4ae5b5 Mon Sep 17 00:00:00 2001 From: Aman Varshney Date: Tue, 18 Mar 2025 15:47:22 +0530 Subject: [PATCH] Add dependency version constants and package management utility --- .changeset/icy-clowns-jam.md | 5 + apps/cli/src/constants.ts | 20 +++ apps/cli/src/helpers/auth-setup.ts | 105 +++++------ apps/cli/src/helpers/create-project.ts | 21 --- apps/cli/src/helpers/db-setup.ts | 168 ++++++++---------- apps/cli/src/utils/add-package-deps.ts | 28 +++ apps/cli/template/base/package.json | 3 - .../base/packages/client/package.json | 1 - .../base/packages/server/package.json | 4 - .../packages/server/src/db/schema.prisma | 2 +- 10 files changed, 175 insertions(+), 182 deletions(-) create mode 100644 .changeset/icy-clowns-jam.md create mode 100644 apps/cli/src/utils/add-package-deps.ts diff --git a/.changeset/icy-clowns-jam.md b/.changeset/icy-clowns-jam.md new file mode 100644 index 0000000..dc4e338 --- /dev/null +++ b/.changeset/icy-clowns-jam.md @@ -0,0 +1,5 @@ +--- +"create-better-t-stack": patch +--- + +Add dependency version constants and package management utility diff --git a/apps/cli/src/constants.ts b/apps/cli/src/constants.ts index 419447d..f1dda3b 100644 --- a/apps/cli/src/constants.ts +++ b/apps/cli/src/constants.ts @@ -16,3 +16,23 @@ export const DEFAULT_CONFIG: ProjectConfig = { packageManager: "npm", noInstall: false, }; + +export const dependencyVersionMap = { + // Authentication + "better-auth": "^1.1.16", + + // Database - Drizzle + "drizzle-orm": "^0.38.4", + "drizzle-kit": "^0.30.4", + + // Database - SQLite/PostgreSQL + "@libsql/client": "^0.14.0", + postgres: "^3.4.5", + + // Database - Prisma + "@prisma/client": "^5.7.1", + "@prisma/adapter-libsql": "^5.7.1", + prisma: "^5.7.1", +} as const; + +export type AvailableDependencies = keyof typeof dependencyVersionMap; diff --git a/apps/cli/src/helpers/auth-setup.ts b/apps/cli/src/helpers/auth-setup.ts index 69a1a9d..db40e63 100644 --- a/apps/cli/src/helpers/auth-setup.ts +++ b/apps/cli/src/helpers/auth-setup.ts @@ -2,8 +2,8 @@ import path from "node:path"; import { log } from "@clack/prompts"; import fs from "fs-extra"; import pc from "picocolors"; -import { PKG_ROOT } from "../constants"; import type { ProjectConfig } from "../types"; +import { addPackageDependency } from "../utils/add-package-deps"; export async function setupAuth( projectDir: string, @@ -18,53 +18,54 @@ export async function setupAuth( return; } + addPackageDependency({ + dependencies: ["better-auth"], + devDependencies: false, + projectDir: serverDir, + }); + const envPath = path.join(serverDir, ".env"); - const templateEnvPath = path.join( - PKG_ROOT, - getOrmTemplatePath(options.orm, options.database, "packages/server/_env"), - ); - if (!(await fs.pathExists(envPath))) { - if (await fs.pathExists(templateEnvPath)) { - await fs.copy(templateEnvPath, envPath); - } else { - const defaultEnv = `BETTER_AUTH_SECRET=${generateAuthSecret()} -BETTER_AUTH_URL=http://localhost:3000 -CORS_ORIGIN=http://localhost:3001 -${options.database === "sqlite" ? "TURSO_CONNECTION_URL=http://127.0.0.1:8080" : ""} -${options.orm === "prisma" ? 'DATABASE_URL="file:./dev.db"' : ""} -`; - await fs.writeFile(envPath, defaultEnv); - } - } else { - let envContent = await fs.readFile(envPath, "utf8"); + // Create or update the .env file directly with required variables + let envContent = ""; - if (!envContent.includes("BETTER_AUTH_SECRET")) { - envContent += `\nBETTER_AUTH_SECRET=${generateAuthSecret()}`; - } - - if (!envContent.includes("BETTER_AUTH_URL")) { - envContent += "\nBETTER_AUTH_URL=http://localhost:3000"; - } - - if (!envContent.includes("CORS_ORIGIN")) { - envContent += "\nCORS_ORIGIN=http://localhost:3001"; - } - - if ( - options.database === "sqlite" && - !envContent.includes("TURSO_CONNECTION_URL") - ) { - envContent += "\nTURSO_CONNECTION_URL=http://127.0.0.1:8080"; - } - - if (options.orm === "prisma" && !envContent.includes("DATABASE_URL")) { - envContent += '\nDATABASE_URL="file:./dev.db"'; - } - - await fs.writeFile(envPath, envContent); + if (await fs.pathExists(envPath)) { + envContent = await fs.readFile(envPath, "utf8"); } + // Only add variables that don't already exist + if (!envContent.includes("BETTER_AUTH_SECRET")) { + envContent += `\nBETTER_AUTH_SECRET=${generateAuthSecret()}`; + } + + if (!envContent.includes("BETTER_AUTH_URL")) { + envContent += "\nBETTER_AUTH_URL=http://localhost:3000"; + } + + if (!envContent.includes("CORS_ORIGIN")) { + envContent += "\nCORS_ORIGIN=http://localhost:3001"; + } + + if ( + options.database === "sqlite" && + !envContent.includes("TURSO_CONNECTION_URL") + ) { + envContent += "\nTURSO_CONNECTION_URL=http://127.0.0.1:8080"; + } + + if (options.orm === "prisma" && !envContent.includes("DATABASE_URL")) { + if (options.database === "sqlite") { + envContent += '\nDATABASE_URL="file:./dev.db"'; + } else if (options.database === "postgres") { + envContent += + '\nDATABASE_URL="postgresql://postgres:postgres@localhost:5432/mydb?schema=public"'; + } + } + + // Write the updated content + await fs.writeFile(envPath, envContent.trim()); + + // Create client .env file if it doesn't exist const clientEnvPath = path.join(clientDir, ".env"); if (!(await fs.pathExists(clientEnvPath))) { const clientEnvContent = "VITE_SERVER_URL=http://localhost:3000\n"; @@ -109,24 +110,6 @@ ${options.orm === "prisma" ? 'DATABASE_URL="file:./dev.db"' : ""} } } -function getOrmTemplatePath( - orm: string, - database: string, - relativePath: string, -): string { - if (orm === "drizzle") { - return database === "sqlite" - ? `template/with-drizzle-sqlite/${relativePath}` - : `template/with-drizzle-postgres/${relativePath}`; - } - if (orm === "prisma") { - return database === "sqlite" - ? `template/with-prisma-sqlite/${relativePath}` - : `template/with-prisma-postgres/${relativePath}`; - } - return `template/base/${relativePath}`; -} - function generateAuthSecret(length = 32): string { const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; diff --git a/apps/cli/src/helpers/create-project.ts b/apps/cli/src/helpers/create-project.ts index 978f4e9..bf97e4a 100644 --- a/apps/cli/src/helpers/create-project.ts +++ b/apps/cli/src/helpers/create-project.ts @@ -42,27 +42,6 @@ export async function createProject(options: ProjectConfig): Promise { } } - const envFiles = [ - [ - path.join(projectDir, "packages/server/_env"), - path.join(projectDir, "packages/server/.env"), - ], - [ - path.join(projectDir, "packages/client/_env"), - path.join(projectDir, "packages/client/.env"), - ], - ]; - - for (const [source, target] of envFiles) { - if (await fs.pathExists(source)) { - if (!(await fs.pathExists(target))) { - await fs.move(source, target); - } else { - await fs.remove(source); - } - } - } - await setupDatabase( projectDir, options.database, diff --git a/apps/cli/src/helpers/db-setup.ts b/apps/cli/src/helpers/db-setup.ts index 679cbb8..de6269e 100644 --- a/apps/cli/src/helpers/db-setup.ts +++ b/apps/cli/src/helpers/db-setup.ts @@ -2,6 +2,7 @@ import path from "node:path"; import { log, spinner } from "@clack/prompts"; import fs from "fs-extra"; import pc from "picocolors"; +import { addPackageDependency } from "../utils/add-package-deps"; import { setupTurso } from "./turso-setup"; export async function setupDatabase( @@ -21,21 +22,93 @@ export async function setupDatabase( try { if (databaseType === "sqlite") { if (orm === "drizzle") { - await setupDrizzleDependencies(projectDir, "sqlite"); + addPackageDependency({ + dependencies: ["drizzle-orm", "drizzle-kit", "@libsql/client"], + devDependencies: false, + projectDir: serverDir, + }); if (setupTursoDb) { await setupTurso(projectDir, true); } } else if (orm === "prisma") { - await setupPrismaDependencies(projectDir, "sqlite"); + addPackageDependency({ + dependencies: [ + "@prisma/client", + "@prisma/adapter-libsql", + "@libsql/client", + ], + devDependencies: false, + projectDir: serverDir, + }); + addPackageDependency({ + dependencies: ["prisma"], + devDependencies: true, + projectDir: serverDir, + }); if (setupTursoDb) { await setupTurso(projectDir, true); } } } else if (databaseType === "postgres") { if (orm === "drizzle") { - await setupDrizzleDependencies(projectDir, "postgres"); + addPackageDependency({ + dependencies: ["drizzle-orm", "postgres"], + devDependencies: false, + projectDir: serverDir, + }); + addPackageDependency({ + dependencies: ["drizzle-kit"], + devDependencies: true, + projectDir: serverDir, + }); } else if (orm === "prisma") { - await setupPrismaDependencies(projectDir, "postgres"); + addPackageDependency({ + dependencies: ["@prisma/client"], + devDependencies: false, + projectDir: serverDir, + }); + addPackageDependency({ + dependencies: ["prisma"], + devDependencies: true, + projectDir: serverDir, + }); + } + } + + const packageJsonPath = path.join(serverDir, "package.json"); + if (await fs.pathExists(packageJsonPath)) { + const packageJson = await fs.readJSON(packageJsonPath); + + if (orm === "drizzle") { + packageJson.scripts = { + ...packageJson.scripts, + "db:generate": "drizzle-kit generate", + "db:migrate": "drizzle-kit push", + "db:studio": "drizzle-kit studio", + }; + } else if (orm === "prisma") { + packageJson.scripts = { + ...packageJson.scripts, + "prisma:generate": "prisma generate", + "prisma:push": "prisma db push", + "prisma:studio": "prisma studio", + }; + } + + await fs.writeJSON(packageJsonPath, packageJson, { spaces: 2 }); + } + + if (orm === "prisma") { + const envPath = path.join(serverDir, ".env"); + if (await fs.pathExists(envPath)) { + const envContent = await fs.readFile(envPath, "utf8"); + if (!envContent.includes("DATABASE_URL")) { + const databaseUrlLine = + databaseType === "sqlite" + ? `\nDATABASE_URL="file:./dev.db"` + : `\nDATABASE_URL="postgresql://postgres:postgres@localhost:5432/mydb?schema=public"`; + await fs.appendFile(envPath, databaseUrlLine); + } } } } catch (error) { @@ -46,90 +119,3 @@ export async function setupDatabase( throw error; } } - -async function setupDrizzleDependencies( - projectDir: string, - dbType: string, -): Promise { - const serverDir = path.join(projectDir, "packages/server"); - - const packageJsonPath = path.join(serverDir, "package.json"); - if (await fs.pathExists(packageJsonPath)) { - const packageJson = await fs.readJSON(packageJsonPath); - - packageJson.dependencies = { - ...packageJson.dependencies, - "drizzle-orm": "^0.38.4", - }; - - if (dbType === "sqlite") { - packageJson.dependencies["@libsql/client"] = "^0.14.0"; - } else if (dbType === "postgres") { - packageJson.dependencies.postgres = "^3.4.5"; - } - - packageJson.devDependencies = { - ...packageJson.devDependencies, - "drizzle-kit": "^0.30.4", - }; - - packageJson.scripts = { - ...packageJson.scripts, - "db:generate": "drizzle-kit generate", - "db:migrate": "drizzle-kit push", - "db:studio": "drizzle-kit studio", - }; - - await fs.writeJSON(packageJsonPath, packageJson, { spaces: 2 }); - } -} - -async function setupPrismaDependencies( - projectDir: string, - dbType: string, -): Promise { - const serverDir = path.join(projectDir, "packages/server"); - - const packageJsonPath = path.join(serverDir, "package.json"); - if (await fs.pathExists(packageJsonPath)) { - const packageJson = await fs.readJSON(packageJsonPath); - - packageJson.dependencies = { - ...packageJson.dependencies, - "@prisma/client": "^5.7.1", - }; - - if (dbType === "sqlite") { - packageJson.dependencies["@prisma/adapter-libsql"] = "^5.7.1"; - packageJson.dependencies["@libsql/client"] = "^0.14.0"; - } else if (dbType === "postgres") { - // PostgreSQL specific dependencies if needed - } - - packageJson.devDependencies = { - ...packageJson.devDependencies, - prisma: "^5.7.1", - }; - - packageJson.scripts = { - ...packageJson.scripts, - "prisma:generate": "prisma generate", - "prisma:push": "prisma db push", - "prisma:studio": "prisma studio", - }; - - await fs.writeJSON(packageJsonPath, packageJson, { spaces: 2 }); - } - - const envPath = path.join(serverDir, ".env"); - if (await fs.pathExists(envPath)) { - const envContent = await fs.readFile(envPath, "utf8"); - if (!envContent.includes("DATABASE_URL")) { - const databaseUrlLine = - dbType === "sqlite" - ? `\nDATABASE_URL="file:./dev.db"` - : `\nDATABASE_URL="postgresql://postgres:postgres@localhost:5432/mydb?schema=public"`; - await fs.appendFile(envPath, databaseUrlLine); - } - } -} diff --git a/apps/cli/src/utils/add-package-deps.ts b/apps/cli/src/utils/add-package-deps.ts new file mode 100644 index 0000000..a3cfe1a --- /dev/null +++ b/apps/cli/src/utils/add-package-deps.ts @@ -0,0 +1,28 @@ +import path from "node:path"; +import fs from "fs-extra"; + +import { type AvailableDependencies, dependencyVersionMap } from "../constants"; + +export const addPackageDependency = (opts: { + dependencies: AvailableDependencies[]; + devDependencies: boolean; + projectDir: string; +}) => { + const { dependencies, devDependencies, projectDir } = opts; + + const pkgJson = fs.readJSONSync(path.join(projectDir, "package.json")); + + for (const pkgName of dependencies) { + const version = dependencyVersionMap[pkgName]; + + if (devDependencies && pkgJson.devDependencies) { + pkgJson.devDependencies[pkgName] = version; + } else if (pkgJson.dependencies) { + pkgJson.dependencies[pkgName] = version; + } + } + + fs.writeJSONSync(path.join(projectDir, "package.json"), pkgJson, { + spaces: 2, + }); +}; diff --git a/apps/cli/template/base/package.json b/apps/cli/template/base/package.json index c582994..8c45085 100644 --- a/apps/cli/template/base/package.json +++ b/apps/cli/template/base/package.json @@ -14,9 +14,6 @@ "db:push": "turbo -F @better-t/server db:push" }, "packageManager": "bun@1.2.4", - "dependencies": { - "drizzle-orm": "^0.38.4" - }, "devDependencies": { "turbo": "^2.4.2" } diff --git a/apps/cli/template/base/packages/client/package.json b/apps/cli/template/base/packages/client/package.json index 140876a..1c97f84 100644 --- a/apps/cli/template/base/packages/client/package.json +++ b/apps/cli/template/base/packages/client/package.json @@ -36,7 +36,6 @@ "@trpc/client": "^11.0.0-rc.748", "@trpc/react-query": "^11.0.0-rc.748", "@trpc/server": "^11.0.0-rc.748", - "better-auth": "^1.1.16", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.473.0", diff --git a/apps/cli/template/base/packages/server/package.json b/apps/cli/template/base/packages/server/package.json index 53ea444..68bb9c5 100644 --- a/apps/cli/template/base/packages/server/package.json +++ b/apps/cli/template/base/packages/server/package.json @@ -17,17 +17,13 @@ "dependencies": { "@hono/node-server": "^1.13.8", "@hono/trpc-server": "^0.3.4", - "@libsql/client": "^0.14.0", "@trpc/server": "^11.0.0-rc.748", - "better-auth": "^1.1.16", "dotenv": "^16.4.7", - "drizzle-orm": "^0.38.4", "hono": "^4.7.0", "zod": "^3.24.1" }, "devDependencies": { "tsx": "^4.19.2", - "drizzle-kit": "^0.30.4", "@types/node": "^22.13.4", "typescript": "^5.7.3" } diff --git a/apps/cli/template/with-prisma-sqlite/packages/server/src/db/schema.prisma b/apps/cli/template/with-prisma-sqlite/packages/server/src/db/schema.prisma index 12f3d1e..fd89f8a 100644 --- a/apps/cli/template/with-prisma-sqlite/packages/server/src/db/schema.prisma +++ b/apps/cli/template/with-prisma-sqlite/packages/server/src/db/schema.prisma @@ -11,7 +11,7 @@ generator client { datasource db { provider = "sqlite" - url = env("DATABASE_URL") + url = env("TURSO_DATABASE_URL") } model User {