@morojs/moro 1.8.12 → 1.8.14

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 (90) hide show
  1. package/README.md +4 -2
  2. package/dist/core/cluster/thread-cluster.d.ts +25 -0
  3. package/dist/core/cluster/thread-cluster.js +95 -3
  4. package/dist/core/cluster/thread-cluster.js.map +1 -1
  5. package/dist/core/config/config-validator.js +20 -0
  6. package/dist/core/config/config-validator.js.map +1 -1
  7. package/dist/core/config/index.js +19 -2
  8. package/dist/core/config/index.js.map +1 -1
  9. package/dist/core/config/schema.js +1 -0
  10. package/dist/core/config/schema.js.map +1 -1
  11. package/dist/core/framework.d.ts +26 -0
  12. package/dist/core/framework.js +195 -6
  13. package/dist/core/framework.js.map +1 -1
  14. package/dist/core/http/http-server.d.ts +19 -0
  15. package/dist/core/http/http-server.js +75 -1
  16. package/dist/core/http/http-server.js.map +1 -1
  17. package/dist/core/http/http2-server.d.ts +15 -0
  18. package/dist/core/http/http2-server.js +36 -3
  19. package/dist/core/http/http2-server.js.map +1 -1
  20. package/dist/core/http/moro-engine-server.d.ts +28 -0
  21. package/dist/core/http/moro-engine-server.js +138 -12
  22. package/dist/core/http/moro-engine-server.js.map +1 -1
  23. package/dist/core/http/utils/body-type.d.ts +12 -0
  24. package/dist/core/http/utils/body-type.js +70 -0
  25. package/dist/core/http/utils/body-type.js.map +1 -0
  26. package/dist/core/http/utils/compression.d.ts +21 -0
  27. package/dist/core/http/utils/compression.js +53 -7
  28. package/dist/core/http/utils/compression.js.map +1 -1
  29. package/dist/core/http/utils/ssl-config.d.ts +11 -0
  30. package/dist/core/http/utils/ssl-config.js +3 -0
  31. package/dist/core/http/utils/ssl-config.js.map +1 -1
  32. package/dist/core/http/utils/uws-worker-clustering.js +5 -4
  33. package/dist/core/http/utils/uws-worker-clustering.js.map +1 -1
  34. package/dist/core/http/uws-http-server.d.ts +3 -0
  35. package/dist/core/http/uws-http-server.js +47 -2
  36. package/dist/core/http/uws-http-server.js.map +1 -1
  37. package/dist/core/middleware/built-in/body-parsers/index.d.ts +18 -0
  38. package/dist/core/middleware/built-in/body-parsers/index.js +41 -0
  39. package/dist/core/middleware/built-in/body-parsers/index.js.map +1 -1
  40. package/dist/core/middleware/built-in/cache/adapters/cache/redis.d.ts +32 -8
  41. package/dist/core/middleware/built-in/cache/adapters/cache/redis.js +117 -25
  42. package/dist/core/middleware/built-in/cache/adapters/cache/redis.js.map +1 -1
  43. package/dist/core/middleware/built-in/compression/core.d.ts +7 -0
  44. package/dist/core/middleware/built-in/compression/core.js +32 -1
  45. package/dist/core/middleware/built-in/compression/core.js.map +1 -1
  46. package/dist/core/middleware/built-in/session/core.d.ts +1 -0
  47. package/dist/core/middleware/built-in/session/core.js.map +1 -1
  48. package/dist/core/middleware/built-in/static/core.d.ts +18 -0
  49. package/dist/core/middleware/built-in/static/core.js +128 -7
  50. package/dist/core/middleware/built-in/static/core.js.map +1 -1
  51. package/dist/core/networking/adapters/engine-adapter.d.ts +2 -2
  52. package/dist/core/networking/adapters/engine-adapter.js +40 -1
  53. package/dist/core/networking/adapters/engine-adapter.js.map +1 -1
  54. package/dist/core/networking/adapters/socketio-adapter.d.ts +2 -2
  55. package/dist/core/networking/adapters/socketio-adapter.js +10 -1
  56. package/dist/core/networking/adapters/socketio-adapter.js.map +1 -1
  57. package/dist/core/networking/adapters/uws-adapter.d.ts +2 -2
  58. package/dist/core/networking/adapters/uws-adapter.js +54 -3
  59. package/dist/core/networking/adapters/uws-adapter.js.map +1 -1
  60. package/dist/core/networking/adapters/ws-adapter.d.ts +9 -2
  61. package/dist/core/networking/adapters/ws-adapter.js +97 -12
  62. package/dist/core/networking/adapters/ws-adapter.js.map +1 -1
  63. package/dist/core/networking/websocket-adapter.d.ts +19 -1
  64. package/dist/core/networking/websocket-adapter.js.map +1 -1
  65. package/dist/core/routing/index.d.ts +12 -8
  66. package/dist/core/routing/index.js +7 -2
  67. package/dist/core/routing/index.js.map +1 -1
  68. package/dist/core/routing/unified-router.d.ts +46 -8
  69. package/dist/core/routing/unified-router.js +108 -32
  70. package/dist/core/routing/unified-router.js.map +1 -1
  71. package/dist/core/utilities/package-utils.d.ts +8 -1
  72. package/dist/core/utilities/package-utils.js +2 -0
  73. package/dist/core/utilities/package-utils.js.map +1 -1
  74. package/dist/core/workers/worker-manager.js +2 -2
  75. package/dist/core/workers/worker-manager.js.map +1 -1
  76. package/dist/index.d.ts +4 -3
  77. package/dist/index.js +2 -1
  78. package/dist/index.js.map +1 -1
  79. package/dist/moro.d.ts +12 -1
  80. package/dist/moro.js +63 -7
  81. package/dist/moro.js.map +1 -1
  82. package/dist/types/cache.d.ts +2 -0
  83. package/dist/types/cache.js.map +1 -1
  84. package/dist/types/config.d.ts +16 -0
  85. package/dist/types/config.js.map +1 -1
  86. package/dist/types/http.d.ts +6 -0
  87. package/dist/types/http.js.map +1 -1
  88. package/dist/types/session.d.ts +1 -0
  89. package/dist/types/session.js.map +1 -1
  90. package/package.json +1 -1
@@ -1,3 +1,4 @@
1
+ import { bodyIsText } from './utils/body-type.js';
1
2
  import { createRequire } from 'module';
2
3
  import { promisify } from 'util';
3
4
  import { randomUUID } from 'crypto';
@@ -24,15 +25,21 @@ const http = requireBuiltin('http');
24
25
  const createServer = http.createServer;
25
26
  let gzipFn;
26
27
  let deflateFn;
28
+ let gzipSyncFn;
29
+ let deflateSyncFn;
27
30
  function compressors() {
28
31
  if (!gzipFn) {
29
32
  const zlib = requireBuiltin('zlib');
30
33
  gzipFn = promisify(zlib.gzip);
31
34
  deflateFn = promisify(zlib.deflate);
35
+ gzipSyncFn = (buf) => zlib.gzipSync(buf);
36
+ deflateSyncFn = (buf) => zlib.deflateSync(buf);
32
37
  }
33
38
  return {
34
39
  gzip: gzipFn,
35
40
  deflate: deflateFn,
41
+ gzipSync: gzipSyncFn,
42
+ deflateSync: deflateSyncFn,
36
43
  };
37
44
  }
38
45
  const JSON_CONTENT_TYPE = 'application/json; charset=utf-8';
@@ -115,6 +122,10 @@ export class MoroIncomingMessage extends http.IncomingMessage {
115
122
  body = null;
116
123
  path = '';
117
124
  _queryString = null;
125
+ /** The request body exactly as received, before any parsing; null when empty. */
126
+ get rawBody() {
127
+ return this._rawBody ?? null;
128
+ }
118
129
  // Single slot for every lazily-computed/assigned helper value (query,
119
130
  // cookies, requestId, hostname, ...). Allocated on first access - a plain
120
131
  // JSON GET that never touches the helpers never allocates it, and the
@@ -378,6 +389,28 @@ export class MoroServerResponse extends http.ServerResponse {
378
389
  const acceptEncoding = this.req?.headers['accept-encoding'];
379
390
  if (acceptEncoding && acceptEncoding.includes('gzip')) {
380
391
  const buffer = Buffer.from(jsonString, 'utf8');
392
+ // A small body is compressed here and now rather than on the threadpool
393
+ // (see compressionMaxInlineBytes); a failure takes the async path below.
394
+ if (server.compressionMaxInlineBytes > 0 &&
395
+ buffer.length <= server.compressionMaxInlineBytes) {
396
+ let compressed;
397
+ try {
398
+ compressed = compressors().gzipSync(buffer);
399
+ }
400
+ catch {
401
+ compressed = undefined;
402
+ }
403
+ if (compressed !== undefined) {
404
+ this.writeHead(this.statusCode || 200, {
405
+ 'Content-Type': JSON_CONTENT_TYPE,
406
+ 'Content-Encoding': 'gzip',
407
+ Vary: 'Accept-Encoding',
408
+ 'Content-Length': compressed.length,
409
+ });
410
+ this.end(compressed);
411
+ return;
412
+ }
413
+ }
381
414
  compressors()
382
415
  .gzip(buffer)
383
416
  .then(compressed => {
@@ -410,6 +443,26 @@ export class MoroServerResponse extends http.ServerResponse {
410
443
  }
411
444
  else if (acceptEncoding && acceptEncoding.includes('deflate')) {
412
445
  const buffer = Buffer.from(jsonString, 'utf8');
446
+ if (server.compressionMaxInlineBytes > 0 &&
447
+ buffer.length <= server.compressionMaxInlineBytes) {
448
+ let compressed;
449
+ try {
450
+ compressed = compressors().deflateSync(buffer);
451
+ }
452
+ catch {
453
+ compressed = undefined;
454
+ }
455
+ if (compressed !== undefined) {
456
+ this.writeHead(this.statusCode || 200, {
457
+ 'Content-Type': JSON_CONTENT_TYPE,
458
+ 'Content-Encoding': 'deflate',
459
+ Vary: 'Accept-Encoding',
460
+ 'Content-Length': compressed.length,
461
+ });
462
+ this.end(compressed);
463
+ return;
464
+ }
465
+ }
413
466
  compressors()
414
467
  .deflate(buffer)
415
468
  .then(compressed => {
@@ -899,6 +952,9 @@ export class MoroHttpServer {
899
952
  compressionEnabled = true;
900
953
  /** @internal read by MoroServerResponse prototype methods */
901
954
  compressionThreshold = 1024;
955
+ // Bodies at or below this size compress on the calling thread (Content-Length
956
+ // response); larger ones on the threadpool. 0 sends everything to the pool.
957
+ compressionMaxInlineBytes = 16384;
902
958
  /** @internal read by MoroIncomingMessage prototype methods */
903
959
  requestTrackingEnabled = true; // Generate request IDs
904
960
  /** @internal read by MoroServerResponse prototype methods */
@@ -1007,6 +1063,9 @@ export class MoroHttpServer {
1007
1063
  if (config.compression.threshold !== undefined) {
1008
1064
  this.compressionThreshold = config.compression.threshold;
1009
1065
  }
1066
+ if (config.compression.maxInlineBytes !== undefined) {
1067
+ this.compressionMaxInlineBytes = config.compression.maxInlineBytes;
1068
+ }
1010
1069
  }
1011
1070
  // Minimal mode - disable ALL overhead for pure speed
1012
1071
  if (config.minimal) {
@@ -1562,6 +1621,8 @@ export class MoroHttpServer {
1562
1621
  const body = chunks.length === 1 && firstChunk !== undefined
1563
1622
  ? firstChunk
1564
1623
  : Buffer.concat(chunks, totalLength);
1624
+ if (totalLength > 0)
1625
+ req._rawBody = body;
1565
1626
  if (contentType.includes('application/json')) {
1566
1627
  // Empty JSON body -> null (parity with the engine/uWS servers, and
1567
1628
  // avoids JSON.parse('') throwing and 500ing an empty POST).
@@ -1574,7 +1635,9 @@ export class MoroHttpServer {
1574
1635
  resolve(this.parseMultipart(body, contentType));
1575
1636
  }
1576
1637
  else {
1577
- resolve(body.toString());
1638
+ // Text decodes to a string; binary (octet-stream, images, protobuf,
1639
+ // ...) stays a Buffer - decoding it would corrupt it irreversibly.
1640
+ resolve(bodyIsText(contentType) ? body.toString() : body);
1578
1641
  }
1579
1642
  }
1580
1643
  catch (error) {
@@ -1788,6 +1851,17 @@ export class MoroHttpServer {
1788
1851
  forceCleanup() {
1789
1852
  this.forceCleanupPools();
1790
1853
  }
1854
+ /**
1855
+ * Replace the TLS certificate/key for new handshakes (node's
1856
+ * tls.Server#setSecureContext). Throws when the server is plain HTTP.
1857
+ */
1858
+ updateSsl(ssl) {
1859
+ const server = this.server;
1860
+ if (typeof server.setSecureContext !== 'function') {
1861
+ throw new Error('updateSsl: this server was not started with TLS (server.ssl)');
1862
+ }
1863
+ server.setSecureContext(ssl);
1864
+ }
1791
1865
  getServer() {
1792
1866
  return this.server;
1793
1867
  }