@expressots/adapter-express 3.0.0 → 4.0.0-preview.1
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 +39 -96
- package/lib/CHANGELOG.md +31 -5
- package/lib/README.md +39 -96
- package/lib/cjs/adapter-express/application-express.base.js +3 -1
- package/lib/cjs/adapter-express/application-express.js +1049 -85
- package/lib/cjs/adapter-express/express-utils/conditional-middleware.js +102 -0
- package/lib/cjs/adapter-express/express-utils/constants.js +17 -0
- package/lib/cjs/adapter-express/express-utils/content-negotiation-decorators.js +129 -0
- package/lib/cjs/adapter-express/express-utils/decorators.js +186 -49
- package/lib/cjs/adapter-express/express-utils/exception-filter-decorators.js +11 -0
- package/lib/cjs/adapter-express/express-utils/guard-context-factory.js +84 -0
- package/lib/cjs/adapter-express/express-utils/guard-middleware.js +115 -0
- package/lib/cjs/adapter-express/express-utils/guard-utils.js +18 -0
- package/lib/cjs/adapter-express/express-utils/http-context-store.js +15 -0
- package/lib/cjs/adapter-express/express-utils/http-status-middleware.js +37 -2
- package/lib/cjs/adapter-express/express-utils/index.js +67 -1
- package/lib/cjs/adapter-express/express-utils/interceptor-middleware.js +132 -0
- package/lib/cjs/adapter-express/express-utils/inversify-express-server.js +810 -63
- package/lib/cjs/adapter-express/express-utils/lazy-module-middleware.js +241 -0
- package/lib/cjs/adapter-express/express-utils/middleware-composition.js +95 -0
- package/lib/cjs/adapter-express/express-utils/permission-preloader.middleware.js +48 -0
- package/lib/cjs/adapter-express/express-utils/route-constraints.js +95 -0
- package/lib/cjs/adapter-express/express-utils/scope-extractor.interface.js +2 -0
- package/lib/cjs/adapter-express/express-utils/scope-extractor.js +66 -0
- package/lib/cjs/adapter-express/express-utils/setup-authorization.js +71 -0
- package/lib/cjs/adapter-express/express-utils/setup-event-system.js +113 -0
- package/lib/cjs/adapter-express/express-utils/setup-interceptors.js +103 -0
- package/lib/cjs/adapter-express/express-utils/setup-lazy-loading.js +228 -0
- package/lib/cjs/adapter-express/express-utils/utils.js +30 -12
- package/lib/cjs/adapter-express/express-utils/validation-decorators.js +205 -0
- package/lib/cjs/adapter-express/express-utils/validation-service.js +252 -0
- package/lib/cjs/adapter-express/index.js +7 -5
- package/lib/cjs/adapter-express/micro-api/application-express-micro-route.js +31 -1
- package/lib/cjs/adapter-express/micro-api/application-express-micro.js +11 -37
- package/lib/cjs/adapter-express/micro-api/gateway/circuit-breaker.js +174 -0
- package/lib/cjs/adapter-express/micro-api/gateway/index.js +11 -0
- package/lib/cjs/adapter-express/micro-api/gateway/service-proxy.js +214 -0
- package/lib/cjs/adapter-express/micro-api/index.js +27 -3
- package/lib/cjs/adapter-express/micro-api/micro.js +217 -0
- package/lib/cjs/adapter-express/micro-api/queue/index.js +8 -0
- package/lib/cjs/adapter-express/micro-api/queue/queue.interface.js +2 -0
- package/lib/cjs/adapter-express/micro-api/queue/rabbitmq-consumer.js +255 -0
- package/lib/cjs/adapter-express/micro-api/serverless/aws-lambda.adapter.js +183 -0
- package/lib/cjs/adapter-express/micro-api/serverless/cloudflare.adapter.js +158 -0
- package/lib/cjs/adapter-express/micro-api/serverless/index.js +12 -0
- package/lib/cjs/adapter-express/micro-api/serverless/vercel.adapter.js +102 -0
- package/lib/cjs/adapter-express/micro-api/service-mesh/index.js +10 -0
- package/lib/cjs/adapter-express/micro-api/service-mesh/service-client.js +194 -0
- package/lib/cjs/adapter-express/micro-api/service-mesh/service-discovery.js +261 -0
- package/lib/cjs/adapter-express/middleware/index.js +21 -0
- package/lib/cjs/adapter-express/middleware/request-logging.middleware.js +244 -0
- package/lib/cjs/adapter-express/render/engine.js +15 -15
- package/lib/cjs/adapter-express/render/index.js +5 -0
- package/lib/cjs/adapter-express/studio/index.js +9 -0
- package/lib/cjs/adapter-express/studio/studio-integration.js +214 -0
- package/lib/cjs/index.js +1 -1
- package/lib/cjs/types/adapter-express/application-express.base.d.ts +20 -7
- package/lib/cjs/types/adapter-express/application-express.d.ts +273 -32
- package/lib/cjs/types/adapter-express/express-utils/base-middleware.d.ts +2 -2
- package/lib/cjs/types/adapter-express/express-utils/conditional-middleware.d.ts +97 -0
- package/lib/cjs/types/adapter-express/express-utils/constants.d.ts +13 -0
- package/lib/cjs/types/adapter-express/express-utils/content-negotiation-decorators.d.ts +94 -0
- package/lib/cjs/types/adapter-express/express-utils/decorators.d.ts +54 -6
- package/lib/cjs/types/adapter-express/express-utils/exception-filter-decorators.d.ts +6 -0
- package/lib/cjs/types/adapter-express/express-utils/guard-context-factory.d.ts +17 -0
- package/lib/cjs/types/adapter-express/express-utils/guard-middleware.d.ts +22 -0
- package/lib/cjs/types/adapter-express/express-utils/guard-utils.d.ts +11 -0
- package/lib/cjs/types/adapter-express/express-utils/http-context-store.d.ts +20 -0
- package/lib/cjs/types/adapter-express/express-utils/httpResponseMessage.d.ts +1 -1
- package/lib/cjs/types/adapter-express/express-utils/index.d.ts +30 -2
- package/lib/cjs/types/adapter-express/express-utils/interceptor-middleware.d.ts +40 -0
- package/lib/cjs/types/adapter-express/express-utils/interfaces.d.ts +42 -5
- package/lib/cjs/types/adapter-express/express-utils/inversify-express-server.d.ts +114 -2
- package/lib/cjs/types/adapter-express/express-utils/lazy-module-middleware.d.ts +122 -0
- package/lib/cjs/types/adapter-express/express-utils/middleware-composition.d.ts +85 -0
- package/lib/cjs/types/adapter-express/express-utils/permission-preloader.middleware.d.ts +10 -0
- package/lib/cjs/types/adapter-express/express-utils/route-constraints.d.ts +89 -0
- package/lib/cjs/types/adapter-express/express-utils/scope-extractor.d.ts +21 -0
- package/lib/cjs/types/adapter-express/express-utils/scope-extractor.interface.d.ts +12 -0
- package/lib/cjs/types/adapter-express/express-utils/setup-authorization.d.ts +34 -0
- package/lib/cjs/types/adapter-express/express-utils/setup-event-system.d.ts +118 -0
- package/lib/cjs/types/adapter-express/express-utils/setup-interceptors.d.ts +115 -0
- package/lib/cjs/types/adapter-express/express-utils/setup-lazy-loading.d.ts +123 -0
- package/lib/cjs/types/adapter-express/express-utils/utils.d.ts +17 -2
- package/lib/cjs/types/adapter-express/express-utils/validation-decorators.d.ts +145 -0
- package/lib/cjs/types/adapter-express/express-utils/validation-service.d.ts +88 -0
- package/lib/cjs/types/adapter-express/index.d.ts +6 -4
- package/lib/cjs/types/adapter-express/micro-api/application-express-micro-route.d.ts +25 -14
- package/lib/cjs/types/adapter-express/micro-api/application-express-micro.d.ts +3 -10
- package/lib/cjs/types/adapter-express/micro-api/gateway/circuit-breaker.d.ts +111 -0
- package/lib/cjs/types/adapter-express/micro-api/gateway/index.d.ts +5 -0
- package/lib/cjs/types/adapter-express/micro-api/gateway/service-proxy.d.ts +83 -0
- package/lib/cjs/types/adapter-express/micro-api/index.d.ts +7 -1
- package/lib/cjs/types/adapter-express/micro-api/micro.d.ts +66 -0
- package/lib/cjs/types/adapter-express/micro-api/queue/index.d.ts +5 -0
- package/lib/cjs/types/adapter-express/micro-api/queue/queue.interface.d.ts +60 -0
- package/lib/cjs/types/adapter-express/micro-api/queue/rabbitmq-consumer.d.ts +86 -0
- package/lib/cjs/types/adapter-express/micro-api/serverless/aws-lambda.adapter.d.ts +77 -0
- package/lib/cjs/types/adapter-express/micro-api/serverless/cloudflare.adapter.d.ts +64 -0
- package/lib/cjs/types/adapter-express/micro-api/serverless/index.d.ts +6 -0
- package/lib/cjs/types/adapter-express/micro-api/serverless/vercel.adapter.d.ts +56 -0
- package/lib/cjs/types/adapter-express/micro-api/service-mesh/index.d.ts +5 -0
- package/lib/cjs/types/adapter-express/micro-api/service-mesh/service-client.d.ts +122 -0
- package/lib/cjs/types/adapter-express/micro-api/service-mesh/service-discovery.d.ts +150 -0
- package/lib/cjs/types/adapter-express/middleware/index.d.ts +5 -0
- package/lib/cjs/types/adapter-express/middleware/request-logging.middleware.d.ts +65 -0
- package/lib/cjs/types/adapter-express/render/index.d.ts +1 -0
- package/lib/cjs/types/adapter-express/studio/index.d.ts +1 -0
- package/lib/cjs/types/adapter-express/studio/studio-integration.d.ts +92 -0
- package/lib/cjs/types/index.d.ts +1 -1
- package/lib/esm/adapter-express/application-express.base.js +24 -0
- package/lib/esm/adapter-express/application-express.js +1300 -0
- package/lib/esm/adapter-express/application-express.types.js +1 -0
- package/lib/esm/adapter-express/express-utils/base-middleware.js +19 -0
- package/lib/esm/adapter-express/express-utils/conditional-middleware.js +96 -0
- package/lib/esm/adapter-express/express-utils/constants.js +63 -0
- package/lib/esm/adapter-express/express-utils/content/httpContent.js +6 -0
- package/lib/esm/adapter-express/express-utils/content-negotiation-decorators.js +120 -0
- package/lib/esm/adapter-express/express-utils/decorators.js +575 -0
- package/lib/esm/adapter-express/express-utils/exception-filter-decorators.js +6 -0
- package/lib/esm/adapter-express/express-utils/guard-context-factory.js +83 -0
- package/lib/esm/adapter-express/express-utils/guard-middleware.js +115 -0
- package/lib/esm/adapter-express/express-utils/guard-utils.js +14 -0
- package/lib/esm/adapter-express/express-utils/http-context-store.js +10 -0
- package/lib/esm/adapter-express/express-utils/http-status-middleware.js +116 -0
- package/lib/esm/adapter-express/express-utils/httpResponseMessage.js +29 -0
- package/lib/esm/adapter-express/express-utils/index.js +24 -0
- package/lib/esm/adapter-express/express-utils/interceptor-middleware.js +130 -0
- package/lib/esm/adapter-express/express-utils/interfaces.js +1 -0
- package/lib/esm/adapter-express/express-utils/inversify-express-server.js +1031 -0
- package/lib/esm/adapter-express/express-utils/lazy-module-middleware.js +236 -0
- package/lib/esm/adapter-express/express-utils/middleware-composition.js +89 -0
- package/lib/esm/adapter-express/express-utils/permission-preloader.middleware.js +45 -0
- package/lib/esm/adapter-express/express-utils/resolver-multer.js +30 -0
- package/lib/esm/adapter-express/express-utils/route-constraints.js +91 -0
- package/lib/esm/adapter-express/express-utils/scope-extractor.interface.js +1 -0
- package/lib/esm/adapter-express/express-utils/scope-extractor.js +63 -0
- package/lib/esm/adapter-express/express-utils/setup-authorization.js +68 -0
- package/lib/esm/adapter-express/express-utils/setup-event-system.js +110 -0
- package/lib/esm/adapter-express/express-utils/setup-interceptors.js +100 -0
- package/lib/esm/adapter-express/express-utils/setup-lazy-loading.js +225 -0
- package/lib/esm/adapter-express/express-utils/utils.js +68 -0
- package/lib/esm/adapter-express/express-utils/validation-decorators.js +199 -0
- package/lib/esm/adapter-express/express-utils/validation-service.js +251 -0
- package/lib/esm/adapter-express/index.js +7 -0
- package/lib/esm/adapter-express/micro-api/application-express-micro-container.js +48 -0
- package/lib/esm/adapter-express/micro-api/application-express-micro-route.js +128 -0
- package/lib/esm/adapter-express/micro-api/application-express-micro.js +161 -0
- package/lib/esm/adapter-express/micro-api/gateway/circuit-breaker.js +174 -0
- package/lib/esm/adapter-express/micro-api/gateway/index.js +5 -0
- package/lib/esm/adapter-express/micro-api/gateway/service-proxy.js +210 -0
- package/lib/esm/adapter-express/micro-api/index.js +10 -0
- package/lib/esm/adapter-express/micro-api/micro.js +211 -0
- package/lib/esm/adapter-express/micro-api/queue/index.js +4 -0
- package/lib/esm/adapter-express/micro-api/queue/queue.interface.js +1 -0
- package/lib/esm/adapter-express/micro-api/queue/rabbitmq-consumer.js +229 -0
- package/lib/esm/adapter-express/micro-api/serverless/aws-lambda.adapter.js +180 -0
- package/lib/esm/adapter-express/micro-api/serverless/cloudflare.adapter.js +155 -0
- package/lib/esm/adapter-express/micro-api/serverless/index.js +6 -0
- package/lib/esm/adapter-express/micro-api/serverless/vercel.adapter.js +99 -0
- package/lib/esm/adapter-express/micro-api/service-mesh/index.js +5 -0
- package/lib/esm/adapter-express/micro-api/service-mesh/service-client.js +191 -0
- package/lib/esm/adapter-express/micro-api/service-mesh/service-discovery.js +259 -0
- package/lib/esm/adapter-express/middleware/index.js +5 -0
- package/lib/esm/adapter-express/middleware/request-logging.middleware.js +239 -0
- package/lib/esm/adapter-express/render/constants.js +37 -0
- package/lib/esm/adapter-express/render/engine.js +51 -0
- package/lib/esm/adapter-express/render/index.js +1 -0
- package/lib/esm/adapter-express/render/resolve-render.js +30 -0
- package/lib/esm/adapter-express/studio/index.js +1 -0
- package/lib/esm/adapter-express/studio/studio-integration.js +184 -0
- package/lib/esm/index.mjs +1 -0
- package/lib/esm/package.json +3 -0
- package/lib/esm/types/adapter-express/application-express.base.d.ts +77 -0
- package/lib/esm/types/adapter-express/application-express.d.ts +411 -0
- package/lib/esm/types/adapter-express/application-express.types.d.ts +23 -0
- package/lib/esm/types/adapter-express/express-utils/base-middleware.d.ts +8 -0
- package/lib/esm/types/adapter-express/express-utils/conditional-middleware.d.ts +97 -0
- package/lib/esm/types/adapter-express/express-utils/constants.d.ts +57 -0
- package/lib/esm/types/adapter-express/express-utils/content/httpContent.d.ts +6 -0
- package/lib/esm/types/adapter-express/express-utils/content-negotiation-decorators.d.ts +94 -0
- package/lib/esm/types/adapter-express/express-utils/decorators.d.ts +257 -0
- package/lib/esm/types/adapter-express/express-utils/exception-filter-decorators.d.ts +6 -0
- package/lib/esm/types/adapter-express/express-utils/guard-context-factory.d.ts +17 -0
- package/lib/esm/types/adapter-express/express-utils/guard-middleware.d.ts +22 -0
- package/lib/esm/types/adapter-express/express-utils/guard-utils.d.ts +11 -0
- package/lib/esm/types/adapter-express/express-utils/http-context-store.d.ts +20 -0
- package/lib/esm/types/adapter-express/express-utils/http-status-middleware.d.ts +26 -0
- package/lib/esm/types/adapter-express/express-utils/httpResponseMessage.d.ts +14 -0
- package/lib/esm/types/adapter-express/express-utils/index.d.ts +30 -0
- package/lib/esm/types/adapter-express/express-utils/interceptor-middleware.d.ts +40 -0
- package/lib/esm/types/adapter-express/express-utils/interfaces.d.ts +115 -0
- package/lib/esm/types/adapter-express/express-utils/inversify-express-server.d.ts +172 -0
- package/lib/esm/types/adapter-express/express-utils/lazy-module-middleware.d.ts +122 -0
- package/lib/esm/types/adapter-express/express-utils/middleware-composition.d.ts +85 -0
- package/lib/esm/types/adapter-express/express-utils/permission-preloader.middleware.d.ts +10 -0
- package/lib/esm/types/adapter-express/express-utils/resolver-multer.d.ts +7 -0
- package/lib/esm/types/adapter-express/express-utils/route-constraints.d.ts +89 -0
- package/lib/esm/types/adapter-express/express-utils/scope-extractor.d.ts +21 -0
- package/lib/esm/types/adapter-express/express-utils/scope-extractor.interface.d.ts +12 -0
- package/lib/esm/types/adapter-express/express-utils/setup-authorization.d.ts +34 -0
- package/lib/esm/types/adapter-express/express-utils/setup-event-system.d.ts +118 -0
- package/lib/esm/types/adapter-express/express-utils/setup-interceptors.d.ts +115 -0
- package/lib/esm/types/adapter-express/express-utils/setup-lazy-loading.d.ts +123 -0
- package/lib/esm/types/adapter-express/express-utils/utils.d.ts +24 -0
- package/lib/esm/types/adapter-express/express-utils/validation-decorators.d.ts +145 -0
- package/lib/esm/types/adapter-express/express-utils/validation-service.d.ts +88 -0
- package/lib/esm/types/adapter-express/index.d.ts +7 -0
- package/lib/esm/types/adapter-express/micro-api/application-express-micro-container.d.ts +47 -0
- package/lib/esm/types/adapter-express/micro-api/application-express-micro-route.d.ts +104 -0
- package/lib/esm/types/adapter-express/micro-api/application-express-micro.d.ts +72 -0
- package/lib/esm/types/adapter-express/micro-api/gateway/circuit-breaker.d.ts +111 -0
- package/lib/esm/types/adapter-express/micro-api/gateway/index.d.ts +5 -0
- package/lib/esm/types/adapter-express/micro-api/gateway/service-proxy.d.ts +83 -0
- package/lib/esm/types/adapter-express/micro-api/index.d.ts +7 -0
- package/lib/esm/types/adapter-express/micro-api/micro.d.ts +66 -0
- package/lib/esm/types/adapter-express/micro-api/queue/index.d.ts +5 -0
- package/lib/esm/types/adapter-express/micro-api/queue/queue.interface.d.ts +60 -0
- package/lib/esm/types/adapter-express/micro-api/queue/rabbitmq-consumer.d.ts +86 -0
- package/lib/esm/types/adapter-express/micro-api/serverless/aws-lambda.adapter.d.ts +77 -0
- package/lib/esm/types/adapter-express/micro-api/serverless/cloudflare.adapter.d.ts +64 -0
- package/lib/esm/types/adapter-express/micro-api/serverless/index.d.ts +6 -0
- package/lib/esm/types/adapter-express/micro-api/serverless/vercel.adapter.d.ts +56 -0
- package/lib/esm/types/adapter-express/micro-api/service-mesh/index.d.ts +5 -0
- package/lib/esm/types/adapter-express/micro-api/service-mesh/service-client.d.ts +122 -0
- package/lib/esm/types/adapter-express/micro-api/service-mesh/service-discovery.d.ts +150 -0
- package/lib/esm/types/adapter-express/middleware/index.d.ts +5 -0
- package/lib/esm/types/adapter-express/middleware/request-logging.middleware.d.ts +65 -0
- package/lib/esm/types/adapter-express/render/constants.d.ts +26 -0
- package/lib/esm/types/adapter-express/render/engine.d.ts +20 -0
- package/lib/esm/types/adapter-express/render/index.d.ts +5 -0
- package/lib/esm/types/adapter-express/render/resolve-render.d.ts +7 -0
- package/lib/esm/types/adapter-express/studio/index.d.ts +1 -0
- package/lib/esm/types/adapter-express/studio/studio-integration.d.ts +92 -0
- package/lib/esm/types/index.d.ts +1 -0
- package/lib/package.json +156 -146
- package/package.json +156 -146
- package/lib/cjs/di/di.interfaces.js +0 -10
- package/lib/cjs/types/di/di.interfaces.d.ts +0 -289
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CircuitBreaker = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* CircuitBreaker - Protect against cascading failures in distributed systems.
|
|
6
|
+
*
|
|
7
|
+
* States:
|
|
8
|
+
* - CLOSED: Normal operation, requests pass through
|
|
9
|
+
* - OPEN: Requests fail immediately without calling the service
|
|
10
|
+
* - HALF_OPEN: Limited requests pass through to test if service recovered
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const circuitBreaker = new CircuitBreaker({
|
|
15
|
+
* failureThreshold: 5,
|
|
16
|
+
* timeout: 60000,
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* app.Route.get("/external-api", async (req, res) => {
|
|
20
|
+
* try {
|
|
21
|
+
* const result = await circuitBreaker.execute(async () => {
|
|
22
|
+
* return await fetch("https://external-api.com/data");
|
|
23
|
+
* });
|
|
24
|
+
* res.json(await result.json());
|
|
25
|
+
* } catch (error) {
|
|
26
|
+
* if (error.message === "Circuit breaker is OPEN") {
|
|
27
|
+
* res.status(503).json({ error: "Service temporarily unavailable" });
|
|
28
|
+
* } else {
|
|
29
|
+
* res.status(500).json({ error: error.message });
|
|
30
|
+
* }
|
|
31
|
+
* }
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
class CircuitBreaker {
|
|
36
|
+
constructor(config) {
|
|
37
|
+
this.state = "CLOSED";
|
|
38
|
+
this.failures = 0;
|
|
39
|
+
this.successes = 0;
|
|
40
|
+
this.totalSuccesses = 0;
|
|
41
|
+
this.totalCalls = 0;
|
|
42
|
+
this.recentFailures = [];
|
|
43
|
+
this.config = {
|
|
44
|
+
failureThreshold: config?.failureThreshold ?? 5,
|
|
45
|
+
successThreshold: config?.successThreshold ?? 2,
|
|
46
|
+
timeout: config?.timeout ?? 60000,
|
|
47
|
+
monitoringPeriod: config?.monitoringPeriod ?? 10000,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Execute a function with circuit breaker protection
|
|
52
|
+
* @param fn - Function to execute
|
|
53
|
+
* @throws Error if circuit is open
|
|
54
|
+
*/
|
|
55
|
+
async execute(fn) {
|
|
56
|
+
this.totalCalls++;
|
|
57
|
+
// Check if circuit is open
|
|
58
|
+
if (this.state === "OPEN") {
|
|
59
|
+
// Check if timeout has passed
|
|
60
|
+
if (this.shouldAttemptReset()) {
|
|
61
|
+
this.state = "HALF_OPEN";
|
|
62
|
+
this.successes = 0;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
throw new Error("Circuit breaker is OPEN");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const result = await fn();
|
|
70
|
+
this.onSuccess();
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
this.onFailure();
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get current circuit state
|
|
80
|
+
*/
|
|
81
|
+
getState() {
|
|
82
|
+
return this.state;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Get circuit breaker statistics
|
|
86
|
+
*/
|
|
87
|
+
getStats() {
|
|
88
|
+
return {
|
|
89
|
+
state: this.state,
|
|
90
|
+
failures: this.failures,
|
|
91
|
+
successes: this.totalSuccesses,
|
|
92
|
+
totalCalls: this.totalCalls,
|
|
93
|
+
lastFailure: this.lastFailure,
|
|
94
|
+
lastSuccess: this.lastSuccess,
|
|
95
|
+
openedAt: this.openedAt,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Manually reset the circuit breaker
|
|
100
|
+
*/
|
|
101
|
+
reset() {
|
|
102
|
+
this.state = "CLOSED";
|
|
103
|
+
this.failures = 0;
|
|
104
|
+
this.successes = 0;
|
|
105
|
+
this.totalSuccesses = 0;
|
|
106
|
+
this.recentFailures = [];
|
|
107
|
+
this.openedAt = undefined;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Manually open the circuit
|
|
111
|
+
*/
|
|
112
|
+
open() {
|
|
113
|
+
this.state = "OPEN";
|
|
114
|
+
this.openedAt = new Date();
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Handle successful call
|
|
118
|
+
*/
|
|
119
|
+
onSuccess() {
|
|
120
|
+
this.totalSuccesses++;
|
|
121
|
+
this.lastSuccess = new Date();
|
|
122
|
+
if (this.state === "HALF_OPEN") {
|
|
123
|
+
this.successes++;
|
|
124
|
+
if (this.successes >= this.config.successThreshold) {
|
|
125
|
+
this.state = "CLOSED";
|
|
126
|
+
this.failures = 0;
|
|
127
|
+
this.recentFailures = [];
|
|
128
|
+
this.openedAt = undefined;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else if (this.state === "CLOSED") {
|
|
132
|
+
// Clear old failures outside monitoring period
|
|
133
|
+
this.cleanupRecentFailures();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Handle failed call
|
|
138
|
+
*/
|
|
139
|
+
onFailure() {
|
|
140
|
+
this.failures++;
|
|
141
|
+
this.lastFailure = new Date();
|
|
142
|
+
this.recentFailures.push(this.lastFailure);
|
|
143
|
+
if (this.state === "HALF_OPEN") {
|
|
144
|
+
// Any failure in half-open state reopens the circuit
|
|
145
|
+
this.state = "OPEN";
|
|
146
|
+
this.openedAt = new Date();
|
|
147
|
+
this.successes = 0;
|
|
148
|
+
}
|
|
149
|
+
else if (this.state === "CLOSED") {
|
|
150
|
+
this.cleanupRecentFailures();
|
|
151
|
+
// Check if we've hit the failure threshold
|
|
152
|
+
if (this.recentFailures.length >= this.config.failureThreshold) {
|
|
153
|
+
this.state = "OPEN";
|
|
154
|
+
this.openedAt = new Date();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Check if timeout has passed and we should try to reset
|
|
160
|
+
*/
|
|
161
|
+
shouldAttemptReset() {
|
|
162
|
+
if (!this.openedAt)
|
|
163
|
+
return true;
|
|
164
|
+
return Date.now() - this.openedAt.getTime() >= this.config.timeout;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Remove failures outside the monitoring period
|
|
168
|
+
*/
|
|
169
|
+
cleanupRecentFailures() {
|
|
170
|
+
const cutoff = Date.now() - this.config.monitoringPeriod;
|
|
171
|
+
this.recentFailures = this.recentFailures.filter((date) => date.getTime() > cutoff);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
exports.CircuitBreaker = CircuitBreaker;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* API Gateway Utilities for ExpressoTS Micro Template
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createProxy = exports.ServiceProxy = exports.CircuitBreaker = void 0;
|
|
7
|
+
var circuit_breaker_js_1 = require("./circuit-breaker.js");
|
|
8
|
+
Object.defineProperty(exports, "CircuitBreaker", { enumerable: true, get: function () { return circuit_breaker_js_1.CircuitBreaker; } });
|
|
9
|
+
var service_proxy_js_1 = require("./service-proxy.js");
|
|
10
|
+
Object.defineProperty(exports, "ServiceProxy", { enumerable: true, get: function () { return service_proxy_js_1.ServiceProxy; } });
|
|
11
|
+
Object.defineProperty(exports, "createProxy", { enumerable: true, get: function () { return service_proxy_js_1.createProxy; } });
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ServiceProxy = void 0;
|
|
4
|
+
exports.createProxy = createProxy;
|
|
5
|
+
const circuit_breaker_js_1 = require("./circuit-breaker.js");
|
|
6
|
+
/**
|
|
7
|
+
* ServiceProxy - Proxy requests to other microservices.
|
|
8
|
+
*
|
|
9
|
+
* Features:
|
|
10
|
+
* - Automatic request forwarding
|
|
11
|
+
* - Path rewriting
|
|
12
|
+
* - Custom headers
|
|
13
|
+
* - Request timeout
|
|
14
|
+
* - Retry support
|
|
15
|
+
* - Optional circuit breaker integration
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* // Proxy to user service
|
|
20
|
+
* const userProxy = createProxy({
|
|
21
|
+
* target: "http://user-service:3001",
|
|
22
|
+
* pathRewrite: (path) => path.replace("/api/users", ""),
|
|
23
|
+
* timeout: 5000,
|
|
24
|
+
* retries: 3,
|
|
25
|
+
* circuitBreaker: true,
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* app.Route.get("/api/users/*", userProxy.handler());
|
|
29
|
+
* app.Route.post("/api/users/*", userProxy.handler());
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
class ServiceProxy {
|
|
33
|
+
constructor(config) {
|
|
34
|
+
this.config = {
|
|
35
|
+
target: config.target,
|
|
36
|
+
timeout: config.timeout ?? 30000,
|
|
37
|
+
retries: config.retries ?? 0,
|
|
38
|
+
headers: config.headers ?? {},
|
|
39
|
+
pathRewrite: config.pathRewrite ?? ((path) => path),
|
|
40
|
+
debug: config.debug ?? false,
|
|
41
|
+
};
|
|
42
|
+
// Initialize circuit breaker if enabled
|
|
43
|
+
if (config.circuitBreaker) {
|
|
44
|
+
const cbConfig = typeof config.circuitBreaker === "object" ? config.circuitBreaker : undefined;
|
|
45
|
+
this.config.circuitBreaker = new circuit_breaker_js_1.CircuitBreaker(cbConfig);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Create an Express handler for proxying requests
|
|
50
|
+
*/
|
|
51
|
+
handler() {
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
53
|
+
return async (req, res, _next) => {
|
|
54
|
+
try {
|
|
55
|
+
const result = await this.proxyRequest(req);
|
|
56
|
+
// Copy status and headers
|
|
57
|
+
res.status(result.status);
|
|
58
|
+
result.headers.forEach((value, key) => {
|
|
59
|
+
// Skip certain headers
|
|
60
|
+
if (!["content-encoding", "transfer-encoding"].includes(key.toLowerCase())) {
|
|
61
|
+
res.setHeader(key, value);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
// Send body
|
|
65
|
+
const body = await result.text();
|
|
66
|
+
res.send(body);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
70
|
+
if (this.config.debug) {
|
|
71
|
+
console.error(`[Proxy] Error:`, errorMessage);
|
|
72
|
+
}
|
|
73
|
+
if (errorMessage === "Circuit breaker is OPEN") {
|
|
74
|
+
res.status(503).json({
|
|
75
|
+
error: "Service temporarily unavailable",
|
|
76
|
+
service: this.config.target,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
else if (error instanceof Error && error.name === "AbortError") {
|
|
80
|
+
res.status(504).json({
|
|
81
|
+
error: "Gateway timeout",
|
|
82
|
+
service: this.config.target,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
res.status(502).json({
|
|
87
|
+
error: "Bad gateway",
|
|
88
|
+
message: errorMessage,
|
|
89
|
+
service: this.config.target,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Proxy a request to the target service
|
|
97
|
+
*/
|
|
98
|
+
async proxyRequest(req) {
|
|
99
|
+
const execute = async () => {
|
|
100
|
+
return await this.executeWithRetry(req);
|
|
101
|
+
};
|
|
102
|
+
if (this.config.circuitBreaker) {
|
|
103
|
+
return await this.config.circuitBreaker.execute(execute);
|
|
104
|
+
}
|
|
105
|
+
return await execute();
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Execute request with retry logic
|
|
109
|
+
*/
|
|
110
|
+
async executeWithRetry(req, attempt = 0) {
|
|
111
|
+
try {
|
|
112
|
+
return await this.executeRequest(req);
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
if (attempt < this.config.retries) {
|
|
116
|
+
// Exponential backoff
|
|
117
|
+
await this.delay(Math.pow(2, attempt) * 100);
|
|
118
|
+
return await this.executeWithRetry(req, attempt + 1);
|
|
119
|
+
}
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Execute a single request
|
|
125
|
+
*/
|
|
126
|
+
async executeRequest(req) {
|
|
127
|
+
// Rewrite path if configured
|
|
128
|
+
const path = this.config.pathRewrite(req.path);
|
|
129
|
+
const url = new URL(path, this.config.target);
|
|
130
|
+
// Copy query parameters
|
|
131
|
+
Object.entries(req.query).forEach(([key, value]) => {
|
|
132
|
+
if (typeof value === "string") {
|
|
133
|
+
url.searchParams.append(key, value);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
// Build headers
|
|
137
|
+
const headers = {
|
|
138
|
+
...this.extractHeaders(req),
|
|
139
|
+
...this.config.headers,
|
|
140
|
+
};
|
|
141
|
+
// Build request options
|
|
142
|
+
const controller = new AbortController();
|
|
143
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
144
|
+
const requestInit = {
|
|
145
|
+
method: req.method,
|
|
146
|
+
headers,
|
|
147
|
+
signal: controller.signal,
|
|
148
|
+
};
|
|
149
|
+
// Add body for non-GET requests
|
|
150
|
+
if (req.method !== "GET" && req.method !== "HEAD" && req.body) {
|
|
151
|
+
requestInit.body = JSON.stringify(req.body);
|
|
152
|
+
headers["content-type"] = "application/json";
|
|
153
|
+
}
|
|
154
|
+
if (this.config.debug) {
|
|
155
|
+
console.log(`[Proxy] ${req.method} ${url.toString()}`);
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
const response = await fetch(url.toString(), requestInit);
|
|
159
|
+
clearTimeout(timeoutId);
|
|
160
|
+
// Cast to ProxyResponse to avoid conflict with Express Response type
|
|
161
|
+
return response;
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
clearTimeout(timeoutId);
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Extract relevant headers from incoming request
|
|
170
|
+
*/
|
|
171
|
+
extractHeaders(req) {
|
|
172
|
+
const headers = {};
|
|
173
|
+
const forwardHeaders = [
|
|
174
|
+
"authorization",
|
|
175
|
+
"content-type",
|
|
176
|
+
"accept",
|
|
177
|
+
"user-agent",
|
|
178
|
+
"x-request-id",
|
|
179
|
+
"x-trace-id",
|
|
180
|
+
"x-span-id",
|
|
181
|
+
"x-correlation-id",
|
|
182
|
+
];
|
|
183
|
+
forwardHeaders.forEach((header) => {
|
|
184
|
+
const value = req.headers[header];
|
|
185
|
+
if (typeof value === "string") {
|
|
186
|
+
headers[header] = value;
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
// Add X-Forwarded headers
|
|
190
|
+
headers["x-forwarded-for"] = req.ip || req.socket.remoteAddress || "unknown";
|
|
191
|
+
headers["x-forwarded-host"] = req.headers.host || "";
|
|
192
|
+
headers["x-forwarded-proto"] = req.protocol;
|
|
193
|
+
return headers;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Delay helper
|
|
197
|
+
*/
|
|
198
|
+
delay(ms) {
|
|
199
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Get circuit breaker stats (if enabled)
|
|
203
|
+
*/
|
|
204
|
+
getCircuitBreakerStats() {
|
|
205
|
+
return this.config.circuitBreaker?.getStats();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
exports.ServiceProxy = ServiceProxy;
|
|
209
|
+
/**
|
|
210
|
+
* Create a new service proxy
|
|
211
|
+
*/
|
|
212
|
+
function createProxy(config) {
|
|
213
|
+
return new ServiceProxy(config);
|
|
214
|
+
}
|
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createMicroAPI = void 0;
|
|
4
|
-
|
|
5
|
-
|
|
17
|
+
exports.createMicroAPI = exports.micro = void 0;
|
|
18
|
+
// Primary API - pure simplicity
|
|
19
|
+
var micro_js_1 = require("./micro.js");
|
|
20
|
+
Object.defineProperty(exports, "micro", { enumerable: true, get: function () { return micro_js_1.micro; } });
|
|
21
|
+
// Advanced features - import separately when needed
|
|
22
|
+
__exportStar(require("./gateway/index.js"), exports); // CircuitBreaker, ServiceProxy
|
|
23
|
+
__exportStar(require("./service-mesh/index.js"), exports); // ServiceDiscovery, ServiceClient
|
|
24
|
+
__exportStar(require("./serverless/index.js"), exports); // Lambda, Cloudflare, Vercel adapters
|
|
25
|
+
__exportStar(require("./queue/index.js"), exports); // RabbitMQ consumer
|
|
26
|
+
// Legacy API - deprecated, will be removed in v6
|
|
27
|
+
/** @deprecated Use micro() instead */
|
|
28
|
+
var application_express_micro_js_1 = require("./application-express-micro.js");
|
|
29
|
+
Object.defineProperty(exports, "createMicroAPI", { enumerable: true, get: function () { return application_express_micro_js_1.createMicroAPI; } });
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.micro = micro;
|
|
7
|
+
const core_1 = require("@expressots/core");
|
|
8
|
+
const express_1 = __importDefault(require("express"));
|
|
9
|
+
const application_express_js_1 = require("../application-express.js");
|
|
10
|
+
/**
|
|
11
|
+
* Create a new micro API instance
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const app = micro();
|
|
16
|
+
* app.get("/", () => "Hello World");
|
|
17
|
+
* app.listen(3000);
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @param config - Optional configuration
|
|
21
|
+
* @returns MicroApp instance
|
|
22
|
+
* @public API
|
|
23
|
+
*/
|
|
24
|
+
function micro(config) {
|
|
25
|
+
// Disable the log buffering from AppExpress since micro() doesn't use the banner system
|
|
26
|
+
// This restores normal console output for micro API users
|
|
27
|
+
application_express_js_1.AppExpress.disableBuffering();
|
|
28
|
+
const app = (0, express_1.default)();
|
|
29
|
+
const logger = new core_1.Logger();
|
|
30
|
+
const console = new core_1.Console();
|
|
31
|
+
const globalPrefix = config?.globalPrefix?.replace(/\/$/, "") || "";
|
|
32
|
+
let httpServer;
|
|
33
|
+
let errorHandler = null;
|
|
34
|
+
// Auto-enable JSON parsing by default
|
|
35
|
+
if (config?.autoParseJson !== false) {
|
|
36
|
+
app.use(express_1.default.json());
|
|
37
|
+
app.use(express_1.default.urlencoded({ extended: true }));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Wrap handler to auto-send return values
|
|
41
|
+
*/
|
|
42
|
+
const wrapHandler = (handler) => {
|
|
43
|
+
return async (req, res, next) => {
|
|
44
|
+
try {
|
|
45
|
+
const result = await handler(req, res, next);
|
|
46
|
+
// If response already sent, don't send again
|
|
47
|
+
if (res.headersSent) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// Auto-send return values
|
|
51
|
+
if (result !== undefined) {
|
|
52
|
+
if (typeof result === "string") {
|
|
53
|
+
res.send(result);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
res.json(result);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
next(error);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Register a route with Express-style middleware ordering
|
|
67
|
+
*/
|
|
68
|
+
const route = (method, path, ...handlers) => {
|
|
69
|
+
const fullPath = `${globalPrefix}${path.startsWith("/") ? path : `/${path}`}`;
|
|
70
|
+
const handler = handlers.pop();
|
|
71
|
+
const middleware = handlers;
|
|
72
|
+
app[method](fullPath, ...middleware, wrapHandler(handler));
|
|
73
|
+
logger.info(`Route ${method.toUpperCase()} '${fullPath}' registered`, "micro");
|
|
74
|
+
// Register in the suggestions engine so 404s can produce "Did you mean ...?"
|
|
75
|
+
try {
|
|
76
|
+
(0, core_1.getRouteRegistry)().register(method.toUpperCase(), fullPath, fullPath);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// Suggestions registry is optional; never fail registration because of it.
|
|
80
|
+
}
|
|
81
|
+
return microApp;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Install a catch-all 404 fallback that mirrors the behavior of the full
|
|
85
|
+
* inversify-express-server: log "Did you mean ...?" via the framework Logger
|
|
86
|
+
* and respond with a structured RFC-7807-style JSON body.
|
|
87
|
+
*
|
|
88
|
+
* Skipped entirely when the suggestion engine is disabled (the env-aware
|
|
89
|
+
* default disables it in NODE_ENV=production).
|
|
90
|
+
*/
|
|
91
|
+
const installNotFoundHandler = () => {
|
|
92
|
+
app.use((req, res, next) => {
|
|
93
|
+
if (res.headersSent) {
|
|
94
|
+
return next();
|
|
95
|
+
}
|
|
96
|
+
const suggestionsConfig = (0, core_1.getDefaultSuggestionsConfig)();
|
|
97
|
+
if (!suggestionsConfig.enabled) {
|
|
98
|
+
return next();
|
|
99
|
+
}
|
|
100
|
+
const requestedPath = req.originalUrl || req.url;
|
|
101
|
+
const requestedMethod = req.method;
|
|
102
|
+
const hints = (0, core_1.getErrorHints)(new Error(`Route '${requestedMethod} ${requestedPath}' not found`), {
|
|
103
|
+
path: requestedPath,
|
|
104
|
+
method: requestedMethod,
|
|
105
|
+
statusCode: 404,
|
|
106
|
+
}, suggestionsConfig);
|
|
107
|
+
if (hints.length > 0) {
|
|
108
|
+
try {
|
|
109
|
+
const formatted = (0, core_1.formatSuggestions)(hints);
|
|
110
|
+
if (formatted) {
|
|
111
|
+
logger.warn(`Route not found: ${requestedMethod} ${requestedPath}${formatted}`, "router-404");
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// best-effort logging
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const routeSuggestion = hints.find((hint) => hint.type === "route");
|
|
119
|
+
const actionHint = hints.find((hint) => hint.type === "hint");
|
|
120
|
+
const body = {
|
|
121
|
+
type: "https://expressots.dev/errors/not-found",
|
|
122
|
+
title: "Route Not Found",
|
|
123
|
+
status: 404,
|
|
124
|
+
detail: `Route '${requestedMethod} ${requestedPath}' does not exist`,
|
|
125
|
+
instance: requestedPath,
|
|
126
|
+
timestamp: new Date().toISOString(),
|
|
127
|
+
};
|
|
128
|
+
if (routeSuggestion?.routes && routeSuggestion.routes.length > 0) {
|
|
129
|
+
body.suggestions = routeSuggestion.routes.map((suggestion) => ({
|
|
130
|
+
method: suggestion.route.method,
|
|
131
|
+
path: suggestion.route.fullPath || suggestion.route.path,
|
|
132
|
+
similarity: Math.round(suggestion.similarity * 100),
|
|
133
|
+
reason: suggestion.reason,
|
|
134
|
+
}));
|
|
135
|
+
}
|
|
136
|
+
else if (actionHint?.actions && actionHint.actions.length > 0) {
|
|
137
|
+
body.actions = actionHint.actions;
|
|
138
|
+
}
|
|
139
|
+
res.status(404).type("application/json").send(JSON.stringify(body));
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Handle server shutdown gracefully
|
|
144
|
+
*/
|
|
145
|
+
const handleExit = () => {
|
|
146
|
+
logger.info("Server shutting down", "micro");
|
|
147
|
+
process.exit(0);
|
|
148
|
+
};
|
|
149
|
+
const microApp = {
|
|
150
|
+
get: (path, ...handlers) => route("get", path, ...handlers),
|
|
151
|
+
post: (path, ...handlers) => route("post", path, ...handlers),
|
|
152
|
+
put: (path, ...handlers) => route("put", path, ...handlers),
|
|
153
|
+
patch: (path, ...handlers) => route("patch", path, ...handlers),
|
|
154
|
+
delete: (path, ...handlers) => route("delete", path, ...handlers),
|
|
155
|
+
use(...args) {
|
|
156
|
+
if (typeof args[0] === "string") {
|
|
157
|
+
app.use(args[0], ...args.slice(1));
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
app.use(...args);
|
|
161
|
+
}
|
|
162
|
+
return microApp;
|
|
163
|
+
},
|
|
164
|
+
setErrorHandler(handler) {
|
|
165
|
+
errorHandler = handler;
|
|
166
|
+
return microApp;
|
|
167
|
+
},
|
|
168
|
+
async listen(port, appInfo) {
|
|
169
|
+
const normalizedPort = typeof port === "string" ? parseInt(port, 10) : port;
|
|
170
|
+
// Install the 404 fallback before the user error handler so unmatched
|
|
171
|
+
// routes get suggestions instead of falling through to the default
|
|
172
|
+
// Express HTML or - worse - to a regular middleware that arity-confused
|
|
173
|
+
// its way into running on every request.
|
|
174
|
+
installNotFoundHandler();
|
|
175
|
+
// Apply error handler last. Wrap it in a 4-arity function so that
|
|
176
|
+
// Express recognizes it as an error-handling middleware regardless of
|
|
177
|
+
// whether the user wrote `(err, req, res)` or `(err, req, res, next)`.
|
|
178
|
+
// Without this wrapper, Express would treat a 3-arg user handler as a
|
|
179
|
+
// regular middleware and run it on every request, which both swallows
|
|
180
|
+
// 404s and crashes when the user calls `res.status(...)` (positional
|
|
181
|
+
// `res` would actually be Express's `next`).
|
|
182
|
+
if (errorHandler) {
|
|
183
|
+
const userHandler = errorHandler;
|
|
184
|
+
const wrappedErrorHandler = (err, req, res, next) => userHandler(err, req, res, next);
|
|
185
|
+
app.use(wrappedErrorHandler);
|
|
186
|
+
}
|
|
187
|
+
return new Promise((resolve, reject) => {
|
|
188
|
+
httpServer = app.listen(normalizedPort, async () => {
|
|
189
|
+
const address = httpServer.address();
|
|
190
|
+
const actualPort = typeof address === "object" && address?.port ? address.port : normalizedPort;
|
|
191
|
+
if (config?.showBanner !== false) {
|
|
192
|
+
await console.messageServer(actualPort, "development", {
|
|
193
|
+
appName: appInfo?.appName || "ExpressoTS Micro",
|
|
194
|
+
appVersion: appInfo?.appVersion || "1.0.0",
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
// Handle graceful shutdown
|
|
198
|
+
["SIGTERM", "SIGHUP", "SIGBREAK", "SIGQUIT", "SIGINT"].forEach((signal) => {
|
|
199
|
+
process.on(signal, handleExit);
|
|
200
|
+
});
|
|
201
|
+
resolve();
|
|
202
|
+
});
|
|
203
|
+
httpServer.on("error", (error) => {
|
|
204
|
+
logger.error(`Server error: ${error.message}`, "micro");
|
|
205
|
+
reject(error);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
},
|
|
209
|
+
getHttpServer() {
|
|
210
|
+
return httpServer;
|
|
211
|
+
},
|
|
212
|
+
getApp() {
|
|
213
|
+
return app;
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
return microApp;
|
|
217
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Queue Integration for ExpressoTS Micro Template
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.RabbitMQConsumer = void 0;
|
|
7
|
+
var rabbitmq_consumer_js_1 = require("./rabbitmq-consumer.js");
|
|
8
|
+
Object.defineProperty(exports, "RabbitMQConsumer", { enumerable: true, get: function () { return rabbitmq_consumer_js_1.RabbitMQConsumer; } });
|