@morojs/moro 1.8.5 → 1.8.7

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/README.md CHANGED
@@ -8,9 +8,9 @@
8
8
 
9
9
  [![npm version](https://badge.fury.io/js/@morojs%2Fmoro.svg)](https://badge.fury.io/js/@morojs%2Fmoro)
10
10
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
11
- [![Node.js Version](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen)](https://nodejs.org/)
11
+ [![Node.js Version](https://img.shields.io/badge/node-%3E%3D20.0.0-brightgreen)](https://nodejs.org/)
12
12
 
13
- [**Website**](https://morojs.com) • [**Documentation**](https://morojs.com/docs) • [**Quick Start**](https://morojs.com/docs/getting-started) • [**Discord**](https://morojs.com/discord)
13
+ [**Website**](https://morojs.com) • [**Documentation**](https://morojs.com/docs) • [**Quick Start**](https://morojs.com/docs/quick-start) • [**Discord**](https://morojs.com/discord)
14
14
 
15
15
  </div>
16
16
 
@@ -18,12 +18,12 @@
18
18
 
19
19
  ## Why MoroJS?
20
20
 
21
- Build high-performance APIs with intelligent routing that automatically orders middleware execution. Deploy anywhere: Node.js, Vercel Edge, AWS Lambda, or Cloudflare Workers - same code, zero configuration.
21
+ Build high-performance APIs with intelligent routing: declare what a route needs and MoroJS runs it in the optimal, security-first order every time — rate limiting sheds floods before auth, auth gates the cache. Middleware ordering stops being something you can get wrong. Deploy anywhere: Node.js, Vercel Edge, AWS Lambda, or Cloudflare Workers - same code, zero configuration.
22
22
 
23
23
  **Key Features:**
24
24
 
25
25
  - **Native C++ Engine** - ~102k req/s real-world through the full framework, 572k pipelined, on a single thread
26
- - **Intelligent Routing** - Automatic middleware ordering, no configuration needed
26
+ - **Intelligent Routing** - Declare auth, validation, rate limits and caching in any order; they always execute in the optimal, security-first one
27
27
  - **Enterprise Auth** - Built-in Better Auth with OAuth & RBAC
28
28
  - **Universal Validation** - Works with Zod, Joi, Yup, or Class Validator
29
29
  - **Message Queues** - Production-ready queues (Bull, RabbitMQ, SQS, Kafka)
@@ -53,6 +53,7 @@ import { createApp, z } from '@morojs/moro';
53
53
  const app = await createApp();
54
54
 
55
55
  // Intelligent routing - order doesn't matter!
56
+ // (rate limit -> auth -> validation -> cache -> handler)
56
57
  app
57
58
  .post('/users')
58
59
  .body(
@@ -196,7 +197,7 @@ Check out [working examples](https://github.com/Moro-JS/examples) for:
196
197
 
197
198
  ## Why Choose MoroJS?
198
199
 
199
- **vs Express** - Intelligent middleware ordering eliminates configuration complexity and race conditions
200
+ **vs Express** - Intelligent security-first middleware pipeline eliminates ordering bugs and configuration complexity
200
201
 
201
202
  **vs Fastify** - ~1.5x the throughput out of the box (Moro's native engine), plus multi-runtime deployment without adapters
202
203
 
@@ -216,6 +217,6 @@ MIT © [Moro Framework Team](https://morojs.com)
216
217
 
217
218
  **Ready to build high-performance APIs?**
218
219
 
219
- [Get Started](https://morojs.com/docs/getting-started) • [GitHub](https://github.com/Moro-JS/moro) • [npm](https://www.npmjs.com/package/@morojs/moro) • [Discord](https://morojs.com/discord)
220
+ [Get Started](https://morojs.com/docs/quick-start) • [GitHub](https://github.com/Moro-JS/moro) • [npm](https://www.npmjs.com/package/@morojs/moro) • [Discord](https://morojs.com/discord)
220
221
 
221
222
  </div>
@@ -1,7 +1,8 @@
1
- import { IncomingMessage, ServerResponse, Server } from 'http';
1
+ import type { Server } from 'http';
2
2
  import type { HttpRuntimeLimits } from './utils/size.js';
3
3
  import { HttpRequest, HttpResponse, HttpHandler, Middleware } from '../../types/http.js';
4
- export declare class MoroIncomingMessage extends IncomingMessage {
4
+ declare const http: typeof import("http");
5
+ export declare class MoroIncomingMessage extends http.IncomingMessage {
5
6
  /** Bound on the per-server subclass prototype - no per-request write needed */
6
7
  _server: MoroHttpServer;
7
8
  params: Record<string, string>;
@@ -39,7 +40,7 @@ export declare class MoroIncomingMessage extends IncomingMessage {
39
40
  accepts(types?: string | string[]): string | false;
40
41
  acceptsLanguages(langs?: string | string[]): string | false;
41
42
  }
42
- export declare class MoroServerResponse extends ServerResponse {
43
+ export declare class MoroServerResponse extends http.ServerResponse {
43
44
  /** Bound on the per-server subclass prototype - no per-request write needed */
44
45
  _server: MoroHttpServer;
45
46
  _locals: Record<string, any> | undefined;
@@ -256,3 +257,4 @@ export declare class MoroHttpServer {
256
257
  };
257
258
  };
258
259
  }
260
+ export {};
@@ -1,7 +1,4 @@
1
- // src/core/http-server.ts
2
- import { IncomingMessage, ServerResponse, createServer } from 'http';
3
- import { createServer as createHttpsServer } from 'https';
4
- import * as zlib from 'zlib';
1
+ import { createRequire } from 'module';
5
2
  import { promisify } from 'util';
6
3
  import { randomUUID } from 'crypto';
7
4
  import { createFrameworkLogger } from '../logger/index.js';
@@ -9,8 +6,35 @@ import { parseMultipart as parseMultipartBuffer, } from './utils/multipart-parse
9
6
  import { parseRawQueryString } from './utils/query-parser.js';
10
7
  import { PathMatcher } from '../routing/path-matcher.js';
11
8
  import { ObjectPoolManager } from '../pooling/object-pool-manager.js';
12
- const gzip = promisify(zlib.gzip);
13
- const deflate = promisify(zlib.deflate);
9
+ // `node:https` and `node:zlib` are resolved on first use rather than at import
10
+ // time. This module is on every app's startup path, but plaintext HTTP apps
11
+ // never touch https (~1.9 MB RSS, it drags in tls) and uncompressed responses
12
+ // never touch zlib (~0.3 MB). Builtins are always synchronously requirable, so
13
+ // the secure-server and compression paths stay fully synchronous.
14
+ // Resolves Node builtins ONLY, so the base passed to createRequire is
15
+ // irrelevant - 'file:///' is used instead of import.meta.url so this file still
16
+ // compiles under the CJS transform Jest applies to the test suite.
17
+ const requireBuiltin = createRequire('file:///');
18
+ // `node:http` is pulled through createRequire rather than `import`. In an ESM
19
+ // package the two are NOT equivalent: building the ESM facade for node:http
20
+ // drags in http2, tls, zlib and worker_threads and costs ~10.4 MB RSS, while
21
+ // require('http') costs ~0.9 MB and pulls only net. Same objects, same
22
+ // semantics - measurably less memory. See also the lazy https/zlib below.
23
+ const http = requireBuiltin('http');
24
+ const createServer = http.createServer;
25
+ let gzipFn;
26
+ let deflateFn;
27
+ function compressors() {
28
+ if (!gzipFn) {
29
+ const zlib = requireBuiltin('zlib');
30
+ gzipFn = promisify(zlib.gzip);
31
+ deflateFn = promisify(zlib.deflate);
32
+ }
33
+ return {
34
+ gzip: gzipFn,
35
+ deflate: deflateFn,
36
+ };
37
+ }
14
38
  const JSON_CONTENT_TYPE = 'application/json; charset=utf-8';
15
39
  const STATUS_MESSAGES = {
16
40
  200: 'OK',
@@ -83,7 +107,7 @@ function parseCookieHeader(cookieHeader) {
83
107
  // the `_server` back-reference, so methods can reach server config (logger,
84
108
  // compression settings) without any per-request allocation.
85
109
  // ---------------------------------------------------------------------------
86
- export class MoroIncomingMessage extends IncomingMessage {
110
+ export class MoroIncomingMessage extends http.IncomingMessage {
87
111
  // Hot per-request fields (assigned in handleRequest; declared here for
88
112
  // stable shape). Everything else lives behind the single `_lazy` slot -
89
113
  // per-request construction pays 5 field initializations instead of 16.
@@ -327,7 +351,7 @@ export class MoroIncomingMessage extends IncomingMessage {
327
351
  return false;
328
352
  }
329
353
  }
330
- export class MoroServerResponse extends ServerResponse {
354
+ export class MoroServerResponse extends http.ServerResponse {
331
355
  _locals = undefined;
332
356
  get locals() {
333
357
  let l = this._locals;
@@ -354,7 +378,8 @@ export class MoroServerResponse extends ServerResponse {
354
378
  const acceptEncoding = this.req?.headers['accept-encoding'];
355
379
  if (acceptEncoding && acceptEncoding.includes('gzip')) {
356
380
  const buffer = Buffer.from(jsonString, 'utf8');
357
- gzip(buffer)
381
+ compressors()
382
+ .gzip(buffer)
358
383
  .then(compressed => {
359
384
  if (this.headersSent)
360
385
  return;
@@ -385,7 +410,8 @@ export class MoroServerResponse extends ServerResponse {
385
410
  }
386
411
  else if (acceptEncoding && acceptEncoding.includes('deflate')) {
387
412
  const buffer = Buffer.from(jsonString, 'utf8');
388
- deflate(buffer)
413
+ compressors()
414
+ .deflate(buffer)
389
415
  .then(compressed => {
390
416
  if (this.headersSent)
391
417
  return;
@@ -935,7 +961,8 @@ export class MoroHttpServer {
935
961
  if (options?.ssl) {
936
962
  // In-process HTTPS. The https ServerOptions extends the http one, so the
937
963
  // IncomingMessage/ServerResponse subclass injection carries over.
938
- this.server = createHttpsServer({ ...serverOpts, ...options.ssl }, this.handleRequest.bind(this));
964
+ const https = requireBuiltin('https');
965
+ this.server = https.createServer({ ...serverOpts, ...options.ssl }, this.handleRequest.bind(this));
939
966
  this.logger.info('HTTPS server created (in-process TLS)', 'HttpServer');
940
967
  }
941
968
  else {