@hazeljs/discovery 0.2.0-beta.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 +281 -0
- package/dist/__tests__/decorators.test.d.ts +5 -0
- package/dist/__tests__/decorators.test.d.ts.map +1 -0
- package/dist/__tests__/decorators.test.js +72 -0
- package/dist/__tests__/discovery-client.test.d.ts +5 -0
- package/dist/__tests__/discovery-client.test.d.ts.map +1 -0
- package/dist/__tests__/discovery-client.test.js +142 -0
- package/dist/__tests__/load-balancer-strategies.test.d.ts +5 -0
- package/dist/__tests__/load-balancer-strategies.test.d.ts.map +1 -0
- package/dist/__tests__/load-balancer-strategies.test.js +234 -0
- package/dist/__tests__/memory-backend.test.d.ts +5 -0
- package/dist/__tests__/memory-backend.test.d.ts.map +1 -0
- package/dist/__tests__/memory-backend.test.js +246 -0
- package/dist/__tests__/service-client.test.d.ts +5 -0
- package/dist/__tests__/service-client.test.d.ts.map +1 -0
- package/dist/__tests__/service-client.test.js +215 -0
- package/dist/__tests__/service-registry.test.d.ts +5 -0
- package/dist/__tests__/service-registry.test.d.ts.map +1 -0
- package/dist/__tests__/service-registry.test.js +65 -0
- package/dist/backends/consul-backend.d.ts +76 -0
- package/dist/backends/consul-backend.d.ts.map +1 -0
- package/dist/backends/consul-backend.js +275 -0
- package/dist/backends/kubernetes-backend.d.ts +65 -0
- package/dist/backends/kubernetes-backend.d.ts.map +1 -0
- package/dist/backends/kubernetes-backend.js +174 -0
- package/dist/backends/memory-backend.d.ts +22 -0
- package/dist/backends/memory-backend.d.ts.map +1 -0
- package/dist/backends/memory-backend.js +115 -0
- package/dist/backends/redis-backend.d.ts +71 -0
- package/dist/backends/redis-backend.d.ts.map +1 -0
- package/dist/backends/redis-backend.js +200 -0
- package/dist/backends/registry-backend.d.ts +39 -0
- package/dist/backends/registry-backend.d.ts.map +1 -0
- package/dist/backends/registry-backend.js +5 -0
- package/dist/client/discovery-client.d.ts +47 -0
- package/dist/client/discovery-client.d.ts.map +1 -0
- package/dist/client/discovery-client.js +123 -0
- package/dist/client/service-client.d.ts +52 -0
- package/dist/client/service-client.d.ts.map +1 -0
- package/dist/client/service-client.js +95 -0
- package/dist/decorators/inject-service-client.decorator.d.ts +16 -0
- package/dist/decorators/inject-service-client.decorator.d.ts.map +1 -0
- package/dist/decorators/inject-service-client.decorator.js +24 -0
- package/dist/decorators/service-registry.decorator.d.ts +11 -0
- package/dist/decorators/service-registry.decorator.d.ts.map +1 -0
- package/dist/decorators/service-registry.decorator.js +20 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/load-balancer/strategies.d.ts +82 -0
- package/dist/load-balancer/strategies.d.ts.map +1 -0
- package/dist/load-balancer/strategies.js +209 -0
- package/dist/registry/service-registry.d.ts +51 -0
- package/dist/registry/service-registry.d.ts.map +1 -0
- package/dist/registry/service-registry.js +148 -0
- package/dist/types/index.d.ts +61 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +14 -0
- package/package.json +78 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Registry Backend Interface
|
|
3
|
+
*/
|
|
4
|
+
import { ServiceInstance, ServiceFilter } from '../types';
|
|
5
|
+
export interface RegistryBackend {
|
|
6
|
+
/**
|
|
7
|
+
* Register a service instance
|
|
8
|
+
*/
|
|
9
|
+
register(instance: ServiceInstance): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* Deregister a service instance
|
|
12
|
+
*/
|
|
13
|
+
deregister(instanceId: string): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Update service instance heartbeat
|
|
16
|
+
*/
|
|
17
|
+
heartbeat(instanceId: string): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Get all instances of a service
|
|
20
|
+
*/
|
|
21
|
+
getInstances(serviceName: string, filter?: ServiceFilter): Promise<ServiceInstance[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Get a specific service instance
|
|
24
|
+
*/
|
|
25
|
+
getInstance(instanceId: string): Promise<ServiceInstance | null>;
|
|
26
|
+
/**
|
|
27
|
+
* Get all registered services
|
|
28
|
+
*/
|
|
29
|
+
getAllServices(): Promise<string[]>;
|
|
30
|
+
/**
|
|
31
|
+
* Update service instance status
|
|
32
|
+
*/
|
|
33
|
+
updateStatus(instanceId: string, status: string): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Clean up expired instances
|
|
36
|
+
*/
|
|
37
|
+
cleanup(): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=registry-backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-backend.d.ts","sourceRoot":"","sources":["../../src/backends/registry-backend.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE1D,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnD;;OAEG;IACH,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C;;OAEG;IACH,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7C;;OAEG;IACH,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IAEtF;;OAEG;IACH,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAEjE;;OAEG;IACH,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAEpC;;OAEG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhE;;OAEG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discovery Client
|
|
3
|
+
* Discovers and retrieves service instances
|
|
4
|
+
*/
|
|
5
|
+
import { ServiceInstance, DiscoveryClientConfig, ServiceFilter } from '../types';
|
|
6
|
+
import { RegistryBackend } from '../backends/registry-backend';
|
|
7
|
+
import { LoadBalancerFactory } from '../load-balancer/strategies';
|
|
8
|
+
export declare class DiscoveryClient {
|
|
9
|
+
private config;
|
|
10
|
+
private backend;
|
|
11
|
+
private cache;
|
|
12
|
+
private loadBalancerFactory;
|
|
13
|
+
constructor(config?: DiscoveryClientConfig, backend?: RegistryBackend);
|
|
14
|
+
/**
|
|
15
|
+
* Get all instances of a service
|
|
16
|
+
*/
|
|
17
|
+
getInstances(serviceName: string, filter?: ServiceFilter): Promise<ServiceInstance[]>;
|
|
18
|
+
/**
|
|
19
|
+
* Get a single instance using load balancing
|
|
20
|
+
*/
|
|
21
|
+
getInstance(serviceName: string, strategy?: string, filter?: ServiceFilter): Promise<ServiceInstance | null>;
|
|
22
|
+
/**
|
|
23
|
+
* Get all registered service names
|
|
24
|
+
*/
|
|
25
|
+
getAllServices(): Promise<string[]>;
|
|
26
|
+
/**
|
|
27
|
+
* Clear cache for a specific service or all services
|
|
28
|
+
*/
|
|
29
|
+
clearCache(serviceName?: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Get the backend
|
|
32
|
+
*/
|
|
33
|
+
getBackend(): RegistryBackend;
|
|
34
|
+
/**
|
|
35
|
+
* Get load balancer factory
|
|
36
|
+
*/
|
|
37
|
+
getLoadBalancerFactory(): LoadBalancerFactory;
|
|
38
|
+
/**
|
|
39
|
+
* Start cache refresh interval
|
|
40
|
+
*/
|
|
41
|
+
private startRefreshInterval;
|
|
42
|
+
/**
|
|
43
|
+
* Apply filter to instances
|
|
44
|
+
*/
|
|
45
|
+
private applyFilter;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=discovery-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery-client.d.ts","sourceRoot":"","sources":["../../src/client/discovery-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE,qBAAa,eAAe;IAMxB,OAAO,CAAC,MAAM;IALhB,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,KAAK,CAA0E;IACvF,OAAO,CAAC,mBAAmB,CAAsB;gBAGvC,MAAM,GAAE,qBAA0B,EAC1C,OAAO,CAAC,EAAE,eAAe;IAU3B;;OAEG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA2B3F;;OAEG;IACG,WAAW,CACf,WAAW,EAAE,MAAM,EACnB,QAAQ,GAAE,MAAsB,EAChC,MAAM,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAQlC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIzC;;OAEG;IACH,UAAU,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAQtC;;OAEG;IACH,UAAU,IAAI,eAAe;IAI7B;;OAEG;IACH,sBAAsB,IAAI,mBAAmB;IAI7C;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAa5B;;OAEG;IACH,OAAO,CAAC,WAAW;CAepB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Discovery Client
|
|
4
|
+
* Discovers and retrieves service instances
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.DiscoveryClient = void 0;
|
|
8
|
+
const memory_backend_1 = require("../backends/memory-backend");
|
|
9
|
+
const strategies_1 = require("../load-balancer/strategies");
|
|
10
|
+
class DiscoveryClient {
|
|
11
|
+
constructor(config = {}, backend) {
|
|
12
|
+
this.config = config;
|
|
13
|
+
this.cache = new Map();
|
|
14
|
+
this.backend = backend || new memory_backend_1.MemoryRegistryBackend();
|
|
15
|
+
this.loadBalancerFactory = new strategies_1.LoadBalancerFactory();
|
|
16
|
+
if (config.refreshInterval) {
|
|
17
|
+
this.startRefreshInterval();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get all instances of a service
|
|
22
|
+
*/
|
|
23
|
+
async getInstances(serviceName, filter) {
|
|
24
|
+
// Check cache first
|
|
25
|
+
if (this.config.cacheEnabled) {
|
|
26
|
+
const cached = this.cache.get(serviceName);
|
|
27
|
+
if (cached) {
|
|
28
|
+
const age = Date.now() - cached.timestamp;
|
|
29
|
+
const ttl = this.config.cacheTTL || 30000;
|
|
30
|
+
if (age < ttl) {
|
|
31
|
+
return this.applyFilter(cached.instances, filter);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Fetch from backend
|
|
36
|
+
const instances = await this.backend.getInstances(serviceName, filter);
|
|
37
|
+
// Update cache
|
|
38
|
+
if (this.config.cacheEnabled) {
|
|
39
|
+
this.cache.set(serviceName, {
|
|
40
|
+
instances,
|
|
41
|
+
timestamp: Date.now(),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return instances;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get a single instance using load balancing
|
|
48
|
+
*/
|
|
49
|
+
async getInstance(serviceName, strategy = 'round-robin', filter) {
|
|
50
|
+
const instances = await this.getInstances(serviceName, filter);
|
|
51
|
+
if (instances.length === 0)
|
|
52
|
+
return null;
|
|
53
|
+
const loadBalancer = this.loadBalancerFactory.create(strategy);
|
|
54
|
+
return loadBalancer.choose(instances);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get all registered service names
|
|
58
|
+
*/
|
|
59
|
+
async getAllServices() {
|
|
60
|
+
return this.backend.getAllServices();
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Clear cache for a specific service or all services
|
|
64
|
+
*/
|
|
65
|
+
clearCache(serviceName) {
|
|
66
|
+
if (serviceName) {
|
|
67
|
+
this.cache.delete(serviceName);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
this.cache.clear();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get the backend
|
|
75
|
+
*/
|
|
76
|
+
getBackend() {
|
|
77
|
+
return this.backend;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get load balancer factory
|
|
81
|
+
*/
|
|
82
|
+
getLoadBalancerFactory() {
|
|
83
|
+
return this.loadBalancerFactory;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Start cache refresh interval
|
|
87
|
+
*/
|
|
88
|
+
startRefreshInterval() {
|
|
89
|
+
setInterval(async () => {
|
|
90
|
+
const services = await this.getAllServices();
|
|
91
|
+
for (const service of services) {
|
|
92
|
+
const instances = await this.backend.getInstances(service);
|
|
93
|
+
this.cache.set(service, {
|
|
94
|
+
instances,
|
|
95
|
+
timestamp: Date.now(),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}, this.config.refreshInterval);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Apply filter to instances
|
|
102
|
+
*/
|
|
103
|
+
applyFilter(instances, filter) {
|
|
104
|
+
if (!filter)
|
|
105
|
+
return instances;
|
|
106
|
+
return instances.filter((instance) => {
|
|
107
|
+
if (filter.zone && instance.zone !== filter.zone)
|
|
108
|
+
return false;
|
|
109
|
+
if (filter.status && instance.status !== filter.status)
|
|
110
|
+
return false;
|
|
111
|
+
if (filter.tags && !filter.tags.every((tag) => instance.tags?.includes(tag)))
|
|
112
|
+
return false;
|
|
113
|
+
if (filter.metadata) {
|
|
114
|
+
for (const [key, value] of Object.entries(filter.metadata)) {
|
|
115
|
+
if (instance.metadata?.[key] !== value)
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return true;
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
exports.DiscoveryClient = DiscoveryClient;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Client
|
|
3
|
+
* HTTP client with automatic service discovery and load balancing
|
|
4
|
+
*/
|
|
5
|
+
import { DiscoveryClient } from './discovery-client';
|
|
6
|
+
import { ServiceFilter } from '../types';
|
|
7
|
+
import { AxiosRequestConfig, AxiosResponse } from 'axios';
|
|
8
|
+
export interface ServiceClientConfig {
|
|
9
|
+
serviceName: string;
|
|
10
|
+
loadBalancingStrategy?: string;
|
|
11
|
+
filter?: ServiceFilter;
|
|
12
|
+
timeout?: number;
|
|
13
|
+
retries?: number;
|
|
14
|
+
retryDelay?: number;
|
|
15
|
+
}
|
|
16
|
+
export declare class ServiceClient {
|
|
17
|
+
private discoveryClient;
|
|
18
|
+
private config;
|
|
19
|
+
private axiosInstance;
|
|
20
|
+
private retries;
|
|
21
|
+
private retryDelay;
|
|
22
|
+
constructor(discoveryClient: DiscoveryClient, config: ServiceClientConfig);
|
|
23
|
+
/**
|
|
24
|
+
* GET request
|
|
25
|
+
*/
|
|
26
|
+
get<T = unknown>(path: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
27
|
+
/**
|
|
28
|
+
* POST request
|
|
29
|
+
*/
|
|
30
|
+
post<T = unknown>(path: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
31
|
+
/**
|
|
32
|
+
* PUT request
|
|
33
|
+
*/
|
|
34
|
+
put<T = unknown>(path: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
35
|
+
/**
|
|
36
|
+
* DELETE request
|
|
37
|
+
*/
|
|
38
|
+
delete<T = unknown>(path: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
39
|
+
/**
|
|
40
|
+
* PATCH request
|
|
41
|
+
*/
|
|
42
|
+
patch<T = unknown>(path: string, data?: unknown, config?: AxiosRequestConfig): Promise<AxiosResponse<T>>;
|
|
43
|
+
/**
|
|
44
|
+
* Generic request with service discovery
|
|
45
|
+
*/
|
|
46
|
+
private request;
|
|
47
|
+
/**
|
|
48
|
+
* Sleep utility
|
|
49
|
+
*/
|
|
50
|
+
private sleep;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=service-client.d.ts.map
|
|
@@ -0,0 +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;AACzC,OAAc,EAAiB,kBAAkB,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAEhF,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;AAED,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;IAUrC;;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;IA2CrB;;OAEG;IACH,OAAO,CAAC,KAAK;CAGd"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Service Client
|
|
4
|
+
* HTTP client with automatic service discovery and load balancing
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.ServiceClient = void 0;
|
|
11
|
+
const axios_1 = __importDefault(require("axios"));
|
|
12
|
+
class ServiceClient {
|
|
13
|
+
constructor(discoveryClient, config) {
|
|
14
|
+
this.discoveryClient = discoveryClient;
|
|
15
|
+
this.config = config;
|
|
16
|
+
this.retries = config.retries || 3;
|
|
17
|
+
this.retryDelay = config.retryDelay || 1000;
|
|
18
|
+
this.axiosInstance = axios_1.default.create({
|
|
19
|
+
timeout: config.timeout || 5000,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* GET request
|
|
24
|
+
*/
|
|
25
|
+
async get(path, config) {
|
|
26
|
+
return this.request({ ...config, method: 'GET', url: path });
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* POST request
|
|
30
|
+
*/
|
|
31
|
+
async post(path, data, config) {
|
|
32
|
+
return this.request({ ...config, method: 'POST', url: path, data });
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* PUT request
|
|
36
|
+
*/
|
|
37
|
+
async put(path, data, config) {
|
|
38
|
+
return this.request({ ...config, method: 'PUT', url: path, data });
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* DELETE request
|
|
42
|
+
*/
|
|
43
|
+
async delete(path, config) {
|
|
44
|
+
return this.request({ ...config, method: 'DELETE', url: path });
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* PATCH request
|
|
48
|
+
*/
|
|
49
|
+
async patch(path, data, config) {
|
|
50
|
+
return this.request({ ...config, method: 'PATCH', url: path, data });
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Generic request with service discovery
|
|
54
|
+
*/
|
|
55
|
+
async request(config) {
|
|
56
|
+
let lastError = null;
|
|
57
|
+
for (let attempt = 0; attempt < this.retries; attempt++) {
|
|
58
|
+
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
|
+
// Build full URL
|
|
65
|
+
const baseURL = `${instance.protocol}://${instance.host}:${instance.port}`;
|
|
66
|
+
const fullConfig = {
|
|
67
|
+
...config,
|
|
68
|
+
baseURL,
|
|
69
|
+
};
|
|
70
|
+
// Make request
|
|
71
|
+
return await this.axiosInstance.request(fullConfig);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
lastError = error;
|
|
75
|
+
// Log error only in development
|
|
76
|
+
if (process.env.NODE_ENV === 'development') {
|
|
77
|
+
// eslint-disable-next-line no-console
|
|
78
|
+
console.error(`Request failed (attempt ${attempt + 1}/${this.retries}):`, error);
|
|
79
|
+
}
|
|
80
|
+
// Wait before retry
|
|
81
|
+
if (attempt < this.retries - 1) {
|
|
82
|
+
await this.sleep(this.retryDelay);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
throw lastError || new Error('Request failed after all retries');
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Sleep utility
|
|
90
|
+
*/
|
|
91
|
+
sleep(ms) {
|
|
92
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.ServiceClient = ServiceClient;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InjectServiceClient Decorator
|
|
3
|
+
* Injects a service client for a specific service
|
|
4
|
+
*/
|
|
5
|
+
import 'reflect-metadata';
|
|
6
|
+
type NewableFunction = new (...args: unknown[]) => unknown;
|
|
7
|
+
export interface InjectServiceClientOptions {
|
|
8
|
+
serviceName: string;
|
|
9
|
+
loadBalancingStrategy?: string;
|
|
10
|
+
timeout?: number;
|
|
11
|
+
retries?: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function InjectServiceClient(serviceName: string, options?: Omit<InjectServiceClientOptions, 'serviceName'>): ParameterDecorator;
|
|
14
|
+
export declare function getInjectServiceClientMetadata(target: NewableFunction): InjectServiceClientOptions[] | undefined;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=inject-service-client.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inject-service-client.decorator.d.ts","sourceRoot":"","sources":["../../src/decorators/inject-service-client.decorator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,kBAAkB,CAAC;AAE1B,KAAK,eAAe,GAAG,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;AAI3D,MAAM,WAAW,0BAA0B;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,IAAI,CAAC,0BAA0B,EAAE,aAAa,CAAC,GACxD,kBAAkB,CAkBpB;AAED,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,eAAe,GACtB,0BAA0B,EAAE,GAAG,SAAS,CAE1C"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* InjectServiceClient Decorator
|
|
4
|
+
* Injects a service client for a specific service
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.InjectServiceClient = InjectServiceClient;
|
|
8
|
+
exports.getInjectServiceClientMetadata = getInjectServiceClientMetadata;
|
|
9
|
+
require("reflect-metadata");
|
|
10
|
+
const INJECT_SERVICE_CLIENT_METADATA = 'hazeljs:inject-service-client';
|
|
11
|
+
function InjectServiceClient(serviceName, options) {
|
|
12
|
+
return function (target, propertyKey, parameterIndex) {
|
|
13
|
+
const config = {
|
|
14
|
+
serviceName,
|
|
15
|
+
...options,
|
|
16
|
+
};
|
|
17
|
+
const existingParams = Reflect.getMetadata(INJECT_SERVICE_CLIENT_METADATA, target) || [];
|
|
18
|
+
existingParams[parameterIndex] = config;
|
|
19
|
+
Reflect.defineMetadata(INJECT_SERVICE_CLIENT_METADATA, existingParams, target);
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function getInjectServiceClientMetadata(target) {
|
|
23
|
+
return Reflect.getMetadata(INJECT_SERVICE_CLIENT_METADATA, target);
|
|
24
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Registry Decorator
|
|
3
|
+
* Automatically registers a service on module initialization
|
|
4
|
+
*/
|
|
5
|
+
import 'reflect-metadata';
|
|
6
|
+
import { ServiceRegistryConfig } from '../types';
|
|
7
|
+
type NewableFunction = new (...args: unknown[]) => unknown;
|
|
8
|
+
export declare function ServiceRegistry(config: ServiceRegistryConfig): ClassDecorator;
|
|
9
|
+
export declare function getServiceRegistryMetadata(target: NewableFunction): ServiceRegistryConfig | undefined;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=service-registry.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-registry.decorator.d.ts","sourceRoot":"","sources":["../../src/decorators/service-registry.decorator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEjD,KAAK,eAAe,GAAG,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;AAI3D,wBAAgB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,cAAc,CAM7E;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,eAAe,GACtB,qBAAqB,GAAG,SAAS,CAEnC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Service Registry Decorator
|
|
4
|
+
* Automatically registers a service on module initialization
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.ServiceRegistry = ServiceRegistry;
|
|
8
|
+
exports.getServiceRegistryMetadata = getServiceRegistryMetadata;
|
|
9
|
+
require("reflect-metadata");
|
|
10
|
+
const SERVICE_REGISTRY_METADATA = 'hazeljs:service-registry';
|
|
11
|
+
function ServiceRegistry(config) {
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
13
|
+
return function (target) {
|
|
14
|
+
Reflect.defineMetadata(SERVICE_REGISTRY_METADATA, config, target);
|
|
15
|
+
return target;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function getServiceRegistryMetadata(target) {
|
|
19
|
+
return Reflect.getMetadata(SERVICE_REGISTRY_METADATA, target);
|
|
20
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hazeljs/discovery
|
|
3
|
+
* Service Discovery and Registry for HazelJS Microservices
|
|
4
|
+
*/
|
|
5
|
+
export * from './types';
|
|
6
|
+
export * from './registry/service-registry';
|
|
7
|
+
export * from './client/discovery-client';
|
|
8
|
+
export * from './client/service-client';
|
|
9
|
+
export * from './load-balancer/strategies';
|
|
10
|
+
export { RegistryBackend } from './backends/registry-backend';
|
|
11
|
+
export { MemoryRegistryBackend } from './backends/memory-backend';
|
|
12
|
+
export { RedisRegistryBackend, RedisBackendConfig } from './backends/redis-backend';
|
|
13
|
+
export { ConsulRegistryBackend, ConsulBackendConfig } from './backends/consul-backend';
|
|
14
|
+
export { KubernetesRegistryBackend, KubernetesBackendConfig } from './backends/kubernetes-backend';
|
|
15
|
+
export { ServiceRegistry as ServiceRegistryDecorator } from './decorators/service-registry.decorator';
|
|
16
|
+
export { getServiceRegistryMetadata } from './decorators/service-registry.decorator';
|
|
17
|
+
export * from './decorators/inject-service-client.decorator';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACvF,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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @hazeljs/discovery
|
|
4
|
+
* Service Discovery and Registry for HazelJS Microservices
|
|
5
|
+
*/
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
18
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.getServiceRegistryMetadata = exports.ServiceRegistryDecorator = exports.KubernetesRegistryBackend = exports.ConsulRegistryBackend = exports.RedisRegistryBackend = exports.MemoryRegistryBackend = void 0;
|
|
22
|
+
// Types
|
|
23
|
+
__exportStar(require("./types"), exports);
|
|
24
|
+
// Registry
|
|
25
|
+
__exportStar(require("./registry/service-registry"), exports);
|
|
26
|
+
// Client
|
|
27
|
+
__exportStar(require("./client/discovery-client"), exports);
|
|
28
|
+
__exportStar(require("./client/service-client"), exports);
|
|
29
|
+
// Load Balancer
|
|
30
|
+
__exportStar(require("./load-balancer/strategies"), exports);
|
|
31
|
+
var memory_backend_1 = require("./backends/memory-backend");
|
|
32
|
+
Object.defineProperty(exports, "MemoryRegistryBackend", { enumerable: true, get: function () { return memory_backend_1.MemoryRegistryBackend; } });
|
|
33
|
+
var redis_backend_1 = require("./backends/redis-backend");
|
|
34
|
+
Object.defineProperty(exports, "RedisRegistryBackend", { enumerable: true, get: function () { return redis_backend_1.RedisRegistryBackend; } });
|
|
35
|
+
var consul_backend_1 = require("./backends/consul-backend");
|
|
36
|
+
Object.defineProperty(exports, "ConsulRegistryBackend", { enumerable: true, get: function () { return consul_backend_1.ConsulRegistryBackend; } });
|
|
37
|
+
var kubernetes_backend_1 = require("./backends/kubernetes-backend");
|
|
38
|
+
Object.defineProperty(exports, "KubernetesRegistryBackend", { enumerable: true, get: function () { return kubernetes_backend_1.KubernetesRegistryBackend; } });
|
|
39
|
+
// Decorators
|
|
40
|
+
var service_registry_decorator_1 = require("./decorators/service-registry.decorator");
|
|
41
|
+
Object.defineProperty(exports, "ServiceRegistryDecorator", { enumerable: true, get: function () { return service_registry_decorator_1.ServiceRegistry; } });
|
|
42
|
+
var service_registry_decorator_2 = require("./decorators/service-registry.decorator");
|
|
43
|
+
Object.defineProperty(exports, "getServiceRegistryMetadata", { enumerable: true, get: function () { return service_registry_decorator_2.getServiceRegistryMetadata; } });
|
|
44
|
+
__exportStar(require("./decorators/inject-service-client.decorator"), exports);
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load Balancing Strategies
|
|
3
|
+
*/
|
|
4
|
+
import { ServiceInstance, LoadBalancerStrategy } from '../types';
|
|
5
|
+
/**
|
|
6
|
+
* Base strategy that filters healthy instances
|
|
7
|
+
*/
|
|
8
|
+
declare abstract class BaseStrategy implements LoadBalancerStrategy {
|
|
9
|
+
abstract name: string;
|
|
10
|
+
protected filterHealthy(instances: ServiceInstance[]): ServiceInstance[];
|
|
11
|
+
abstract choose(instances: ServiceInstance[]): ServiceInstance | null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Round Robin Strategy
|
|
15
|
+
*/
|
|
16
|
+
export declare class RoundRobinStrategy extends BaseStrategy {
|
|
17
|
+
name: string;
|
|
18
|
+
private currentIndex;
|
|
19
|
+
choose(instances: ServiceInstance[]): ServiceInstance | null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Random Strategy
|
|
23
|
+
*/
|
|
24
|
+
export declare class RandomStrategy extends BaseStrategy {
|
|
25
|
+
name: string;
|
|
26
|
+
choose(instances: ServiceInstance[]): ServiceInstance | null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Least Connections Strategy
|
|
30
|
+
* Tracks active connections per instance
|
|
31
|
+
*/
|
|
32
|
+
export declare class LeastConnectionsStrategy extends BaseStrategy {
|
|
33
|
+
name: string;
|
|
34
|
+
private connections;
|
|
35
|
+
choose(instances: ServiceInstance[]): ServiceInstance | null;
|
|
36
|
+
incrementConnections(instanceId: string): void;
|
|
37
|
+
decrementConnections(instanceId: string): void;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Weighted Round Robin Strategy
|
|
41
|
+
* Uses metadata.weight for weighted selection
|
|
42
|
+
*/
|
|
43
|
+
export declare class WeightedRoundRobinStrategy extends BaseStrategy {
|
|
44
|
+
name: string;
|
|
45
|
+
private currentIndex;
|
|
46
|
+
private currentWeight;
|
|
47
|
+
choose(instances: ServiceInstance[]): ServiceInstance | null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* IP Hash Strategy
|
|
51
|
+
* Consistent hashing based on client IP
|
|
52
|
+
*/
|
|
53
|
+
export declare class IPHashStrategy extends BaseStrategy {
|
|
54
|
+
name: string;
|
|
55
|
+
choose(instances: ServiceInstance[], clientIP?: string): ServiceInstance | null;
|
|
56
|
+
private hashCode;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Zone Aware Strategy
|
|
60
|
+
* Prefers instances in the same zone
|
|
61
|
+
*/
|
|
62
|
+
export declare class ZoneAwareStrategy extends BaseStrategy {
|
|
63
|
+
private preferredZone?;
|
|
64
|
+
name: string;
|
|
65
|
+
constructor(preferredZone?: string | undefined);
|
|
66
|
+
choose(instances: ServiceInstance[]): ServiceInstance | null;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Load Balancer Factory
|
|
70
|
+
*/
|
|
71
|
+
export declare class LoadBalancerFactory {
|
|
72
|
+
private strategies;
|
|
73
|
+
constructor();
|
|
74
|
+
private registerDefaultStrategies;
|
|
75
|
+
register(strategy: LoadBalancerStrategy): void;
|
|
76
|
+
get(name: string): LoadBalancerStrategy | undefined;
|
|
77
|
+
create(name: string, options?: {
|
|
78
|
+
zone?: string;
|
|
79
|
+
}): LoadBalancerStrategy;
|
|
80
|
+
}
|
|
81
|
+
export {};
|
|
82
|
+
//# sourceMappingURL=strategies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strategies.d.ts","sourceRoot":"","sources":["../../src/load-balancer/strategies.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAiB,MAAM,UAAU,CAAC;AAEhF;;GAEG;AACH,uBAAe,YAAa,YAAW,oBAAoB;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,SAAS,CAAC,aAAa,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,eAAe,EAAE;IAIxE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,eAAe,GAAG,IAAI;CACtE;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,YAAY;IAClD,IAAI,SAAiB;IACrB,OAAO,CAAC,YAAY,CAAK;IAEzB,MAAM,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,eAAe,GAAG,IAAI;CAQ7D;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAC9C,IAAI,SAAY;IAEhB,MAAM,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,eAAe,GAAG,IAAI;CAO7D;AAED;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,YAAY;IACxD,IAAI,SAAuB;IAC3B,OAAO,CAAC,WAAW,CAA6B;IAEhD,MAAM,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,eAAe,GAAG,IAAI;IAmB5D,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAK9C,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;CAI/C;AAED;;;GAGG;AACH,qBAAa,0BAA2B,SAAQ,YAAY;IAC1D,IAAI,SAA0B;IAC9B,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,aAAa,CAAK;IAE1B,MAAM,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,eAAe,GAAG,IAAI;CAoB7D;AAED;;;GAGG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAC9C,IAAI,SAAa;IAEjB,MAAM,CAAC,SAAS,EAAE,eAAe,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI;IAW/E,OAAO,CAAC,QAAQ;CASjB;AAED;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,YAAY;IAGrC,OAAO,CAAC,aAAa,CAAC;IAFlC,IAAI,SAAgB;gBAEA,aAAa,CAAC,EAAE,MAAM,YAAA;IAI1C,MAAM,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,eAAe,GAAG,IAAI;CAe7D;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,UAAU,CAA2C;;IAM7D,OAAO,CAAC,yBAAyB;IAQjC,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI;IAI9C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS;IAInD,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,oBAAoB;CAWxE"}
|