@abinashpatri/orchestrator 1.0.0 → 1.0.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 +37 -11
- package/dist/{consul-D2-fKyU6.d.mts → consul-DHnTju-E.d.mts} +4 -2
- package/dist/{consul-D2-fKyU6.d.ts → consul-DHnTju-E.d.ts} +4 -2
- package/dist/express.d.mts +2 -2
- package/dist/express.d.ts +2 -2
- package/dist/express.js +1 -1
- package/dist/express.js.map +1 -1
- package/dist/express.mjs +1 -1
- package/dist/express.mjs.map +1 -1
- package/dist/index.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ discovery, and API gateway routing.
|
|
|
5
5
|
|
|
6
6
|
Works in both ESM and CommonJS projects with full TypeScript type support.
|
|
7
7
|
|
|
8
|
-
Core APIs (`
|
|
8
|
+
Core APIs (`createServiceClient`, `registerService`, `deregisterService`, `getServiceUrl`) are framework-agnostic.
|
|
9
9
|
Express gateway APIs are available from the subpath `@abinashpatri/orchestrator/express`.
|
|
10
10
|
|
|
11
11
|
## Install
|
|
@@ -33,9 +33,9 @@ npm install express http-proxy-middleware
|
|
|
33
33
|
## 1) Create a Consul client
|
|
34
34
|
|
|
35
35
|
```ts
|
|
36
|
-
import {
|
|
36
|
+
import { createServiceClient } from "@abinashpatri/orchestrator";
|
|
37
37
|
|
|
38
|
-
const consul =
|
|
38
|
+
const consul = createServiceClient({
|
|
39
39
|
host: process.env.CONSUL_HOST ?? "127.0.0.1",
|
|
40
40
|
port: Number(process.env.CONSUL_PORT ?? 8500),
|
|
41
41
|
token: process.env.CONSUL_HTTP_TOKEN, // optional
|
|
@@ -76,12 +76,32 @@ By default, discovery returns a random healthy instance (simple load balancing).
|
|
|
76
76
|
|
|
77
77
|
```ts
|
|
78
78
|
import { createGatewayApp } from "@abinashpatri/orchestrator/express";
|
|
79
|
+
const userHeaderMiddleware = (req, res, next) => {
|
|
80
|
+
req.headers["x-service-source"] = "api-gateway";
|
|
81
|
+
next();
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const paymentAuthMiddleware = (req, res, next) => {
|
|
85
|
+
if (!req.headers.authorization) {
|
|
86
|
+
res.status(401).json({ error: "Missing Authorization header" });
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
next();
|
|
90
|
+
};
|
|
79
91
|
|
|
80
92
|
const app = createGatewayApp(consul, {
|
|
81
93
|
healthPath: "/health",
|
|
82
94
|
routes: [
|
|
83
|
-
{
|
|
84
|
-
|
|
95
|
+
{
|
|
96
|
+
serviceName: "user-service",
|
|
97
|
+
routePrefix: "/api/users",
|
|
98
|
+
middlewares: [userHeaderMiddleware],
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
serviceName: "payment-service",
|
|
102
|
+
routePrefix: "/api/payments",
|
|
103
|
+
middlewares: [paymentAuthMiddleware],
|
|
104
|
+
},
|
|
85
105
|
{ serviceName: "notification-service" }, // defaults to /api/notification-service
|
|
86
106
|
],
|
|
87
107
|
});
|
|
@@ -120,14 +140,14 @@ process.on("SIGTERM", shutdown("SIGTERM"));
|
|
|
120
140
|
|
|
121
141
|
```ts
|
|
122
142
|
import {
|
|
123
|
-
|
|
143
|
+
createServiceClient,
|
|
124
144
|
registerService,
|
|
125
145
|
deregisterService,
|
|
126
146
|
getServiceUrl,
|
|
127
147
|
} from "@abinashpatri/orchestrator";
|
|
128
148
|
import { createGatewayApp } from "@abinashpatri/orchestrator/express";
|
|
129
149
|
|
|
130
|
-
const consul =
|
|
150
|
+
const consul = createServiceClient({
|
|
131
151
|
host: process.env.CONSUL_HOST ?? "127.0.0.1",
|
|
132
152
|
port: Number(process.env.CONSUL_PORT ?? 8500),
|
|
133
153
|
token: process.env.CONSUL_HTTP_TOKEN,
|
|
@@ -186,7 +206,7 @@ process.on("SIGTERM", async () => {
|
|
|
186
206
|
|
|
187
207
|
```js
|
|
188
208
|
const {
|
|
189
|
-
|
|
209
|
+
createServiceClient,
|
|
190
210
|
registerService,
|
|
191
211
|
getServiceUrl,
|
|
192
212
|
deregisterService,
|
|
@@ -194,7 +214,7 @@ const {
|
|
|
194
214
|
const { createGatewayApp } = require("@abinashpatri/orchestrator/express");
|
|
195
215
|
|
|
196
216
|
async function main() {
|
|
197
|
-
const consul =
|
|
217
|
+
const consul = createServiceClient({
|
|
198
218
|
host: "127.0.0.1",
|
|
199
219
|
port: 8500,
|
|
200
220
|
token: process.env.CONSUL_HTTP_TOKEN,
|
|
@@ -235,7 +255,7 @@ main().catch((err) => {
|
|
|
235
255
|
|
|
236
256
|
## API reference
|
|
237
257
|
|
|
238
|
-
### `
|
|
258
|
+
### `createServiceClient(options?)`
|
|
239
259
|
|
|
240
260
|
Creates and returns a Consul client.
|
|
241
261
|
|
|
@@ -289,7 +309,7 @@ Creates an Express app and mounts service proxies for all routes.
|
|
|
289
309
|
|
|
290
310
|
`options`:
|
|
291
311
|
|
|
292
|
-
- `routes: Array<{ serviceName: string; routePrefix?: string }>` (required)
|
|
312
|
+
- `routes: Array<{ serviceName: string; routePrefix?: string; middlewares?: RequestHandler[] }>` (required)
|
|
293
313
|
- `healthPath?: string` (default: `/health`)
|
|
294
314
|
|
|
295
315
|
---
|
|
@@ -299,3 +319,9 @@ Creates an Express app and mounts service proxies for all routes.
|
|
|
299
319
|
- If Consul returns `host.docker.internal`, the library auto-resolves it to `127.0.0.1` for host-local calls.
|
|
300
320
|
- Keep service names consistent across registration and discovery.
|
|
301
321
|
- For production, always use graceful shutdown to avoid stale Consul registrations.
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## License
|
|
326
|
+
|
|
327
|
+
MIT
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Consul from 'consul';
|
|
2
|
+
import { RequestHandler } from 'express';
|
|
2
3
|
|
|
3
4
|
interface ConsulClientOptions {
|
|
4
5
|
host?: string;
|
|
@@ -23,6 +24,7 @@ interface ServiceRegistrationOptions {
|
|
|
23
24
|
interface GatewayRoute {
|
|
24
25
|
serviceName: string;
|
|
25
26
|
routePrefix?: string;
|
|
27
|
+
middlewares?: RequestHandler[];
|
|
26
28
|
}
|
|
27
29
|
interface ServiceProxyOptions {
|
|
28
30
|
serviceName: string;
|
|
@@ -34,6 +36,6 @@ interface GatewayOptions {
|
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
type ConsulClient = InstanceType<typeof Consul>;
|
|
37
|
-
declare function
|
|
39
|
+
declare function createServiceClient(options?: ConsulClientOptions): ConsulClient;
|
|
38
40
|
|
|
39
|
-
export { type ConsulClient as C, type GatewayOptions as G, type ServiceProxyOptions as S, type GatewayRoute as a, type ServiceDiscoveryOptions as b, type ServiceRegistrationOptions as c, type ConsulClientOptions as d,
|
|
41
|
+
export { type ConsulClient as C, type GatewayOptions as G, type ServiceProxyOptions as S, type GatewayRoute as a, type ServiceDiscoveryOptions as b, type ServiceRegistrationOptions as c, type ConsulClientOptions as d, createServiceClient as e };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Consul from 'consul';
|
|
2
|
+
import { RequestHandler } from 'express';
|
|
2
3
|
|
|
3
4
|
interface ConsulClientOptions {
|
|
4
5
|
host?: string;
|
|
@@ -23,6 +24,7 @@ interface ServiceRegistrationOptions {
|
|
|
23
24
|
interface GatewayRoute {
|
|
24
25
|
serviceName: string;
|
|
25
26
|
routePrefix?: string;
|
|
27
|
+
middlewares?: RequestHandler[];
|
|
26
28
|
}
|
|
27
29
|
interface ServiceProxyOptions {
|
|
28
30
|
serviceName: string;
|
|
@@ -34,6 +36,6 @@ interface GatewayOptions {
|
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
type ConsulClient = InstanceType<typeof Consul>;
|
|
37
|
-
declare function
|
|
39
|
+
declare function createServiceClient(options?: ConsulClientOptions): ConsulClient;
|
|
38
40
|
|
|
39
|
-
export { type ConsulClient as C, type GatewayOptions as G, type ServiceProxyOptions as S, type GatewayRoute as a, type ServiceDiscoveryOptions as b, type ServiceRegistrationOptions as c, type ConsulClientOptions as d,
|
|
41
|
+
export { type ConsulClient as C, type GatewayOptions as G, type ServiceProxyOptions as S, type GatewayRoute as a, type ServiceDiscoveryOptions as b, type ServiceRegistrationOptions as c, type ConsulClientOptions as d, createServiceClient as e };
|
package/dist/express.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Express, RequestHandler } from 'express';
|
|
2
|
-
import { C as ConsulClient, G as GatewayOptions, S as ServiceProxyOptions } from './consul-
|
|
3
|
-
export { a as GatewayRoute } from './consul-
|
|
2
|
+
import { C as ConsulClient, G as GatewayOptions, S as ServiceProxyOptions } from './consul-DHnTju-E.mjs';
|
|
3
|
+
export { a as GatewayRoute } from './consul-DHnTju-E.mjs';
|
|
4
4
|
import 'consul';
|
|
5
5
|
|
|
6
6
|
declare function createServiceProxy(consulClient: ConsulClient, options: ServiceProxyOptions): RequestHandler;
|
package/dist/express.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Express, RequestHandler } from 'express';
|
|
2
|
-
import { C as ConsulClient, G as GatewayOptions, S as ServiceProxyOptions } from './consul-
|
|
3
|
-
export { a as GatewayRoute } from './consul-
|
|
2
|
+
import { C as ConsulClient, G as GatewayOptions, S as ServiceProxyOptions } from './consul-DHnTju-E.js';
|
|
3
|
+
export { a as GatewayRoute } from './consul-DHnTju-E.js';
|
|
4
4
|
import 'consul';
|
|
5
5
|
|
|
6
6
|
declare function createServiceProxy(consulClient: ConsulClient, options: ServiceProxyOptions): RequestHandler;
|
package/dist/express.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var g=Object.create;var
|
|
1
|
+
"use strict";var g=Object.create;var c=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,w=Object.prototype.hasOwnProperty;var S=(e,r)=>{for(var o in r)c(e,o,{get:r[o],enumerable:!0})},l=(e,r,o,s)=>{if(r&&typeof r=="object"||typeof r=="function")for(let t of P(r))!w.call(e,t)&&t!==o&&c(e,t,{get:()=>r[t],enumerable:!(s=x(r,t))||s.enumerable});return e};var C=(e,r,o)=>(o=e!=null?g(d(e)):{},l(r||!e||!e.__esModule?c(o,"default",{value:e,enumerable:!0}):o,e)),O=e=>l(c({},"__esModule",{value:!0}),e);var G={};S(G,{createGatewayApp:()=>h,createServiceProxy:()=>u});module.exports=O(G);var y=C(require("express")),f=require("http-proxy-middleware");function $(e){return e==="host.docker.internal"?"127.0.0.1":e}async function m(e,r,o={}){let s=await e.health.service({service:r,passing:o.passing??!0});if(!s.length)throw new Error(`No healthy instance found for "${r}"`);let t=s[Math.floor(Math.random()*s.length)],n=$(t.Service.Address),i=t.Service.Port;return`http://${n}:${String(i)}`}function p(e){return e.startsWith("/")?e:`/${e}`}function u(e,r){let s=`^${p(r.routePrefix??`/api/${r.serviceName}`)}`;return async(t,n,i)=>{try{let a=await m(e,r.serviceName);return(0,f.createProxyMiddleware)({target:a,changeOrigin:!0,pathRewrite:{[s]:""}})(t,n,i)}catch(a){let v=a instanceof Error?a.message:"Service discovery failed";n.status(503).json({service:r.serviceName,error:v})}}}function h(e,r){let o=(0,y.default)(),s=p(r.healthPath??"/health");o.get(s,(t,n)=>{n.status(200).send("OK")});for(let t of r.routes){let n=p(t.routePrefix??`/api/${t.serviceName}`),i=t.middlewares??[];o.use(n,...i,u(e,{serviceName:t.serviceName,routePrefix:n}))}return o}0&&(module.exports={createGatewayApp,createServiceProxy});
|
|
2
2
|
//# sourceMappingURL=express.js.map
|
package/dist/express.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/express.ts","../src/gateway.ts","../src/discover.ts"],"sourcesContent":["export { createGatewayApp, createServiceProxy } from \"./gateway\";\n\nexport type { GatewayOptions, GatewayRoute, ServiceProxyOptions } from \"./types\";\n","import express, { type Express, type RequestHandler } from \"express\";\nimport { createProxyMiddleware } from \"http-proxy-middleware\";\nimport type { ConsulClient } from \"./consul\";\nimport { getServiceUrl } from \"./discover\";\nimport type { GatewayOptions, ServiceProxyOptions } from \"./types\";\n\nfunction normalizePrefix(prefix: string): string {\n return prefix.startsWith(\"/\") ? prefix : `/${prefix}`;\n}\n\nexport function createServiceProxy(\n consulClient: ConsulClient,\n options: ServiceProxyOptions,\n): RequestHandler {\n const routePrefix = normalizePrefix(options.routePrefix ?? `/api/${options.serviceName}`);\n const pathPrefixPattern = `^${routePrefix}`;\n\n return async (req, res, next) => {\n try {\n const target = await getServiceUrl(consulClient, options.serviceName);\n\n return createProxyMiddleware({\n target,\n changeOrigin: true,\n pathRewrite: {\n [pathPrefixPattern]: \"\",\n },\n })(req, res, next);\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Service discovery failed\";\n res.status(503).json({\n service: options.serviceName,\n error: message,\n });\n }\n };\n}\n\nexport function createGatewayApp(consulClient: ConsulClient, options: GatewayOptions): Express {\n const app = express();\n const healthPath = normalizePrefix(options.healthPath ?? \"/health\");\n\n app.get(healthPath, (_req, res) => {\n res.status(200).send(\"OK\");\n });\n\n for (const route of options.routes) {\n const routePrefix = normalizePrefix(route.routePrefix ?? `/api/${route.serviceName}`);\n app.use(routePrefix
|
|
1
|
+
{"version":3,"sources":["../src/express.ts","../src/gateway.ts","../src/discover.ts"],"sourcesContent":["export { createGatewayApp, createServiceProxy } from \"./gateway\";\n\nexport type { GatewayOptions, GatewayRoute, ServiceProxyOptions } from \"./types\";\n","import express, { type Express, type RequestHandler } from \"express\";\nimport { createProxyMiddleware } from \"http-proxy-middleware\";\nimport type { ConsulClient } from \"./consul\";\nimport { getServiceUrl } from \"./discover\";\nimport type { GatewayOptions, ServiceProxyOptions } from \"./types\";\n\nfunction normalizePrefix(prefix: string): string {\n return prefix.startsWith(\"/\") ? prefix : `/${prefix}`;\n}\n\nexport function createServiceProxy(\n consulClient: ConsulClient,\n options: ServiceProxyOptions,\n): RequestHandler {\n const routePrefix = normalizePrefix(options.routePrefix ?? `/api/${options.serviceName}`);\n const pathPrefixPattern = `^${routePrefix}`;\n\n return async (req, res, next) => {\n try {\n const target = await getServiceUrl(consulClient, options.serviceName);\n\n return createProxyMiddleware({\n target,\n changeOrigin: true,\n pathRewrite: {\n [pathPrefixPattern]: \"\",\n },\n })(req, res, next);\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Service discovery failed\";\n res.status(503).json({\n service: options.serviceName,\n error: message,\n });\n }\n };\n}\n\nexport function createGatewayApp(consulClient: ConsulClient, options: GatewayOptions): Express {\n const app = express();\n const healthPath = normalizePrefix(options.healthPath ?? \"/health\");\n\n app.get(healthPath, (_req, res) => {\n res.status(200).send(\"OK\");\n });\n\n for (const route of options.routes) {\n const routePrefix = normalizePrefix(route.routePrefix ?? `/api/${route.serviceName}`);\n const middlewares = route.middlewares ?? [];\n app.use(\n routePrefix,\n ...middlewares,\n createServiceProxy(consulClient, {\n serviceName: route.serviceName,\n routePrefix,\n }),\n );\n }\n\n return app;\n}\n","import type { ConsulClient } from \"./consul\";\nimport type { ServiceDiscoveryOptions } from \"./types\";\n\nfunction normalizeHost(address: string): string {\n return address === \"host.docker.internal\" ? \"127.0.0.1\" : address;\n}\n\nexport async function getServiceUrl(\n consulClient: ConsulClient,\n serviceName: string,\n options: ServiceDiscoveryOptions = {},\n): Promise<string> {\n const services = await consulClient.health.service({\n service: serviceName,\n passing: options.passing ?? true,\n });\n\n if (!services.length) {\n throw new Error(`No healthy instance found for \"${serviceName}\"`);\n }\n\n const randomInstance = services[Math.floor(Math.random() * services.length)];\n const host = normalizeHost(randomInstance.Service.Address);\n const port = randomInstance.Service.Port;\n\n return `http://${host}:${String(port)}`;\n}\n"],"mappings":"0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,sBAAAE,EAAA,uBAAAC,IAAA,eAAAC,EAAAJ,GCAA,IAAAK,EAA2D,sBAC3DC,EAAsC,iCCEtC,SAASC,EAAcC,EAAyB,CAC9C,OAAOA,IAAY,uBAAyB,YAAcA,CAC5D,CAEA,eAAsBC,EACpBC,EACAC,EACAC,EAAmC,CAAC,EACnB,CACjB,IAAMC,EAAW,MAAMH,EAAa,OAAO,QAAQ,CACjD,QAASC,EACT,QAASC,EAAQ,SAAW,EAC9B,CAAC,EAED,GAAI,CAACC,EAAS,OACZ,MAAM,IAAI,MAAM,kCAAkCF,CAAW,GAAG,EAGlE,IAAMG,EAAiBD,EAAS,KAAK,MAAM,KAAK,OAAO,EAAIA,EAAS,MAAM,CAAC,EACrEE,EAAOR,EAAcO,EAAe,QAAQ,OAAO,EACnDE,EAAOF,EAAe,QAAQ,KAEpC,MAAO,UAAUC,CAAI,IAAI,OAAOC,CAAI,CAAC,EACvC,CDpBA,SAASC,EAAgBC,EAAwB,CAC/C,OAAOA,EAAO,WAAW,GAAG,EAAIA,EAAS,IAAIA,CAAM,EACrD,CAEO,SAASC,EACdC,EACAC,EACgB,CAEhB,IAAMC,EAAoB,IADNL,EAAgBI,EAAQ,aAAe,QAAQA,EAAQ,WAAW,EAAE,CAC/C,GAEzC,MAAO,OAAOE,EAAKC,EAAKC,IAAS,CAC/B,GAAI,CACF,IAAMC,EAAS,MAAMC,EAAcP,EAAcC,EAAQ,WAAW,EAEpE,SAAO,yBAAsB,CAC3B,OAAAK,EACA,aAAc,GACd,YAAa,CACX,CAACJ,CAAiB,EAAG,EACvB,CACF,CAAC,EAAEC,EAAKC,EAAKC,CAAI,CACnB,OAASG,EAAO,CACd,IAAMC,EAAUD,aAAiB,MAAQA,EAAM,QAAU,2BACzDJ,EAAI,OAAO,GAAG,EAAE,KAAK,CACnB,QAASH,EAAQ,YACjB,MAAOQ,CACT,CAAC,CACH,CACF,CACF,CAEO,SAASC,EAAiBV,EAA4BC,EAAkC,CAC7F,IAAMU,KAAM,EAAAC,SAAQ,EACdC,EAAahB,EAAgBI,EAAQ,YAAc,SAAS,EAElEU,EAAI,IAAIE,EAAY,CAACC,EAAMV,IAAQ,CACjCA,EAAI,OAAO,GAAG,EAAE,KAAK,IAAI,CAC3B,CAAC,EAED,QAAWW,KAASd,EAAQ,OAAQ,CAClC,IAAMe,EAAcnB,EAAgBkB,EAAM,aAAe,QAAQA,EAAM,WAAW,EAAE,EAC9EE,EAAcF,EAAM,aAAe,CAAC,EAC1CJ,EAAI,IACFK,EACA,GAAGC,EACHlB,EAAmBC,EAAc,CAC/B,YAAae,EAAM,YACnB,YAAAC,CACF,CAAC,CACH,CACF,CAEA,OAAOL,CACT","names":["express_exports","__export","createGatewayApp","createServiceProxy","__toCommonJS","import_express","import_http_proxy_middleware","normalizeHost","address","getServiceUrl","consulClient","serviceName","options","services","randomInstance","host","port","normalizePrefix","prefix","createServiceProxy","consulClient","options","pathPrefixPattern","req","res","next","target","getServiceUrl","error","message","createGatewayApp","app","express","healthPath","_req","route","routePrefix","middlewares"]}
|
package/dist/express.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as
|
|
1
|
+
import{a as p}from"./chunk-24OKBTEJ.mjs";import y from"express";import{createProxyMiddleware as f}from"http-proxy-middleware";function c(e){return e.startsWith("/")?e:`/${e}`}function u(e,r){let i=`^${c(r.routePrefix??`/api/${r.serviceName}`)}`;return async(t,a,n)=>{try{let s=await p(e,r.serviceName);return f({target:s,changeOrigin:!0,pathRewrite:{[i]:""}})(t,a,n)}catch(s){let m=s instanceof Error?s.message:"Service discovery failed";a.status(503).json({service:r.serviceName,error:m})}}}function l(e,r){let o=y(),i=c(r.healthPath??"/health");o.get(i,(t,a)=>{a.status(200).send("OK")});for(let t of r.routes){let a=c(t.routePrefix??`/api/${t.serviceName}`),n=t.middlewares??[];o.use(a,...n,u(e,{serviceName:t.serviceName,routePrefix:a}))}return o}export{l as createGatewayApp,u as createServiceProxy};
|
|
2
2
|
//# sourceMappingURL=express.mjs.map
|
package/dist/express.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/gateway.ts"],"sourcesContent":["import express, { type Express, type RequestHandler } from \"express\";\nimport { createProxyMiddleware } from \"http-proxy-middleware\";\nimport type { ConsulClient } from \"./consul\";\nimport { getServiceUrl } from \"./discover\";\nimport type { GatewayOptions, ServiceProxyOptions } from \"./types\";\n\nfunction normalizePrefix(prefix: string): string {\n return prefix.startsWith(\"/\") ? prefix : `/${prefix}`;\n}\n\nexport function createServiceProxy(\n consulClient: ConsulClient,\n options: ServiceProxyOptions,\n): RequestHandler {\n const routePrefix = normalizePrefix(options.routePrefix ?? `/api/${options.serviceName}`);\n const pathPrefixPattern = `^${routePrefix}`;\n\n return async (req, res, next) => {\n try {\n const target = await getServiceUrl(consulClient, options.serviceName);\n\n return createProxyMiddleware({\n target,\n changeOrigin: true,\n pathRewrite: {\n [pathPrefixPattern]: \"\",\n },\n })(req, res, next);\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Service discovery failed\";\n res.status(503).json({\n service: options.serviceName,\n error: message,\n });\n }\n };\n}\n\nexport function createGatewayApp(consulClient: ConsulClient, options: GatewayOptions): Express {\n const app = express();\n const healthPath = normalizePrefix(options.healthPath ?? \"/health\");\n\n app.get(healthPath, (_req, res) => {\n res.status(200).send(\"OK\");\n });\n\n for (const route of options.routes) {\n const routePrefix = normalizePrefix(route.routePrefix ?? `/api/${route.serviceName}`);\n app.use(routePrefix
|
|
1
|
+
{"version":3,"sources":["../src/gateway.ts"],"sourcesContent":["import express, { type Express, type RequestHandler } from \"express\";\nimport { createProxyMiddleware } from \"http-proxy-middleware\";\nimport type { ConsulClient } from \"./consul\";\nimport { getServiceUrl } from \"./discover\";\nimport type { GatewayOptions, ServiceProxyOptions } from \"./types\";\n\nfunction normalizePrefix(prefix: string): string {\n return prefix.startsWith(\"/\") ? prefix : `/${prefix}`;\n}\n\nexport function createServiceProxy(\n consulClient: ConsulClient,\n options: ServiceProxyOptions,\n): RequestHandler {\n const routePrefix = normalizePrefix(options.routePrefix ?? `/api/${options.serviceName}`);\n const pathPrefixPattern = `^${routePrefix}`;\n\n return async (req, res, next) => {\n try {\n const target = await getServiceUrl(consulClient, options.serviceName);\n\n return createProxyMiddleware({\n target,\n changeOrigin: true,\n pathRewrite: {\n [pathPrefixPattern]: \"\",\n },\n })(req, res, next);\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Service discovery failed\";\n res.status(503).json({\n service: options.serviceName,\n error: message,\n });\n }\n };\n}\n\nexport function createGatewayApp(consulClient: ConsulClient, options: GatewayOptions): Express {\n const app = express();\n const healthPath = normalizePrefix(options.healthPath ?? \"/health\");\n\n app.get(healthPath, (_req, res) => {\n res.status(200).send(\"OK\");\n });\n\n for (const route of options.routes) {\n const routePrefix = normalizePrefix(route.routePrefix ?? `/api/${route.serviceName}`);\n const middlewares = route.middlewares ?? [];\n app.use(\n routePrefix,\n ...middlewares,\n createServiceProxy(consulClient, {\n serviceName: route.serviceName,\n routePrefix,\n }),\n );\n }\n\n return app;\n}\n"],"mappings":"yCAAA,OAAOA,MAAoD,UAC3D,OAAS,yBAAAC,MAA6B,wBAKtC,SAASC,EAAgBC,EAAwB,CAC/C,OAAOA,EAAO,WAAW,GAAG,EAAIA,EAAS,IAAIA,CAAM,EACrD,CAEO,SAASC,EACdC,EACAC,EACgB,CAEhB,IAAMC,EAAoB,IADNL,EAAgBI,EAAQ,aAAe,QAAQA,EAAQ,WAAW,EAAE,CAC/C,GAEzC,MAAO,OAAOE,EAAKC,EAAKC,IAAS,CAC/B,GAAI,CACF,IAAMC,EAAS,MAAMC,EAAcP,EAAcC,EAAQ,WAAW,EAEpE,OAAOO,EAAsB,CAC3B,OAAAF,EACA,aAAc,GACd,YAAa,CACX,CAACJ,CAAiB,EAAG,EACvB,CACF,CAAC,EAAEC,EAAKC,EAAKC,CAAI,CACnB,OAASI,EAAO,CACd,IAAMC,EAAUD,aAAiB,MAAQA,EAAM,QAAU,2BACzDL,EAAI,OAAO,GAAG,EAAE,KAAK,CACnB,QAASH,EAAQ,YACjB,MAAOS,CACT,CAAC,CACH,CACF,CACF,CAEO,SAASC,EAAiBX,EAA4BC,EAAkC,CAC7F,IAAMW,EAAMC,EAAQ,EACdC,EAAajB,EAAgBI,EAAQ,YAAc,SAAS,EAElEW,EAAI,IAAIE,EAAY,CAACC,EAAMX,IAAQ,CACjCA,EAAI,OAAO,GAAG,EAAE,KAAK,IAAI,CAC3B,CAAC,EAED,QAAWY,KAASf,EAAQ,OAAQ,CAClC,IAAMgB,EAAcpB,EAAgBmB,EAAM,aAAe,QAAQA,EAAM,WAAW,EAAE,EAC9EE,EAAcF,EAAM,aAAe,CAAC,EAC1CJ,EAAI,IACFK,EACA,GAAGC,EACHnB,EAAmBC,EAAc,CAC/B,YAAagB,EAAM,YACnB,YAAAC,CACF,CAAC,CACH,CACF,CAEA,OAAOL,CACT","names":["express","createProxyMiddleware","normalizePrefix","prefix","createServiceProxy","consulClient","options","pathPrefixPattern","req","res","next","target","getServiceUrl","createProxyMiddleware","error","message","createGatewayApp","app","express","healthPath","_req","route","routePrefix","middlewares"]}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { C as ConsulClient, b as ServiceDiscoveryOptions, c as ServiceRegistrationOptions } from './consul-
|
|
2
|
-
export { d as ConsulClientOptions, e as
|
|
1
|
+
import { C as ConsulClient, b as ServiceDiscoveryOptions, c as ServiceRegistrationOptions } from './consul-DHnTju-E.mjs';
|
|
2
|
+
export { d as ConsulClientOptions, e as createServiceClient } from './consul-DHnTju-E.mjs';
|
|
3
3
|
import 'consul';
|
|
4
|
+
import 'express';
|
|
4
5
|
|
|
5
6
|
declare function getServiceUrl(consulClient: ConsulClient, serviceName: string, options?: ServiceDiscoveryOptions): Promise<string>;
|
|
6
7
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { C as ConsulClient, b as ServiceDiscoveryOptions, c as ServiceRegistrationOptions } from './consul-
|
|
2
|
-
export { d as ConsulClientOptions, e as
|
|
1
|
+
import { C as ConsulClient, b as ServiceDiscoveryOptions, c as ServiceRegistrationOptions } from './consul-DHnTju-E.js';
|
|
2
|
+
export { d as ConsulClientOptions, e as createServiceClient } from './consul-DHnTju-E.js';
|
|
3
3
|
import 'consul';
|
|
4
|
+
import 'express';
|
|
4
5
|
|
|
5
6
|
declare function getServiceUrl(consulClient: ConsulClient, serviceName: string, options?: ServiceDiscoveryOptions): Promise<string>;
|
|
6
7
|
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var g=Object.create;var s=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var
|
|
1
|
+
"use strict";var g=Object.create;var s=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var C=Object.getPrototypeOf,d=Object.prototype.hasOwnProperty;var y=(t,e)=>{for(var r in e)s(t,r,{get:e[r],enumerable:!0})},a=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of f(e))!d.call(t,i)&&i!==r&&s(t,i,{get:()=>e[i],enumerable:!(n=m(e,i))||n.enumerable});return t};var S=(t,e,r)=>(r=t!=null?g(C(t)):{},a(e||!t||!t.__esModule?s(r,"default",{value:t,enumerable:!0}):r,t)),x=t=>a(s({},"__esModule",{value:!0}),t);var $={};y($,{createServiceClient:()=>p,deregisterService:()=>u,getServiceUrl:()=>h,registerService:()=>v});module.exports=x($);var l=S(require("consul"));function p(t={}){let{host:e="127.0.0.1",port:r=8500,token:n,secure:i=!1}=t;return new l.default({host:e,port:r,secure:i,defaults:n?{token:n}:void 0})}function O(t){return t==="host.docker.internal"?"127.0.0.1":t}async function h(t,e,r={}){let n=await t.health.service({service:e,passing:r.passing??!0});if(!n.length)throw new Error(`No healthy instance found for "${e}"`);let i=n[Math.floor(Math.random()*n.length)],o=O(i.Service.Address),c=i.Service.Port;return`http://${o}:${String(c)}`}async function v(t,e){let r=e.serviceId??`${e.serviceName}-${process.pid}`,n=e.healthPath??"/health",i=e.healthInterval??"10s",o=e.healthTimeout??"5s",c=e.deregisterCriticalServiceAfter??"30s";return await t.agent.service.register({id:r,name:e.serviceName,address:e.address,port:e.port,tags:e.tags,check:{name:`${e.serviceName}-health`,http:`http://${e.address}:${String(e.port)}${n}`,interval:i,timeout:o,deregistercriticalserviceafter:c}}),r}async function u(t,e){await t.agent.service.deregister(e)}0&&(module.exports={createServiceClient,deregisterService,getServiceUrl,registerService});
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/consul.ts","../src/discover.ts","../src/register.ts"],"sourcesContent":["export {
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/consul.ts","../src/discover.ts","../src/register.ts"],"sourcesContent":["export { createServiceClient } from \"./consul\";\nexport type { ConsulClient } from \"./consul\";\n\nexport { getServiceUrl } from \"./discover\";\nexport { registerService, deregisterService } from \"./register\";\n\nexport type {\n ConsulClientOptions,\n ServiceDiscoveryOptions,\n ServiceRegistrationOptions,\n} from \"./types\";\n","import Consul from \"consul\";\nimport type { ConsulClientOptions } from \"./types\";\n\nexport type ConsulClient = InstanceType<typeof Consul>;\n\nexport function createServiceClient(options: ConsulClientOptions = {}): ConsulClient {\n const { host = \"127.0.0.1\", port = 8500, token, secure = false } = options;\n\n return new Consul({\n host,\n port,\n secure,\n defaults: token ? { token } : undefined,\n });\n}\n","import type { ConsulClient } from \"./consul\";\nimport type { ServiceDiscoveryOptions } from \"./types\";\n\nfunction normalizeHost(address: string): string {\n return address === \"host.docker.internal\" ? \"127.0.0.1\" : address;\n}\n\nexport async function getServiceUrl(\n consulClient: ConsulClient,\n serviceName: string,\n options: ServiceDiscoveryOptions = {},\n): Promise<string> {\n const services = await consulClient.health.service({\n service: serviceName,\n passing: options.passing ?? true,\n });\n\n if (!services.length) {\n throw new Error(`No healthy instance found for \"${serviceName}\"`);\n }\n\n const randomInstance = services[Math.floor(Math.random() * services.length)];\n const host = normalizeHost(randomInstance.Service.Address);\n const port = randomInstance.Service.Port;\n\n return `http://${host}:${String(port)}`;\n}\n","import type { ConsulClient } from \"./consul\";\nimport type { ServiceRegistrationOptions } from \"./types\";\n\nexport async function registerService(\n consulClient: ConsulClient,\n options: ServiceRegistrationOptions,\n): Promise<string> {\n const serviceId = options.serviceId ?? `${options.serviceName}-${process.pid}`;\n const healthPath = options.healthPath ?? \"/health\";\n const healthInterval = options.healthInterval ?? \"10s\";\n const healthTimeout = options.healthTimeout ?? \"5s\";\n const deregisterAfter = options.deregisterCriticalServiceAfter ?? \"30s\";\n\n await consulClient.agent.service.register({\n id: serviceId,\n name: options.serviceName,\n address: options.address,\n port: options.port,\n tags: options.tags,\n check: {\n name: `${options.serviceName}-health`,\n http: `http://${options.address}:${String(options.port)}${healthPath}`,\n interval: healthInterval,\n timeout: healthTimeout,\n deregistercriticalserviceafter: deregisterAfter,\n },\n });\n\n return serviceId;\n}\n\nexport async function deregisterService(\n consulClient: ConsulClient,\n serviceId: string,\n): Promise<void> {\n await consulClient.agent.service.deregister(serviceId);\n}\n"],"mappings":"0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,yBAAAE,EAAA,sBAAAC,EAAA,kBAAAC,EAAA,oBAAAC,IAAA,eAAAC,EAAAN,GCAA,IAAAO,EAAmB,qBAKZ,SAASC,EAAoBC,EAA+B,CAAC,EAAiB,CACnF,GAAM,CAAE,KAAAC,EAAO,YAAa,KAAAC,EAAO,KAAM,MAAAC,EAAO,OAAAC,EAAS,EAAM,EAAIJ,EAEnE,OAAO,IAAI,EAAAK,QAAO,CAChB,KAAAJ,EACA,KAAAC,EACA,OAAAE,EACA,SAAUD,EAAQ,CAAE,MAAAA,CAAM,EAAI,MAChC,CAAC,CACH,CCXA,SAASG,EAAcC,EAAyB,CAC9C,OAAOA,IAAY,uBAAyB,YAAcA,CAC5D,CAEA,eAAsBC,EACpBC,EACAC,EACAC,EAAmC,CAAC,EACnB,CACjB,IAAMC,EAAW,MAAMH,EAAa,OAAO,QAAQ,CACjD,QAASC,EACT,QAASC,EAAQ,SAAW,EAC9B,CAAC,EAED,GAAI,CAACC,EAAS,OACZ,MAAM,IAAI,MAAM,kCAAkCF,CAAW,GAAG,EAGlE,IAAMG,EAAiBD,EAAS,KAAK,MAAM,KAAK,OAAO,EAAIA,EAAS,MAAM,CAAC,EACrEE,EAAOR,EAAcO,EAAe,QAAQ,OAAO,EACnDE,EAAOF,EAAe,QAAQ,KAEpC,MAAO,UAAUC,CAAI,IAAI,OAAOC,CAAI,CAAC,EACvC,CCvBA,eAAsBC,EACpBC,EACAC,EACiB,CACjB,IAAMC,EAAYD,EAAQ,WAAa,GAAGA,EAAQ,WAAW,IAAI,QAAQ,GAAG,GACtEE,EAAaF,EAAQ,YAAc,UACnCG,EAAiBH,EAAQ,gBAAkB,MAC3CI,EAAgBJ,EAAQ,eAAiB,KACzCK,EAAkBL,EAAQ,gCAAkC,MAElE,aAAMD,EAAa,MAAM,QAAQ,SAAS,CACxC,GAAIE,EACJ,KAAMD,EAAQ,YACd,QAASA,EAAQ,QACjB,KAAMA,EAAQ,KACd,KAAMA,EAAQ,KACd,MAAO,CACL,KAAM,GAAGA,EAAQ,WAAW,UAC5B,KAAM,UAAUA,EAAQ,OAAO,IAAI,OAAOA,EAAQ,IAAI,CAAC,GAAGE,CAAU,GACpE,SAAUC,EACV,QAASC,EACT,+BAAgCC,CAClC,CACF,CAAC,EAEMJ,CACT,CAEA,eAAsBK,EACpBP,EACAE,EACe,CACf,MAAMF,EAAa,MAAM,QAAQ,WAAWE,CAAS,CACvD","names":["index_exports","__export","createServiceClient","deregisterService","getServiceUrl","registerService","__toCommonJS","import_consul","createServiceClient","options","host","port","token","secure","Consul","normalizeHost","address","getServiceUrl","consulClient","serviceName","options","services","randomInstance","host","port","registerService","consulClient","options","serviceId","healthPath","healthInterval","healthTimeout","deregisterAfter","deregisterService"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a}from"./chunk-24OKBTEJ.mjs";import
|
|
1
|
+
import{a as c}from"./chunk-24OKBTEJ.mjs";import a from"consul";function l(t={}){let{host:e="127.0.0.1",port:r=8500,token:i,secure:s=!1}=t;return new a({host:e,port:r,secure:s,defaults:i?{token:i}:void 0})}async function p(t,e){let r=e.serviceId??`${e.serviceName}-${process.pid}`,i=e.healthPath??"/health",s=e.healthInterval??"10s",n=e.healthTimeout??"5s",o=e.deregisterCriticalServiceAfter??"30s";return await t.agent.service.register({id:r,name:e.serviceName,address:e.address,port:e.port,tags:e.tags,check:{name:`${e.serviceName}-health`,http:`http://${e.address}:${String(e.port)}${i}`,interval:s,timeout:n,deregistercriticalserviceafter:o}}),r}async function v(t,e){await t.agent.service.deregister(e)}export{l as createServiceClient,v as deregisterService,c as getServiceUrl,p as registerService};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/consul.ts","../src/register.ts"],"sourcesContent":["import Consul from \"consul\";\nimport type { ConsulClientOptions } from \"./types\";\n\nexport type ConsulClient = InstanceType<typeof Consul>;\n\nexport function
|
|
1
|
+
{"version":3,"sources":["../src/consul.ts","../src/register.ts"],"sourcesContent":["import Consul from \"consul\";\nimport type { ConsulClientOptions } from \"./types\";\n\nexport type ConsulClient = InstanceType<typeof Consul>;\n\nexport function createServiceClient(options: ConsulClientOptions = {}): ConsulClient {\n const { host = \"127.0.0.1\", port = 8500, token, secure = false } = options;\n\n return new Consul({\n host,\n port,\n secure,\n defaults: token ? { token } : undefined,\n });\n}\n","import type { ConsulClient } from \"./consul\";\nimport type { ServiceRegistrationOptions } from \"./types\";\n\nexport async function registerService(\n consulClient: ConsulClient,\n options: ServiceRegistrationOptions,\n): Promise<string> {\n const serviceId = options.serviceId ?? `${options.serviceName}-${process.pid}`;\n const healthPath = options.healthPath ?? \"/health\";\n const healthInterval = options.healthInterval ?? \"10s\";\n const healthTimeout = options.healthTimeout ?? \"5s\";\n const deregisterAfter = options.deregisterCriticalServiceAfter ?? \"30s\";\n\n await consulClient.agent.service.register({\n id: serviceId,\n name: options.serviceName,\n address: options.address,\n port: options.port,\n tags: options.tags,\n check: {\n name: `${options.serviceName}-health`,\n http: `http://${options.address}:${String(options.port)}${healthPath}`,\n interval: healthInterval,\n timeout: healthTimeout,\n deregistercriticalserviceafter: deregisterAfter,\n },\n });\n\n return serviceId;\n}\n\nexport async function deregisterService(\n consulClient: ConsulClient,\n serviceId: string,\n): Promise<void> {\n await consulClient.agent.service.deregister(serviceId);\n}\n"],"mappings":"yCAAA,OAAOA,MAAY,SAKZ,SAASC,EAAoBC,EAA+B,CAAC,EAAiB,CACnF,GAAM,CAAE,KAAAC,EAAO,YAAa,KAAAC,EAAO,KAAM,MAAAC,EAAO,OAAAC,EAAS,EAAM,EAAIJ,EAEnE,OAAO,IAAIF,EAAO,CAChB,KAAAG,EACA,KAAAC,EACA,OAAAE,EACA,SAAUD,EAAQ,CAAE,MAAAA,CAAM,EAAI,MAChC,CAAC,CACH,CCXA,eAAsBE,EACpBC,EACAC,EACiB,CACjB,IAAMC,EAAYD,EAAQ,WAAa,GAAGA,EAAQ,WAAW,IAAI,QAAQ,GAAG,GACtEE,EAAaF,EAAQ,YAAc,UACnCG,EAAiBH,EAAQ,gBAAkB,MAC3CI,EAAgBJ,EAAQ,eAAiB,KACzCK,EAAkBL,EAAQ,gCAAkC,MAElE,aAAMD,EAAa,MAAM,QAAQ,SAAS,CACxC,GAAIE,EACJ,KAAMD,EAAQ,YACd,QAASA,EAAQ,QACjB,KAAMA,EAAQ,KACd,KAAMA,EAAQ,KACd,MAAO,CACL,KAAM,GAAGA,EAAQ,WAAW,UAC5B,KAAM,UAAUA,EAAQ,OAAO,IAAI,OAAOA,EAAQ,IAAI,CAAC,GAAGE,CAAU,GACpE,SAAUC,EACV,QAASC,EACT,+BAAgCC,CAClC,CACF,CAAC,EAEMJ,CACT,CAEA,eAAsBK,EACpBP,EACAE,EACe,CACf,MAAMF,EAAa,MAAM,QAAQ,WAAWE,CAAS,CACvD","names":["Consul","createServiceClient","options","host","port","token","secure","registerService","consulClient","options","serviceId","healthPath","healthInterval","healthTimeout","deregisterAfter","deregisterService"]}
|
package/package.json
CHANGED