kontas-express 1.0.1 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.js +3 -0
- package/package.json +13 -4
- package/index.js +0 -1
- package/jsconfig.json +0 -27
- package/templates/files/config/mongodb-config.js +0 -45
- package/templates/files/config/mongodb-json.js +0 -14
- package/templates/files/error-handler.js +0 -54
- package/templates/files/home-controller.js +0 -7
- package/templates/files/index.js +0 -129
- package/templates/files/model-seeder.js +0 -43
- package/templates/files/repository.js +0 -47
- package/templates/files/route-controller.js +0 -53
- package/templates/files/schema.js +0 -53
- package/templates/files/seeder-index.js +0 -62
- package/templates/files/service.js +0 -103
- package/templates/files/user/auth-service.js +0 -72
- package/templates/files/user/controller.js +0 -21
- package/templates/files/user/id-controller.js +0 -32
- package/templates/files/user/register-controller.js +0 -11
- package/templates/files/user/repository.js +0 -59
- package/templates/files/user/seeder.js +0 -33
- package/templates/files/user/service.js +0 -173
- package/templates/files/user/sessions-controller.js +0 -24
- package/templates/files/utils/bcrypt.js +0 -15
- package/templates/files/utils/jwt.js +0 -33
- package/templates/index.js +0 -60
package/dist/index.js
ADDED
package/package.json
CHANGED
@@ -1,13 +1,22 @@
|
|
1
1
|
{
|
2
2
|
"name": "kontas-express",
|
3
|
-
"version": "1.0.
|
4
|
-
"main": "index.js",
|
3
|
+
"version": "1.0.3",
|
4
|
+
"main": "dist/index.js",
|
5
5
|
"scripts": {
|
6
|
-
"
|
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,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
|
-
}`
|
package/templates/files/index.js
DELETED
@@ -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
|
-
}`
|
package/templates/index.js
DELETED
@@ -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
|