zuro-cli 0.0.2-beta.14 → 0.0.2-beta.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # zuro-cli
2
2
 
3
- A CLI for scaffolding backend foundations and modules in your project.
3
+ A CLI for adding production-ready backend modules you own, without framework lock-in.
4
4
 
5
5
  ## init
6
6
 
@@ -31,6 +31,7 @@ npx zuro-cli add auth
31
31
  Available modules include:
32
32
 
33
33
  - `database`
34
+ - `uploads`
34
35
  - `auth`
35
36
  - `validator`
36
37
  - `error-handler`
@@ -7,27 +7,78 @@ import path from "path";
7
7
  import fs from "fs-extra";
8
8
  import prompts from "prompts";
9
9
  import chalk from "chalk";
10
+ var DATABASE_MODULE_MAP = {
11
+ drizzle: {
12
+ postgresql: "database-pg",
13
+ mysql: "database-mysql"
14
+ },
15
+ prisma: {
16
+ postgresql: "database-prisma-pg",
17
+ mysql: "database-prisma-mysql"
18
+ }
19
+ };
10
20
  var DEFAULT_DATABASE_URLS = {
11
21
  "database-pg": "postgresql://postgres@localhost:5432/mydb",
12
- "database-mysql": "mysql://root@localhost:3306/mydb"
22
+ "database-mysql": "mysql://root@localhost:3306/mydb",
23
+ "database-prisma-pg": "postgresql://postgres@localhost:5432/mydb",
24
+ "database-prisma-mysql": "mysql://root@localhost:3306/mydb"
13
25
  };
14
26
  function parseDatabaseDialect(value) {
15
27
  const normalized = value?.trim().toLowerCase();
16
28
  if (!normalized) {
17
29
  return null;
18
30
  }
19
- if (normalized === "pg" || normalized === "postgres" || normalized === "postgresql" || normalized === "database-pg") {
31
+ if (normalized === "pg" || normalized === "postgres" || normalized === "postgresql" || normalized === "database-pg" || normalized === "drizzle-pg" || normalized === "drizzle-postgres" || normalized === "database-drizzle-pg") {
20
32
  return "database-pg";
21
33
  }
22
- if (normalized === "mysql" || normalized === "database-mysql") {
34
+ if (normalized === "mysql" || normalized === "database-mysql" || normalized === "drizzle-mysql" || normalized === "database-drizzle-mysql") {
23
35
  return "database-mysql";
24
36
  }
37
+ if (normalized === "database-prisma-pg" || normalized === "prisma-pg" || normalized === "prisma-postgres" || normalized === "prisma-postgresql" || normalized === "database-prisma") {
38
+ return "database-prisma-pg";
39
+ }
40
+ if (normalized === "database-prisma-mysql" || normalized === "prisma-mysql") {
41
+ return "database-prisma-mysql";
42
+ }
25
43
  return null;
26
44
  }
27
45
  function isDatabaseModule(moduleName) {
46
+ return moduleName === "database-pg" || moduleName === "database-mysql" || moduleName === "database-prisma-pg" || moduleName === "database-prisma-mysql";
47
+ }
48
+ function isDrizzleDatabaseModule(moduleName) {
28
49
  return moduleName === "database-pg" || moduleName === "database-mysql";
29
50
  }
51
+ function getDatabaseSelection(moduleName) {
52
+ if (moduleName === "database-pg") {
53
+ return { orm: "drizzle", dialect: "postgresql" };
54
+ }
55
+ if (moduleName === "database-mysql") {
56
+ return { orm: "drizzle", dialect: "mysql" };
57
+ }
58
+ if (moduleName === "database-prisma-pg") {
59
+ return { orm: "prisma", dialect: "postgresql" };
60
+ }
61
+ return { orm: "prisma", dialect: "mysql" };
62
+ }
63
+ function getDatabaseModule(orm, dialect) {
64
+ return DATABASE_MODULE_MAP[orm][dialect];
65
+ }
66
+ function parsePrismaProvider(schemaContent) {
67
+ const match = schemaContent.match(/provider\s*=\s*"([^"]+)"/);
68
+ if (!match) {
69
+ return null;
70
+ }
71
+ const provider = match[1]?.trim().toLowerCase();
72
+ if (provider === "mysql") {
73
+ return "mysql";
74
+ }
75
+ if (provider === "postgresql" || provider === "postgres") {
76
+ return "postgresql";
77
+ }
78
+ return null;
79
+ }
30
80
  function validateDatabaseUrl(rawUrl, moduleName) {
81
+ const { dialect } = getDatabaseSelection(moduleName);
31
82
  const dbUrl = rawUrl.trim();
32
83
  if (!dbUrl) {
33
84
  throw new Error("Database URL cannot be empty.");
@@ -39,25 +90,43 @@ function validateDatabaseUrl(rawUrl, moduleName) {
39
90
  throw new Error(`Invalid database URL: '${dbUrl}'.`);
40
91
  }
41
92
  const protocol = parsed.protocol.toLowerCase();
42
- if (moduleName === "database-pg" && protocol !== "postgresql:" && protocol !== "postgres:") {
93
+ if (dialect === "postgresql" && protocol !== "postgresql:" && protocol !== "postgres:") {
43
94
  throw new Error("PostgreSQL URL must start with postgres:// or postgresql://");
44
95
  }
45
- if (moduleName === "database-mysql" && protocol !== "mysql:") {
96
+ if (dialect === "mysql" && protocol !== "mysql:") {
46
97
  throw new Error("MySQL URL must start with mysql://");
47
98
  }
48
99
  return dbUrl;
49
100
  }
50
101
  async function detectInstalledDatabaseDialect(projectRoot, srcDir) {
51
102
  const dbIndexPath = path.join(projectRoot, srcDir, "db", "index.ts");
52
- if (!fs.existsSync(dbIndexPath)) {
53
- return null;
54
- }
55
- const content = await fs.readFile(dbIndexPath, "utf-8");
56
- if (content.includes("drizzle-orm/node-postgres") || content.includes(`from "pg"`)) {
57
- return "database-pg";
103
+ const prismaSchemaPath = path.join(projectRoot, "prisma", "schema.prisma");
104
+ if (fs.existsSync(dbIndexPath)) {
105
+ const content = await fs.readFile(dbIndexPath, "utf-8");
106
+ if (content.includes("drizzle-orm/node-postgres") || content.includes(`from "pg"`)) {
107
+ return "database-pg";
108
+ }
109
+ if (content.includes("drizzle-orm/mysql2") || content.includes(`from "mysql2`)) {
110
+ return "database-mysql";
111
+ }
112
+ if (content.includes(`from "@prisma/client"`)) {
113
+ if (fs.existsSync(prismaSchemaPath)) {
114
+ const schemaContent = await fs.readFile(prismaSchemaPath, "utf-8");
115
+ const dialect = parsePrismaProvider(schemaContent);
116
+ if (dialect === "mysql") {
117
+ return "database-prisma-mysql";
118
+ }
119
+ }
120
+ return "database-prisma-pg";
121
+ }
58
122
  }
59
- if (content.includes("drizzle-orm/mysql2") || content.includes(`from "mysql2`)) {
60
- return "database-mysql";
123
+ if (fs.existsSync(prismaSchemaPath)) {
124
+ const schemaContent = await fs.readFile(prismaSchemaPath, "utf-8");
125
+ const dialect = parsePrismaProvider(schemaContent);
126
+ if (dialect === "mysql") {
127
+ return "database-prisma-mysql";
128
+ }
129
+ return "database-prisma-pg";
61
130
  }
62
131
  return null;
63
132
  }
@@ -66,7 +135,8 @@ async function backupDatabaseFiles(projectRoot, srcDir) {
66
135
  const backupRoot = path.join(projectRoot, ".zuro", "backups", `database-${timestamp}`);
67
136
  const candidates = [
68
137
  path.join(projectRoot, srcDir, "db", "index.ts"),
69
- path.join(projectRoot, "drizzle.config.ts")
138
+ path.join(projectRoot, "drizzle.config.ts"),
139
+ path.join(projectRoot, "prisma", "schema.prisma")
70
140
  ];
71
141
  let copied = false;
72
142
  for (const filePath of candidates) {
@@ -82,7 +152,10 @@ async function backupDatabaseFiles(projectRoot, srcDir) {
82
152
  return copied ? backupRoot : null;
83
153
  }
84
154
  function databaseLabel(moduleName) {
85
- return moduleName === "database-pg" ? "PostgreSQL" : "MySQL";
155
+ const selection = getDatabaseSelection(moduleName);
156
+ const ormLabel = selection.orm === "drizzle" ? "Drizzle" : "Prisma";
157
+ const dialectLabel = selection.dialect === "postgresql" ? "PostgreSQL" : "MySQL";
158
+ return `${ormLabel} (${dialectLabel})`;
86
159
  }
87
160
  function getDatabaseSetupHint(moduleName, dbUrl) {
88
161
  try {
@@ -122,23 +195,42 @@ async function ensureSchemaExport(projectRoot, srcDir, schemaFileName) {
122
195
  async function promptDatabaseConfig(initialModuleName, projectRoot, srcDir) {
123
196
  let resolvedModuleName;
124
197
  if (initialModuleName === "database") {
198
+ const ormResponse = await prompts({
199
+ type: "select",
200
+ name: "orm",
201
+ message: "Which ORM?",
202
+ choices: [
203
+ { title: "Drizzle", value: "drizzle" },
204
+ { title: "Prisma", value: "prisma" }
205
+ ],
206
+ initial: 0
207
+ });
208
+ if (!ormResponse.orm) {
209
+ console.log(chalk.yellow("Operation cancelled."));
210
+ return null;
211
+ }
125
212
  const variantResponse = await prompts({
126
213
  type: "select",
127
- name: "variant",
214
+ name: "dialect",
128
215
  message: "Which database dialect?",
129
216
  choices: [
130
- { title: "PostgreSQL", value: "database-pg" },
131
- { title: "MySQL", value: "database-mysql" }
217
+ { title: "PostgreSQL", value: "postgresql" },
218
+ { title: "MySQL", value: "mysql" }
132
219
  ]
133
220
  });
134
- if (!variantResponse.variant) {
221
+ if (!variantResponse.dialect) {
135
222
  console.log(chalk.yellow("Operation cancelled."));
136
223
  return null;
137
224
  }
138
- resolvedModuleName = variantResponse.variant;
225
+ resolvedModuleName = getDatabaseModule(ormResponse.orm, variantResponse.dialect);
139
226
  } else {
140
- resolvedModuleName = initialModuleName;
227
+ const parsed = parseDatabaseDialect(initialModuleName);
228
+ if (!parsed) {
229
+ throw new Error(`Unsupported database module '${initialModuleName}'.`);
230
+ }
231
+ resolvedModuleName = parsed;
141
232
  }
233
+ const { orm: selectedOrm, dialect: selectedDialect } = getDatabaseSelection(resolvedModuleName);
142
234
  let databaseBackupPath = null;
143
235
  const installedDialect = await detectInstalledDatabaseDialect(projectRoot, srcDir);
144
236
  if (installedDialect && installedDialect !== resolvedModuleName) {
@@ -182,7 +274,14 @@ async function promptDatabaseConfig(initialModuleName, projectRoot, srcDir) {
182
274
  const enteredUrl = response.dbUrl?.trim() || "";
183
275
  const usedDefaultDbUrl = enteredUrl.length === 0;
184
276
  const customDbUrl = validateDatabaseUrl(enteredUrl || defaultUrl, resolvedModuleName);
185
- return { resolvedModuleName, customDbUrl, usedDefaultDbUrl, databaseBackupPath };
277
+ return {
278
+ resolvedModuleName,
279
+ selectedOrm,
280
+ selectedDialect,
281
+ customDbUrl,
282
+ usedDefaultDbUrl,
283
+ databaseBackupPath
284
+ };
186
285
  }
187
286
  function printDatabaseHints(moduleName, customDbUrl, usedDefaultDbUrl, databaseBackupPath) {
188
287
  if (databaseBackupPath) {
@@ -197,13 +296,20 @@ function printDatabaseHints(moduleName, customDbUrl, usedDefaultDbUrl, databaseB
197
296
  customDbUrl || DEFAULT_DATABASE_URLS[moduleName]
198
297
  );
199
298
  console.log(chalk.yellow(`\u2139 Ensure DB exists: ${setupHint}`));
200
- console.log(chalk.yellow("\u2139 Run migrations: npx drizzle-kit generate && npx drizzle-kit migrate"));
299
+ if (isDrizzleDatabaseModule(moduleName)) {
300
+ console.log(chalk.yellow("\u2139 Run migrations: npx drizzle-kit generate && npx drizzle-kit migrate"));
301
+ return;
302
+ }
303
+ console.log(chalk.yellow("\u2139 Run migrations: npx prisma migrate dev --name init"));
304
+ console.log(chalk.yellow("\u2139 Generate client: npx prisma generate"));
201
305
  }
202
306
 
203
307
  export {
204
308
  DEFAULT_DATABASE_URLS,
205
309
  parseDatabaseDialect,
206
310
  isDatabaseModule,
311
+ isDrizzleDatabaseModule,
312
+ getDatabaseSelection,
207
313
  validateDatabaseUrl,
208
314
  detectInstalledDatabaseDialect,
209
315
  backupDatabaseFiles,
@@ -213,4 +319,4 @@ export {
213
319
  promptDatabaseConfig,
214
320
  printDatabaseHints
215
321
  };
216
- //# sourceMappingURL=chunk-W36ZIR4Y.mjs.map
322
+ //# sourceMappingURL=chunk-R3MGV5UR.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/handlers/database.handler.ts"],"sourcesContent":["import path from \"path\";\nimport fs from \"fs-extra\";\nimport prompts from \"prompts\";\nimport chalk from \"chalk\";\nimport { escapeRegex } from \"../utils/code-inject\";\n\nexport type DatabaseOrm = \"drizzle\" | \"prisma\";\nexport type DatabaseDialect = \"postgresql\" | \"mysql\";\nexport type DatabaseModuleName =\n | \"database-pg\"\n | \"database-mysql\"\n | \"database-prisma-pg\"\n | \"database-prisma-mysql\";\n\nconst DATABASE_MODULE_MAP: Record<DatabaseOrm, Record<DatabaseDialect, DatabaseModuleName>> = {\n drizzle: {\n postgresql: \"database-pg\",\n mysql: \"database-mysql\",\n },\n prisma: {\n postgresql: \"database-prisma-pg\",\n mysql: \"database-prisma-mysql\",\n },\n};\n\nexport const DEFAULT_DATABASE_URLS: Record<DatabaseModuleName, string> = {\n \"database-pg\": \"postgresql://postgres@localhost:5432/mydb\",\n \"database-mysql\": \"mysql://root@localhost:3306/mydb\",\n \"database-prisma-pg\": \"postgresql://postgres@localhost:5432/mydb\",\n \"database-prisma-mysql\": \"mysql://root@localhost:3306/mydb\",\n};\n\nexport function parseDatabaseDialect(value?: string): DatabaseModuleName | null {\n const normalized = value?.trim().toLowerCase();\n if (!normalized) {\n return null;\n }\n\n if (\n normalized === \"pg\"\n || normalized === \"postgres\"\n || normalized === \"postgresql\"\n || normalized === \"database-pg\"\n || normalized === \"drizzle-pg\"\n || normalized === \"drizzle-postgres\"\n || normalized === \"database-drizzle-pg\"\n ) {\n return \"database-pg\";\n }\n\n if (\n normalized === \"mysql\"\n || normalized === \"database-mysql\"\n || normalized === \"drizzle-mysql\"\n || normalized === \"database-drizzle-mysql\"\n ) {\n return \"database-mysql\";\n }\n\n if (\n normalized === \"database-prisma-pg\"\n || normalized === \"prisma-pg\"\n || normalized === \"prisma-postgres\"\n || normalized === \"prisma-postgresql\"\n || normalized === \"database-prisma\"\n ) {\n return \"database-prisma-pg\";\n }\n\n if (normalized === \"database-prisma-mysql\" || normalized === \"prisma-mysql\") {\n return \"database-prisma-mysql\";\n }\n\n return null;\n}\n\nexport function isDatabaseModule(moduleName: string): moduleName is DatabaseModuleName {\n return (\n moduleName === \"database-pg\"\n || moduleName === \"database-mysql\"\n || moduleName === \"database-prisma-pg\"\n || moduleName === \"database-prisma-mysql\"\n );\n}\n\nexport function isDrizzleDatabaseModule(moduleName: string): moduleName is \"database-pg\" | \"database-mysql\" {\n return moduleName === \"database-pg\" || moduleName === \"database-mysql\";\n}\n\nexport function getDatabaseSelection(moduleName: DatabaseModuleName): { orm: DatabaseOrm; dialect: DatabaseDialect } {\n if (moduleName === \"database-pg\") {\n return { orm: \"drizzle\", dialect: \"postgresql\" };\n }\n\n if (moduleName === \"database-mysql\") {\n return { orm: \"drizzle\", dialect: \"mysql\" };\n }\n\n if (moduleName === \"database-prisma-pg\") {\n return { orm: \"prisma\", dialect: \"postgresql\" };\n }\n\n return { orm: \"prisma\", dialect: \"mysql\" };\n}\n\nfunction getDatabaseModule(orm: DatabaseOrm, dialect: DatabaseDialect): DatabaseModuleName {\n return DATABASE_MODULE_MAP[orm][dialect];\n}\n\nfunction parsePrismaProvider(schemaContent: string): DatabaseDialect | null {\n const match = schemaContent.match(/provider\\s*=\\s*\"([^\"]+)\"/);\n if (!match) {\n return null;\n }\n\n const provider = match[1]?.trim().toLowerCase();\n if (provider === \"mysql\") {\n return \"mysql\";\n }\n\n if (provider === \"postgresql\" || provider === \"postgres\") {\n return \"postgresql\";\n }\n\n return null;\n}\n\nexport function validateDatabaseUrl(rawUrl: string, moduleName: DatabaseModuleName) {\n const { dialect } = getDatabaseSelection(moduleName);\n const dbUrl = rawUrl.trim();\n if (!dbUrl) {\n throw new Error(\"Database URL cannot be empty.\");\n }\n\n let parsed: URL;\n try {\n parsed = new URL(dbUrl);\n } catch {\n throw new Error(`Invalid database URL: '${dbUrl}'.`);\n }\n\n const protocol = parsed.protocol.toLowerCase();\n if (dialect === \"postgresql\" && protocol !== \"postgresql:\" && protocol !== \"postgres:\") {\n throw new Error(\"PostgreSQL URL must start with postgres:// or postgresql://\");\n }\n\n if (dialect === \"mysql\" && protocol !== \"mysql:\") {\n throw new Error(\"MySQL URL must start with mysql://\");\n }\n\n return dbUrl;\n}\n\nexport async function detectInstalledDatabaseDialect(projectRoot: string, srcDir: string): Promise<DatabaseModuleName | null> {\n const dbIndexPath = path.join(projectRoot, srcDir, \"db\", \"index.ts\");\n const prismaSchemaPath = path.join(projectRoot, \"prisma\", \"schema.prisma\");\n\n if (fs.existsSync(dbIndexPath)) {\n const content = await fs.readFile(dbIndexPath, \"utf-8\");\n if (content.includes(\"drizzle-orm/node-postgres\") || content.includes(`from \"pg\"`)) {\n return \"database-pg\";\n }\n\n if (content.includes(\"drizzle-orm/mysql2\") || content.includes(`from \"mysql2`)) {\n return \"database-mysql\";\n }\n\n if (content.includes(`from \"@prisma/client\"`)) {\n if (fs.existsSync(prismaSchemaPath)) {\n const schemaContent = await fs.readFile(prismaSchemaPath, \"utf-8\");\n const dialect = parsePrismaProvider(schemaContent);\n if (dialect === \"mysql\") {\n return \"database-prisma-mysql\";\n }\n }\n\n return \"database-prisma-pg\";\n }\n }\n\n if (fs.existsSync(prismaSchemaPath)) {\n const schemaContent = await fs.readFile(prismaSchemaPath, \"utf-8\");\n const dialect = parsePrismaProvider(schemaContent);\n if (dialect === \"mysql\") {\n return \"database-prisma-mysql\";\n }\n\n return \"database-prisma-pg\";\n }\n\n return null;\n}\n\nexport async function backupDatabaseFiles(projectRoot: string, srcDir: string): Promise<string | null> {\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const backupRoot = path.join(projectRoot, \".zuro\", \"backups\", `database-${timestamp}`);\n const candidates = [\n path.join(projectRoot, srcDir, \"db\", \"index.ts\"),\n path.join(projectRoot, \"drizzle.config.ts\"),\n path.join(projectRoot, \"prisma\", \"schema.prisma\"),\n ];\n\n let copied = false;\n for (const filePath of candidates) {\n if (!fs.existsSync(filePath)) {\n continue;\n }\n\n const relativePath = path.relative(projectRoot, filePath);\n const backupPath = path.join(backupRoot, relativePath);\n await fs.ensureDir(path.dirname(backupPath));\n await fs.copyFile(filePath, backupPath);\n copied = true;\n }\n\n return copied ? backupRoot : null;\n}\n\nexport function databaseLabel(moduleName: DatabaseModuleName) {\n const selection = getDatabaseSelection(moduleName);\n const ormLabel = selection.orm === \"drizzle\" ? \"Drizzle\" : \"Prisma\";\n const dialectLabel = selection.dialect === \"postgresql\" ? \"PostgreSQL\" : \"MySQL\";\n return `${ormLabel} (${dialectLabel})`;\n}\n\nexport function getDatabaseSetupHint(moduleName: DatabaseModuleName, dbUrl: string) {\n try {\n const parsed = new URL(dbUrl);\n const dbName = parsed.pathname.replace(/^\\/+/, \"\") || \"mydb\";\n\n if (moduleName === \"database-pg\") {\n return `createdb ${dbName}`;\n }\n\n return `mysql -e \"CREATE DATABASE IF NOT EXISTS ${dbName};\"`;\n } catch {\n return moduleName === \"database-pg\"\n ? \"createdb <database_name>\"\n : `mysql -e \"CREATE DATABASE IF NOT EXISTS <database_name>;\"`;\n }\n}\n\nexport async function ensureSchemaExport(projectRoot: string, srcDir: string, schemaFileName: string) {\n const schemaIndexPath = path.join(projectRoot, srcDir, \"db\", \"schema\", \"index.ts\");\n if (!await fs.pathExists(schemaIndexPath)) {\n return;\n }\n\n const exportLine = `export * from \"./${schemaFileName}\";`;\n const content = await fs.readFile(schemaIndexPath, \"utf-8\");\n const normalized = content.replace(/\\r\\n/g, \"\\n\");\n const exportPattern = new RegExp(\n `^\\\\s*export\\\\s*\\\\*\\\\s*from\\\\s*[\"']\\\\./${escapeRegex(schemaFileName)}[\"'];?\\\\s*$`,\n \"m\"\n );\n\n if (exportPattern.test(normalized)) {\n return;\n }\n\n let next = normalized\n .replace(/^\\s*export\\s*\\{\\s*\\};?\\s*$/m, \"\")\n .trimEnd();\n\n if (next.length > 0) {\n next += \"\\n\\n\";\n }\n\n next += `${exportLine}\\n`;\n await fs.writeFile(schemaIndexPath, next);\n}\n\nexport interface DatabasePromptResult {\n resolvedModuleName: DatabaseModuleName;\n selectedOrm: DatabaseOrm;\n selectedDialect: DatabaseDialect;\n customDbUrl: string | undefined;\n usedDefaultDbUrl: boolean;\n databaseBackupPath: string | null;\n}\n\n/**\n * Runs all database-specific interactive prompts and validation.\n * Returns null if the user cancels.\n */\nexport async function promptDatabaseConfig(\n initialModuleName: string,\n projectRoot: string,\n srcDir: string,\n): Promise<DatabasePromptResult | null> {\n let resolvedModuleName: DatabaseModuleName;\n\n if (initialModuleName === \"database\") {\n const ormResponse = await prompts({\n type: \"select\",\n name: \"orm\",\n message: \"Which ORM?\",\n choices: [\n { title: \"Drizzle\", value: \"drizzle\" },\n { title: \"Prisma\", value: \"prisma\" },\n ],\n initial: 0,\n });\n\n if (!ormResponse.orm) {\n console.log(chalk.yellow(\"Operation cancelled.\"));\n return null;\n }\n\n const variantResponse = await prompts({\n type: \"select\",\n name: \"dialect\",\n message: \"Which database dialect?\",\n choices: [\n { title: \"PostgreSQL\", value: \"postgresql\" },\n { title: \"MySQL\", value: \"mysql\" },\n ],\n });\n\n if (!variantResponse.dialect) {\n console.log(chalk.yellow(\"Operation cancelled.\"));\n return null;\n }\n\n resolvedModuleName = getDatabaseModule(ormResponse.orm as DatabaseOrm, variantResponse.dialect as DatabaseDialect);\n } else {\n const parsed = parseDatabaseDialect(initialModuleName);\n if (!parsed) {\n throw new Error(`Unsupported database module '${initialModuleName}'.`);\n }\n\n resolvedModuleName = parsed;\n }\n\n const { orm: selectedOrm, dialect: selectedDialect } = getDatabaseSelection(resolvedModuleName);\n\n // Check for dialect switch\n let databaseBackupPath: string | null = null;\n const installedDialect = await detectInstalledDatabaseDialect(projectRoot, srcDir);\n\n if (installedDialect && installedDialect !== resolvedModuleName) {\n console.log(\n chalk.yellow(\n `\\n⚠ Existing database setup detected: ${databaseLabel(installedDialect)}.`\n )\n );\n console.log(\n chalk.yellow(\n ` Switching to ${databaseLabel(resolvedModuleName)} will overwrite db files and drizzle config.\\n`\n )\n );\n\n const switchResponse = await prompts({\n type: \"confirm\",\n name: \"proceed\",\n message: \"Continue and switch database dialect?\",\n initial: false,\n });\n\n if (!switchResponse.proceed) {\n console.log(chalk.yellow(\"Operation cancelled.\"));\n return null;\n }\n\n databaseBackupPath = await backupDatabaseFiles(projectRoot, srcDir);\n }\n\n // Prompt for database URL\n const defaultUrl = DEFAULT_DATABASE_URLS[resolvedModuleName];\n console.log(chalk.dim(` Tip: Leave blank to use ${defaultUrl}\\n`));\n\n const response = await prompts({\n type: \"text\",\n name: \"dbUrl\",\n message: \"Database URL\",\n initial: \"\",\n });\n\n if (response.dbUrl === undefined) {\n console.log(chalk.yellow(\"Operation cancelled.\"));\n return null;\n }\n\n const enteredUrl = response.dbUrl?.trim() || \"\";\n const usedDefaultDbUrl = enteredUrl.length === 0;\n const customDbUrl = validateDatabaseUrl(enteredUrl || defaultUrl, resolvedModuleName);\n\n return {\n resolvedModuleName,\n selectedOrm,\n selectedDialect,\n customDbUrl,\n usedDefaultDbUrl,\n databaseBackupPath,\n };\n}\n\n/**\n * Prints post-install hints for database modules.\n */\nexport function printDatabaseHints(\n moduleName: DatabaseModuleName,\n customDbUrl: string | undefined,\n usedDefaultDbUrl: boolean,\n databaseBackupPath: string | null,\n) {\n if (databaseBackupPath) {\n console.log(chalk.blue(`ℹ Backup created at: ${databaseBackupPath}\\n`));\n }\n\n if (usedDefaultDbUrl) {\n console.log(chalk.yellow(\"ℹ Review DATABASE_URL in .env if your local DB config differs.\"));\n }\n\n const setupHint = getDatabaseSetupHint(\n moduleName,\n customDbUrl || DEFAULT_DATABASE_URLS[moduleName]\n );\n console.log(chalk.yellow(`ℹ Ensure DB exists: ${setupHint}`));\n if (isDrizzleDatabaseModule(moduleName)) {\n console.log(chalk.yellow(\"ℹ Run migrations: npx drizzle-kit generate && npx drizzle-kit migrate\"));\n return;\n }\n\n console.log(chalk.yellow(\"ℹ Run migrations: npx prisma migrate dev --name init\"));\n console.log(chalk.yellow(\"ℹ Generate client: npx prisma generate\"));\n}\n"],"mappings":"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","names":[]}
@@ -4,13 +4,15 @@ import {
4
4
  databaseLabel,
5
5
  detectInstalledDatabaseDialect,
6
6
  ensureSchemaExport,
7
+ getDatabaseSelection,
7
8
  getDatabaseSetupHint,
8
9
  isDatabaseModule,
10
+ isDrizzleDatabaseModule,
9
11
  parseDatabaseDialect,
10
12
  printDatabaseHints,
11
13
  promptDatabaseConfig,
12
14
  validateDatabaseUrl
13
- } from "./chunk-W36ZIR4Y.mjs";
15
+ } from "./chunk-R3MGV5UR.mjs";
14
16
  import "./chunk-VMOTWTER.mjs";
15
17
  export {
16
18
  DEFAULT_DATABASE_URLS,
@@ -18,11 +20,13 @@ export {
18
20
  databaseLabel,
19
21
  detectInstalledDatabaseDialect,
20
22
  ensureSchemaExport,
23
+ getDatabaseSelection,
21
24
  getDatabaseSetupHint,
22
25
  isDatabaseModule,
26
+ isDrizzleDatabaseModule,
23
27
  parseDatabaseDialect,
24
28
  printDatabaseHints,
25
29
  promptDatabaseConfig,
26
30
  validateDatabaseUrl
27
31
  };
28
- //# sourceMappingURL=database.handler-D7EVXRJX.mjs.map
32
+ //# sourceMappingURL=database.handler-5OUD6XJZ.mjs.map