@morojs/moro 1.8.4 → 1.8.6

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>
@@ -1142,7 +1142,9 @@ export class MoroHttpServer {
1142
1142
  httpReq.method === MoroHttpServer.METHOD_PATCH;
1143
1143
  const hookManager = this.hookManager;
1144
1144
  const hasHooks = !!(hookManager &&
1145
- (hookManager.hasHooks === undefined || hookManager.hasHooks('request')));
1145
+ (hookManager.hasHooks === undefined ||
1146
+ hookManager.hasHooks('request') ||
1147
+ hookManager.hasHooks('response')));
1146
1148
  if (needsBody || hasHooks || this.globalMiddleware.length > 0) {
1147
1149
  // Slow path: real awaits ahead (body parse / hooks / middleware).
1148
1150
  // Errors are fully handled inside - the returned promise never rejects.
@@ -1190,6 +1192,14 @@ export class MoroHttpServer {
1190
1192
  request: httpReq,
1191
1193
  response: httpRes,
1192
1194
  });
1195
+ // Post-response hooks (session persistence, auth session refresh,
1196
+ // CDN invalidation) run after the response is flushed, off the
1197
+ // request's critical path.
1198
+ if (this.hookManager.hasHooks === undefined || this.hookManager.hasHooks('response')) {
1199
+ httpRes.once('finish', () => {
1200
+ void Promise.resolve(this.hookManager.execute('response', { request: httpReq, response: httpRes })).catch((error) => this.logger?.error?.(`Response hook error: ${error?.message || error}`, 'Hooks'));
1201
+ });
1202
+ }
1193
1203
  }
1194
1204
  // executeMiddleware returns undefined when the whole chain completed
1195
1205
  // synchronously, so a sync chain costs zero promise allocations.
@@ -1273,6 +1283,13 @@ export class MoroHttpServer {
1273
1283
  // Shared error handling for all request paths (sync throw, slow-path catch,
1274
1284
  // and promise rejections from async handlers/middleware). Never throws.
1275
1285
  async onRequestError(error, httpReq, httpRes, req) {
1286
+ // Error hooks are observational (Sentry-style reporting, audit trails):
1287
+ // fire-and-forget so a slow or throwing observer can never delay or
1288
+ // alter the error response.
1289
+ if (this.hookManager &&
1290
+ (this.hookManager.hasHooks === undefined || this.hookManager.hasHooks('error'))) {
1291
+ void Promise.resolve(this.hookManager.execute('error', { request: httpReq, response: httpRes, error })).catch((hookError) => this.logger?.error?.(`Error hook error: ${hookError?.message || hookError}`, 'Hooks'));
1292
+ }
1276
1293
  try {
1277
1294
  // Debug: Log the actual error and where it came from
1278
1295
  this.logger.debug('Request error details', 'RequestHandler', {