lapeh 1.0.4 → 1.0.6

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/.env.example CHANGED
@@ -1,6 +1,6 @@
1
1
  PORT=4000
2
2
  DATABASE_PROVIDER="postgresql"
3
- DATABASE_URL="postgresql://roby:12341234@localhost:5432/db_contact?schema=public"
3
+ DATABASE_URL="postgresql://roby:12341234@localhost:5432/db_example_test?schema=public"
4
4
  JWT_SECRET="replace_this_with_a_secure_random_string"
5
5
 
6
6
  # redis example:
package/bin/index.js CHANGED
@@ -3,12 +3,15 @@
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const { execSync } = require('child_process');
6
+ const readline = require('readline');
6
7
 
7
- const projectName = process.argv[2];
8
+ const args = process.argv.slice(2);
9
+ const projectName = args.find(arg => !arg.startsWith('-'));
10
+ const isFull = args.includes('--full');
8
11
 
9
12
  if (!projectName) {
10
13
  console.error('āŒ Please specify the project name:');
11
- console.error(' npx lapeh-cli <project-name>');
14
+ console.error(' npx lapeh-cli <project-name> [--full]');
12
15
  process.exit(1);
13
16
  }
14
17
 
@@ -21,85 +24,207 @@ if (fs.existsSync(projectDir)) {
21
24
  process.exit(1);
22
25
  }
23
26
 
24
- console.log(`šŸš€ Creating a new API Lapeh project in ${projectDir}...`);
25
- fs.mkdirSync(projectDir);
26
-
27
- // List of files/folders to exclude
28
- const ignoreList = [
29
- 'node_modules',
30
- 'dist',
31
- '.git',
32
- '.env',
33
- 'bin', // Don't copy the CLI script itself
34
- 'package-lock.json',
35
- '.DS_Store',
36
- projectName // Don't copy the destination folder itself if creating inside the template
37
- ];
38
-
39
- function copyDir(src, dest) {
40
- const entries = fs.readdirSync(src, { withFileTypes: true });
41
-
42
- for (const entry of entries) {
43
- const srcPath = path.join(src, entry.name);
44
- const destPath = path.join(dest, entry.name);
45
-
46
- if (ignoreList.includes(entry.name)) {
47
- continue;
27
+ // Setup readline interface
28
+ const rl = readline.createInterface({
29
+ input: process.stdin,
30
+ output: process.stdout,
31
+ });
32
+
33
+ const ask = (query, defaultVal) => {
34
+ return new Promise((resolve) => {
35
+ rl.question(`${query} ${defaultVal ? `[${defaultVal}]` : ""}: `, (answer) => {
36
+ resolve(answer.trim() || defaultVal);
37
+ });
38
+ });
39
+ };
40
+
41
+ const selectOption = async (query, options) => {
42
+ console.log(query);
43
+ options.forEach((opt, idx) => {
44
+ console.log(` [${opt.key}] ${opt.label}`);
45
+ });
46
+
47
+ while (true) {
48
+ const answer = await ask(">", options[0].key);
49
+ const selected = options.find(o => o.key.toLowerCase() === answer.toLowerCase());
50
+ if (selected) return selected;
51
+
52
+ const byLabel = options.find(o => o.label.toLowerCase().includes(answer.toLowerCase()));
53
+ if (byLabel) return byLabel;
54
+
55
+ console.log("Pilihan tidak valid. Silakan coba lagi.");
56
+ }
57
+ };
58
+
59
+ (async () => {
60
+ console.log(`šŸš€ Creating a new API Lapeh project in ${projectDir}...`);
61
+ fs.mkdirSync(projectDir);
62
+
63
+ // --- DATABASE SELECTION ---
64
+ console.log("\n--- Database Configuration ---");
65
+ const dbType = await selectOption("Database apa yang akan digunakan?", [
66
+ { key: "pgsql", label: "PostgreSQL", provider: "postgresql", defaultPort: "5432" },
67
+ { key: "mysql", label: "MySQL", provider: "mysql", defaultPort: "3306" },
68
+ { key: "mariadb", label: "MariaDB", provider: "mysql", defaultPort: "3306" },
69
+ { key: "sqlite", label: "SQLite", provider: "sqlite", defaultPort: "" },
70
+ ]);
71
+
72
+ let dbUrl = "";
73
+ let dbProvider = dbType.provider;
74
+
75
+ if (dbType.key === "sqlite") {
76
+ dbUrl = "file:./dev.db";
77
+ } else {
78
+ const host = await ask("Database Host", "localhost");
79
+ const port = await ask("Database Port", dbType.defaultPort);
80
+ const user = await ask("Database User", "root");
81
+ const password = await ask("Database Password", "");
82
+ const dbName = await ask("Database Name", projectName.replace(/-/g, '_')); // Default db name based on project name
83
+
84
+ if (dbType.key === "pgsql") {
85
+ dbUrl = `postgresql://${user}:${password}@${host}:${port}/${dbName}?schema=public`;
86
+ } else {
87
+ dbUrl = `mysql://${user}:${password}@${host}:${port}/${dbName}`;
48
88
  }
89
+ }
49
90
 
50
- if (entry.isDirectory()) {
51
- fs.mkdirSync(destPath);
52
- copyDir(srcPath, destPath);
53
- } else {
54
- fs.copyFileSync(srcPath, destPath);
91
+ rl.close();
92
+
93
+ // List of files/folders to exclude
94
+ const ignoreList = [
95
+ 'node_modules',
96
+ 'dist',
97
+ '.git',
98
+ '.env',
99
+ 'bin', // Don't copy the CLI script itself
100
+ 'package-lock.json',
101
+ '.DS_Store',
102
+ projectName // Don't copy the destination folder itself if creating inside the template
103
+ ];
104
+
105
+ function copyDir(src, dest) {
106
+ const entries = fs.readdirSync(src, { withFileTypes: true });
107
+
108
+ for (const entry of entries) {
109
+ const srcPath = path.join(src, entry.name);
110
+ const destPath = path.join(dest, entry.name);
111
+
112
+ if (ignoreList.includes(entry.name)) {
113
+ continue;
114
+ }
115
+
116
+ if (entry.isDirectory()) {
117
+ fs.mkdirSync(destPath);
118
+ copyDir(srcPath, destPath);
119
+ } else {
120
+ fs.copyFileSync(srcPath, destPath);
121
+ }
55
122
  }
56
123
  }
57
- }
58
124
 
59
- console.log('šŸ“‚ Copying template files...');
60
- copyDir(templateDir, projectDir);
125
+ console.log('\nšŸ“‚ Copying template files...');
126
+ copyDir(templateDir, projectDir);
127
+
128
+ // Update package.json
129
+ console.log('šŸ“ Updating package.json...');
130
+ const packageJsonPath = path.join(projectDir, 'package.json');
131
+ const packageJson = require(packageJsonPath);
132
+
133
+ packageJson.name = projectName;
134
+ // Add lapeh framework version to dependencies to track it like react-router
135
+ packageJson.dependencies = packageJson.dependencies || {};
136
+ packageJson.dependencies["lapeh"] = packageJson.version;
137
+
138
+ packageJson.version = '1.0.0';
139
+ packageJson.description = 'Generated by lapeh';
140
+ delete packageJson.bin; // Remove the bin entry from the generated project
141
+ delete packageJson.repository; // Remove repository info if specific to the template
142
+
143
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
144
+
145
+ // Create .env from .env.example with correct DB config
146
+ console.log('āš™ļø Configuring environment...');
147
+ const envExamplePath = path.join(projectDir, '.env.example');
148
+ const envPath = path.join(projectDir, '.env');
149
+ const prismaBaseFile = path.join(projectDir, "prisma", "base.prisma");
150
+
151
+ if (fs.existsSync(envExamplePath)) {
152
+ let envContent = fs.readFileSync(envExamplePath, 'utf8');
153
+
154
+ // Replace DATABASE_URL and DATABASE_PROVIDER
155
+ if (envContent.includes("DATABASE_URL=")) {
156
+ envContent = envContent.replace(/DATABASE_URL=".+"/g, `DATABASE_URL="${dbUrl}"`);
157
+ envContent = envContent.replace(/DATABASE_URL=.+/g, `DATABASE_URL="${dbUrl}"`);
158
+ } else {
159
+ envContent += `\nDATABASE_URL="${dbUrl}"`;
160
+ }
61
161
 
62
- // Update package.json
63
- console.log('šŸ“ Updating package.json...');
64
- const packageJsonPath = path.join(projectDir, 'package.json');
65
- const packageJson = require(packageJsonPath);
162
+ if (envContent.includes("DATABASE_PROVIDER=")) {
163
+ envContent = envContent.replace(/DATABASE_PROVIDER=".+"/g, `DATABASE_PROVIDER="${dbProvider}"`);
164
+ envContent = envContent.replace(/DATABASE_PROVIDER=.+/g, `DATABASE_PROVIDER="${dbProvider}"`);
165
+ } else {
166
+ envContent += `\nDATABASE_PROVIDER="${dbProvider}"`;
167
+ }
66
168
 
67
- packageJson.name = projectName;
68
- packageJson.version = '1.0.0';
69
- packageJson.description = 'Generated by lapeh';
70
- delete packageJson.bin; // Remove the bin entry from the generated project
71
- delete packageJson.repository; // Remove repository info if specific to the template
169
+ fs.writeFileSync(envPath, envContent);
170
+ }
72
171
 
73
- fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
172
+ // Update prisma/base.prisma
173
+ console.log("šŸ“„ Updating prisma/base.prisma...");
174
+ if (fs.existsSync(prismaBaseFile)) {
175
+ let baseContent = fs.readFileSync(prismaBaseFile, "utf8");
176
+ // Replace provider
177
+ baseContent = baseContent.replace(/provider\s*=\s*".*"/, `provider = "${dbProvider}"`);
178
+ fs.writeFileSync(prismaBaseFile, baseContent);
179
+ }
74
180
 
75
- // Create .env from .env.example
76
- console.log('āš™ļø Configuring environment...');
77
- const envExamplePath = path.join(projectDir, '.env.example');
78
- const envPath = path.join(projectDir, '.env');
181
+ // Install dependencies
182
+ console.log('šŸ“¦ Installing dependencies (this might take a while)...');
183
+ try {
184
+ execSync('npm install', { cwd: projectDir, stdio: 'inherit' });
185
+ } catch (error) {
186
+ console.error('āŒ Error installing dependencies.');
187
+ process.exit(1);
188
+ }
79
189
 
80
- if (fs.existsSync(envExamplePath)) {
81
- fs.copyFileSync(envExamplePath, envPath);
82
- }
190
+ // Generate JWT Secret
191
+ console.log('šŸ”‘ Generating JWT Secret...');
192
+ try {
193
+ execSync('npm run generate:jwt', { cwd: projectDir, stdio: 'inherit' });
194
+ } catch (error) {
195
+ console.warn('āš ļø Could not generate JWT secret automatically.');
196
+ }
83
197
 
84
- // Install dependencies
85
- console.log('šŸ“¦ Installing dependencies (this might take a while)...');
86
- try {
87
- execSync('npm install', { cwd: projectDir, stdio: 'inherit' });
88
- } catch (error) {
89
- console.error('āŒ Error installing dependencies.');
90
- process.exit(1);
91
- }
198
+ // Generate Prisma Client & Migrate
199
+ console.log('šŸ—„ļø Setting up database...');
200
+ try {
201
+ console.log(' Compiling schema...');
202
+ execSync('node scripts/compile-schema.js', { cwd: projectDir, stdio: 'inherit' });
203
+
204
+ console.log(' Generating Prisma Client...');
205
+ execSync('npx prisma generate', { cwd: projectDir, stdio: 'inherit' });
206
+
207
+ // Try to migrate (this will create the DB if it doesn't exist)
208
+ console.log(' Running migration (creates DB if missing)...');
209
+ execSync('npx prisma migrate dev --name init_setup', { cwd: projectDir, stdio: 'inherit' });
210
+
211
+ // Seed
212
+ if (isFull) {
213
+ console.log(' Seeding database...');
214
+ execSync('npm run db:seed', { cwd: projectDir, stdio: 'inherit' });
215
+ } else {
216
+ console.log(' ā„¹ļø Skipping database seeding (use --full to seed default data)...');
217
+ }
92
218
 
93
- // Generate JWT Secret
94
- console.log('šŸ”‘ Generating JWT Secret...');
95
- try {
96
- execSync('npm run generate:jwt', { cwd: projectDir, stdio: 'inherit' });
97
- } catch (error) {
98
- console.warn('āš ļø Could not generate JWT secret automatically. Please run "npm run generate:jwt" manually.');
99
- }
219
+ } catch (error) {
220
+ console.warn('āš ļø Database setup encountered an issue.');
221
+ console.warn(' You may need to check your .env credentials and run:');
222
+ console.warn(' cd ' + projectName);
223
+ console.warn(' npm run prisma:migrate');
224
+ }
100
225
 
101
- console.log('\nāœ… Project created successfully!');
102
- console.log(`\nNext steps:\n`);
103
- console.log(` cd ${projectName}`);
104
- console.log(` npm run dev`);
105
- console.log('\nHappy coding! šŸš€\n');
226
+ console.log(`\nāœ… Project ${projectName} created successfully!`);
227
+ console.log(`\nNext steps:`);
228
+ console.log(` cd ${projectName}`);
229
+ console.log(` npm run dev`);
230
+ })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lapeh",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Framework API Express yang siap pakai (Standardized)",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -38,36 +38,36 @@
38
38
  "license": "MIT",
39
39
  "type": "commonjs",
40
40
  "dependencies": {
41
- "@prisma/adapter-mariadb": "^7.2.0",
42
- "@prisma/adapter-pg": "^7.2.0",
43
- "@prisma/client": "^7.2.0",
44
- "bcryptjs": "^3.0.3",
45
- "cors": "^2.8.5",
46
- "dotenv": "^17.2.3",
47
- "express": "^5.2.1",
48
- "express-rate-limit": "^8.2.1",
49
- "helmet": "^8.1.0",
50
- "ioredis": "^5.8.2",
51
- "jsonwebtoken": "^9.0.3",
52
- "multer": "^2.0.2",
53
- "pg": "^8.16.3",
54
- "slugify": "^1.6.6",
55
- "socket.io": "^4.8.3",
56
- "uuid": "^13.0.0",
57
- "zod": "^3.23.8"
41
+ "@prisma/adapter-mariadb": "7.2.0",
42
+ "@prisma/adapter-pg": "7.2.0",
43
+ "@prisma/client": "7.2.0",
44
+ "bcryptjs": "3.0.3",
45
+ "cors": "2.8.5",
46
+ "dotenv": "17.2.3",
47
+ "express": "5.2.1",
48
+ "express-rate-limit": "8.2.1",
49
+ "helmet": "8.1.0",
50
+ "ioredis": "5.8.2",
51
+ "jsonwebtoken": "9.0.3",
52
+ "multer": "2.0.2",
53
+ "pg": "8.16.3",
54
+ "slugify": "1.6.6",
55
+ "socket.io": "4.8.3",
56
+ "uuid": "13.0.0",
57
+ "zod": "3.23.8"
58
58
  },
59
59
  "devDependencies": {
60
- "@types/bcryptjs": "^2.4.6",
61
- "@types/cors": "^2.8.19",
62
- "@types/express": "^5.0.6",
63
- "@types/jsonwebtoken": "^9.0.10",
64
- "@types/node": "^25.0.3",
65
- "@types/pg": "^8.16.0",
66
- "@types/uuid": "^10.0.0",
67
- "nodemon": "^3.1.11",
68
- "prisma": "^7.2.0",
69
- "ts-node": "^10.9.2",
70
- "ts-node-dev": "^2.0.0",
71
- "typescript": "^5.9.3"
60
+ "@types/bcryptjs": "2.4.6",
61
+ "@types/cors": "2.8.19",
62
+ "@types/express": "5.0.6",
63
+ "@types/jsonwebtoken": "9.0.10",
64
+ "@types/node": "25.0.3",
65
+ "@types/pg": "8.16.0",
66
+ "@types/uuid": "10.0.0",
67
+ "nodemon": "3.1.11",
68
+ "prisma": "7.2.0",
69
+ "ts-node": "10.9.2",
70
+ "ts-node-dev": "2.0.0",
71
+ "typescript": "5.9.3"
72
72
  }
73
73
  }
@@ -1,5 +1,5 @@
1
1
  generator client {
2
- provider = "prisma-client"
2
+ provider = "postgresql"
3
3
  output = "../generated/prisma"
4
4
  }
5
5
 
@@ -1,11 +1,13 @@
1
1
  generator client {
2
- provider = "prisma-client"
2
+ provider = "postgresql"
3
3
  output = "../generated/prisma"
4
4
  }
5
5
 
6
6
  datasource db {
7
7
  provider = "postgresql"
8
8
  }
9
+
10
+
9
11
 
10
12
  model cache {
11
13
  key String @id @db.VarChar(255)
package/readme.md CHANGED
@@ -20,12 +20,20 @@ Buat project baru cukup dengan satu perintah:
20
20
  npx lapeh nama-project-anda
21
21
  ```
22
22
 
23
+ Atau gunakan flag `--full` untuk setup lengkap (termasuk seeding data default user & roles):
24
+
25
+ ```bash
26
+ npx lapeh nama-project-anda --full
27
+ ```
28
+
23
29
  ### Apa yang terjadi otomatis?
24
30
 
25
31
  1. Struktur project dibuat.
26
32
  2. Dependencies diinstall.
27
- 3. Environment variable (`.env`) disiapkan.
28
- 4. **JWT Secret** di-generate otomatis.
33
+ 3. Database dipilih & dikonfigurasi secara interaktif.
34
+ 4. **Database** dibuat dan dimigrasi otomatis.
35
+ 5. **JWT Secret** di-generate otomatis.
36
+ 6. **Seeding Data** (jika menggunakan `--full`).
29
37
 
30
38
  Masuk ke folder project dan jalankan:
31
39
 
@@ -10,7 +10,9 @@ const REPO_VERSION_URL = 'https://registry.npmjs.org/lapeh/latest';
10
10
  const TIMEOUT = 2000; // Timeout 2 detik agar tidak terlalu lama menunggu
11
11
 
12
12
  const packageJson = require('../package.json');
13
- const currentVersion = packageJson.version;
13
+ // Cek apakah ada key "lapeh" di dependencies (project user)
14
+ // Jika tidak ada, fallback ke version package.json (mungkin ini repo framework itu sendiri)
15
+ const currentVersion = packageJson.dependencies?.['lapeh'] || packageJson.version;
14
16
 
15
17
  function checkForUpdates() {
16
18
  if (!REPO_VERSION_URL) return;
@@ -1,71 +1,166 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
- const { execSync } = require("child_process");
4
-
5
- const rootDir = path.join(__dirname, "..");
6
- const envExample = path.join(rootDir, ".env.example");
7
- const envFile = path.join(rootDir, ".env");
8
-
9
- console.log("šŸš€ Starting project initialization...");
10
-
11
- try {
12
- // 1. Copy .env
13
- if (!fs.existsSync(envFile)) {
14
- console.log("šŸ“„ Copying .env.example to .env...");
15
- fs.copyFileSync(envExample, envFile);
16
- } else {
17
- console.log("āš ļø .env already exists, skipping copy.");
18
- }
19
-
20
- // 2. Install dependencies
21
- console.log("šŸ“¦ Installing dependencies...");
22
- execSync("npm install", { stdio: "inherit", cwd: rootDir });
23
-
24
- // 3. Generate JWT Secret
25
- console.log("šŸ”‘ Generating JWT Secret...");
26
- execSync("node scripts/generate-jwt-secret.js", {
27
- stdio: "inherit",
28
- cwd: rootDir,
29
- });
30
-
31
- // 4. Setup Database (Migrate)
32
- console.log("šŸ—„ļø Setting up database...");
33
- // We skip the interactive prompt by providing a name if needed,
34
- // or just let it run. However, if it prompts, the script might hang or fail if not interactive.
35
- // 'prisma migrate dev' asks for name if there are changes.
36
- // We try to run it. If it fails, we inform the user.
37
- // We use npx to ensure we use the local binary.
38
- try {
39
- // We use the script defined in package.json but add --name init to avoid prompt for new migration
40
- // However, if migrations already exist, --name might create a new one.
41
- // If it's a fresh clone, 'prisma migrate dev' checks existing migrations.
42
- // Let's just run the compile-schema first, then migrate.
43
- execSync('node scripts/compile-schema.js', { stdio: 'inherit', cwd: rootDir });
44
-
45
- // Explicitly generate Prisma Client before migration to ensure it exists
46
- console.log('āš™ļø Generating Prisma Client...');
47
- execSync('npx prisma generate', { stdio: 'inherit', cwd: rootDir });
48
-
49
- execSync('npx prisma migrate dev --name init_setup', { stdio: 'inherit', cwd: rootDir });
50
- } catch (error) {
51
- console.warn(
52
- 'āš ļø Database migration had an issue. Please check your database connection in .env and run "npm run prisma:migrate" manually.'
53
- );
54
- }
55
-
56
- // 5. Seed Database
57
- console.log("🌱 Seeding database...");
58
- try {
59
- execSync("npm run db:seed", { stdio: "inherit", cwd: rootDir });
60
- } catch (error) {
61
- console.warn(
62
- 'āš ļø Database seeding had an issue. You might need to run "npm run db:seed" manually.'
63
- );
64
- }
65
-
66
- console.log("\nāœ… Setup complete! You can now run:");
67
- console.log(" npm run dev");
68
- } catch (error) {
69
- console.error("āŒ Setup failed:", error.message);
70
- process.exit(1);
71
- }
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const { execSync } = require("child_process");
4
+ const readline = require("readline");
5
+
6
+ const rootDir = path.join(__dirname, "..");
7
+ const envExample = path.join(rootDir, ".env.example");
8
+ const envFile = path.join(rootDir, ".env");
9
+ const prismaBaseFile = path.join(rootDir, "prisma", "base.prisma");
10
+
11
+ const rl = readline.createInterface({
12
+ input: process.stdin,
13
+ output: process.stdout,
14
+ });
15
+
16
+ const ask = (query, defaultVal) => {
17
+ return new Promise((resolve) => {
18
+ rl.question(`${query} ${defaultVal ? `[${defaultVal}]` : ""}: `, (answer) => {
19
+ resolve(answer.trim() || defaultVal);
20
+ });
21
+ });
22
+ };
23
+
24
+ const selectOption = async (query, options) => {
25
+ console.log(query);
26
+ options.forEach((opt, idx) => {
27
+ console.log(` [${opt.key}] ${opt.label}`);
28
+ });
29
+
30
+ while (true) {
31
+ const answer = await ask(">", options[0].key); // Default to first option
32
+ const selected = options.find(o => o.key.toLowerCase() === answer.toLowerCase());
33
+ if (selected) return selected;
34
+
35
+ // Check if user entered the full name or label
36
+ const byLabel = options.find(o => o.label.toLowerCase().includes(answer.toLowerCase()));
37
+ if (byLabel) return byLabel;
38
+
39
+ console.log("Pilihan tidak valid. Silakan coba lagi.");
40
+ }
41
+ };
42
+
43
+ (async () => {
44
+ console.log("šŸš€ Starting project initialization...");
45
+
46
+ try {
47
+ // --- DATABASE SELECTION ---
48
+ console.log("\n--- Database Configuration ---");
49
+ const dbType = await selectOption("Database apa yang akan digunakan?", [
50
+ { key: "pgsql", label: "PostgreSQL", provider: "postgresql", defaultPort: "5432" },
51
+ { key: "mysql", label: "MySQL", provider: "mysql", defaultPort: "3306" },
52
+ { key: "mariadb", label: "MariaDB", provider: "mysql", defaultPort: "3306" },
53
+ { key: "sqlite", label: "SQLite", provider: "sqlite", defaultPort: "" },
54
+ ]);
55
+
56
+ let dbUrl = "";
57
+ let dbProvider = dbType.provider;
58
+
59
+ if (dbType.key === "sqlite") {
60
+ dbUrl = "file:./dev.db";
61
+ } else {
62
+ const host = await ask("Database Host", "localhost");
63
+ const port = await ask("Database Port", dbType.defaultPort);
64
+ const user = await ask("Database User", "root");
65
+ const password = await ask("Database Password", "");
66
+ const dbName = await ask("Database Name", "lapeh");
67
+
68
+ if (dbType.key === "pgsql") {
69
+ dbUrl = `postgresql://${user}:${password}@${host}:${port}/${dbName}?schema=public`;
70
+ } else {
71
+ dbUrl = `mysql://${user}:${password}@${host}:${port}/${dbName}`;
72
+ }
73
+ }
74
+
75
+ // Close readline as we are done with input
76
+ rl.close();
77
+
78
+ // 1. Setup .env
79
+ console.log("\nšŸ“„ Setting up .env...");
80
+ let envContent = "";
81
+ if (fs.existsSync(envExample)) {
82
+ envContent = fs.readFileSync(envExample, "utf8");
83
+ } else {
84
+ // Fallback minimal env if example missing
85
+ envContent = `PORT=4000\nDATABASE_PROVIDER="postgresql"\nDATABASE_URL=""\nJWT_SECRET="replace_this"\n`;
86
+ }
87
+
88
+ // Replace DATABASE_URL and DATABASE_PROVIDER
89
+ // Regex to replace existing values or append if missing (simplified)
90
+ if (envContent.includes("DATABASE_URL=")) {
91
+ envContent = envContent.replace(/DATABASE_URL=".+"/g, `DATABASE_URL="${dbUrl}"`);
92
+ envContent = envContent.replace(/DATABASE_URL=.+/g, `DATABASE_URL="${dbUrl}"`); // Handle unquoted
93
+ } else {
94
+ envContent += `\nDATABASE_URL="${dbUrl}"`;
95
+ }
96
+
97
+ if (envContent.includes("DATABASE_PROVIDER=")) {
98
+ envContent = envContent.replace(/DATABASE_PROVIDER=".+"/g, `DATABASE_PROVIDER="${dbProvider}"`);
99
+ envContent = envContent.replace(/DATABASE_PROVIDER=.+/g, `DATABASE_PROVIDER="${dbProvider}"`);
100
+ } else {
101
+ envContent += `\nDATABASE_PROVIDER="${dbProvider}"`;
102
+ }
103
+
104
+ fs.writeFileSync(envFile, envContent);
105
+ console.log("āœ… .env updated with database configuration.");
106
+
107
+ // 2. Update prisma/base.prisma
108
+ console.log("šŸ“„ Updating prisma/base.prisma...");
109
+ if (fs.existsSync(prismaBaseFile)) {
110
+ let baseContent = fs.readFileSync(prismaBaseFile, "utf8");
111
+ // Replace provider
112
+ baseContent = baseContent.replace(/provider\s*=\s*".*"/, `provider = "${dbProvider}"`);
113
+ fs.writeFileSync(prismaBaseFile, baseContent);
114
+ } else {
115
+ console.warn("āš ļø prisma/base.prisma not found. Skipping.");
116
+ }
117
+
118
+ // 3. Install dependencies
119
+ console.log("\nšŸ“¦ Installing dependencies...");
120
+ execSync("npm install", { stdio: "inherit", cwd: rootDir });
121
+
122
+ // 4. Generate JWT Secret
123
+ console.log("\nšŸ”‘ Generating JWT Secret...");
124
+ try {
125
+ execSync("node scripts/generate-jwt-secret.js", {
126
+ stdio: "inherit",
127
+ cwd: rootDir,
128
+ });
129
+ } catch (e) {
130
+ console.warn("āš ļø Failed to generate JWT secret automatically.");
131
+ }
132
+
133
+ // 5. Setup Database (Migrate)
134
+ console.log("\nšŸ—„ļø Setting up database...");
135
+ try {
136
+ execSync("node scripts/compile-schema.js", { stdio: "inherit", cwd: rootDir });
137
+ console.log("āš™ļø Generating Prisma Client...");
138
+ execSync("npx prisma generate", { stdio: "inherit", cwd: rootDir });
139
+
140
+ console.log("šŸš€ Running Migration...");
141
+ execSync("npx prisma migrate dev --name init_setup", { stdio: "inherit", cwd: rootDir });
142
+ } catch (error) {
143
+ console.warn(
144
+ 'āš ļø Database migration had an issue. Please check your database connection in .env and run "npm run prisma:migrate" manually.'
145
+ );
146
+ }
147
+
148
+ // 6. Seed Database
149
+ console.log("\n🌱 Seeding database...");
150
+ try {
151
+ execSync("npm run db:seed", { stdio: "inherit", cwd: rootDir });
152
+ } catch (error) {
153
+ console.warn(
154
+ 'āš ļø Database seeding had an issue. You might need to run "npm run db:seed" manually.'
155
+ );
156
+ }
157
+
158
+ console.log("\nāœ… Setup complete! You can now run:");
159
+ console.log(" npm run dev");
160
+
161
+ } catch (error) {
162
+ console.error("\nāŒ Setup failed:", error.message);
163
+ rl.close();
164
+ process.exit(1);
165
+ }
166
+ })();