@morojs/moro 1.8.8 → 1.8.9
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/dist/core/http/moro-engine-server.d.ts +1 -0
- package/dist/core/http/moro-engine-server.js +104 -35
- package/dist/core/http/moro-engine-server.js.map +1 -1
- package/dist/core/http/uws-http-server.d.ts +1 -0
- package/dist/core/http/uws-http-server.js +102 -20
- package/dist/core/http/uws-http-server.js.map +1 -1
- package/dist/core/routing/unified-router.js +60 -29
- package/dist/core/routing/unified-router.js.map +1 -1
- package/package.json +1 -1
|
@@ -127,6 +127,7 @@ export declare class UWebSocketsHttpServer {
|
|
|
127
127
|
private createMoroResponse;
|
|
128
128
|
private readBody;
|
|
129
129
|
private executeMiddleware;
|
|
130
|
+
private dispatchMiddleware;
|
|
130
131
|
use(middleware: Middleware): void;
|
|
131
132
|
setRequestTracking(enabled: boolean): void;
|
|
132
133
|
setHookManager(hookManager: any): void;
|
|
@@ -673,10 +673,14 @@ export class UWebSocketsHttpServer {
|
|
|
673
673
|
// rejection). Registration of the response hooks above still stands.
|
|
674
674
|
if (httpRes.headersSent)
|
|
675
675
|
return;
|
|
676
|
-
// Execute global middleware chain
|
|
676
|
+
// Execute global middleware chain. executeMiddleware returns undefined
|
|
677
|
+
// when the whole chain completed synchronously, so a sync chain costs
|
|
678
|
+
// zero promise allocations.
|
|
677
679
|
if (this.globalMiddleware.length > 0) {
|
|
678
680
|
httpReq.materialize();
|
|
679
|
-
|
|
681
|
+
const mwResult = this.executeMiddleware(this.globalMiddleware, httpReq, httpRes);
|
|
682
|
+
if (mwResult)
|
|
683
|
+
await mwResult;
|
|
680
684
|
if (httpRes.headersSent)
|
|
681
685
|
return;
|
|
682
686
|
}
|
|
@@ -1586,27 +1590,105 @@ export class UWebSocketsHttpServer {
|
|
|
1586
1590
|
}
|
|
1587
1591
|
});
|
|
1588
1592
|
}
|
|
1589
|
-
|
|
1590
|
-
|
|
1593
|
+
// Middleware execution with Express-compatible error propagation - identical
|
|
1594
|
+
// semantics to MoroHttpServer/MoroEngineServer so a route behaves the same on
|
|
1595
|
+
// every backend. Supports 3-arg (req, res, next), 4-arg error middleware
|
|
1596
|
+
// (err, req, res, next), and next(err) to skip forward to the next error
|
|
1597
|
+
// middleware. Previously this adapter called EVERY middleware with three
|
|
1598
|
+
// arguments, so registering a 4-arg error handler passed `req` as `err` and
|
|
1599
|
+
// broke every ordinary request; with no 4-arg middleware registered the
|
|
1600
|
+
// behaviour here is unchanged (next(err) aborts the chain and propagates to
|
|
1601
|
+
// the request handler's catch).
|
|
1602
|
+
//
|
|
1603
|
+
// Sync-aware dispatch: middleware that calls next() synchronously (or throws
|
|
1604
|
+
// synchronously) advances the chain in a plain loop with ZERO promise
|
|
1605
|
+
// allocations; a promise is only created when a middleware actually completes
|
|
1606
|
+
// asynchronously. Returns undefined when the whole chain ran synchronously so
|
|
1607
|
+
// the caller can skip its await.
|
|
1608
|
+
executeMiddleware(middleware, req, res) {
|
|
1609
|
+
return this.dispatchMiddleware(middleware, req, res, 0, undefined);
|
|
1610
|
+
}
|
|
1611
|
+
dispatchMiddleware(middleware, req, res, startIndex, initialError) {
|
|
1612
|
+
const len = middleware.length;
|
|
1613
|
+
let activeError = initialError;
|
|
1614
|
+
let i = startIndex;
|
|
1615
|
+
while (i < len) {
|
|
1591
1616
|
if (res.headersSent)
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1617
|
+
return;
|
|
1618
|
+
const mw = middleware[i];
|
|
1619
|
+
i++;
|
|
1620
|
+
const isErrorHandler = mw.length >= 4;
|
|
1621
|
+
// Non-error middleware is skipped while an error is active; error middleware
|
|
1622
|
+
// is skipped while no error is active. Matches Express semantics.
|
|
1623
|
+
if (activeError !== undefined && !isErrorHandler)
|
|
1624
|
+
continue;
|
|
1625
|
+
if (activeError === undefined && isErrorHandler)
|
|
1626
|
+
continue;
|
|
1627
|
+
let settled = false;
|
|
1628
|
+
let settledError = undefined;
|
|
1629
|
+
let asyncResolve;
|
|
1630
|
+
const next = (err) => {
|
|
1631
|
+
if (settled)
|
|
1632
|
+
return;
|
|
1633
|
+
settled = true;
|
|
1634
|
+
settledError = err;
|
|
1635
|
+
if (asyncResolve)
|
|
1636
|
+
asyncResolve(err);
|
|
1637
|
+
};
|
|
1638
|
+
let result;
|
|
1639
|
+
try {
|
|
1640
|
+
result = isErrorHandler ? mw(activeError, req, res, next) : mw(req, res, next);
|
|
1641
|
+
}
|
|
1642
|
+
catch (err) {
|
|
1643
|
+
if (!settled) {
|
|
1644
|
+
settled = true;
|
|
1645
|
+
settledError = err;
|
|
1605
1646
|
}
|
|
1606
|
-
|
|
1607
|
-
|
|
1647
|
+
}
|
|
1648
|
+
const isThenable = result && typeof result.then === 'function';
|
|
1649
|
+
if (settled) {
|
|
1650
|
+
// Completed synchronously (next() called sync, or threw sync). A still
|
|
1651
|
+
// pending returned promise no longer gates the chain once next() has
|
|
1652
|
+
// been called; swallow late rejections so they never go unhandled.
|
|
1653
|
+
if (isThenable) {
|
|
1654
|
+
result.then(undefined, () => { });
|
|
1608
1655
|
}
|
|
1609
|
-
|
|
1656
|
+
activeError = settledError;
|
|
1657
|
+
continue;
|
|
1658
|
+
}
|
|
1659
|
+
if (!isThenable && res.headersSent) {
|
|
1660
|
+
// Terminal middleware (Express style): it answered the request and
|
|
1661
|
+
// deliberately never calls next(). The chain is finished - skip
|
|
1662
|
+
// allocating a promise that nothing would ever settle.
|
|
1663
|
+
return;
|
|
1664
|
+
}
|
|
1665
|
+
if (!isThenable) {
|
|
1666
|
+
// Sync-looking middleware that neither called next() nor returned a
|
|
1667
|
+
// promise: it will call next() later (e.g. from an event callback).
|
|
1668
|
+
// Fall back to a promise for the remainder of the chain.
|
|
1669
|
+
const resumeIndex = i;
|
|
1670
|
+
return new Promise(resolve => {
|
|
1671
|
+
asyncResolve = resolve;
|
|
1672
|
+
}).then(err => this.dispatchMiddleware(middleware, req, res, resumeIndex, err));
|
|
1673
|
+
}
|
|
1674
|
+
// Async middleware: completion is next() OR promise settle, whichever
|
|
1675
|
+
// happens first (same semantics as the previous implementation).
|
|
1676
|
+
const resumeIndex = i;
|
|
1677
|
+
return new Promise(resolve => {
|
|
1678
|
+
asyncResolve = resolve;
|
|
1679
|
+
result.then(() => {
|
|
1680
|
+
if (!settled)
|
|
1681
|
+
next();
|
|
1682
|
+
}, (err) => {
|
|
1683
|
+
if (!settled)
|
|
1684
|
+
next(err);
|
|
1685
|
+
});
|
|
1686
|
+
}).then(err => this.dispatchMiddleware(middleware, req, res, resumeIndex, err));
|
|
1687
|
+
}
|
|
1688
|
+
// If an error is still unhandled after the chain, re-throw so the request
|
|
1689
|
+
// handler's catch can invoke the registered errorHandler / default 500.
|
|
1690
|
+
if (activeError !== undefined) {
|
|
1691
|
+
throw activeError;
|
|
1610
1692
|
}
|
|
1611
1693
|
}
|
|
1612
1694
|
// Public API - matches MoroHttpServer interface
|