@ifecodes/backend-template 1.0.7 → 1.0.9
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/bin/cli.js +46 -11
- package/bin/lib/service-setup.js +35 -2
- package/package.json +1 -1
- package/template/base/gitignore +31 -0
- package/template/base/src/config/env.ts +1 -0
- package/template/base/src/server.ts +12 -4
- package/template/features/auth/base/inject.js +2 -1
- package/template/features/auth/bcrypt/inject.js +2 -0
- package/template/features/cors/inject.js +3 -2
- package/template/features/morgan/inject.js +2 -1
package/bin/cli.js
CHANGED
|
@@ -123,21 +123,30 @@ if (isInMicroserviceProject || config.projectType === "microservice") {
|
|
|
123
123
|
.filter((f) => fs.statSync(path.join(servicesDir, f)).isDirectory())
|
|
124
124
|
: servicesToCreate;
|
|
125
125
|
|
|
126
|
+
// Track if all installs succeeded for Husky setup
|
|
127
|
+
let allInstallsSucceeded = true;
|
|
128
|
+
|
|
126
129
|
// Now setup each service with knowledge of all services
|
|
127
130
|
for (const serviceName of servicesToCreate) {
|
|
128
131
|
const serviceRoot = path.join(target, "services", serviceName);
|
|
129
132
|
const shouldIncludeAuth = isInMicroserviceProject
|
|
130
133
|
? config.auth
|
|
131
134
|
: serviceName === "auth-service";
|
|
132
|
-
await setupService(
|
|
135
|
+
const result = await setupService(
|
|
133
136
|
config,
|
|
134
137
|
serviceName,
|
|
135
138
|
serviceRoot,
|
|
136
139
|
shouldIncludeAuth,
|
|
137
140
|
allServices
|
|
138
141
|
);
|
|
142
|
+
if (!result.installSucceeded) {
|
|
143
|
+
allInstallsSucceeded = false;
|
|
144
|
+
}
|
|
139
145
|
}
|
|
140
146
|
|
|
147
|
+
// Store for later use
|
|
148
|
+
config.allInstallsSucceeded = allInstallsSucceeded;
|
|
149
|
+
|
|
141
150
|
if (mode === "docker") {
|
|
142
151
|
generateDockerCompose(target, allServices);
|
|
143
152
|
copyDockerfile(target, servicesToCreate);
|
|
@@ -165,7 +174,8 @@ if (isInMicroserviceProject || config.projectType === "microservice") {
|
|
|
165
174
|
);
|
|
166
175
|
}
|
|
167
176
|
} else {
|
|
168
|
-
await setupService(config, null, target, true);
|
|
177
|
+
const result = await setupService(config, null, target, true);
|
|
178
|
+
config.installSucceeded = result.installSucceeded;
|
|
169
179
|
}
|
|
170
180
|
|
|
171
181
|
// Generate README.md
|
|
@@ -174,6 +184,28 @@ if (!isInMicroserviceProject) {
|
|
|
174
184
|
const readmeContent = generateReadme(config);
|
|
175
185
|
fs.writeFileSync(path.join(target, "README.md"), readmeContent);
|
|
176
186
|
|
|
187
|
+
// Rename gitignore to .gitignore (npm doesn't publish .gitignore files)
|
|
188
|
+
if (config.projectType === "microservice") {
|
|
189
|
+
const servicesDir = path.join(target, "services");
|
|
190
|
+
const allServices = fs.readdirSync(servicesDir).filter((f) =>
|
|
191
|
+
fs.statSync(path.join(servicesDir, f)).isDirectory()
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
for (const service of allServices) {
|
|
195
|
+
const gitignorePath = path.join(servicesDir, service, "gitignore");
|
|
196
|
+
const dotGitignorePath = path.join(servicesDir, service, ".gitignore");
|
|
197
|
+
if (fs.existsSync(gitignorePath)) {
|
|
198
|
+
fs.renameSync(gitignorePath, dotGitignorePath);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
} else {
|
|
202
|
+
const gitignorePath = path.join(target, "gitignore");
|
|
203
|
+
const dotGitignorePath = path.join(target, ".gitignore");
|
|
204
|
+
if (fs.existsSync(gitignorePath)) {
|
|
205
|
+
fs.renameSync(gitignorePath, dotGitignorePath);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
177
209
|
// Generate .env from .env.example for each service or root
|
|
178
210
|
console.log("📄 Setting up environment files...\n");
|
|
179
211
|
if (config.projectType === "microservice") {
|
|
@@ -205,17 +237,20 @@ if (!isInMicroserviceProject) {
|
|
|
205
237
|
// Install husky and setup at root level
|
|
206
238
|
if (config.projectType === "microservice") {
|
|
207
239
|
console.log("\n📦 Installing Husky at root level...\n");
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
240
|
+
if (config.allInstallsSucceeded) {
|
|
241
|
+
try {
|
|
242
|
+
execSync("npm install", { cwd: target, stdio: "inherit" });
|
|
243
|
+
console.log("\n🔧 Setting up Husky...\n");
|
|
244
|
+
execSync("npm run prepare", { cwd: target, stdio: "inherit" });
|
|
245
|
+
} catch (error) {
|
|
246
|
+
console.log("\n⚠️ Husky setup failed\n");
|
|
247
|
+
}
|
|
248
|
+
} else {
|
|
249
|
+
console.log("\n⚠️ Husky setup skipped (run 'npm install && npm run prepare' after fixing service dependencies)\n");
|
|
214
250
|
}
|
|
215
251
|
} else if (config.projectType === "monolith") {
|
|
216
|
-
// Only setup Husky if
|
|
217
|
-
|
|
218
|
-
if (fs.existsSync(nodeModulesPath)) {
|
|
252
|
+
// Only setup Husky if installation succeeded
|
|
253
|
+
if (config.installSucceeded) {
|
|
219
254
|
console.log("\n🔧 Setting up Husky...\n");
|
|
220
255
|
try {
|
|
221
256
|
execSync("npm run prepare", { cwd: target, stdio: "inherit" });
|
package/bin/lib/service-setup.js
CHANGED
|
@@ -14,6 +14,7 @@ export const setupService = async (
|
|
|
14
14
|
let imports = [];
|
|
15
15
|
let middlewares = [];
|
|
16
16
|
let deps = [];
|
|
17
|
+
let devDeps = [];
|
|
17
18
|
let v1Imports = [];
|
|
18
19
|
let v1Routes = [];
|
|
19
20
|
|
|
@@ -61,6 +62,9 @@ export const setupService = async (
|
|
|
61
62
|
imports.push(feature.imports);
|
|
62
63
|
middlewares.push(feature.middleware);
|
|
63
64
|
deps.push(...feature.deps);
|
|
65
|
+
if (feature.devDeps) {
|
|
66
|
+
devDeps.push(...feature.devDeps);
|
|
67
|
+
}
|
|
64
68
|
}
|
|
65
69
|
}
|
|
66
70
|
|
|
@@ -70,6 +74,9 @@ export const setupService = async (
|
|
|
70
74
|
"../../template/features/auth/base/inject.js"
|
|
71
75
|
);
|
|
72
76
|
deps.push(...baseAuth.deps);
|
|
77
|
+
if (baseAuth.devDeps) {
|
|
78
|
+
devDeps.push(...baseAuth.devDeps);
|
|
79
|
+
}
|
|
73
80
|
|
|
74
81
|
for (const file in baseAuth.files) {
|
|
75
82
|
const fullPath = path.join(serviceRoot, file);
|
|
@@ -103,6 +110,9 @@ export const setupService = async (
|
|
|
103
110
|
`../../template/features/auth/${algo.hasher}/inject.js`
|
|
104
111
|
);
|
|
105
112
|
deps.push(...hashFeature.deps);
|
|
113
|
+
if (hashFeature.devDeps) {
|
|
114
|
+
devDeps.push(...hashFeature.devDeps);
|
|
115
|
+
}
|
|
106
116
|
|
|
107
117
|
for (const file in hashFeature.files) {
|
|
108
118
|
const fullPath = path.join(serviceRoot, file);
|
|
@@ -197,8 +207,13 @@ export const setupService = async (
|
|
|
197
207
|
"/*__MONGO_URI__*/",
|
|
198
208
|
'MONGO_URI: process.env.MONGO_URI!,'
|
|
199
209
|
);
|
|
210
|
+
envContent = envContent.replace(
|
|
211
|
+
"/*__JWT_SECRET__*/",
|
|
212
|
+
'JWT_SECRET: process.env.JWT_SECRET!,'
|
|
213
|
+
);
|
|
200
214
|
} else {
|
|
201
215
|
envContent = envContent.replace("/*__MONGO_URI__*/", "");
|
|
216
|
+
envContent = envContent.replace("/*__JWT_SECRET__*/", "");
|
|
202
217
|
}
|
|
203
218
|
|
|
204
219
|
fs.writeFileSync(envPath, envContent);
|
|
@@ -297,6 +312,8 @@ await connectDB();`
|
|
|
297
312
|
`\n📦 Installing dependencies for ${serviceName || "project"}...\n`
|
|
298
313
|
);
|
|
299
314
|
|
|
315
|
+
let installSucceeded = false;
|
|
316
|
+
|
|
300
317
|
try {
|
|
301
318
|
if (deps.length) {
|
|
302
319
|
execSync(`npm install ${deps.join(" ")}`, {
|
|
@@ -304,18 +321,34 @@ await connectDB();`
|
|
|
304
321
|
stdio: "inherit",
|
|
305
322
|
});
|
|
306
323
|
}
|
|
324
|
+
if (devDeps.length) {
|
|
325
|
+
execSync(`npm install -D ${devDeps.join(" ")}`, {
|
|
326
|
+
cwd: serviceRoot,
|
|
327
|
+
stdio: "inherit",
|
|
328
|
+
});
|
|
329
|
+
}
|
|
307
330
|
execSync("npm install", { cwd: serviceRoot, stdio: "inherit" });
|
|
331
|
+
installSucceeded = true;
|
|
332
|
+
|
|
333
|
+
// Run format after successful install
|
|
334
|
+
console.log("\n🎨 Formatting code...\n");
|
|
335
|
+
try {
|
|
336
|
+
execSync("npm run format", { cwd: serviceRoot, stdio: "inherit" });
|
|
337
|
+
} catch (formatError) {
|
|
338
|
+
console.warn("⚠️ Warning: Code formatting failed. You can run it manually later with: npm run format\n");
|
|
339
|
+
}
|
|
308
340
|
} catch (error) {
|
|
309
341
|
console.error("\n⚠️ Warning: Some dependencies failed to install.");
|
|
310
342
|
console.error("This is usually due to native modules (like argon2) requiring build tools.\n");
|
|
311
343
|
console.error("💡 Solutions:");
|
|
312
344
|
console.error(" 1. Install build tools: npm install --global windows-build-tools");
|
|
313
345
|
console.error(" 2. Or switch to bcrypt (works better on Windows)");
|
|
314
|
-
console.error(" 3. Or manually install later: cd " + (serviceName || res.sanitizedName) + " && npm install
|
|
346
|
+
console.error(" 3. Or manually install later: cd " + (serviceName || res.sanitizedName) + " && npm install");
|
|
347
|
+
console.error(" 4. Then run: npm run format\n");
|
|
315
348
|
|
|
316
349
|
// Don't exit - let the project be created anyway
|
|
317
350
|
console.log("⏭️ Continuing with project creation...\n");
|
|
318
351
|
}
|
|
319
352
|
|
|
320
|
-
return deps;
|
|
353
|
+
return { deps, installSucceeded };
|
|
321
354
|
};
|
package/package.json
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
package-lock.json
|
|
4
|
+
|
|
5
|
+
# Build output
|
|
6
|
+
dist/
|
|
7
|
+
|
|
8
|
+
# Environment variables
|
|
9
|
+
.env
|
|
10
|
+
.env.local
|
|
11
|
+
.env.*.local
|
|
12
|
+
|
|
13
|
+
# Logs
|
|
14
|
+
logs/
|
|
15
|
+
*.log
|
|
16
|
+
npm-debug.log*
|
|
17
|
+
yarn-debug.log*
|
|
18
|
+
|
|
19
|
+
# ESLint
|
|
20
|
+
.eslintcache
|
|
21
|
+
|
|
22
|
+
# OS files
|
|
23
|
+
.DS_Store
|
|
24
|
+
Thumbs.db
|
|
25
|
+
|
|
26
|
+
# IDE
|
|
27
|
+
.vscode/
|
|
28
|
+
.idea/
|
|
29
|
+
*.swp
|
|
30
|
+
*.swo
|
|
31
|
+
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import app from "./app";
|
|
2
2
|
import { ENV } from "./config";
|
|
3
|
+
import { logger } from "@/utils";
|
|
3
4
|
/*__DB_IMPORT__*/
|
|
4
5
|
|
|
5
6
|
const PORT = ENV.PORT || 3000;
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
const startServer = async () => {
|
|
9
|
+
/*__DB_CONNECT__*/
|
|
8
10
|
|
|
9
|
-
app.listen(PORT, () => {
|
|
10
|
-
|
|
11
|
-
});
|
|
11
|
+
app.listen(PORT, () => {
|
|
12
|
+
logger.info("Server", `Server is running on port ${PORT}`);
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
startServer().catch((error) => {
|
|
17
|
+
logger.error("Server", "Failed to start server", error as Error);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
});
|
|
@@ -84,6 +84,7 @@ export const imports = `import { authRoutes } from "./auth";`;
|
|
|
84
84
|
|
|
85
85
|
export const middleware = `router.use("/auth", authRoutes);`;
|
|
86
86
|
|
|
87
|
-
export const deps = ["jsonwebtoken", "
|
|
87
|
+
export const deps = ["jsonwebtoken", "mongoose"];
|
|
88
|
+
export const devDeps = ["@types/jsonwebtoken"];
|
|
88
89
|
|
|
89
90
|
export const targetFile = "src/modules/v1/index.ts";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export const deps = ["cors"
|
|
2
|
-
export const
|
|
1
|
+
export const deps = ["cors"];
|
|
2
|
+
export const devDeps = ["@types/cors"];
|
|
3
|
+
export const imports = `import cors from "cors";\nimport { ENV } from "@/config";`;
|
|
3
4
|
export const middleware = `
|
|
4
5
|
const corsOptions = {
|
|
5
6
|
origin: ENV.ALLOWED_ORIGIN,
|