create-craftjs 1.0.4 → 1.0.6

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.
Files changed (67) hide show
  1. package/README.md +139 -137
  2. package/bin/index.js +158 -158
  3. package/package.json +24 -24
  4. package/template/Dockerfile +57 -12
  5. package/template/babel.config.json +3 -3
  6. package/template/craft/commands/build.js +16 -15
  7. package/template/craft/commands/db-fresh.js +22 -22
  8. package/template/craft/commands/db-generate.js +23 -23
  9. package/template/craft/commands/db-migrate.js +22 -22
  10. package/template/craft/commands/dev.js +16 -16
  11. package/template/craft/commands/key-generate.js +41 -41
  12. package/template/craft/commands/make-apidocs.js +121 -121
  13. package/template/craft/commands/make-command.js +38 -38
  14. package/template/craft/commands/make-controller.js +95 -95
  15. package/template/craft/commands/make-dto.js +39 -39
  16. package/template/craft/commands/make-middleware.js +46 -46
  17. package/template/craft/commands/make-repository.js +36 -36
  18. package/template/craft/commands/make-route.js +92 -92
  19. package/template/craft/commands/make-service.js +39 -39
  20. package/template/craft/commands/make-test.js +48 -48
  21. package/template/craft/commands/make-utils.js +30 -30
  22. package/template/craft/commands/make-validation.js +42 -42
  23. package/template/craft/commands/make-view.js +42 -42
  24. package/template/craft/commands/start.js +29 -29
  25. package/template/craft/commands/test.js +20 -20
  26. package/template/craft.js +256 -256
  27. package/template/docker-compose.yml +8 -0
  28. package/template/nodemon.json +6 -6
  29. package/template/package-lock.json +8877 -8877
  30. package/template/package.json +84 -84
  31. package/template/prisma/schema.prisma +22 -22
  32. package/template/prisma/seed.ts +29 -29
  33. package/template/src/apidocs/auth-docs.ts +314 -314
  34. package/template/src/apidocs/users-docs.ts +240 -240
  35. package/template/src/config/cloudinary.ts +21 -21
  36. package/template/src/config/database.ts +90 -90
  37. package/template/src/config/env.ts +67 -67
  38. package/template/src/config/logger.ts +139 -139
  39. package/template/src/config/nodemailer.ts +23 -23
  40. package/template/src/config/web.ts +47 -47
  41. package/template/src/controllers/auth-controller.ts +88 -88
  42. package/template/src/controllers/user-controller.ts +79 -79
  43. package/template/src/dtos/list-dto.ts +12 -12
  44. package/template/src/dtos/user-dto.ts +57 -57
  45. package/template/src/main.ts +28 -28
  46. package/template/src/middleware/auth-middleware.ts +44 -44
  47. package/template/src/middleware/error-middleware.ts +27 -27
  48. package/template/src/middleware/http-logger-middleware.ts +31 -31
  49. package/template/src/repositories/user-repository.ts +75 -75
  50. package/template/src/routes/auth-route.ts +20 -20
  51. package/template/src/routes/main-route.ts +25 -25
  52. package/template/src/routes/user-route.ts +35 -35
  53. package/template/src/services/auth-service.ts +162 -162
  54. package/template/src/services/user-service.ts +102 -102
  55. package/template/src/types/type-request.ts +6 -6
  56. package/template/src/utils/async-handler.ts +9 -9
  57. package/template/src/utils/response-error.ts +10 -10
  58. package/template/src/utils/response.ts +60 -60
  59. package/template/src/utils/swagger.ts +135 -135
  60. package/template/src/utils/validation.ts +7 -7
  61. package/template/src/validations/user-validation.ts +127 -127
  62. package/template/src/views/index.ejs +6 -6
  63. package/template/src/views/layouts/main.ejs +14 -14
  64. package/template/src/views/partials/header.ejs +3 -3
  65. package/template/test/user.test.ts +16 -16
  66. package/template/tsconfig.json +13 -13
  67. package/template/.dockerignore +0 -4
@@ -1,12 +1,57 @@
1
- FROM node:20
2
- WORKDIR /usr/src/app
3
- COPY package*.json ./
4
- RUN npm install
5
- COPY prisma ./prisma
6
- RUN npx prisma generate
7
- COPY . .
8
- COPY .env .env
9
- RUN npm install typescript
10
- RUN npm run build
11
- EXPOSE 3000
12
- CMD ["npm", "run", "dev"]
1
+ FROM node:22-slim AS base
2
+
3
+ # Install timezone data
4
+ RUN apt-get update && apt-get install -y tzdata openssl
5
+
6
+ # Set timezone
7
+ ENV TZ=Asia/Jakarta
8
+ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
9
+
10
+ WORKDIR /usr/src/app
11
+
12
+ # Create logs folder
13
+ RUN mkdir -p logs
14
+
15
+ # Install dependencies based on package-lock.json
16
+ COPY package*.json ./
17
+ RUN npm ci
18
+
19
+ # Copy source code
20
+ COPY . .
21
+
22
+ # Generate Prisma client
23
+ RUN npx prisma generate
24
+
25
+ # Generate key (sesuaikan dengan perintahmu)
26
+ RUN node craft key:generate
27
+
28
+ # Build project (jika ada)
29
+ RUN node craft build
30
+
31
+
32
+ # Build stage untuk copy hasil build
33
+ FROM base AS build
34
+
35
+ # Nothing extra, base sudah berisi semua
36
+
37
+ # Production image
38
+ FROM node:22-slim AS production
39
+
40
+ WORKDIR /usr/src/app
41
+
42
+ # Copy package files untuk install production dependencies
43
+ COPY package*.json ./
44
+
45
+ # Install production dependencies saja
46
+ RUN npm ci --omit=dev
47
+
48
+ # Copy hasil build dan file penting dari build stage
49
+ COPY --from=build /usr/src/app/build ./build
50
+ COPY --from=build /usr/src/app/node_modules/.prisma ./node_modules/.prisma
51
+ COPY --from=build /usr/src/app/prisma ./prisma
52
+ COPY --from=build /usr/src/app/.env ./
53
+ COPY --from=build /usr/src/app/logs ./build/logs
54
+
55
+ EXPOSE 3000
56
+
57
+ CMD ["node", "build/main.js"]
@@ -1,3 +1,3 @@
1
- {
2
- "presets": ["@babel/preset-env", "@babel/preset-typescript"]
3
- }
1
+ {
2
+ "presets": ["@babel/preset-env", "@babel/preset-typescript"]
3
+ }
@@ -1,15 +1,16 @@
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;
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 build/views", { stdio: "inherit" });
8
+ execSync("cp -r public build/public", { stdio: "inherit" });
9
+ console.log(chalk.green("✅ Build completed successfully."));
10
+ } catch (error) {
11
+ console.error(chalk.red("❌ Build failed."));
12
+ process.exit(1);
13
+ }
14
+ }
15
+
16
+ module.exports = Build;
@@ -1,22 +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;
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;
@@ -1,23 +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;
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;
@@ -1,22 +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;
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;
@@ -1,16 +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;
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;
@@ -1,41 +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;
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;
@@ -1,121 +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;
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;