millas 0.2.11 → 0.2.12-beta-1

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 (74) hide show
  1. package/package.json +6 -5
  2. package/src/auth/Auth.js +13 -8
  3. package/src/auth/AuthController.js +45 -134
  4. package/src/auth/AuthMiddleware.js +12 -23
  5. package/src/auth/AuthUser.js +98 -0
  6. package/src/auth/RoleMiddleware.js +7 -17
  7. package/src/cli.js +1 -1
  8. package/src/commands/migrate.js +46 -31
  9. package/src/commands/serve.js +238 -38
  10. package/src/container/AppInitializer.js +158 -0
  11. package/src/container/Application.js +288 -183
  12. package/src/container/HttpServer.js +156 -0
  13. package/src/container/MillasApp.js +23 -280
  14. package/src/container/MillasConfig.js +163 -0
  15. package/src/controller/Controller.js +79 -300
  16. package/src/core/auth.js +9 -0
  17. package/src/core/db.js +8 -0
  18. package/src/core/foundation.js +67 -0
  19. package/src/core/http.js +11 -0
  20. package/src/core/mail.js +6 -0
  21. package/src/core/queue.js +7 -0
  22. package/src/core/validation.js +29 -0
  23. package/src/errors/ErrorRenderer.js +640 -0
  24. package/src/facades/Admin.js +49 -0
  25. package/src/facades/Auth.js +29 -0
  26. package/src/facades/Cache.js +28 -0
  27. package/src/facades/Database.js +43 -0
  28. package/src/facades/Events.js +25 -0
  29. package/src/facades/Facade.js +197 -0
  30. package/src/facades/Http.js +51 -0
  31. package/src/facades/Log.js +32 -0
  32. package/src/facades/Mail.js +35 -0
  33. package/src/facades/Queue.js +30 -0
  34. package/src/facades/Storage.js +25 -0
  35. package/src/facades/Url.js +53 -0
  36. package/src/http/HttpClient.js +673 -0
  37. package/src/http/MillasRequest.js +253 -0
  38. package/src/http/MillasResponse.js +196 -0
  39. package/src/http/RequestContext.js +176 -0
  40. package/src/http/ResponseDispatcher.js +51 -0
  41. package/src/http/UrlGenerator.js +375 -0
  42. package/src/http/WelcomePage.js +273 -0
  43. package/src/http/adapters/ExpressAdapter.js +315 -0
  44. package/src/http/adapters/HttpAdapter.js +168 -0
  45. package/src/http/adapters/index.js +9 -0
  46. package/src/http/helpers.js +164 -0
  47. package/src/http/index.js +13 -0
  48. package/src/index.js +5 -91
  49. package/src/logger/formatters/PrettyFormatter.js +15 -5
  50. package/src/logger/internal.js +76 -0
  51. package/src/logger/patchConsole.js +145 -0
  52. package/src/middleware/CorsMiddleware.js +22 -30
  53. package/src/middleware/LogMiddleware.js +27 -59
  54. package/src/middleware/Middleware.js +24 -15
  55. package/src/middleware/MiddlewarePipeline.js +30 -67
  56. package/src/middleware/MiddlewareRegistry.js +106 -0
  57. package/src/middleware/ThrottleMiddleware.js +22 -26
  58. package/src/orm/fields/index.js +124 -56
  59. package/src/orm/migration/ModelInspector.js +339 -336
  60. package/src/orm/model/Model.js +96 -6
  61. package/src/orm/query/QueryBuilder.js +141 -3
  62. package/src/providers/AuthServiceProvider.js +9 -5
  63. package/src/providers/CacheStorageServiceProvider.js +3 -1
  64. package/src/providers/EventServiceProvider.js +2 -1
  65. package/src/providers/LogServiceProvider.js +88 -17
  66. package/src/providers/MailServiceProvider.js +3 -2
  67. package/src/providers/ProviderRegistry.js +14 -1
  68. package/src/providers/QueueServiceProvider.js +3 -2
  69. package/src/providers/ServiceProvider.js +40 -8
  70. package/src/router/Router.js +121 -222
  71. package/src/scaffold/maker.js +24 -59
  72. package/src/scaffold/templates.js +21 -19
  73. package/src/validation/BaseValidator.js +193 -0
  74. package/src/validation/Validator.js +680 -0
@@ -1,299 +1,42 @@
1
1
  'use strict';
2
2
 
3
- const express = require('express');
4
- const Application = require('./Application');
3
+ const MillasConfig = require('./MillasConfig');
5
4
 
6
5
  /**
7
- * MillasApp
8
- *
9
- * A clean factory wrapper around Application that wires up Express,
10
- * core providers, routes, and the admin panel automatically.
11
- *
12
- * Reduces bootstrap/app.js from ~60 lines to ~8.
13
- *
14
- * ── Usage ───────────────────────────────────────────────────────────────────
6
+ * Millas
7
+
8
+ * ── bootstrap/app.js ────────────────────────────────────────────────────────
15
9
  *
16
- * require('dotenv').config();
17
- * const { MillasApp } = require('millas');
18
- * const AppServiceProvider = require('../providers/AppServiceProvider');
10
+ * const { Millas } = require('millas');
19
11
  *
20
- * const app = MillasApp.create()
12
+ * module.exports = Millas.config()
21
13
  * .providers([AppServiceProvider])
22
14
  * .routes(Route => {
23
15
  * require('../routes/web')(Route);
24
16
  * require('../routes/api')(Route);
25
17
  * })
26
- * .withAdmin();
27
- *
28
- * module.exports = app.start();
29
- *
30
- * ── Escape hatches ──────────────────────────────────────────────────────────
31
- *
32
- * // Access the raw Express app
33
- * app.express.use(someExpressMiddleware());
34
- *
35
- * // Access the DI container
36
- * app.container.make('db');
37
- *
38
- * // Access the underlying Application kernel
39
- * app.kernel
18
+ * .withAdmin()
19
+ * .create();
40
20
  *
41
- * ── Advanced ────────────────────────────────────────────────────────────────
21
+ * That is everything a developer writes. The rest is handled internally.
42
22
  *
43
- * MillasApp.create({
44
- * // Disable a core provider
45
- * mail: false,
46
- * queue: false,
23
+ * Millas.config() → MillasConfig (chainable, collects config only)
24
+ * .create() → MillasInstance (sealed carrier, no callable methods)
47
25
  *
48
- * // Custom admin prefix
49
- * admin: { prefix: '/cms', title: 'My CMS' },
50
- *
51
- * // Add Express middleware before routes
52
- * expressMiddleware: [cors(), helmet()],
53
- *
54
- * // Called once the app is listening
55
- * onStart: (port, host) => console.log(`Running on ${host}:${port}`),
56
- * })
26
+ * The framework's AppInitialiser receives the MillasInstance, reads its
27
+ * config, and boots the full application — adapter, kernel, providers,
28
+ * routes, admin, HTTP server — without the developer being involved.
57
29
  */
58
- class MillasApp {
59
-
60
- // ─── Factory ──────────────────────────────────────────────────────────────
61
-
62
- /**
63
- * Create a new MillasApp instance.
64
- * @param {object} [options]
65
- * @param {boolean} [options.database=true] — register DatabaseServiceProvider
66
- * @param {boolean} [options.cache=true] — register CacheServiceProvider
67
- * @param {boolean} [options.storage=true] — register StorageServiceProvider
68
- * @param {boolean} [options.mail=true] — register MailServiceProvider
69
- * @param {boolean} [options.queue=true] — register QueueServiceProvider
70
- * @param {boolean} [options.events=true] — register EventServiceProvider
71
- * @param {boolean} [options.logging=true] — register LogServiceProvider
72
- * @param {Array} [options.expressMiddleware] — Express middleware applied before routes
73
- * @param {Function}[options.onStart] — callback(port, host) after listen
74
- */
75
- static create(options = {}) {
76
- return new MillasApp(options);
77
- }
78
-
79
- constructor(options = {}) {
80
- this._options = options;
81
- this._userProviders = [];
82
- this._routesCb = null;
83
- this._adminOptions = null; // null = no admin; object/true = mount admin
84
- this._expressApp = null;
85
- this._kernel = null;
86
- this._started = false;
87
- }
88
-
89
- // ─── Fluent API ───────────────────────────────────────────────────────────
90
-
30
+ const Millas = {
91
31
  /**
92
- * Register application service providers.
32
+ * Start building an application config.
33
+ * Returns a MillasConfig chain ending in .create().
93
34
  *
94
- * .providers([AppServiceProvider, PaymentServiceProvider])
35
+ * @returns {MillasConfig}
95
36
  */
96
- providers(list = []) {
97
- this._userProviders.push(...list);
98
- return this;
99
- }
100
-
101
- /**
102
- * Define application routes.
103
- *
104
- * .routes(Route => {
105
- * require('../routes/web')(Route);
106
- * require('../routes/api')(Route);
107
- * })
108
- */
109
- routes(callback) {
110
- this._routesCb = callback;
111
- return this;
112
- }
113
-
114
- /**
115
- * Register a named middleware alias.
116
- * Must be called before start().
117
- *
118
- * .middleware('verified', EmailVerifiedMiddleware)
119
- */
120
- middleware(alias, handler) {
121
- if (!this._pendingMiddleware) this._pendingMiddleware = [];
122
- this._pendingMiddleware.push({ alias, handler });
123
- return this;
124
- }
125
-
126
- /**
127
- * Mount the admin panel.
128
- *
129
- * .withAdmin() // default /admin
130
- * .withAdmin({ prefix: '/cms' }) // custom prefix
131
- * .withAdmin({ prefix: '/admin', auth: { users: [...] } })
132
- */
133
- withAdmin(options = {}) {
134
- this._adminOptions = options;
135
- return this;
136
- }
137
-
138
- // ─── Start ────────────────────────────────────────────────────────────────
139
-
140
- /**
141
- * Boot all providers, mount routes, and start listening.
142
- * Returns an object with { app, expressApp, route } for module.exports.
143
- *
144
- * Safe to await if you need to run code after boot:
145
- * const { app } = await MillasApp.create()...start();
146
- */
147
- start() {
148
- // Build Express + Application kernel
149
- this._expressApp = express();
150
- this._expressApp.use(express.json());
151
- this._expressApp.use(express.urlencoded({ extended: true }));
152
-
153
- // Apply any extra Express middleware (e.g. helmet, cors)
154
- for (const mw of (this._options.expressMiddleware || [])) {
155
- this._expressApp.use(mw);
156
- }
157
-
158
- this._kernel = new Application(this._expressApp);
159
-
160
- // Register pending middleware aliases
161
- for (const { alias, handler } of (this._pendingMiddleware || [])) {
162
- this._kernel.middleware(alias, handler);
163
- }
164
-
165
- // Register core providers (auto, unless disabled)
166
- const coreProviders = this._buildCoreProviders();
167
- this._kernel.providers([...coreProviders, ...this._userProviders]);
168
-
169
- // Register routes
170
- if (this._routesCb) {
171
- this._kernel.routes(this._routesCb);
172
- }
173
-
174
- // Boot asynchronously
175
- const self = this;
176
- const boot = (async () => {
177
- await self._kernel.boot();
178
-
179
- if (!process.env.MILLAS_ROUTE_LIST) {
180
- self._kernel.mountRoutes();
181
-
182
- // Admin panel (mounted between routes and fallbacks)
183
- if (self._adminOptions !== null) {
184
- const adminOpts = typeof self._adminOptions === 'object'
185
- ? self._adminOptions
186
- : {};
187
-
188
- try {
189
- const Admin = require('../admin/Admin');
190
- if (Object.keys(adminOpts).length) {
191
- Admin.configure(adminOpts);
192
- }
193
- Admin.mount(self._expressApp);
194
- } catch (err) {
195
- process.stderr.write(`[millas] Admin mount failed: ${err.message}\n`);
196
- }
197
- }
198
-
199
- self._kernel.mountFallbacks();
200
-
201
- const onStart = self._options.onStart || null;
202
- self._kernel.listen(undefined, undefined, onStart || undefined);
203
- }
204
-
205
- self._started = true;
206
- })();
207
-
208
- // Expose the promise for testing / programmatic use
209
- this._bootPromise = boot;
210
-
211
- return this;
212
- }
213
-
214
- /**
215
- * Await the boot promise. Useful in tests or scripts.
216
- *
217
- * const app = await MillasApp.create().routes(...).start().ready();
218
- */
219
- async ready() {
220
- await (this._bootPromise || Promise.resolve());
221
- return this;
222
- }
223
-
224
- // ─── Escape hatches ───────────────────────────────────────────────────────
225
-
226
- /** The raw Express application instance. */
227
- get express() { return this._expressApp; }
228
-
229
- /** The underlying Application kernel (also accessible as .app for back-compat). */
230
- get kernel() { return this._kernel; }
231
- get app() { return this._kernel; }
232
-
233
- /** The DI container. */
234
- get container() { return this._kernel?._container; }
235
-
236
- /** The Route instance — used by route:list command. */
237
- get route() { return this._kernel?._route; }
238
-
239
- /**
240
- * The raw Express app — backward-compatible alias.
241
- * Allows: const { expressApp } = require('./bootstrap/app')
242
- */
243
- get expressApp() { return this._expressApp; }
244
-
245
- // ─── Internal ─────────────────────────────────────────────────────────────
246
-
247
- _buildCoreProviders() {
248
- const opts = this._options;
249
- const providers = [];
250
-
251
- // Helper — require a provider, silently skip if not found
252
- const load = (path) => {
253
- try { return require(path); } catch { return null; }
254
- };
255
-
256
- // Logging — first so all other providers can use Log
257
- if (opts.logging !== false) {
258
- const p = load('../providers/LogServiceProvider');
259
- if (p) providers.push(p);
260
- }
261
-
262
- // Database
263
- if (opts.database !== false) {
264
- const p = load('../providers/DatabaseServiceProvider');
265
- if (p) providers.push(p);
266
- }
267
-
268
- // Cache + Storage
269
- if (opts.cache !== false || opts.storage !== false) {
270
- const p = load('../providers/CacheStorageServiceProvider');
271
- if (p) {
272
- if (opts.cache !== false && p.CacheServiceProvider) providers.push(p.CacheServiceProvider);
273
- if (opts.storage !== false && p.StorageServiceProvider) providers.push(p.StorageServiceProvider);
274
- }
275
- }
276
-
277
- // Mail
278
- if (opts.mail !== false) {
279
- const p = load('../providers/MailServiceProvider');
280
- if (p) providers.push(p);
281
- }
282
-
283
- // Queue
284
- if (opts.queue !== false) {
285
- const p = load('../providers/QueueServiceProvider');
286
- if (p) providers.push(p);
287
- }
288
-
289
- // Events
290
- if (opts.events !== false) {
291
- const p = load('../providers/EventServiceProvider');
292
- if (p) providers.push(p);
293
- }
294
-
295
- return providers;
296
- }
297
- }
37
+ config() {
38
+ return new MillasConfig();
39
+ },
40
+ };
298
41
 
299
- module.exports = MillasApp;
42
+ module.exports = Millas;
@@ -0,0 +1,163 @@
1
+ 'use strict';
2
+
3
+ const AppInitializer = require("./AppInitializer");
4
+
5
+ /**
6
+ * MillasConfig
7
+ *
8
+ * A pure config collector — no side effects, no HTTP, no booting.
9
+ * Every method returns `this` for chaining.
10
+ * The chain ends with .create() which seals the config into a MillasInstance.
11
+ *
12
+ * ── Usage (bootstrap/app.js) ─────────────────────────────────────────────────
13
+ *
14
+ * const { Millas } = require('millas');
15
+ *
16
+ * module.exports = Millas.config()
17
+ * .providers([AppServiceProvider])
18
+ * .routes(Route => {
19
+ * require('../routes/web')(Route);
20
+ * require('../routes/api')(Route);
21
+ * })
22
+ * .withAdmin()
23
+ * .create();
24
+ */
25
+ class MillasConfig {
26
+ constructor() {
27
+ this._config = {
28
+ // Service providers
29
+ providers: [],
30
+
31
+ // Route registration callback: (Route) => void
32
+ routes: null,
33
+
34
+ // Named middleware aliases: [{ alias, handler }]
35
+ middleware: [],
36
+
37
+ // Core service toggles
38
+ database: true,
39
+ cache: true,
40
+ storage: true,
41
+ mail: true,
42
+ queue: true,
43
+ events: true,
44
+ logging: true,
45
+
46
+ // Admin panel — null means disabled, {} or options object means enabled
47
+ admin: null,
48
+
49
+ // Raw adapter-level middleware (e.g. helmet, compression)
50
+ adapterMiddleware: [],
51
+
52
+ // Lifecycle callbacks
53
+ onStart: null,
54
+ onShutdown: null,
55
+ };
56
+ }
57
+
58
+ // ── Chainable config methods ───────────────────────────────────────────────
59
+
60
+ /**
61
+ * Register application service providers.
62
+ *
63
+ * .providers([AppServiceProvider, PaymentServiceProvider])
64
+ */
65
+ providers(list = []) {
66
+ this._config.providers.push(...list);
67
+ return this;
68
+ }
69
+
70
+ /**
71
+ * Register application routes.
72
+ *
73
+ * .routes(Route => {
74
+ * require('../routes/web')(Route);
75
+ * require('../routes/api')(Route);
76
+ * })
77
+ */
78
+ routes(callback) {
79
+ this._config.routes = callback;
80
+ return this;
81
+ }
82
+
83
+ /**
84
+ * Register a named middleware alias.
85
+ *
86
+ * .middleware('verified', EmailVerifiedMiddleware)
87
+ */
88
+ middleware(alias, handler) {
89
+ this._config.middleware.push({alias, handler});
90
+ return this;
91
+ }
92
+
93
+ /**
94
+ * Enable the admin panel.
95
+ *
96
+ * .withAdmin()
97
+ * .withAdmin({ prefix: '/cms', title: 'My CMS' })
98
+ */
99
+ withAdmin(options = {}) {
100
+ this._config.admin = options;
101
+ return this;
102
+ }
103
+
104
+ /**
105
+ * Disable individual core services.
106
+ *
107
+ * .disable('mail', 'queue')
108
+ */
109
+ disable(...services) {
110
+ for (const svc of services) {
111
+ if (svc in this._config) this._config[svc] = false;
112
+ }
113
+ return this;
114
+ }
115
+
116
+ /**
117
+ * Apply raw adapter-level middleware (e.g. helmet, compression).
118
+ * These are applied before any Millas routes.
119
+ *
120
+ * .use(helmet())
121
+ * .use(compression())
122
+ */
123
+ use(...fns) {
124
+ this._config.adapterMiddleware.push(...fns);
125
+ return this;
126
+ }
127
+
128
+ /**
129
+ * Called once the server is listening.
130
+ *
131
+ * .onStart((port, host) => console.log(`up on ${host}:${port}`))
132
+ */
133
+ onStart(fn) {
134
+ this._config.onStart = fn;
135
+ return this;
136
+ }
137
+
138
+ /**
139
+ * Called before graceful shutdown.
140
+ *
141
+ * .onShutdown(async () => db.close())
142
+ */
143
+ onShutdown(fn) {
144
+ this._config.onShutdown = fn;
145
+ return this;
146
+ }
147
+
148
+ // ── Terminal method ────────────────────────────────────────────────────────
149
+
150
+ /**
151
+ *
152
+ *
153
+ * module.exports = Millas.config()
154
+ * .providers([AppServiceProvider])
155
+ * .routes(...)
156
+ * .create();
157
+ */
158
+ async create() {
159
+ return (new AppInitializer(Object.freeze({...this._config}))).boot();
160
+ }
161
+ }
162
+
163
+ module.exports = MillasConfig;