@hazeljs/discovery 0.2.0-alpha.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.
Files changed (78) hide show
  1. package/LICENSE +192 -0
  2. package/README.md +450 -0
  3. package/dist/__tests__/consul-backend.test.d.ts +6 -0
  4. package/dist/__tests__/consul-backend.test.d.ts.map +1 -0
  5. package/dist/__tests__/consul-backend.test.js +300 -0
  6. package/dist/__tests__/decorators.test.d.ts +5 -0
  7. package/dist/__tests__/decorators.test.d.ts.map +1 -0
  8. package/dist/__tests__/decorators.test.js +72 -0
  9. package/dist/__tests__/discovery-client.test.d.ts +5 -0
  10. package/dist/__tests__/discovery-client.test.d.ts.map +1 -0
  11. package/dist/__tests__/discovery-client.test.js +142 -0
  12. package/dist/__tests__/kubernetes-backend.test.d.ts +6 -0
  13. package/dist/__tests__/kubernetes-backend.test.d.ts.map +1 -0
  14. package/dist/__tests__/kubernetes-backend.test.js +261 -0
  15. package/dist/__tests__/load-balancer-strategies.test.d.ts +5 -0
  16. package/dist/__tests__/load-balancer-strategies.test.d.ts.map +1 -0
  17. package/dist/__tests__/load-balancer-strategies.test.js +234 -0
  18. package/dist/__tests__/memory-backend.test.d.ts +5 -0
  19. package/dist/__tests__/memory-backend.test.d.ts.map +1 -0
  20. package/dist/__tests__/memory-backend.test.js +246 -0
  21. package/dist/__tests__/redis-backend.test.d.ts +6 -0
  22. package/dist/__tests__/redis-backend.test.d.ts.map +1 -0
  23. package/dist/__tests__/redis-backend.test.js +280 -0
  24. package/dist/__tests__/service-client.test.d.ts +5 -0
  25. package/dist/__tests__/service-client.test.d.ts.map +1 -0
  26. package/dist/__tests__/service-client.test.js +216 -0
  27. package/dist/__tests__/service-registry.test.d.ts +5 -0
  28. package/dist/__tests__/service-registry.test.d.ts.map +1 -0
  29. package/dist/__tests__/service-registry.test.js +65 -0
  30. package/dist/backends/consul-backend.d.ts +115 -0
  31. package/dist/backends/consul-backend.d.ts.map +1 -0
  32. package/dist/backends/consul-backend.js +259 -0
  33. package/dist/backends/kubernetes-backend.d.ts +103 -0
  34. package/dist/backends/kubernetes-backend.d.ts.map +1 -0
  35. package/dist/backends/kubernetes-backend.js +153 -0
  36. package/dist/backends/memory-backend.d.ts +21 -0
  37. package/dist/backends/memory-backend.d.ts.map +1 -0
  38. package/dist/backends/memory-backend.js +86 -0
  39. package/dist/backends/redis-backend.d.ts +76 -0
  40. package/dist/backends/redis-backend.d.ts.map +1 -0
  41. package/dist/backends/redis-backend.js +220 -0
  42. package/dist/backends/registry-backend.d.ts +39 -0
  43. package/dist/backends/registry-backend.d.ts.map +1 -0
  44. package/dist/backends/registry-backend.js +5 -0
  45. package/dist/client/discovery-client.d.ts +49 -0
  46. package/dist/client/discovery-client.d.ts.map +1 -0
  47. package/dist/client/discovery-client.js +123 -0
  48. package/dist/client/service-client.d.ts +48 -0
  49. package/dist/client/service-client.d.ts.map +1 -0
  50. package/dist/client/service-client.js +155 -0
  51. package/dist/decorators/inject-service-client.decorator.d.ts +16 -0
  52. package/dist/decorators/inject-service-client.decorator.d.ts.map +1 -0
  53. package/dist/decorators/inject-service-client.decorator.js +24 -0
  54. package/dist/decorators/service-registry.decorator.d.ts +11 -0
  55. package/dist/decorators/service-registry.decorator.d.ts.map +1 -0
  56. package/dist/decorators/service-registry.decorator.js +20 -0
  57. package/dist/index.d.ts +21 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +51 -0
  60. package/dist/load-balancer/strategies.d.ts +82 -0
  61. package/dist/load-balancer/strategies.d.ts.map +1 -0
  62. package/dist/load-balancer/strategies.js +209 -0
  63. package/dist/registry/service-registry.d.ts +51 -0
  64. package/dist/registry/service-registry.d.ts.map +1 -0
  65. package/dist/registry/service-registry.js +159 -0
  66. package/dist/types/index.d.ts +61 -0
  67. package/dist/types/index.d.ts.map +1 -0
  68. package/dist/types/index.js +14 -0
  69. package/dist/utils/filter.d.ts +10 -0
  70. package/dist/utils/filter.d.ts.map +1 -0
  71. package/dist/utils/filter.js +39 -0
  72. package/dist/utils/logger.d.ts +21 -0
  73. package/dist/utils/logger.d.ts.map +1 -0
  74. package/dist/utils/logger.js +34 -0
  75. package/dist/utils/validation.d.ts +36 -0
  76. package/dist/utils/validation.d.ts.map +1 -0
  77. package/dist/utils/validation.js +109 -0
  78. package/package.json +81 -0
@@ -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 ADDED
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "@hazeljs/discovery",
3
+ "version": "0.2.0-alpha.1",
4
+ "description": "Service discovery and registry for HazelJS microservices - Eureka-inspired with multiple backend support",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "test": "jest --coverage --passWithNoTests",
13
+ "test:ci": "jest --coverage --coverageReporters=text --coverageReporters=lcov --coverageReporters=clover --no-coverage-threshold",
14
+ "test:watch": "jest --watch",
15
+ "lint": "eslint \"src/**/*.ts\"",
16
+ "lint:fix": "eslint \"src/**/*.ts\" --fix",
17
+ "format": "prettier --write \"src/**/*.ts\"",
18
+ "clean": "rm -rf dist"
19
+ },
20
+ "dependencies": {
21
+ "@hazeljs/core": "^0.2.0-alpha.1",
22
+ "@hazeljs/resilience": "^0.2.0-alpha.1",
23
+ "axios": "^1.6.0",
24
+ "reflect-metadata": "^0.2.2"
25
+ },
26
+ "devDependencies": {
27
+ "@types/jest": "^29.5.14",
28
+ "@types/node": "^20.17.50",
29
+ "@typescript-eslint/eslint-plugin": "^8.18.2",
30
+ "@typescript-eslint/parser": "^8.18.2",
31
+ "eslint": "^8.56.0",
32
+ "eslint-config-prettier": "^9.1.0",
33
+ "eslint-plugin-prettier": "^5.1.3",
34
+ "jest": "^29.7.0",
35
+ "prettier": "^3.2.5",
36
+ "ts-jest": "^29.1.2",
37
+ "typescript": "^5.3.3"
38
+ },
39
+ "peerDependencies": {
40
+ "@hazeljs/core": ">=0.2.0-beta.0",
41
+ "@kubernetes/client-node": "^0.20.0",
42
+ "consul": "^1.2.0",
43
+ "ioredis": "^5.3.0"
44
+ },
45
+ "peerDependenciesMeta": {
46
+ "ioredis": {
47
+ "optional": true
48
+ },
49
+ "consul": {
50
+ "optional": true
51
+ },
52
+ "@kubernetes/client-node": {
53
+ "optional": true
54
+ }
55
+ },
56
+ "publishConfig": {
57
+ "access": "public"
58
+ },
59
+ "repository": {
60
+ "type": "git",
61
+ "url": "git+https://github.com/hazel-js/hazeljs.git",
62
+ "directory": "packages/discovery"
63
+ },
64
+ "keywords": [
65
+ "hazeljs",
66
+ "microservices",
67
+ "service-discovery",
68
+ "service-registry",
69
+ "load-balancing",
70
+ "eureka",
71
+ "consul",
72
+ "kubernetes"
73
+ ],
74
+ "author": "Muhammad Arslan <muhammad.arslan@hazeljs.com>",
75
+ "license": "Apache-2.0",
76
+ "bugs": {
77
+ "url": "https://github.com/hazeljs/hazel-js/issues"
78
+ },
79
+ "homepage": "https://hazeljs.com",
80
+ "gitHead": "cbc5ee2c12ced28fd0576faf13c5f078c1e8421e"
81
+ }