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
@@ -0,0 +1,26 @@
1
+ class MethodOverride {
2
+ /**
3
+ * Handle the incoming request.
4
+ *
5
+ * @param {object} data
6
+ * @param {Function} next
7
+ * @returns {any}
8
+ */
9
+ handle({ req, res }, next) {
10
+ if (req.method() === 'POST') {
11
+ const method = req.input('_method');
12
+
13
+ if (method) {
14
+ const upperMethod = method.toUpperCase();
15
+ if (['PUT', 'PATCH', 'DELETE'].includes(upperMethod)) {
16
+ // Update the underlying express request method
17
+ req.getOriginalRequest().method = upperMethod;
18
+ }
19
+ }
20
+ }
21
+
22
+ return next();
23
+ }
24
+ }
25
+
26
+ module.exports = MethodOverride;
@@ -0,0 +1,98 @@
1
+ class Request {
2
+ /**
3
+ * Create a new Request instance.
4
+ *
5
+ * @param {import('express').Request} req
6
+ */
7
+ constructor(req) {
8
+ this.req = req;
9
+ this.body = req.body || {};
10
+ this.query = req.query || {};
11
+ this.params = req.params || {};
12
+ this.headers = req.headers || {};
13
+ }
14
+
15
+ /**
16
+ * Get a value from the request input (body, query, or params).
17
+ *
18
+ * @param {string} key
19
+ * @param {any} defaultValue
20
+ * @returns {any}
21
+ */
22
+ input(key, defaultValue = null) {
23
+ if (this.body[key] !== undefined) return this.body[key];
24
+ if (this.query[key] !== undefined) return this.query[key];
25
+ if (this.params[key] !== undefined) return this.params[key];
26
+
27
+ return defaultValue;
28
+ }
29
+
30
+ /**
31
+ * Get all input values.
32
+ *
33
+ * @returns {object}
34
+ */
35
+ all() {
36
+ return { ...this.query, ...this.body, ...this.params };
37
+ }
38
+
39
+ /**
40
+ * Get a header value.
41
+ *
42
+ * @param {string} key
43
+ * @param {any} defaultValue
44
+ * @returns {string|null}
45
+ */
46
+ header(key, defaultValue = null) {
47
+ return this.headers[key.toLowerCase()] || defaultValue;
48
+ }
49
+
50
+ /**
51
+ * Get the underlying Express request.
52
+ *
53
+ * @returns {import('express').Request}
54
+ */
55
+ getOriginalRequest() {
56
+ return this.req;
57
+ }
58
+
59
+ /**
60
+ * Check if the request contains a given key.
61
+ *
62
+ * @param {string} key
63
+ * @returns {boolean}
64
+ */
65
+ has(key) {
66
+ return this.input(key) !== null;
67
+ }
68
+
69
+ /**
70
+ * Get the request method.
71
+ *
72
+ * @returns {string}
73
+ */
74
+ method() {
75
+ return this.req.method;
76
+ }
77
+
78
+ /**
79
+ * Get the request URL.
80
+ *
81
+ * @returns {string}
82
+ */
83
+ url() {
84
+ return this.req.url;
85
+ }
86
+ /**
87
+ * Check if the request is an AJAX or API request.
88
+ *
89
+ * @returns {boolean}
90
+ */
91
+ isApi() {
92
+ return this.header('X-Requested-With') === 'XMLHttpRequest' ||
93
+ this.header('Accept')?.includes('application/json') ||
94
+ this.url().startsWith('/api');
95
+ }
96
+ }
97
+
98
+ module.exports = Request;
@@ -0,0 +1,58 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ class Logger {
7
+ /**
8
+ * Create a new Logger instance.
9
+ *
10
+ * @param {import('../Foundation/Application')} app
11
+ */
12
+ constructor(app) {
13
+ this.app = app;
14
+ }
15
+
16
+ /**
17
+ * Log an info message.
18
+ */
19
+ info(message) {
20
+ this.write('INFO', message);
21
+ }
22
+
23
+ /**
24
+ * Log an error message.
25
+ */
26
+ error(message) {
27
+ this.write('ERROR', message);
28
+ }
29
+
30
+ /**
31
+ * Log a warning message.
32
+ */
33
+ warning(message) {
34
+ this.write('WARNING', message);
35
+ }
36
+
37
+ /**
38
+ * Write the message to the log file.
39
+ */
40
+ write(level, message) {
41
+ const timestamp = new Date().toISOString();
42
+ const formattedMessage = `[${timestamp}] ${level}: ${message}\n`;
43
+ const logPath = this.app.storagePath('logs/luak.log');
44
+
45
+ // Ensure directory exists (just in case)
46
+ const dir = path.dirname(logPath);
47
+ if (!fs.existsSync(dir)) {
48
+ fs.mkdirSync(dir, { recursive: true });
49
+ }
50
+
51
+ fs.appendFileSync(logPath, formattedMessage);
52
+
53
+ // Also log to console for development visibility
54
+ console.log(formattedMessage.trim());
55
+ }
56
+ }
57
+
58
+ module.exports = Logger;
@@ -0,0 +1,50 @@
1
+ class Controller {
2
+ /**
3
+ * Create a new Controller instance.
4
+ */
5
+ constructor() {
6
+ // Base controller logic
7
+ }
8
+
9
+ /**
10
+ * Send a JSON response.
11
+ *
12
+ * @param {import('express').Response} res
13
+ * @param {object} data
14
+ * @param {number} status
15
+ */
16
+ json(res, data, status = 200) {
17
+ return res.status(status).json(data);
18
+ }
19
+
20
+ /**
21
+ * Send a success response.
22
+ *
23
+ * @param {import('express').Response} res
24
+ * @param {object} data
25
+ * @param {string} message
26
+ */
27
+ success(res, data = {}, message = 'Success') {
28
+ return res.status(200).json({
29
+ success: true,
30
+ message,
31
+ data
32
+ });
33
+ }
34
+
35
+ /**
36
+ * Send an error response.
37
+ *
38
+ * @param {import('express').Response} res
39
+ * @param {string} message
40
+ * @param {number} status
41
+ */
42
+ error(res, message = 'Error', status = 500) {
43
+ return res.status(status).json({
44
+ success: false,
45
+ message
46
+ });
47
+ }
48
+ }
49
+
50
+ module.exports = Controller;
@@ -0,0 +1,67 @@
1
+ class Pipeline {
2
+ /**
3
+ * Create a new Pipeline instance.
4
+ *
5
+ * @param {import('../Foundation/Application')} app
6
+ */
7
+ constructor(app) {
8
+ this.app = app;
9
+ this.pipes = [];
10
+ }
11
+
12
+ /**
13
+ * Set the object being sent through the pipeline.
14
+ *
15
+ * @param {object} passable
16
+ * @returns {this}
17
+ */
18
+ send(passable) {
19
+ this.passable = passable;
20
+ return this;
21
+ }
22
+
23
+ /**
24
+ * Set the array of pipes.
25
+ *
26
+ * @param {Array} pipes
27
+ * @returns {this}
28
+ */
29
+ through(pipes) {
30
+ this.pipes = pipes;
31
+ return this;
32
+ }
33
+
34
+ /**
35
+ * Run the pipeline with a final destination callback.
36
+ *
37
+ * @param {Function} destination
38
+ * @returns {any}
39
+ */
40
+ then(destination) {
41
+ const pipeline = this.pipes.reduceRight((stack, pipe) => {
42
+ return () => {
43
+ // Resolve middleware from container if it's a string/class
44
+ let middleware = pipe;
45
+ if (typeof pipe === 'string' || (typeof pipe === 'function' && pipe.prototype)) {
46
+ middleware = this.app.make(pipe);
47
+ }
48
+
49
+ if (typeof middleware.handle === 'function') {
50
+ // It's a class middleware
51
+ return middleware.handle(this.passable, stack);
52
+ }
53
+
54
+ if (typeof middleware === 'function') {
55
+ // It's a functional middleware (passable, next)
56
+ return middleware(this.passable, stack);
57
+ }
58
+
59
+ throw new Error('Invalid middleware type');
60
+ };
61
+ }, destination);
62
+
63
+ return pipeline();
64
+ }
65
+ }
66
+
67
+ module.exports = Pipeline;
@@ -0,0 +1,163 @@
1
+ const express = require('express');
2
+
3
+ class Router {
4
+ /**
5
+ * Create a new Router instance.
6
+ *
7
+ * @param {import('../Foundation/Application')} app
8
+ */
9
+ constructor(app) {
10
+ this.app = app;
11
+ this.router = express.Router();
12
+ this.groupStack = [];
13
+ }
14
+
15
+ /**
16
+ * Create a route group with shared attributes.
17
+ *
18
+ * @param {object} attributes
19
+ * @param {Function} callback
20
+ */
21
+ group(attributes, callback) {
22
+ this.groupStack.push(attributes);
23
+ callback(this);
24
+ this.groupStack.pop();
25
+ }
26
+
27
+ /**
28
+ * Register a GET route.
29
+ *
30
+ * @param {string} path
31
+ * @param {class|Function|Array} action
32
+ */
33
+ get(path, action) {
34
+ this.addRoute('get', path, action);
35
+ return this;
36
+ }
37
+
38
+ /**
39
+ * Register a POST route.
40
+ *
41
+ * @param {string} path
42
+ * @param {class|Function|Array} action
43
+ */
44
+ post(path, action) {
45
+ this.addRoute('post', path, action);
46
+ return this;
47
+ }
48
+
49
+ /**
50
+ * Register a PUT route.
51
+ */
52
+ put(path, action) {
53
+ this.addRoute('put', path, action);
54
+ return this;
55
+ }
56
+
57
+ /**
58
+ * Register a PATCH route.
59
+ */
60
+ patch(path, action) {
61
+ this.addRoute('patch', path, action);
62
+ return this;
63
+ }
64
+
65
+ /**
66
+ * Register a DELETE route.
67
+ */
68
+ delete(path, action) {
69
+ this.addRoute('delete', path, action);
70
+ return this;
71
+ }
72
+
73
+ /**
74
+ * Register an OPTIONS route.
75
+ */
76
+ options(path, action) {
77
+ this.addRoute('options', path, action);
78
+ return this;
79
+ }
80
+
81
+ /**
82
+ * Register a route for all methods.
83
+ */
84
+ any(path, action) {
85
+ this.addRoute('all', path, action);
86
+ return this;
87
+ }
88
+
89
+ /**
90
+ * Register a route for specific methods.
91
+ *
92
+ * @param {Array} methods
93
+ * @param {string} path
94
+ * @param {any} action
95
+ */
96
+ match(methods, path, action) {
97
+ methods.forEach(method => {
98
+ this.addRoute(method.toLowerCase(), path, action);
99
+ });
100
+ return this;
101
+ }
102
+
103
+ /**
104
+ * Add route to the underlying Express router.
105
+ *
106
+ * @param {string} method
107
+ * @param {string} path
108
+ * @param {any} action
109
+ */
110
+ addRoute(method, path, action) {
111
+ // Calculate Prefix
112
+ const prefix = this.groupStack.reduce((acc, group) => {
113
+ return acc + (group.prefix || '');
114
+ }, '');
115
+
116
+ const fullPath = (prefix + path).replace(/\/\//g, '/');
117
+
118
+ this.router[method](fullPath, (req, res, next) => {
119
+ const request = this.app.make('request');
120
+ this.dispatch(action, request, res, next);
121
+ });
122
+ }
123
+
124
+ /**
125
+ * Dispatch the request to the controller/action.
126
+ *
127
+ * @param {any} action
128
+ * @param {import('../Http/Request')} req
129
+ * @param {object} res
130
+ * @param {Function} next
131
+ */
132
+ dispatch(action, req, res, next) {
133
+ // Handle [Controller, 'method'] syntax
134
+ if (Array.isArray(action)) {
135
+ const [ControllerClass, method] = action;
136
+
137
+ // Resolve Controller from Container (DI happens here!)
138
+ const controller = this.app.build(ControllerClass);
139
+
140
+ if (typeof controller[method] === 'function') {
141
+ return controller[method](req, res, next);
142
+ }
143
+ }
144
+
145
+ // Handle Closure
146
+ if (typeof action === 'function') {
147
+ return action(req, res, next);
148
+ }
149
+
150
+ throw new Error('Invalid route action.');
151
+ }
152
+
153
+ /**
154
+ * Get the Express router instance.
155
+ *
156
+ * @returns {import('express').Router}
157
+ */
158
+ getExpressRouter() {
159
+ return this.router;
160
+ }
161
+ }
162
+
163
+ module.exports = Router;
@@ -0,0 +1,69 @@
1
+ class Facade {
2
+ /**
3
+ * Get the registered name of the component.
4
+ *
5
+ * @throws {Error}
6
+ * @returns {string}
7
+ */
8
+ static getFacadeAccessor() {
9
+ throw new Error('Facade does not implement getFacadeAccessor method.');
10
+ }
11
+
12
+ /**
13
+ * Resolve the facade root instance from the container.
14
+ *
15
+ * @returns {any}
16
+ */
17
+ static resolveFacadeInstance() {
18
+ const accessor = this.getFacadeAccessor();
19
+ if (!global.app) {
20
+ throw new Error('Application instance is not available globally.');
21
+ }
22
+ return global.app(accessor);
23
+ }
24
+
25
+ /**
26
+ * Handle dynamic static method calls.
27
+ *
28
+ * @param {string} method
29
+ * @param {Array} args
30
+ * @returns {any}
31
+ */
32
+ static __callStatic(method, args) {
33
+ const instance = this.resolveFacadeInstance();
34
+
35
+ if (!instance) {
36
+ throw new Error(`Facade root [${this.getFacadeAccessor()}] has not been resolved.`);
37
+ }
38
+
39
+ if (typeof instance[method] !== 'function') {
40
+ throw new Error(`Method [${method}] does not exist on facade root [${this.getFacadeAccessor()}].`);
41
+ }
42
+
43
+ return instance[method](...args);
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Create a Proxy to handle static method calls.
49
+ *
50
+ * @param {typeof Facade} Target
51
+ * @returns {typeof Facade}
52
+ */
53
+ const createFacade = (Target) => {
54
+ return new Proxy(Target, {
55
+ get: (target, prop, receiver) => {
56
+ // If the property exists on the class itself (like getFacadeAccessor), return it.
57
+ if (Reflect.has(target, prop)) {
58
+ return Reflect.get(target, prop, receiver);
59
+ }
60
+
61
+ // Otherwise, return a function that forwards the call to the instance.
62
+ return (...args) => {
63
+ return target.__callStatic(prop, args);
64
+ };
65
+ }
66
+ });
67
+ };
68
+
69
+ module.exports = { Facade, createFacade };
@@ -0,0 +1,9 @@
1
+ const { Facade, createFacade } = require('../Facade');
2
+
3
+ class Cache extends Facade {
4
+ static getFacadeAccessor() {
5
+ return 'cache';
6
+ }
7
+ }
8
+
9
+ module.exports = createFacade(Cache);
@@ -0,0 +1,14 @@
1
+ const { Facade, createFacade } = require('../Facade');
2
+
3
+ class Config extends Facade {
4
+ /**
5
+ * Get the registered name of the component.
6
+ *
7
+ * @returns {string}
8
+ */
9
+ static getFacadeAccessor() {
10
+ return 'config';
11
+ }
12
+ }
13
+
14
+ module.exports = createFacade(Config);
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ const { Facade, createFacade } = require('../Facade');
4
+
5
+ class Log extends Facade {
6
+ /**
7
+ * Get the registered name of the component.
8
+ *
9
+ * @returns {string}
10
+ */
11
+ static getFacadeAccessor() {
12
+ return 'log';
13
+ }
14
+ }
15
+
16
+ module.exports = createFacade(Log);
@@ -0,0 +1,14 @@
1
+ const { Facade, createFacade } = require('../Facade');
2
+
3
+ class Request extends Facade {
4
+ /**
5
+ * Get the registered name of the component.
6
+ *
7
+ * @returns {string}
8
+ */
9
+ static getFacadeAccessor() {
10
+ return 'request';
11
+ }
12
+ }
13
+
14
+ module.exports = createFacade(Request);
@@ -0,0 +1,14 @@
1
+ const { Facade, createFacade } = require('../Facade');
2
+
3
+ class Route extends Facade {
4
+ /**
5
+ * Get the registered name of the component.
6
+ *
7
+ * @returns {string}
8
+ */
9
+ static getFacadeAccessor() {
10
+ return 'router';
11
+ }
12
+ }
13
+
14
+ module.exports = createFacade(Route);
@@ -0,0 +1,30 @@
1
+ class ServiceProvider {
2
+ /**
3
+ * Create a new service provider instance.
4
+ *
5
+ * @param {import('../Foundation/Application')} app
6
+ */
7
+ constructor(app) {
8
+ this.app = app;
9
+ }
10
+
11
+ /**
12
+ * Register any application services.
13
+ *
14
+ * @returns {void}
15
+ */
16
+ register() {
17
+ //
18
+ }
19
+
20
+ /**
21
+ * Bootstrap any application services.
22
+ *
23
+ * @returns {void}
24
+ */
25
+ boot() {
26
+ //
27
+ }
28
+ }
29
+
30
+ module.exports = ServiceProvider;