create-craftjs 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/README.md +137 -0
- package/bin/index.js +158 -0
- package/package.json +24 -0
- package/template/.dockerignore +4 -0
- package/template/Dockerfile +12 -0
- package/template/babel.config.json +3 -0
- package/template/craft/commands/build.js +15 -0
- package/template/craft/commands/db-fresh.js +22 -0
- package/template/craft/commands/db-generate.js +23 -0
- package/template/craft/commands/db-migrate.js +22 -0
- package/template/craft/commands/dev.js +16 -0
- package/template/craft/commands/key-generate.js +41 -0
- package/template/craft/commands/make-apidocs.js +121 -0
- package/template/craft/commands/make-command.js +38 -0
- package/template/craft/commands/make-dto.js +39 -0
- package/template/craft/commands/make-middleware.js +46 -0
- package/template/craft/commands/make-repository.js +36 -0
- package/template/craft/commands/make-route.js +88 -0
- package/template/craft/commands/make-service.js +39 -0
- package/template/craft/commands/make-test.js +48 -0
- package/template/craft/commands/make-utils.js +30 -0
- package/template/craft/commands/make-validation.js +42 -0
- package/template/craft/commands/make-view.js +42 -0
- package/template/craft/commands/start.js +29 -0
- package/template/craft/commands/test.js +20 -0
- package/template/craft.js +256 -0
- package/template/nodemon.json +6 -0
- package/template/package-lock.json +8777 -0
- package/template/package.json +79 -0
- package/template/prisma/migrations/20250518142257_create_table_users/migration.sql +13 -0
- package/template/prisma/migrations/migration_lock.toml +3 -0
- package/template/prisma/schema.prisma +22 -0
- package/template/prisma/seed.ts +29 -0
- package/template/public/assets/images/default-user.png +0 -0
- package/template/src/apidocs/auth-docs.ts +314 -0
- package/template/src/apidocs/users-docs.ts +240 -0
- package/template/src/config/database.ts +90 -0
- package/template/src/config/env.ts +29 -0
- package/template/src/config/logger.ts +116 -0
- package/template/src/config/web.ts +40 -0
- package/template/src/controllers/auth-controller.ts +88 -0
- package/template/src/controllers/user-controller.ts +79 -0
- package/template/src/dtos/list-dto.ts +12 -0
- package/template/src/dtos/user-dto.ts +57 -0
- package/template/src/main.ts +28 -0
- package/template/src/middleware/auth-middleware.ts +44 -0
- package/template/src/middleware/error-middleware.ts +27 -0
- package/template/src/middleware/http-logger-middleware.ts +31 -0
- package/template/src/repositories/user-repository.ts +75 -0
- package/template/src/routes/auth-route.ts +20 -0
- package/template/src/routes/main-route.ts +25 -0
- package/template/src/routes/user-route.ts +35 -0
- package/template/src/services/auth-service.ts +162 -0
- package/template/src/services/user-service.ts +102 -0
- package/template/src/types/type-request.ts +6 -0
- package/template/src/utils/async-handler.ts +9 -0
- package/template/src/utils/response-error.ts +10 -0
- package/template/src/utils/response.ts +60 -0
- package/template/src/utils/swagger.ts +135 -0
- package/template/src/utils/validation.ts +7 -0
- package/template/src/validations/user-validation.ts +127 -0
- package/template/src/views/index.ejs +6 -0
- package/template/src/views/layouts/main.ejs +14 -0
- package/template/src/views/partials/header.ejs +3 -0
- package/template/test/user.test.ts +16 -0
- package/template/tsconfig.json +13 -0
package/README.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# CraftJS
|
|
2
|
+
|
|
3
|
+
A starter kit backend framework powered by Express, TypeScript, EJS Engine, and Prisma — designed for rapid development, simplicity, and scalability.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Express.js** based API architecture
|
|
10
|
+
- **TypeScript** support out of the box
|
|
11
|
+
- **Prisma ORM** with scalable database structure
|
|
12
|
+
- **CLI tool** (`craft`) for project automation
|
|
13
|
+
- Built-in **Logger**, **Validation**, **Error handler**, and **Request lifecycle**
|
|
14
|
+
- Predefined project structure for fast onboarding
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
💡 Note: EJS View Engine is included but disabled by default. To enable it:
|
|
19
|
+
Open src/application/web.ts and uncomment the following lines:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
import expressLayouts from "express-ejs-layouts";
|
|
23
|
+
import path from "path";
|
|
24
|
+
|
|
25
|
+
web.set("view engine", "ejs");
|
|
26
|
+
web.set("views", path.join(\_\_dirname, "..", "views"));
|
|
27
|
+
web.use(expressLayouts);
|
|
28
|
+
web.set("layout", "layouts/main");
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Then, go to src/routes/main-route.ts and uncomment this:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
mainRouter.get("/", (req, res) => {
|
|
35
|
+
res.render("index", { title: "Home Page" });
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Getting Started
|
|
40
|
+
|
|
41
|
+
### Scaffold a New Project
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx create-craftjs my-app
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
OR
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm init craftjs my-app
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Go to project folder
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
cd my-app
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Run Craft Setup
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install
|
|
63
|
+
node craft key:generate
|
|
64
|
+
node craft generate
|
|
65
|
+
node craft db:migrate
|
|
66
|
+
node craft dev
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Available Craft Commands
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
node craft help
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Project Structure
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
my-app/
|
|
81
|
+
├── craft/
|
|
82
|
+
├── src/
|
|
83
|
+
│ ├── apidocs/
|
|
84
|
+
│ ├── config/
|
|
85
|
+
│ ├── controllers/
|
|
86
|
+
│ ├── middleware/
|
|
87
|
+
│ ├── repositories/
|
|
88
|
+
│ ├── dtos/
|
|
89
|
+
│ ├── routes/
|
|
90
|
+
│ └── services/
|
|
91
|
+
│ └── types/
|
|
92
|
+
│ └── utils/
|
|
93
|
+
│ └── validations/
|
|
94
|
+
│ └── main.ts
|
|
95
|
+
├── test/
|
|
96
|
+
├── logs/
|
|
97
|
+
├── .env
|
|
98
|
+
├── .env.example
|
|
99
|
+
├── prisma/
|
|
100
|
+
├── .gitignore
|
|
101
|
+
├── babel.config.json
|
|
102
|
+
├── craft.js
|
|
103
|
+
├── nodemon.json
|
|
104
|
+
├── package.json
|
|
105
|
+
├── package-lock.json
|
|
106
|
+
└── tsconfig.json
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Scripts
|
|
112
|
+
|
|
113
|
+
| Command | Description |
|
|
114
|
+
| ----------------------- | ------------------------------ |
|
|
115
|
+
| `craft start` | Start production server |
|
|
116
|
+
| `craft dev` | Run in development mode |
|
|
117
|
+
| `craft build` | Build for production |
|
|
118
|
+
| `craft test` | Run Jest tests |
|
|
119
|
+
| `craft db:generate` | Generate Prisma client |
|
|
120
|
+
| `craft db:migrate` | Run Prisma migrations |
|
|
121
|
+
| `craft db:reset` | Run Prisma migrations refresh |
|
|
122
|
+
| `craft key:generate` | Generate secret keys |
|
|
123
|
+
| `craft make:controller` | Make Controller File |
|
|
124
|
+
| `craft make:command` | Make Command File |
|
|
125
|
+
| `craft make:middleware` | Make Middleware File |
|
|
126
|
+
| `craft make:repository` | Make repository File |
|
|
127
|
+
| `craft make:dto` | Make Data Transfer Object File |
|
|
128
|
+
| `craft make:route` | Make Route File |
|
|
129
|
+
| `craft make:service` | Make Service File |
|
|
130
|
+
| `craft make:test` | Make Test case |
|
|
131
|
+
| `craft make:utils` | Make Utils |
|
|
132
|
+
| `craft make:validation` | Make Validation |
|
|
133
|
+
| `craft make:view` | Make View |
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
Made by [@muhammadisa-n](https://github.com/muhammadisa-n)
|
package/bin/index.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const { spawnSync } = require("child_process");
|
|
6
|
+
const readline = require("readline");
|
|
7
|
+
|
|
8
|
+
const rl = readline.createInterface({
|
|
9
|
+
input: process.stdin,
|
|
10
|
+
output: process.stdout,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const ask = (question) => {
|
|
14
|
+
return new Promise((resolve) => {
|
|
15
|
+
rl.question(question, (answer) => resolve(answer.trim()));
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
(async () => {
|
|
20
|
+
console.log("🚀 Welcome to CraftJS Project Creator!");
|
|
21
|
+
|
|
22
|
+
let projectName = process.argv[2];
|
|
23
|
+
|
|
24
|
+
if (!projectName) {
|
|
25
|
+
projectName = await ask("📦 Enter your project name: ");
|
|
26
|
+
while (!projectName || !/^[a-zA-Z0-9-_]+$/.test(projectName)) {
|
|
27
|
+
console.log(
|
|
28
|
+
"❌ Invalid project name. Use only letters, numbers, - and _."
|
|
29
|
+
);
|
|
30
|
+
projectName = await ask("📦 Enter your project name: ");
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
if (!/^[a-zA-Z0-9-_]+$/.test(projectName)) {
|
|
34
|
+
console.error(
|
|
35
|
+
"❌ Project name can only contain letters, numbers, dashes (-), and underscores (_)."
|
|
36
|
+
);
|
|
37
|
+
rl.close();
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const targetPath = path.resolve(process.cwd(), projectName);
|
|
43
|
+
const templatePath = path.join(__dirname, "..", "template");
|
|
44
|
+
|
|
45
|
+
if (fs.existsSync(targetPath)) {
|
|
46
|
+
console.error(`❌ Folder "${projectName}" already exists.`);
|
|
47
|
+
rl.close();
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const copyRecursiveSync = (src, dest) => {
|
|
52
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
53
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
54
|
+
|
|
55
|
+
for (let entry of entries) {
|
|
56
|
+
const srcPath = path.join(src, entry.name);
|
|
57
|
+
const destPath = path.join(dest, entry.name);
|
|
58
|
+
if (entry.isDirectory()) {
|
|
59
|
+
copyRecursiveSync(srcPath, destPath);
|
|
60
|
+
} else {
|
|
61
|
+
fs.copyFileSync(srcPath, destPath);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
console.log(`\n🚧 Creating project in ./${projectName}...`);
|
|
67
|
+
copyRecursiveSync(templatePath, targetPath);
|
|
68
|
+
|
|
69
|
+
const packageJsonPath = path.join(targetPath, "package.json");
|
|
70
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
71
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
72
|
+
pkg.name = projectName;
|
|
73
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2));
|
|
74
|
+
console.log(`📦 Updated package.json name to "${projectName}"`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const envContent = `APP_NAME="${projectName}"
|
|
78
|
+
APP_SECRET=
|
|
79
|
+
NODE_ENV="development"
|
|
80
|
+
TZ="Asia/Jakarta"
|
|
81
|
+
DATETIME_FORMAT="dd-MM-yyyy HH:mm:ss"
|
|
82
|
+
DATABASE_URL="mysql://root:@localhost:3306/${projectName}"
|
|
83
|
+
BASE_URL="http://localhost:3000"
|
|
84
|
+
BASE_API_URL="http://localhost:3000/api"
|
|
85
|
+
PORT=3000
|
|
86
|
+
JWT_SECRET=
|
|
87
|
+
`;
|
|
88
|
+
|
|
89
|
+
const envExampleContent = envContent.replace(/=.*/g, "=");
|
|
90
|
+
|
|
91
|
+
const sourceReadmePath = path.join(__dirname, "..", "README.md");
|
|
92
|
+
const targetReadmePath = path.join(targetPath, "README.md");
|
|
93
|
+
|
|
94
|
+
if (fs.existsSync(sourceReadmePath)) {
|
|
95
|
+
fs.copyFileSync(sourceReadmePath, targetReadmePath);
|
|
96
|
+
console.log("📄 Copied README.md...");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
console.log("📝 Generating .env and .env.example...");
|
|
100
|
+
fs.writeFileSync(path.join(targetPath, ".env"), envContent);
|
|
101
|
+
fs.writeFileSync(path.join(targetPath, ".env.example"), envExampleContent);
|
|
102
|
+
|
|
103
|
+
console.log("🔧 Initializing git repository...");
|
|
104
|
+
const gitInit = spawnSync("git", ["init"], {
|
|
105
|
+
cwd: targetPath,
|
|
106
|
+
stdio: "inherit",
|
|
107
|
+
shell: true,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
if (gitInit.status !== 0) {
|
|
111
|
+
console.warn("⚠️ Git initialization failed.");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const gitignorePath = path.join(targetPath, ".gitignore");
|
|
115
|
+
if (!fs.existsSync(gitignorePath)) {
|
|
116
|
+
fs.writeFileSync(
|
|
117
|
+
gitignorePath,
|
|
118
|
+
`node_modules
|
|
119
|
+
.env
|
|
120
|
+
dist
|
|
121
|
+
`
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const installNow = await ask(
|
|
126
|
+
"📥 Do you want to install dependencies now? (yes/no): "
|
|
127
|
+
);
|
|
128
|
+
if (installNow.toLowerCase() === "yes" || installNow.toLowerCase() === "y") {
|
|
129
|
+
console.log("📦 Installing dependencies...");
|
|
130
|
+
const npmInstall = spawnSync("npm", ["install"], {
|
|
131
|
+
cwd: targetPath,
|
|
132
|
+
stdio: "inherit",
|
|
133
|
+
shell: true,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
if (npmInstall.status !== 0) {
|
|
137
|
+
console.warn("⚠️ npm install failed.");
|
|
138
|
+
console.log("\n✅ Done!");
|
|
139
|
+
console.log(
|
|
140
|
+
`\nNext steps:\n cd ${projectName}\n npm install\n node craft key:generate\n node craft db:generate\n node craft db:migrate\n node craft dev`
|
|
141
|
+
);
|
|
142
|
+
} else {
|
|
143
|
+
console.log("✅ Dependencies installed successfully.");
|
|
144
|
+
console.log("\n✅ Done!");
|
|
145
|
+
console.log(
|
|
146
|
+
`\nNext steps:\n cd ${projectName}\n node craft key:generate\n node craft db:generate\n node craft db:migrate\n node craft dev`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
} else {
|
|
150
|
+
console.log("ℹ️ Skipping dependency installation.");
|
|
151
|
+
console.log("\n✅ Done!");
|
|
152
|
+
console.log(
|
|
153
|
+
`\nNext steps:\n cd ${projectName}\n npm install\n node craft key:generate\n node craft db:generate\n node craft db:migrate\n node craft dev`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
rl.close();
|
|
158
|
+
})();
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-craftjs",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A starter kit backend framework powered by Express, TypeScript, EJS Engine, and Prisma — designed for rapid development, simplicity, and scalability.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"create-craftjs": "bin/index.js"
|
|
7
|
+
},
|
|
8
|
+
"author": "Muhammad Isa Nuruddin",
|
|
9
|
+
"homepage": "https://github.com/muhammadisa-n/CraftJS#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/muhammadisa-n/CraftJS/issues"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/muhammadisa-n/CraftJS.git"
|
|
16
|
+
},
|
|
17
|
+
"license": "UNLICENSED",
|
|
18
|
+
"keywords": [
|
|
19
|
+
"express",
|
|
20
|
+
"typescript",
|
|
21
|
+
"prisma",
|
|
22
|
+
"api"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const { execSync } = require("child_process");
|
|
2
|
+
const chalk = require("chalk");
|
|
3
|
+
function Build() {
|
|
4
|
+
console.log(chalk.blue("📦 Building project..."));
|
|
5
|
+
|
|
6
|
+
try {
|
|
7
|
+
execSync("npx tsc && cp -r src/views dist/views", { stdio: "inherit" });
|
|
8
|
+
console.log(chalk.green("✅ Build completed successfully."));
|
|
9
|
+
} catch (error) {
|
|
10
|
+
console.error(chalk.red("❌ Build failed."));
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = Build;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const { spawnSync } = require("child_process");
|
|
2
|
+
const chalk = require("chalk");
|
|
3
|
+
|
|
4
|
+
function DbReset() {
|
|
5
|
+
console.log(chalk.blue("🚀 Running prisma migrate reset..."));
|
|
6
|
+
|
|
7
|
+
const result = spawnSync("npx", ["prisma", "migrate", "reset"], {
|
|
8
|
+
stdio: "inherit",
|
|
9
|
+
shell: true,
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
if (result.status !== 0) {
|
|
13
|
+
console.error(chalk.red("❌ Migrate reset failed."));
|
|
14
|
+
if (result.error) {
|
|
15
|
+
console.error(chalk.red(`Error: ${result.error.message}`));
|
|
16
|
+
}
|
|
17
|
+
process.exit(result.status ?? 1);
|
|
18
|
+
} else {
|
|
19
|
+
console.log(chalk.green("✅ Migrate reset completed."));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
module.exports = DbReset;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const { spawnSync } = require("child_process");
|
|
2
|
+
const chalk = require("chalk");
|
|
3
|
+
|
|
4
|
+
function DbGenerate() {
|
|
5
|
+
console.log(chalk.blue("🚀 Running prisma generate..."));
|
|
6
|
+
|
|
7
|
+
const result = spawnSync("npx", ["prisma", "generate"], {
|
|
8
|
+
stdio: "inherit",
|
|
9
|
+
shell: true,
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
if (result.status !== 0) {
|
|
13
|
+
console.error(chalk.red("❌ Generate failed."));
|
|
14
|
+
// Jika ada error, print detailnya
|
|
15
|
+
if (result.error) {
|
|
16
|
+
console.error(chalk.red(`Error: ${result.error.message}`));
|
|
17
|
+
}
|
|
18
|
+
process.exit(result.status ?? 1);
|
|
19
|
+
} else {
|
|
20
|
+
console.log(chalk.green("✅ Prisma generate completed."));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
module.exports = DbGenerate;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const { spawnSync } = require("child_process");
|
|
2
|
+
const chalk = require("chalk");
|
|
3
|
+
|
|
4
|
+
function DbMigrate() {
|
|
5
|
+
console.log(chalk.blue("🚀 Running prisma migrate dev..."));
|
|
6
|
+
|
|
7
|
+
const result = spawnSync("npx", ["prisma", "migrate", "dev"], {
|
|
8
|
+
stdio: "inherit",
|
|
9
|
+
shell: true,
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
if (result.status !== 0) {
|
|
13
|
+
console.error(chalk.red("❌ Migration failed."));
|
|
14
|
+
if (result.error) {
|
|
15
|
+
console.error(chalk.red(`Error: ${result.error.message}`));
|
|
16
|
+
}
|
|
17
|
+
process.exit(result.status ?? 1);
|
|
18
|
+
} else {
|
|
19
|
+
console.log(chalk.green("✅ Migration completed."));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
module.exports = DbMigrate;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const { spawnSync } = require("child_process");
|
|
2
|
+
const chalk = require("chalk");
|
|
3
|
+
|
|
4
|
+
function Dev() {
|
|
5
|
+
console.log(chalk.blue("🚀 Starting development server with nodemon..."));
|
|
6
|
+
const result = spawnSync("nodemon", ["./src/main.ts"], {
|
|
7
|
+
stdio: "inherit",
|
|
8
|
+
shell: true,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
if (result.status !== 0) {
|
|
12
|
+
console.error(chalk.red("❌ Failed to start development server."));
|
|
13
|
+
process.exit(result.status ?? 1);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
module.exports = Dev;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const chalk = require("chalk");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const crypto = require("crypto");
|
|
5
|
+
|
|
6
|
+
function keyGenerate() {
|
|
7
|
+
const envPath = path.resolve(process.cwd(), ".env");
|
|
8
|
+
if (!fs.existsSync(envPath)) {
|
|
9
|
+
console.error(chalk.red("❌ .env file not found!"));
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let envContent = fs.readFileSync(envPath, "utf-8");
|
|
14
|
+
|
|
15
|
+
const generateKey = (number) => crypto.randomBytes(number).toString("hex");
|
|
16
|
+
|
|
17
|
+
if (envContent.includes("JWT_SECRET=")) {
|
|
18
|
+
envContent = envContent.replace(
|
|
19
|
+
/JWT_SECRET=.*/g,
|
|
20
|
+
`JWT_SECRET=${generateKey(16)}`
|
|
21
|
+
);
|
|
22
|
+
} else {
|
|
23
|
+
envContent += `\nJWT_SECRET_ACCESS_TOKEN=${generateKey(16)}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (envContent.includes("APP_SECRET=")) {
|
|
27
|
+
envContent = envContent.replace(
|
|
28
|
+
/APP_SECRET=.*/g,
|
|
29
|
+
`APP_SECRET=${generateKey(32)}`
|
|
30
|
+
);
|
|
31
|
+
} else {
|
|
32
|
+
envContent += `\APP_SECRET=${generateKey(32)}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
fs.writeFileSync(envPath, envContent);
|
|
36
|
+
|
|
37
|
+
console.log(
|
|
38
|
+
chalk.green("✅ App Secret and JWT Secret generated successfully.")
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
module.exports = keyGenerate;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const chalk = require("chalk");
|
|
4
|
+
|
|
5
|
+
function makeApiDocs(name) {
|
|
6
|
+
if (!name) {
|
|
7
|
+
console.log(chalk.red("❌ Please provide a apidocs name."));
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const fileName = `${name.toLowerCase()}-docs.ts`;
|
|
12
|
+
const targetDir = path.resolve("src", "apidocs");
|
|
13
|
+
|
|
14
|
+
if (!fs.existsSync(targetDir)) {
|
|
15
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const filePath = path.join(targetDir, fileName);
|
|
19
|
+
if (fs.existsSync(filePath)) {
|
|
20
|
+
console.log(chalk.yellow("⚠️ Apidocs already exists."));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const content = `/**
|
|
25
|
+
* @swagger
|
|
26
|
+
* /api/${name}:
|
|
27
|
+
* get:
|
|
28
|
+
* summary: Mengambil daftar semua ${name}
|
|
29
|
+
* tags: [${name}s]
|
|
30
|
+
* security:
|
|
31
|
+
* - bearerAuth: []
|
|
32
|
+
* parameters:
|
|
33
|
+
* - in: query
|
|
34
|
+
* name: page
|
|
35
|
+
* schema:
|
|
36
|
+
* type: integer
|
|
37
|
+
* required: false
|
|
38
|
+
* description: Nomor halaman
|
|
39
|
+
* - in: query
|
|
40
|
+
* name: take
|
|
41
|
+
* schema:
|
|
42
|
+
* type: integer
|
|
43
|
+
* required: false
|
|
44
|
+
* description: Jumlah data per halaman
|
|
45
|
+
* - in: query
|
|
46
|
+
* name: name
|
|
47
|
+
* schema:
|
|
48
|
+
* type: string
|
|
49
|
+
* required: false
|
|
50
|
+
* description: Filter berdasarkan nama (fullName)
|
|
51
|
+
* responses:
|
|
52
|
+
* 200:
|
|
53
|
+
* description: Berhasil Get All Data
|
|
54
|
+
* content:
|
|
55
|
+
* application/json:
|
|
56
|
+
* schema:
|
|
57
|
+
* type: object
|
|
58
|
+
* properties:
|
|
59
|
+
* status:
|
|
60
|
+
* type: boolean
|
|
61
|
+
* status_code:
|
|
62
|
+
* type: integer
|
|
63
|
+
* message:
|
|
64
|
+
* type: string
|
|
65
|
+
* data:
|
|
66
|
+
* type: object
|
|
67
|
+
* properties:
|
|
68
|
+
* data:
|
|
69
|
+
* type: array
|
|
70
|
+
* items:
|
|
71
|
+
* type: object
|
|
72
|
+
* properties:
|
|
73
|
+
* id:
|
|
74
|
+
* type: string
|
|
75
|
+
* format: uuid
|
|
76
|
+
* fullName:
|
|
77
|
+
* type: string
|
|
78
|
+
* email:
|
|
79
|
+
* type: string
|
|
80
|
+
* username:
|
|
81
|
+
* type: string
|
|
82
|
+
* password:
|
|
83
|
+
* type: string
|
|
84
|
+
* description: (Hashed password)
|
|
85
|
+
* image_id:
|
|
86
|
+
* type: string
|
|
87
|
+
* image_url:
|
|
88
|
+
* type: string
|
|
89
|
+
* format: uri
|
|
90
|
+
* is_verify:
|
|
91
|
+
* type: boolean
|
|
92
|
+
* created_at:
|
|
93
|
+
* type: string
|
|
94
|
+
* format: date-time
|
|
95
|
+
* updated_at:
|
|
96
|
+
* type: string
|
|
97
|
+
* format: date-time
|
|
98
|
+
* deleted_at:
|
|
99
|
+
* type: string
|
|
100
|
+
* format: date-time
|
|
101
|
+
* nullable: true
|
|
102
|
+
* role_id:
|
|
103
|
+
* type: string
|
|
104
|
+
* format: uuid
|
|
105
|
+
* total_data:
|
|
106
|
+
* type: integer
|
|
107
|
+
* paging:
|
|
108
|
+
* type: object
|
|
109
|
+
* properties:
|
|
110
|
+
* current_page:
|
|
111
|
+
* type: integer
|
|
112
|
+
* total_page:
|
|
113
|
+
* type: integer
|
|
114
|
+
|
|
115
|
+
*/
|
|
116
|
+
`;
|
|
117
|
+
|
|
118
|
+
fs.writeFileSync(filePath, content);
|
|
119
|
+
console.log(chalk.green(`✅ Controller created at ${filePath}`));
|
|
120
|
+
}
|
|
121
|
+
module.exports = makeApiDocs;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const chalk = require("chalk");
|
|
4
|
+
|
|
5
|
+
function makeCommand(name) {
|
|
6
|
+
if (!name) {
|
|
7
|
+
console.log(chalk.red("❌ Please provide a command name."));
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const fileName = `${name.toLowerCase()}.js`;
|
|
12
|
+
const targetDir = path.resolve("craft", "commands");
|
|
13
|
+
|
|
14
|
+
if (!fs.existsSync(targetDir)) {
|
|
15
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const filePath = path.join(targetDir, fileName);
|
|
19
|
+
if (fs.existsSync(filePath)) {
|
|
20
|
+
console.log(chalk.yellow("⚠️ Command already exists."));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const content = `const fs = require("fs");
|
|
25
|
+
const path = require("path");
|
|
26
|
+
const chalk = require("chalk");
|
|
27
|
+
|
|
28
|
+
function make${name}(name) {
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = make${name};
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
fs.writeFileSync(filePath, content);
|
|
36
|
+
console.log(chalk.green(`✅ Command created at ${filePath}`));
|
|
37
|
+
}
|
|
38
|
+
module.exports = makeCommand;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const chalk = require("chalk");
|
|
4
|
+
|
|
5
|
+
const toPascalCase = (str) =>
|
|
6
|
+
str.replace(/(^\w|-\w)/g, (m) => m.replace("-", "").toUpperCase());
|
|
7
|
+
|
|
8
|
+
function makeDto(name) {
|
|
9
|
+
if (!name) {
|
|
10
|
+
console.log(chalk.red("❌ Please provide a dto name."));
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const typeName = `${toPascalCase(name)}Request`;
|
|
15
|
+
const fileName = `${name.toLowerCase()}-dto.ts`;
|
|
16
|
+
const targetDir = path.resolve("src", "dtos");
|
|
17
|
+
|
|
18
|
+
if (!fs.existsSync(targetDir)) {
|
|
19
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const filePath = path.join(targetDir, fileName);
|
|
23
|
+
if (fs.existsSync(filePath)) {
|
|
24
|
+
console.log(chalk.yellow("⚠️ Dto already exists."));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const content = `export type ${typeName} = {
|
|
29
|
+
field1: string;
|
|
30
|
+
field2?: string; // optional
|
|
31
|
+
|
|
32
|
+
};
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
fs.writeFileSync(filePath, content);
|
|
36
|
+
console.log(chalk.green(`✅ Dto created at ${filePath}`));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = makeDto;
|