luak-express 2.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.
Files changed (48) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +63 -0
  3. package/app/Exceptions/AppException.js +45 -0
  4. package/app/Exceptions/Handler.js +23 -0
  5. package/app/Http/Middleware/LoggerMiddleware.js +16 -0
  6. package/app/Models/Post.js +14 -0
  7. package/app/Models/User.js +14 -0
  8. package/app/Providers/AppServiceProvider.js +24 -0
  9. package/app/Providers/CacheServiceProvider.js +12 -0
  10. package/app/Providers/DatabaseServiceProvider.js +59 -0
  11. package/app/Providers/RouteServiceProvider.js +55 -0
  12. package/bin/luak +85 -0
  13. package/bootstrap/app.js +43 -0
  14. package/config/app.js +32 -0
  15. package/config/cache.js +12 -0
  16. package/config/database.js +42 -0
  17. package/index.js +82 -0
  18. package/package.json +54 -0
  19. package/routes/api.js +9 -0
  20. package/routes/web.js +13 -0
  21. package/src/Cache/CacheManager.js +54 -0
  22. package/src/Cache/Drivers/FileStore.js +67 -0
  23. package/src/Cache/Repository.js +34 -0
  24. package/src/Database/Model.js +86 -0
  25. package/src/Foundation/Application.js +217 -0
  26. package/src/Foundation/Config.js +111 -0
  27. package/src/Foundation/Exceptions/Handler.js +76 -0
  28. package/src/Foundation/Kernel.js +56 -0
  29. package/src/Foundation/helpers/dd.js +357 -0
  30. package/src/Foundation/resources/errors/404.ejs +132 -0
  31. package/src/Foundation/resources/errors/500.ejs +750 -0
  32. package/src/Http/Middleware/MethodOverride.js +26 -0
  33. package/src/Http/Request.js +98 -0
  34. package/src/Log/Logger.js +58 -0
  35. package/src/Routing/Controller.js +50 -0
  36. package/src/Routing/Pipeline.js +67 -0
  37. package/src/Routing/Router.js +163 -0
  38. package/src/Support/Facade.js +69 -0
  39. package/src/Support/Facades/Cache.js +9 -0
  40. package/src/Support/Facades/Config.js +14 -0
  41. package/src/Support/Facades/Log.js +16 -0
  42. package/src/Support/Facades/Request.js +14 -0
  43. package/src/Support/Facades/Route.js +14 -0
  44. package/src/Support/ServiceProvider.js +30 -0
  45. package/src/Support/helpers.js +79 -0
  46. package/src/index.js +21 -0
  47. package/storage/framework/cache/data/00942f4668670f34c5943cf52c7ef3139fe2b8d6 +1 -0
  48. package/storage/logs/luak.log +3 -0
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026, Eko Suprianto
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # Luak Express Framework v2.0.0 🚀
2
+
3
+ **Luak Express** adalah framework Node.js premium berbasis Express yang dirancang untuk memberikan pengalaman pengembangan (Developer Experience) sekelas Laravel. Dengan fokus pada keindahan desain, kemudahan penggunaan, dan struktur yang solid.
4
+
5
+ ## ✨ Fitur Utama (v2.0.0)
6
+
7
+ * **Premium Debugging (`dd` & `d`)**: Fungsi "Dump and Die" dengan tampilan HTML mewah, tipografi IBM Plex, dan isolasi konteks menggunakan `AsyncLocalStorage`.
8
+ * **Encapsulated Core Handling**: Exception handler dan view error default (500, 404) kini terisolasi di dalam core framework untuk keamanan maksimal.
9
+ * **Laravel-Like Architecture**: Struktur folder yang familiar (Controllers, Providers, Middleware, Routes).
10
+ * **Dynamic Branding**: Sinkronisasi otomatis Nama Aplikasi dan Versi di seluruh halaman sistem.
11
+ * **Dark Mode Aesthetic**: Desain UI sistem yang modern dan nyaman di mata.
12
+
13
+ ## 📦 Sertifikasi Instalasi
14
+
15
+ ```bash
16
+ npm install luak-express
17
+ ```
18
+
19
+ ## 🛠️ Penggunaan Dasar
20
+
21
+ ### Global Helpers
22
+ Luak Express menyediakan helper global yang bisa dipanggil di mana saja tanpa `require`.
23
+
24
+ #### Dump and Die (`dd`)
25
+ Hentikan eksekusi dan lihat isi variabel dengan tampilan cantik:
26
+ ```javascript
27
+ Route.get('/debug', (req, res) => {
28
+ const data = {
29
+ user: 'Luak Developer',
30
+ role: 'Admin',
31
+ permissions: ['read', 'write']
32
+ };
33
+
34
+ dd(data, req.all()); // Berhenti di sini
35
+ });
36
+ ```
37
+
38
+ #### Dump (`d`)
39
+ Lihat isi variabel tanpa menghentikan eksekusi:
40
+ ```javascript
41
+ d('Ini hanyalah log premium');
42
+ ```
43
+
44
+ ## 🏗️ Struktur Proyek
45
+
46
+ ```text
47
+ ├── app/ # Logika Aplikasi (Controllers, Providers, etc)
48
+ ├── bootstrap/ # Inisialisasi Framework
49
+ ├── config/ # File Konfigurasi
50
+ ├── resources/ # Views & Assets (User Land)
51
+ ├── routes/ # Definisi Routing
52
+ ├── src/ # Core Framework (Protected)
53
+ └── package.json
54
+ ```
55
+
56
+ ## ⬆️ Update v2.0.0
57
+ * Centralized Versioning di `Application.js`.
58
+ * Pemindahan Error Handler ke `src/Foundation/Exceptions/Handler.js`.
59
+ * Premium UI overhaul untuk halaman 404 dan 500.
60
+ * Sinkronisasi gradient logo di seluruh sistem.
61
+
62
+ ---
63
+ Dikembangkan dengan ❤️ oleh **Luak Express Team**.
@@ -0,0 +1,45 @@
1
+ class AppException extends Error {
2
+ /**
3
+ * Create a new App Exception.
4
+ *
5
+ * @param {string} message - Error message
6
+ * @param {number} statusCode - HTTP Status code
7
+ * @param {Array} errors - Additional error details
8
+ */
9
+ constructor(message, statusCode = 500, errors = []) {
10
+ super(message);
11
+ this.name = this.constructor.name;
12
+ this.statusCode = statusCode;
13
+ this.status = statusCode;
14
+ this.isOperational = true;
15
+ this.errors = errors;
16
+
17
+ Error.captureStackTrace(this, this.constructor);
18
+ }
19
+
20
+ /**
21
+ * Returns the error message.
22
+ * @returns {string}
23
+ */
24
+ getMessage() {
25
+ return this.message;
26
+ }
27
+
28
+ /**
29
+ * Returns the status code.
30
+ * @returns {number}
31
+ */
32
+ getStatusCode() {
33
+ return this.statusCode;
34
+ }
35
+
36
+ /**
37
+ * Returns the errors array.
38
+ * @returns {Array}
39
+ */
40
+ getErrors() {
41
+ return this.errors;
42
+ }
43
+ }
44
+
45
+ module.exports = AppException;
@@ -0,0 +1,23 @@
1
+ 'use strict';
2
+
3
+ const CoreHandler = require('../../src/Foundation/Exceptions/Handler');
4
+
5
+ /**
6
+ * User-land Exception Handler.
7
+ *
8
+ * This class inherits from the framework's core handler.
9
+ * You can override the render method here to customize
10
+ * how exceptions are reported or rendered.
11
+ */
12
+ class Handler extends CoreHandler {
13
+ /**
14
+ * Create a new exception handler instance.
15
+ *
16
+ * @param {import('../../src/Foundation/Application')} app
17
+ */
18
+ constructor(app) {
19
+ super(app);
20
+ }
21
+ }
22
+
23
+ module.exports = Handler;
@@ -0,0 +1,16 @@
1
+ class LoggerMiddleware {
2
+ /**
3
+ * Handle an incoming request.
4
+ *
5
+ * @param {import('express').Request} req
6
+ * @param {import('express').Response} res
7
+ * @param {Function} next
8
+ */
9
+ handle({ req, res }, next) {
10
+ const { Log } = require('../../../src/index');
11
+ Log.info(`${req.method()} ${req.url()}`);
12
+ return next();
13
+ }
14
+ }
15
+
16
+ module.exports = LoggerMiddleware;
@@ -0,0 +1,14 @@
1
+ const { Model } = require('../../src/index');
2
+
3
+ class Post extends Model {
4
+ /**
5
+ * The table associated with the model.
6
+ *
7
+ * @returns {string}
8
+ */
9
+ static get table() {
10
+ return 'posts';
11
+ }
12
+ }
13
+
14
+ module.exports = Post;
@@ -0,0 +1,14 @@
1
+ const { Model } = require('../../src/index');
2
+
3
+ class User extends Model {
4
+ /**
5
+ * The table associated with the model.
6
+ *
7
+ * @returns {string}
8
+ */
9
+ static get table() {
10
+ return 'users';
11
+ }
12
+ }
13
+
14
+ module.exports = User;
@@ -0,0 +1,24 @@
1
+ const { ServiceProvider } = require('../../src/index');
2
+
3
+ class AppServiceProvider extends ServiceProvider {
4
+ /**
5
+ * Register any application services.
6
+ *
7
+ * @returns {void}
8
+ */
9
+ register() {
10
+ // Register your own bindings here
11
+ // this.app.bind('Services/UserService', require('../Services/UserService'));
12
+ }
13
+
14
+ /**
15
+ * Bootstrap any application services.
16
+ *
17
+ * @returns {void}
18
+ */
19
+ boot() {
20
+ //
21
+ }
22
+ }
23
+
24
+ module.exports = AppServiceProvider;
@@ -0,0 +1,12 @@
1
+ const { ServiceProvider } = require('../../src/index');
2
+ const CacheManager = require('../../src/Cache/CacheManager');
3
+
4
+ class CacheServiceProvider extends ServiceProvider {
5
+ register() {
6
+ this.app.singleton('cache', () => {
7
+ return new CacheManager(this.app);
8
+ });
9
+ }
10
+ }
11
+
12
+ module.exports = CacheServiceProvider;
@@ -0,0 +1,59 @@
1
+ const { ServiceProvider } = require('../../src/index');
2
+
3
+ class DatabaseServiceProvider extends ServiceProvider {
4
+ /**
5
+ * Register any application services.
6
+ *
7
+ * @returns {void}
8
+ */
9
+ register() {
10
+ this.app.singleton('db', () => {
11
+ const config = this.app.make('config');
12
+ const defaultConnection = config.get('database.default');
13
+ const dbConfig = config.get(`database.connections.${defaultConnection}`);
14
+
15
+ if (!dbConfig) {
16
+ throw new Error(`Database connection [${defaultConnection}] not configured.`);
17
+ }
18
+
19
+ // For now, let's use Sequelize as the primary engine for SQL drivers
20
+ if (['mysql', 'sqlite', 'postgres'].includes(dbConfig.driver)) {
21
+ const { Sequelize } = require('sequelize');
22
+
23
+ if (dbConfig.driver === 'sqlite') {
24
+ return new Sequelize({
25
+ dialect: 'sqlite',
26
+ storage: dbConfig.database,
27
+ logging: config.get('app.debug') ? console.log : false
28
+ });
29
+ }
30
+
31
+ return new Sequelize(dbConfig.database, dbConfig.username, dbConfig.password, {
32
+ host: dbConfig.host,
33
+ port: dbConfig.port,
34
+ dialect: dbConfig.driver,
35
+ logging: config.get('app.debug') ? console.log : false
36
+ });
37
+ }
38
+
39
+ return {};
40
+ });
41
+ }
42
+
43
+ boot() {
44
+ const db = this.app.make('db');
45
+ if (db.authenticate) {
46
+ db.authenticate()
47
+ .then(() => {
48
+ if (this.app.make('config').get('app.debug')) {
49
+ console.log('Database connection has been established successfully.');
50
+ }
51
+ })
52
+ .catch(err => {
53
+ console.error('Unable to connect to the database:', err);
54
+ });
55
+ }
56
+ }
57
+ }
58
+
59
+ module.exports = DatabaseServiceProvider;
@@ -0,0 +1,55 @@
1
+ const { ServiceProvider } = require('../../src/index');
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+
5
+ class RouteServiceProvider extends ServiceProvider {
6
+ /**
7
+ * Map the routes.
8
+ *
9
+ * @returns {void}
10
+ */
11
+ boot() {
12
+ // Mount the router onto Express
13
+ const router = this.app.make('router');
14
+ const app = this.app.make('express');
15
+
16
+ this.mapApiRoutes();
17
+ this.mapWebRoutes();
18
+
19
+ app.use('/', router.getExpressRouter());
20
+ }
21
+
22
+ /**
23
+ * Define the "api" routes for the application.
24
+ *
25
+ * @returns {void}
26
+ */
27
+ mapApiRoutes() {
28
+ const router = this.app.make('router');
29
+ const routePath = this.app.path('routes/api.js');
30
+
31
+ if (fs.existsSync(routePath)) {
32
+ router.group({ prefix: '/api/v1' }, () => {
33
+ require(routePath);
34
+ });
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Define the "web" routes for the application.
40
+ *
41
+ * @returns {void}
42
+ */
43
+ mapWebRoutes() {
44
+ const router = this.app.make('router');
45
+ const routePath = this.app.path('routes/web.js');
46
+
47
+ if (fs.existsSync(routePath)) {
48
+ router.group({ prefix: '/' }, () => {
49
+ require(routePath);
50
+ });
51
+ }
52
+ }
53
+ }
54
+
55
+ module.exports = RouteServiceProvider;
package/bin/luak ADDED
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { spawn } = require('child_process');
6
+
7
+ const command = process.argv[2];
8
+
9
+ if (command === 'init') {
10
+ console.log('Initializing Luak Express project...');
11
+ initProject();
12
+ } else {
13
+ console.log('Usage: luak init');
14
+ process.exit(1);
15
+ }
16
+
17
+ function initProject() {
18
+ const targetDir = process.cwd();
19
+ const packageDir = path.resolve(__dirname, '../'); // Assuming bin is inside the package
20
+
21
+ // Directories to copy
22
+ const dirsToCopy = [
23
+ 'app',
24
+ 'bootstrap',
25
+ 'config',
26
+ 'routes',
27
+ // 'database' // Optional, maybe created empty
28
+ ];
29
+
30
+ // Files to copy
31
+ const filesToCopy = [
32
+ 'index.js',
33
+ '.env.example',
34
+ 'gitignore.example' // We might need to rename .gitignore check
35
+ ];
36
+
37
+ // 1. Copy Directories
38
+ dirsToCopy.forEach(dir => {
39
+ const src = path.join(packageDir, dir);
40
+ const dest = path.join(targetDir, dir);
41
+
42
+ if (fs.existsSync(src)) {
43
+ copyRecursiveSync(src, dest);
44
+ console.log(`Created: ${dir}`);
45
+ }
46
+ });
47
+
48
+ // 2. Copy Files
49
+ filesToCopy.forEach(file => {
50
+ const src = path.join(packageDir, file);
51
+ const dest = path.join(targetDir, file);
52
+
53
+ // Handle .gitignore specifically if needed to avoid npm publishing issues
54
+ // For now direct copy
55
+ if (fs.existsSync(src)) {
56
+ fs.copyFileSync(src, dest);
57
+ console.log(`Created: ${file}`);
58
+ } else if (file === '.env.example' && fs.existsSync(path.join(packageDir, '.env'))) {
59
+ // Fallback to .env if .env.example doesn't exist in source but we want to provide one
60
+ fs.copyFileSync(path.join(packageDir, '.env'), dest);
61
+ console.log(`Created: ${file}`);
62
+ }
63
+ });
64
+
65
+ console.log('\nProject initialized successfully!');
66
+ console.log('Run "npm install" to install dependencies.');
67
+ }
68
+
69
+ function copyRecursiveSync(src, dest) {
70
+ const exists = fs.existsSync(src);
71
+ const stats = exists && fs.statSync(src);
72
+ const isDirectory = exists && stats.isDirectory();
73
+
74
+ if (isDirectory) {
75
+ if (!fs.existsSync(dest)) {
76
+ fs.mkdirSync(dest);
77
+ }
78
+
79
+ fs.readdirSync(src).forEach(childItemName => {
80
+ copyRecursiveSync(path.join(src, childItemName), path.join(dest, childItemName));
81
+ });
82
+ } else {
83
+ fs.copyFileSync(src, dest);
84
+ }
85
+ }
@@ -0,0 +1,43 @@
1
+ const { Application } = require('../src/index');
2
+ const path = require('path');
3
+
4
+ /*
5
+ |--------------------------------------------------------------------------
6
+ | Create The Application
7
+ |--------------------------------------------------------------------------
8
+ |
9
+ | The first thing we will do is create a new framework application instance
10
+ | which serves as the "glue" for all the components of logic, and
11
+ | serves as the IoC container for the system binding all of the
12
+ | various parts.
13
+ |
14
+ */
15
+
16
+ const app = new Application(
17
+ path.join(__dirname, '../')
18
+ );
19
+
20
+ /*
21
+ |--------------------------------------------------------------------------
22
+ | Load Configuration & Providers
23
+ |--------------------------------------------------------------------------
24
+ |
25
+ | We check the configuration (either file or cache) and load the
26
+ | providers.
27
+ |
28
+ */
29
+
30
+ app.registerConfiguredProviders();
31
+
32
+ /*
33
+ |--------------------------------------------------------------------------
34
+ | Return The Application
35
+ |--------------------------------------------------------------------------
36
+ |
37
+ | This script returns the application instance. The instance is given to
38
+ | the calling script so we can separate the building of the instances
39
+ | from the actual running of the application and sending responses.
40
+ |
41
+ */
42
+
43
+ module.exports = app;
package/config/app.js ADDED
@@ -0,0 +1,32 @@
1
+ module.exports = {
2
+ /*
3
+ |--------------------------------------------------------------------------
4
+ | Autoloaded Service Providers
5
+ |--------------------------------------------------------------------------
6
+ |
7
+ | The service providers listed here will be automatically loaded on the
8
+ | request to your application. Feel free to add your own services to
9
+ | this array to grant expanded functionality to your applications.
10
+ |
11
+ */
12
+
13
+ /*
14
+ |--------------------------------------------------------------------------
15
+ | Application Name
16
+ |--------------------------------------------------------------------------
17
+ */
18
+ name: process.env.APP_NAME || 'Luak Express',
19
+
20
+ debug: process.env.APP_DEBUG === 'true',
21
+
22
+ providers: [
23
+ // Framework Providers...
24
+ // ...
25
+
26
+ // Application Service Providers...
27
+ 'app/Providers/AppServiceProvider',
28
+ 'app/Providers/RouteServiceProvider',
29
+ 'app/Providers/DatabaseServiceProvider',
30
+ 'app/Providers/CacheServiceProvider',
31
+ ],
32
+ };
@@ -0,0 +1,12 @@
1
+ const path = require('path');
2
+
3
+ module.exports = {
4
+ default: process.env.CACHE_DRIVER || 'file',
5
+
6
+ stores: {
7
+ file: {
8
+ driver: 'file',
9
+ path: path.join(__dirname, '../storage/framework/cache/data'),
10
+ },
11
+ },
12
+ };
@@ -0,0 +1,42 @@
1
+ module.exports = {
2
+ /**
3
+ * Default Database Connection Name
4
+ */
5
+ default: process.env.DB_CONNECTION || 'mysql',
6
+
7
+ /**
8
+ * Database Connections
9
+ */
10
+ connections: {
11
+ sqlite: {
12
+ driver: 'sqlite',
13
+ database: process.env.DB_DATABASE || 'database.sqlite',
14
+ prefix: '',
15
+ },
16
+
17
+ mysql: {
18
+ driver: 'mysql',
19
+ host: process.env.DB_HOST || '127.0.0.1',
20
+ port: process.env.DB_PORT || '3306',
21
+ database: process.env.DB_DATABASE || 'luak_express',
22
+ username: process.env.DB_USERNAME || 'root',
23
+ password: process.env.DB_PASSWORD || '',
24
+ charset: 'utf8mb4',
25
+ collation: 'utf8mb4_unicode_ci',
26
+ prefix: '',
27
+ },
28
+
29
+ mongodb: {
30
+ driver: 'mongodb',
31
+ host: process.env.DB_HOST || '127.0.0.1',
32
+ port: process.env.DB_PORT || '27017',
33
+ database: process.env.DB_DATABASE || 'luak_express',
34
+ username: process.env.DB_USERNAME || '',
35
+ password: process.env.DB_PASSWORD || '',
36
+ options: {
37
+ useNewUrlParser: true,
38
+ useUnifiedTopology: true,
39
+ }
40
+ }
41
+ }
42
+ };
package/index.js ADDED
@@ -0,0 +1,82 @@
1
+ require('dotenv').config();
2
+
3
+ /**
4
+ * Register global helpers
5
+ */
6
+ require('./src/Support/helpers');
7
+
8
+ /**
9
+ * Bootstrap the application
10
+ */
11
+ const app = require('./bootstrap/app');
12
+ const { Kernel } = require('./src/index');
13
+
14
+ /**
15
+ * Run the application
16
+ */
17
+ const port = process.env.PORT || 3000;
18
+
19
+ const express = require('express');
20
+ const path = require('path');
21
+ const server = express();
22
+
23
+ // Bind express to container
24
+ app.bind('express', () => server, true);
25
+
26
+ // Body Parsers
27
+ server.use(express.json());
28
+ server.use(express.urlencoded({ extended: true }));
29
+
30
+ // Configure View Engine
31
+ server.set('view engine', 'ejs');
32
+ server.set('views', path.join(__dirname, 'resources/views'));
33
+
34
+ // Resolve Kernel & Handler
35
+ const kernel = new Kernel(app);
36
+ const Handler = require('./app/Exceptions/Handler');
37
+ const handler = new Handler(app);
38
+
39
+ // Register Global Middleware
40
+ const LoggerMiddleware = require('./app/Http/Middleware/LoggerMiddleware');
41
+ const MethodOverride = require('./src/Http/Middleware/MethodOverride');
42
+ const { ddContextMiddleware } = require('./src/Foundation/helpers/dd');
43
+
44
+ server.use(ddContextMiddleware);
45
+ kernel.pushMiddleware(new MethodOverride());
46
+ kernel.pushMiddleware(new LoggerMiddleware());
47
+
48
+ // Wire up the Kernel to Express
49
+ server.use((req, res, next) => {
50
+ try {
51
+ const result = kernel.handle(req, res, next);
52
+ if (result && typeof result.catch === 'function') {
53
+ result.catch(err => handler.render(req, res, err));
54
+ }
55
+ } catch (err) {
56
+ handler.render(req, res, err);
57
+ }
58
+ });
59
+
60
+ // Mount the Router
61
+ const router = app.make('router');
62
+ server.use(router.router);
63
+
64
+ // 404 Handler
65
+ server.use((req, res, next) => {
66
+ const AppException = require('./app/Exceptions/AppException');
67
+ handler.render(req, res, new AppException('Page Not Found', 404));
68
+ });
69
+
70
+ // Final Error Handler for Express
71
+ server.use((err, req, res, next) => {
72
+ handler.render(req, res, err);
73
+ });
74
+
75
+ app.start().then(() => {
76
+ server.listen(port, () => {
77
+ console.log(`Server is running on port ${port}`);
78
+ });
79
+ }).catch(err => {
80
+ console.error('Failed to start application:', err);
81
+ process.exit(1);
82
+ });