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,12 +1,14 @@
1
1
  'use strict';
2
2
 
3
- const Container = require('./Container');
3
+ const Container = require('./Container');
4
4
  const ProviderRegistry = require('../providers/ProviderRegistry');
5
- const { Route, Router, MiddlewareRegistry } = require('../router');
6
- const CorsMiddleware = require('../middleware/CorsMiddleware');
5
+ const {Route, Router, MiddlewareRegistry} = require('../router');
6
+ const CorsMiddleware = require('../middleware/CorsMiddleware');
7
7
  const ThrottleMiddleware = require('../middleware/ThrottleMiddleware');
8
- const LogMiddleware = require('../middleware/LogMiddleware');
9
- const AuthMiddleware = require('../auth/AuthMiddleware');
8
+ const LogMiddleware = require('../middleware/LogMiddleware');
9
+ const AuthMiddleware = require('../auth/AuthMiddleware');
10
+ const Facade = require("../facades/Facade");
11
+ const UrlGenerator = require("../http/UrlGenerator");
10
12
 
11
13
  /**
12
14
  * Application
@@ -14,195 +16,298 @@ const AuthMiddleware = require('../auth/AuthMiddleware');
14
16
  * The central Millas kernel. Owns:
15
17
  * - The DI container
16
18
  * - The provider registry
17
- * - The Express app
19
+ * - The HttpAdapter (NOT Express directly — any adapter works)
18
20
  * - The route instance
19
21
  * - The middleware registry
20
22
  *
23
+ * The kernel is fully decoupled from Express. It talks to the HTTP layer
24
+ * exclusively through the HttpAdapter interface.
25
+ *
21
26
  * Usage in bootstrap/app.js:
22
27
  *
23
- * const { Application } = require('millas/src/container');
24
- * const app = new Application(expressApp);
25
- * app.providers([AppServiceProvider, DatabaseServiceProvider]);
28
+ * const { Application } = require('millas/src/container');
29
+ * const { ExpressAdapter } = require('millas/src/http/adapters');
30
+ * const express = require('express');
31
+ *
32
+ * const adapter = new ExpressAdapter(express());
33
+ * const app = new Application(adapter);
34
+ * app.providers([AppServiceProvider]);
26
35
  * await app.boot();
27
- * app.routes(route => {
28
- * require('../routes/web')(route);
29
- * require('../routes/api')(route);
30
- * });
36
+ * app.routes(Route => require('../routes/api')(Route));
31
37
  * app.mount();
32
38
  * app.listen();
33
39
  */
34
40
  class Application {
35
- constructor(expressApp) {
36
- this._express = expressApp;
37
- this._container = new Container();
38
- this._providers = new ProviderRegistry(this._container, expressApp);
39
- this._mwRegistry = new MiddlewareRegistry();
40
- this._route = new Route();
41
- this._booted = false;
42
-
43
- // Register core framework bindings
44
- this._registerCoreBindings();
45
- }
46
-
47
- // ─── Configuration ───────────────────────────────────────────────────────────
48
-
49
- /**
50
- * Add service providers.
51
- * @param {Array} providers
52
- */
53
- providers(providers = []) {
54
- this._providers.addMany(providers);
55
- return this;
56
- }
57
-
58
- /**
59
- * Register a middleware alias.
60
- *
61
- * app.middleware('auth', AuthMiddleware)
62
- * app.middleware('throttle', new ThrottleMiddleware({ max: 60 }))
63
- */
64
- middleware(alias, handler) {
65
- this._mwRegistry.register(alias, handler);
66
- return this;
67
- }
68
-
69
- /**
70
- * Define all routes via a callback.
71
- *
72
- * app.routes(route => {
73
- * require('../routes/web')(route);
74
- * require('../routes/api')(route);
75
- * });
76
- */
77
- routes(callback) {
78
- callback(this._route);
79
- return this;
80
- }
81
-
82
- // ─── Lifecycle ───────────────────────────────────────────────────────────────
83
-
84
- /**
85
- * Run the full provider register → boot lifecycle.
86
- */
87
- async boot() {
88
- if (this._booted) return this;
89
- await this._providers.boot();
90
- this._booted = true;
91
- return this;
92
- }
93
-
94
- /**
95
- * Bind all routes onto the Express app.
96
- * Does NOT add 404/error fallbacks — call mountFallbacks() after
97
- * registering any extra middleware (e.g. Admin panel).
98
- *
99
- * Typical usage:
100
- * app.mountRoutes();
101
- * Admin.mount(expressApp); // admin routes added here
102
- * app.mountFallbacks(); // 404 + error handler last
103
- *
104
- * Or use app.mount() which does all three in one call.
105
- */
106
- mountRoutes() {
107
- this._router = new Router(this._express, this._route.getRegistry(), this._mwRegistry);
108
- this._router.mountRoutes();
109
- return this;
110
- }
111
-
112
- /**
113
- * Add 404 + global error handlers. Must be called LAST.
114
- */
115
- mountFallbacks() {
116
- if (!this._router) {
117
- this._router = new Router(this._express, this._route.getRegistry(), this._mwRegistry);
118
- }
119
- this._router.mountFallbacks();
120
- return this;
121
- }
122
-
123
- /**
124
- * Bind routes + add 404/error handlers in one call.
125
- * Use this when NOT using the Admin panel, or when Admin
126
- * is mounted before this call.
127
- */
128
- mount() {
129
- const router = new Router(this._express, this._route.getRegistry(), this._mwRegistry);
130
- router.mount();
131
- return this;
132
- }
133
-
134
- /**
135
- * Start the HTTP server.
136
- */
137
- listen(port, host, callback) {
138
- const _port = port || parseInt(process.env.APP_PORT, 10) || 3000;
139
- const _host = host || process.env.MILLAS_HOST || 'localhost';
140
-
141
- this._express.listen(_port, _host, () => {
142
- if (!process.env.MILLAS_ROUTE_LIST) {
41
+ /**
42
+ * @param {import('../http/adapters/HttpAdapter')} adapter
43
+ */
44
+ constructor(adapter) {
45
+ this._adapter = adapter;
46
+ this._container = new Container();
47
+ this._providers = new ProviderRegistry(this._container, adapter.nativeApp || adapter);
48
+ this._mwRegistry = new MiddlewareRegistry();
49
+ this._route = new Route();
50
+ this._booted = false;
51
+
52
+ this._registerCoreBindings();
53
+ }
54
+
55
+ // ── Configuration ──────────────────────────────────────────────────────────
56
+
57
+ providers(providers = []) {
58
+ this._providers.addMany(providers);
59
+ return this;
60
+ }
61
+
62
+ /**
63
+ * Register a middleware alias.
64
+ *
65
+ * app.middleware('auth', AuthMiddleware)
66
+ * app.middleware('throttle', new ThrottleMiddleware({ max: 60 }))
67
+ */
68
+ middleware(alias, handler) {
69
+ this._mwRegistry.register(alias, handler);
70
+ return this;
71
+ }
72
+
73
+ /**
74
+ * Define all routes via a callback.
75
+ *
76
+ * app.routes(Route => {
77
+ * require('../routes/api')(Route);
78
+ * });
79
+ */
80
+ routes(callback) {
81
+ callback(this._route);
82
+ return this;
83
+ }
84
+
85
+ // ── Lifecycle ──────────────────────────────────────────────────────────────
86
+
87
+ /**
88
+ * Run the full provider lifecycle:
89
+ * Phase 0 — beforeBoot (sync, global setup)
90
+ * Phase 1 — register (sync, container bindings)
91
+ * Phase 2 boot (async, all bindings available)
92
+ */
93
+ async boot() {
94
+ if (this._booted) return this;
95
+
96
+ this._emitSync('platform.booting', {providers: this._providers.list()});
97
+
98
+ await this._providers.boot();
99
+ this._booted = true;
100
+
101
+ this._emitSync('platform.booted', {providers: this._providers.list()});
102
+
103
+ return this;
104
+ }
105
+
106
+ /**
107
+ * Mount all registered routes onto the adapter.
108
+ * Does NOT add fallbacks — call mountFallbacks() separately after
109
+ * any extra middleware (e.g. Admin panel) is mounted.
110
+ */
111
+ mountRoutes() {
112
+ this._router = new Router(
113
+ this._adapter,
114
+ this._route.getRegistry(),
115
+ this._mwRegistry,
116
+ this._container
117
+ );
118
+ this._router.mountRoutes();
119
+ return this;
120
+ }
121
+
122
+ /**
123
+ * Mount 404 + error handler. Must be called LAST.
124
+ */
125
+ mountFallbacks() {
126
+ if (!this._router) {
127
+ this._router = new Router(
128
+ this._adapter,
129
+ this._route.getRegistry(),
130
+ this._mwRegistry,
131
+ this._container
132
+ );
133
+ }
134
+ this._router.mountFallbacks();
135
+ return this;
136
+ }
137
+
138
+ /**
139
+ * Mount routes + fallbacks in one call.
140
+ */
141
+ mount() {
142
+ const router = new Router(
143
+ this._adapter,
144
+ this._route.getRegistry(),
145
+ this._mwRegistry,
146
+ this._container
147
+ );
148
+ router.mount();
149
+ return this;
150
+ }
151
+
152
+ /**
153
+ * Start the HTTP server via the adapter.
154
+ * Emits: platform.listening
155
+ */
156
+ async listen(port, host, callback) {
157
+ const _port = port
158
+ || parseInt(process.env.MILLAS_INTERNAL_PORT, 10)
159
+ || parseInt(process.env.APP_PORT, 10)
160
+ || 3000;
161
+ const _host = host || process.env.MILLAS_HOST || 'localhost';
162
+
163
+ await this._adapter.listen(_port, _host);
164
+
165
+ if (process.env.APP_ENV === "development" && process.env.MILLAS_START_UP && !process.env.MILLERS_NODE_ENV) {
166
+ this._printStartupLog(_host, _port);
167
+ }
168
+
169
+ this._emitSync('platform.listening', {port: _port, host: _host});
170
+
171
+ if (typeof callback === 'function') callback(_port, _host);
172
+
173
+ return this;
174
+ }
175
+
176
+ _printStartupLog(host, port) {
177
+ const chalk = _tryChalk();
143
178
  const routeCount = this._route.list().length;
144
- console.log(`\n ⚡ Millas running at http://${_host}:${_port}`);
145
- console.log(` ${routeCount} route(s) registered\n`);
146
- }
147
- if (typeof callback === 'function') callback(_port, _host);
148
- });
149
-
150
- return this;
151
- }
152
-
153
- // ─── Container Proxy ─────────────────────────────────────────────────────────
154
-
155
- /**
156
- * Bind a transient into the container.
157
- */
158
- bind(abstract, concrete) {
159
- this._container.bind(abstract, concrete);
160
- return this;
161
- }
162
-
163
- /**
164
- * Bind a singleton into the container.
165
- */
166
- singleton(abstract, concrete) {
167
- this._container.singleton(abstract, concrete);
168
- return this;
169
- }
170
-
171
- /**
172
- * Register a pre-built instance.
173
- */
174
- instance(abstract, value) {
175
- this._container.instance(abstract, value);
176
- return this;
177
- }
178
-
179
- /**
180
- * Resolve something from the container.
181
- */
182
- make(abstract, overrides) {
183
- return this._container.make(abstract, overrides);
184
- }
185
-
186
- // ─── Accessors ───────────────────────────────────────────────────────────────
187
-
188
- get container() { return this._container; }
189
- get route() { return this._route; }
190
- get express() { return this._express; }
191
- get mwRegistry() { return this._mwRegistry; }
192
-
193
- // ─── Internal ────────────────────────────────────────────────────────────────
194
-
195
- _registerCoreBindings() {
196
- // Register the application itself
197
- this._container.instance('app', this);
198
- this._container.instance('container', this._container);
199
-
200
- // Register built-in middleware
201
- this._mwRegistry.register('cors', new CorsMiddleware());
202
- this._mwRegistry.register('throttle', new ThrottleMiddleware({ max: 60, window: 60 }));
203
- this._mwRegistry.register('log', new LogMiddleware());
204
- this._mwRegistry.register('auth', AuthMiddleware);
205
- }
179
+ const url = `http://${host}:${port}`;
180
+
181
+ // console.error(chalk.dim('›') + ' ' +
182
+ // chalk.dim('Listening on ') + chalk.bold.white(url)
183
+ // );
184
+ console.log(chalk.dim('›') + ' ' +
185
+ chalk.white(routeCount + ' route' + (routeCount !== 1 ? 's' : '') + ' registered')
186
+ );
187
+ console.error(chalk.dim('›') + ' ' +
188
+ chalk.dim('Press ') + chalk.bold('Ctrl+C') + chalk.dim(' to stop')
189
+ );
190
+ }
191
+
192
+ /**
193
+ * Graceful shutdown.
194
+ */
195
+ async shutdown(code = 0) {
196
+ this._emitSync('platform.shutting_down', {});
197
+ await this._adapter.close();
198
+ process.exit(code);
199
+ }
200
+
201
+ // ── Platform event bus ─────────────────────────────────────────────────────
202
+
203
+ on(event, fn) {
204
+ if (!this._platformListeners) this._platformListeners = new Map();
205
+ if (!this._platformListeners.has(event)) this._platformListeners.set(event, []);
206
+ this._platformListeners.get(event).push(fn);
207
+ return this;
208
+ }
209
+
210
+ _emitSync(event, data) {
211
+ if (!this._platformListeners) return;
212
+ const listeners = this._platformListeners.get(event) || [];
213
+ for (const fn of listeners) {
214
+ try {
215
+ fn(data);
216
+ } catch {
217
+ }
218
+ }
219
+ }
220
+
221
+ // ── Container proxy ────────────────────────────────────────────────────────
222
+
223
+ bind(abstract, concrete) {
224
+ this._container.bind(abstract, concrete);
225
+ return this;
226
+ }
227
+
228
+ singleton(abstract, c) {
229
+ this._container.singleton(abstract, c);
230
+ return this;
231
+ }
232
+
233
+ instance(abstract, value) {
234
+ this._container.instance(abstract, value);
235
+ return this;
236
+ }
237
+
238
+ make(abstract, overrides) {
239
+ return this._container.make(abstract, overrides);
240
+ }
241
+
242
+ // ── Accessors ──────────────────────────────────────────────────────────────
243
+
244
+ get container() {
245
+ return this._container;
246
+ }
247
+
248
+ get route() {
249
+ return this._route;
250
+ }
251
+
252
+ get adapter() {
253
+ return this._adapter;
254
+ }
255
+
256
+ get mwRegistry() {
257
+ return this._mwRegistry;
258
+ }
259
+
260
+ /**
261
+ * express — backward-compatible escape hatch.
262
+ * Returns the native app from the adapter if available.
263
+ * Prefer adapter.nativeApp for new code.
264
+ */
265
+ get express() {
266
+ return this._adapter.nativeApp || this._adapter;
267
+ }
268
+
269
+ // ── Internal ───────────────────────────────────────────────────────────────
270
+
271
+ _registerCoreBindings() {
272
+ this._container.instance('app', this);
273
+ this._container.instance('container', this._container);
274
+
275
+ const Facade = require('../facades/Facade');
276
+ Facade.setContainer(this._container);
277
+ // Http client — always available, no provider needed
278
+ const {HttpClient} = require('../http/HttpClient');
279
+ this._container.instance('HttpClient', HttpClient);
280
+ this._container.alias('http', "HttpClient");
281
+
282
+ const UrlGenerator = require('../http/UrlGenerator');
283
+ const urlGenerator = new UrlGenerator({
284
+ baseUrl: process.env.APP_URL || '',
285
+ appKey: process.env.APP_KEY || '',
286
+ routeRegistry: this._route?.getRegistry?.() || null,
287
+ });
288
+ this._container.instance('url', urlGenerator);
289
+
290
+
291
+ this._mwRegistry.register('cors', new CorsMiddleware());
292
+ this._mwRegistry.register('throttle', new ThrottleMiddleware({max: 60, window: 60}));
293
+ this._mwRegistry.register('log', new LogMiddleware());
294
+ this._mwRegistry.register('auth', AuthMiddleware);
295
+ }
206
296
  }
207
297
 
208
298
  module.exports = Application;
299
+
300
+ // ── Helpers ───────────────────────────────────────────────────────────────────
301
+
302
+ function _tryChalk() {
303
+ try {
304
+ return require('chalk');
305
+ } catch {
306
+ const id = s => s;
307
+ const p = new Proxy({}, {get: () => p, apply: (_, __, [s]) => String(s || '')});
308
+ p.dim = id;
309
+ p.bold = p;
310
+ p.white = id;
311
+ return p;
312
+ }
313
+ }
@@ -0,0 +1,156 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * HttpServer
5
+ *
6
+ * Owns everything that belongs to the process/server layer — the things
7
+ * Express puts in bin/www that have nothing to do with your app logic:
8
+ *
9
+ * - Port normalisation and validation
10
+ * - EADDRINUSE / EACCES error handling with clear messages
11
+ * - Startup log (route count, URL, Ctrl+C hint)
12
+ * - IPC ready signal to the hot-reload proxy (millas serve)
13
+ * - Graceful shutdown on SIGTERM / SIGINT
14
+ *
15
+ * The Application kernel knows nothing about any of this.
16
+ *
17
+ * ── Usage in bootstrap/server.js ────────────────────────────────────────────
18
+ *
19
+ * const app = require('./app'); // configured Millas app, no listen()
20
+ * const server = new HttpServer(app);
21
+ * server.start();
22
+ *
23
+ * ── Advanced ─────────────────────────────────────────────────────────────────
24
+ *
25
+ * new HttpServer(app, {
26
+ * port: 4000,
27
+ * host: '0.0.0.0',
28
+ * onStart: (port, host) => console.log(`up on ${host}:${port}`),
29
+ * onShutdown: () => db.close(),
30
+ * }).start();
31
+ */
32
+ class HttpServer {
33
+ /**
34
+ * @param {import('./Application')} app — booted Millas Application instance
35
+ * @param {object} options
36
+ * @param {number} [options.port]
37
+ * @param {string} [options.host]
38
+ * @param {Function}[options.onStart] — (port, host) => void, called after listen
39
+ * @param {Function}[options.onShutdown] — async () => void, called before process.exit
40
+ */
41
+ constructor(app, options = {}) {
42
+ this._app = app;
43
+ this._options = options;
44
+ }
45
+
46
+ /**
47
+ * Resolve port, boot the server, wire signals.
48
+ * Returns a Promise that resolves once the server is listening.
49
+ */
50
+ async start() {
51
+ const port = this._resolvePort();
52
+ const host = this._options.host
53
+ || process.env.MILLAS_HOST
54
+ || process.env.HOST
55
+ || 'localhost';
56
+
57
+ // Boot providers if not already done
58
+ if (!this._app._booted) {
59
+ await this._app.boot();
60
+ }
61
+
62
+ // Mount routes + fallbacks if not already mounted
63
+ if (!this._app._router) {
64
+ this._app.mount();
65
+ }
66
+
67
+ // Start listening — may throw on EADDRINUSE / EACCES
68
+ try {
69
+ await this._app.listen(port, host);
70
+ } catch (err) {
71
+ this._handleListenError(err, port);
72
+ return; // _handleListenError always exits
73
+ }
74
+
75
+ // Notify the millas serve hot-reload proxy that we're ready
76
+ if (typeof process.send === 'function') {
77
+ process.send({type: 'ready', port});
78
+ }
79
+
80
+ // User callback
81
+ if (typeof this._options.onStart === 'function') {
82
+ this._options.onStart(port, host);
83
+ }
84
+ this._handleSignals();
85
+
86
+ }
87
+
88
+ // ── Private ────────────────────────────────────────────────────────────────
89
+
90
+ _resolvePort() {
91
+ const raw =
92
+ this._options.port ||
93
+ parseInt(process.env.MILLAS_INTERNAL_PORT, 10) ||
94
+ parseInt(process.env.APP_PORT, 10) ||
95
+ parseInt(process.env.PORT, 10) ||
96
+ 3000;
97
+
98
+ return this._normalizePort(raw);
99
+ }
100
+
101
+ _normalizePort(val) {
102
+ const n = parseInt(val, 10);
103
+ if (isNaN(n)) return val; // named pipe — pass through
104
+ if (n >= 0) return n;
105
+ return 3000;
106
+ }
107
+
108
+ _handleListenError(err, port) {
109
+ const bind = typeof port === 'string' ? `pipe ${port}` : `port ${port}`;
110
+
111
+ switch (err.code) {
112
+ case 'EACCES':
113
+ console.error(
114
+ `✖ ${bind} requires elevated privileges.\n` +
115
+ ` Try a port above 1024 or run with sudo.`
116
+ );
117
+ break;
118
+
119
+ case 'EADDRINUSE':
120
+ console.error(
121
+ `✖ ${bind} is already in use.\n` +
122
+ ` Another process is listening on that port.\n` +
123
+ ` Try: APP_PORT=3001 millas serve`
124
+ );
125
+ break;
126
+
127
+ default:
128
+ console.error(`✖ Listen error: ${err.message}`);
129
+ if (process.env.APP_DEBUG) console.error(err.stack + '\n');
130
+ }
131
+
132
+ process.exit(1);
133
+ }
134
+
135
+
136
+ _handleSignals() {
137
+ const shutdown = async (signal) => {
138
+ process.exit(0);
139
+ // process.stdout.write(`\n Shutting down (${signal})…\n`);
140
+ //
141
+ // if (typeof this._options.onShutdown === 'function') {
142
+ // try {
143
+ // await this._options.onShutdown();
144
+ // } catch {
145
+ // }
146
+ // }
147
+ //
148
+ // await this._app.shutdown(0);
149
+ };
150
+
151
+ process.once('SIGTERM', () => shutdown("SIGTERM"));
152
+ process.once('SIGINT', () => shutdown('SIGINT'));
153
+ }
154
+ }
155
+
156
+ module.exports = HttpServer;