create-manifest 1.3.0 → 1.3.2
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/dist/commands/index.js +100 -32
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
package/dist/commands/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Args, Command, Flags } from '@oclif/core';
|
|
2
2
|
import axios from 'axios';
|
|
3
|
-
import { exec as execCp } from 'node:child_process';
|
|
3
|
+
import { exec as execCp, spawn } from 'node:child_process';
|
|
4
4
|
import * as fs from 'node:fs';
|
|
5
5
|
import * as crypto from 'node:crypto';
|
|
6
6
|
import * as path from 'node:path';
|
|
@@ -14,10 +14,46 @@ import { updatePackageJsonFile } from '../utils/UpdatePackageJsonFile.js';
|
|
|
14
14
|
import { updateSettingsJsonFile } from '../utils/UpdateSettingsJsonFile.js';
|
|
15
15
|
import { getLatestPackageVersion } from '../utils/GetLatestPackageVersion.js';
|
|
16
16
|
import { getBackendFileContent } from '../utils/GetBackendFileContent.js';
|
|
17
|
-
import { input
|
|
17
|
+
import { input } from '@inquirer/prompts';
|
|
18
18
|
import { slugify } from '../utils/helpers.js';
|
|
19
19
|
import chalk from 'chalk';
|
|
20
20
|
const exec = promisify(execCp);
|
|
21
|
+
/**
|
|
22
|
+
* Execute a command in a specific directory with cross-platform support
|
|
23
|
+
* @param command - The command to execute
|
|
24
|
+
* @param cwd - The working directory
|
|
25
|
+
* @returns Promise with stdout and stderr
|
|
26
|
+
*/
|
|
27
|
+
async function execInDirectory(command, cwd) {
|
|
28
|
+
return exec(command, { cwd });
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Spawn a command in a specific directory that runs in the background
|
|
32
|
+
* @param command - The command to execute
|
|
33
|
+
* @param args - The command arguments
|
|
34
|
+
* @param cwd - The working directory
|
|
35
|
+
* @returns ChildProcess
|
|
36
|
+
*/
|
|
37
|
+
function spawnInDirectory(command, args, cwd) {
|
|
38
|
+
const isWindows = process.platform === 'win32';
|
|
39
|
+
if (isWindows) {
|
|
40
|
+
// On Windows, use shell to resolve npm command
|
|
41
|
+
return spawn(command, args, {
|
|
42
|
+
cwd,
|
|
43
|
+
stdio: 'pipe',
|
|
44
|
+
detached: false,
|
|
45
|
+
shell: true
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// On Unix systems, spawn directly
|
|
50
|
+
return spawn(command, args, {
|
|
51
|
+
cwd,
|
|
52
|
+
stdio: 'pipe',
|
|
53
|
+
detached: false
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
21
57
|
export default class CreateManifest extends Command {
|
|
22
58
|
static description = 'Create a new Manifest project with the default files and folders.';
|
|
23
59
|
static args = {
|
|
@@ -58,7 +94,8 @@ export default class CreateManifest extends Command {
|
|
|
58
94
|
// * 1 Create a folder named after the first argument or ask for it.
|
|
59
95
|
const { argv } = await this.parse(CreateManifest);
|
|
60
96
|
let projectName = argv[0];
|
|
61
|
-
let isMonorepo = argv[1] === 'monorepo'
|
|
97
|
+
// let isMonorepo: boolean = argv[1] === 'monorepo'
|
|
98
|
+
const isMonorepo = false; // Hide this feature.
|
|
62
99
|
if (!projectName) {
|
|
63
100
|
projectName = await input({
|
|
64
101
|
message: 'What name would you like to use for the new workspace?',
|
|
@@ -74,24 +111,24 @@ export default class CreateManifest extends Command {
|
|
|
74
111
|
}
|
|
75
112
|
});
|
|
76
113
|
}
|
|
77
|
-
if (!isMonorepo) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
114
|
+
// if (!isMonorepo) {
|
|
115
|
+
// const projectType = await select({
|
|
116
|
+
// message: 'What type of project would you like to develop?',
|
|
117
|
+
// choices: [
|
|
118
|
+
// {
|
|
119
|
+
// name: 'A full-stack app (monorepo)',
|
|
120
|
+
// value: 'monorepo',
|
|
121
|
+
// description: 'Creates a monorepo with both "web" and "api" folders'
|
|
122
|
+
// },
|
|
123
|
+
// {
|
|
124
|
+
// name: 'A standalone backend',
|
|
125
|
+
// value: 'standalone',
|
|
126
|
+
// description: 'Creates a backend-only project'
|
|
127
|
+
// }
|
|
128
|
+
// ]
|
|
129
|
+
// })
|
|
130
|
+
// isMonorepo = projectType === 'monorepo'
|
|
131
|
+
// }
|
|
95
132
|
projectName = slugify(projectName);
|
|
96
133
|
const spinner = ora(`Creating your Manifest project in ${projectName} folder...`).start();
|
|
97
134
|
const rootFolderPath = path.join(process.cwd(), projectName);
|
|
@@ -297,7 +334,7 @@ export default class CreateManifest extends Command {
|
|
|
297
334
|
spinner.start('Installing dependencies...');
|
|
298
335
|
// Install deps.
|
|
299
336
|
try {
|
|
300
|
-
await
|
|
337
|
+
await execInDirectory(`npm install --silent`, projectName);
|
|
301
338
|
}
|
|
302
339
|
catch (error) {
|
|
303
340
|
spinner.fail(`Execution error: ${error}`);
|
|
@@ -321,19 +358,30 @@ export default class CreateManifest extends Command {
|
|
|
321
358
|
fs.writeFileSync(envFilePath, envContent);
|
|
322
359
|
spinner.succeed();
|
|
323
360
|
spinner.start('Building the database...');
|
|
324
|
-
let
|
|
361
|
+
let serverProcess = null;
|
|
325
362
|
try {
|
|
326
|
-
// We run the manifest script to build the database
|
|
327
|
-
|
|
363
|
+
// We run the manifest script to build the database in the background
|
|
364
|
+
serverProcess = spawnInDirectory('npm', ['run', 'start'], projectName);
|
|
365
|
+
// Wait for the server to be ready
|
|
328
366
|
await this.waitForServerToBeReady();
|
|
329
367
|
spinner.succeed();
|
|
330
368
|
}
|
|
331
369
|
catch (error) {
|
|
332
370
|
spinner.fail(`Execution error: ${error}`);
|
|
371
|
+
// If server failed to start, try to kill it
|
|
372
|
+
if (serverProcess && serverProcess.pid) {
|
|
373
|
+
try {
|
|
374
|
+
await this.silentKill(serverProcess.pid);
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
// Ignore errors when killing the process
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
throw error;
|
|
333
381
|
}
|
|
334
382
|
spinner.start('Seeding initial data...');
|
|
335
383
|
try {
|
|
336
|
-
await
|
|
384
|
+
await execInDirectory(`npm run seed`, projectName);
|
|
337
385
|
}
|
|
338
386
|
catch (error) {
|
|
339
387
|
spinner.fail(`Execution error: ${error}`);
|
|
@@ -347,7 +395,15 @@ export default class CreateManifest extends Command {
|
|
|
347
395
|
console.log(chalk.bold(` cd ${projectName}`));
|
|
348
396
|
console.log(chalk.bold(' npm run start'));
|
|
349
397
|
console.log();
|
|
350
|
-
|
|
398
|
+
// Kill the background server process if it exists
|
|
399
|
+
if (serverProcess && serverProcess.pid) {
|
|
400
|
+
try {
|
|
401
|
+
await this.silentKill(serverProcess.pid);
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
// Ignore errors when killing the process
|
|
405
|
+
}
|
|
406
|
+
}
|
|
351
407
|
process.exit();
|
|
352
408
|
}
|
|
353
409
|
/**
|
|
@@ -357,10 +413,16 @@ export default class CreateManifest extends Command {
|
|
|
357
413
|
*
|
|
358
414
|
**/
|
|
359
415
|
async isServerReady() {
|
|
360
|
-
|
|
361
|
-
.get('http://localhost:1111/api/health'
|
|
362
|
-
|
|
363
|
-
|
|
416
|
+
try {
|
|
417
|
+
const response = await axios.get('http://localhost:1111/api/health', {
|
|
418
|
+
timeout: 5000 // 5 second timeout
|
|
419
|
+
});
|
|
420
|
+
return response.status === 200;
|
|
421
|
+
}
|
|
422
|
+
catch {
|
|
423
|
+
// Server is not ready yet
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
364
426
|
}
|
|
365
427
|
/**
|
|
366
428
|
* Wait for the server to be ready.
|
|
@@ -370,12 +432,18 @@ export default class CreateManifest extends Command {
|
|
|
370
432
|
**/
|
|
371
433
|
async waitForServerToBeReady() {
|
|
372
434
|
let serverReady = false;
|
|
373
|
-
|
|
435
|
+
let attempts = 0;
|
|
436
|
+
const maxAttempts = 30; // 30 seconds timeout
|
|
437
|
+
while (!serverReady && attempts < maxAttempts) {
|
|
374
438
|
serverReady = await this.isServerReady();
|
|
375
439
|
if (!serverReady) {
|
|
440
|
+
attempts++;
|
|
376
441
|
await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1s before retrying
|
|
377
442
|
}
|
|
378
443
|
}
|
|
444
|
+
if (!serverReady) {
|
|
445
|
+
throw new Error('Server failed to start within 30 seconds');
|
|
446
|
+
}
|
|
379
447
|
}
|
|
380
448
|
/**
|
|
381
449
|
* Transform a JSON with comments to a JSON without comments.
|
package/oclif.manifest.json
CHANGED