neatnode 3.0.3 → 3.1.4
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/package.json +3 -1
- package/src/actions/createProject.js +14 -11
- package/src/cli.js +45 -30
- package/src/config/templates.js +12 -19
- package/src/utils/downloadRepoTemplate.js +45 -0
- package/templates/express-basic/.env.example +0 -3
- package/templates/express-basic/package-lock.json +0 -1505
- package/templates/express-basic/package.json +0 -21
- package/templates/express-basic/server.js +0 -11
- package/templates/express-basic/src/app.js +0 -45
- package/templates/express-basic/src/config/db.config.js +0 -12
- package/templates/express-basic/src/config/env.config.js +0 -11
- package/templates/express-basic/src/controllers/todo.controller.js +0 -90
- package/templates/express-basic/src/middleware/notFound.middleware.js +0 -5
- package/templates/express-basic/src/models/todo.model.js +0 -21
- package/templates/express-basic/src/routes/index.route.js +0 -10
- package/templates/express-basic/src/routes/todo.route.js +0 -15
- package/templates/express-basic/src/utils/responseHandler.js +0 -7
- package/templates/express-rest-api/.env.example +0 -7
- package/templates/express-rest-api/package-lock.json +0 -1977
- package/templates/express-rest-api/package.json +0 -30
- package/templates/express-rest-api/server.js +0 -14
- package/templates/express-rest-api/src/app.js +0 -55
- package/templates/express-rest-api/src/config/db.config.js +0 -14
- package/templates/express-rest-api/src/config/env.config.js +0 -13
- package/templates/express-rest-api/src/config/logger.config.js +0 -20
- package/templates/express-rest-api/src/controllers/user.controller.js +0 -35
- package/templates/express-rest-api/src/middleware/auth.middleware.js +0 -36
- package/templates/express-rest-api/src/middleware/error.middleware.js +0 -32
- package/templates/express-rest-api/src/middleware/rateLimiter.js +0 -13
- package/templates/express-rest-api/src/middleware/validateRequest.middleware.js +0 -15
- package/templates/express-rest-api/src/models/user.model.js +0 -31
- package/templates/express-rest-api/src/routes/user.route.js +0 -14
- package/templates/express-rest-api/src/schemas/user.schema.js +0 -43
- package/templates/express-rest-api/src/services/user.service.js +0 -54
- package/templates/express-rest-api/src/utils/ApiError.js +0 -17
- package/templates/express-rest-api/src/utils/ApiResponse.js +0 -9
- package/templates/express-rest-api/src/utils/CatchAsync.js +0 -5
- package/templates/express-rest-api/src/utils/Token.js +0 -16
- package/templates/express-socket/.env.example +0 -5
- package/templates/express-socket/package-lock.json +0 -2262
- package/templates/express-socket/package.json +0 -31
- package/templates/express-socket/server.js +0 -19
- package/templates/express-socket/src/app.js +0 -33
- package/templates/express-socket/src/config/db.config.js +0 -14
- package/templates/express-socket/src/config/env.config.js +0 -10
- package/templates/express-socket/src/config/logger.js +0 -20
- package/templates/express-socket/src/config/socket.js +0 -23
- package/templates/express-socket/src/middleware/auth.middleware.js +0 -36
- package/templates/express-socket/src/middleware/error.middleware.js +0 -31
- package/templates/express-socket/src/middleware/rateLimiter.js +0 -14
- package/templates/express-socket/src/middleware/validateRequest.middleware.js +0 -15
- package/templates/express-socket/src/utils/ApiError.js +0 -17
- package/templates/express-socket/src/utils/ApiResponse.js +0 -9
- package/templates/express-socket/src/utils/CatchAsync.js +0 -5
- package/templates/express-socket/src/utils/Token.js +0 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neatnode",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.4",
|
|
4
4
|
"description": "Plug & Play Node.js backend starter templates — build REST APIs, socket servers, and more in seconds.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"neatnode": "./bin/index.js"
|
|
@@ -39,6 +39,8 @@
|
|
|
39
39
|
"license": "ISC",
|
|
40
40
|
"type": "module",
|
|
41
41
|
"dependencies": {
|
|
42
|
+
"axios": "^1.13.2",
|
|
43
|
+
"extract-zip": "^2.0.1",
|
|
42
44
|
"fs-extra": "^11.3.2",
|
|
43
45
|
"inquirer": "^12.10.0"
|
|
44
46
|
}
|
|
@@ -4,14 +4,16 @@ import os from "os";
|
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import { copyTemplate } from "../utils/copyTemplate.js";
|
|
6
6
|
import { removeCrud, removeCrudReferences } from "./removeCRUD.js";
|
|
7
|
+
import { downloadTemplate } from "../utils/downloadRepoTemplate.js";
|
|
7
8
|
|
|
8
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
10
|
const __dirname = path.dirname(__filename);
|
|
10
11
|
|
|
11
|
-
export async function createProject({ projectName,
|
|
12
|
+
export async function createProject({ projectName, repoPath, includeCrud, crudName }) {
|
|
12
13
|
try {
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
const targetPath = projectName === "."
|
|
15
|
+
? process.cwd()
|
|
16
|
+
: path.join(process.cwd(), projectName);
|
|
15
17
|
|
|
16
18
|
if (fs.existsSync(targetPath) && projectName !== ".") {
|
|
17
19
|
console.error(`❌ Folder "${projectName}" already exists.`);
|
|
@@ -23,25 +25,26 @@ export async function createProject({ projectName, templatePath, includeCrud, cr
|
|
|
23
25
|
fs.mkdirSync(targetPath);
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
console.log("Downloading template...");
|
|
29
|
+
const localTemplatePath = await downloadTemplate(repoPath);
|
|
30
|
+
|
|
31
|
+
await copyTemplate(localTemplatePath, targetPath, {
|
|
27
32
|
"project-name": projectName === "." ? path.basename(process.cwd()) : projectName,
|
|
28
33
|
"author": os.userInfo().username || "author",
|
|
29
34
|
});
|
|
30
35
|
|
|
31
|
-
if (
|
|
32
|
-
console.log("
|
|
36
|
+
if (includeCrud && crudName ) {
|
|
37
|
+
console.log("🗑 Removing CRUD files...");
|
|
33
38
|
removeCrud(targetPath, crudName);
|
|
34
39
|
removeCrudReferences(path.join(targetPath, "src", "app.js"));
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
console.log(
|
|
38
|
-
console.log(`\ncd ${projectName === "." ? "" : projectName}`);
|
|
39
|
-
console.log("npm install");
|
|
40
|
-
console.log("npm run dev (or npm start)\n");
|
|
42
|
+
console.log(`\n✅ Project "${projectName}" created successfully!\n`);
|
|
41
43
|
|
|
42
44
|
} catch (err) {
|
|
43
|
-
console.error("Failed to create project:", err);
|
|
45
|
+
console.error("❌ Failed to create project:", err);
|
|
44
46
|
process.exit(1);
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
|
|
50
|
+
|
package/src/cli.js
CHANGED
|
@@ -1,74 +1,89 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import inquirer from "inquirer";
|
|
3
|
-
import { createProject } from "./actions/createProject.js";
|
|
4
3
|
import templates from "./config/templates.js";
|
|
4
|
+
import { createProject } from "./actions/createProject.js";
|
|
5
5
|
|
|
6
6
|
async function main() {
|
|
7
|
-
console.log("\n🚀 Welcome to
|
|
7
|
+
console.log("\n🚀 Welcome to NeatNode CLI!\n");
|
|
8
8
|
|
|
9
|
-
//
|
|
9
|
+
// STEP 1 — Project Name
|
|
10
10
|
const { projectName } = await inquirer.prompt([
|
|
11
11
|
{
|
|
12
|
-
name: "projectName",
|
|
13
12
|
type: "input",
|
|
14
|
-
|
|
13
|
+
name: "projectName",
|
|
14
|
+
message: "Enter project folder name:",
|
|
15
15
|
default: "my-app",
|
|
16
|
-
validate: (
|
|
17
|
-
}
|
|
16
|
+
validate: (v) => v.trim() !== "" || "Project name cannot be empty.",
|
|
17
|
+
},
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
// STEP 2 — Choose Language
|
|
21
|
+
const { language } = await inquirer.prompt([
|
|
22
|
+
{
|
|
23
|
+
type: "list",
|
|
24
|
+
name: "language",
|
|
25
|
+
message: "Select language:",
|
|
26
|
+
choices: ["JavaScript", "TypeScript"],
|
|
27
|
+
},
|
|
18
28
|
]);
|
|
19
29
|
|
|
20
|
-
|
|
30
|
+
const langKey = language === "JavaScript" ? "js" : "ts";
|
|
31
|
+
const templateList = templates[langKey];
|
|
32
|
+
|
|
33
|
+
// STEP 3 — Choose Template
|
|
21
34
|
const { template } = await inquirer.prompt([
|
|
22
35
|
{
|
|
23
|
-
name: "template",
|
|
24
36
|
type: "list",
|
|
37
|
+
name: "template",
|
|
25
38
|
message: "Choose a template:",
|
|
26
|
-
choices:
|
|
27
|
-
}
|
|
39
|
+
choices: templateList.map((t) => t.name),
|
|
40
|
+
},
|
|
28
41
|
]);
|
|
29
42
|
|
|
30
|
-
const chosen =
|
|
43
|
+
const chosen = templateList.find((t) => t.name === template);
|
|
31
44
|
|
|
32
|
-
//
|
|
45
|
+
// STEP 4 — CRUD Optional (only for some templates)
|
|
33
46
|
let includeCrud = false;
|
|
34
47
|
let crudName = "";
|
|
48
|
+
|
|
35
49
|
if (chosen.name === "Basic Express") {
|
|
36
|
-
const answer = await inquirer.prompt([
|
|
50
|
+
const { includeCrud: answer } = await inquirer.prompt([
|
|
37
51
|
{
|
|
38
|
-
name: "includeCrud",
|
|
39
52
|
type: "confirm",
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
53
|
+
name: "includeCrud",
|
|
54
|
+
message: "Include example Todo CRUD?",
|
|
55
|
+
default: true,
|
|
56
|
+
},
|
|
43
57
|
]);
|
|
44
|
-
includeCrud = answer
|
|
58
|
+
includeCrud = answer;
|
|
45
59
|
crudName = "todo";
|
|
46
60
|
}
|
|
47
61
|
|
|
48
62
|
if (chosen.name === "REST API") {
|
|
49
|
-
const answer = await inquirer.prompt([
|
|
63
|
+
const { includeCrud: answer } = await inquirer.prompt([
|
|
50
64
|
{
|
|
51
|
-
name: "includeCrud",
|
|
52
65
|
type: "confirm",
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
66
|
+
name: "includeCrud",
|
|
67
|
+
message: "Include example User CRUD?",
|
|
68
|
+
default: true,
|
|
69
|
+
},
|
|
56
70
|
]);
|
|
57
|
-
includeCrud = answer
|
|
71
|
+
includeCrud = answer;
|
|
58
72
|
crudName = "user";
|
|
59
73
|
}
|
|
60
74
|
|
|
61
|
-
//
|
|
75
|
+
// STEP 5 — Create Project (Remote download logic inside)
|
|
62
76
|
await createProject({
|
|
63
77
|
projectName,
|
|
64
|
-
|
|
78
|
+
repoPath: chosen.repoPath,
|
|
65
79
|
includeCrud,
|
|
66
|
-
crudName
|
|
80
|
+
crudName,
|
|
81
|
+
language: langKey,
|
|
67
82
|
});
|
|
68
83
|
|
|
69
|
-
console.log(`\n✅ Project "${projectName}" created successfully using "${chosen.name}"
|
|
84
|
+
console.log(`\n✅ Project "${projectName}" created successfully using "${chosen.name}".\n`);
|
|
70
85
|
}
|
|
71
86
|
|
|
72
87
|
main().catch((err) => {
|
|
73
|
-
console.error("❌ Error:", err.message);
|
|
88
|
+
console.error("❌ Error:", err.message || err);
|
|
74
89
|
});
|
package/src/config/templates.js
CHANGED
|
@@ -1,20 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export default {
|
|
2
|
+
js: [
|
|
3
|
+
{ name: "Basic Express", repoPath: "templates/js/express-basic" },
|
|
4
|
+
{ name: "REST API", repoPath: "templates/js/express-rest-api" },
|
|
5
|
+
{ name: "Socket.IO", repoPath: "templates/js/express-socket" },
|
|
6
|
+
],
|
|
3
7
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
path: path.join(__dirname, "../../templates/express-basic")
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
name: "REST API",
|
|
14
|
-
path: path.join(__dirname, "../../templates/express-rest-api")
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
name: "Socket.IO Setup",
|
|
18
|
-
path: path.join(__dirname, "../../templates/express-socket")
|
|
19
|
-
}
|
|
20
|
-
];
|
|
8
|
+
ts: [
|
|
9
|
+
{ name: "Basic Express (TS)", repoPath: "templates/ts/basic-express" },
|
|
10
|
+
// { name: "REST API (TS)", repoPath: "templates/ts/express-rest-api" },
|
|
11
|
+
// { name: "Socket.IO (TS)", repoPath: "templates/ts/express-socket" },
|
|
12
|
+
],
|
|
13
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import extract from "extract-zip";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import os from "os";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
|
|
11
|
+
const owner = "aakash-gupta02";
|
|
12
|
+
const repo = "NeatNode";
|
|
13
|
+
|
|
14
|
+
const zipUrl = `https://codeload.github.com/${owner}/${repo}/zip/refs/heads/main`;
|
|
15
|
+
|
|
16
|
+
export async function downloadTemplate(repoPath) {
|
|
17
|
+
// SAFE TEMP DIRECTORY
|
|
18
|
+
const tmpBase = fs.mkdtempSync(path.join(os.tmpdir(), "neatnode-"));
|
|
19
|
+
|
|
20
|
+
const tempZip = path.join(tmpBase, "repo.zip");
|
|
21
|
+
const tempExtractDir = path.join(tmpBase, "repo-extract");
|
|
22
|
+
const tempFinalDir = path.join(tmpBase, "template-final");
|
|
23
|
+
|
|
24
|
+
// download zip
|
|
25
|
+
const response = await axios({
|
|
26
|
+
url: zipUrl,
|
|
27
|
+
responseType: "arraybuffer",
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
fs.writeFileSync(tempZip, response.data);
|
|
31
|
+
|
|
32
|
+
// unzip
|
|
33
|
+
await extract(tempZip, { dir: tempExtractDir });
|
|
34
|
+
|
|
35
|
+
const extractedRoot = path.join(tempExtractDir, `${repo}-main`);
|
|
36
|
+
const srcTemplatePath = path.join(extractedRoot, repoPath);
|
|
37
|
+
|
|
38
|
+
// copy template
|
|
39
|
+
fs.mkdirSync(tempFinalDir, { recursive: true });
|
|
40
|
+
fs.cpSync(srcTemplatePath, tempFinalDir, { recursive: true });
|
|
41
|
+
|
|
42
|
+
console.log("✔ Template downloaded & extracted");
|
|
43
|
+
|
|
44
|
+
return tempFinalDir;
|
|
45
|
+
}
|