speedrun-cli 2.6.12 → 2.7.0
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/CHANGELOG.md +22 -0
- package/package.json +1 -1
- package/src/generator.js +1 -16
- package/src/moduleGenerator.js +597 -121
- package/src/postSetup.js +423 -402
- package/src/prompts.js +25 -3
- package/templates/orm/drizzle/package.json +2 -1
- package/templates/orm/mongoose/package.json +2 -1
- package/templates/orm/prisma/package.json +1 -0
- package/templates/base-crud/src/modules/products/dto/create-product.dto.ts +0 -34
- package/templates/base-crud/src/modules/products/dto/product.dto.ts +0 -36
- package/templates/base-crud/src/modules/products/dto/update-product.dto.ts +0 -4
- package/templates/base-crud/src/modules/products/products.controller.ts +0 -78
- package/templates/base-crud-drizzle/src/modules/products/dto/create-product.dto.ts +0 -34
- package/templates/base-crud-drizzle/src/modules/products/dto/product.dto.ts +0 -36
- package/templates/base-crud-drizzle/src/modules/products/dto/update-product.dto.ts +0 -4
- package/templates/base-crud-drizzle/src/modules/products/products.controller.ts +0 -78
- package/templates/base-crud-drizzle/src/modules/products/products.module.ts +0 -24
- package/templates/base-crud-drizzle/src/modules/products/products.service.ts +0 -140
- package/templates/base-crud-drizzle/src/modules/products/schema/products.schema.ts +0 -39
- package/templates/base-crud-mongoose/src/modules/products/dto/create-product.dto.ts +0 -34
- package/templates/base-crud-mongoose/src/modules/products/dto/product.dto.ts +0 -36
- package/templates/base-crud-mongoose/src/modules/products/dto/update-product.dto.ts +0 -4
- package/templates/base-crud-mongoose/src/modules/products/products.controller.ts +0 -78
- package/templates/base-crud-mongoose/src/modules/products/products.module.ts +0 -26
- package/templates/base-crud-mongoose/src/modules/products/products.service.ts +0 -133
- package/templates/base-crud-mongoose/src/modules/products/schemas/product.schema.ts +0 -67
- package/templates/base-crud-prisma/src/modules/products/dto/create-product.dto.ts +0 -34
- package/templates/base-crud-prisma/src/modules/products/dto/product.dto.ts +0 -36
- package/templates/base-crud-prisma/src/modules/products/dto/update-product.dto.ts +0 -4
- package/templates/base-crud-prisma/src/modules/products/products.controller.ts +0 -78
- package/templates/base-crud-prisma/src/modules/products/products.module.ts +0 -12
- package/templates/base-crud-prisma/src/modules/products/products.service.ts +0 -100
- package/templates/base-crud-typeorm/src/modules/products/dto/create-product.dto.ts +0 -34
- package/templates/base-crud-typeorm/src/modules/products/dto/product.dto.ts +0 -36
- package/templates/base-crud-typeorm/src/modules/products/dto/update-product.dto.ts +0 -4
- package/templates/base-crud-typeorm/src/modules/products/entities/product.entity.ts +0 -58
- package/templates/base-crud-typeorm/src/modules/products/products.controller.ts +0 -78
- package/templates/base-crud-typeorm/src/modules/products/products.module.ts +0 -25
- package/templates/base-crud-typeorm/src/modules/products/products.service.ts +0 -102
package/src/postSetup.js
CHANGED
|
@@ -1,402 +1,423 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Post-Setup Interactive Handlers
|
|
3
|
-
* @module postSetup
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const fs = require('fs-extra');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
const { execSync } = require('child_process');
|
|
9
|
-
const chalk = require('chalk');
|
|
10
|
-
const inquirer = require('inquirer');
|
|
11
|
-
const { ORM_OPTIONS, DATABASE_OPTIONS } = require('./constants');
|
|
12
|
-
const { generateJWTSecret, getRunPrefix } = require('./utils');
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*
|
|
23
|
-
* @param {string}
|
|
24
|
-
* @param {
|
|
25
|
-
* @
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
console.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
console.
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
console.
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
console.
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
name
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
console.log(chalk.
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
console.log(chalk.
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Post-Setup Interactive Handlers
|
|
3
|
+
* @module postSetup
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs-extra');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { execSync } = require('child_process');
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const inquirer = require('inquirer');
|
|
11
|
+
const { ORM_OPTIONS, DATABASE_OPTIONS } = require('./constants');
|
|
12
|
+
const { generateJWTSecret, getRunPrefix } = require('./utils');
|
|
13
|
+
|
|
14
|
+
// Lazy-loaded to avoid circular deps: moduleGenerator requires constants/utils
|
|
15
|
+
let _generateModule;
|
|
16
|
+
function getGenerateModule() {
|
|
17
|
+
if (!_generateModule) _generateModule = require('./moduleGenerator').generateModule;
|
|
18
|
+
return _generateModule;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Handles interactive post-setup configuration
|
|
23
|
+
* @param {string} targetDir - Project directory
|
|
24
|
+
* @param {string} appName - Application name
|
|
25
|
+
* @param {object} options - Configuration options
|
|
26
|
+
* @returns {Promise<boolean>} Whether interactive setup completed
|
|
27
|
+
*/
|
|
28
|
+
async function handlePostSetup(targetDir, appName, options) {
|
|
29
|
+
const { packageManager, orm, database, swagger, baseCrud, generateFirstCrud, firstModuleName, yes: isYesMode, skipInstall } = options;
|
|
30
|
+
|
|
31
|
+
if (isYesMode || skipInstall) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
printSuccessHeader(appName, orm, database, swagger, baseCrud);
|
|
36
|
+
|
|
37
|
+
const { continueSetup } = await inquirer.prompt([{
|
|
38
|
+
type: 'confirm',
|
|
39
|
+
name: 'continueSetup',
|
|
40
|
+
message: 'Would you like to complete the setup now? (JWT secrets, database, CRUD)',
|
|
41
|
+
default: true,
|
|
42
|
+
}]);
|
|
43
|
+
|
|
44
|
+
if (!continueSetup) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Step 1: Configure JWT secrets and database URL
|
|
49
|
+
await configureEnvironment(targetDir, database);
|
|
50
|
+
|
|
51
|
+
// Step 2: ORM-specific database setup (Schema/Migration → Seed)
|
|
52
|
+
await setupDatabase(targetDir, orm, packageManager);
|
|
53
|
+
|
|
54
|
+
// Step 3: CRUD module generation
|
|
55
|
+
if (generateFirstCrud !== false) {
|
|
56
|
+
await promptCrudGeneration(targetDir, orm, firstModuleName);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Step 4: Display Post-Setup Summary Log with Next Steps
|
|
60
|
+
printNextStepsSummary(orm);
|
|
61
|
+
|
|
62
|
+
// Step 5: Optionally start dev server
|
|
63
|
+
await promptDevServer(targetDir, packageManager);
|
|
64
|
+
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Prints the success header
|
|
70
|
+
*/
|
|
71
|
+
function printSuccessHeader(appName, orm, database, swagger, baseCrud) {
|
|
72
|
+
console.log(chalk.green('\n✅ Success! Created ' + chalk.bold(appName)));
|
|
73
|
+
console.log(chalk.gray(` ORM: ${ORM_OPTIONS[orm]?.name || orm}`));
|
|
74
|
+
console.log(chalk.gray(` Database: ${DATABASE_OPTIONS[database]?.name || database}`));
|
|
75
|
+
if (swagger) {
|
|
76
|
+
console.log(chalk.gray(` Swagger: ${chalk.green('Enabled')}`));
|
|
77
|
+
}
|
|
78
|
+
if (baseCrud) {
|
|
79
|
+
console.log(chalk.gray(` Base CRUD Architecture: ${chalk.green('Enabled')} — src/common/base/`));
|
|
80
|
+
}
|
|
81
|
+
console.log(chalk.white('\n🎉 Your project is ready!\n'));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Configures environment variables
|
|
86
|
+
*/
|
|
87
|
+
async function configureEnvironment(targetDir, database) {
|
|
88
|
+
console.log(chalk.yellow('\n🔑 Generating JWT secrets...\n'));
|
|
89
|
+
const accessSecret = generateJWTSecret();
|
|
90
|
+
const refreshSecret = generateJWTSecret();
|
|
91
|
+
|
|
92
|
+
console.log(chalk.gray(' Generated JWT_ACCESS_SECRET'));
|
|
93
|
+
console.log(chalk.gray(' Generated JWT_REFRESH_SECRET\n'));
|
|
94
|
+
|
|
95
|
+
const dbInfo = DATABASE_OPTIONS[database];
|
|
96
|
+
const { databaseUrl } = await inquirer.prompt([{
|
|
97
|
+
type: 'input',
|
|
98
|
+
name: 'databaseUrl',
|
|
99
|
+
message: `Enter your ${dbInfo.name} database URL:`,
|
|
100
|
+
default: dbInfo.urlTemplate,
|
|
101
|
+
validate: (input) => {
|
|
102
|
+
if (!input || input.trim() === '') {
|
|
103
|
+
return 'Database URL is required';
|
|
104
|
+
}
|
|
105
|
+
const validPrefix = dbInfo.urlPrefix.some((prefix) => input.startsWith(prefix));
|
|
106
|
+
if (!validPrefix) {
|
|
107
|
+
return `Database URL must start with ${dbInfo.urlPrefix.join(' or ')}`;
|
|
108
|
+
}
|
|
109
|
+
return true;
|
|
110
|
+
},
|
|
111
|
+
}]);
|
|
112
|
+
|
|
113
|
+
// Update .env file
|
|
114
|
+
console.log(chalk.gray('\n Updating .env file...'));
|
|
115
|
+
const envPath = path.join(targetDir, '.env');
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
let envContent = await fs.readFile(envPath, 'utf8');
|
|
119
|
+
envContent = envContent.replace(/DATABASE_URL=.*/, `DATABASE_URL="${databaseUrl}"`);
|
|
120
|
+
envContent = envContent.replace(/JWT_ACCESS_SECRET=.*/, `JWT_ACCESS_SECRET="${accessSecret}"`);
|
|
121
|
+
envContent = envContent.replace(/JWT_REFRESH_SECRET=.*/, `JWT_REFRESH_SECRET="${refreshSecret}"`);
|
|
122
|
+
await fs.writeFile(envPath, envContent);
|
|
123
|
+
console.log(chalk.green(' ✓ Environment variables configured\n'));
|
|
124
|
+
} catch {
|
|
125
|
+
console.error(chalk.red(' ✗ Failed to update .env file'));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Sets up the database based on selected ORM
|
|
131
|
+
*/
|
|
132
|
+
async function setupDatabase(targetDir, orm, packageManager) {
|
|
133
|
+
const setupHandlers = {
|
|
134
|
+
prisma: setupPrisma,
|
|
135
|
+
typeorm: setupTypeOrm,
|
|
136
|
+
mongoose: setupMongoose,
|
|
137
|
+
drizzle: setupDrizzle,
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const handler = setupHandlers[orm];
|
|
141
|
+
if (handler) {
|
|
142
|
+
await handler(targetDir, packageManager);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function setupPrisma(targetDir, packageManager) {
|
|
147
|
+
const { setupDatabase } = await inquirer.prompt([{
|
|
148
|
+
type: 'confirm',
|
|
149
|
+
name: 'setupDatabase',
|
|
150
|
+
message: 'Set up the database now? (generate Prisma client, run migrations, seed)',
|
|
151
|
+
default: true,
|
|
152
|
+
}]);
|
|
153
|
+
|
|
154
|
+
if (!setupDatabase) return;
|
|
155
|
+
|
|
156
|
+
// Prompt for migration name before running prisma commands
|
|
157
|
+
const { migrationName } = await inquirer.prompt([{
|
|
158
|
+
type: 'input',
|
|
159
|
+
name: 'migrationName',
|
|
160
|
+
message: 'Enter migration name:',
|
|
161
|
+
default: 'init',
|
|
162
|
+
validate: (input) => {
|
|
163
|
+
if (!input || input.trim() === '') {
|
|
164
|
+
return 'Migration name is required';
|
|
165
|
+
}
|
|
166
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(input)) {
|
|
167
|
+
return 'Migration name can only contain letters, numbers, underscores, and hyphens';
|
|
168
|
+
}
|
|
169
|
+
return true;
|
|
170
|
+
},
|
|
171
|
+
}]);
|
|
172
|
+
|
|
173
|
+
console.log(chalk.yellow('\n📦 Setting up database...\n'));
|
|
174
|
+
const pmPrefix = getRunPrefix(packageManager);
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
console.log(chalk.gray(' Generating Prisma client...'));
|
|
178
|
+
execSync(`${pmPrefix} prisma:generate`, { cwd: targetDir, stdio: 'inherit' });
|
|
179
|
+
|
|
180
|
+
console.log(chalk.gray('\n Running database migrations...'));
|
|
181
|
+
// Run prisma directly with --name to avoid double prompt
|
|
182
|
+
execSync(`npx prisma migrate dev --name ${migrationName}`, { cwd: targetDir, stdio: 'inherit' });
|
|
183
|
+
|
|
184
|
+
console.log(chalk.gray('\n Seeding database...'));
|
|
185
|
+
execSync(`${pmPrefix} prisma:seed`, { cwd: targetDir, stdio: 'inherit' });
|
|
186
|
+
|
|
187
|
+
printCredentials();
|
|
188
|
+
} catch {
|
|
189
|
+
console.error(chalk.red('\n ✗ Database setup failed'));
|
|
190
|
+
console.error(chalk.yellow(' Run these commands manually:'));
|
|
191
|
+
console.error(chalk.gray(` ${pmPrefix} prisma:generate`));
|
|
192
|
+
console.error(chalk.gray(` ${pmPrefix} prisma:migrate`));
|
|
193
|
+
console.error(chalk.gray(` ${pmPrefix} prisma:seed\n`));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function setupTypeOrm(targetDir, packageManager) {
|
|
198
|
+
const { setupDatabase } = await inquirer.prompt([{
|
|
199
|
+
type: 'confirm',
|
|
200
|
+
name: 'setupDatabase',
|
|
201
|
+
message: 'Set up the database now? (sync schema, seed)',
|
|
202
|
+
default: true,
|
|
203
|
+
}]);
|
|
204
|
+
|
|
205
|
+
if (!setupDatabase) return;
|
|
206
|
+
|
|
207
|
+
console.log(chalk.yellow('\n📦 Setting up database...\n'));
|
|
208
|
+
const pmPrefix = getRunPrefix(packageManager);
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
console.log(chalk.gray(' Synchronizing database schema...'));
|
|
212
|
+
execSync(`${pmPrefix} schema:sync`, { cwd: targetDir, stdio: 'inherit' });
|
|
213
|
+
|
|
214
|
+
console.log(chalk.gray('\n Seeding database...'));
|
|
215
|
+
execSync(`${pmPrefix} seed`, { cwd: targetDir, stdio: 'inherit' });
|
|
216
|
+
|
|
217
|
+
printCredentials();
|
|
218
|
+
} catch {
|
|
219
|
+
console.error(chalk.red('\n ✗ Database setup failed'));
|
|
220
|
+
console.error(chalk.yellow(' Run these commands manually:'));
|
|
221
|
+
console.error(chalk.gray(` ${pmPrefix} schema:sync`));
|
|
222
|
+
console.error(chalk.gray(` ${pmPrefix} seed\n`));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async function setupMongoose(targetDir, packageManager) {
|
|
227
|
+
const { setupDatabase } = await inquirer.prompt([{
|
|
228
|
+
type: 'confirm',
|
|
229
|
+
name: 'setupDatabase',
|
|
230
|
+
message: 'Seed the database now? (create default admin user)',
|
|
231
|
+
default: true,
|
|
232
|
+
}]);
|
|
233
|
+
|
|
234
|
+
if (!setupDatabase) return;
|
|
235
|
+
|
|
236
|
+
console.log(chalk.yellow('\n📦 Setting up database...\n'));
|
|
237
|
+
const pmPrefix = getRunPrefix(packageManager);
|
|
238
|
+
|
|
239
|
+
try {
|
|
240
|
+
console.log(chalk.gray(' Seeding database...'));
|
|
241
|
+
execSync(`${pmPrefix} db:seed`, { cwd: targetDir, stdio: 'inherit' });
|
|
242
|
+
|
|
243
|
+
printCredentials();
|
|
244
|
+
} catch {
|
|
245
|
+
console.error(chalk.red('\n ✗ Database setup failed'));
|
|
246
|
+
console.error(chalk.yellow(' Run this command manually:'));
|
|
247
|
+
console.error(chalk.gray(` ${pmPrefix} db:seed\n`));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async function setupDrizzle(targetDir, packageManager) {
|
|
252
|
+
const { setupDatabase } = await inquirer.prompt([{
|
|
253
|
+
type: 'confirm',
|
|
254
|
+
name: 'setupDatabase',
|
|
255
|
+
message: 'Set up the database now? (push schema, seed)',
|
|
256
|
+
default: true,
|
|
257
|
+
}]);
|
|
258
|
+
|
|
259
|
+
if (!setupDatabase) return;
|
|
260
|
+
|
|
261
|
+
console.log(chalk.yellow('\n📦 Setting up database...\n'));
|
|
262
|
+
const pmPrefix = getRunPrefix(packageManager);
|
|
263
|
+
|
|
264
|
+
try {
|
|
265
|
+
console.log(chalk.gray(' Pushing schema to database...'));
|
|
266
|
+
execSync(`${pmPrefix} db:push`, { cwd: targetDir, stdio: 'inherit' });
|
|
267
|
+
|
|
268
|
+
console.log(chalk.gray('\n Seeding database...'));
|
|
269
|
+
execSync(`${pmPrefix} db:seed`, { cwd: targetDir, stdio: 'inherit' });
|
|
270
|
+
|
|
271
|
+
printCredentials();
|
|
272
|
+
} catch {
|
|
273
|
+
console.error(chalk.red('\n ✗ Database setup failed'));
|
|
274
|
+
console.error(chalk.yellow(' Run these commands manually:'));
|
|
275
|
+
console.error(chalk.gray(` ${pmPrefix} db:push`));
|
|
276
|
+
console.error(chalk.gray(` ${pmPrefix} db:seed\n`));
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Prints default admin credentials
|
|
282
|
+
*/
|
|
283
|
+
function printCredentials() {
|
|
284
|
+
console.log(chalk.green('\n ✓ Database setup complete!\n'));
|
|
285
|
+
console.log(chalk.cyan(' 📝 Default admin credentials:'));
|
|
286
|
+
console.log(chalk.white(' Email: admin@example.com'));
|
|
287
|
+
console.log(chalk.white(' Password: Admin@123\n'));
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Prompts user to generate their first CRUD module
|
|
292
|
+
*/
|
|
293
|
+
async function promptCrudGeneration(targetDir, orm, providedModuleName) {
|
|
294
|
+
let moduleName = providedModuleName;
|
|
295
|
+
|
|
296
|
+
if (!moduleName) {
|
|
297
|
+
const { generateNow } = await inquirer.prompt([{
|
|
298
|
+
type: 'confirm',
|
|
299
|
+
name: 'generateNow',
|
|
300
|
+
message: 'Do you want to generate your first CRUD module now?',
|
|
301
|
+
default: true,
|
|
302
|
+
}]);
|
|
303
|
+
|
|
304
|
+
if (!generateNow) {
|
|
305
|
+
console.log(chalk.gray('\n Skipping CRUD generation. Run `speedrun-cli generate <name>` anytime.\n'));
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
try {
|
|
311
|
+
await getGenerateModule()(moduleName, targetDir, orm);
|
|
312
|
+
} catch (err) {
|
|
313
|
+
console.warn(chalk.yellow(`\n ⚠️ CRUD generation failed: ${err.message}`));
|
|
314
|
+
console.warn(chalk.gray(' Run `speedrun-cli generate <name>` manually inside your project.\n'));
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Display post-install summary with instructions to run database migrations and seeds dynamically based on selected ORM
|
|
320
|
+
*/
|
|
321
|
+
function printNextStepsSummary(orm) {
|
|
322
|
+
console.log(chalk.cyan.bold('\n💡 Next Steps:\n'));
|
|
323
|
+
|
|
324
|
+
if (orm === 'prisma') {
|
|
325
|
+
console.log(chalk.white('1. Run Database Migration: ') + chalk.yellow('npx prisma db push'));
|
|
326
|
+
console.log(chalk.white('2. Run Database Seed: ') + chalk.yellow('npm run seed\n'));
|
|
327
|
+
} else if (orm === 'typeorm') {
|
|
328
|
+
console.log(chalk.white('1. Synchronize Database Schema: ') + chalk.yellow('npm run schema:sync'));
|
|
329
|
+
console.log(chalk.white('2. Run Database Seed: ') + chalk.yellow('npm run seed\n'));
|
|
330
|
+
} else if (orm === 'mongoose') {
|
|
331
|
+
console.log(chalk.white('1. Run Database Seed: ') + chalk.yellow('npm run db:seed\n'));
|
|
332
|
+
} else if (orm === 'drizzle') {
|
|
333
|
+
console.log(chalk.white('1. Push Schema to Database: ') + chalk.yellow('npm run db:push'));
|
|
334
|
+
console.log(chalk.white('2. Run Database Seed: ') + chalk.yellow('npm run db:seed\n'));
|
|
335
|
+
} else {
|
|
336
|
+
console.log(chalk.white('1. Run Database Migration & Seed commands for your ORM\n'));
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Prompts user to start dev server
|
|
342
|
+
*/
|
|
343
|
+
async function promptDevServer(targetDir, packageManager) {
|
|
344
|
+
const { startServer } = await inquirer.prompt([{
|
|
345
|
+
type: 'confirm',
|
|
346
|
+
name: 'startServer',
|
|
347
|
+
message: 'Start the development server now?',
|
|
348
|
+
default: false,
|
|
349
|
+
}]);
|
|
350
|
+
|
|
351
|
+
if (!startServer) return;
|
|
352
|
+
|
|
353
|
+
console.log(chalk.yellow('\n🚀 Starting development server...\n'));
|
|
354
|
+
console.log(chalk.gray(` Your API will be available at: ${chalk.cyan('http://localhost:8080/api/v1')}`));
|
|
355
|
+
console.log(chalk.gray(` Press ${chalk.bold('Ctrl+C')} to stop the server\n`));
|
|
356
|
+
|
|
357
|
+
const pmPrefix = getRunPrefix(packageManager);
|
|
358
|
+
|
|
359
|
+
try {
|
|
360
|
+
execSync(`${pmPrefix} start:dev`, { cwd: targetDir, stdio: 'inherit' });
|
|
361
|
+
} catch {
|
|
362
|
+
console.log(chalk.yellow('\n Server stopped.'));
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Prints manual setup instructions when interactive setup is skipped
|
|
368
|
+
*/
|
|
369
|
+
function printManualInstructions(appName, options) {
|
|
370
|
+
const { orm, database, packageManager, installDependencies, swagger, baseCrud } = options;
|
|
371
|
+
|
|
372
|
+
console.log(chalk.green('\n✅ Success! Created ' + chalk.bold(appName)));
|
|
373
|
+
console.log(chalk.gray(` ORM: ${ORM_OPTIONS[orm]?.name || orm}`));
|
|
374
|
+
console.log(chalk.gray(` Database: ${DATABASE_OPTIONS[database]?.name || database}`));
|
|
375
|
+
if (swagger) {
|
|
376
|
+
console.log(chalk.gray(` Swagger: ${chalk.green('Enabled')}`));
|
|
377
|
+
}
|
|
378
|
+
if (baseCrud) {
|
|
379
|
+
console.log(chalk.gray(` Base CRUD Architecture: ${chalk.green('Enabled')} — see CRUD_README.md`));
|
|
380
|
+
}
|
|
381
|
+
console.log(chalk.white('\n📚 Next steps:\n'));
|
|
382
|
+
console.log(chalk.cyan(` cd ${appName}`));
|
|
383
|
+
|
|
384
|
+
if (!installDependencies) {
|
|
385
|
+
const installCmd = require('./utils').getInstallCommand(packageManager);
|
|
386
|
+
console.log(chalk.cyan(` ${installCmd}`));
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
console.log(chalk.cyan('\n # Generate secure JWT secrets (save these!):'));
|
|
390
|
+
console.log(chalk.gray(' openssl rand -base64 32 # For JWT_ACCESS_SECRET'));
|
|
391
|
+
console.log(chalk.gray(' openssl rand -base64 32 # For JWT_REFRESH_SECRET'));
|
|
392
|
+
console.log(chalk.cyan('\n # Edit .env with your database URL and JWT secrets'));
|
|
393
|
+
|
|
394
|
+
printNextStepsSummary(orm);
|
|
395
|
+
|
|
396
|
+
console.log(chalk.cyan(' # Generate your first CRUD module:'));
|
|
397
|
+
console.log(chalk.gray(' speedrun-cli generate <module-name>'));
|
|
398
|
+
console.log(chalk.gray(' # e.g. speedrun-cli generate orders'));
|
|
399
|
+
|
|
400
|
+
console.log(chalk.cyan('\n # Start development server:'));
|
|
401
|
+
console.log(chalk.gray(' npm run start:dev'));
|
|
402
|
+
|
|
403
|
+
if (swagger) {
|
|
404
|
+
console.log(chalk.cyan('\n # Swagger API documentation:'));
|
|
405
|
+
console.log(chalk.gray(' http://localhost:8080/api/docs'));
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (baseCrud) {
|
|
409
|
+
console.log(chalk.cyan('\n # Base CRUD Architecture:'));
|
|
410
|
+
console.log(chalk.gray(' src/common/base/ — BaseService & BaseController'));
|
|
411
|
+
console.log(chalk.gray(' CRUD_README.md — Full guide & cheatsheet'));
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
console.log(chalk.white('\n📖 Documentation: https://github.com/masabinhok/create-nestjs-auth'));
|
|
415
|
+
console.log(chalk.white('🐛 Issues: https://github.com/masabinhok/create-nestjs-auth/issues\n'));
|
|
416
|
+
console.log(chalk.magenta('Happy coding! 🎉\n'));
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
module.exports = {
|
|
420
|
+
handlePostSetup,
|
|
421
|
+
printManualInstructions,
|
|
422
|
+
printNextStepsSummary,
|
|
423
|
+
};
|