@push.rocks/smartproxy 25.17.9 → 26.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 (179) hide show
  1. package/changelog.md +16 -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/socket-handler-server.js +6 -1
  18. package/dist_ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.d.ts +0 -7
  19. package/dist_ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.js +50 -51
  20. package/dist_ts/routing/index.d.ts +0 -1
  21. package/dist_ts/routing/index.js +1 -3
  22. package/package.json +1 -1
  23. package/ts/00_commitinfo_data.ts +1 -1
  24. package/ts/core/index.ts +0 -1
  25. package/ts/core/models/index.ts +0 -1
  26. package/ts/core/utils/index.ts +0 -12
  27. package/ts/index.ts +1 -7
  28. package/ts/protocols/http/index.ts +1 -2
  29. package/ts/protocols/index.ts +0 -7
  30. package/ts/proxies/smart-proxy/socket-handler-server.ts +6 -0
  31. package/ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.ts +60 -59
  32. package/ts/routing/index.ts +0 -3
  33. package/dist_ts/core/events/index.d.ts +0 -4
  34. package/dist_ts/core/events/index.js +0 -5
  35. package/dist_ts/core/models/socket-augmentation.d.ts +0 -15
  36. package/dist_ts/core/models/socket-augmentation.js +0 -18
  37. package/dist_ts/core/utils/async-utils.d.ts +0 -81
  38. package/dist_ts/core/utils/async-utils.js +0 -216
  39. package/dist_ts/core/utils/binary-heap.d.ts +0 -73
  40. package/dist_ts/core/utils/binary-heap.js +0 -193
  41. package/dist_ts/core/utils/enhanced-connection-pool.d.ts +0 -110
  42. package/dist_ts/core/utils/enhanced-connection-pool.js +0 -325
  43. package/dist_ts/core/utils/fs-utils.d.ts +0 -144
  44. package/dist_ts/core/utils/fs-utils.js +0 -252
  45. package/dist_ts/core/utils/ip-utils.d.ts +0 -69
  46. package/dist_ts/core/utils/ip-utils.js +0 -270
  47. package/dist_ts/core/utils/lifecycle-component.d.ts +0 -59
  48. package/dist_ts/core/utils/lifecycle-component.js +0 -211
  49. package/dist_ts/core/utils/log-deduplicator.d.ts +0 -39
  50. package/dist_ts/core/utils/log-deduplicator.js +0 -305
  51. package/dist_ts/core/utils/security-utils.d.ts +0 -111
  52. package/dist_ts/core/utils/security-utils.js +0 -212
  53. package/dist_ts/core/utils/shared-security-manager.d.ts +0 -128
  54. package/dist_ts/core/utils/shared-security-manager.js +0 -362
  55. package/dist_ts/core/utils/socket-utils.d.ts +0 -63
  56. package/dist_ts/core/utils/socket-utils.js +0 -249
  57. package/dist_ts/core/utils/template-utils.d.ts +0 -37
  58. package/dist_ts/core/utils/template-utils.js +0 -104
  59. package/dist_ts/core/utils/validation-utils.d.ts +0 -61
  60. package/dist_ts/core/utils/validation-utils.js +0 -149
  61. package/dist_ts/core/utils/websocket-utils.d.ts +0 -22
  62. package/dist_ts/core/utils/websocket-utils.js +0 -30
  63. package/dist_ts/detection/detectors/http-detector.d.ts +0 -33
  64. package/dist_ts/detection/detectors/http-detector.js +0 -101
  65. package/dist_ts/detection/detectors/quick-detector.d.ts +0 -28
  66. package/dist_ts/detection/detectors/quick-detector.js +0 -131
  67. package/dist_ts/detection/detectors/routing-extractor.d.ts +0 -28
  68. package/dist_ts/detection/detectors/routing-extractor.js +0 -122
  69. package/dist_ts/detection/detectors/tls-detector.d.ts +0 -47
  70. package/dist_ts/detection/detectors/tls-detector.js +0 -183
  71. package/dist_ts/detection/index.d.ts +0 -17
  72. package/dist_ts/detection/index.js +0 -22
  73. package/dist_ts/detection/models/detection-types.d.ts +0 -87
  74. package/dist_ts/detection/models/detection-types.js +0 -5
  75. package/dist_ts/detection/models/interfaces.d.ts +0 -97
  76. package/dist_ts/detection/models/interfaces.js +0 -5
  77. package/dist_ts/detection/protocol-detector.d.ts +0 -79
  78. package/dist_ts/detection/protocol-detector.js +0 -253
  79. package/dist_ts/detection/utils/buffer-utils.d.ts +0 -61
  80. package/dist_ts/detection/utils/buffer-utils.js +0 -127
  81. package/dist_ts/detection/utils/fragment-manager.d.ts +0 -31
  82. package/dist_ts/detection/utils/fragment-manager.js +0 -53
  83. package/dist_ts/detection/utils/parser-utils.d.ts +0 -42
  84. package/dist_ts/detection/utils/parser-utils.js +0 -63
  85. package/dist_ts/protocols/common/fragment-handler.d.ts +0 -73
  86. package/dist_ts/protocols/common/fragment-handler.js +0 -121
  87. package/dist_ts/protocols/common/index.d.ts +0 -7
  88. package/dist_ts/protocols/common/index.js +0 -8
  89. package/dist_ts/protocols/common/types.d.ts +0 -68
  90. package/dist_ts/protocols/common/types.js +0 -7
  91. package/dist_ts/protocols/http/parser.d.ts +0 -58
  92. package/dist_ts/protocols/http/parser.js +0 -184
  93. package/dist_ts/protocols/proxy/index.d.ts +0 -5
  94. package/dist_ts/protocols/proxy/index.js +0 -6
  95. package/dist_ts/protocols/proxy/types.d.ts +0 -47
  96. package/dist_ts/protocols/proxy/types.js +0 -6
  97. package/dist_ts/protocols/tls/alerts/index.d.ts +0 -4
  98. package/dist_ts/protocols/tls/alerts/index.js +0 -5
  99. package/dist_ts/protocols/tls/alerts/tls-alert.d.ts +0 -150
  100. package/dist_ts/protocols/tls/alerts/tls-alert.js +0 -226
  101. package/dist_ts/protocols/tls/index.d.ts +0 -12
  102. package/dist_ts/protocols/tls/index.js +0 -27
  103. package/dist_ts/protocols/tls/sni/client-hello-parser.d.ts +0 -100
  104. package/dist_ts/protocols/tls/sni/client-hello-parser.js +0 -463
  105. package/dist_ts/protocols/tls/sni/index.d.ts +0 -5
  106. package/dist_ts/protocols/tls/sni/index.js +0 -6
  107. package/dist_ts/protocols/tls/sni/sni-extraction.d.ts +0 -58
  108. package/dist_ts/protocols/tls/sni/sni-extraction.js +0 -275
  109. package/dist_ts/protocols/tls/utils/index.d.ts +0 -4
  110. package/dist_ts/protocols/tls/utils/index.js +0 -5
  111. package/dist_ts/protocols/tls/utils/tls-utils.d.ts +0 -158
  112. package/dist_ts/protocols/tls/utils/tls-utils.js +0 -187
  113. package/dist_ts/protocols/websocket/constants.d.ts +0 -55
  114. package/dist_ts/protocols/websocket/constants.js +0 -58
  115. package/dist_ts/protocols/websocket/index.d.ts +0 -7
  116. package/dist_ts/protocols/websocket/index.js +0 -8
  117. package/dist_ts/protocols/websocket/types.d.ts +0 -47
  118. package/dist_ts/protocols/websocket/types.js +0 -5
  119. package/dist_ts/protocols/websocket/utils.d.ts +0 -25
  120. package/dist_ts/protocols/websocket/utils.js +0 -103
  121. package/dist_ts/routing/router/http-router.d.ts +0 -89
  122. package/dist_ts/routing/router/http-router.js +0 -205
  123. package/dist_ts/routing/router/index.d.ts +0 -5
  124. package/dist_ts/routing/router/index.js +0 -6
  125. package/dist_ts/tls/index.d.ts +0 -16
  126. package/dist_ts/tls/index.js +0 -24
  127. package/dist_ts/tls/sni/index.d.ts +0 -4
  128. package/dist_ts/tls/sni/index.js +0 -5
  129. package/dist_ts/tls/sni/sni-handler.d.ts +0 -154
  130. package/dist_ts/tls/sni/sni-handler.js +0 -191
  131. package/ts/core/events/index.ts +0 -3
  132. package/ts/core/models/socket-augmentation.ts +0 -38
  133. package/ts/core/utils/async-utils.ts +0 -275
  134. package/ts/core/utils/binary-heap.ts +0 -225
  135. package/ts/core/utils/enhanced-connection-pool.ts +0 -425
  136. package/ts/core/utils/fs-utils.ts +0 -270
  137. package/ts/core/utils/ip-utils.ts +0 -303
  138. package/ts/core/utils/lifecycle-component.ts +0 -251
  139. package/ts/core/utils/log-deduplicator.ts +0 -370
  140. package/ts/core/utils/security-utils.ts +0 -305
  141. package/ts/core/utils/shared-security-manager.ts +0 -470
  142. package/ts/core/utils/socket-utils.ts +0 -322
  143. package/ts/core/utils/template-utils.ts +0 -124
  144. package/ts/core/utils/validation-utils.ts +0 -177
  145. package/ts/core/utils/websocket-utils.ts +0 -33
  146. package/ts/detection/detectors/http-detector.ts +0 -127
  147. package/ts/detection/detectors/quick-detector.ts +0 -148
  148. package/ts/detection/detectors/routing-extractor.ts +0 -147
  149. package/ts/detection/detectors/tls-detector.ts +0 -223
  150. package/ts/detection/index.ts +0 -25
  151. package/ts/detection/models/detection-types.ts +0 -102
  152. package/ts/detection/models/interfaces.ts +0 -115
  153. package/ts/detection/protocol-detector.ts +0 -319
  154. package/ts/detection/utils/buffer-utils.ts +0 -141
  155. package/ts/detection/utils/fragment-manager.ts +0 -64
  156. package/ts/detection/utils/parser-utils.ts +0 -77
  157. package/ts/protocols/common/fragment-handler.ts +0 -167
  158. package/ts/protocols/common/index.ts +0 -8
  159. package/ts/protocols/common/types.ts +0 -76
  160. package/ts/protocols/http/parser.ts +0 -219
  161. package/ts/protocols/proxy/index.ts +0 -6
  162. package/ts/protocols/proxy/types.ts +0 -53
  163. package/ts/protocols/tls/alerts/index.ts +0 -3
  164. package/ts/protocols/tls/alerts/tls-alert.ts +0 -259
  165. package/ts/protocols/tls/index.ts +0 -37
  166. package/ts/protocols/tls/sni/client-hello-parser.ts +0 -629
  167. package/ts/protocols/tls/sni/index.ts +0 -6
  168. package/ts/protocols/tls/sni/sni-extraction.ts +0 -353
  169. package/ts/protocols/tls/utils/index.ts +0 -3
  170. package/ts/protocols/tls/utils/tls-utils.ts +0 -201
  171. package/ts/protocols/websocket/constants.ts +0 -60
  172. package/ts/protocols/websocket/index.ts +0 -8
  173. package/ts/protocols/websocket/types.ts +0 -53
  174. package/ts/protocols/websocket/utils.ts +0 -98
  175. package/ts/routing/router/http-router.ts +0 -266
  176. package/ts/routing/router/index.ts +0 -7
  177. package/ts/tls/index.ts +0 -29
  178. package/ts/tls/sni/index.ts +0 -3
  179. package/ts/tls/sni/sni-handler.ts +0 -264
@@ -1,303 +0,0 @@
1
- import * as plugins from '../../plugins.js';
2
-
3
- /**
4
- * Utility class for IP address operations
5
- */
6
- export class IpUtils {
7
- /**
8
- * Check if the IP matches any of the glob patterns
9
- *
10
- * This method checks IP addresses against glob patterns and handles IPv4/IPv6 normalization.
11
- * It's used to implement IP filtering based on security configurations.
12
- *
13
- * @param ip - The IP address to check
14
- * @param patterns - Array of glob patterns
15
- * @returns true if IP matches any pattern, false otherwise
16
- */
17
- public static isGlobIPMatch(ip: string, patterns: string[]): boolean {
18
- if (!ip || !patterns || patterns.length === 0) return false;
19
-
20
- // Normalize the IP being checked
21
- const normalizedIPVariants = this.normalizeIP(ip);
22
- if (normalizedIPVariants.length === 0) return false;
23
-
24
- // Check each pattern
25
- for (const pattern of patterns) {
26
- // Handle CIDR notation
27
- if (pattern.includes('/')) {
28
- if (this.matchCIDR(ip, pattern)) {
29
- return true;
30
- }
31
- continue;
32
- }
33
-
34
- // Handle range notation
35
- if (pattern.includes('-') && !pattern.includes('*')) {
36
- if (this.matchIPRange(ip, pattern)) {
37
- return true;
38
- }
39
- continue;
40
- }
41
-
42
- // Expand shorthand patterns for glob matching
43
- let expandedPattern = pattern;
44
- if (pattern.includes('*') && !pattern.includes(':')) {
45
- const parts = pattern.split('.');
46
- while (parts.length < 4) {
47
- parts.push('*');
48
- }
49
- expandedPattern = parts.join('.');
50
- }
51
-
52
- // Normalize and check with minimatch
53
- const normalizedPatterns = this.normalizeIP(expandedPattern);
54
-
55
- for (const ipVariant of normalizedIPVariants) {
56
- for (const normalizedPattern of normalizedPatterns) {
57
- if (plugins.minimatch(ipVariant, normalizedPattern)) {
58
- return true;
59
- }
60
- }
61
- }
62
- }
63
-
64
- return false;
65
- }
66
-
67
- /**
68
- * Normalize IP addresses for consistent comparison
69
- *
70
- * @param ip The IP address to normalize
71
- * @returns Array of normalized IP forms
72
- */
73
- public static normalizeIP(ip: string): string[] {
74
- if (!ip) return [];
75
-
76
- // Handle IPv4-mapped IPv6 addresses (::ffff:127.0.0.1)
77
- if (ip.startsWith('::ffff:')) {
78
- const ipv4 = ip.slice(7);
79
- return [ip, ipv4];
80
- }
81
-
82
- // Handle IPv4 addresses by also checking IPv4-mapped form
83
- if (/^\d{1,3}(\.\d{1,3}){3}$/.test(ip)) {
84
- return [ip, `::ffff:${ip}`];
85
- }
86
-
87
- return [ip];
88
- }
89
-
90
- /**
91
- * Check if an IP is authorized using security rules
92
- *
93
- * @param ip - The IP address to check
94
- * @param allowedIPs - Array of allowed IP patterns
95
- * @param blockedIPs - Array of blocked IP patterns
96
- * @returns true if IP is authorized, false if blocked
97
- */
98
- public static isIPAuthorized(ip: string, allowedIPs: string[] = [], blockedIPs: string[] = []): boolean {
99
- // Skip IP validation if no rules are defined
100
- if (!ip || (allowedIPs.length === 0 && blockedIPs.length === 0)) {
101
- return true;
102
- }
103
-
104
- // First check if IP is blocked - blocked IPs take precedence
105
- if (blockedIPs.length > 0 && this.isGlobIPMatch(ip, blockedIPs)) {
106
- return false;
107
- }
108
-
109
- // Then check if IP is allowed (if no allowed IPs are specified, all non-blocked IPs are allowed)
110
- return allowedIPs.length === 0 || this.isGlobIPMatch(ip, allowedIPs);
111
- }
112
-
113
- /**
114
- * Check if an IP address is a private network address
115
- *
116
- * @param ip The IP address to check
117
- * @returns true if the IP is a private network address, false otherwise
118
- */
119
- public static isPrivateIP(ip: string): boolean {
120
- if (!ip) return false;
121
-
122
- // Handle IPv4-mapped IPv6 addresses
123
- if (ip.startsWith('::ffff:')) {
124
- ip = ip.slice(7);
125
- }
126
-
127
- // Check IPv4 private ranges
128
- if (/^\d{1,3}(\.\d{1,3}){3}$/.test(ip)) {
129
- const parts = ip.split('.').map(Number);
130
-
131
- // Check common private ranges
132
- // 10.0.0.0/8
133
- if (parts[0] === 10) return true;
134
-
135
- // 172.16.0.0/12
136
- if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return true;
137
-
138
- // 192.168.0.0/16
139
- if (parts[0] === 192 && parts[1] === 168) return true;
140
-
141
- // 127.0.0.0/8 (localhost)
142
- if (parts[0] === 127) return true;
143
-
144
- return false;
145
- }
146
-
147
- // IPv6 local addresses
148
- return ip === '::1' || ip.startsWith('fc00:') || ip.startsWith('fd00:') || ip.startsWith('fe80:');
149
- }
150
-
151
- /**
152
- * Check if an IP address is a public network address
153
- *
154
- * @param ip The IP address to check
155
- * @returns true if the IP is a public network address, false otherwise
156
- */
157
- public static isPublicIP(ip: string): boolean {
158
- return !this.isPrivateIP(ip);
159
- }
160
-
161
- /**
162
- * Check if an IP matches a CIDR notation
163
- *
164
- * @param ip The IP address to check
165
- * @param cidr The CIDR notation (e.g., "192.168.1.0/24")
166
- * @returns true if IP is within the CIDR range
167
- */
168
- private static matchCIDR(ip: string, cidr: string): boolean {
169
- if (!cidr.includes('/')) return false;
170
-
171
- const [networkAddr, prefixStr] = cidr.split('/');
172
- const prefix = parseInt(prefixStr, 10);
173
-
174
- // Handle IPv4-mapped IPv6 in the IP being checked
175
- let checkIP = ip;
176
- if (checkIP.startsWith('::ffff:')) {
177
- checkIP = checkIP.slice(7);
178
- }
179
-
180
- // Handle IPv6 CIDR
181
- if (networkAddr.includes(':')) {
182
- // TODO: Implement IPv6 CIDR matching
183
- return false;
184
- }
185
-
186
- // IPv4 CIDR matching
187
- if (!/^\d{1,3}(\.\d{1,3}){3}$/.test(checkIP)) return false;
188
- if (!/^\d{1,3}(\.\d{1,3}){3}$/.test(networkAddr)) return false;
189
- if (isNaN(prefix) || prefix < 0 || prefix > 32) return false;
190
-
191
- const ipParts = checkIP.split('.').map(Number);
192
- const netParts = networkAddr.split('.').map(Number);
193
-
194
- // Validate IP parts
195
- for (const part of [...ipParts, ...netParts]) {
196
- if (part < 0 || part > 255) return false;
197
- }
198
-
199
- // Convert to 32-bit integers
200
- const ipNum = (ipParts[0] << 24) | (ipParts[1] << 16) | (ipParts[2] << 8) | ipParts[3];
201
- const netNum = (netParts[0] << 24) | (netParts[1] << 16) | (netParts[2] << 8) | netParts[3];
202
-
203
- // Create mask
204
- const mask = (-1 << (32 - prefix)) >>> 0;
205
-
206
- // Check if IP is in network range
207
- return (ipNum & mask) === (netNum & mask);
208
- }
209
-
210
- /**
211
- * Check if an IP matches a range notation
212
- *
213
- * @param ip The IP address to check
214
- * @param range The range notation (e.g., "192.168.1.1-192.168.1.100")
215
- * @returns true if IP is within the range
216
- */
217
- private static matchIPRange(ip: string, range: string): boolean {
218
- if (!range.includes('-')) return false;
219
-
220
- const [startIP, endIP] = range.split('-').map(s => s.trim());
221
-
222
- // Handle IPv4-mapped IPv6 in the IP being checked
223
- let checkIP = ip;
224
- if (checkIP.startsWith('::ffff:')) {
225
- checkIP = checkIP.slice(7);
226
- }
227
-
228
- // Only handle IPv4 for now
229
- if (!/^\d{1,3}(\.\d{1,3}){3}$/.test(checkIP)) return false;
230
- if (!/^\d{1,3}(\.\d{1,3}){3}$/.test(startIP)) return false;
231
- if (!/^\d{1,3}(\.\d{1,3}){3}$/.test(endIP)) return false;
232
-
233
- const ipParts = checkIP.split('.').map(Number);
234
- const startParts = startIP.split('.').map(Number);
235
- const endParts = endIP.split('.').map(Number);
236
-
237
- // Validate parts
238
- for (const part of [...ipParts, ...startParts, ...endParts]) {
239
- if (part < 0 || part > 255) return false;
240
- }
241
-
242
- // Convert to 32-bit integers for comparison
243
- const ipNum = (ipParts[0] << 24) | (ipParts[1] << 16) | (ipParts[2] << 8) | ipParts[3];
244
- const startNum = (startParts[0] << 24) | (startParts[1] << 16) | (startParts[2] << 8) | startParts[3];
245
- const endNum = (endParts[0] << 24) | (endParts[1] << 16) | (endParts[2] << 8) | endParts[3];
246
-
247
- // Convert to unsigned for proper comparison
248
- const ipUnsigned = ipNum >>> 0;
249
- const startUnsigned = startNum >>> 0;
250
- const endUnsigned = endNum >>> 0;
251
-
252
- return ipUnsigned >= startUnsigned && ipUnsigned <= endUnsigned;
253
- }
254
-
255
- /**
256
- * Convert a subnet CIDR to an IP range for filtering
257
- *
258
- * @param cidr The CIDR notation (e.g., "192.168.1.0/24")
259
- * @returns Array of glob patterns that match the CIDR range
260
- */
261
- public static cidrToGlobPatterns(cidr: string): string[] {
262
- if (!cidr || !cidr.includes('/')) return [];
263
-
264
- const [ipPart, prefixPart] = cidr.split('/');
265
- const prefix = parseInt(prefixPart, 10);
266
-
267
- if (isNaN(prefix) || prefix < 0 || prefix > 32) return [];
268
-
269
- // For IPv4 only for now
270
- if (!/^\d{1,3}(\.\d{1,3}){3}$/.test(ipPart)) return [];
271
-
272
- const ipParts = ipPart.split('.').map(Number);
273
- const fullMask = Math.pow(2, 32 - prefix) - 1;
274
-
275
- // Convert IP to a numeric value
276
- const ipNum = (ipParts[0] << 24) | (ipParts[1] << 16) | (ipParts[2] << 8) | ipParts[3];
277
-
278
- // Calculate network address (IP & ~fullMask)
279
- const networkNum = ipNum & ~fullMask;
280
-
281
- // For large ranges, return wildcard patterns
282
- if (prefix <= 8) {
283
- return [`${(networkNum >>> 24) & 255}.*.*.*`];
284
- } else if (prefix <= 16) {
285
- return [`${(networkNum >>> 24) & 255}.${(networkNum >>> 16) & 255}.*.*`];
286
- } else if (prefix <= 24) {
287
- return [`${(networkNum >>> 24) & 255}.${(networkNum >>> 16) & 255}.${(networkNum >>> 8) & 255}.*`];
288
- }
289
-
290
- // For small ranges, create individual IP patterns
291
- const patterns = [];
292
- const maxAddresses = Math.min(256, Math.pow(2, 32 - prefix));
293
-
294
- for (let i = 0; i < maxAddresses; i++) {
295
- const currentIpNum = networkNum + i;
296
- patterns.push(
297
- `${(currentIpNum >>> 24) & 255}.${(currentIpNum >>> 16) & 255}.${(currentIpNum >>> 8) & 255}.${currentIpNum & 255}`
298
- );
299
- }
300
-
301
- return patterns;
302
- }
303
- }
@@ -1,251 +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 abstract class LifecycleComponent {
6
- private timers: Set<NodeJS.Timeout> = new Set();
7
- private intervals: Set<NodeJS.Timeout> = new Set();
8
- private listeners: Array<{
9
- target: any;
10
- event: string;
11
- handler: Function;
12
- actualHandler?: Function; // The actual handler registered (may be wrapped)
13
- once?: boolean;
14
- }> = [];
15
- private childComponents: Set<LifecycleComponent> = new Set();
16
- protected isShuttingDown = false;
17
- private cleanupPromise?: Promise<void>;
18
-
19
- /**
20
- * Create a managed setTimeout that will be automatically cleaned up
21
- */
22
- protected setTimeout(handler: Function, timeout: number): NodeJS.Timeout {
23
- if (this.isShuttingDown) {
24
- // Return a dummy timer if shutting down
25
- const dummyTimer = setTimeout(() => {}, 0);
26
- if (typeof dummyTimer.unref === 'function') {
27
- dummyTimer.unref();
28
- }
29
- return dummyTimer;
30
- }
31
-
32
- const wrappedHandler = () => {
33
- this.timers.delete(timer);
34
- if (!this.isShuttingDown) {
35
- handler();
36
- }
37
- };
38
-
39
- const timer = setTimeout(wrappedHandler, timeout);
40
- this.timers.add(timer);
41
-
42
- // Allow process to exit even with timer
43
- if (typeof timer.unref === 'function') {
44
- timer.unref();
45
- }
46
-
47
- return timer;
48
- }
49
-
50
- /**
51
- * Create a managed setInterval that will be automatically cleaned up
52
- */
53
- protected setInterval(handler: Function, interval: number): NodeJS.Timeout {
54
- if (this.isShuttingDown) {
55
- // Return a dummy timer if shutting down
56
- const dummyTimer = setInterval(() => {}, interval);
57
- if (typeof dummyTimer.unref === 'function') {
58
- dummyTimer.unref();
59
- }
60
- clearInterval(dummyTimer); // Clear immediately since we don't need it
61
- return dummyTimer;
62
- }
63
-
64
- const wrappedHandler = () => {
65
- if (!this.isShuttingDown) {
66
- handler();
67
- }
68
- };
69
-
70
- const timer = setInterval(wrappedHandler, interval);
71
- this.intervals.add(timer);
72
-
73
- // Allow process to exit even with timer
74
- if (typeof timer.unref === 'function') {
75
- timer.unref();
76
- }
77
-
78
- return timer;
79
- }
80
-
81
- /**
82
- * Clear a managed timeout
83
- */
84
- protected clearTimeout(timer: NodeJS.Timeout): void {
85
- clearTimeout(timer);
86
- this.timers.delete(timer);
87
- }
88
-
89
- /**
90
- * Clear a managed interval
91
- */
92
- protected clearInterval(timer: NodeJS.Timeout): void {
93
- clearInterval(timer);
94
- this.intervals.delete(timer);
95
- }
96
-
97
- /**
98
- * Add a managed event listener that will be automatically removed on cleanup
99
- */
100
- protected addEventListener(
101
- target: any,
102
- event: string,
103
- handler: Function,
104
- options?: { once?: boolean }
105
- ): void {
106
- if (this.isShuttingDown) {
107
- return;
108
- }
109
-
110
- // For 'once' listeners, we need to wrap the handler to remove it from our tracking
111
- let actualHandler = handler;
112
- if (options?.once) {
113
- actualHandler = (...args: any[]) => {
114
- // Call the original handler
115
- handler(...args);
116
-
117
- // Remove from our internal tracking
118
- const index = this.listeners.findIndex(
119
- l => l.target === target && l.event === event && l.handler === handler
120
- );
121
- if (index !== -1) {
122
- this.listeners.splice(index, 1);
123
- }
124
- };
125
- }
126
-
127
- // Support both EventEmitter and DOM-style event targets
128
- if (typeof target.on === 'function') {
129
- if (options?.once) {
130
- target.once(event, actualHandler);
131
- } else {
132
- target.on(event, actualHandler);
133
- }
134
- } else if (typeof target.addEventListener === 'function') {
135
- target.addEventListener(event, actualHandler, options);
136
- } else {
137
- throw new Error('Target must support on() or addEventListener()');
138
- }
139
-
140
- // Store both the original handler and the actual handler registered
141
- this.listeners.push({
142
- target,
143
- event,
144
- handler,
145
- actualHandler, // The handler that was actually registered (may be wrapped)
146
- once: options?.once
147
- });
148
- }
149
-
150
- /**
151
- * Remove a specific event listener
152
- */
153
- protected removeEventListener(target: any, event: string, handler: Function): void {
154
- // Remove from target
155
- if (typeof target.removeListener === 'function') {
156
- target.removeListener(event, handler);
157
- } else if (typeof target.removeEventListener === 'function') {
158
- target.removeEventListener(event, handler);
159
- }
160
-
161
- // Remove from our tracking
162
- const index = this.listeners.findIndex(
163
- l => l.target === target && l.event === event && l.handler === handler
164
- );
165
- if (index !== -1) {
166
- this.listeners.splice(index, 1);
167
- }
168
- }
169
-
170
- /**
171
- * Register a child component that should be cleaned up when this component is cleaned up
172
- */
173
- protected registerChildComponent(component: LifecycleComponent): void {
174
- this.childComponents.add(component);
175
- }
176
-
177
- /**
178
- * Unregister a child component
179
- */
180
- protected unregisterChildComponent(component: LifecycleComponent): void {
181
- this.childComponents.delete(component);
182
- }
183
-
184
- /**
185
- * Override this method to implement component-specific cleanup logic
186
- */
187
- protected async onCleanup(): Promise<void> {
188
- // Override in subclasses
189
- }
190
-
191
- /**
192
- * Clean up all managed resources
193
- */
194
- public async cleanup(): Promise<void> {
195
- // Return existing cleanup promise if already cleaning up
196
- if (this.cleanupPromise) {
197
- return this.cleanupPromise;
198
- }
199
-
200
- this.cleanupPromise = this.performCleanup();
201
- return this.cleanupPromise;
202
- }
203
-
204
- private async performCleanup(): Promise<void> {
205
- this.isShuttingDown = true;
206
-
207
- // First, clean up child components
208
- const childCleanupPromises: Promise<void>[] = [];
209
- for (const child of this.childComponents) {
210
- childCleanupPromises.push(child.cleanup());
211
- }
212
- await Promise.all(childCleanupPromises);
213
- this.childComponents.clear();
214
-
215
- // Clear all timers
216
- for (const timer of this.timers) {
217
- clearTimeout(timer);
218
- }
219
- this.timers.clear();
220
-
221
- // Clear all intervals
222
- for (const timer of this.intervals) {
223
- clearInterval(timer);
224
- }
225
- this.intervals.clear();
226
-
227
- // Remove all event listeners
228
- for (const { target, event, handler, actualHandler } of this.listeners) {
229
- // Use actualHandler if available (for wrapped handlers), otherwise use the original handler
230
- const handlerToRemove = actualHandler || handler;
231
-
232
- // All listeners need to be removed, including 'once' listeners that might not have fired
233
- if (typeof target.removeListener === 'function') {
234
- target.removeListener(event, handlerToRemove);
235
- } else if (typeof target.removeEventListener === 'function') {
236
- target.removeEventListener(event, handlerToRemove);
237
- }
238
- }
239
- this.listeners = [];
240
-
241
- // Call subclass cleanup
242
- await this.onCleanup();
243
- }
244
-
245
- /**
246
- * Check if the component is shutting down
247
- */
248
- protected isShuttingDownState(): boolean {
249
- return this.isShuttingDown;
250
- }
251
- }