@hazeljs/discovery 0.2.0-beta.16 → 0.2.0-beta.18
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 +185 -19
- package/dist/__tests__/consul-backend.test.d.ts +6 -0
- package/dist/__tests__/consul-backend.test.d.ts.map +1 -0
- package/dist/__tests__/consul-backend.test.js +300 -0
- package/dist/__tests__/kubernetes-backend.test.d.ts +6 -0
- package/dist/__tests__/kubernetes-backend.test.d.ts.map +1 -0
- package/dist/__tests__/kubernetes-backend.test.js +261 -0
- package/dist/__tests__/redis-backend.test.d.ts +6 -0
- package/dist/__tests__/redis-backend.test.d.ts.map +1 -0
- package/dist/__tests__/redis-backend.test.js +280 -0
- package/dist/backends/consul-backend.d.ts +46 -7
- package/dist/backends/consul-backend.d.ts.map +1 -1
- package/dist/backends/consul-backend.js +23 -39
- package/dist/backends/kubernetes-backend.d.ts +44 -6
- package/dist/backends/kubernetes-backend.d.ts.map +1 -1
- package/dist/backends/kubernetes-backend.js +11 -32
- package/dist/backends/memory-backend.d.ts +0 -1
- package/dist/backends/memory-backend.d.ts.map +1 -1
- package/dist/backends/memory-backend.js +3 -32
- package/dist/backends/redis-backend.d.ts +11 -6
- package/dist/backends/redis-backend.d.ts.map +1 -1
- package/dist/backends/redis-backend.js +66 -46
- package/dist/client/discovery-client.d.ts +6 -4
- package/dist/client/discovery-client.d.ts.map +1 -1
- package/dist/client/discovery-client.js +30 -30
- package/dist/client/service-client.d.ts.map +1 -1
- package/dist/client/service-client.js +82 -17
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/registry/service-registry.d.ts.map +1 -1
- package/dist/registry/service-registry.js +13 -2
- package/dist/utils/filter.d.ts +10 -0
- package/dist/utils/filter.d.ts.map +1 -0
- package/dist/utils/filter.js +39 -0
- package/dist/utils/logger.d.ts +21 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +34 -0
- package/dist/utils/validation.d.ts +36 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +109 -0
- package/package.json +3 -3
|
@@ -7,10 +7,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.DiscoveryClient = void 0;
|
|
8
8
|
const memory_backend_1 = require("../backends/memory-backend");
|
|
9
9
|
const strategies_1 = require("../load-balancer/strategies");
|
|
10
|
+
const filter_1 = require("../utils/filter");
|
|
11
|
+
const logger_1 = require("../utils/logger");
|
|
12
|
+
const validation_1 = require("../utils/validation");
|
|
10
13
|
class DiscoveryClient {
|
|
11
14
|
constructor(config = {}, backend) {
|
|
12
15
|
this.config = config;
|
|
13
16
|
this.cache = new Map();
|
|
17
|
+
this.refreshIntervalHandle = null;
|
|
18
|
+
(0, validation_1.validateDiscoveryClientConfig)(config);
|
|
14
19
|
this.backend = backend || new memory_backend_1.MemoryRegistryBackend();
|
|
15
20
|
this.loadBalancerFactory = new strategies_1.LoadBalancerFactory();
|
|
16
21
|
if (config.refreshInterval) {
|
|
@@ -28,7 +33,7 @@ class DiscoveryClient {
|
|
|
28
33
|
const age = Date.now() - cached.timestamp;
|
|
29
34
|
const ttl = this.config.cacheTTL || 30000;
|
|
30
35
|
if (age < ttl) {
|
|
31
|
-
return
|
|
36
|
+
return (0, filter_1.applyServiceFilter)(cached.instances, filter);
|
|
32
37
|
}
|
|
33
38
|
}
|
|
34
39
|
}
|
|
@@ -83,41 +88,36 @@ class DiscoveryClient {
|
|
|
83
88
|
return this.loadBalancerFactory;
|
|
84
89
|
}
|
|
85
90
|
/**
|
|
86
|
-
*
|
|
91
|
+
* Close the discovery client and release all resources.
|
|
92
|
+
* Stops the cache refresh interval and clears the cache.
|
|
87
93
|
*/
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
instances,
|
|
95
|
-
timestamp: Date.now(),
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
}, this.config.refreshInterval);
|
|
94
|
+
close() {
|
|
95
|
+
if (this.refreshIntervalHandle) {
|
|
96
|
+
clearInterval(this.refreshIntervalHandle);
|
|
97
|
+
this.refreshIntervalHandle = null;
|
|
98
|
+
}
|
|
99
|
+
this.cache.clear();
|
|
99
100
|
}
|
|
100
101
|
/**
|
|
101
|
-
*
|
|
102
|
+
* Start cache refresh interval
|
|
102
103
|
*/
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
for (const [key, value] of Object.entries(filter.metadata)) {
|
|
115
|
-
if (instance.metadata?.[key] !== value)
|
|
116
|
-
return false;
|
|
104
|
+
startRefreshInterval() {
|
|
105
|
+
const logger = logger_1.DiscoveryLogger.getLogger();
|
|
106
|
+
this.refreshIntervalHandle = setInterval(async () => {
|
|
107
|
+
try {
|
|
108
|
+
const services = await this.getAllServices();
|
|
109
|
+
for (const service of services) {
|
|
110
|
+
const instances = await this.backend.getInstances(service);
|
|
111
|
+
this.cache.set(service, {
|
|
112
|
+
instances,
|
|
113
|
+
timestamp: Date.now(),
|
|
114
|
+
});
|
|
117
115
|
}
|
|
118
116
|
}
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
catch (error) {
|
|
118
|
+
logger.error('Failed to refresh service cache', error);
|
|
119
|
+
}
|
|
120
|
+
}, this.config.refreshInterval);
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
exports.DiscoveryClient = DiscoveryClient;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-client.d.ts","sourceRoot":"","sources":["../../src/client/service-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"service-client.d.ts","sourceRoot":"","sources":["../../src/client/service-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAIzC,OAAc,EAAiB,kBAAkB,EAAE,aAAa,EAAc,MAAM,OAAO,CAAC;AAE5F,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAqBD,qBAAa,aAAa;IAMtB,OAAO,CAAC,eAAe;IACvB,OAAO,CAAC,MAAM;IANhB,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;gBAGjB,eAAe,EAAE,eAAe,EAChC,MAAM,EAAE,mBAAmB;IAYrC;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAI5F;;OAEG;IACG,IAAI,CAAC,CAAC,GAAG,OAAO,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,MAAM,CAAC,EAAE,kBAAkB,GAC1B,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAI5B;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EACnB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,MAAM,CAAC,EAAE,kBAAkB,GAC1B,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAI5B;;OAEG;IACG,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAI/F;;OAEG;IACG,KAAK,CAAC,CAAC,GAAG,OAAO,EACrB,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,EACd,MAAM,CAAC,EAAE,kBAAkB,GAC1B,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAI5B;;OAEG;YACW,OAAO;IAgErB;;OAEG;IACH,OAAO,CAAC,KAAK;CAGd"}
|
|
@@ -3,18 +3,68 @@
|
|
|
3
3
|
* Service Client
|
|
4
4
|
* HTTP client with automatic service discovery and load balancing
|
|
5
5
|
*/
|
|
6
|
-
var
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
9
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
40
|
exports.ServiceClient = void 0;
|
|
11
|
-
const
|
|
41
|
+
const strategies_1 = require("../load-balancer/strategies");
|
|
42
|
+
const logger_1 = require("../utils/logger");
|
|
43
|
+
const validation_1 = require("../utils/validation");
|
|
44
|
+
const axios_1 = __importStar(require("axios"));
|
|
45
|
+
/** HTTP status codes that are safe to retry */
|
|
46
|
+
const RETRYABLE_STATUS_CODES = new Set([502, 503, 504, 408, 429]);
|
|
47
|
+
/**
|
|
48
|
+
* Determine whether an error is transient and worth retrying.
|
|
49
|
+
* Client errors (4xx except 408/429) are NOT retried.
|
|
50
|
+
*/
|
|
51
|
+
function isRetryableError(error) {
|
|
52
|
+
if (error instanceof axios_1.AxiosError) {
|
|
53
|
+
// Network / timeout errors are always retryable
|
|
54
|
+
if (!error.response)
|
|
55
|
+
return true;
|
|
56
|
+
return RETRYABLE_STATUS_CODES.has(error.response.status);
|
|
57
|
+
}
|
|
58
|
+
// Non-Axios errors (e.g. "no instances available") are retryable
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
12
61
|
class ServiceClient {
|
|
13
62
|
constructor(discoveryClient, config) {
|
|
14
63
|
this.discoveryClient = discoveryClient;
|
|
15
64
|
this.config = config;
|
|
16
|
-
|
|
17
|
-
this.
|
|
65
|
+
(0, validation_1.validateServiceClientConfig)(config);
|
|
66
|
+
this.retries = config.retries ?? 3;
|
|
67
|
+
this.retryDelay = config.retryDelay ?? 1000;
|
|
18
68
|
this.axiosInstance = axios_1.default.create({
|
|
19
69
|
timeout: config.timeout || 5000,
|
|
20
70
|
});
|
|
@@ -53,14 +103,23 @@ class ServiceClient {
|
|
|
53
103
|
* Generic request with service discovery
|
|
54
104
|
*/
|
|
55
105
|
async request(config) {
|
|
106
|
+
const logger = logger_1.DiscoveryLogger.getLogger();
|
|
56
107
|
let lastError = null;
|
|
57
108
|
for (let attempt = 0; attempt < this.retries; attempt++) {
|
|
109
|
+
// Discover service instance
|
|
110
|
+
const instance = await this.discoveryClient.getInstance(this.config.serviceName, this.config.loadBalancingStrategy, this.config.filter);
|
|
111
|
+
if (!instance) {
|
|
112
|
+
throw new Error(`No instances available for service: ${this.config.serviceName}`);
|
|
113
|
+
}
|
|
114
|
+
// Track active connections for least-connections strategy
|
|
115
|
+
const lbStrategy = this.discoveryClient
|
|
116
|
+
.getLoadBalancerFactory()
|
|
117
|
+
.get(this.config.loadBalancingStrategy || 'round-robin');
|
|
118
|
+
const isLeastConn = lbStrategy instanceof strategies_1.LeastConnectionsStrategy;
|
|
119
|
+
if (isLeastConn) {
|
|
120
|
+
lbStrategy.incrementConnections(instance.id);
|
|
121
|
+
}
|
|
58
122
|
try {
|
|
59
|
-
// Discover service instance
|
|
60
|
-
const instance = await this.discoveryClient.getInstance(this.config.serviceName, this.config.loadBalancingStrategy, this.config.filter);
|
|
61
|
-
if (!instance) {
|
|
62
|
-
throw new Error(`No instances available for service: ${this.config.serviceName}`);
|
|
63
|
-
}
|
|
64
123
|
// Build full URL
|
|
65
124
|
const baseURL = `${instance.protocol}://${instance.host}:${instance.port}`;
|
|
66
125
|
const fullConfig = {
|
|
@@ -68,20 +127,26 @@ class ServiceClient {
|
|
|
68
127
|
baseURL,
|
|
69
128
|
};
|
|
70
129
|
// Make request
|
|
71
|
-
|
|
130
|
+
const response = await this.axiosInstance.request(fullConfig);
|
|
131
|
+
return response;
|
|
72
132
|
}
|
|
73
133
|
catch (error) {
|
|
74
134
|
lastError = error;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
135
|
+
logger.warn(`Request to ${this.config.serviceName} failed (attempt ${attempt + 1}/${this.retries})`, error);
|
|
136
|
+
// Only retry on transient / network errors
|
|
137
|
+
if (!isRetryableError(error)) {
|
|
138
|
+
throw error;
|
|
79
139
|
}
|
|
80
|
-
// Wait before retry
|
|
140
|
+
// Wait before retry (skip delay on last attempt since we'll throw)
|
|
81
141
|
if (attempt < this.retries - 1) {
|
|
82
142
|
await this.sleep(this.retryDelay);
|
|
83
143
|
}
|
|
84
144
|
}
|
|
145
|
+
finally {
|
|
146
|
+
if (isLeastConn) {
|
|
147
|
+
lbStrategy.decrementConnections(instance.id);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
85
150
|
}
|
|
86
151
|
throw lastError || new Error('Request failed after all retries');
|
|
87
152
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,9 +10,12 @@ export * from './load-balancer/strategies';
|
|
|
10
10
|
export { RegistryBackend } from './backends/registry-backend';
|
|
11
11
|
export { MemoryRegistryBackend } from './backends/memory-backend';
|
|
12
12
|
export { RedisRegistryBackend, RedisBackendConfig } from './backends/redis-backend';
|
|
13
|
-
export { ConsulRegistryBackend, ConsulBackendConfig } from './backends/consul-backend';
|
|
13
|
+
export { ConsulRegistryBackend, ConsulBackendConfig, ConsulClient, } from './backends/consul-backend';
|
|
14
14
|
export { KubernetesRegistryBackend, KubernetesBackendConfig } from './backends/kubernetes-backend';
|
|
15
15
|
export { ServiceRegistry as ServiceRegistryDecorator } from './decorators/service-registry.decorator';
|
|
16
16
|
export { getServiceRegistryMetadata } from './decorators/service-registry.decorator';
|
|
17
17
|
export * from './decorators/inject-service-client.decorator';
|
|
18
|
+
export { applyServiceFilter } from './utils/filter';
|
|
19
|
+
export { DiscoveryLogger, Logger } from './utils/logger';
|
|
20
|
+
export { ConfigValidationError } from './utils/validation';
|
|
18
21
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,cAAc,SAAS,CAAC;AAGxB,cAAc,6BAA6B,CAAC;AAG5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AAGxC,cAAc,4BAA4B,CAAC;AAG3C,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACpF,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,cAAc,SAAS,CAAC;AAGxB,cAAc,6BAA6B,CAAC;AAG5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AAGxC,cAAc,4BAA4B,CAAC;AAG3C,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACpF,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,YAAY,GACb,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAGnG,OAAO,EAAE,eAAe,IAAI,wBAAwB,EAAE,MAAM,yCAAyC,CAAC;AACtG,OAAO,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAC;AACrF,cAAc,8CAA8C,CAAC;AAG7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -18,7 +18,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
18
18
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
19
19
|
};
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.getServiceRegistryMetadata = exports.ServiceRegistryDecorator = exports.KubernetesRegistryBackend = exports.ConsulRegistryBackend = exports.RedisRegistryBackend = exports.MemoryRegistryBackend = void 0;
|
|
21
|
+
exports.ConfigValidationError = exports.DiscoveryLogger = exports.applyServiceFilter = exports.getServiceRegistryMetadata = exports.ServiceRegistryDecorator = exports.KubernetesRegistryBackend = exports.ConsulRegistryBackend = exports.RedisRegistryBackend = exports.MemoryRegistryBackend = void 0;
|
|
22
22
|
// Types
|
|
23
23
|
__exportStar(require("./types"), exports);
|
|
24
24
|
// Registry
|
|
@@ -42,3 +42,10 @@ Object.defineProperty(exports, "ServiceRegistryDecorator", { enumerable: true, g
|
|
|
42
42
|
var service_registry_decorator_2 = require("./decorators/service-registry.decorator");
|
|
43
43
|
Object.defineProperty(exports, "getServiceRegistryMetadata", { enumerable: true, get: function () { return service_registry_decorator_2.getServiceRegistryMetadata; } });
|
|
44
44
|
__exportStar(require("./decorators/inject-service-client.decorator"), exports);
|
|
45
|
+
// Utilities
|
|
46
|
+
var filter_1 = require("./utils/filter");
|
|
47
|
+
Object.defineProperty(exports, "applyServiceFilter", { enumerable: true, get: function () { return filter_1.applyServiceFilter; } });
|
|
48
|
+
var logger_1 = require("./utils/logger");
|
|
49
|
+
Object.defineProperty(exports, "DiscoveryLogger", { enumerable: true, get: function () { return logger_1.DiscoveryLogger; } });
|
|
50
|
+
var validation_1 = require("./utils/validation");
|
|
51
|
+
Object.defineProperty(exports, "ConfigValidationError", { enumerable: true, get: function () { return validation_1.ConfigValidationError; } });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-registry.d.ts","sourceRoot":"","sources":["../../src/registry/service-registry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAiB,MAAM,UAAU,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"service-registry.d.ts","sourceRoot":"","sources":["../../src/registry/service-registry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAiB,MAAM,UAAU,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAM/D,qBAAa,eAAe;IAOxB,OAAO,CAAC,MAAM;IANhB,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,eAAe,CAA+B;gBAG5C,MAAM,EAAE,qBAAqB,EACrC,OAAO,CAAC,EAAE,eAAe;IAO3B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAgC/B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBjC;;OAEG;IACH,WAAW,IAAI,eAAe,GAAG,IAAI;IAIrC;;OAEG;IACH,UAAU,IAAI,eAAe;IAI7B;;OAEG;IACH,OAAO,CAAC,cAAc;IAYtB;;OAEG;IACH,OAAO,CAAC,YAAY;IAWpB;;OAEG;YACW,kBAAkB;IA0BhC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAI1B;;OAEG;IACH,OAAO,CAAC,UAAU;CAgBnB"}
|
|
@@ -10,6 +10,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.ServiceRegistry = void 0;
|
|
11
11
|
const types_1 = require("../types");
|
|
12
12
|
const memory_backend_1 = require("../backends/memory-backend");
|
|
13
|
+
const logger_1 = require("../utils/logger");
|
|
14
|
+
const validation_1 = require("../utils/validation");
|
|
13
15
|
const axios_1 = __importDefault(require("axios"));
|
|
14
16
|
class ServiceRegistry {
|
|
15
17
|
constructor(config, backend) {
|
|
@@ -17,6 +19,7 @@ class ServiceRegistry {
|
|
|
17
19
|
this.instance = null;
|
|
18
20
|
this.heartbeatInterval = null;
|
|
19
21
|
this.cleanupInterval = null;
|
|
22
|
+
(0, validation_1.validateServiceRegistryConfig)(config);
|
|
20
23
|
this.backend = backend || new memory_backend_1.MemoryRegistryBackend();
|
|
21
24
|
}
|
|
22
25
|
/**
|
|
@@ -95,7 +98,13 @@ class ServiceRegistry {
|
|
|
95
98
|
*/
|
|
96
99
|
startCleanup() {
|
|
97
100
|
this.cleanupInterval = setInterval(async () => {
|
|
98
|
-
|
|
101
|
+
try {
|
|
102
|
+
await this.backend.cleanup();
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
const logger = logger_1.DiscoveryLogger.getLogger();
|
|
106
|
+
logger.error('Cleanup task failed', error);
|
|
107
|
+
}
|
|
99
108
|
}, 60000); // Run every minute
|
|
100
109
|
}
|
|
101
110
|
/**
|
|
@@ -104,6 +113,7 @@ class ServiceRegistry {
|
|
|
104
113
|
async performHealthCheck() {
|
|
105
114
|
if (!this.instance)
|
|
106
115
|
return;
|
|
116
|
+
const logger = logger_1.DiscoveryLogger.getLogger();
|
|
107
117
|
try {
|
|
108
118
|
const url = `${this.instance.protocol}://${this.instance.host}:${this.instance.port}${this.instance.healthCheckPath}`;
|
|
109
119
|
const response = await axios_1.default.get(url, { timeout: 5000 });
|
|
@@ -116,9 +126,10 @@ class ServiceRegistry {
|
|
|
116
126
|
await this.backend.updateStatus(this.instance.id, types_1.ServiceStatus.DOWN);
|
|
117
127
|
}
|
|
118
128
|
}
|
|
119
|
-
catch {
|
|
129
|
+
catch (error) {
|
|
120
130
|
this.instance.status = types_1.ServiceStatus.DOWN;
|
|
121
131
|
await this.backend.updateStatus(this.instance.id, types_1.ServiceStatus.DOWN);
|
|
132
|
+
logger.warn(`Health check failed for ${this.instance.name} (${this.instance.id}), marking as DOWN`, error);
|
|
122
133
|
}
|
|
123
134
|
}
|
|
124
135
|
/**
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared filter utility for service instances
|
|
3
|
+
*/
|
|
4
|
+
import { ServiceInstance, ServiceFilter } from '../types';
|
|
5
|
+
/**
|
|
6
|
+
* Apply a ServiceFilter to an array of ServiceInstances.
|
|
7
|
+
* Returns only instances matching all specified filter criteria.
|
|
8
|
+
*/
|
|
9
|
+
export declare function applyServiceFilter(instances: ServiceInstance[], filter?: ServiceFilter): ServiceInstance[];
|
|
10
|
+
//# sourceMappingURL=filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../src/utils/filter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE1D;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,eAAe,EAAE,EAC5B,MAAM,CAAC,EAAE,aAAa,GACrB,eAAe,EAAE,CAgCnB"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared filter utility for service instances
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.applyServiceFilter = applyServiceFilter;
|
|
7
|
+
/**
|
|
8
|
+
* Apply a ServiceFilter to an array of ServiceInstances.
|
|
9
|
+
* Returns only instances matching all specified filter criteria.
|
|
10
|
+
*/
|
|
11
|
+
function applyServiceFilter(instances, filter) {
|
|
12
|
+
if (!filter)
|
|
13
|
+
return instances;
|
|
14
|
+
return instances.filter((instance) => {
|
|
15
|
+
// Filter by zone
|
|
16
|
+
if (filter.zone && instance.zone !== filter.zone) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
// Filter by status
|
|
20
|
+
if (filter.status && instance.status !== filter.status) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
// Filter by tags
|
|
24
|
+
if (filter.tags && filter.tags.length > 0) {
|
|
25
|
+
if (!instance.tags || !filter.tags.every((tag) => instance.tags.includes(tag))) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Filter by metadata
|
|
30
|
+
if (filter.metadata) {
|
|
31
|
+
for (const [key, value] of Object.entries(filter.metadata)) {
|
|
32
|
+
if (!instance.metadata || instance.metadata[key] !== value) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return true;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pluggable logger for @hazeljs/discovery
|
|
3
|
+
*
|
|
4
|
+
* Consumers can supply their own logger via DiscoveryLogger.setLogger().
|
|
5
|
+
* The default logger writes to the console.
|
|
6
|
+
*/
|
|
7
|
+
export interface Logger {
|
|
8
|
+
debug(message: string, ...args: unknown[]): void;
|
|
9
|
+
info(message: string, ...args: unknown[]): void;
|
|
10
|
+
warn(message: string, ...args: unknown[]): void;
|
|
11
|
+
error(message: string, ...args: unknown[]): void;
|
|
12
|
+
}
|
|
13
|
+
export declare const DiscoveryLogger: {
|
|
14
|
+
/** Replace the default console logger with a custom implementation */
|
|
15
|
+
setLogger(logger: Logger): void;
|
|
16
|
+
/** Reset to the default console logger */
|
|
17
|
+
resetLogger(): void;
|
|
18
|
+
/** Get the current logger instance */
|
|
19
|
+
getLogger(): Logger;
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACjD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CAClD;AAeD,eAAO,MAAM,eAAe;IAC1B,sEAAsE;sBACpD,MAAM,GAAG,IAAI;IAI/B,0CAA0C;mBAC3B,IAAI;IAInB,sCAAsC;iBACzB,MAAM;CAGpB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Pluggable logger for @hazeljs/discovery
|
|
4
|
+
*
|
|
5
|
+
* Consumers can supply their own logger via DiscoveryLogger.setLogger().
|
|
6
|
+
* The default logger writes to the console.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.DiscoveryLogger = void 0;
|
|
10
|
+
const defaultLogger = {
|
|
11
|
+
// eslint-disable-next-line no-console
|
|
12
|
+
debug: (msg, ...args) => console.debug(`[discovery] ${msg}`, ...args),
|
|
13
|
+
// eslint-disable-next-line no-console
|
|
14
|
+
info: (msg, ...args) => console.info(`[discovery] ${msg}`, ...args),
|
|
15
|
+
// eslint-disable-next-line no-console
|
|
16
|
+
warn: (msg, ...args) => console.warn(`[discovery] ${msg}`, ...args),
|
|
17
|
+
// eslint-disable-next-line no-console
|
|
18
|
+
error: (msg, ...args) => console.error(`[discovery] ${msg}`, ...args),
|
|
19
|
+
};
|
|
20
|
+
let currentLogger = defaultLogger;
|
|
21
|
+
exports.DiscoveryLogger = {
|
|
22
|
+
/** Replace the default console logger with a custom implementation */
|
|
23
|
+
setLogger(logger) {
|
|
24
|
+
currentLogger = logger;
|
|
25
|
+
},
|
|
26
|
+
/** Reset to the default console logger */
|
|
27
|
+
resetLogger() {
|
|
28
|
+
currentLogger = defaultLogger;
|
|
29
|
+
},
|
|
30
|
+
/** Get the current logger instance */
|
|
31
|
+
getLogger() {
|
|
32
|
+
return currentLogger;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime validation utilities for discovery configuration objects
|
|
3
|
+
*/
|
|
4
|
+
import { ServiceRegistryConfig, DiscoveryClientConfig } from '../types';
|
|
5
|
+
import { RedisBackendConfig } from '../backends/redis-backend';
|
|
6
|
+
import { ConsulBackendConfig } from '../backends/consul-backend';
|
|
7
|
+
import { KubernetesBackendConfig } from '../backends/kubernetes-backend';
|
|
8
|
+
import { ServiceClientConfig } from '../client/service-client';
|
|
9
|
+
export declare class ConfigValidationError extends Error {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Validate ServiceRegistryConfig at runtime
|
|
14
|
+
*/
|
|
15
|
+
export declare function validateServiceRegistryConfig(config: ServiceRegistryConfig): void;
|
|
16
|
+
/**
|
|
17
|
+
* Validate DiscoveryClientConfig at runtime
|
|
18
|
+
*/
|
|
19
|
+
export declare function validateDiscoveryClientConfig(config: DiscoveryClientConfig): void;
|
|
20
|
+
/**
|
|
21
|
+
* Validate ServiceClientConfig at runtime
|
|
22
|
+
*/
|
|
23
|
+
export declare function validateServiceClientConfig(config: ServiceClientConfig): void;
|
|
24
|
+
/**
|
|
25
|
+
* Validate RedisBackendConfig at runtime
|
|
26
|
+
*/
|
|
27
|
+
export declare function validateRedisBackendConfig(config: RedisBackendConfig): void;
|
|
28
|
+
/**
|
|
29
|
+
* Validate ConsulBackendConfig at runtime
|
|
30
|
+
*/
|
|
31
|
+
export declare function validateConsulBackendConfig(config: ConsulBackendConfig): void;
|
|
32
|
+
/**
|
|
33
|
+
* Validate KubernetesBackendConfig at runtime
|
|
34
|
+
*/
|
|
35
|
+
export declare function validateKubernetesBackendConfig(config: KubernetesBackendConfig): void;
|
|
36
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,qBAAqB,GAAG,IAAI,CAgCjF;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,qBAAqB,GAAG,IAAI,CAejF;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAkC7E;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAe3E;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAkB7E;AAED;;GAEG;AACH,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,uBAAuB,GAAG,IAAI,CASrF"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Runtime validation utilities for discovery configuration objects
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ConfigValidationError = void 0;
|
|
7
|
+
exports.validateServiceRegistryConfig = validateServiceRegistryConfig;
|
|
8
|
+
exports.validateDiscoveryClientConfig = validateDiscoveryClientConfig;
|
|
9
|
+
exports.validateServiceClientConfig = validateServiceClientConfig;
|
|
10
|
+
exports.validateRedisBackendConfig = validateRedisBackendConfig;
|
|
11
|
+
exports.validateConsulBackendConfig = validateConsulBackendConfig;
|
|
12
|
+
exports.validateKubernetesBackendConfig = validateKubernetesBackendConfig;
|
|
13
|
+
class ConfigValidationError extends Error {
|
|
14
|
+
constructor(message) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = 'ConfigValidationError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.ConfigValidationError = ConfigValidationError;
|
|
20
|
+
/**
|
|
21
|
+
* Validate ServiceRegistryConfig at runtime
|
|
22
|
+
*/
|
|
23
|
+
function validateServiceRegistryConfig(config) {
|
|
24
|
+
if (!config.name || typeof config.name !== 'string' || config.name.trim().length === 0) {
|
|
25
|
+
throw new ConfigValidationError('ServiceRegistryConfig: "name" is required and must be a non-empty string');
|
|
26
|
+
}
|
|
27
|
+
if (config.port == null ||
|
|
28
|
+
typeof config.port !== 'number' ||
|
|
29
|
+
config.port < 0 ||
|
|
30
|
+
config.port > 65535) {
|
|
31
|
+
throw new ConfigValidationError('ServiceRegistryConfig: "port" is required and must be a number between 0 and 65535');
|
|
32
|
+
}
|
|
33
|
+
if (config.healthCheckInterval != null &&
|
|
34
|
+
(typeof config.healthCheckInterval !== 'number' || config.healthCheckInterval <= 0)) {
|
|
35
|
+
throw new ConfigValidationError('ServiceRegistryConfig: "healthCheckInterval" must be a positive number (ms)');
|
|
36
|
+
}
|
|
37
|
+
if (config.protocol && !['http', 'https', 'grpc'].includes(config.protocol)) {
|
|
38
|
+
throw new ConfigValidationError('ServiceRegistryConfig: "protocol" must be one of "http", "https", "grpc"');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Validate DiscoveryClientConfig at runtime
|
|
43
|
+
*/
|
|
44
|
+
function validateDiscoveryClientConfig(config) {
|
|
45
|
+
if (config.cacheTTL != null && (typeof config.cacheTTL !== 'number' || config.cacheTTL <= 0)) {
|
|
46
|
+
throw new ConfigValidationError('DiscoveryClientConfig: "cacheTTL" must be a positive number (ms)');
|
|
47
|
+
}
|
|
48
|
+
if (config.refreshInterval != null &&
|
|
49
|
+
(typeof config.refreshInterval !== 'number' || config.refreshInterval <= 0)) {
|
|
50
|
+
throw new ConfigValidationError('DiscoveryClientConfig: "refreshInterval" must be a positive number (ms)');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Validate ServiceClientConfig at runtime
|
|
55
|
+
*/
|
|
56
|
+
function validateServiceClientConfig(config) {
|
|
57
|
+
if (!config.serviceName ||
|
|
58
|
+
typeof config.serviceName !== 'string' ||
|
|
59
|
+
config.serviceName.trim().length === 0) {
|
|
60
|
+
throw new ConfigValidationError('ServiceClientConfig: "serviceName" is required and must be a non-empty string');
|
|
61
|
+
}
|
|
62
|
+
if (config.timeout != null && (typeof config.timeout !== 'number' || config.timeout <= 0)) {
|
|
63
|
+
throw new ConfigValidationError('ServiceClientConfig: "timeout" must be a positive number (ms)');
|
|
64
|
+
}
|
|
65
|
+
if (config.retries != null &&
|
|
66
|
+
(typeof config.retries !== 'number' || config.retries < 0 || !Number.isInteger(config.retries))) {
|
|
67
|
+
throw new ConfigValidationError('ServiceClientConfig: "retries" must be a non-negative integer');
|
|
68
|
+
}
|
|
69
|
+
if (config.retryDelay != null &&
|
|
70
|
+
(typeof config.retryDelay !== 'number' || config.retryDelay < 0)) {
|
|
71
|
+
throw new ConfigValidationError('ServiceClientConfig: "retryDelay" must be a non-negative number (ms)');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Validate RedisBackendConfig at runtime
|
|
76
|
+
*/
|
|
77
|
+
function validateRedisBackendConfig(config) {
|
|
78
|
+
if (config.ttl != null && (typeof config.ttl !== 'number' || config.ttl <= 0)) {
|
|
79
|
+
throw new ConfigValidationError('RedisBackendConfig: "ttl" must be a positive number (seconds)');
|
|
80
|
+
}
|
|
81
|
+
if (config.port != null &&
|
|
82
|
+
(typeof config.port !== 'number' || config.port < 0 || config.port > 65535)) {
|
|
83
|
+
throw new ConfigValidationError('RedisBackendConfig: "port" must be a number between 0 and 65535');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Validate ConsulBackendConfig at runtime
|
|
88
|
+
*/
|
|
89
|
+
function validateConsulBackendConfig(config) {
|
|
90
|
+
if (config.ttl != null && typeof config.ttl === 'string') {
|
|
91
|
+
const match = config.ttl.match(/^(\d+)([smh])$/);
|
|
92
|
+
if (!match) {
|
|
93
|
+
throw new ConfigValidationError('ConsulBackendConfig: "ttl" must match format like "30s", "5m", or "1h"');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (config.port != null &&
|
|
97
|
+
(typeof config.port !== 'number' || config.port < 0 || config.port > 65535)) {
|
|
98
|
+
throw new ConfigValidationError('ConsulBackendConfig: "port" must be a number between 0 and 65535');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Validate KubernetesBackendConfig at runtime
|
|
103
|
+
*/
|
|
104
|
+
function validateKubernetesBackendConfig(config) {
|
|
105
|
+
if (config.namespace != null &&
|
|
106
|
+
(typeof config.namespace !== 'string' || config.namespace.trim().length === 0)) {
|
|
107
|
+
throw new ConfigValidationError('KubernetesBackendConfig: "namespace" must be a non-empty string');
|
|
108
|
+
}
|
|
109
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hazeljs/discovery",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.18",
|
|
4
4
|
"description": "Service discovery and registry for HazelJS microservices - Eureka-inspired with multiple backend support",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"clean": "rm -rf dist"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@hazeljs/core": "^0.2.0-beta.
|
|
21
|
+
"@hazeljs/core": "^0.2.0-beta.18",
|
|
22
22
|
"axios": "^1.6.0",
|
|
23
23
|
"reflect-metadata": "^0.2.2"
|
|
24
24
|
},
|
|
@@ -75,5 +75,5 @@
|
|
|
75
75
|
"url": "https://github.com/hazeljs/hazel-js/issues"
|
|
76
76
|
},
|
|
77
77
|
"homepage": "https://hazeljs.com",
|
|
78
|
-
"gitHead": "
|
|
78
|
+
"gitHead": "22082c1277661421cd32b3c4371c2c9d0bdf0501"
|
|
79
79
|
}
|