@morojs/moro 1.7.29 → 1.8.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.
Files changed (67) hide show
  1. package/README.md +89 -37
  2. package/dist/core/config/config-sources.js +114 -2
  3. package/dist/core/config/config-sources.js.map +1 -1
  4. package/dist/core/config/config-validator.js +187 -5
  5. package/dist/core/config/config-validator.js.map +1 -1
  6. package/dist/core/config/schema.js +31 -3
  7. package/dist/core/config/schema.js.map +1 -1
  8. package/dist/core/framework.d.ts +41 -2
  9. package/dist/core/framework.js +338 -73
  10. package/dist/core/framework.js.map +1 -1
  11. package/dist/core/http/http-server.d.ts +21 -22
  12. package/dist/core/http/http-server.js +268 -226
  13. package/dist/core/http/http-server.js.map +1 -1
  14. package/dist/core/http/http2-server.d.ts +6 -16
  15. package/dist/core/http/http2-server.js +14 -79
  16. package/dist/core/http/http2-server.js.map +1 -1
  17. package/dist/core/http/index.d.ts +1 -0
  18. package/dist/core/http/index.js +3 -0
  19. package/dist/core/http/index.js.map +1 -1
  20. package/dist/core/http/moro-engine-server.d.ts +263 -0
  21. package/dist/core/http/moro-engine-server.js +1939 -0
  22. package/dist/core/http/moro-engine-server.js.map +1 -0
  23. package/dist/core/http/utils/compression.d.ts +47 -0
  24. package/dist/core/http/utils/compression.js +132 -0
  25. package/dist/core/http/utils/compression.js.map +1 -0
  26. package/dist/core/http/utils/lazy-event-emitter.d.ts +11 -0
  27. package/dist/core/http/utils/lazy-event-emitter.js +69 -0
  28. package/dist/core/http/utils/lazy-event-emitter.js.map +1 -0
  29. package/dist/core/http/utils/multipart-parser.d.ts +32 -0
  30. package/dist/core/http/utils/multipart-parser.js +211 -0
  31. package/dist/core/http/utils/multipart-parser.js.map +1 -0
  32. package/dist/core/http/utils/query-parser.d.ts +1 -0
  33. package/dist/core/http/utils/query-parser.js +44 -0
  34. package/dist/core/http/utils/query-parser.js.map +1 -0
  35. package/dist/core/http/utils/size.d.ts +33 -0
  36. package/dist/core/http/utils/size.js +37 -0
  37. package/dist/core/http/utils/size.js.map +1 -0
  38. package/dist/core/http/utils/ssl-config.d.ts +69 -0
  39. package/dist/core/http/utils/ssl-config.js +116 -0
  40. package/dist/core/http/utils/ssl-config.js.map +1 -0
  41. package/dist/core/http/utils/uws-worker-clustering.js +8 -2
  42. package/dist/core/http/utils/uws-worker-clustering.js.map +1 -1
  43. package/dist/core/http/uws-http-server.d.ts +24 -3
  44. package/dist/core/http/uws-http-server.js +386 -65
  45. package/dist/core/http/uws-http-server.js.map +1 -1
  46. package/dist/core/middleware/built-in/compression/core.d.ts +3 -0
  47. package/dist/core/middleware/built-in/compression/core.js +28 -34
  48. package/dist/core/middleware/built-in/compression/core.js.map +1 -1
  49. package/dist/core/networking/adapters/engine-adapter.d.ts +23 -0
  50. package/dist/core/networking/adapters/engine-adapter.js +365 -0
  51. package/dist/core/networking/adapters/engine-adapter.js.map +1 -0
  52. package/dist/core/networking/adapters/index.d.ts +1 -0
  53. package/dist/core/networking/adapters/index.js +1 -0
  54. package/dist/core/networking/adapters/index.js.map +1 -1
  55. package/dist/core/networking/adapters/uws-adapter.js +26 -15
  56. package/dist/core/networking/adapters/uws-adapter.js.map +1 -1
  57. package/dist/core/utilities/package-utils.d.ts +68 -0
  58. package/dist/core/utilities/package-utils.js +198 -1
  59. package/dist/core/utilities/package-utils.js.map +1 -1
  60. package/dist/index.d.ts +1 -1
  61. package/dist/index.js +1 -1
  62. package/dist/index.js.map +1 -1
  63. package/dist/moro.d.ts +2 -0
  64. package/dist/moro.js +63 -21
  65. package/dist/moro.js.map +1 -1
  66. package/dist/types/config.d.ts +90 -5
  67. package/package.json +4 -1
@@ -1,7 +1,8 @@
1
1
  // Package and Module Resolution Utilities
2
2
  // ESM-compatible helpers for detecting and resolving optional dependencies
3
3
  import { createRequire } from 'module';
4
- import { join } from 'path';
4
+ import { dirname, join } from 'path';
5
+ import { existsSync, realpathSync } from 'fs';
5
6
  import { pathToFileURL } from 'url';
6
7
  /**
7
8
  * Check if a package is available in the user's node_modules
@@ -55,6 +56,202 @@ export function resolveUserPackage(packageName) {
55
56
  export function createUserRequire() {
56
57
  return createRequire(join(process.cwd(), 'package.json'));
57
58
  }
59
+ // ---------------------------------------------------------------------------
60
+ // Native HTTP engine loading
61
+ // ---------------------------------------------------------------------------
62
+ /**
63
+ * Package names probed for the native HTTP engine, in priority order.
64
+ * '@morojs/engine' is Moro's own engine (installed as an optionalDependency of
65
+ * the framework); 'uWebSockets.js' is honored as a legacy user-installed peer.
66
+ */
67
+ export const NATIVE_ENGINE_PACKAGES = ['@morojs/engine', 'uWebSockets.js'];
68
+ const FRAMEWORK_PACKAGE_NAME = '@morojs/moro';
69
+ const NO_CAPABILITIES = {
70
+ limits: false,
71
+ tls: false,
72
+ http2: false,
73
+ wsDeflate: false,
74
+ };
75
+ const capabilitiesCache = new WeakMap();
76
+ /**
77
+ * Feature-detect a loaded engine module. Reads probe().capabilities when the
78
+ * engine exposes it (>= 1.1.0); otherwise everything is false so the framework
79
+ * passes only the options an older engine understood. uWS-style modules (no
80
+ * probe/serve) report all-false — their SSL/limits go through the uWS-specific
81
+ * paths, not these flags.
82
+ */
83
+ export function getEngineCapabilities(module) {
84
+ const surface = module?.default || module;
85
+ if (!surface || typeof surface !== 'object')
86
+ return NO_CAPABILITIES;
87
+ const cached = capabilitiesCache.get(surface);
88
+ if (cached)
89
+ return cached;
90
+ let caps = NO_CAPABILITIES;
91
+ try {
92
+ if (typeof surface.probe === 'function') {
93
+ const probe = surface.probe();
94
+ const c = probe?.capabilities;
95
+ if (c && typeof c === 'object') {
96
+ caps = {
97
+ limits: c.limits === true,
98
+ tls: c.tls === true,
99
+ http2: c.http2 === true,
100
+ wsDeflate: c.wsDeflate === true,
101
+ };
102
+ }
103
+ }
104
+ }
105
+ catch {
106
+ caps = NO_CAPABILITIES;
107
+ }
108
+ capabilitiesCache.set(surface, caps);
109
+ return caps;
110
+ }
111
+ // undefined = never attempted, null = attempted and failed
112
+ let cachedEngine;
113
+ let engineLoadErrors = [];
114
+ /**
115
+ * Locate the installed framework package directory so the engine (a dependency
116
+ * of moro, not of the user's app) resolves under strict layouts like pnpm's.
117
+ * Walks up from cwd looking for node_modules/@morojs/moro, resolving symlinks
118
+ * so pnpm's store-linked layout anchors requires next to moro's own deps.
119
+ * Inside the framework repo itself (tests, examples) cwd is the framework dir.
120
+ */
121
+ function findFrameworkAnchor() {
122
+ try {
123
+ const cwdPackageJson = join(process.cwd(), 'package.json');
124
+ if (existsSync(cwdPackageJson)) {
125
+ const require = createRequire(cwdPackageJson);
126
+ const name = require(cwdPackageJson)?.name;
127
+ if (name === FRAMEWORK_PACKAGE_NAME) {
128
+ return require;
129
+ }
130
+ }
131
+ }
132
+ catch {
133
+ // fall through to the node_modules walk
134
+ }
135
+ let dir = process.cwd();
136
+ for (;;) {
137
+ const packageJson = join(dir, 'node_modules', '@morojs', 'moro', 'package.json');
138
+ try {
139
+ if (existsSync(packageJson)) {
140
+ return createRequire(join(realpathSync(dirname(packageJson)), 'package.json'));
141
+ }
142
+ }
143
+ catch {
144
+ // unreadable/broken link - keep walking up
145
+ }
146
+ const parent = dirname(dir);
147
+ if (parent === dir)
148
+ return null;
149
+ dir = parent;
150
+ }
151
+ }
152
+ /**
153
+ * Synchronously load the native HTTP engine, trying '@morojs/engine' first and
154
+ * falling back to a user-installed 'uWebSockets.js'. Loading is require-based
155
+ * (both packages are CJS at their core - .node addon loading is require-based),
156
+ * so the instance is shared with any later import() via the CJS module cache.
157
+ *
158
+ * The default call is memoized: the engine either loads once per process or it
159
+ * doesn't. Failure details are retained for logging via
160
+ * getNativeEngineLoadErrors().
161
+ *
162
+ * @param options.candidates - Override the probed package names (testing).
163
+ * When provided, the call bypasses the cache.
164
+ * @returns The loaded engine and its source package, or null if none loads
165
+ */
166
+ export function loadNativeEngine(options) {
167
+ const useCache = !options?.candidates;
168
+ if (useCache && cachedEngine !== undefined) {
169
+ if (options?.collectErrors && !cachedEngine) {
170
+ options.collectErrors.push(...engineLoadErrors);
171
+ }
172
+ return cachedEngine;
173
+ }
174
+ const candidates = options?.candidates ?? NATIVE_ENGINE_PACKAGES;
175
+ const errors = [];
176
+ let result = null;
177
+ const frameworkRequire = findFrameworkAnchor();
178
+ const userRequire = createUserRequire();
179
+ for (const candidate of candidates) {
180
+ // Moro's own engine lives in moro's dependencies (framework anchor first);
181
+ // the legacy uWS peer dep lives in the user's node_modules (cwd first).
182
+ const anchors = candidate === 'uWebSockets.js'
183
+ ? [userRequire, frameworkRequire]
184
+ : [frameworkRequire, userRequire];
185
+ for (const anchor of anchors) {
186
+ if (!anchor)
187
+ continue;
188
+ try {
189
+ const module = anchor(candidate);
190
+ // Capability check: the HTTP server needs either a uWS-style App()
191
+ // factory or the Moro-shaped engine surface (serve()/respond()).
192
+ // A package that loads but can't serve (e.g. a pre-M1 @morojs/engine
193
+ // that only exposes probe()) must not shadow a usable alternative.
194
+ const surface = module?.default || module;
195
+ const uwsStyle = typeof surface?.App === 'function';
196
+ const moroStyle = !uwsStyle &&
197
+ typeof surface?.serve === 'function' &&
198
+ typeof surface?.respond === 'function';
199
+ if (!uwsStyle && !moroStyle) {
200
+ errors.push(`${candidate}: loaded but provides neither App() nor serve()/respond() - not a usable HTTP engine`);
201
+ continue;
202
+ }
203
+ let version;
204
+ try {
205
+ // May be blocked by the package's exports map - version is optional
206
+ version = anchor(`${candidate}/package.json`)?.version;
207
+ }
208
+ catch {
209
+ version = undefined;
210
+ }
211
+ result = {
212
+ module,
213
+ source: candidate,
214
+ version,
215
+ capabilities: moroStyle ? getEngineCapabilities(module) : NO_CAPABILITIES,
216
+ };
217
+ break;
218
+ }
219
+ catch (error) {
220
+ const message = error instanceof Error ? error.message.split('\n')[0] : String(error);
221
+ errors.push(`${candidate}: ${message}`);
222
+ }
223
+ }
224
+ if (result)
225
+ break;
226
+ }
227
+ // Candidate-override probes (e.g. the clustering worker's uWS-only check)
228
+ // must not clobber the diagnostics of the real default load, which
229
+ // framework startup logging reads via getNativeEngineLoadErrors().
230
+ if (useCache) {
231
+ engineLoadErrors = result ? [] : [...new Set(errors)];
232
+ cachedEngine = result;
233
+ }
234
+ // Hand this specific call's failure detail back to a caller that asked for it,
235
+ // regardless of caching (so 'moro'/'uws' fallback reasons are precise).
236
+ if (options?.collectErrors && !result) {
237
+ options.collectErrors.push(...new Set(errors));
238
+ }
239
+ return result;
240
+ }
241
+ /**
242
+ * Failure details from the most recent unsuccessful loadNativeEngine() call,
243
+ * one entry per package/anchor attempt. Empty after a successful load.
244
+ */
245
+ export function getNativeEngineLoadErrors() {
246
+ return engineLoadErrors;
247
+ }
248
+ /**
249
+ * Clear the memoized engine load result. Testing only.
250
+ */
251
+ export function resetNativeEngineLoaderForTesting() {
252
+ cachedEngine = undefined;
253
+ engineLoadErrors = [];
254
+ }
58
255
  /**
59
256
  * Convert a file path to a file URL for ESM dynamic imports
60
257
  * This is required on Windows where absolute paths like C:\path\to\module
@@ -1 +1 @@
1
- {"version":3,"file":"package-utils.js","sourceRoot":"","sources":["../../../src/core/utilities/package-utils.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,2EAA2E;AAE3E,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAmB;IACpD,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;QACvE,WAAW,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAmB;IACpD,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;IACvE,OAAO,WAAW,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAgB;IAClD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,0EAA0E;IAC1E,IACE,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC;QAC9B,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC;QAC9B,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,EAC/B,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,qDAAqD;IACrD,MAAM,wBAAwB,GAAG,kBAAkB,CAAC;IACpD,MAAM,iBAAiB,GAAG,wBAAwB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAElE,qDAAqD;IACrD,MAAM,cAAc,GAAG,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAEhD,oDAAoD;IACpD,MAAM,YAAY,GAAG,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAEjD,sCAAsC;IACtC,IAAI,iBAAiB,IAAI,cAAc,IAAI,YAAY,EAAE,CAAC;QACxD,OAAO,aAAa,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;IACtC,CAAC;IAED,2DAA2D;IAC3D,OAAO,QAAQ,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"package-utils.js","sourceRoot":"","sources":["../../../src/core/utilities/package-utils.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ export type { RuntimeType, RuntimeAdapter, RuntimeConfig, RuntimeHttpResponse, }
8
8
  export { NodeRuntimeAdapter, VercelEdgeAdapter, AWSLambdaAdapter, CloudflareWorkersAdapter, createRuntimeAdapter, createNodeHandler, createEdgeHandler, createLambdaHandler, createWorkerHandler, } from './core/runtime/index.js';
9
9
  export type { LambdaEvent, LambdaContext, LambdaResponse, } from './core/runtime/aws-lambda-adapter.js';
10
10
  export type { WorkersEnv, WorkersContext } from './core/runtime/cloudflare-workers-adapter.js';
11
- export { MoroHttpServer, UWebSocketsHttpServer } from './core/http/index.js';
11
+ export { MoroHttpServer, UWebSocketsHttpServer, MoroEngineServer } from './core/http/index.js';
12
12
  export { builtInMiddleware, simpleMiddleware } from './core/middleware/built-in/index.js';
13
13
  export { WebSocketManager, ServiceRegistry } from './core/networking/index.js';
14
14
  export type { ServiceInfo, ServiceDiscoveryOptions } from './core/networking/service-discovery.js';
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ export { createAuthMiddleware, MoroJSAuth } from './core/auth/morojs-adapter.js'
6
6
  export { auth, providers, twoFactor, organization, anonymous, accountLinking, rateLimit, bearerToken, } from './core/middleware/built-in/auth/index.js';
7
7
  export { NodeRuntimeAdapter, VercelEdgeAdapter, AWSLambdaAdapter, CloudflareWorkersAdapter, createRuntimeAdapter, createNodeHandler, createEdgeHandler, createLambdaHandler, createWorkerHandler, } from './core/runtime/index.js';
8
8
  // Core exports
9
- export { MoroHttpServer, UWebSocketsHttpServer } from './core/http/index.js';
9
+ export { MoroHttpServer, UWebSocketsHttpServer, MoroEngineServer } from './core/http/index.js';
10
10
  export { builtInMiddleware, simpleMiddleware } from './core/middleware/built-in/index.js';
11
11
  // Networking System
12
12
  export { WebSocketManager, ServiceRegistry } from './core/networking/index.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,EACL,IAAI,EACJ,IAAI,IAAI,QAAQ,EAChB,SAAS,EACT,aAAa,EACb,aAAa,EACb,eAAe,EACf,eAAe,EACf,MAAM,EACN,UAAU,GACX,MAAM,WAAW,CAAC;AAwBnB,qCAAqC;AACrC,OAAO,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEjF,uCAAuC;AACvC,OAAO,EACL,IAAI,EACJ,SAAS,EACT,SAAS,EACT,YAAY,EACZ,SAAS,EACT,cAAc,EACd,SAAS,EACT,WAAW,GACZ,MAAM,0CAA0C,CAAC;AAkBlD,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,wBAAwB,EACxB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,yBAAyB,CAAC;AAUjC,eAAe;AACf,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC/F,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAE1F,oBAAoB;AACpB,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAG/E,iCAAiC;AACjC,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,SAAS,EACT,WAAW,EACX,cAAc,EACd,WAAW,EACX,WAAW,EACX,UAAU,EACV,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB;AACjB,wDAAwD;AACxD,QAAQ,EACR,eAAe,GAChB,MAAM,2BAA2B,CAAC;AAUnC,eAAe;AACf,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAYtD,gBAAgB;AAChB,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEvE,8BAA8B;AAC9B,OAAO,EACL,QAAQ,EACR,IAAI,EACJ,KAAK,EACL,MAAM,EACN,cAAc,EACd,CAAC,EACD,qBAAqB,EACrB,eAAe,GAChB,MAAM,4BAA4B,CAAC;AAmBpC,OAAO,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;AACjF,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,IAAI,eAAe,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAEhG,gBAAgB;AAChB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,6BAA6B,GAC9B,MAAM,yBAAyB,CAAC;AAcjC,8BAA8B;AAC9B,OAAO,EACL,eAAe,EACf,SAAS,EACT,kBAAkB,GACnB,MAAM,qCAAqC,CAAC;AAE7C,6BAA6B;AAC7B,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,yBAAyB,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAa7F,uBAAuB;AACvB,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,yBAAyB,EACzB,iCAAiC,GAClC,MAAM,sBAAsB,CAAC;AAG9B,0BAA0B;AAC1B,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,SAAS,EACT,WAAW,EACX,UAAU,EACV,aAAa,EACb,YAAY,EACZ,SAAS,EACT,cAAc,EACd,MAAM,EACN,cAAc,GACf,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,WAAW,GACZ,MAAM,wBAAwB,CAAC;AA6BhC,OAAO,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AAEjF,wEAAwE;AACxE,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,sBAAsB,EACtB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,+CAA+C,CAAC;AAEvD,aAAa;AACb,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,cAAc,EACd,aAAa,EACb,YAAY,EACZ,SAAS,EACT,SAAS,GACV,MAAM,sBAAsB,CAAC;AAmB9B,oBAAoB;AACpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAG/D,eAAe;AACf,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,kDAAkD,CAAC;AAEpF,gFAAgF;AAChF,mEAAmE;AACnE,0EAA0E;AAC1E,OAAO,EAAE,YAAY,EAAE,YAAY,IAAI,MAAM,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAanG,WAAW;AACX,cAAc,oDAAoD,CAAC;AACnE,cAAc,kDAAkD,CAAC;AACjE,cAAc,mCAAmC,CAAC;AAqClD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAE9D,kBAAkB;AAClB,OAAO,EACL,QAAQ,EACR,qBAAqB,EACrB,eAAe,EACf,wBAAwB,EACxB,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAoB9B,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,UAAU,EACV,aAAa,GACd,MAAM,+BAA+B,CAAC"}
package/dist/moro.d.ts CHANGED
@@ -214,6 +214,8 @@ export declare class Moro extends EventEmitter {
214
214
  private pathToRegex;
215
215
  get events(): MoroEventBus;
216
216
  get core(): MoroCore;
217
+ get engine(): ReturnType<MoroCore['getServerKind']>;
218
+ getServerKind(): ReturnType<MoroCore['getServerKind']>;
217
219
  getContainer(): import("./index.js").Container;
218
220
  forceCleanup(): void;
219
221
  private addRoute;
package/dist/moro.js CHANGED
@@ -767,8 +767,11 @@ export class Moro extends EventEmitter {
767
767
  const startServer = () => {
768
768
  const actualCallback = () => {
769
769
  const displayHost = host || 'localhost';
770
+ const serverKind = this.engine;
770
771
  this.logger.info('Moro Server Started', 'Server');
771
772
  this.logger.info(`Runtime: ${this.runtimeType}`, 'Server');
773
+ this.logger.info(`HTTP engine: ${serverKind.server}` +
774
+ (serverKind.enginePackage ? ` (${serverKind.enginePackage})` : ''), 'Server');
772
775
  this.logger.info(`HTTP API: http://${displayHost}:${port}`, 'Server');
773
776
  if (this.config.websocket.enabled) {
774
777
  this.logger.info(`WebSocket: ws://${displayHost}:${port}`, 'Server');
@@ -781,7 +784,11 @@ export class Moro extends EventEmitter {
781
784
  // Log performance stats
782
785
  this.unifiedRouter.logPerformanceStats();
783
786
  }
784
- this.eventBus.emit('server:started', { port, runtime: this.runtimeType });
787
+ this.eventBus.emit('server:started', {
788
+ port,
789
+ runtime: this.runtimeType,
790
+ engine: serverKind,
791
+ });
785
792
  // Start job scheduler after server starts
786
793
  this.startJobScheduler().catch(err => {
787
794
  this.logger.error(`Failed to start job scheduler: ${String(err)}`);
@@ -813,20 +820,30 @@ export class Moro extends EventEmitter {
813
820
  this.ensureAutoDiscoveryComplete().then(() => this.ensureRoutesLoaded()),
814
821
  this.processQueuedWebSocketRegistrations(),
815
822
  ])
816
- .then(() => {
817
- startServer();
818
- })
819
- .catch(error => {
823
+ .then(() => startServer(), initError => {
824
+ // Initialization (auto-discovery / WebSocket setup) failed — this is
825
+ // NOT the listen() call. Handle it here so a subsequent listen()
826
+ // failure can't be misdiagnosed as an init failure and retried.
820
827
  this.logger.error('Initialization failed during server start', 'Framework', {
821
- error: error instanceof Error ? error.message : String(error),
828
+ error: initError instanceof Error ? initError.message : String(initError),
822
829
  });
823
- // For auto-discovery failures, start server anyway
824
- // For WebSocket failures with queued registrations, error will propagate
825
- if (error instanceof Error &&
826
- error.message.includes('WebSocket features require a WebSocket adapter')) {
827
- throw error;
830
+ // WebSocket-adapter misconfiguration is fatal; propagate it.
831
+ if (initError instanceof Error &&
832
+ initError.message.includes('WebSocket features require a WebSocket adapter')) {
833
+ throw initError;
828
834
  }
835
+ // A non-fatal init issue (e.g. auto-discovery) — start the server anyway.
829
836
  startServer();
837
+ })
838
+ .catch(error => {
839
+ // startServer()/listen() failed — e.g. EADDRINUSE thrown synchronously
840
+ // by the native engine. Retrying would fail identically, so surface it
841
+ // via the 'error' event (Node's server convention) instead of retrying
842
+ // into an unhandled rejection. With no 'error' listener, EventEmitter
843
+ // rethrows — the desired visible crash for a fatal bind failure.
844
+ const message = error instanceof Error ? error.message : String(error);
845
+ this.logger.error(`Failed to start server on port ${port}: ${message}`, 'Framework');
846
+ this.emit('error', error);
830
847
  });
831
848
  }
832
849
  // Public method to manually initialize auto-discovery
@@ -1113,6 +1130,15 @@ export class Moro extends EventEmitter {
1113
1130
  get core() {
1114
1131
  return this.coreFramework;
1115
1132
  }
1133
+ // Which HTTP server actually booted (engine/node/http2), the package
1134
+ // backing a native engine, and the fallback reason when one was requested
1135
+ // but the Node server booted instead. Stable surface for logs/tests/benchmarks.
1136
+ get engine() {
1137
+ return this.coreFramework.getServerKind();
1138
+ }
1139
+ getServerKind() {
1140
+ return this.coreFramework.getServerKind();
1141
+ }
1116
1142
  // Public API for accessing the DI container
1117
1143
  getContainer() {
1118
1144
  return this.coreFramework.getContainer();
@@ -1278,7 +1304,7 @@ export class Moro extends EventEmitter {
1278
1304
  }
1279
1305
  // Rate limiting middleware
1280
1306
  if (route.rateLimit) {
1281
- const clientId = req.ip || req.connection.remoteAddress || 'unknown';
1307
+ const clientId = req.ip || req.connection?.remoteAddress || 'unknown';
1282
1308
  const key = `${route.method}:${route.path}:${clientId}`;
1283
1309
  if (!this.checkRateLimit(key, route.rateLimit)) {
1284
1310
  res.status(429).json({
@@ -1720,33 +1746,49 @@ export class Moro extends EventEmitter {
1720
1746
  port,
1721
1747
  runtime: this.runtimeType,
1722
1748
  worker: process.pid,
1749
+ engine: this.engine,
1723
1750
  });
1724
1751
  };
1725
1752
  // Ensure WebSocket setup is complete before starting worker
1726
- this.processQueuedWebSocketRegistrations()
1727
- .then(() => {
1753
+ const startWorkerListening = () => {
1728
1754
  if (host) {
1729
1755
  this.coreFramework.listen(port, host, workerCallback);
1730
1756
  }
1731
1757
  else {
1732
1758
  this.coreFramework.listen(port, workerCallback);
1733
1759
  }
1734
- })
1760
+ };
1761
+ this.processQueuedWebSocketRegistrations()
1762
+ .then(startWorkerListening)
1735
1763
  .catch(error => {
1764
+ const message = error instanceof Error ? error.message : String(error);
1765
+ const code = error?.code;
1766
+ // listen() itself failed (EADDRINUSE etc.): retrying is guaranteed to
1767
+ // fail again and would surface as an unhandled rejection crash-loop.
1768
+ // Log fatally and exit so the cluster primary sees a clean death.
1769
+ // Prefer the code the native/Node servers set; fall back to message.
1770
+ if (code === 'EADDRINUSE' ||
1771
+ code === 'EACCES' ||
1772
+ /EADDRINUSE|failed to bind/i.test(message)) {
1773
+ this.logger.error(`Worker ${process.pid} could not bind port ${port}: ${message}`, 'Worker');
1774
+ process.exit(1);
1775
+ }
1736
1776
  this.logger.error('WebSocket initialization failed in worker', 'Worker', {
1737
- error: error instanceof Error ? error.message : String(error),
1777
+ error: message,
1738
1778
  });
1739
1779
  // For WebSocket failures with queued registrations, error will propagate
1740
1780
  if (error instanceof Error &&
1741
1781
  error.message.includes('WebSocket features require a WebSocket adapter')) {
1742
1782
  throw error;
1743
1783
  }
1744
- // Start anyway for other errors
1745
- if (host) {
1746
- this.coreFramework.listen(port, host, workerCallback);
1784
+ // WebSocket setup failed but the HTTP server can still serve: start
1785
+ // anyway, and surface (not swallow) a listen failure from this path.
1786
+ try {
1787
+ startWorkerListening();
1747
1788
  }
1748
- else {
1749
- this.coreFramework.listen(port, workerCallback);
1789
+ catch (listenError) {
1790
+ this.logger.error(`Worker ${process.pid} failed to start: ${listenError instanceof Error ? listenError.message : String(listenError)}`, 'Worker');
1791
+ process.exit(1);
1750
1792
  }
1751
1793
  });
1752
1794
  }