@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.
- package/README.md +89 -37
- package/dist/core/config/config-sources.js +114 -2
- package/dist/core/config/config-sources.js.map +1 -1
- package/dist/core/config/config-validator.js +187 -5
- package/dist/core/config/config-validator.js.map +1 -1
- package/dist/core/config/schema.js +31 -3
- package/dist/core/config/schema.js.map +1 -1
- package/dist/core/framework.d.ts +41 -2
- package/dist/core/framework.js +338 -73
- package/dist/core/framework.js.map +1 -1
- package/dist/core/http/http-server.d.ts +21 -22
- package/dist/core/http/http-server.js +268 -226
- package/dist/core/http/http-server.js.map +1 -1
- package/dist/core/http/http2-server.d.ts +6 -16
- package/dist/core/http/http2-server.js +14 -79
- package/dist/core/http/http2-server.js.map +1 -1
- package/dist/core/http/index.d.ts +1 -0
- package/dist/core/http/index.js +3 -0
- package/dist/core/http/index.js.map +1 -1
- package/dist/core/http/moro-engine-server.d.ts +263 -0
- package/dist/core/http/moro-engine-server.js +1939 -0
- package/dist/core/http/moro-engine-server.js.map +1 -0
- package/dist/core/http/utils/compression.d.ts +47 -0
- package/dist/core/http/utils/compression.js +132 -0
- package/dist/core/http/utils/compression.js.map +1 -0
- package/dist/core/http/utils/lazy-event-emitter.d.ts +11 -0
- package/dist/core/http/utils/lazy-event-emitter.js +69 -0
- package/dist/core/http/utils/lazy-event-emitter.js.map +1 -0
- package/dist/core/http/utils/multipart-parser.d.ts +32 -0
- package/dist/core/http/utils/multipart-parser.js +211 -0
- package/dist/core/http/utils/multipart-parser.js.map +1 -0
- package/dist/core/http/utils/query-parser.d.ts +1 -0
- package/dist/core/http/utils/query-parser.js +44 -0
- package/dist/core/http/utils/query-parser.js.map +1 -0
- package/dist/core/http/utils/size.d.ts +33 -0
- package/dist/core/http/utils/size.js +37 -0
- package/dist/core/http/utils/size.js.map +1 -0
- package/dist/core/http/utils/ssl-config.d.ts +69 -0
- package/dist/core/http/utils/ssl-config.js +116 -0
- package/dist/core/http/utils/ssl-config.js.map +1 -0
- package/dist/core/http/utils/uws-worker-clustering.js +8 -2
- package/dist/core/http/utils/uws-worker-clustering.js.map +1 -1
- package/dist/core/http/uws-http-server.d.ts +24 -3
- package/dist/core/http/uws-http-server.js +386 -65
- package/dist/core/http/uws-http-server.js.map +1 -1
- package/dist/core/middleware/built-in/compression/core.d.ts +3 -0
- package/dist/core/middleware/built-in/compression/core.js +28 -34
- package/dist/core/middleware/built-in/compression/core.js.map +1 -1
- package/dist/core/networking/adapters/engine-adapter.d.ts +23 -0
- package/dist/core/networking/adapters/engine-adapter.js +365 -0
- package/dist/core/networking/adapters/engine-adapter.js.map +1 -0
- package/dist/core/networking/adapters/index.d.ts +1 -0
- package/dist/core/networking/adapters/index.js +1 -0
- package/dist/core/networking/adapters/index.js.map +1 -1
- package/dist/core/networking/adapters/uws-adapter.js +26 -15
- package/dist/core/networking/adapters/uws-adapter.js.map +1 -1
- package/dist/core/utilities/package-utils.d.ts +68 -0
- package/dist/core/utilities/package-utils.js +198 -1
- package/dist/core/utilities/package-utils.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/moro.d.ts +2 -0
- package/dist/moro.js +63 -21
- package/dist/moro.js.map +1 -1
- package/dist/types/config.d.ts +90 -5
- 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;
|
|
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":"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,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
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', {
|
|
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
|
-
|
|
818
|
-
|
|
819
|
-
|
|
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:
|
|
828
|
+
error: initError instanceof Error ? initError.message : String(initError),
|
|
822
829
|
});
|
|
823
|
-
//
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
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
|
|
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
|
-
|
|
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:
|
|
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
|
-
//
|
|
1745
|
-
|
|
1746
|
-
|
|
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
|
-
|
|
1749
|
-
this.
|
|
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
|
}
|