kontas-express 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ // index.js
3
+ console.log("Kontas Express Framework");
package/package.json CHANGED
@@ -1,13 +1,22 @@
1
1
  {
2
2
  "name": "kontas-express",
3
- "version": "1.0.1",
4
- "main": "index.js",
3
+ "version": "1.0.2",
4
+ "main": "dist/index.js",
5
5
  "scripts": {
6
- "test": "echo \"Error: no test specified\" && exit 1"
6
+ "build": "bun build ./index.js --outdir ./dist --target bun",
7
+ "prepublishOnly": "bun run build"
7
8
  },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "keywords": [
13
+ "kontas",
14
+ "express",
15
+ "framework"
16
+ ],
8
17
  "author": "Hens MSN",
9
18
  "license": "ISC",
10
- "description": "",
19
+ "description": "Kontas Express Framework",
11
20
  "devDependencies": {
12
21
  "@types/bun": "latest"
13
22
  },
package/index.js DELETED
@@ -1 +0,0 @@
1
- export { default as templates } from './templates/index.js'
package/jsconfig.json DELETED
@@ -1,27 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- // Enable latest features
4
- "lib": ["ESNext", "DOM"],
5
- "target": "ESNext",
6
- "module": "ESNext",
7
- "moduleDetection": "force",
8
- "jsx": "react-jsx",
9
- "allowJs": true,
10
-
11
- // Bundler mode
12
- "moduleResolution": "bundler",
13
- "allowImportingTsExtensions": true,
14
- "verbatimModuleSyntax": true,
15
- "noEmit": true,
16
-
17
- // Best practices
18
- "strict": true,
19
- "skipLibCheck": true,
20
- "noFallthroughCasesInSwitch": true,
21
-
22
- // Some stricter flags (disabled by default)
23
- "noUnusedLocals": false,
24
- "noUnusedParameters": false,
25
- "noPropertyAccessFromIndexSignature": false
26
- }
27
- }
@@ -1,45 +0,0 @@
1
- export default `import { MongoClient } from "mongodb"
2
- import config from "./mongodb.json"
3
-
4
- // Mendapatkan environment yang sedang berjalan (default: development)
5
- const env = process.env.NODE_ENV || "development"
6
- const { uri: configUri, name } = config[env as keyof typeof config]
7
-
8
- // Menggunakan URI dari environment variable jika tersedia, jika tidak menggunakan dari config
9
- const uri = process.env.MONGODB_URI || configUri
10
-
11
- // Inisialisasi MongoDB Client
12
- const client = new MongoClient(uri)
13
-
14
- /**
15
- * Membuat koneksi ke MongoDB
16
- * @throws {Error} Jika koneksi gagal
17
- */
18
- export async function connect() {
19
- try {
20
- await client.connect()
21
- // console.log("✅ Berhasil terhubung ke MongoDB")
22
- } catch (error) {
23
- console.error("❌ Gagal terhubung ke MongoDB:", error)
24
- await client.close() // Menutup koneksi jika terjadi kegagalan
25
- throw error // Re-throw error untuk handling di level aplikasi
26
- }
27
- }
28
-
29
- /**
30
- * Mendapatkan instance database
31
- * @returns {Promise<Db>} Instance database MongoDB
32
- */
33
- export async function getDb() {
34
- return client.db(name)
35
- }
36
-
37
- /**
38
- * Mendapatkan collection dari database
39
- * @param {string} collectionName - Nama collection yang ingin diakses
40
- * @returns {Promise<Collection>} Instance collection MongoDB
41
- */
42
- export async function getCollection(collectionName: string) {
43
- const db = await getDb()
44
- return db.collection(collectionName)
45
- }`
@@ -1,14 +0,0 @@
1
- export default (uri, dbName) => `{
2
- "development": {
3
- "uri": "${uri}",
4
- "name": "${dbName}"
5
- },
6
- "test": {
7
- "uri": "${uri}",
8
- "name": "${dbName}_test"
9
- },
10
- "production": {
11
- "uri": "${uri}",
12
- "name": "${dbName}_prod"
13
- }
14
- }`
@@ -1,54 +0,0 @@
1
- export default `import type { Request, Response, NextFunction } from 'express'
2
- import { z } from 'zod'
3
-
4
- export const errorHandler = (
5
- err: Error,
6
- req: Request,
7
- res: Response,
8
- next: NextFunction
9
- ): void => {
10
- // console.error('🔥 Error:', err)
11
-
12
- // Zod validation errors
13
- if (err instanceof z.ZodError) {
14
- res.status(422).json({
15
- success: false,
16
- status: 422,
17
- error: err.issues.map(issue => ({
18
- field: issue.path.join('.'),
19
- message: issue.message
20
- }))
21
- })
22
- return
23
- }
24
-
25
- // Known errors
26
- if (err instanceof Error) {
27
- let status = 400
28
- let message = err.message
29
-
30
- if (err.message.includes('not found')) {
31
- status = 404
32
- } else if (err.message.includes('unauthorized')) {
33
- status = 401
34
- } else if (err.message.includes('forbidden')) {
35
- status = 403
36
- } else if (err.message.includes('already exists')) {
37
- status = 409
38
- }
39
-
40
- res.status(status).json({
41
- success: false,
42
- status,
43
- error: message
44
- })
45
- return
46
- }
47
-
48
- // Unknown errors
49
- res.status(500).json({
50
- success: false,
51
- status: 500,
52
- error: 'Internal Server Error'
53
- })
54
- }`
@@ -1,7 +0,0 @@
1
- export default `import type { Request, Response } from 'express'
2
-
3
- export async function GET(req: Request, res: Response) {
4
- res.json({
5
- message: \`Selamat datang di KONTAS XROUTES\`,
6
- })
7
- }`
@@ -1,129 +0,0 @@
1
- export default `import dotenv from 'dotenv'
2
- import express from 'express'
3
- import { XRoutes, XMiddleware } from 'kontas-xroutes'
4
- import { connect } from '@config/mongodb'
5
-
6
- // Load environment variables
7
- dotenv.config()
8
-
9
- /*
10
- * 📚 Tutorial Express + XRoutes:
11
- *
12
- * 🔥 XRoutes Features:
13
- * - Auto-routing dari folder structure (mirip NextJS)
14
- * - Wajib pake nama controller.ts (bkn route.ts)
15
- * - Support middleware per route/global
16
- * - Compatible dgn Express & Bun
17
- *
18
- * 📁 Struktur Route:
19
- * src/
20
- * ├─ products/
21
- * │ ├─ [id]/
22
- * │ │ └─ controller.ts => /products/:id
23
- * │ └─ controller.ts => /products
24
- * ├─ users/
25
- * │ ├─ [id]/
26
- * │ │ └─ controller.ts => /users/:id
27
- * │ └─ controller.ts => /users
28
- * └─ auth/
29
- * └─ controller.ts => /auth
30
- *
31
- * 🔐 Route Middleware Examples:
32
- * - '/products/*': Semua route /products
33
- * - '/users': Exact route /users
34
- * - '/users/*': Route yg ada /users/ didalamnya
35
- */
36
-
37
- const app = express()
38
- const port = process.env.PORT || 3000
39
-
40
- /*
41
- * 🛠️ Content-Length Fix untuk Bun:
42
- * Reset content-length pada:
43
- * 1. GET requests
44
- * 2. OPTIONS (CORS)
45
- * 3. Non-JSON requests
46
- */
47
- app.use((req, res, next) => {
48
- if (
49
- req.method === 'GET' ||
50
- req.method === 'OPTIONS' ||
51
- !req.is('application/json')
52
- ) {
53
- req.headers['content-length'] = undefined;
54
- }
55
- next();
56
- });
57
-
58
- // Basic middleware
59
- app.use(express.json())
60
- app.use(express.urlencoded({ extended: true }))
61
-
62
- // Setup simple logging middleware
63
- XMiddleware.setup({
64
- // Global middleware
65
- global: [
66
- async (req, res, next) => {
67
- console.log(\`🚀 \${req.method} \${req.path}\`)
68
- next()
69
- }
70
- ],
71
-
72
- // Route specific middleware
73
- /*
74
- routes: {
75
- '/products/*': [
76
- async (req, res, next) => {
77
- console.log('📦 Products Route accessed')
78
- next()
79
- }
80
- ],
81
-
82
- '/users': [
83
- async (req, res, next) => {
84
- console.log('👥 Users Route accessed!')
85
- next()
86
- }
87
- ],
88
-
89
- '/users/*': [
90
- async (req, res, next) => {
91
- console.log('👤 User Detail Route accessed!')
92
- next()
93
- }
94
- ]
95
- }
96
- */
97
-
98
- // Jika pakai middleware dari file lain
99
- // Import dulu middlewarenya di paling atas
100
- /*
101
- routes: {
102
- '/products/*': [
103
- authMiddleware,
104
- loggerMiddleware,
105
- multerMiddleware
106
- ]
107
- }
108
- */
109
- })
110
-
111
- // Start server dgn auto-routing
112
- await XRoutes.createServer(app, { dir: 'src' })
113
-
114
- // Test MongoDB connection before starting server
115
- let isMongoConnected = false
116
- try {
117
- await connect()
118
- isMongoConnected = true
119
- } catch (error: unknown) {
120
- console.error('❌ MongoDB Connection Error:', (error as Error).message)
121
- }
122
-
123
- app.listen(port, () => {
124
- console.log(\`🚀 Server is running on:
125
- - Port: http://localhost:\${port}
126
- - Environment: \${process.env.NODE_ENV || 'development'}
127
- - MongoDB: \${isMongoConnected ? 'Connected' : 'Failed to connect'}\`)
128
- })
129
- `
@@ -1,43 +0,0 @@
1
- export default `import fs from "fs/promises";
2
- import { getCollection } from "@config/mongodb";
3
- import { ObjectId } from "mongodb";
4
- import type { {{MODEL}} } from "@modules/{{MODEL_LC}}/{{MODEL_LC}}.schema";
5
-
6
- /*
7
- * 📚 Tutorial Model Seeder:
8
- * 1. Template ini bikin seeder utk masing2 model
9
- * 2. Dia baca data dari file JSON di src/data/
10
- * 3. Nambahin field yg dibutuhin kyk _id, createdAt, updatedAt
11
- * 4. Masukin data ke MongoDB
12
- */
13
-
14
- const collectionName = "{{MODEL_PLURAL}}"
15
-
16
- export const seed{{MODEL_PLURAL}} = async () => {
17
- /*
18
- * 🔄 Langkah2 Seeding:
19
- * 1. Ambil referensi collection
20
- * 2. Baca data JSON
21
- * 3. Ubah data (tambahin ID & timestamp)
22
- * 4. Masukin ke database
23
- */
24
- try {
25
- const {{MODEL_LC}}Collection = await getCollection(collectionName);
26
-
27
- const {{MODEL_LC_PLURAL}} = JSON.parse(
28
- await fs.readFile("./src/data/{{MODEL_LC_PLURAL}}.json", "utf-8")
29
- );
30
-
31
- {{MODEL_LC_PLURAL}}.map((el: {{MODEL}}) => {
32
- el._id = new ObjectId();
33
- el.createdAt = new Date();
34
- el.updatedAt = new Date();
35
- return el;
36
- });
37
-
38
- await {{MODEL_LC}}Collection.insertMany({{MODEL_LC_PLURAL}});
39
- console.log("{{MODEL}} seeding completed successfully.");
40
- } catch (error) {
41
- console.error("Error seeding {{MODEL_LC_PLURAL}}:", error);
42
- }
43
- }`
@@ -1,47 +0,0 @@
1
- export default `import { getCollection } from "../../config/mongodb"
2
- import { ObjectId } from "mongodb"
3
-
4
- import type {
5
- Create{{MODEL}},
6
- {{MODEL}},
7
- {{MODEL}}Id,
8
- Update{{MODEL}}
9
- } from "./{{MODEL_LC}}.schema"
10
-
11
- const {{MODEL_LC_PLURAL}} = await getCollection("{{MODEL_PLURAL}}")
12
-
13
- export const {{MODEL_LC}}Repository = {
14
-
15
- create: async (data: Create{{MODEL}}) => {
16
- const result = await {{MODEL_LC_PLURAL}}.insertOne({
17
- ...data,
18
- createdAt: new Date(),
19
- updatedAt: new Date()
20
- })
21
- return { _id: result.insertedId, ...data } as {{MODEL}}
22
- },
23
-
24
- findAll: async () => {
25
- return await {{MODEL_LC_PLURAL}}.find().toArray() as {{MODEL}}[]
26
- },
27
-
28
- findById: async ({ id }: {{MODEL}}Id) => {
29
- return await {{MODEL_LC_PLURAL}}.findOne(
30
- { _id: new ObjectId(id) }
31
- ) as {{MODEL}} | null
32
- },
33
-
34
- update: async ({ id }: {{MODEL}}Id, data: Update{{MODEL}}) => {
35
- return await {{MODEL_LC_PLURAL}}.findOneAndUpdate(
36
- { _id: new ObjectId(id) },
37
- { $set: { ...data, updatedAt: new Date() } },
38
- { returnDocument: "after" }
39
- )
40
- },
41
-
42
- delete: async ({ id }: {{MODEL}}Id) => {
43
- return await {{MODEL_LC_PLURAL}}.findOneAndDelete(
44
- { _id: new ObjectId(id) }
45
- )
46
- }
47
- }`
@@ -1,53 +0,0 @@
1
- export const routeController = (MODEL, MODEL_PLURAL, MODEL_LC_PLURAL) => `import type { Request, Response, NextFunction } from 'express'
2
- import { ${MODEL}Service } from "@modules/${MODEL.toLowerCase()}/${MODEL.toLowerCase()}.service"
3
-
4
- export async function GET(req: Request, res: Response, next: NextFunction) {
5
- try {
6
- const ${MODEL_LC_PLURAL} = await ${MODEL}Service.getAll${MODEL_PLURAL}()
7
- res.status(${MODEL_LC_PLURAL}.status).json(${MODEL_LC_PLURAL})
8
- } catch (error) {
9
- next(error)
10
- }
11
- }
12
-
13
- export async function POST(req: Request, res: Response, next: NextFunction) {
14
- try {
15
- const ${MODEL.toLowerCase()} = await ${MODEL}Service.create${MODEL}(req.body)
16
- res.status(${MODEL.toLowerCase()}.status).json(${MODEL.toLowerCase()})
17
- } catch (error) {
18
- next(error)
19
- }
20
- }`
21
-
22
- export const routeIdController = (MODEL) => `import type { Request, Response, NextFunction } from 'express'
23
- import { ${MODEL}Service } from "@modules/${MODEL.toLowerCase()}/${MODEL.toLowerCase()}.service"
24
-
25
- export async function GET(req: Request, res: Response, next: NextFunction) {
26
- try {
27
- const { id } = req.params
28
- const ${MODEL.toLowerCase()} = await ${MODEL}Service.get${MODEL}ById({ id })
29
- res.status(${MODEL.toLowerCase()}.status).json(${MODEL.toLowerCase()})
30
- } catch (error) {
31
- next(error)
32
- }
33
- }
34
-
35
- export async function PUT(req: Request, res: Response, next: NextFunction) {
36
- try {
37
- const { id } = req.params
38
- const ${MODEL.toLowerCase()} = await ${MODEL}Service.update${MODEL}({ id }, req.body)
39
- res.status(${MODEL.toLowerCase()}.status).json(${MODEL.toLowerCase()})
40
- } catch (error) {
41
- next(error)
42
- }
43
- }
44
-
45
- export async function DELETE(req: Request, res: Response, next: NextFunction) {
46
- try {
47
- const { id } = req.params
48
- const ${MODEL.toLowerCase()} = await ${MODEL}Service.delete${MODEL}({ id })
49
- res.status(${MODEL.toLowerCase()}.status).json(${MODEL.toLowerCase()})
50
- } catch (error) {
51
- next(error)
52
- }
53
- }`
@@ -1,53 +0,0 @@
1
- export default `import { z } from "zod"
2
- import { ObjectId } from "mongodb"
3
-
4
- /*
5
- * 📚 Quick Zod Guide:
6
- *
7
- * Contoh validasi dgn message:
8
- * const userSchema = z.object({
9
- * name: z.string().min(2, "Minimal 2 karakter"),
10
- * email: z.string().email("Email tidak valid"),
11
- * age: z.number().min(17, "Minimal umur 17 tahun")
12
- * })
13
- */
14
-
15
- // Base schema yg shared di semua operations
16
- const {{MODEL}}BaseSchema = z.object({
17
- {{FIELDS}}
18
- })
19
-
20
- const WithIdSchema = z.object({
21
- _id: z.instanceof(ObjectId)
22
- })
23
-
24
- const TimestampSchema = z.object({
25
- createdAt: z.date(),
26
- updatedAt: z.date()
27
- })
28
-
29
- const {{MODEL}}IdSchema = z.object({
30
- id: z.string().regex(/^[0-9a-fA-F]{24}$/)
31
- })
32
-
33
- const Create{{MODEL}}Schema = {{MODEL}}BaseSchema
34
-
35
- const {{MODEL}}Schema = {{MODEL}}BaseSchema
36
- .merge(WithIdSchema)
37
- .merge(TimestampSchema)
38
-
39
- const Update{{MODEL}}Schema = {{MODEL}}BaseSchema.partial()
40
-
41
- // Export types
42
- export type Create{{MODEL}} = z.infer<typeof Create{{MODEL}}Schema>
43
- export type {{MODEL}} = z.infer<typeof {{MODEL}}Schema>
44
- export type Update{{MODEL}} = z.infer<typeof Update{{MODEL}}Schema>
45
- export type {{MODEL}}Id = z.infer<typeof {{MODEL}}IdSchema>
46
-
47
- // Export schemas
48
- export {
49
- Create{{MODEL}}Schema,
50
- {{MODEL}}Schema,
51
- Update{{MODEL}}Schema,
52
- {{MODEL}}IdSchema
53
- }`
@@ -1,62 +0,0 @@
1
- export default `import { connect, getDb } from "@config/mongodb";
2
- {{IMPORTS}}
3
-
4
- /*
5
- * 📚 Tutorial: Proses Seeding
6
- * 1. File ini adalah seeder utama yg ngatur semua operasi seeding
7
- * 2. Pertama, dia bakal drop collection yg udh ada biar datanya bersih
8
- * 3. Trus jalanin semua seeder secara bersamaan pake Promise.all
9
- */
10
-
11
- async function dropCollections() {
12
- /*
13
- * 🔍 Gmn cara kerja dropCollections:
14
- * - Dapetin koneksi database
15
- * - Coba drop tiap collection
16
- * - Handle kasus klo collection blm ada
17
- */
18
- try {
19
- const db = await getDb();
20
-
21
- const collections = [{{COLLECTIONS}}];
22
-
23
- for (const collectionName of collections) {
24
- try {
25
- await db.collection(collectionName).drop();
26
- } catch {
27
- console.log(\`⚠️ \${collectionName} collection not found, skipping...\`);
28
- }
29
- }
30
-
31
- console.log("✨ Successfully dropped all collections!");
32
- } catch (error) {
33
- console.error("❌ Failed to drop collections:", error);
34
- throw error;
35
- }
36
- }
37
-
38
- async function seed() {
39
- /*
40
- * 🌱 Langkah2 Proses Seeding:
41
- * 1. Konek ke MongoDB
42
- * 2. Drop collection yg udh ada
43
- * 3. Jalanin semua seeder barengan
44
- * 4. Exit process klo udh selesai
45
- */
46
- try {
47
- await connect();
48
- await dropCollections();
49
-
50
- await Promise.all([
51
- {{SEEDERS}}
52
- ]);
53
-
54
- console.log("🌱 Seeding completed successfully!");
55
- } catch (error) {
56
- console.error("❌ Seeding failed:", error);
57
- } finally {
58
- process.exit(0);
59
- }
60
- }
61
-
62
- seed();`
@@ -1,103 +0,0 @@
1
- export default `import { {{MODEL_LC}}Repository } from "./{{MODEL_LC}}.repository"
2
- import type { Create{{MODEL}}, {{MODEL}}Id, Update{{MODEL}} } from "./{{MODEL_LC}}.schema"
3
- import { Create{{MODEL}}Schema, {{MODEL}}IdSchema, Update{{MODEL}}Schema } from "./{{MODEL_LC}}.schema"
4
-
5
- export class {{MODEL}}Service {
6
-
7
- static async create{{MODEL}}({{MODEL_LC}}: Create{{MODEL}}) {
8
- try {
9
- const validated = Create{{MODEL}}Schema.parse({{MODEL_LC}})
10
- const result = await {{MODEL_LC}}Repository.create(validated)
11
-
12
- return {
13
- success: true,
14
- status: 201,
15
- data: result
16
- }
17
-
18
- } catch (error) {
19
- throw error
20
- }
21
- }
22
-
23
- static async getAll{{MODEL_PLURAL}}() {
24
- try {
25
- const {{MODEL_LC_PLURAL}} = await {{MODEL_LC}}Repository.findAll()
26
-
27
- if ({{MODEL_LC_PLURAL}}.length === 0) {
28
- throw new Error("No {{MODEL_LC_PLURAL}} found")
29
- }
30
-
31
- return {
32
- success: true,
33
- status: 200,
34
- data: {{MODEL_LC_PLURAL}}
35
- }
36
-
37
- } catch (error) {
38
- throw error
39
- }
40
- }
41
-
42
- static async get{{MODEL}}ById(params: {{MODEL}}Id) {
43
- try {
44
- const { id } = {{MODEL}}IdSchema.parse(params)
45
- const {{MODEL_LC}} = await {{MODEL_LC}}Repository.findById({ id })
46
-
47
- if (!{{MODEL_LC}}) {
48
- throw new Error("{{MODEL}} not found")
49
- }
50
-
51
- return {
52
- success: true,
53
- status: 200,
54
- data: {{MODEL_LC}}
55
- }
56
-
57
- } catch (error) {
58
- throw error
59
- }
60
- }
61
-
62
- static async update{{MODEL}}(params: {{MODEL}}Id, data: Update{{MODEL}}) {
63
- try {
64
- const { id } = {{MODEL}}IdSchema.parse(params)
65
- const validated = Update{{MODEL}}Schema.parse(data)
66
-
67
- const result = await {{MODEL_LC}}Repository.update({ id }, validated)
68
-
69
- if (!result) {
70
- throw new Error("{{MODEL}} not found")
71
- }
72
-
73
- return {
74
- success: true,
75
- status: 200,
76
- data: result
77
- }
78
-
79
- } catch (error) {
80
- throw error
81
- }
82
- }
83
-
84
- static async delete{{MODEL}}(params: {{MODEL}}Id) {
85
- try {
86
- const { id } = {{MODEL}}IdSchema.parse(params)
87
- const result = await {{MODEL_LC}}Repository.delete({ id })
88
-
89
- if (!result) {
90
- throw new Error("{{MODEL}} not found")
91
- }
92
-
93
- return {
94
- success: true,
95
- status: 200,
96
- data: result
97
- }
98
-
99
- } catch (error) {
100
- throw error
101
- }
102
- }
103
- }`
@@ -1,72 +0,0 @@
1
- export default `import { {{MODEL_LC}}Repository } from "./{{MODEL_LC}}.repository"
2
- import type { Create{{MODEL}} } from "./{{MODEL_LC}}.schema"
3
- import { Create{{MODEL}}Schema } from "./{{MODEL_LC}}.schema"
4
- import { hash, compare } from "@utils/bcrypt"
5
- import { createToken } from "@utils/jwt"
6
-
7
- export class Auth{{MODEL}}Service {
8
- static async login(email: string, password: string) {
9
- try {
10
- const user = await {{MODEL_LC}}Repository.findByEmail(email)
11
-
12
- if (!user) {
13
- throw new Error("Invalid credentials")
14
- }
15
-
16
- const isValidPassword = await compare(password, user.password)
17
-
18
- if (!isValidPassword) {
19
- throw new Error("Invalid credentials")
20
- }
21
-
22
- const token = await createToken({
23
- userId: user._id.toString(),
24
- email: user.email
25
- })
26
-
27
- // Remove password from response
28
- const { password: _, ...userWithoutPassword } = user
29
-
30
- return {
31
- success: true,
32
- status: 200,
33
- data: { user: userWithoutPassword, token }
34
- }
35
- } catch (error) {
36
- throw error
37
- }
38
- }
39
-
40
- static async register(data: Create{{MODEL}}) {
41
- try {
42
- const validated = Create{{MODEL}}Schema.parse(data)
43
-
44
- // Check if email already exists
45
- const existing = await {{MODEL_LC}}Repository.findByEmail(validated.email)
46
- if (existing) {
47
- throw new Error("Email already registered")
48
- }
49
-
50
- // Hash password
51
- validated.password = await hash(validated.password)
52
-
53
- const result = await {{MODEL_LC}}Repository.create(validated)
54
- const token = await createToken({
55
- userId: result._id.toString(),
56
- email: result.email
57
- })
58
-
59
- // Remove password from response
60
- const { password: _, ...userWithoutPassword } = result
61
-
62
- return {
63
- success: true,
64
- status: 201,
65
- data: { user: userWithoutPassword, token }
66
- }
67
-
68
- } catch (error) {
69
- throw error
70
- }
71
- }
72
- }`
@@ -1,21 +0,0 @@
1
- export default `import type { Request, Response, NextFunction } from 'express'
2
- import { {{MODEL}}Service } from "@modules/{{MODEL_LC}}/{{MODEL_LC}}.service"
3
-
4
- export async function GET(req: Request, res: Response, next: NextFunction) {
5
- try {
6
- const result = await {{MODEL}}Service.getAll{{MODEL}}s()
7
- res.status(result.status).json(result)
8
- } catch (error) {
9
- next(error)
10
- }
11
- }
12
-
13
- // Create user (admin only)
14
- export async function POST(req: Request, res: Response, next: NextFunction) {
15
- try {
16
- const result = await {{MODEL}}Service.create{{MODEL}}(req.body)
17
- res.status(result.status).json(result)
18
- } catch (error) {
19
- next(error)
20
- }
21
- }`
@@ -1,32 +0,0 @@
1
- export default `import type { Request, Response, NextFunction } from 'express'
2
- import { {{MODEL}}Service } from "@modules/{{MODEL_LC}}/{{MODEL_LC}}.service"
3
-
4
- export async function GET(req: Request, res: Response, next: NextFunction) {
5
- try {
6
- const { id } = req.params
7
- const result = await {{MODEL}}Service.get{{MODEL}}ById({ id })
8
- res.status(result.status).json(result)
9
- } catch (error) {
10
- next(error)
11
- }
12
- }
13
-
14
- export async function PUT(req: Request, res: Response, next: NextFunction) {
15
- try {
16
- const { id } = req.params
17
- const result = await {{MODEL}}Service.update{{MODEL}}({ id }, req.body)
18
- res.status(result.status).json(result)
19
- } catch (error) {
20
- next(error)
21
- }
22
- }
23
-
24
- export async function DELETE(req: Request, res: Response, next: NextFunction) {
25
- try {
26
- const { id } = req.params
27
- const result = await {{MODEL}}Service.delete{{MODEL}}({ id })
28
- res.status(result.status).json(result)
29
- } catch (error) {
30
- next(error)
31
- }
32
- }`
@@ -1,11 +0,0 @@
1
- export default `import type { Request, Response, NextFunction } from 'express'
2
- import { Auth{{MODEL}}Service } from "@modules/{{MODEL_LC}}/auth.service"
3
-
4
- export async function POST(req: Request, res: Response, next: NextFunction) {
5
- try {
6
- const result = await Auth{{MODEL}}Service.register(req.body)
7
- res.status(result.status).json(result)
8
- } catch (error) {
9
- next(error)
10
- }
11
- }`
@@ -1,59 +0,0 @@
1
- export default `import { getCollection } from "../../config/mongodb"
2
- import { ObjectId } from "mongodb"
3
-
4
- import type {
5
- Create{{MODEL}},
6
- {{MODEL}},
7
- {{MODEL}}Id,
8
- Update{{MODEL}}
9
- } from "./{{MODEL_LC}}.schema"
10
-
11
- const {{MODEL_LC}}s = await getCollection("{{MODEL}}s")
12
-
13
- export const {{MODEL_LC}}Repository = {
14
-
15
- create: async (data: Create{{MODEL}}) => {
16
- const result = await {{MODEL_LC}}s.insertOne({
17
- ...data,
18
- createdAt: new Date(),
19
- updatedAt: new Date()
20
- })
21
- return { _id: result.insertedId, ...data } as {{MODEL}}
22
- },
23
-
24
- findAll: async () => {
25
- return await {{MODEL_LC}}s.find({}, { projection: { password: 0 } }).toArray() as {{MODEL}}[]
26
- },
27
-
28
- findById: async ({ id }: {{MODEL}}Id) => {
29
- return await {{MODEL_LC}}s.findOne(
30
- { _id: new ObjectId(id) },
31
- { projection: { password: 0 } }
32
- ) as {{MODEL}} | null
33
- },
34
-
35
- // Khusus User: findByEmail (tetap include password utk login)
36
- findByEmail: async (email: string) => {
37
- return await {{MODEL_LC}}s.findOne({ email }) as {{MODEL}} | null
38
- },
39
-
40
- update: async ({ id }: {{MODEL}}Id, data: Update{{MODEL}}) => {
41
- const result = await {{MODEL_LC}}s.findOneAndUpdate(
42
- { _id: new ObjectId(id) },
43
- { $set: { ...data, updatedAt: new Date() } },
44
- {
45
- returnDocument: "after",
46
- projection: { password: 0 }
47
- }
48
- )
49
- return result
50
- },
51
-
52
- delete: async ({ id }: {{MODEL}}Id) => {
53
- const result = await {{MODEL_LC}}s.findOneAndDelete(
54
- { _id: new ObjectId(id) },
55
- { projection: { password: 0 } }
56
- )
57
- return result
58
- }
59
- }`
@@ -1,33 +0,0 @@
1
- export default `import fs from "fs/promises"
2
- import { getCollection } from "@config/mongodb"
3
- import { ObjectId } from "mongodb"
4
- import type { User } from "@modules/user/user.schema"
5
- import { hash } from "@utils/bcrypt"
6
-
7
- const collectionName = "Users"
8
-
9
- export const seedUsers = async () => {
10
- try {
11
- const userCollection = await getCollection(collectionName)
12
-
13
- const users = JSON.parse(
14
- await fs.readFile("./src/data/users.json", "utf-8")
15
- )
16
-
17
- // Hash passwords before inserting
18
- const usersWithHashedPasswords = await Promise.all(
19
- users.map(async (el: User) => {
20
- el._id = new ObjectId()
21
- el.password = await hash(el.password)
22
- el.createdAt = new Date()
23
- el.updatedAt = new Date()
24
- return el
25
- })
26
- )
27
-
28
- await userCollection.insertMany(usersWithHashedPasswords)
29
- console.log("User seeding completed successfully.")
30
- } catch (error) {
31
- console.error("Error seeding users:", error)
32
- }
33
- }`
@@ -1,173 +0,0 @@
1
- export default `import { {{MODEL_LC}}Repository } from "./{{MODEL_LC}}.repository"
2
- import type { Create{{MODEL}}, {{MODEL}}Id, Update{{MODEL}} } from "./{{MODEL_LC}}.schema"
3
- import { Create{{MODEL}}Schema, {{MODEL}}IdSchema, Update{{MODEL}}Schema } from "./{{MODEL_LC}}.schema"
4
- import { hash, compare } from "@utils/bcrypt"
5
- import { createToken } from "@utils/jwt"
6
-
7
- export class {{MODEL}}Service {
8
- static async create{{MODEL}}({{MODEL_LC}}: Create{{MODEL}}) {
9
- try {
10
- const validated = Create{{MODEL}}Schema.parse({{MODEL_LC}})
11
-
12
- // Hash password before saving
13
- validated.password = await hash(validated.password)
14
-
15
- const result = await {{MODEL_LC}}Repository.create(validated)
16
-
17
- return {
18
- success: true,
19
- status: 201,
20
- data: result
21
- }
22
-
23
- } catch (error) {
24
- throw error
25
- }
26
- }
27
-
28
- static async getAll{{MODEL}}s() {
29
- try {
30
- const {{MODEL_LC}}s = await {{MODEL_LC}}Repository.findAll()
31
-
32
- if ({{MODEL_LC}}s.length === 0) {
33
- throw new Error("No {{MODEL_LC}}s found")
34
- }
35
-
36
- return {
37
- success: true,
38
- status: 200,
39
- data: {{MODEL_LC}}s
40
- }
41
-
42
- } catch (error) {
43
- throw error
44
- }
45
- }
46
-
47
- static async get{{MODEL}}ById(params: {{MODEL}}Id) {
48
- try {
49
- const { id } = {{MODEL}}IdSchema.parse(params)
50
- const {{MODEL_LC}} = await {{MODEL_LC}}Repository.findById({ id })
51
-
52
- if (!{{MODEL_LC}}) {
53
- throw new Error("{{MODEL}} not found")
54
- }
55
-
56
- return {
57
- success: true,
58
- status: 200,
59
- data: {{MODEL_LC}}
60
- }
61
-
62
- } catch (error) {
63
- throw error
64
- }
65
- }
66
-
67
- static async update{{MODEL}}(params: {{MODEL}}Id, data: Update{{MODEL}}) {
68
- try {
69
- const { id } = {{MODEL}}IdSchema.parse(params)
70
- const validated = Update{{MODEL}}Schema.parse(data)
71
-
72
- // Hash password if it's being updated
73
- if (validated.password) {
74
- validated.password = await hash(validated.password)
75
- }
76
-
77
- const result = await {{MODEL_LC}}Repository.update({ id }, validated)
78
-
79
- if (!result) {
80
- throw new Error("{{MODEL}} not found")
81
- }
82
-
83
- return {
84
- success: true,
85
- status: 200,
86
- data: result
87
- }
88
-
89
- } catch (error) {
90
- throw error
91
- }
92
- }
93
-
94
- static async delete{{MODEL}}(params: {{MODEL}}Id) {
95
- try {
96
- const { id } = {{MODEL}}IdSchema.parse(params)
97
- const result = await {{MODEL_LC}}Repository.delete({ id })
98
-
99
- if (!result) {
100
- throw new Error("{{MODEL}} not found")
101
- }
102
-
103
- return {
104
- success: true,
105
- status: 200,
106
- data: result
107
- }
108
-
109
- } catch (error) {
110
- throw error
111
- }
112
- }
113
-
114
- // Auth methods
115
- static async login(email: string, password: string) {
116
- try {
117
- const user = await {{MODEL_LC}}Repository.findByEmail(email)
118
-
119
- if (!user) {
120
- throw new Error("Invalid credentials")
121
- }
122
-
123
- const isValidPassword = await compare(password, user.password)
124
-
125
- if (!isValidPassword) {
126
- throw new Error("Invalid credentials")
127
- }
128
-
129
- const token = await createToken({
130
- userId: user._id.toString(),
131
- email: user.email
132
- })
133
-
134
- return {
135
- success: true,
136
- status: 200,
137
- data: { user, token }
138
- }
139
- } catch (error) {
140
- throw error
141
- }
142
- }
143
-
144
- static async register(data: Create{{MODEL}}) {
145
- try {
146
- const validated = Create{{MODEL}}Schema.parse(data)
147
-
148
- // Check if email already exists
149
- const existing = await {{MODEL_LC}}Repository.findByEmail(validated.email)
150
- if (existing) {
151
- throw new Error("Email already registered")
152
- }
153
-
154
- // Hash password
155
- validated.password = await hash(validated.password)
156
-
157
- const result = await {{MODEL_LC}}Repository.create(validated)
158
- const token = await createToken({
159
- userId: result._id.toString(),
160
- email: result.email
161
- })
162
-
163
- return {
164
- success: true,
165
- status: 201,
166
- data: { user: result, token }
167
- }
168
-
169
- } catch (error) {
170
- throw error
171
- }
172
- }
173
- }`
@@ -1,24 +0,0 @@
1
- export default `import type { Request, Response, NextFunction } from 'express'
2
- import { Auth{{MODEL}}Service } from "@modules/{{MODEL_LC}}/auth.service"
3
-
4
- export async function POST(req: Request, res: Response, next: NextFunction) {
5
- try {
6
- const { email, password } = req.body
7
- const result = await Auth{{MODEL}}Service.login(email, password)
8
- res.status(result.status).json(result)
9
- } catch (error) {
10
- next(error)
11
- }
12
- }
13
-
14
- export async function DELETE(req: Request, res: Response, next: NextFunction) {
15
- try {
16
- // Handle logout (invalidate token, clear cookie etc)
17
- res.status(200).json({
18
- success: true,
19
- message: "Logged out successfully"
20
- })
21
- } catch (error) {
22
- next(error)
23
- }
24
- }`
@@ -1,15 +0,0 @@
1
- export default `import bcrypt from "bcryptjs"
2
-
3
- export const hash = async (
4
- password: string,
5
- saltRounds: number = 10
6
- ): Promise<string> => {
7
- return await bcrypt.hash(password, saltRounds)
8
- }
9
-
10
- export const compare = async (
11
- password: string,
12
- hash: string
13
- ): Promise<boolean> => {
14
- return await bcrypt.compare(password, hash)
15
- }`
@@ -1,33 +0,0 @@
1
- export default `import jwt from "jsonwebtoken"
2
-
3
- interface TokenPayload {
4
- userId: string
5
- email: string
6
- role?: string
7
- }
8
-
9
- const JWT_SECRET = process.env.JWT_SECRET || "your-secret-key"
10
- const JWT_EXPIRES_IN = "24h"
11
-
12
- export const createToken = async (payload: TokenPayload): Promise<string> => {
13
- return new Promise((resolve, reject) => {
14
- jwt.sign(
15
- payload,
16
- JWT_SECRET,
17
- { expiresIn: JWT_EXPIRES_IN },
18
- (error, token) => {
19
- if (error) reject(error)
20
- resolve(token as string)
21
- }
22
- )
23
- })
24
- }
25
-
26
- export const verifyToken = async (token: string): Promise<TokenPayload> => {
27
- return new Promise((resolve, reject) => {
28
- jwt.verify(token, JWT_SECRET, (error, decoded) => {
29
- if (error) reject(error)
30
- resolve(decoded as TokenPayload)
31
- })
32
- })
33
- }`
@@ -1,60 +0,0 @@
1
- import repository from './files/repository.js'
2
- import schema from './files/schema.js'
3
- import service from './files/service.js'
4
- import rootIndex from './files/index.js'
5
- import homeController from './files/home-controller.js'
6
- import mongodbConfig from './files/config/mongodb-config.js'
7
- import mongodbJson from './files/config/mongodb-json.js'
8
- import seederIndex from './files/seeder-index.js'
9
- import modelSeeder from './files/model-seeder.js'
10
- import errorHandler from './files/error-handler.js'
11
- import { routeController, routeIdController } from './files/route-controller.js'
12
-
13
- // User specific templates
14
- import bcryptUtil from './files/utils/bcrypt.js'
15
- import jwtUtil from './files/utils/jwt.js'
16
- import userRepository from './files/user/repository.js'
17
- import userService from './files/user/service.js'
18
- import userController from './files/user/controller.js'
19
- import userIdController from './files/user/id-controller.js'
20
- import userSessionsController from './files/user/sessions-controller.js'
21
- import userRegisterController from './files/user/register-controller.js'
22
- import userSeeder from './files/user/seeder.js'
23
- import userAuthService from './files/user/auth-service.js'
24
-
25
- const gitignoreContent = `node_modules
26
- .env
27
- .DS_Store
28
- dist
29
- .turbo`
30
-
31
- const templates = {
32
- // Standard templates
33
- repository,
34
- schema,
35
- service,
36
- rootIndex,
37
- homeController,
38
- mongodbConfig,
39
- mongodbJson,
40
- gitignore: gitignoreContent,
41
- seederIndex,
42
- modelSeeder,
43
- errorHandler,
44
- routeController,
45
- routeIdController,
46
-
47
- // User specific templates
48
- bcryptUtil,
49
- jwtUtil,
50
- userRepository,
51
- userService,
52
- userController,
53
- userIdController,
54
- userSessionsController,
55
- userRegisterController,
56
- userSeeder,
57
- userAuthService
58
- }
59
-
60
- export default templates