kontas-express 1.0.1 → 1.0.3

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/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.3",
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