vibe-gx 1.0.7 โ†’ 3.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.
package/README.md CHANGED
@@ -2,159 +2,305 @@
2
2
  <img src="./assets/vlogo.png" alt="Vibe Logo" width="180" />
3
3
  <h1>Vibe</h1>
4
4
  <p>
5
- <b>A lightweight, high-performance Node.js web framework built for speed and scalability.</b>
5
+ <b>The fastest Node.js web framework with the simplest syntax.</b>
6
+ </p>
7
+ <p>
8
+ <img src="https://img.shields.io/badge/performance-14,687_RPS-brightgreen" alt="Performance" />
9
+ <img src="https://img.shields.io/badge/vs_Express-2.2x_faster-blue" alt="vs Express" />
10
+ <img src="https://img.shields.io/badge/vs_Fastify-30%25_faster-orange" alt="vs Fastify" />
11
+ <img src="https://img.shields.io/badge/license-MIT-green" alt="License" />
6
12
  </p>
7
13
  </div>
8
14
 
9
15
  ---
10
16
 
11
- Vibe (part of the **GeNeSix** ecosystem) is a zero-dependency\* web framework with **Radix Trie routing**, **cluster mode**, **response caching**, and a **Fastify-style plugin system**.
17
+ ## ๐Ÿ“ฆ Installation
18
+
19
+ ```bash
20
+ npm install vibe-gx
21
+ ```
22
+
23
+ ### Optional: Build C++ Native Module
24
+
25
+ For maximum performance, build the optional C++ native module:
26
+
27
+ ```bash
28
+ npm run build:native
29
+ ```
30
+
31
+ > If the build fails, Vibe automatically falls back to pure JavaScript with zero configuration.
32
+
33
+ ---
34
+
35
+ ## ๐Ÿ† Why Vibe?
36
+
37
+ | Metric | Vibe | Express | Fastify |
38
+ | :------------------------ | :------------: | :-------: | :--------: |
39
+ | **JSON Performance** | **14,687 RPS** | 6,629 RPS | 11,289 RPS |
40
+ | **Install Size** | **~280 KB** | ~5 MB | ~4 MB |
41
+ | **Lines for Hello World** | 3 | 5 | 6 |
42
+ | **Dependencies** | 2 | 30+ | 15+ |
43
+ | **Built-in Clustering** | โœ… | โŒ | โŒ |
44
+ | **Built-in Caching** | โœ… | โŒ | โŒ |
45
+ | **C++ Optimizations** | โœ… | โŒ | โŒ |
12
46
 
13
- > **Dependency Note:** The only dependency is `busboy` for multipart file parsing.
47
+ > **Vibe is faster than Fastify, simpler than Express, and 14-18x smaller than both.**
48
+
49
+ ---
14
50
 
15
51
  ## โšก Features
16
52
 
17
- | Feature | Description |
18
- | :----------------------- | :-------------------------------------------- |
19
- | ๐Ÿš€ **Radix Trie Router** | O(log n) route matching with hybrid mode |
20
- | ๐Ÿ”Œ **Plugin System** | Fastify-style `register()` with encapsulation |
21
- | ๐ŸŽจ **Decorators** | Extend app, request, and response |
22
- | โšก **Cluster Mode** | Multi-process scaling |
23
- | ๐Ÿ’พ **Response Caching** | LRU cache with ETag support |
24
- | ๐Ÿ”— **Connection Pool** | Generic pool for database connections |
25
- | ๐Ÿ“‚ **Streaming** | Stream large files without buffering |
53
+ | Feature | Description |
54
+ | :----------------------- | :--------------------------------------------------------- |
55
+ | ๐Ÿš€ **C++ Native Module** | JSON stringify & URL parsing in C++ |
56
+ | ๐ŸŽฏ **Hybrid Router** | O(1) static + O(log n) Trie routing |
57
+ | ๐Ÿ”Œ **Plugin System** | Fastify-style `register()` with encapsulation |
58
+ | ๐ŸŽจ **Decorators** | Extend app, request, and response |
59
+ | โšก **Cluster Mode** | Built-in multi-process scaling |
60
+ | ๐Ÿ’พ **LRU Cache** | Built-in response caching with ETag |
61
+ | ๐Ÿ”— **Connection Pool** | Generic pool for databases |
62
+ | ๐Ÿ“‚ **File Uploads** | Multipart uploads with size/type validation |
63
+ | ๐ŸŒŠ **Streaming** | Large file uploads without buffering |
64
+ | ๐Ÿ”’ **Security** | Path traversal protection, body limits, error sanitization |
65
+ | ๐Ÿ”„ **Express Adapter** | Use any Express middleware with `adapt()` |
66
+
67
+ ---
26
68
 
27
69
  ## ๐Ÿš€ Quick Start
28
70
 
29
71
  ```javascript
30
- import vibe from "./vibe.js";
72
+ import vibe from "vibe-gx";
31
73
 
32
74
  const app = vibe();
33
75
 
76
+ // Direct value - no callback needed!
34
77
  app.get("/", "Hello Vibe!");
35
- app.get("/users/:id", (req, res) => ({ userId: req.params.id }));
78
+
79
+ // Auto JSON response - just return an object
80
+ app.get("/users/:id", (req) => ({ userId: req.params.id }));
36
81
 
37
82
  app.listen(3000);
38
83
  ```
39
84
 
85
+ **That's it.** No `res.send()`, no `res.json()` - just return data.
86
+
87
+ ---
88
+
40
89
  ## ๐Ÿ“– Core API
41
90
 
42
91
  ### Routes
43
92
 
93
+ Vibe supports all standard HTTP methods with a clean, flexible syntax:
94
+
44
95
  ```javascript
45
- app.get("/path", handler);
46
- app.post("/path", { intercept: authMiddleware }, handler);
47
- app.del("/path", handler); // DELETE
96
+ // String response
97
+ app.get("/", "Hello World");
98
+
99
+ // JSON response (just return an object)
100
+ app.get("/json", { message: "Hello" });
101
+
102
+ // Handler function with request access
103
+ app.get("/users/:id", (req) => ({ id: req.params.id }));
104
+
105
+ // Multiple route parameters
106
+ app.get("/posts/:postId/comments/:commentId", (req) => ({
107
+ postId: req.params.postId,
108
+ commentId: req.params.commentId,
109
+ }));
110
+
111
+ // With options (interceptors, file uploads)
112
+ app.post("/protected", { intercept: authCheck }, handler);
113
+
114
+ // All HTTP methods
115
+ app.get("/");
116
+ app.post("/");
117
+ app.put("/");
118
+ app.del("/"); // DELETE
119
+ app.patch("/");
120
+ app.head("/");
48
121
  ```
49
122
 
50
- ### Plugins (Fastify-style)
123
+ ### Query Parameters
51
124
 
52
125
  ```javascript
53
- app.register(
54
- async (app) => {
55
- app.get("/status", { status: "ok" });
56
- },
57
- { prefix: "/api" },
58
- );
126
+ // GET /search?q=hello&page=2
127
+ app.get("/search", (req) => ({
128
+ query: req.query.q, // "hello"
129
+ page: req.query.page, // "2"
130
+ }));
59
131
  ```
60
132
 
61
- ### Decorators
133
+ ### Request Body
62
134
 
63
135
  ```javascript
64
- app.decorate("config", { env: "prod" });
65
- app.decorateRequest("user", null);
66
- app.decorateReply("sendSuccess", function (d) {
67
- this.success(d);
136
+ app.post("/users", (req) => {
137
+ const { name, email } = req.body;
138
+ return { created: { name, email } };
68
139
  });
69
140
  ```
70
141
 
71
142
  ---
72
143
 
73
- ## ๐Ÿ”ฅ Scalability Features
144
+ ## ๐Ÿ”Œ Plugins (Fastify-style)
74
145
 
75
- ### Cluster Mode
146
+ Plugins provide encapsulated route groups with optional prefixes:
76
147
 
77
148
  ```javascript
78
- import vibe, { clusterize } from "./vibe.js";
149
+ // Register a plugin with prefix
150
+ await app.register(
151
+ async (api) => {
152
+ api.get("/status", { status: "ok" }); // GET /api/status
153
+ api.get("/health", { healthy: true }); // GET /api/health
154
+
155
+ // Plugins can have their own interceptors
156
+ api.plugin((req, res) => {
157
+ console.log(`[API] ${req.method} ${req.url}`);
158
+ });
159
+ },
160
+ { prefix: "/api" },
161
+ );
79
162
 
80
- clusterize(
81
- () => {
82
- const app = vibe();
83
- app.get("/", "Hello from worker!");
84
- app.listen(3000);
163
+ // Nested plugins
164
+ await app.register(
165
+ async (v1) => {
166
+ v1.get("/users", { version: 1 }); // GET /api/v1/users
85
167
  },
86
- { workers: 4, restart: true },
168
+ { prefix: "/api/v1" },
87
169
  );
88
170
  ```
89
171
 
90
- ### Response Caching
172
+ ---
91
173
 
92
- ```javascript
93
- import vibe, { LRUCache, cacheMiddleware } from "./vibe.js";
174
+ ## ๐Ÿ›ก๏ธ Interceptors (Middleware)
94
175
 
95
- const app = vibe();
96
- const cache = new LRUCache({ max: 1000, ttl: 60000 });
176
+ Interceptors run before your handler. Return `false` to stop execution.
97
177
 
98
- app.get("/data", { intercept: cacheMiddleware(cache) }, () => {
99
- return { expensive: "computation" };
178
+ ### Single Interceptor
179
+
180
+ ```javascript
181
+ const authCheck = (req, res) => {
182
+ if (!req.headers.authorization) {
183
+ res.unauthorized("Token required");
184
+ return false; // Stop execution
185
+ }
186
+ req.user = { id: 1 };
187
+ return true; // Continue to handler
188
+ };
189
+
190
+ app.get("/protected", { intercept: authCheck }, (req) => {
191
+ return { user: req.user };
100
192
  });
101
193
  ```
102
194
 
103
- ### Connection Pool
195
+ ### Multiple Interceptors
104
196
 
105
197
  ```javascript
106
- import vibe, { createPool } from "./vibe.js";
198
+ app.get(
199
+ "/admin",
200
+ {
201
+ intercept: [authCheck, adminCheck, rateLimiter],
202
+ },
203
+ handler,
204
+ );
205
+ ```
107
206
 
108
- const dbPool = createPool({
109
- create: async () => new DBConnection(),
110
- destroy: async (conn) => conn.close(),
111
- max: 10,
207
+ ### Global Interceptors
208
+
209
+ ```javascript
210
+ // Applies to ALL routes
211
+ app.plugin((req, res) => {
212
+ console.log(`${req.method} ${req.url}`);
112
213
  });
214
+ ```
215
+
216
+ ---
113
217
 
114
- app.decorate("db", dbPool);
218
+ ## ๐ŸŽจ Decorators
115
219
 
116
- app.get("/users", async (req, res) => {
117
- return await app.decorators.db.use(async (conn) => {
118
- return conn.query("SELECT * FROM users");
119
- });
220
+ Extend app, request, or response with custom properties:
221
+
222
+ ```javascript
223
+ // App decorator - shared config
224
+ app.decorate("config", { env: "production", version: "1.0.0" });
225
+
226
+ // Access via app.decorators in main app
227
+ app.get("/version", () => ({ version: app.decorators.config.version }));
228
+
229
+ // In plugins, decorators are spread directly (no .decorators)
230
+ app.register(
231
+ async (api) => {
232
+ api.get("/env", () => ({ env: api.config.env })); // Direct access
233
+ },
234
+ { prefix: "/api" },
235
+ );
236
+
237
+ // Request decorator - add to all requests
238
+ app.decorateRequest("timestamp", () => Date.now());
239
+
240
+ app.get("/time", (req) => ({ timestamp: req.timestamp }));
241
+
242
+ // Reply decorator - add methods to response
243
+ app.decorateReply("sendSuccess", function (data) {
244
+ this.success(data);
120
245
  });
121
246
  ```
122
247
 
123
- ### File Uploads
248
+ ---
249
+
250
+ ## ๐Ÿ“‚ File Uploads
124
251
 
125
- Vibe supports multipart file uploads with built-in validation.
252
+ Vibe supports multipart file uploads with built-in validation and security.
126
253
 
127
- #### Basic File Upload
254
+ > **๐Ÿ”’ Security**: File uploads are **disabled by default**. You must explicitly configure `media` options to accept uploads.
255
+
256
+ ### Basic Upload
128
257
 
129
258
  ```javascript
130
- app.post("/upload", { media: { dest: "uploads" } }, (req, res) => {
259
+ app.post("/upload", { media: { dest: "uploads" } }, (req) => {
131
260
  return { files: req.files, body: req.body };
132
261
  });
133
262
  ```
134
263
 
135
- #### Media Options
264
+ ### Media Options
136
265
 
137
266
  ```javascript
138
267
  app.post(
139
268
  "/upload",
140
269
  {
141
270
  media: {
142
- dest: "uploads", // Folder to save files
271
+ dest: "uploads", // Subfolder destination
143
272
  public: true, // Save inside public folder (default: true)
144
273
  maxSize: 5 * 1024 * 1024, // Max file size: 5MB
145
- allowedTypes: ["image/jpeg", "image/png", "application/pdf"],
274
+ allowedTypes: ["image/jpeg", "image/png", "image/*"], // Wildcards supported
146
275
  },
147
276
  },
148
277
  handler,
149
278
  );
150
279
  ```
151
280
 
152
- #### Streaming Uploads (Large Files)
281
+ ### Uploaded File Object
282
+
283
+ ```javascript
284
+ // req.files contains:
285
+ [
286
+ {
287
+ filename: "image-a7x92b.png", // Saved filename (safe)
288
+ originalName: "photo.png", // Original filename
289
+ type: "image/png", // MIME type
290
+ filePath: "/uploads/image-a7x92b.png", // Full path
291
+ size: 102400, // Size in bytes
292
+ },
293
+ ];
294
+ ```
295
+
296
+ ### Streaming Uploads (Large Files)
297
+
298
+ For large files, use streaming mode to avoid buffering in memory:
153
299
 
154
300
  ```javascript
155
301
  import fs from "fs";
156
302
 
157
- app.post("/upload", { media: { streaming: true } }, (req, res) => {
303
+ app.post("/upload-large", { media: { streaming: true } }, (req) => {
158
304
  req.on("file", (name, stream, info) => {
159
305
  stream.pipe(fs.createWriteStream(`/uploads/${info.filename}`));
160
306
  });
@@ -162,65 +308,186 @@ app.post("/upload", { media: { streaming: true } }, (req, res) => {
162
308
  });
163
309
  ```
164
310
 
165
- #### Uploaded File Object
311
+ ### Error Handling
312
+
313
+ - **413 Payload Too Large** - File exceeds `maxSize`
314
+ - **415 Unsupported Media Type** - File type not in `allowedTypes`
315
+
316
+ ---
317
+
318
+ ## ๐Ÿ”ฅ Scalability
319
+
320
+ ### Cluster Mode
321
+
322
+ Scale across all CPU cores automatically:
166
323
 
167
324
  ```javascript
168
- // req.files contains:
169
- [
325
+ import vibe, { clusterize, isPrimary, getWorkerId } from "vibe-gx";
326
+
327
+ clusterize(
328
+ () => {
329
+ const app = vibe();
330
+ app.get("/", `Hello from worker ${getWorkerId()}!`);
331
+ app.listen(3000);
332
+ },
170
333
  {
171
- filename: "image-a7x92b.png", // Saved filename
172
- originalName: "photo.png", // Original filename
173
- type: "image/png", // MIME type
174
- filePath: "/uploads/image.png", // Full path
175
- size: 102400, // Size in bytes
334
+ workers: 4, // Number of workers (default: CPU count)
335
+ restart: true, // Auto-restart crashed workers
336
+ restartDelay: 1000, // Delay before restart (ms)
176
337
  },
177
- ];
338
+ );
178
339
  ```
179
340
 
180
- ---
341
+ ### LRU Cache
181
342
 
182
- ### Interceptors (Middleware)
343
+ Built-in response caching with ETag support:
183
344
 
184
- Interceptors run before your handler. Return `false` to stop execution.
345
+ ```javascript
346
+ import vibe, { LRUCache, cacheMiddleware } from "vibe-gx";
185
347
 
186
- #### Single Interceptor
348
+ const cache = new LRUCache({
349
+ max: 1000, // Maximum entries
350
+ ttl: 60000, // TTL in milliseconds (60 seconds)
351
+ });
352
+
353
+ app.get("/expensive", { intercept: cacheMiddleware(cache) }, async () => {
354
+ // This only runs on cache MISS
355
+ return await expensiveOperation();
356
+ });
357
+
358
+ // Manual cache operations
359
+ cache.set("key", { data: "value" });
360
+ cache.get("key"); // { value, expires, etag }
361
+ cache.delete("key");
362
+ cache.clear();
363
+ ```
364
+
365
+ ### Connection Pool
366
+
367
+ Generic connection pool for databases:
187
368
 
188
369
  ```javascript
189
- const authCheck = (req, res) => {
190
- if (!req.headers.authorization) {
191
- res.unauthorized("Token required");
192
- return false;
193
- }
194
- req.user = { id: 1 };
195
- return true;
196
- };
370
+ import vibe, { createPool } from "vibe-gx";
197
371
 
198
- app.get("/protected", { intercept: authCheck }, (req) => {
199
- return { user: req.user };
372
+ const dbPool = createPool({
373
+ create: async () => await connectToDatabase(),
374
+ destroy: async (conn) => await conn.close(),
375
+ validate: (conn) => conn.isAlive(),
376
+ min: 2, // Minimum connections
377
+ max: 10, // Maximum connections
378
+ acquireTimeout: 30000, // Timeout to acquire (ms)
379
+ idleTimeout: 60000, // Idle timeout (ms)
380
+ });
381
+
382
+ app.get("/users", async () => {
383
+ return await dbPool.use(async (conn) => {
384
+ return await conn.query("SELECT * FROM users");
385
+ });
200
386
  });
387
+
388
+ // Pool statistics
389
+ console.log(dbPool.stats);
390
+ // { available: 5, inUse: 2, waiting: 0, max: 10 }
391
+
392
+ // Cleanup on shutdown
393
+ process.on("SIGTERM", () => dbPool.close());
201
394
  ```
202
395
 
203
- #### Multiple Interceptors
396
+ ---
397
+
398
+ ## ๐Ÿ”„ Express Middleware Adapter
399
+
400
+ Use any Express middleware with the adapter:
204
401
 
205
402
  ```javascript
206
- app.get(
207
- "/admin",
403
+ import { adapt } from "vibe-gx/utils/helpers/adapt.js";
404
+ import cors from "cors";
405
+ import helmet from "helmet";
406
+ import compression from "compression";
407
+
408
+ app.plugin(adapt(cors()));
409
+ app.plugin(adapt(helmet()));
410
+ app.plugin(adapt(compression()));
411
+ ```
412
+
413
+ ---
414
+
415
+ ## ๐Ÿ”’ Security
416
+
417
+ Built-in protections:
418
+
419
+ | Feature | Status |
420
+ | :--------------------------------------- | :----: |
421
+ | **File upload protection** (opt-in only) | โœ… |
422
+ | Path traversal protection | โœ… |
423
+ | File type validation | โœ… |
424
+ | Body size limits (1MB JSON, 10MB files) | โœ… |
425
+ | Error sanitization (production mode) | โœ… |
426
+ | Safe filename generation | โœ… |
427
+ | Port validation | โœ… |
428
+
429
+ ### File Upload Security
430
+
431
+ Routes **reject multipart uploads by default** unless `media` is explicitly configured:
432
+
433
+ ```javascript
434
+ // โŒ This will reject file uploads with 400 Bad Request
435
+ app.post("/api/data", (req) => ({ data: req.body }));
436
+
437
+ // โœ… This accepts file uploads (explicit opt-in)
438
+ app.post(
439
+ "/upload",
208
440
  {
209
- intercept: [authCheck, adminCheck, rateLimiter],
441
+ media: {
442
+ dest: "uploads",
443
+ maxSize: 5 * 1024 * 1024,
444
+ allowedTypes: ["image/*", "application/pdf"],
445
+ },
210
446
  },
211
447
  handler,
212
448
  );
213
449
  ```
214
450
 
215
- #### Global Interceptors
451
+ This prevents attackers from uploading malicious files to unintended routes.
452
+
453
+ Set `NODE_ENV=production` for secure error handling (stack traces hidden).
454
+
455
+ ---
456
+
457
+ ## โšก Schema-Based Serialization
458
+
459
+ **Optional** performance boost: Pre-compile JSON serializers for 2-3x faster responses.
216
460
 
217
461
  ```javascript
218
- // Applies to ALL routes
219
- app.plugin((req, res) => {
220
- console.log(`${req.method} ${req.url}`);
221
- });
462
+ app.get(
463
+ "/users/:id",
464
+ {
465
+ schema: {
466
+ response: {
467
+ type: "object",
468
+ properties: {
469
+ id: { type: "number" },
470
+ name: { type: "string" },
471
+ email: { type: "string" },
472
+ active: { type: "boolean" },
473
+ },
474
+ },
475
+ },
476
+ },
477
+ async (req) => {
478
+ const user = await db.getUser(req.params.id);
479
+ return user; // Uses pre-compiled serializer (2-3x faster than JSON.stringify)
480
+ },
481
+ );
222
482
  ```
223
483
 
484
+ **Benefits:**
485
+
486
+ - โœ… 2-3x faster JSON serialization
487
+ - โœ… No `Object.keys()` enumeration
488
+ - โœ… Zero runtime type checking
489
+ - โœ… Completely optional (routes work without schemas)
490
+
224
491
  ---
225
492
 
226
493
  ### Route Options
@@ -245,34 +512,120 @@ app.post(
245
512
 
246
513
  ### Application
247
514
 
248
- | Method | Description |
249
- | :------------------------ | :---------------- |
250
- | `app.listen(port)` | Start server |
251
- | `app.register(fn, opts)` | Register plugin |
252
- | `app.decorate(name, val)` | Add app property |
253
- | `app.plugin(fn)` | Global middleware |
515
+ | Method | Description |
516
+ | :----------------------------------------------- | :------------------- |
517
+ | `app.get/post/put/del/patch/head(path, handler)` | Register route |
518
+ | `app.listen(port, host?, callback?)` | Start server |
519
+ | `app.register(fn, { prefix })` | Register plugin |
520
+ | `app.plugin(fn)` | Global interceptor |
521
+ | `app.decorate(name, value)` | Add app property |
522
+ | `app.decorateRequest(name, value)` | Add to all requests |
523
+ | `app.decorateReply(name, value)` | Add to all responses |
524
+ | `app.setPublicFolder(path)` | Set static folder |
525
+ | `app.logRoutes()` | Log all routes |
254
526
 
255
527
  ### Request (`req`)
256
528
 
257
- | Property | Description |
258
- | :----------- | :--------------- |
259
- | `req.params` | Route parameters |
260
- | `req.query` | Query strings |
261
- | `req.body` | Parsed body |
262
- | `req.files` | Uploaded files |
529
+ | Property | Description |
530
+ | :------------ | :------------------------- |
531
+ | `req.params` | Route parameters (`:id`) |
532
+ | `req.query` | Query string (`?page=1`) |
533
+ | `req.body` | Parsed JSON/form body |
534
+ | `req.files` | Uploaded files (multipart) |
535
+ | `req.ip` | Client IP address |
536
+ | `req.method` | HTTP method |
537
+ | `req.url` | Request URL |
538
+ | `req.headers` | Request headers |
263
539
 
264
540
  ### Response (`res`)
265
541
 
266
- | Method | Description |
267
- | :------------------ | :------------ |
268
- | `res.json(data)` | Send JSON |
269
- | `res.send(data)` | Send response |
270
- | `res.status(code)` | Set status |
271
- | `res.success(data)` | 200 OK |
272
- | `res.notFound()` | 404 |
542
+ | Method | Description |
543
+ | :---------------------------------- | :--------------------------- |
544
+ | `res.json(data)` | Send JSON |
545
+ | `res.send(data)` | Send any response |
546
+ | `res.status(code)` | Set status (chainable) |
547
+ | `res.redirect(url, code?)` | Redirect (302) |
548
+ | `res.sendFile(path)` | Send file from public folder |
549
+ | `res.sendAbsoluteFile(path, opts?)` | Send file from any path |
550
+ | `res.sendHtml(filename)` | Send HTML file |
551
+ | `res.success(data?, msg?)` | 200 OK |
552
+ | `res.created(data?, msg?)` | 201 Created |
553
+ | `res.badRequest(msg?, errors?)` | 400 Bad Request |
554
+ | `res.unauthorized(msg?)` | 401 Unauthorized |
555
+ | `res.forbidden(msg?)` | 403 Forbidden |
556
+ | `res.notFound(msg?)` | 404 Not Found |
557
+ | `res.conflict(msg?)` | 409 Conflict |
558
+ | `res.serverError(err?)` | 500 Server Error |
559
+
560
+ ### Cluster Utilities
561
+
562
+ | Function | Description |
563
+ | :--------------------- | :---------------------------- |
564
+ | `clusterize(fn, opts)` | Start in cluster mode |
565
+ | `isPrimary()` | Check if primary process |
566
+ | `isWorker()` | Check if worker process |
567
+ | `getWorkerId()` | Get worker ID (0 for primary) |
568
+ | `getWorkerCount()` | Get number of active workers |
569
+
570
+ ### Cache Utilities
571
+
572
+ | Class/Function | Description |
573
+ | :-------------------------- | :------------------------ |
574
+ | `new LRUCache(opts)` | Create LRU cache instance |
575
+ | `cacheMiddleware(cache)` | Create cache interceptor |
576
+ | `LRUCache.key(method, url)` | Generate cache key |
577
+ | `LRUCache.etag(value)` | Generate ETag |
578
+
579
+ ### Pool Utilities
580
+
581
+ | Class/Function | Description |
582
+ | :----------------- | :--------------------- |
583
+ | `createPool(opts)` | Create connection pool |
584
+ | `pool.acquire()` | Acquire resource |
585
+ | `pool.release(r)` | Release resource |
586
+ | `pool.use(fn)` | Use with auto-release |
587
+ | `pool.close()` | Close pool |
588
+ | `pool.stats` | Get pool statistics |
589
+
590
+ ---
591
+
592
+ ## ๐Ÿ“Š Benchmarks
593
+
594
+ Run benchmarks yourself:
595
+
596
+ ```bash
597
+ npm run benchmark
598
+ ```
599
+
600
+ Tested with 5,000 requests, 50 concurrency:
601
+
602
+ ```
603
+ Framework | JSON RPS | vs Express | vs Fastify
604
+ -------------|-------------|------------|------------
605
+ Vibe | 14,687 | 2.2x โœ… | 1.3x โœ…
606
+ Fastify | 11,289 | 1.7x | baseline
607
+ Express | 6,629 | baseline | 0.6x
608
+ ```
609
+
610
+ ---
611
+
612
+ ## ๐Ÿงช Testing
613
+
614
+ ```bash
615
+ # Run all tests
616
+ npm test
617
+
618
+ # Run comprehensive tests
619
+ npm run test:all
620
+
621
+ # Run benchmarks
622
+ npm run benchmark
623
+ ```
273
624
 
274
625
  ---
275
626
 
276
627
  ## ๐Ÿ“ License
277
628
 
278
- Part of the **GeNeSix** brand. Created by **Nnamdi "Joe" Amaga**. MIT License.
629
+ Part of the **GeNeSix** brand. Created by **Nnamdi "Joe" Amaga**.
630
+
631
+ MIT License.