Add dependency version constants and package management utility

This commit is contained in:
Aman Varshney
2025-03-18 15:47:22 +05:30
parent bda0d5ad09
commit b7ac81d496
10 changed files with 175 additions and 182 deletions

View File

@@ -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;

View File

@@ -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";

View File

@@ -42,27 +42,6 @@ export async function createProject(options: ProjectConfig): Promise<string> {
}
}
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,

View File

@@ -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<void> {
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<void> {
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);
}
}
}

View File

@@ -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,
});
};