create-lumina-project 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +73 -0
- package/package.json +28 -0
- package/template/.env.example +15 -0
- package/template/.sequelizerc +11 -0
- package/template/_gitignore +3 -0
- package/template/nodemon.json +5 -0
- package/template/package.json +53 -0
- package/template/public/img/logo1.png +0 -0
- package/template/public/img/logo2.png +0 -0
- package/template/scripts/create-controller.ts +89 -0
- package/template/scripts/create-factory.ts +98 -0
- package/template/scripts/create-migration.ts +98 -0
- package/template/scripts/create-model.ts +105 -0
- package/template/scripts/maintenance.ts +73 -0
- package/template/scripts/migrate.ts +146 -0
- package/template/scripts/seed.ts +42 -0
- package/template/scripts/stubs/controller.stub +50 -0
- package/template/scripts/stubs/factory.stub +19 -0
- package/template/scripts/stubs/migration.stub +44 -0
- package/template/scripts/stubs/model.stub +39 -0
- package/template/server.ts +63 -0
- package/template/src/config/database.ts +39 -0
- package/template/src/controllers/AuthController.ts +21 -0
- package/template/src/controllers/UserController.ts +52 -0
- package/template/src/database/factories/Factory.ts +33 -0
- package/template/src/database/factories/UserFactory.ts +26 -0
- package/template/src/database/migrations/20260205084944-create_user.js +68 -0
- package/template/src/database/seeders/DatabaseSeeder.js +32 -0
- package/template/src/exceptions/Handler.ts +32 -0
- package/template/src/middlewares/Authentication.ts +34 -0
- package/template/src/middlewares/Limiter.ts +34 -0
- package/template/src/middlewares/Maintenance.ts +37 -0
- package/template/src/middlewares/Validator.ts +29 -0
- package/template/src/models/User.ts +91 -0
- package/template/src/models/index.ts +92 -0
- package/template/src/requests/UserRequest.ts +26 -0
- package/template/src/routes/api.ts +30 -0
- package/template/src/routes/web.ts +29 -0
- package/template/src/services/AuthService.ts +29 -0
- package/template/src/services/RouteService.ts +15 -0
- package/template/src/services/StorageService.ts +59 -0
- package/template/src/services/UserService.ts +31 -0
- package/template/src/types/Pagination.d.ts +13 -0
- package/template/src/types/express/index.d.ts +9 -0
- package/template/src/utils/ApiResponse.ts +27 -0
- package/template/src/utils/Hash.ts +21 -0
- package/template/src/utils/Logger.ts +79 -0
- package/template/src/utils/Paginator.ts +41 -0
- package/template/tsconfig.json +24 -0
- package/template/views/maintenance.html +42 -0
- package/template/views/welcome.html +62 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import winston from 'winston';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import dotenv from 'dotenv';
|
|
4
|
+
|
|
5
|
+
dotenv.config();
|
|
6
|
+
|
|
7
|
+
class Logger {
|
|
8
|
+
private logger: winston.Logger;
|
|
9
|
+
|
|
10
|
+
constructor() {
|
|
11
|
+
// Define the custom format (Timestamp + Level + Message)
|
|
12
|
+
const logFormat = winston.format.printf(({ level, message, timestamp }) => {
|
|
13
|
+
return `${timestamp} [${level}]: ${message}`;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
this.logger = winston.createLogger({
|
|
17
|
+
level: process.env.LOG_LEVEL || 'info',
|
|
18
|
+
format: winston.format.combine(
|
|
19
|
+
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
|
20
|
+
winston.format.errors({ stack: true }),
|
|
21
|
+
winston.format.splat(),
|
|
22
|
+
logFormat
|
|
23
|
+
),
|
|
24
|
+
transports: [
|
|
25
|
+
// 1. Write all logs with level 'error' and below to error.log
|
|
26
|
+
new winston.transports.File({
|
|
27
|
+
filename: path.join(process.cwd(), 'logs', 'error.log'),
|
|
28
|
+
level: 'error'
|
|
29
|
+
}),
|
|
30
|
+
// 2. Write all logs to combined.log
|
|
31
|
+
new winston.transports.File({
|
|
32
|
+
filename: path.join(process.cwd(), 'logs', 'combined.log')
|
|
33
|
+
}),
|
|
34
|
+
],
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// If we're not in production, log to the console with colors
|
|
38
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
39
|
+
this.logger.add(
|
|
40
|
+
new winston.transports.Console({
|
|
41
|
+
format: winston.format.combine(
|
|
42
|
+
winston.format.colorize(),
|
|
43
|
+
winston.format.simple()
|
|
44
|
+
),
|
|
45
|
+
})
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Log an info message.
|
|
52
|
+
*/
|
|
53
|
+
public info(message: string, meta?: any): void {
|
|
54
|
+
this.logger.info(message, meta);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Log an error message.
|
|
59
|
+
*/
|
|
60
|
+
public error(message: string, meta?: any): void {
|
|
61
|
+
this.logger.error(message, meta);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Log a warning message.
|
|
66
|
+
*/
|
|
67
|
+
public warn(message: string, meta?: any): void {
|
|
68
|
+
this.logger.warn(message, meta);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Log a debug message.
|
|
73
|
+
*/
|
|
74
|
+
public debug(message: string, meta?: any): void {
|
|
75
|
+
this.logger.debug(message, meta);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export default new Logger();
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Model, ModelStatic, FindOptions } from 'sequelize';
|
|
2
|
+
import { PaginatedResult } from '../types/Pagination.js';
|
|
3
|
+
|
|
4
|
+
class Paginator {
|
|
5
|
+
/**
|
|
6
|
+
* Paginate a Sequelize Model.
|
|
7
|
+
* * @param model The Sequelize Model class (e.g., User)
|
|
8
|
+
* @param page The current page number (default: 1)
|
|
9
|
+
* @param limit The number of items per page (default: 15)
|
|
10
|
+
* @param options Additional Sequelize query options (where, include, order)
|
|
11
|
+
*/
|
|
12
|
+
public async paginate<T extends Model>(
|
|
13
|
+
model: ModelStatic<T>,
|
|
14
|
+
page: number = 1,
|
|
15
|
+
limit: number = 15,
|
|
16
|
+
options: FindOptions = {}
|
|
17
|
+
): Promise<PaginatedResult<T>> {
|
|
18
|
+
const offset = (page - 1) * limit;
|
|
19
|
+
|
|
20
|
+
// Sequelize's findAndCountAll is perfect for pagination
|
|
21
|
+
const { count, rows } = await model.findAndCountAll({
|
|
22
|
+
...options,
|
|
23
|
+
limit,
|
|
24
|
+
offset,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
data: rows,
|
|
29
|
+
meta: {
|
|
30
|
+
total: count,
|
|
31
|
+
per_page: limit,
|
|
32
|
+
current_page: page,
|
|
33
|
+
last_page: Math.ceil(count / limit),
|
|
34
|
+
from: offset + 1,
|
|
35
|
+
to: offset + rows.length,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default new Paginator();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
/* Base Options */
|
|
4
|
+
"target": "ES2022",
|
|
5
|
+
"module": "NodeNext",
|
|
6
|
+
"moduleResolution": "NodeNext",
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"forceConsistentCasingInFileNames": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"typeRoots": ["./src/types", "./node_modules/@types"],
|
|
12
|
+
|
|
13
|
+
/* Output Options */
|
|
14
|
+
"outDir": "./dist",
|
|
15
|
+
"rootDir": "./src",
|
|
16
|
+
"removeComments": true,
|
|
17
|
+
|
|
18
|
+
/* Experimental Options (Helpful for Decorators if you use them later) */
|
|
19
|
+
"experimentalDecorators": true,
|
|
20
|
+
"emitDecoratorMetadata": true
|
|
21
|
+
},
|
|
22
|
+
"include": ["src/**/*"],
|
|
23
|
+
"exclude": ["node_modules", "**/*.spec.ts"]
|
|
24
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Lumina - Under Maintenance</title>
|
|
7
|
+
<style>
|
|
8
|
+
body {
|
|
9
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
10
|
+
background-color: #f3f4f6;
|
|
11
|
+
display: flex;
|
|
12
|
+
justify-content: center;
|
|
13
|
+
align-items: center;
|
|
14
|
+
height: 100vh;
|
|
15
|
+
margin: 0;
|
|
16
|
+
color: #374151;
|
|
17
|
+
}
|
|
18
|
+
.container {
|
|
19
|
+
text-align: center;
|
|
20
|
+
background: white;
|
|
21
|
+
padding: 3rem;
|
|
22
|
+
border-radius: 1rem;
|
|
23
|
+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
24
|
+
max-width: 500px;
|
|
25
|
+
}
|
|
26
|
+
h1 { font-size: 2.5rem; margin-bottom: 1rem; color: #111827; }
|
|
27
|
+
p { font-size: 1.125rem; color: #6b7280; margin-bottom: 2rem; }
|
|
28
|
+
.icon { font-size: 4rem; margin-bottom: 1rem; }
|
|
29
|
+
small {
|
|
30
|
+
color: red;
|
|
31
|
+
}
|
|
32
|
+
</style>
|
|
33
|
+
</head>
|
|
34
|
+
<body>
|
|
35
|
+
<div class="container">
|
|
36
|
+
<div class="icon">🛠️</div>
|
|
37
|
+
<h1>We'll be back soon!</h1>
|
|
38
|
+
<p>Our system is currently undergoing scheduled maintenance to improve your experience. Please check back in a few minutes.</p>
|
|
39
|
+
<small>Error: 503 Service Unavailable</small>
|
|
40
|
+
</div>
|
|
41
|
+
</body>
|
|
42
|
+
</html>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Lumina</title>
|
|
7
|
+
<link rel="shortcut icon" href="/img/logo2.png" type="image/x-icon">
|
|
8
|
+
<style>
|
|
9
|
+
body {
|
|
10
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
11
|
+
background-color: #f3f4f6;
|
|
12
|
+
color: #1f2937;
|
|
13
|
+
display: flex;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
align-items: center;
|
|
16
|
+
height: 100vh;
|
|
17
|
+
margin: 0;
|
|
18
|
+
}
|
|
19
|
+
.container {
|
|
20
|
+
text-align: center;
|
|
21
|
+
background: white;
|
|
22
|
+
padding: 3rem;
|
|
23
|
+
border-radius: 1rem;
|
|
24
|
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
|
25
|
+
max-width: 500px;
|
|
26
|
+
}
|
|
27
|
+
img {
|
|
28
|
+
width: 100px;
|
|
29
|
+
height: 100px;
|
|
30
|
+
border-radius: 20px;
|
|
31
|
+
}
|
|
32
|
+
h1 { margin-bottom: 0.5rem; color: #4f46e5; }
|
|
33
|
+
p { color: #6b7280; margin-bottom: 2rem; }
|
|
34
|
+
.status {
|
|
35
|
+
display: inline-block;
|
|
36
|
+
padding: 0.5rem 1rem;
|
|
37
|
+
background-color: #d1fae5;
|
|
38
|
+
color: #065f46;
|
|
39
|
+
border-radius: 9999px;
|
|
40
|
+
font-size: 0.875rem;
|
|
41
|
+
font-weight: 600;
|
|
42
|
+
}
|
|
43
|
+
.links { margin-top: 2rem; }
|
|
44
|
+
a { color: #4f46e5; text-decoration: none; margin: 0 10px; font-weight: 500; }
|
|
45
|
+
a:hover { text-decoration: underline; }
|
|
46
|
+
</style>
|
|
47
|
+
</head>
|
|
48
|
+
<body>
|
|
49
|
+
<div class="container">
|
|
50
|
+
<img src="/img/logo2.png" alt="Lumina Logo" class="logo">
|
|
51
|
+
<h1>Lumina</h1>
|
|
52
|
+
<p>A production-grade Express.js starter kit crafted with TypeScript. Features a fully Object-Oriented architecture, Singleton services, and type-safe database interactions.</p>
|
|
53
|
+
|
|
54
|
+
<div class="status">Application is Running</div>
|
|
55
|
+
|
|
56
|
+
<div class="links">
|
|
57
|
+
<a href="/status">System Status</a>
|
|
58
|
+
<a href="https://github.com/glensonansin/lumina" target="_blank">Documentation</a>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</body>
|
|
62
|
+
</html>
|