@naman_deep_singh/communication-core 1.0.0

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 (134) hide show
  1. package/README.md +345 -0
  2. package/dist/cjs/abstract/BaseCircuitBreaker.js +253 -0
  3. package/dist/cjs/abstract/BaseClient.js +298 -0
  4. package/dist/cjs/abstract/BaseCompressionManager.js +377 -0
  5. package/dist/cjs/abstract/BaseConnectionPool.js +543 -0
  6. package/dist/cjs/abstract/BaseInterceptor.js +235 -0
  7. package/dist/cjs/abstract/BaseLoadBalancer.js +269 -0
  8. package/dist/cjs/abstract/BaseProtocol.js +269 -0
  9. package/dist/cjs/abstract/BaseRetryStrategy.js +255 -0
  10. package/dist/cjs/abstract/BaseSerializer.js +341 -0
  11. package/dist/cjs/abstract/BaseServiceDiscoverer.js +254 -0
  12. package/dist/cjs/abstract/BaseTimeoutManager.js +295 -0
  13. package/dist/cjs/abstract/index.js +25 -0
  14. package/dist/cjs/errors/CircuitBreakerError.js +16 -0
  15. package/dist/cjs/errors/CommunicationError.js +15 -0
  16. package/dist/cjs/errors/ConnectionError.js +15 -0
  17. package/dist/cjs/errors/DiscoveryError.js +15 -0
  18. package/dist/cjs/errors/LoadBalancerError.js +15 -0
  19. package/dist/cjs/errors/ProtocolError.js +15 -0
  20. package/dist/cjs/errors/RetryError.js +16 -0
  21. package/dist/cjs/errors/SerializationError.js +15 -0
  22. package/dist/cjs/errors/ServiceUnavailableError.js +15 -0
  23. package/dist/cjs/errors/TimeoutError.js +16 -0
  24. package/dist/cjs/errors/communicationErrorCodes.js +35 -0
  25. package/dist/cjs/errors/index.js +31 -0
  26. package/dist/cjs/index.js +38 -0
  27. package/dist/cjs/interfaces/CircuitBreaker.interface.js +6 -0
  28. package/dist/cjs/interfaces/Client.interface.js +6 -0
  29. package/dist/cjs/interfaces/Compression.interface.js +6 -0
  30. package/dist/cjs/interfaces/ConnectionPool.interface.js +6 -0
  31. package/dist/cjs/interfaces/Interceptor.interface.js +6 -0
  32. package/dist/cjs/interfaces/LoadBalancer.interface.js +2 -0
  33. package/dist/cjs/interfaces/Protocol.interface.js +6 -0
  34. package/dist/cjs/interfaces/RetryStrategy.interface.js +6 -0
  35. package/dist/cjs/interfaces/Serializer.interface.js +2 -0
  36. package/dist/cjs/interfaces/ServiceDiscovery.interface.js +6 -0
  37. package/dist/cjs/interfaces/Timeout.interface.js +6 -0
  38. package/dist/cjs/interfaces/index.js +6 -0
  39. package/dist/cjs/types/config.js +6 -0
  40. package/dist/cjs/types/events.js +6 -0
  41. package/dist/cjs/types/index.js +6 -0
  42. package/dist/cjs/types/request.js +6 -0
  43. package/dist/cjs/types/response.js +6 -0
  44. package/dist/cjs/types/service.js +6 -0
  45. package/dist/cjs/utils.js +200 -0
  46. package/dist/esm/abstract/BaseCircuitBreaker.js +249 -0
  47. package/dist/esm/abstract/BaseClient.js +294 -0
  48. package/dist/esm/abstract/BaseCompressionManager.js +373 -0
  49. package/dist/esm/abstract/BaseConnectionPool.js +539 -0
  50. package/dist/esm/abstract/BaseInterceptor.js +231 -0
  51. package/dist/esm/abstract/BaseLoadBalancer.js +265 -0
  52. package/dist/esm/abstract/BaseProtocol.js +265 -0
  53. package/dist/esm/abstract/BaseRetryStrategy.js +251 -0
  54. package/dist/esm/abstract/BaseSerializer.js +337 -0
  55. package/dist/esm/abstract/BaseServiceDiscoverer.js +250 -0
  56. package/dist/esm/abstract/BaseTimeoutManager.js +291 -0
  57. package/dist/esm/abstract/index.js +11 -0
  58. package/dist/esm/errors/CircuitBreakerError.js +12 -0
  59. package/dist/esm/errors/CommunicationError.js +11 -0
  60. package/dist/esm/errors/ConnectionError.js +11 -0
  61. package/dist/esm/errors/DiscoveryError.js +11 -0
  62. package/dist/esm/errors/LoadBalancerError.js +11 -0
  63. package/dist/esm/errors/ProtocolError.js +11 -0
  64. package/dist/esm/errors/RetryError.js +12 -0
  65. package/dist/esm/errors/SerializationError.js +11 -0
  66. package/dist/esm/errors/ServiceUnavailableError.js +11 -0
  67. package/dist/esm/errors/TimeoutError.js +12 -0
  68. package/dist/esm/errors/communicationErrorCodes.js +32 -0
  69. package/dist/esm/errors/index.js +17 -0
  70. package/dist/esm/index.js +18 -0
  71. package/dist/esm/interfaces/CircuitBreaker.interface.js +5 -0
  72. package/dist/esm/interfaces/Client.interface.js +5 -0
  73. package/dist/esm/interfaces/Compression.interface.js +5 -0
  74. package/dist/esm/interfaces/ConnectionPool.interface.js +5 -0
  75. package/dist/esm/interfaces/Interceptor.interface.js +5 -0
  76. package/dist/esm/interfaces/LoadBalancer.interface.js +1 -0
  77. package/dist/esm/interfaces/Protocol.interface.js +5 -0
  78. package/dist/esm/interfaces/RetryStrategy.interface.js +5 -0
  79. package/dist/esm/interfaces/Serializer.interface.js +1 -0
  80. package/dist/esm/interfaces/ServiceDiscovery.interface.js +5 -0
  81. package/dist/esm/interfaces/Timeout.interface.js +5 -0
  82. package/dist/esm/interfaces/index.js +5 -0
  83. package/dist/esm/types/config.js +5 -0
  84. package/dist/esm/types/events.js +5 -0
  85. package/dist/esm/types/index.js +5 -0
  86. package/dist/esm/types/request.js +5 -0
  87. package/dist/esm/types/response.js +5 -0
  88. package/dist/esm/types/service.js +5 -0
  89. package/dist/esm/utils.js +193 -0
  90. package/dist/types/abstract/BaseCircuitBreaker.d.ts +167 -0
  91. package/dist/types/abstract/BaseClient.d.ts +197 -0
  92. package/dist/types/abstract/BaseCompressionManager.d.ts +180 -0
  93. package/dist/types/abstract/BaseConnectionPool.d.ts +210 -0
  94. package/dist/types/abstract/BaseInterceptor.d.ts +150 -0
  95. package/dist/types/abstract/BaseLoadBalancer.d.ts +167 -0
  96. package/dist/types/abstract/BaseProtocol.d.ts +163 -0
  97. package/dist/types/abstract/BaseRetryStrategy.d.ts +130 -0
  98. package/dist/types/abstract/BaseSerializer.d.ts +181 -0
  99. package/dist/types/abstract/BaseServiceDiscoverer.d.ts +161 -0
  100. package/dist/types/abstract/BaseTimeoutManager.d.ts +145 -0
  101. package/dist/types/abstract/index.d.ts +11 -0
  102. package/dist/types/errors/CircuitBreakerError.d.ts +8 -0
  103. package/dist/types/errors/CommunicationError.d.ts +10 -0
  104. package/dist/types/errors/ConnectionError.d.ts +9 -0
  105. package/dist/types/errors/DiscoveryError.d.ts +9 -0
  106. package/dist/types/errors/LoadBalancerError.d.ts +9 -0
  107. package/dist/types/errors/ProtocolError.d.ts +9 -0
  108. package/dist/types/errors/RetryError.d.ts +11 -0
  109. package/dist/types/errors/SerializationError.d.ts +9 -0
  110. package/dist/types/errors/ServiceUnavailableError.d.ts +12 -0
  111. package/dist/types/errors/TimeoutError.d.ts +11 -0
  112. package/dist/types/errors/communicationErrorCodes.d.ts +27 -0
  113. package/dist/types/errors/index.d.ts +11 -0
  114. package/dist/types/index.d.ts +13 -0
  115. package/dist/types/interfaces/CircuitBreaker.interface.d.ts +150 -0
  116. package/dist/types/interfaces/Client.interface.d.ts +153 -0
  117. package/dist/types/interfaces/Compression.interface.d.ts +190 -0
  118. package/dist/types/interfaces/ConnectionPool.interface.d.ts +191 -0
  119. package/dist/types/interfaces/Interceptor.interface.d.ts +220 -0
  120. package/dist/types/interfaces/LoadBalancer.interface.d.ts +153 -0
  121. package/dist/types/interfaces/Protocol.interface.d.ts +117 -0
  122. package/dist/types/interfaces/RetryStrategy.interface.d.ts +160 -0
  123. package/dist/types/interfaces/Serializer.interface.d.ts +176 -0
  124. package/dist/types/interfaces/ServiceDiscovery.interface.d.ts +189 -0
  125. package/dist/types/interfaces/Timeout.interface.d.ts +135 -0
  126. package/dist/types/interfaces/index.d.ts +15 -0
  127. package/dist/types/types/config.d.ts +540 -0
  128. package/dist/types/types/events.d.ts +204 -0
  129. package/dist/types/types/index.d.ts +9 -0
  130. package/dist/types/types/request.d.ts +143 -0
  131. package/dist/types/types/response.d.ts +155 -0
  132. package/dist/types/types/service.d.ts +279 -0
  133. package/dist/types/utils.d.ts +179 -0
  134. package/package.json +88 -0
@@ -0,0 +1,298 @@
1
+ "use strict";
2
+ /**
3
+ * Abstract base client implementation
4
+ * @packageDocumentation
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.BaseClient = void 0;
8
+ const CommunicationError_js_1 = require("../errors/CommunicationError.js");
9
+ const communicationErrorCodes_js_1 = require("../errors/communicationErrorCodes.js");
10
+ /**
11
+ * Abstract base client implementation
12
+ * Provides common functionality for all client implementations
13
+ */
14
+ class BaseClient {
15
+ /**
16
+ * Create a new base client instance
17
+ * @param serviceName Service name to communicate with
18
+ * @param config Client configuration
19
+ * @param protocol Protocol instance
20
+ */
21
+ constructor(serviceName, config, protocol) {
22
+ /** Client interceptors */
23
+ this.interceptors = [];
24
+ /** Cached service instances */
25
+ this.cachedInstances = [];
26
+ /** Client metrics */
27
+ this.metrics = {};
28
+ /** Client start time */
29
+ this.startTime = Date.now();
30
+ /** Total calls made */
31
+ this.totalCalls = 0;
32
+ /** Successful calls */
33
+ this.successfulCalls = 0;
34
+ /** Failed calls */
35
+ this.failedCalls = 0;
36
+ this.serviceName = serviceName;
37
+ this.config = { ...config };
38
+ this.protocol = protocol;
39
+ this.name = config.custom?.name || `client_${serviceName}_${Date.now()}`;
40
+ // Initialize components
41
+ this.initializeComponents();
42
+ }
43
+ /**
44
+ * Initialize client components
45
+ */
46
+ initializeComponents() {
47
+ // Can be overridden by subclasses to initialize
48
+ // serviceDiscoverer, loadBalancer, circuitBreaker, retryStrategy
49
+ }
50
+ /**
51
+ * Get service discovery instance
52
+ */
53
+ getServiceDiscoverer() {
54
+ return this.serviceDiscoverer;
55
+ }
56
+ /**
57
+ * Get load balancer instance
58
+ */
59
+ getLoadBalancer() {
60
+ return this.loadBalancer;
61
+ }
62
+ /**
63
+ * Get circuit breaker instance
64
+ */
65
+ getCircuitBreaker() {
66
+ return this.circuitBreaker;
67
+ }
68
+ /**
69
+ * Get retry strategy instance
70
+ */
71
+ getRetryStrategy() {
72
+ return this.retryStrategy;
73
+ }
74
+ /**
75
+ * Add an interceptor to the client
76
+ * @param interceptor IInterceptor to add
77
+ */
78
+ addInterceptor(interceptor) {
79
+ this.interceptors.push(interceptor);
80
+ interceptor.initialize?.({ client: this.name, service: this.serviceName });
81
+ this.onInterceptorAdded(interceptor);
82
+ }
83
+ /**
84
+ * Hook for interceptor addition
85
+ * @param interceptor Added interceptor
86
+ */
87
+ onInterceptorAdded(interceptor) {
88
+ // Can be overridden by subclasses
89
+ }
90
+ /**
91
+ * Remove an interceptor from the client
92
+ * @param interceptorId IInterceptor identifier
93
+ */
94
+ removeInterceptor(interceptorId) {
95
+ const index = this.interceptors.findIndex(i => i.name === interceptorId);
96
+ if (index !== -1) {
97
+ const interceptor = this.interceptors[index];
98
+ interceptor.cleanup?.();
99
+ this.interceptors.splice(index, 1);
100
+ this.onInterceptorRemoved(interceptorId);
101
+ }
102
+ }
103
+ /**
104
+ * Hook for interceptor removal
105
+ * @param interceptorId Removed interceptor ID
106
+ */
107
+ onInterceptorRemoved(interceptorId) {
108
+ // Can be overridden by subclasses
109
+ }
110
+ /**
111
+ * Get all interceptors
112
+ */
113
+ getInterceptors() {
114
+ return [...this.interceptors];
115
+ }
116
+ /**
117
+ * Clear all interceptors
118
+ */
119
+ clearInterceptors() {
120
+ for (const interceptor of this.interceptors) {
121
+ interceptor.cleanup?.();
122
+ }
123
+ this.interceptors = [];
124
+ this.onInterceptorsCleared();
125
+ }
126
+ /**
127
+ * Hook for interceptors cleared
128
+ */
129
+ onInterceptorsCleared() {
130
+ // Can be overridden by subclasses
131
+ }
132
+ /**
133
+ * Discover service instances
134
+ * @returns Promise resolving to service instances
135
+ */
136
+ async discoverService() {
137
+ if (!this.serviceDiscoverer) {
138
+ throw new CommunicationError_js_1.CommunicationError(communicationErrorCodes_js_1.COMMUNICATION_ERROR_CODES.DISCOVERY_ERROR, 503, {
139
+ message: 'Service discovery not configured',
140
+ service: this.serviceName,
141
+ });
142
+ }
143
+ const result = await this.serviceDiscoverer.resolve(this.serviceName);
144
+ this.cachedInstances = result.instances;
145
+ this.lastCacheRefresh = Date.now();
146
+ return this.cachedInstances;
147
+ }
148
+ /**
149
+ * Get current service instances (cached)
150
+ */
151
+ getServiceInstances() {
152
+ return [...this.cachedInstances];
153
+ }
154
+ /**
155
+ * Refresh service instances cache
156
+ */
157
+ async refreshServiceInstances() {
158
+ await this.discoverService();
159
+ }
160
+ /**
161
+ * Select a service instance using load balancer
162
+ * @param instances Available instances
163
+ * @returns Selected instance
164
+ */
165
+ selectInstance(instances) {
166
+ if (instances.length === 0) {
167
+ throw new CommunicationError_js_1.CommunicationError(communicationErrorCodes_js_1.COMMUNICATION_ERROR_CODES.NO_AVAILABLE_INSTANCES, 503, {
168
+ service: this.serviceName,
169
+ });
170
+ }
171
+ if (instances.length === 1) {
172
+ return instances[0];
173
+ }
174
+ if (this.loadBalancer) {
175
+ return this.loadBalancer.select(instances, {
176
+ service: this.serviceName,
177
+ client: this.name,
178
+ });
179
+ }
180
+ // Default: round-robin selection
181
+ const index = this.totalCalls % instances.length;
182
+ return instances[index];
183
+ }
184
+ /**
185
+ * Update client metrics
186
+ * @param success Whether call was successful
187
+ * @param duration Call duration in milliseconds
188
+ */
189
+ updateMetrics(success, duration) {
190
+ this.totalCalls++;
191
+ if (success) {
192
+ this.successfulCalls++;
193
+ }
194
+ else {
195
+ this.failedCalls++;
196
+ }
197
+ this.metrics = {
198
+ ...this.metrics,
199
+ totalCalls: this.totalCalls,
200
+ successfulCalls: this.successfulCalls,
201
+ failedCalls: this.failedCalls,
202
+ successRate: this.totalCalls > 0 ? this.successfulCalls / this.totalCalls : 0,
203
+ averageResponseTime: this.calculateAverageResponseTime(duration),
204
+ uptime: Date.now() - this.startTime,
205
+ cachedInstances: this.cachedInstances.length,
206
+ lastCacheRefresh: this.lastCacheRefresh,
207
+ };
208
+ }
209
+ /**
210
+ * Calculate average response time
211
+ * @param newDuration New call duration
212
+ * @returns Average response time
213
+ */
214
+ calculateAverageResponseTime(newDuration) {
215
+ const currentAverage = this.metrics.averageResponseTime || 0;
216
+ const totalDuration = currentAverage * (this.totalCalls - 1) + newDuration;
217
+ return totalDuration / this.totalCalls;
218
+ }
219
+ /**
220
+ * Health check for the client
221
+ * @returns Promise resolving to health status
222
+ */
223
+ async healthCheck() {
224
+ const checks = [];
225
+ // Check protocol health
226
+ const protocolHealth = await this.protocol.healthCheck?.() || { healthy: false };
227
+ checks.push({
228
+ component: 'protocol',
229
+ healthy: protocolHealth.healthy,
230
+ message: protocolHealth.message,
231
+ });
232
+ // Check service discovery health if configured
233
+ if (this.serviceDiscoverer) {
234
+ const discoveryHealth = await this.serviceDiscoverer.healthCheckSelf();
235
+ checks.push({
236
+ component: 'service-discovery',
237
+ healthy: discoveryHealth.healthy,
238
+ message: discoveryHealth.message,
239
+ });
240
+ }
241
+ // Check if we have service instances
242
+ const hasInstances = this.cachedInstances.length > 0;
243
+ checks.push({
244
+ component: 'service-instances',
245
+ healthy: hasInstances,
246
+ message: hasInstances ? `Has ${this.cachedInstances.length} instances` : 'No instances available',
247
+ });
248
+ const allHealthy = checks.every(check => check.healthy);
249
+ return {
250
+ healthy: allHealthy,
251
+ message: allHealthy ? 'Client is healthy' : 'Client has issues',
252
+ details: {
253
+ name: this.name,
254
+ service: this.serviceName,
255
+ checks,
256
+ metrics: this.metrics,
257
+ },
258
+ };
259
+ }
260
+ /**
261
+ * Get client metrics
262
+ */
263
+ getMetrics() {
264
+ return { ...this.metrics };
265
+ }
266
+ /**
267
+ * Reset client metrics
268
+ */
269
+ resetMetrics() {
270
+ this.totalCalls = 0;
271
+ this.successfulCalls = 0;
272
+ this.failedCalls = 0;
273
+ this.metrics = {
274
+ uptime: Date.now() - this.startTime,
275
+ };
276
+ }
277
+ /**
278
+ * Close/cleanup client resources
279
+ */
280
+ async close() {
281
+ // Clear interceptors
282
+ this.clearInterceptors();
283
+ // Close protocol
284
+ await this.protocol.disconnect?.();
285
+ // Close service discovery if configured
286
+ if (this.serviceDiscoverer) {
287
+ await this.serviceDiscoverer.close();
288
+ }
289
+ this.onClose();
290
+ }
291
+ /**
292
+ * Hook for client close
293
+ */
294
+ onClose() {
295
+ // Can be overridden by subclasses
296
+ }
297
+ }
298
+ exports.BaseClient = BaseClient;
@@ -0,0 +1,377 @@
1
+ "use strict";
2
+ /**
3
+ * Abstract base compression manager implementation
4
+ * @packageDocumentation
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.BaseCompressionManager = void 0;
8
+ const communicationErrorCodes_js_1 = require("../errors/communicationErrorCodes.js");
9
+ const SerializationError_js_1 = require("../errors/SerializationError.js");
10
+ /**
11
+ * Abstract base compression manager implementation
12
+ * Provides common functionality for compression management
13
+ */
14
+ class BaseCompressionManager {
15
+ /**
16
+ * Create a new base compression manager instance
17
+ * @param name Compression manager name
18
+ * @param config Compression configuration
19
+ */
20
+ constructor(name, config) {
21
+ /** Supported algorithms */
22
+ this.supportedAlgorithms = ['none'];
23
+ /** Compression statistics */
24
+ this.stats = {
25
+ totalCompressions: 0,
26
+ totalDecompressions: 0,
27
+ compressionErrors: 0,
28
+ decompressionErrors: 0,
29
+ totalCompressionTime: 0,
30
+ totalDecompressionTime: 0,
31
+ totalOriginalSize: 0,
32
+ totalCompressedSize: 0,
33
+ totalDecompressedSize: 0,
34
+ averageCompressionTime: 0,
35
+ averageDecompressionTime: 0,
36
+ averageCompressionRatio: 0,
37
+ algorithmUsage: {},
38
+ };
39
+ this.name = name;
40
+ this.config = { ...config };
41
+ this.initialize();
42
+ }
43
+ /**
44
+ * Initialize compression manager
45
+ */
46
+ initialize() {
47
+ // Detect supported algorithms
48
+ this.supportedAlgorithms.push(...this.detectSupportedAlgorithms());
49
+ }
50
+ /**
51
+ * Compress data
52
+ * @param data Data to compress
53
+ * @param options Compression options
54
+ * @returns Promise resolving to compression result
55
+ * @throws {CommunicationError} If compression fails
56
+ */
57
+ async compress(data, options) {
58
+ const result = await this.compressWithMetrics(data, options);
59
+ return result;
60
+ }
61
+ /**
62
+ * Compress data with detailed metrics
63
+ * @param data Data to compress
64
+ * @param options Compression options
65
+ * @returns Promise resolving to compression result with metrics
66
+ */
67
+ async compressWithMetrics(data, options) {
68
+ const startTime = Date.now();
69
+ const algorithm = options?.algorithm || this.config.algorithm || 'gzip';
70
+ const level = options?.level || this.config.level || 6;
71
+ // Convert string to buffer if needed
72
+ const inputBuffer = typeof data === 'string'
73
+ ? Buffer.from(data, 'utf8')
74
+ : Buffer.from(data);
75
+ const originalSize = inputBuffer.length;
76
+ // Check if we should compress
77
+ if (!this.shouldCompress(originalSize)) {
78
+ return {
79
+ data: inputBuffer,
80
+ originalSize,
81
+ compressedSize: originalSize,
82
+ compressionRatio: 1,
83
+ algorithm: 'none',
84
+ level: 0,
85
+ compressionTime: Date.now() - startTime,
86
+ };
87
+ }
88
+ // Check algorithm support
89
+ if (!this.isAlgorithmSupported(algorithm)) {
90
+ throw new SerializationError_js_1.SerializationError(communicationErrorCodes_js_1.COMMUNICATION_ERROR_CODES.SERIALIZATION_ERROR, {
91
+ message: `Compression algorithm not supported: ${algorithm}`,
92
+ algorithm,
93
+ supportedAlgorithms: this.supportedAlgorithms,
94
+ });
95
+ }
96
+ try {
97
+ const compressedData = await this.compressData(inputBuffer, algorithm, level);
98
+ const compressionTime = Date.now() - startTime;
99
+ const compressedSize = compressedData.length;
100
+ const compressionRatio = compressedSize / originalSize;
101
+ // Update statistics
102
+ this.updateCompressionStats(originalSize, compressedSize, compressionTime, algorithm);
103
+ return {
104
+ data: compressedData,
105
+ originalSize,
106
+ compressedSize,
107
+ compressionRatio,
108
+ algorithm,
109
+ level,
110
+ compressionTime,
111
+ };
112
+ }
113
+ catch (error) {
114
+ this.stats.compressionErrors++;
115
+ throw new SerializationError_js_1.SerializationError(communicationErrorCodes_js_1.COMMUNICATION_ERROR_CODES.SERIALIZATION_ERROR, {
116
+ message: `Compression failed: ${error instanceof Error ? error.message : String(error)}`,
117
+ algorithm,
118
+ level,
119
+ originalSize,
120
+ }, error instanceof Error ? error : undefined);
121
+ }
122
+ }
123
+ /**
124
+ * Decompress data
125
+ * @param data Data to decompress
126
+ * @param options Decompression options
127
+ * @returns Promise resolving to decompression result
128
+ * @throws {CommunicationError} If decompression fails
129
+ */
130
+ async decompress(data, options) {
131
+ const startTime = Date.now();
132
+ const algorithm = options?.algorithm || this.detectAlgorithm(data) || 'gzip';
133
+ // Check algorithm support
134
+ if (!this.isAlgorithmSupported(algorithm)) {
135
+ throw new SerializationError_js_1.SerializationError(communicationErrorCodes_js_1.COMMUNICATION_ERROR_CODES.DESERIALIZATION_ERROR, {
136
+ message: `Decompression algorithm not supported: ${algorithm}`,
137
+ algorithm,
138
+ supportedAlgorithms: this.supportedAlgorithms,
139
+ });
140
+ }
141
+ try {
142
+ const decompressedData = await this.decompressData(Buffer.from(data), algorithm);
143
+ const decompressionTime = Date.now() - startTime;
144
+ const originalSize = data.length;
145
+ const decompressedSize = decompressedData.length;
146
+ // Update statistics
147
+ this.updateDecompressionStats(originalSize, decompressedSize, decompressionTime, algorithm);
148
+ return {
149
+ data: decompressedData,
150
+ originalSize,
151
+ decompressedSize,
152
+ decompressionTime,
153
+ algorithm,
154
+ };
155
+ }
156
+ catch (error) {
157
+ this.stats.decompressionErrors++;
158
+ throw new SerializationError_js_1.SerializationError(communicationErrorCodes_js_1.COMMUNICATION_ERROR_CODES.DESERIALIZATION_ERROR, {
159
+ message: `Decompression failed: ${error instanceof Error ? error.message : String(error)}`,
160
+ algorithm,
161
+ originalSize: data.length,
162
+ }, error instanceof Error ? error : undefined);
163
+ }
164
+ }
165
+ /**
166
+ * Detect compression algorithm from data
167
+ * @param data Compressed data
168
+ * @returns Detected algorithm or undefined
169
+ */
170
+ detectAlgorithm(data) {
171
+ const buffer = Buffer.from(data);
172
+ // Check for gzip magic number: 0x1F 0x8B
173
+ if (buffer.length >= 2 && buffer[0] === 0x1F && buffer[1] === 0x8B) {
174
+ return 'gzip';
175
+ }
176
+ // Check for deflate magic number: 0x78 (zlib header)
177
+ if (buffer.length >= 1 && (buffer[0] === 0x78 || buffer[0] === 0x58)) {
178
+ return 'deflate';
179
+ }
180
+ // Check for brotli magic number: 0xCE 0x2B 0x2F
181
+ if (buffer.length >= 3 && buffer[0] === 0xCE && buffer[1] === 0x2B && buffer[2] === 0x2F) {
182
+ return 'brotli';
183
+ }
184
+ return undefined;
185
+ }
186
+ /**
187
+ * Check if algorithm is supported
188
+ * @param algorithm Algorithm to check
189
+ * @returns True if algorithm is supported
190
+ */
191
+ isAlgorithmSupported(algorithm) {
192
+ return this.supportedAlgorithms.includes(algorithm);
193
+ }
194
+ /**
195
+ * Get content encoding header for algorithm
196
+ * @param algorithm Compression algorithm
197
+ * @returns Content-Encoding header value
198
+ */
199
+ getContentEncoding(algorithm) {
200
+ switch (algorithm) {
201
+ case 'gzip':
202
+ return 'gzip';
203
+ case 'deflate':
204
+ return 'deflate';
205
+ case 'brotli':
206
+ return 'br';
207
+ case 'none':
208
+ return 'identity';
209
+ default:
210
+ return algorithm;
211
+ }
212
+ }
213
+ /**
214
+ * Get algorithm from content encoding header
215
+ * @param contentEncoding Content-Encoding header value
216
+ * @returns Compression algorithm or undefined
217
+ */
218
+ getAlgorithmFromEncoding(contentEncoding) {
219
+ const normalized = contentEncoding.toLowerCase().trim();
220
+ switch (normalized) {
221
+ case 'gzip':
222
+ case 'x-gzip':
223
+ return 'gzip';
224
+ case 'deflate':
225
+ return 'deflate';
226
+ case 'br':
227
+ return 'brotli';
228
+ case 'identity':
229
+ case 'none':
230
+ return 'none';
231
+ default:
232
+ return undefined;
233
+ }
234
+ }
235
+ /**
236
+ * Should compress based on configuration
237
+ * @param dataSize Data size in bytes
238
+ * @param contentType Content type
239
+ * @returns True if should compress
240
+ */
241
+ shouldCompress(dataSize, contentType) {
242
+ if (!this.config.enabled) {
243
+ return false;
244
+ }
245
+ // Check minimum size
246
+ if (this.config.minSize && dataSize < this.config.minSize) {
247
+ return false;
248
+ }
249
+ // Check maximum size
250
+ if (this.config.maxSize && dataSize > this.config.maxSize) {
251
+ return false;
252
+ }
253
+ // Check content types
254
+ if (this.config.contentTypes && contentType) {
255
+ const normalizedContentType = contentType.toLowerCase().split(';')[0].trim();
256
+ const shouldCompress = this.config.contentTypes.some(ct => normalizedContentType.includes(ct.toLowerCase()));
257
+ if (!shouldCompress) {
258
+ return false;
259
+ }
260
+ }
261
+ return true;
262
+ }
263
+ /**
264
+ * Create compression stream
265
+ * @param algorithm Compression algorithm
266
+ * @param options Compression options
267
+ * @returns Transform stream for compression
268
+ */
269
+ createCompressionStream(algorithm, options) {
270
+ throw new Error('createCompressionStream not implemented');
271
+ }
272
+ /**
273
+ * Create decompression stream
274
+ * @param algorithm Compression algorithm
275
+ * @returns Transform stream for decompression
276
+ */
277
+ createDecompressionStream(algorithm) {
278
+ throw new Error('createDecompressionStream not implemented');
279
+ }
280
+ /**
281
+ * Update compression statistics
282
+ * @param originalSize Original size in bytes
283
+ * @param compressedSize Compressed size in bytes
284
+ * @param compressionTime Compression time in milliseconds
285
+ * @param algorithm Compression algorithm used
286
+ */
287
+ updateCompressionStats(originalSize, compressedSize, compressionTime, algorithm) {
288
+ this.stats.totalCompressions++;
289
+ this.stats.totalCompressionTime += compressionTime;
290
+ this.stats.totalOriginalSize += originalSize;
291
+ this.stats.totalCompressedSize += compressedSize;
292
+ // Update algorithm usage
293
+ this.stats.algorithmUsage[algorithm] = (this.stats.algorithmUsage[algorithm] || 0) + 1;
294
+ // Update averages
295
+ this.stats.averageCompressionTime = this.stats.totalCompressionTime / this.stats.totalCompressions;
296
+ this.stats.averageCompressionRatio = this.stats.totalCompressedSize / this.stats.totalOriginalSize;
297
+ }
298
+ /**
299
+ * Update decompression statistics
300
+ * @param originalSize Original compressed size in bytes
301
+ * @param decompressedSize Decompressed size in bytes
302
+ * @param decompressionTime Decompression time in milliseconds
303
+ * @param algorithm Decompression algorithm used
304
+ */
305
+ updateDecompressionStats(originalSize, decompressedSize, decompressionTime, algorithm) {
306
+ this.stats.totalDecompressions++;
307
+ this.stats.totalDecompressionTime += decompressionTime;
308
+ this.stats.totalDecompressedSize += decompressedSize;
309
+ // Update algorithm usage
310
+ this.stats.algorithmUsage[algorithm] = (this.stats.algorithmUsage[algorithm] || 0) + 1;
311
+ // Update averages
312
+ this.stats.averageDecompressionTime = this.stats.totalDecompressionTime / this.stats.totalDecompressions;
313
+ }
314
+ /**
315
+ * Update compression configuration
316
+ * @param config New configuration
317
+ */
318
+ updateConfig(config) {
319
+ this.config = { ...this.config, ...config };
320
+ }
321
+ /**
322
+ * Get compression statistics
323
+ */
324
+ getStats() {
325
+ const bytesSaved = this.stats.totalOriginalSize - this.stats.totalCompressedSize;
326
+ return {
327
+ totalCompressions: this.stats.totalCompressions,
328
+ totalDecompressions: this.stats.totalDecompressions,
329
+ compressionErrors: this.stats.compressionErrors,
330
+ decompressionErrors: this.stats.decompressionErrors,
331
+ averageCompressionTime: this.stats.averageCompressionTime,
332
+ averageDecompressionTime: this.stats.averageDecompressionTime,
333
+ averageCompressionRatio: this.stats.averageCompressionRatio,
334
+ algorithmUsage: { ...this.stats.algorithmUsage },
335
+ totalBytesCompressed: this.stats.totalOriginalSize,
336
+ totalBytesDecompressed: this.stats.totalDecompressedSize,
337
+ bytesSaved: Math.max(0, bytesSaved),
338
+ };
339
+ }
340
+ /**
341
+ * Reset compression statistics
342
+ */
343
+ resetStats() {
344
+ this.stats = {
345
+ totalCompressions: 0,
346
+ totalDecompressions: 0,
347
+ compressionErrors: 0,
348
+ decompressionErrors: 0,
349
+ totalCompressionTime: 0,
350
+ totalDecompressionTime: 0,
351
+ totalOriginalSize: 0,
352
+ totalCompressedSize: 0,
353
+ totalDecompressedSize: 0,
354
+ averageCompressionTime: 0,
355
+ averageDecompressionTime: 0,
356
+ averageCompressionRatio: 0,
357
+ algorithmUsage: {},
358
+ };
359
+ }
360
+ /**
361
+ * Health check for compression manager
362
+ */
363
+ healthCheck() {
364
+ const healthy = this.supportedAlgorithms.length > 0;
365
+ return {
366
+ healthy,
367
+ message: healthy ? 'Compression manager is operational' : 'No compression algorithms supported',
368
+ details: {
369
+ name: this.name,
370
+ supportedAlgorithms: this.supportedAlgorithms,
371
+ config: this.config,
372
+ statistics: this.getStats(),
373
+ },
374
+ };
375
+ }
376
+ }
377
+ exports.BaseCompressionManager = BaseCompressionManager;