@push.rocks/smartproxy 25.17.10 → 26.1.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 (184) hide show
  1. package/changelog.md +15 -0
  2. package/dist_rust/rustproxy_linux_amd64 +0 -0
  3. package/dist_rust/rustproxy_linux_arm64 +0 -0
  4. package/dist_ts/00_commitinfo_data.js +2 -2
  5. package/dist_ts/core/index.d.ts +0 -1
  6. package/dist_ts/core/index.js +1 -2
  7. package/dist_ts/core/models/index.d.ts +0 -1
  8. package/dist_ts/core/models/index.js +1 -2
  9. package/dist_ts/core/utils/index.d.ts +0 -12
  10. package/dist_ts/core/utils/index.js +1 -13
  11. package/dist_ts/index.d.ts +0 -3
  12. package/dist_ts/index.js +2 -7
  13. package/dist_ts/protocols/http/index.d.ts +0 -1
  14. package/dist_ts/protocols/http/index.js +1 -2
  15. package/dist_ts/protocols/index.d.ts +0 -7
  16. package/dist_ts/protocols/index.js +1 -8
  17. package/dist_ts/proxies/smart-proxy/models/metrics-types.d.ts +20 -0
  18. package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.d.ts +2 -1
  19. package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.js +4 -1
  20. package/dist_ts/proxies/smart-proxy/socket-handler-server.js +6 -1
  21. package/dist_ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.d.ts +0 -7
  22. package/dist_ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.js +50 -51
  23. package/dist_ts/routing/index.d.ts +0 -1
  24. package/dist_ts/routing/index.js +1 -3
  25. package/package.json +1 -1
  26. package/ts/00_commitinfo_data.ts +1 -1
  27. package/ts/core/index.ts +0 -1
  28. package/ts/core/models/index.ts +0 -1
  29. package/ts/core/utils/index.ts +0 -12
  30. package/ts/index.ts +1 -7
  31. package/ts/protocols/http/index.ts +1 -2
  32. package/ts/protocols/index.ts +0 -7
  33. package/ts/proxies/smart-proxy/models/metrics-types.ts +21 -0
  34. package/ts/proxies/smart-proxy/rust-metrics-adapter.ts +4 -1
  35. package/ts/proxies/smart-proxy/socket-handler-server.ts +6 -0
  36. package/ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.ts +60 -59
  37. package/ts/routing/index.ts +0 -3
  38. package/dist_ts/core/events/index.d.ts +0 -4
  39. package/dist_ts/core/events/index.js +0 -5
  40. package/dist_ts/core/models/socket-augmentation.d.ts +0 -15
  41. package/dist_ts/core/models/socket-augmentation.js +0 -18
  42. package/dist_ts/core/utils/async-utils.d.ts +0 -81
  43. package/dist_ts/core/utils/async-utils.js +0 -216
  44. package/dist_ts/core/utils/binary-heap.d.ts +0 -73
  45. package/dist_ts/core/utils/binary-heap.js +0 -193
  46. package/dist_ts/core/utils/enhanced-connection-pool.d.ts +0 -110
  47. package/dist_ts/core/utils/enhanced-connection-pool.js +0 -325
  48. package/dist_ts/core/utils/fs-utils.d.ts +0 -144
  49. package/dist_ts/core/utils/fs-utils.js +0 -252
  50. package/dist_ts/core/utils/ip-utils.d.ts +0 -69
  51. package/dist_ts/core/utils/ip-utils.js +0 -270
  52. package/dist_ts/core/utils/lifecycle-component.d.ts +0 -59
  53. package/dist_ts/core/utils/lifecycle-component.js +0 -211
  54. package/dist_ts/core/utils/log-deduplicator.d.ts +0 -39
  55. package/dist_ts/core/utils/log-deduplicator.js +0 -305
  56. package/dist_ts/core/utils/security-utils.d.ts +0 -111
  57. package/dist_ts/core/utils/security-utils.js +0 -212
  58. package/dist_ts/core/utils/shared-security-manager.d.ts +0 -128
  59. package/dist_ts/core/utils/shared-security-manager.js +0 -362
  60. package/dist_ts/core/utils/socket-utils.d.ts +0 -63
  61. package/dist_ts/core/utils/socket-utils.js +0 -249
  62. package/dist_ts/core/utils/template-utils.d.ts +0 -37
  63. package/dist_ts/core/utils/template-utils.js +0 -104
  64. package/dist_ts/core/utils/validation-utils.d.ts +0 -61
  65. package/dist_ts/core/utils/validation-utils.js +0 -149
  66. package/dist_ts/core/utils/websocket-utils.d.ts +0 -22
  67. package/dist_ts/core/utils/websocket-utils.js +0 -30
  68. package/dist_ts/detection/detectors/http-detector.d.ts +0 -33
  69. package/dist_ts/detection/detectors/http-detector.js +0 -101
  70. package/dist_ts/detection/detectors/quick-detector.d.ts +0 -28
  71. package/dist_ts/detection/detectors/quick-detector.js +0 -131
  72. package/dist_ts/detection/detectors/routing-extractor.d.ts +0 -28
  73. package/dist_ts/detection/detectors/routing-extractor.js +0 -122
  74. package/dist_ts/detection/detectors/tls-detector.d.ts +0 -47
  75. package/dist_ts/detection/detectors/tls-detector.js +0 -183
  76. package/dist_ts/detection/index.d.ts +0 -17
  77. package/dist_ts/detection/index.js +0 -22
  78. package/dist_ts/detection/models/detection-types.d.ts +0 -87
  79. package/dist_ts/detection/models/detection-types.js +0 -5
  80. package/dist_ts/detection/models/interfaces.d.ts +0 -97
  81. package/dist_ts/detection/models/interfaces.js +0 -5
  82. package/dist_ts/detection/protocol-detector.d.ts +0 -79
  83. package/dist_ts/detection/protocol-detector.js +0 -253
  84. package/dist_ts/detection/utils/buffer-utils.d.ts +0 -61
  85. package/dist_ts/detection/utils/buffer-utils.js +0 -127
  86. package/dist_ts/detection/utils/fragment-manager.d.ts +0 -31
  87. package/dist_ts/detection/utils/fragment-manager.js +0 -53
  88. package/dist_ts/detection/utils/parser-utils.d.ts +0 -42
  89. package/dist_ts/detection/utils/parser-utils.js +0 -63
  90. package/dist_ts/protocols/common/fragment-handler.d.ts +0 -73
  91. package/dist_ts/protocols/common/fragment-handler.js +0 -121
  92. package/dist_ts/protocols/common/index.d.ts +0 -7
  93. package/dist_ts/protocols/common/index.js +0 -8
  94. package/dist_ts/protocols/common/types.d.ts +0 -68
  95. package/dist_ts/protocols/common/types.js +0 -7
  96. package/dist_ts/protocols/http/parser.d.ts +0 -58
  97. package/dist_ts/protocols/http/parser.js +0 -184
  98. package/dist_ts/protocols/proxy/index.d.ts +0 -5
  99. package/dist_ts/protocols/proxy/index.js +0 -6
  100. package/dist_ts/protocols/proxy/types.d.ts +0 -47
  101. package/dist_ts/protocols/proxy/types.js +0 -6
  102. package/dist_ts/protocols/tls/alerts/index.d.ts +0 -4
  103. package/dist_ts/protocols/tls/alerts/index.js +0 -5
  104. package/dist_ts/protocols/tls/alerts/tls-alert.d.ts +0 -150
  105. package/dist_ts/protocols/tls/alerts/tls-alert.js +0 -226
  106. package/dist_ts/protocols/tls/index.d.ts +0 -12
  107. package/dist_ts/protocols/tls/index.js +0 -27
  108. package/dist_ts/protocols/tls/sni/client-hello-parser.d.ts +0 -100
  109. package/dist_ts/protocols/tls/sni/client-hello-parser.js +0 -463
  110. package/dist_ts/protocols/tls/sni/index.d.ts +0 -5
  111. package/dist_ts/protocols/tls/sni/index.js +0 -6
  112. package/dist_ts/protocols/tls/sni/sni-extraction.d.ts +0 -58
  113. package/dist_ts/protocols/tls/sni/sni-extraction.js +0 -275
  114. package/dist_ts/protocols/tls/utils/index.d.ts +0 -4
  115. package/dist_ts/protocols/tls/utils/index.js +0 -5
  116. package/dist_ts/protocols/tls/utils/tls-utils.d.ts +0 -158
  117. package/dist_ts/protocols/tls/utils/tls-utils.js +0 -187
  118. package/dist_ts/protocols/websocket/constants.d.ts +0 -55
  119. package/dist_ts/protocols/websocket/constants.js +0 -58
  120. package/dist_ts/protocols/websocket/index.d.ts +0 -7
  121. package/dist_ts/protocols/websocket/index.js +0 -8
  122. package/dist_ts/protocols/websocket/types.d.ts +0 -47
  123. package/dist_ts/protocols/websocket/types.js +0 -5
  124. package/dist_ts/protocols/websocket/utils.d.ts +0 -25
  125. package/dist_ts/protocols/websocket/utils.js +0 -103
  126. package/dist_ts/routing/router/http-router.d.ts +0 -89
  127. package/dist_ts/routing/router/http-router.js +0 -205
  128. package/dist_ts/routing/router/index.d.ts +0 -5
  129. package/dist_ts/routing/router/index.js +0 -6
  130. package/dist_ts/tls/index.d.ts +0 -16
  131. package/dist_ts/tls/index.js +0 -24
  132. package/dist_ts/tls/sni/index.d.ts +0 -4
  133. package/dist_ts/tls/sni/index.js +0 -5
  134. package/dist_ts/tls/sni/sni-handler.d.ts +0 -154
  135. package/dist_ts/tls/sni/sni-handler.js +0 -191
  136. package/ts/core/events/index.ts +0 -3
  137. package/ts/core/models/socket-augmentation.ts +0 -38
  138. package/ts/core/utils/async-utils.ts +0 -275
  139. package/ts/core/utils/binary-heap.ts +0 -225
  140. package/ts/core/utils/enhanced-connection-pool.ts +0 -425
  141. package/ts/core/utils/fs-utils.ts +0 -270
  142. package/ts/core/utils/ip-utils.ts +0 -303
  143. package/ts/core/utils/lifecycle-component.ts +0 -251
  144. package/ts/core/utils/log-deduplicator.ts +0 -370
  145. package/ts/core/utils/security-utils.ts +0 -305
  146. package/ts/core/utils/shared-security-manager.ts +0 -470
  147. package/ts/core/utils/socket-utils.ts +0 -322
  148. package/ts/core/utils/template-utils.ts +0 -124
  149. package/ts/core/utils/validation-utils.ts +0 -177
  150. package/ts/core/utils/websocket-utils.ts +0 -33
  151. package/ts/detection/detectors/http-detector.ts +0 -127
  152. package/ts/detection/detectors/quick-detector.ts +0 -148
  153. package/ts/detection/detectors/routing-extractor.ts +0 -147
  154. package/ts/detection/detectors/tls-detector.ts +0 -223
  155. package/ts/detection/index.ts +0 -25
  156. package/ts/detection/models/detection-types.ts +0 -102
  157. package/ts/detection/models/interfaces.ts +0 -115
  158. package/ts/detection/protocol-detector.ts +0 -319
  159. package/ts/detection/utils/buffer-utils.ts +0 -141
  160. package/ts/detection/utils/fragment-manager.ts +0 -64
  161. package/ts/detection/utils/parser-utils.ts +0 -77
  162. package/ts/protocols/common/fragment-handler.ts +0 -167
  163. package/ts/protocols/common/index.ts +0 -8
  164. package/ts/protocols/common/types.ts +0 -76
  165. package/ts/protocols/http/parser.ts +0 -219
  166. package/ts/protocols/proxy/index.ts +0 -6
  167. package/ts/protocols/proxy/types.ts +0 -53
  168. package/ts/protocols/tls/alerts/index.ts +0 -3
  169. package/ts/protocols/tls/alerts/tls-alert.ts +0 -259
  170. package/ts/protocols/tls/index.ts +0 -37
  171. package/ts/protocols/tls/sni/client-hello-parser.ts +0 -629
  172. package/ts/protocols/tls/sni/index.ts +0 -6
  173. package/ts/protocols/tls/sni/sni-extraction.ts +0 -353
  174. package/ts/protocols/tls/utils/index.ts +0 -3
  175. package/ts/protocols/tls/utils/tls-utils.ts +0 -201
  176. package/ts/protocols/websocket/constants.ts +0 -60
  177. package/ts/protocols/websocket/index.ts +0 -8
  178. package/ts/protocols/websocket/types.ts +0 -53
  179. package/ts/protocols/websocket/utils.ts +0 -98
  180. package/ts/routing/router/http-router.ts +0 -266
  181. package/ts/routing/router/index.ts +0 -7
  182. package/ts/tls/index.ts +0 -29
  183. package/ts/tls/sni/index.ts +0 -3
  184. package/ts/tls/sni/sni-handler.ts +0 -264
@@ -1,211 +0,0 @@
1
- /**
2
- * Base class for components that need proper resource lifecycle management
3
- * Provides automatic cleanup of timers and event listeners to prevent memory leaks
4
- */
5
- export class LifecycleComponent {
6
- constructor() {
7
- this.timers = new Set();
8
- this.intervals = new Set();
9
- this.listeners = [];
10
- this.childComponents = new Set();
11
- this.isShuttingDown = false;
12
- }
13
- /**
14
- * Create a managed setTimeout that will be automatically cleaned up
15
- */
16
- setTimeout(handler, timeout) {
17
- if (this.isShuttingDown) {
18
- // Return a dummy timer if shutting down
19
- const dummyTimer = setTimeout(() => { }, 0);
20
- if (typeof dummyTimer.unref === 'function') {
21
- dummyTimer.unref();
22
- }
23
- return dummyTimer;
24
- }
25
- const wrappedHandler = () => {
26
- this.timers.delete(timer);
27
- if (!this.isShuttingDown) {
28
- handler();
29
- }
30
- };
31
- const timer = setTimeout(wrappedHandler, timeout);
32
- this.timers.add(timer);
33
- // Allow process to exit even with timer
34
- if (typeof timer.unref === 'function') {
35
- timer.unref();
36
- }
37
- return timer;
38
- }
39
- /**
40
- * Create a managed setInterval that will be automatically cleaned up
41
- */
42
- setInterval(handler, interval) {
43
- if (this.isShuttingDown) {
44
- // Return a dummy timer if shutting down
45
- const dummyTimer = setInterval(() => { }, interval);
46
- if (typeof dummyTimer.unref === 'function') {
47
- dummyTimer.unref();
48
- }
49
- clearInterval(dummyTimer); // Clear immediately since we don't need it
50
- return dummyTimer;
51
- }
52
- const wrappedHandler = () => {
53
- if (!this.isShuttingDown) {
54
- handler();
55
- }
56
- };
57
- const timer = setInterval(wrappedHandler, interval);
58
- this.intervals.add(timer);
59
- // Allow process to exit even with timer
60
- if (typeof timer.unref === 'function') {
61
- timer.unref();
62
- }
63
- return timer;
64
- }
65
- /**
66
- * Clear a managed timeout
67
- */
68
- clearTimeout(timer) {
69
- clearTimeout(timer);
70
- this.timers.delete(timer);
71
- }
72
- /**
73
- * Clear a managed interval
74
- */
75
- clearInterval(timer) {
76
- clearInterval(timer);
77
- this.intervals.delete(timer);
78
- }
79
- /**
80
- * Add a managed event listener that will be automatically removed on cleanup
81
- */
82
- addEventListener(target, event, handler, options) {
83
- if (this.isShuttingDown) {
84
- return;
85
- }
86
- // For 'once' listeners, we need to wrap the handler to remove it from our tracking
87
- let actualHandler = handler;
88
- if (options?.once) {
89
- actualHandler = (...args) => {
90
- // Call the original handler
91
- handler(...args);
92
- // Remove from our internal tracking
93
- const index = this.listeners.findIndex(l => l.target === target && l.event === event && l.handler === handler);
94
- if (index !== -1) {
95
- this.listeners.splice(index, 1);
96
- }
97
- };
98
- }
99
- // Support both EventEmitter and DOM-style event targets
100
- if (typeof target.on === 'function') {
101
- if (options?.once) {
102
- target.once(event, actualHandler);
103
- }
104
- else {
105
- target.on(event, actualHandler);
106
- }
107
- }
108
- else if (typeof target.addEventListener === 'function') {
109
- target.addEventListener(event, actualHandler, options);
110
- }
111
- else {
112
- throw new Error('Target must support on() or addEventListener()');
113
- }
114
- // Store both the original handler and the actual handler registered
115
- this.listeners.push({
116
- target,
117
- event,
118
- handler,
119
- actualHandler, // The handler that was actually registered (may be wrapped)
120
- once: options?.once
121
- });
122
- }
123
- /**
124
- * Remove a specific event listener
125
- */
126
- removeEventListener(target, event, handler) {
127
- // Remove from target
128
- if (typeof target.removeListener === 'function') {
129
- target.removeListener(event, handler);
130
- }
131
- else if (typeof target.removeEventListener === 'function') {
132
- target.removeEventListener(event, handler);
133
- }
134
- // Remove from our tracking
135
- const index = this.listeners.findIndex(l => l.target === target && l.event === event && l.handler === handler);
136
- if (index !== -1) {
137
- this.listeners.splice(index, 1);
138
- }
139
- }
140
- /**
141
- * Register a child component that should be cleaned up when this component is cleaned up
142
- */
143
- registerChildComponent(component) {
144
- this.childComponents.add(component);
145
- }
146
- /**
147
- * Unregister a child component
148
- */
149
- unregisterChildComponent(component) {
150
- this.childComponents.delete(component);
151
- }
152
- /**
153
- * Override this method to implement component-specific cleanup logic
154
- */
155
- async onCleanup() {
156
- // Override in subclasses
157
- }
158
- /**
159
- * Clean up all managed resources
160
- */
161
- async cleanup() {
162
- // Return existing cleanup promise if already cleaning up
163
- if (this.cleanupPromise) {
164
- return this.cleanupPromise;
165
- }
166
- this.cleanupPromise = this.performCleanup();
167
- return this.cleanupPromise;
168
- }
169
- async performCleanup() {
170
- this.isShuttingDown = true;
171
- // First, clean up child components
172
- const childCleanupPromises = [];
173
- for (const child of this.childComponents) {
174
- childCleanupPromises.push(child.cleanup());
175
- }
176
- await Promise.all(childCleanupPromises);
177
- this.childComponents.clear();
178
- // Clear all timers
179
- for (const timer of this.timers) {
180
- clearTimeout(timer);
181
- }
182
- this.timers.clear();
183
- // Clear all intervals
184
- for (const timer of this.intervals) {
185
- clearInterval(timer);
186
- }
187
- this.intervals.clear();
188
- // Remove all event listeners
189
- for (const { target, event, handler, actualHandler } of this.listeners) {
190
- // Use actualHandler if available (for wrapped handlers), otherwise use the original handler
191
- const handlerToRemove = actualHandler || handler;
192
- // All listeners need to be removed, including 'once' listeners that might not have fired
193
- if (typeof target.removeListener === 'function') {
194
- target.removeListener(event, handlerToRemove);
195
- }
196
- else if (typeof target.removeEventListener === 'function') {
197
- target.removeEventListener(event, handlerToRemove);
198
- }
199
- }
200
- this.listeners = [];
201
- // Call subclass cleanup
202
- await this.onCleanup();
203
- }
204
- /**
205
- * Check if the component is shutting down
206
- */
207
- isShuttingDownState() {
208
- return this.isShuttingDown;
209
- }
210
- }
211
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlmZWN5Y2xlLWNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2NvcmUvdXRpbHMvbGlmZWN5Y2xlLWNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFDSCxNQUFNLE9BQWdCLGtCQUFrQjtJQUF4QztRQUNVLFdBQU0sR0FBd0IsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUN4QyxjQUFTLEdBQXdCLElBQUksR0FBRyxFQUFFLENBQUM7UUFDM0MsY0FBUyxHQU1aLEVBQUUsQ0FBQztRQUNBLG9CQUFlLEdBQTRCLElBQUksR0FBRyxFQUFFLENBQUM7UUFDbkQsbUJBQWMsR0FBRyxLQUFLLENBQUM7SUEyT25DLENBQUM7SUF4T0M7O09BRUc7SUFDTyxVQUFVLENBQUMsT0FBaUIsRUFBRSxPQUFlO1FBQ3JELElBQUksSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3hCLHdDQUF3QztZQUN4QyxNQUFNLFVBQVUsR0FBRyxVQUFVLENBQUMsR0FBRyxFQUFFLEdBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQzNDLElBQUksT0FBTyxVQUFVLENBQUMsS0FBSyxLQUFLLFVBQVUsRUFBRSxDQUFDO2dCQUMzQyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDckIsQ0FBQztZQUNELE9BQU8sVUFBVSxDQUFDO1FBQ3BCLENBQUM7UUFFRCxNQUFNLGNBQWMsR0FBRyxHQUFHLEVBQUU7WUFDMUIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDMUIsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDekIsT0FBTyxFQUFFLENBQUM7WUFDWixDQUFDO1FBQ0gsQ0FBQyxDQUFDO1FBRUYsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLGNBQWMsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUNsRCxJQUFJLENBQUMsTUFBTSxDQUFDLEdB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
@@ -1,39 +0,0 @@
1
- /**
2
- * Log deduplication utility to reduce log spam for repetitive events
3
- */
4
- export declare class LogDeduplicator {
5
- private globalFlushTimer?;
6
- private aggregatedEvents;
7
- private flushInterval;
8
- private maxBatchSize;
9
- private rapidEventThreshold;
10
- private lastRapidCheck;
11
- constructor(flushInterval?: number);
12
- /**
13
- * Log a deduplicated event
14
- * @param key - Aggregation key (e.g., 'connection-rejected', 'cleanup-batch')
15
- * @param level - Log level
16
- * @param message - Log message template
17
- * @param data - Additional data
18
- * @param dedupeKey - Deduplication key within the aggregation (e.g., IP address, reason)
19
- */
20
- log(key: string, level: 'info' | 'warn' | 'error' | 'debug', message: string, data?: any, dedupeKey?: string): void;
21
- /**
22
- * Flush aggregated events for a specific key
23
- */
24
- flush(key: string): void;
25
- /**
26
- * Flush all pending events
27
- */
28
- flushAll(): void;
29
- private flushConnectionRejections;
30
- private flushConnectionCleanups;
31
- private flushConnectionTerminations;
32
- private flushIPRejections;
33
- private flushGeneric;
34
- /**
35
- * Cleanup and stop deduplication
36
- */
37
- cleanup(): void;
38
- }
39
- export declare const connectionLogDeduplicator: LogDeduplicator;
@@ -1,305 +0,0 @@
1
- import { logger } from './logger.js';
2
- /**
3
- * Log deduplication utility to reduce log spam for repetitive events
4
- */
5
- export class LogDeduplicator {
6
- constructor(flushInterval) {
7
- this.aggregatedEvents = new Map();
8
- this.flushInterval = 5000; // 5 seconds
9
- this.maxBatchSize = 100;
10
- this.rapidEventThreshold = 50; // Flush early if this many events in 1 second
11
- this.lastRapidCheck = Date.now();
12
- if (flushInterval) {
13
- this.flushInterval = flushInterval;
14
- }
15
- // Set up global periodic flush to ensure logs are emitted regularly
16
- this.globalFlushTimer = setInterval(() => {
17
- this.flushAll();
18
- }, this.flushInterval * 2); // Flush everything every 2x the normal interval
19
- if (this.globalFlushTimer.unref) {
20
- this.globalFlushTimer.unref();
21
- }
22
- }
23
- /**
24
- * Log a deduplicated event
25
- * @param key - Aggregation key (e.g., 'connection-rejected', 'cleanup-batch')
26
- * @param level - Log level
27
- * @param message - Log message template
28
- * @param data - Additional data
29
- * @param dedupeKey - Deduplication key within the aggregation (e.g., IP address, reason)
30
- */
31
- log(key, level, message, data, dedupeKey) {
32
- const eventKey = dedupeKey || message;
33
- const now = Date.now();
34
- if (!this.aggregatedEvents.has(key)) {
35
- this.aggregatedEvents.set(key, {
36
- key,
37
- events: new Map(),
38
- flushTimer: undefined
39
- });
40
- }
41
- const aggregated = this.aggregatedEvents.get(key);
42
- if (aggregated.events.has(eventKey)) {
43
- const event = aggregated.events.get(eventKey);
44
- event.count++;
45
- event.lastSeen = now;
46
- if (data) {
47
- event.data = { ...event.data, ...data };
48
- }
49
- }
50
- else {
51
- aggregated.events.set(eventKey, {
52
- level,
53
- message,
54
- data,
55
- count: 1,
56
- firstSeen: now,
57
- lastSeen: now
58
- });
59
- }
60
- // Check for rapid events (many events in short time)
61
- const totalEvents = Array.from(aggregated.events.values()).reduce((sum, e) => sum + e.count, 0);
62
- // If we're getting flooded with events, flush more frequently
63
- if (now - this.lastRapidCheck < 1000 && totalEvents >= this.rapidEventThreshold) {
64
- this.flush(key);
65
- this.lastRapidCheck = now;
66
- }
67
- else if (aggregated.events.size >= this.maxBatchSize) {
68
- // Check if we should flush due to size
69
- this.flush(key);
70
- }
71
- else if (!aggregated.flushTimer) {
72
- // Schedule flush
73
- aggregated.flushTimer = setTimeout(() => {
74
- this.flush(key);
75
- }, this.flushInterval);
76
- if (aggregated.flushTimer.unref) {
77
- aggregated.flushTimer.unref();
78
- }
79
- }
80
- // Update rapid check time
81
- if (now - this.lastRapidCheck >= 1000) {
82
- this.lastRapidCheck = now;
83
- }
84
- }
85
- /**
86
- * Flush aggregated events for a specific key
87
- */
88
- flush(key) {
89
- const aggregated = this.aggregatedEvents.get(key);
90
- if (!aggregated || aggregated.events.size === 0) {
91
- return;
92
- }
93
- if (aggregated.flushTimer) {
94
- clearTimeout(aggregated.flushTimer);
95
- aggregated.flushTimer = undefined;
96
- }
97
- // Emit aggregated log based on the key
98
- switch (key) {
99
- case 'connection-rejected':
100
- this.flushConnectionRejections(aggregated);
101
- break;
102
- case 'connection-cleanup':
103
- this.flushConnectionCleanups(aggregated);
104
- break;
105
- case 'connection-terminated':
106
- this.flushConnectionTerminations(aggregated);
107
- break;
108
- case 'ip-rejected':
109
- this.flushIPRejections(aggregated);
110
- break;
111
- default:
112
- this.flushGeneric(aggregated);
113
- }
114
- // Clear events
115
- aggregated.events.clear();
116
- }
117
- /**
118
- * Flush all pending events
119
- */
120
- flushAll() {
121
- for (const key of this.aggregatedEvents.keys()) {
122
- this.flush(key);
123
- }
124
- }
125
- flushConnectionRejections(aggregated) {
126
- const totalCount = Array.from(aggregated.events.values()).reduce((sum, e) => sum + e.count, 0);
127
- const byReason = new Map();
128
- for (const [, event] of aggregated.events) {
129
- const reason = event.data?.reason || 'unknown';
130
- byReason.set(reason, (byReason.get(reason) || 0) + event.count);
131
- }
132
- const reasonSummary = Array.from(byReason.entries())
133
- .sort((a, b) => b[1] - a[1])
134
- .map(([reason, count]) => `${reason}: ${count}`)
135
- .join(', ');
136
- const duration = Date.now() - Math.min(...Array.from(aggregated.events.values()).map(e => e.firstSeen));
137
- logger.log('warn', `[SUMMARY] Rejected ${totalCount} connections in ${Math.round(duration / 1000)}s`, {
138
- reasons: reasonSummary,
139
- uniqueIPs: aggregated.events.size,
140
- component: 'connection-dedup'
141
- });
142
- }
143
- flushConnectionCleanups(aggregated) {
144
- const totalCount = Array.from(aggregated.events.values()).reduce((sum, e) => sum + e.count, 0);
145
- const byReason = new Map();
146
- for (const [, event] of aggregated.events) {
147
- const reason = event.data?.reason || 'normal';
148
- byReason.set(reason, (byReason.get(reason) || 0) + event.count);
149
- }
150
- const reasonSummary = Array.from(byReason.entries())
151
- .sort((a, b) => b[1] - a[1])
152
- .slice(0, 5) // Top 5 reasons
153
- .map(([reason, count]) => `${reason}: ${count}`)
154
- .join(', ');
155
- logger.log('info', `Cleaned up ${totalCount} connections`, {
156
- reasons: reasonSummary,
157
- duration: Date.now() - Math.min(...Array.from(aggregated.events.values()).map(e => e.firstSeen)),
158
- component: 'connection-dedup'
159
- });
160
- }
161
- flushConnectionTerminations(aggregated) {
162
- const totalCount = Array.from(aggregated.events.values()).reduce((sum, e) => sum + e.count, 0);
163
- const byReason = new Map();
164
- const byIP = new Map();
165
- let lastActiveCount = 0;
166
- for (const [, event] of aggregated.events) {
167
- const reason = event.data?.reason || 'unknown';
168
- const ip = event.data?.remoteIP || 'unknown';
169
- byReason.set(reason, (byReason.get(reason) || 0) + event.count);
170
- // Track by IP
171
- if (ip !== 'unknown') {
172
- byIP.set(ip, (byIP.get(ip) || 0) + event.count);
173
- }
174
- // Track the last active connection count
175
- if (event.data?.activeConnections !== undefined) {
176
- lastActiveCount = event.data.activeConnections;
177
- }
178
- }
179
- const reasonSummary = Array.from(byReason.entries())
180
- .sort((a, b) => b[1] - a[1])
181
- .slice(0, 5) // Top 5 reasons
182
- .map(([reason, count]) => `${reason}: ${count}`)
183
- .join(', ');
184
- // Show top IPs if there are many different ones
185
- let ipInfo = '';
186
- if (byIP.size > 3) {
187
- const topIPs = Array.from(byIP.entries())
188
- .sort((a, b) => b[1] - a[1])
189
- .slice(0, 3)
190
- .map(([ip, count]) => `${ip} (${count})`)
191
- .join(', ');
192
- ipInfo = `, from ${byIP.size} IPs (top: ${topIPs})`;
193
- }
194
- else if (byIP.size > 0) {
195
- ipInfo = `, IPs: ${Array.from(byIP.keys()).join(', ')}`;
196
- }
197
- const duration = Date.now() - Math.min(...Array.from(aggregated.events.values()).map(e => e.firstSeen));
198
- // Special handling for localhost connections (HttpProxy)
199
- const localhostCount = byIP.get('::ffff:127.0.0.1') || 0;
200
- if (localhostCount > 0 && byIP.size === 1) {
201
- // All connections are from localhost (HttpProxy)
202
- logger.log('info', `[SUMMARY] ${totalCount} HttpProxy connections terminated in ${Math.round(duration / 1000)}s`, {
203
- reasons: reasonSummary,
204
- activeConnections: lastActiveCount,
205
- component: 'connection-dedup'
206
- });
207
- }
208
- else {
209
- logger.log('info', `[SUMMARY] ${totalCount} connections terminated in ${Math.round(duration / 1000)}s`, {
210
- reasons: reasonSummary,
211
- activeConnections: lastActiveCount,
212
- uniqueReasons: byReason.size,
213
- ...(ipInfo ? { ips: ipInfo } : {}),
214
- component: 'connection-dedup'
215
- });
216
- }
217
- }
218
- flushIPRejections(aggregated) {
219
- const byIP = new Map();
220
- const allReasons = new Map();
221
- for (const [ip, event] of aggregated.events) {
222
- if (!byIP.has(ip)) {
223
- byIP.set(ip, { count: 0, reasons: new Set() });
224
- }
225
- const ipData = byIP.get(ip);
226
- ipData.count += event.count;
227
- if (event.data?.reason) {
228
- ipData.reasons.add(event.data.reason);
229
- // Track overall reason counts
230
- allReasons.set(event.data.reason, (allReasons.get(event.data.reason) || 0) + event.count);
231
- }
232
- }
233
- // Create reason summary
234
- const reasonSummary = Array.from(allReasons.entries())
235
- .sort((a, b) => b[1] - a[1])
236
- .map(([reason, count]) => `${reason}: ${count}`)
237
- .join(', ');
238
- // Log top offenders
239
- const topOffenders = Array.from(byIP.entries())
240
- .sort((a, b) => b[1].count - a[1].count)
241
- .slice(0, 10)
242
- .map(([ip, data]) => `${ip} (${data.count}x, ${Array.from(data.reasons).join('/')})`)
243
- .join(', ');
244
- const totalRejections = Array.from(byIP.values()).reduce((sum, data) => sum + data.count, 0);
245
- const duration = Date.now() - Math.min(...Array.from(aggregated.events.values()).map(e => e.firstSeen));
246
- logger.log('warn', `[SUMMARY] Rejected ${totalRejections} connections from ${byIP.size} IPs in ${Math.round(duration / 1000)}s (${reasonSummary})`, {
247
- topOffenders,
248
- component: 'ip-dedup'
249
- });
250
- }
251
- flushGeneric(aggregated) {
252
- const totalCount = Array.from(aggregated.events.values()).reduce((sum, e) => sum + e.count, 0);
253
- const level = aggregated.events.values().next().value?.level || 'info';
254
- // Special handling for IP cleanup events
255
- if (aggregated.key === 'ip-cleanup') {
256
- const totalCleaned = Array.from(aggregated.events.values()).reduce((sum, e) => {
257
- return sum + (e.data?.cleanedIPs || 0) + (e.data?.cleanedRateLimits || 0);
258
- }, 0);
259
- if (totalCleaned > 0) {
260
- logger.log(level, `IP tracking cleanup: removed ${totalCleaned} entries across ${totalCount} cleanup cycles`, {
261
- duration: Date.now() - Math.min(...Array.from(aggregated.events.values()).map(e => e.firstSeen)),
262
- component: 'log-dedup'
263
- });
264
- }
265
- }
266
- else {
267
- logger.log(level, `${aggregated.key}: ${totalCount} events`, {
268
- uniqueEvents: aggregated.events.size,
269
- duration: Date.now() - Math.min(...Array.from(aggregated.events.values()).map(e => e.firstSeen)),
270
- component: 'log-dedup'
271
- });
272
- }
273
- }
274
- /**
275
- * Cleanup and stop deduplication
276
- */
277
- cleanup() {
278
- this.flushAll();
279
- if (this.globalFlushTimer) {
280
- clearInterval(this.globalFlushTimer);
281
- this.globalFlushTimer = undefined;
282
- }
283
- for (const aggregated of this.aggregatedEvents.values()) {
284
- if (aggregated.flushTimer) {
285
- clearTimeout(aggregated.flushTimer);
286
- }
287
- }
288
- this.aggregatedEvents.clear();
289
- }
290
- }
291
- // Global instance for connection-related log deduplication
292
- export const connectionLogDeduplicator = new LogDeduplicator(5000); // 5 second batches
293
- // Ensure logs are flushed on process exit.
294
- // Only use beforeExit — do NOT call process.exit() from SIGINT/SIGTERM handlers
295
- // as that kills the host process's graceful shutdown (e.g., dcrouter connection draining).
296
- process.on('beforeExit', () => {
297
- connectionLogDeduplicator.flushAll();
298
- });
299
- process.on('SIGINT', () => {
300
- connectionLogDeduplicator.cleanup();
301
- });
302
- process.on('SIGTERM', () => {
303
- connectionLogDeduplicator.cleanup();
304
- });
305
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nLWRlZHVwbGljYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL2NvcmUvdXRpbHMvbG9nLWRlZHVwbGljYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBaUJyQzs7R0FFRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBUTFCLFlBQVksYUFBc0I7UUFOMUIscUJBQWdCLEdBQWtDLElBQUksR0FBRyxFQUFFLENBQUM7UUFDNUQsa0JBQWEsR0FBVyxJQUFJLENBQUMsQ0FBQyxZQUFZO1FBQzFDLGlCQUFZLEdBQVcsR0FBRyxDQUFDO1FBQzNCLHdCQUFtQixHQUFXLEVBQUUsQ0FBQyxDQUFDLDhDQUE4QztRQUNoRixtQkFBYyxHQUFXLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUcxQyxJQUFJLGFBQWEsRUFBRSxDQUFDO1lBQ2xCLElBQUksQ0FBQyxhQUFhLEdBQUcsYUFBYSxDQUFDO1FBQ3JDLENBQUM7UUFFRCxvRUFBb0U7UUFDcEUsSUFBSSxDQUFDLGdCQUFnQixHQUFHLFdBQVcsQ0FBQyxHQUFHLEVBQUU7WUFDdkMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ2xCLENBQUMsRUFBRSxJQUFJLENBQUMsYUFBYSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsZ0RBQWdEO1FBRTVFLElBQUksSUFBSSxDQUFDLGdCQUFnQixDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ2hDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNoQyxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSSxHQUFHLENBQ1IsR0FBVyxFQUNYLEtBQTBDLEVBQzFDLE9BQWUsRUFDZixJQUFVLEVBQ1YsU0FBa0I7UUFFbEIsTUFBTSxRQUFRLEdBQUcsU0FBUyxJQUFJLE9BQU8sQ0FBQztRQUN0QyxNQUFNLEdBQUcsR0FBRyxJQUFJLENB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TSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQztRQUMvRixNQUFNLFFBQVEsR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztRQUUzQyxLQUFLLE1BQU0sQ0FBQyxFQUFFLEtBQUssQ0FBQyxJQUFJLFVBQVUsQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUMxQyxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsSUFBSSxFQUFFLE1BQU0sSUFBSSxTQUFTLENBQUM7WUFDL0MsUUFBUSxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNsRSxDQUFDO1FBRUQsTUFBTSxhQUFhLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxFQUFFLENBQUM7YUFDakQsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzthQUMzQixHQUFHLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxNQUFNLEtBQUssS0FBSyxFQUFFLENBQUM7YUFDL0MsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRWQsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQztRQUN4RyxNQUFNLENBQUMsR0FB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