create-souro-api 1.0.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/dist/index.d.ts +2 -0
- package/dist/index.js +154 -0
- package/package.json +18 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const ora_1 = __importDefault(require("ora"));
|
|
11
|
+
const execa_1 = require("execa");
|
|
12
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const REPO_URL = 'https://github.com/CoulibalySourouga/node-api-boilerplate.git';
|
|
15
|
+
const program = new commander_1.Command();
|
|
16
|
+
program
|
|
17
|
+
.name('create-souro-api')
|
|
18
|
+
.description('CLI to Generate a production-ready Node.js REST API boilerplate')
|
|
19
|
+
.argument('[project-name]', 'Name of the project')
|
|
20
|
+
.action(async (projectName) => {
|
|
21
|
+
await run(projectName);
|
|
22
|
+
});
|
|
23
|
+
program.parse();
|
|
24
|
+
async function run(projectName) {
|
|
25
|
+
console.log(chalk_1.default.bold.cyan('\n🚀 Create Souro API\n'));
|
|
26
|
+
// 1. Demander le nom du projet si non fourni
|
|
27
|
+
if (!projectName) {
|
|
28
|
+
const answer = await inquirer_1.default.prompt([
|
|
29
|
+
{
|
|
30
|
+
type: 'input',
|
|
31
|
+
name: 'projectName',
|
|
32
|
+
message: 'Project name:',
|
|
33
|
+
default: 'my-api',
|
|
34
|
+
},
|
|
35
|
+
]);
|
|
36
|
+
projectName = answer.projectName;
|
|
37
|
+
}
|
|
38
|
+
const targetDir = path_1.default.join(process.cwd(), projectName);
|
|
39
|
+
// 2. VĂ©rifier si le dossier existe dĂ©jĂ
|
|
40
|
+
if (fs_extra_1.default.existsSync(targetDir)) {
|
|
41
|
+
console.log(chalk_1.default.red(`\n❌ Folder "${projectName}" already exists.\n`));
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
// 3. Poser les questions de configuration
|
|
45
|
+
const config = await inquirer_1.default.prompt([
|
|
46
|
+
{
|
|
47
|
+
type: 'confirm',
|
|
48
|
+
name: 'includeAI',
|
|
49
|
+
message: 'Include AI integration (OpenAI/Anthropic)?',
|
|
50
|
+
default: true,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
type: 'confirm',
|
|
54
|
+
name: 'includeDocker',
|
|
55
|
+
message: 'Include Docker setup?',
|
|
56
|
+
default: true,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: 'confirm',
|
|
60
|
+
name: 'initGit',
|
|
61
|
+
message: 'Initialize a new git repository?',
|
|
62
|
+
default: true,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
type: 'confirm',
|
|
66
|
+
name: 'installDeps',
|
|
67
|
+
message: 'Install dependencies now?',
|
|
68
|
+
default: true,
|
|
69
|
+
},
|
|
70
|
+
]);
|
|
71
|
+
await scaffold(projectName, targetDir, config);
|
|
72
|
+
async function scaffold(projectName, targetDir, config) {
|
|
73
|
+
// 1. Cloner le repo
|
|
74
|
+
const spinner = (0, ora_1.default)('Cloning boilerplate...').start();
|
|
75
|
+
try {
|
|
76
|
+
await (0, execa_1.execa)('git', ['clone', '--depth=1', REPO_URL, targetDir]);
|
|
77
|
+
spinner.succeed('Boilerplate cloned');
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
spinner.fail('Failed to clone repository');
|
|
81
|
+
console.error(error);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
// 2. Supprimer le .git cloné (on repart propre)
|
|
85
|
+
await fs_extra_1.default.remove(path_1.default.join(targetDir, '.git'));
|
|
86
|
+
// 3. Supprimer Docker si non désiré
|
|
87
|
+
if (!config.includeDocker) {
|
|
88
|
+
await fs_extra_1.default.remove(path_1.default.join(targetDir, 'Dockerfile'));
|
|
89
|
+
await fs_extra_1.default.remove(path_1.default.join(targetDir, 'docker-compose.yml'));
|
|
90
|
+
}
|
|
91
|
+
// 4. Générer le fichier .env
|
|
92
|
+
await generateEnvFile(targetDir, config);
|
|
93
|
+
// 5. Initialiser git
|
|
94
|
+
if (config.initGit) {
|
|
95
|
+
const gitSpinner = (0, ora_1.default)('Initializing git repository...').start();
|
|
96
|
+
await (0, execa_1.execa)('git', ['init'], { cwd: targetDir });
|
|
97
|
+
gitSpinner.succeed('Git repository initialized');
|
|
98
|
+
}
|
|
99
|
+
// 6. Installer les dépendances
|
|
100
|
+
if (config.installDeps) {
|
|
101
|
+
const installSpinner = (0, ora_1.default)('Installing dependencies (this may take a minute)...').start();
|
|
102
|
+
try {
|
|
103
|
+
await (0, execa_1.execa)('npm', ['install'], { cwd: targetDir });
|
|
104
|
+
installSpinner.succeed('Dependencies installed');
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
installSpinner.fail('Failed to install dependencies');
|
|
108
|
+
console.log(chalk_1.default.yellow('You can install them manually with: npm install'));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// 7. Message final
|
|
112
|
+
printSuccessMessage(projectName, config);
|
|
113
|
+
}
|
|
114
|
+
async function generateEnvFile(targetDir, config) {
|
|
115
|
+
const envContent = `# Server
|
|
116
|
+
PORT=3000
|
|
117
|
+
NODE_ENV=development
|
|
118
|
+
|
|
119
|
+
# Database
|
|
120
|
+
DATABASE_URL="postgresql://admin:password@localhost:5432/${path_1.default.basename(targetDir)}"
|
|
121
|
+
POSTGRES_PASSWORD=password
|
|
122
|
+
|
|
123
|
+
# JWT
|
|
124
|
+
JWT_SECRET=change_this_secret_key
|
|
125
|
+
JWT_REFRESH_SECRET=change_this_refresh_secret
|
|
126
|
+
JWT_EXPIRES_IN=15m
|
|
127
|
+
JWT_REFRESH_EXPIRES_IN=7d
|
|
128
|
+
|
|
129
|
+
# AI Provider (mock | openai | anthropic)
|
|
130
|
+
AI_PROVIDER=${config.includeAI ? 'mock' : 'mock'}
|
|
131
|
+
OPENAI_API_KEY=your_openai_key_here
|
|
132
|
+
ANTHROPIC_API_KEY=your_anthropic_key_here
|
|
133
|
+
`;
|
|
134
|
+
await fs_extra_1.default.writeFile(path_1.default.join(targetDir, '.env'), envContent);
|
|
135
|
+
await fs_extra_1.default.writeFile(path_1.default.join(targetDir, '.env.example'), envContent);
|
|
136
|
+
}
|
|
137
|
+
function printSuccessMessage(projectName, config) {
|
|
138
|
+
console.log(chalk_1.default.bold.green('\nâś… Project created successfully!\n'));
|
|
139
|
+
console.log(chalk_1.default.bold('Next steps:\n'));
|
|
140
|
+
console.log(chalk_1.default.cyan(` cd ${projectName}`));
|
|
141
|
+
if (!config.installDeps) {
|
|
142
|
+
console.log(chalk_1.default.cyan(' npm install'));
|
|
143
|
+
}
|
|
144
|
+
if (config.includeDocker) {
|
|
145
|
+
console.log(chalk_1.default.cyan(' docker-compose up --build'));
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
console.log(chalk_1.default.cyan(' npx prisma migrate dev'));
|
|
149
|
+
console.log(chalk_1.default.cyan(' npx ts-node src/index.ts'));
|
|
150
|
+
}
|
|
151
|
+
console.log(chalk_1.default.gray('\nđź“„ Docs: http://localhost:3000/api/docs'));
|
|
152
|
+
console.log(chalk_1.default.gray('🤖 AI Provider is set to "mock" by default — update AI_PROVIDER in .env\n'));
|
|
153
|
+
}
|
|
154
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-souro-api",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI to scaffold a production-ready Node.js REST API boilerplate",
|
|
5
|
+
"bin": {
|
|
6
|
+
"create-souro-api": "./dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"dev": "ts-node src/index.ts"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"keywords": ["nodejs", "boilerplate", "cli", "typescript", "prisma", "jwt"],
|
|
17
|
+
"license": "MIT"
|
|
18
|
+
}
|