@push.rocks/smartproxy 25.17.10 → 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.
- package/changelog.md +8 -0
- package/dist_rust/rustproxy_linux_amd64 +0 -0
- package/dist_rust/rustproxy_linux_arm64 +0 -0
- package/dist_ts/00_commitinfo_data.js +2 -2
- package/dist_ts/core/index.d.ts +0 -1
- package/dist_ts/core/index.js +1 -2
- package/dist_ts/core/models/index.d.ts +0 -1
- package/dist_ts/core/models/index.js +1 -2
- package/dist_ts/core/utils/index.d.ts +0 -12
- package/dist_ts/core/utils/index.js +1 -13
- package/dist_ts/index.d.ts +0 -3
- package/dist_ts/index.js +2 -7
- package/dist_ts/protocols/http/index.d.ts +0 -1
- package/dist_ts/protocols/http/index.js +1 -2
- package/dist_ts/protocols/index.d.ts +0 -7
- package/dist_ts/protocols/index.js +1 -8
- package/dist_ts/proxies/smart-proxy/socket-handler-server.js +6 -1
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.d.ts +0 -7
- package/dist_ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.js +50 -51
- package/dist_ts/routing/index.d.ts +0 -1
- package/dist_ts/routing/index.js +1 -3
- package/package.json +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/core/index.ts +0 -1
- package/ts/core/models/index.ts +0 -1
- package/ts/core/utils/index.ts +0 -12
- package/ts/index.ts +1 -7
- package/ts/protocols/http/index.ts +1 -2
- package/ts/protocols/index.ts +0 -7
- package/ts/proxies/smart-proxy/socket-handler-server.ts +6 -0
- package/ts/proxies/smart-proxy/utils/route-helpers/socket-handlers.ts +60 -59
- package/ts/routing/index.ts +0 -3
- package/dist_ts/core/events/index.d.ts +0 -4
- package/dist_ts/core/events/index.js +0 -5
- package/dist_ts/core/models/socket-augmentation.d.ts +0 -15
- package/dist_ts/core/models/socket-augmentation.js +0 -18
- package/dist_ts/core/utils/async-utils.d.ts +0 -81
- package/dist_ts/core/utils/async-utils.js +0 -216
- package/dist_ts/core/utils/binary-heap.d.ts +0 -73
- package/dist_ts/core/utils/binary-heap.js +0 -193
- package/dist_ts/core/utils/enhanced-connection-pool.d.ts +0 -110
- package/dist_ts/core/utils/enhanced-connection-pool.js +0 -325
- package/dist_ts/core/utils/fs-utils.d.ts +0 -144
- package/dist_ts/core/utils/fs-utils.js +0 -252
- package/dist_ts/core/utils/ip-utils.d.ts +0 -69
- package/dist_ts/core/utils/ip-utils.js +0 -270
- package/dist_ts/core/utils/lifecycle-component.d.ts +0 -59
- package/dist_ts/core/utils/lifecycle-component.js +0 -211
- package/dist_ts/core/utils/log-deduplicator.d.ts +0 -39
- package/dist_ts/core/utils/log-deduplicator.js +0 -305
- package/dist_ts/core/utils/security-utils.d.ts +0 -111
- package/dist_ts/core/utils/security-utils.js +0 -212
- package/dist_ts/core/utils/shared-security-manager.d.ts +0 -128
- package/dist_ts/core/utils/shared-security-manager.js +0 -362
- package/dist_ts/core/utils/socket-utils.d.ts +0 -63
- package/dist_ts/core/utils/socket-utils.js +0 -249
- package/dist_ts/core/utils/template-utils.d.ts +0 -37
- package/dist_ts/core/utils/template-utils.js +0 -104
- package/dist_ts/core/utils/validation-utils.d.ts +0 -61
- package/dist_ts/core/utils/validation-utils.js +0 -149
- package/dist_ts/core/utils/websocket-utils.d.ts +0 -22
- package/dist_ts/core/utils/websocket-utils.js +0 -30
- package/dist_ts/detection/detectors/http-detector.d.ts +0 -33
- package/dist_ts/detection/detectors/http-detector.js +0 -101
- package/dist_ts/detection/detectors/quick-detector.d.ts +0 -28
- package/dist_ts/detection/detectors/quick-detector.js +0 -131
- package/dist_ts/detection/detectors/routing-extractor.d.ts +0 -28
- package/dist_ts/detection/detectors/routing-extractor.js +0 -122
- package/dist_ts/detection/detectors/tls-detector.d.ts +0 -47
- package/dist_ts/detection/detectors/tls-detector.js +0 -183
- package/dist_ts/detection/index.d.ts +0 -17
- package/dist_ts/detection/index.js +0 -22
- package/dist_ts/detection/models/detection-types.d.ts +0 -87
- package/dist_ts/detection/models/detection-types.js +0 -5
- package/dist_ts/detection/models/interfaces.d.ts +0 -97
- package/dist_ts/detection/models/interfaces.js +0 -5
- package/dist_ts/detection/protocol-detector.d.ts +0 -79
- package/dist_ts/detection/protocol-detector.js +0 -253
- package/dist_ts/detection/utils/buffer-utils.d.ts +0 -61
- package/dist_ts/detection/utils/buffer-utils.js +0 -127
- package/dist_ts/detection/utils/fragment-manager.d.ts +0 -31
- package/dist_ts/detection/utils/fragment-manager.js +0 -53
- package/dist_ts/detection/utils/parser-utils.d.ts +0 -42
- package/dist_ts/detection/utils/parser-utils.js +0 -63
- package/dist_ts/protocols/common/fragment-handler.d.ts +0 -73
- package/dist_ts/protocols/common/fragment-handler.js +0 -121
- package/dist_ts/protocols/common/index.d.ts +0 -7
- package/dist_ts/protocols/common/index.js +0 -8
- package/dist_ts/protocols/common/types.d.ts +0 -68
- package/dist_ts/protocols/common/types.js +0 -7
- package/dist_ts/protocols/http/parser.d.ts +0 -58
- package/dist_ts/protocols/http/parser.js +0 -184
- package/dist_ts/protocols/proxy/index.d.ts +0 -5
- package/dist_ts/protocols/proxy/index.js +0 -6
- package/dist_ts/protocols/proxy/types.d.ts +0 -47
- package/dist_ts/protocols/proxy/types.js +0 -6
- package/dist_ts/protocols/tls/alerts/index.d.ts +0 -4
- package/dist_ts/protocols/tls/alerts/index.js +0 -5
- package/dist_ts/protocols/tls/alerts/tls-alert.d.ts +0 -150
- package/dist_ts/protocols/tls/alerts/tls-alert.js +0 -226
- package/dist_ts/protocols/tls/index.d.ts +0 -12
- package/dist_ts/protocols/tls/index.js +0 -27
- package/dist_ts/protocols/tls/sni/client-hello-parser.d.ts +0 -100
- package/dist_ts/protocols/tls/sni/client-hello-parser.js +0 -463
- package/dist_ts/protocols/tls/sni/index.d.ts +0 -5
- package/dist_ts/protocols/tls/sni/index.js +0 -6
- package/dist_ts/protocols/tls/sni/sni-extraction.d.ts +0 -58
- package/dist_ts/protocols/tls/sni/sni-extraction.js +0 -275
- package/dist_ts/protocols/tls/utils/index.d.ts +0 -4
- package/dist_ts/protocols/tls/utils/index.js +0 -5
- package/dist_ts/protocols/tls/utils/tls-utils.d.ts +0 -158
- package/dist_ts/protocols/tls/utils/tls-utils.js +0 -187
- package/dist_ts/protocols/websocket/constants.d.ts +0 -55
- package/dist_ts/protocols/websocket/constants.js +0 -58
- package/dist_ts/protocols/websocket/index.d.ts +0 -7
- package/dist_ts/protocols/websocket/index.js +0 -8
- package/dist_ts/protocols/websocket/types.d.ts +0 -47
- package/dist_ts/protocols/websocket/types.js +0 -5
- package/dist_ts/protocols/websocket/utils.d.ts +0 -25
- package/dist_ts/protocols/websocket/utils.js +0 -103
- package/dist_ts/routing/router/http-router.d.ts +0 -89
- package/dist_ts/routing/router/http-router.js +0 -205
- package/dist_ts/routing/router/index.d.ts +0 -5
- package/dist_ts/routing/router/index.js +0 -6
- package/dist_ts/tls/index.d.ts +0 -16
- package/dist_ts/tls/index.js +0 -24
- package/dist_ts/tls/sni/index.d.ts +0 -4
- package/dist_ts/tls/sni/index.js +0 -5
- package/dist_ts/tls/sni/sni-handler.d.ts +0 -154
- package/dist_ts/tls/sni/sni-handler.js +0 -191
- package/ts/core/events/index.ts +0 -3
- package/ts/core/models/socket-augmentation.ts +0 -38
- package/ts/core/utils/async-utils.ts +0 -275
- package/ts/core/utils/binary-heap.ts +0 -225
- package/ts/core/utils/enhanced-connection-pool.ts +0 -425
- package/ts/core/utils/fs-utils.ts +0 -270
- package/ts/core/utils/ip-utils.ts +0 -303
- package/ts/core/utils/lifecycle-component.ts +0 -251
- package/ts/core/utils/log-deduplicator.ts +0 -370
- package/ts/core/utils/security-utils.ts +0 -305
- package/ts/core/utils/shared-security-manager.ts +0 -470
- package/ts/core/utils/socket-utils.ts +0 -322
- package/ts/core/utils/template-utils.ts +0 -124
- package/ts/core/utils/validation-utils.ts +0 -177
- package/ts/core/utils/websocket-utils.ts +0 -33
- package/ts/detection/detectors/http-detector.ts +0 -127
- package/ts/detection/detectors/quick-detector.ts +0 -148
- package/ts/detection/detectors/routing-extractor.ts +0 -147
- package/ts/detection/detectors/tls-detector.ts +0 -223
- package/ts/detection/index.ts +0 -25
- package/ts/detection/models/detection-types.ts +0 -102
- package/ts/detection/models/interfaces.ts +0 -115
- package/ts/detection/protocol-detector.ts +0 -319
- package/ts/detection/utils/buffer-utils.ts +0 -141
- package/ts/detection/utils/fragment-manager.ts +0 -64
- package/ts/detection/utils/parser-utils.ts +0 -77
- package/ts/protocols/common/fragment-handler.ts +0 -167
- package/ts/protocols/common/index.ts +0 -8
- package/ts/protocols/common/types.ts +0 -76
- package/ts/protocols/http/parser.ts +0 -219
- package/ts/protocols/proxy/index.ts +0 -6
- package/ts/protocols/proxy/types.ts +0 -53
- package/ts/protocols/tls/alerts/index.ts +0 -3
- package/ts/protocols/tls/alerts/tls-alert.ts +0 -259
- package/ts/protocols/tls/index.ts +0 -37
- package/ts/protocols/tls/sni/client-hello-parser.ts +0 -629
- package/ts/protocols/tls/sni/index.ts +0 -6
- package/ts/protocols/tls/sni/sni-extraction.ts +0 -353
- package/ts/protocols/tls/utils/index.ts +0 -3
- package/ts/protocols/tls/utils/tls-utils.ts +0 -201
- package/ts/protocols/websocket/constants.ts +0 -60
- package/ts/protocols/websocket/index.ts +0 -8
- package/ts/protocols/websocket/types.ts +0 -53
- package/ts/protocols/websocket/utils.ts +0 -98
- package/ts/routing/router/http-router.ts +0 -266
- package/ts/routing/router/index.ts +0 -7
- package/ts/tls/index.ts +0 -29
- package/ts/tls/sni/index.ts +0 -3
- package/ts/tls/sni/sni-handler.ts +0 -264
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Async utility functions for SmartProxy
|
|
3
|
-
* Provides non-blocking alternatives to synchronous operations
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Delays execution for the specified number of milliseconds
|
|
8
|
-
* Non-blocking alternative to busy wait loops
|
|
9
|
-
* @param ms - Number of milliseconds to delay
|
|
10
|
-
* @returns Promise that resolves after the delay
|
|
11
|
-
*/
|
|
12
|
-
export async function delay(ms: number): Promise<void> {
|
|
13
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Retry an async operation with exponential backoff
|
|
18
|
-
* @param fn - The async function to retry
|
|
19
|
-
* @param options - Retry options
|
|
20
|
-
* @returns The result of the function or throws the last error
|
|
21
|
-
*/
|
|
22
|
-
export async function retryWithBackoff<T>(
|
|
23
|
-
fn: () => Promise<T>,
|
|
24
|
-
options: {
|
|
25
|
-
maxAttempts?: number;
|
|
26
|
-
initialDelay?: number;
|
|
27
|
-
maxDelay?: number;
|
|
28
|
-
factor?: number;
|
|
29
|
-
onRetry?: (attempt: number, error: Error) => void;
|
|
30
|
-
} = {}
|
|
31
|
-
): Promise<T> {
|
|
32
|
-
const {
|
|
33
|
-
maxAttempts = 3,
|
|
34
|
-
initialDelay = 100,
|
|
35
|
-
maxDelay = 10000,
|
|
36
|
-
factor = 2,
|
|
37
|
-
onRetry
|
|
38
|
-
} = options;
|
|
39
|
-
|
|
40
|
-
let lastError: Error | null = null;
|
|
41
|
-
let currentDelay = initialDelay;
|
|
42
|
-
|
|
43
|
-
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
44
|
-
try {
|
|
45
|
-
return await fn();
|
|
46
|
-
} catch (error: any) {
|
|
47
|
-
lastError = error;
|
|
48
|
-
|
|
49
|
-
if (attempt === maxAttempts) {
|
|
50
|
-
throw error;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (onRetry) {
|
|
54
|
-
onRetry(attempt, error);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
await delay(currentDelay);
|
|
58
|
-
currentDelay = Math.min(currentDelay * factor, maxDelay);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
throw lastError || new Error('Retry failed');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Execute an async operation with a timeout
|
|
67
|
-
* @param fn - The async function to execute
|
|
68
|
-
* @param timeoutMs - Timeout in milliseconds
|
|
69
|
-
* @param timeoutError - Optional custom timeout error
|
|
70
|
-
* @returns The result of the function or throws timeout error
|
|
71
|
-
*/
|
|
72
|
-
export async function withTimeout<T>(
|
|
73
|
-
fn: () => Promise<T>,
|
|
74
|
-
timeoutMs: number,
|
|
75
|
-
timeoutError?: Error
|
|
76
|
-
): Promise<T> {
|
|
77
|
-
const timeoutPromise = new Promise<never>((_, reject) => {
|
|
78
|
-
setTimeout(() => {
|
|
79
|
-
reject(timeoutError || new Error(`Operation timed out after ${timeoutMs}ms`));
|
|
80
|
-
}, timeoutMs);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
return Promise.race([fn(), timeoutPromise]);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Run multiple async operations in parallel with a concurrency limit
|
|
88
|
-
* @param items - Array of items to process
|
|
89
|
-
* @param fn - Async function to run for each item
|
|
90
|
-
* @param concurrency - Maximum number of concurrent operations
|
|
91
|
-
* @returns Array of results in the same order as input
|
|
92
|
-
*/
|
|
93
|
-
export async function parallelLimit<T, R>(
|
|
94
|
-
items: T[],
|
|
95
|
-
fn: (item: T, index: number) => Promise<R>,
|
|
96
|
-
concurrency: number
|
|
97
|
-
): Promise<R[]> {
|
|
98
|
-
const results: R[] = new Array(items.length);
|
|
99
|
-
const executing: Set<Promise<void>> = new Set();
|
|
100
|
-
|
|
101
|
-
for (let i = 0; i < items.length; i++) {
|
|
102
|
-
const promise = fn(items[i], i).then(result => {
|
|
103
|
-
results[i] = result;
|
|
104
|
-
executing.delete(promise);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
executing.add(promise);
|
|
108
|
-
|
|
109
|
-
if (executing.size >= concurrency) {
|
|
110
|
-
await Promise.race(executing);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
await Promise.all(executing);
|
|
115
|
-
return results;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Debounce an async function
|
|
120
|
-
* @param fn - The async function to debounce
|
|
121
|
-
* @param delayMs - Delay in milliseconds
|
|
122
|
-
* @returns Debounced function with cancel method
|
|
123
|
-
*/
|
|
124
|
-
export function debounceAsync<T extends (...args: any[]) => Promise<any>>(
|
|
125
|
-
fn: T,
|
|
126
|
-
delayMs: number
|
|
127
|
-
): T & { cancel: () => void } {
|
|
128
|
-
let timeoutId: NodeJS.Timeout | null = null;
|
|
129
|
-
let lastPromise: Promise<any> | null = null;
|
|
130
|
-
|
|
131
|
-
const debounced = ((...args: Parameters<T>) => {
|
|
132
|
-
if (timeoutId) {
|
|
133
|
-
clearTimeout(timeoutId);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
lastPromise = new Promise((resolve, reject) => {
|
|
137
|
-
timeoutId = setTimeout(async () => {
|
|
138
|
-
timeoutId = null;
|
|
139
|
-
try {
|
|
140
|
-
const result = await fn(...args);
|
|
141
|
-
resolve(result);
|
|
142
|
-
} catch (error) {
|
|
143
|
-
reject(error);
|
|
144
|
-
}
|
|
145
|
-
}, delayMs);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
return lastPromise;
|
|
149
|
-
}) as any;
|
|
150
|
-
|
|
151
|
-
debounced.cancel = () => {
|
|
152
|
-
if (timeoutId) {
|
|
153
|
-
clearTimeout(timeoutId);
|
|
154
|
-
timeoutId = null;
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
return debounced as T & { cancel: () => void };
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Create a mutex for ensuring exclusive access to a resource
|
|
163
|
-
*/
|
|
164
|
-
export class AsyncMutex {
|
|
165
|
-
private queue: Array<() => void> = [];
|
|
166
|
-
private locked = false;
|
|
167
|
-
|
|
168
|
-
async acquire(): Promise<() => void> {
|
|
169
|
-
if (!this.locked) {
|
|
170
|
-
this.locked = true;
|
|
171
|
-
return () => this.release();
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return new Promise<() => void>(resolve => {
|
|
175
|
-
this.queue.push(() => {
|
|
176
|
-
resolve(() => this.release());
|
|
177
|
-
});
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
private release(): void {
|
|
182
|
-
const next = this.queue.shift();
|
|
183
|
-
if (next) {
|
|
184
|
-
next();
|
|
185
|
-
} else {
|
|
186
|
-
this.locked = false;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
async runExclusive<T>(fn: () => Promise<T>): Promise<T> {
|
|
191
|
-
const release = await this.acquire();
|
|
192
|
-
try {
|
|
193
|
-
return await fn();
|
|
194
|
-
} finally {
|
|
195
|
-
release();
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Circuit breaker for protecting against cascading failures
|
|
202
|
-
*/
|
|
203
|
-
export class CircuitBreaker {
|
|
204
|
-
private failureCount = 0;
|
|
205
|
-
private lastFailureTime = 0;
|
|
206
|
-
private state: 'closed' | 'open' | 'half-open' = 'closed';
|
|
207
|
-
|
|
208
|
-
constructor(
|
|
209
|
-
private options: {
|
|
210
|
-
failureThreshold: number;
|
|
211
|
-
resetTimeout: number;
|
|
212
|
-
onStateChange?: (state: 'closed' | 'open' | 'half-open') => void;
|
|
213
|
-
}
|
|
214
|
-
) {}
|
|
215
|
-
|
|
216
|
-
async execute<T>(fn: () => Promise<T>): Promise<T> {
|
|
217
|
-
if (this.state === 'open') {
|
|
218
|
-
if (Date.now() - this.lastFailureTime > this.options.resetTimeout) {
|
|
219
|
-
this.setState('half-open');
|
|
220
|
-
} else {
|
|
221
|
-
throw new Error('Circuit breaker is open');
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
try {
|
|
226
|
-
const result = await fn();
|
|
227
|
-
this.onSuccess();
|
|
228
|
-
return result;
|
|
229
|
-
} catch (error) {
|
|
230
|
-
this.onFailure();
|
|
231
|
-
throw error;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
private onSuccess(): void {
|
|
236
|
-
this.failureCount = 0;
|
|
237
|
-
if (this.state !== 'closed') {
|
|
238
|
-
this.setState('closed');
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
private onFailure(): void {
|
|
243
|
-
this.failureCount++;
|
|
244
|
-
this.lastFailureTime = Date.now();
|
|
245
|
-
|
|
246
|
-
if (this.failureCount >= this.options.failureThreshold) {
|
|
247
|
-
this.setState('open');
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
private setState(state: 'closed' | 'open' | 'half-open'): void {
|
|
252
|
-
if (this.state !== state) {
|
|
253
|
-
this.state = state;
|
|
254
|
-
if (this.options.onStateChange) {
|
|
255
|
-
this.options.onStateChange(state);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
isOpen(): boolean {
|
|
261
|
-
return this.state === 'open';
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
getState(): 'closed' | 'open' | 'half-open' {
|
|
265
|
-
return this.state;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
recordSuccess(): void {
|
|
269
|
-
this.onSuccess();
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
recordFailure(): void {
|
|
273
|
-
this.onFailure();
|
|
274
|
-
}
|
|
275
|
-
}
|
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A binary heap implementation for efficient priority queue operations
|
|
3
|
-
* Supports O(log n) insert and extract operations
|
|
4
|
-
*/
|
|
5
|
-
export class BinaryHeap<T> {
|
|
6
|
-
private heap: T[] = [];
|
|
7
|
-
private keyMap?: Map<string, number>; // For efficient key-based lookups
|
|
8
|
-
|
|
9
|
-
constructor(
|
|
10
|
-
private compareFn: (a: T, b: T) => number,
|
|
11
|
-
private extractKey?: (item: T) => string
|
|
12
|
-
) {
|
|
13
|
-
if (extractKey) {
|
|
14
|
-
this.keyMap = new Map();
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Get the current size of the heap
|
|
20
|
-
*/
|
|
21
|
-
public get size(): number {
|
|
22
|
-
return this.heap.length;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Check if the heap is empty
|
|
27
|
-
*/
|
|
28
|
-
public isEmpty(): boolean {
|
|
29
|
-
return this.heap.length === 0;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Peek at the top element without removing it
|
|
34
|
-
*/
|
|
35
|
-
public peek(): T | undefined {
|
|
36
|
-
return this.heap[0];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Insert a new item into the heap
|
|
41
|
-
* O(log n) time complexity
|
|
42
|
-
*/
|
|
43
|
-
public insert(item: T): void {
|
|
44
|
-
const index = this.heap.length;
|
|
45
|
-
this.heap.push(item);
|
|
46
|
-
|
|
47
|
-
if (this.keyMap && this.extractKey) {
|
|
48
|
-
const key = this.extractKey(item);
|
|
49
|
-
this.keyMap.set(key, index);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
this.bubbleUp(index);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Extract the top element from the heap
|
|
57
|
-
* O(log n) time complexity
|
|
58
|
-
*/
|
|
59
|
-
public extract(): T | undefined {
|
|
60
|
-
if (this.heap.length === 0) return undefined;
|
|
61
|
-
if (this.heap.length === 1) {
|
|
62
|
-
const item = this.heap.pop()!;
|
|
63
|
-
if (this.keyMap && this.extractKey) {
|
|
64
|
-
this.keyMap.delete(this.extractKey(item));
|
|
65
|
-
}
|
|
66
|
-
return item;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const result = this.heap[0];
|
|
70
|
-
const lastItem = this.heap.pop()!;
|
|
71
|
-
this.heap[0] = lastItem;
|
|
72
|
-
|
|
73
|
-
if (this.keyMap && this.extractKey) {
|
|
74
|
-
this.keyMap.delete(this.extractKey(result));
|
|
75
|
-
this.keyMap.set(this.extractKey(lastItem), 0);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
this.bubbleDown(0);
|
|
79
|
-
return result;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Extract an element that matches the predicate
|
|
84
|
-
* O(n) time complexity for search, O(log n) for extraction
|
|
85
|
-
*/
|
|
86
|
-
public extractIf(predicate: (item: T) => boolean): T | undefined {
|
|
87
|
-
const index = this.heap.findIndex(predicate);
|
|
88
|
-
if (index === -1) return undefined;
|
|
89
|
-
|
|
90
|
-
return this.extractAt(index);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Extract an element by its key (if extractKey was provided)
|
|
95
|
-
* O(log n) time complexity
|
|
96
|
-
*/
|
|
97
|
-
public extractByKey(key: string): T | undefined {
|
|
98
|
-
if (!this.keyMap || !this.extractKey) {
|
|
99
|
-
throw new Error('extractKey function must be provided to use key-based extraction');
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const index = this.keyMap.get(key);
|
|
103
|
-
if (index === undefined) return undefined;
|
|
104
|
-
|
|
105
|
-
return this.extractAt(index);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Check if a key exists in the heap
|
|
110
|
-
* O(1) time complexity
|
|
111
|
-
*/
|
|
112
|
-
public hasKey(key: string): boolean {
|
|
113
|
-
if (!this.keyMap) return false;
|
|
114
|
-
return this.keyMap.has(key);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Get all elements as an array (does not modify heap)
|
|
119
|
-
* O(n) time complexity
|
|
120
|
-
*/
|
|
121
|
-
public toArray(): T[] {
|
|
122
|
-
return [...this.heap];
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Clear the heap
|
|
127
|
-
*/
|
|
128
|
-
public clear(): void {
|
|
129
|
-
this.heap = [];
|
|
130
|
-
if (this.keyMap) {
|
|
131
|
-
this.keyMap.clear();
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Extract element at specific index
|
|
137
|
-
*/
|
|
138
|
-
private extractAt(index: number): T {
|
|
139
|
-
const item = this.heap[index];
|
|
140
|
-
|
|
141
|
-
if (this.keyMap && this.extractKey) {
|
|
142
|
-
this.keyMap.delete(this.extractKey(item));
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (index === this.heap.length - 1) {
|
|
146
|
-
this.heap.pop();
|
|
147
|
-
return item;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const lastItem = this.heap.pop()!;
|
|
151
|
-
this.heap[index] = lastItem;
|
|
152
|
-
|
|
153
|
-
if (this.keyMap && this.extractKey) {
|
|
154
|
-
this.keyMap.set(this.extractKey(lastItem), index);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Try bubbling up first
|
|
158
|
-
const parentIndex = Math.floor((index - 1) / 2);
|
|
159
|
-
if (parentIndex >= 0 && this.compareFn(this.heap[index], this.heap[parentIndex]) < 0) {
|
|
160
|
-
this.bubbleUp(index);
|
|
161
|
-
} else {
|
|
162
|
-
this.bubbleDown(index);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return item;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Bubble up element at given index to maintain heap property
|
|
170
|
-
*/
|
|
171
|
-
private bubbleUp(index: number): void {
|
|
172
|
-
while (index > 0) {
|
|
173
|
-
const parentIndex = Math.floor((index - 1) / 2);
|
|
174
|
-
|
|
175
|
-
if (this.compareFn(this.heap[index], this.heap[parentIndex]) >= 0) {
|
|
176
|
-
break;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
this.swap(index, parentIndex);
|
|
180
|
-
index = parentIndex;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Bubble down element at given index to maintain heap property
|
|
186
|
-
*/
|
|
187
|
-
private bubbleDown(index: number): void {
|
|
188
|
-
const length = this.heap.length;
|
|
189
|
-
|
|
190
|
-
while (true) {
|
|
191
|
-
const leftChild = 2 * index + 1;
|
|
192
|
-
const rightChild = 2 * index + 2;
|
|
193
|
-
let smallest = index;
|
|
194
|
-
|
|
195
|
-
if (leftChild < length &&
|
|
196
|
-
this.compareFn(this.heap[leftChild], this.heap[smallest]) < 0) {
|
|
197
|
-
smallest = leftChild;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (rightChild < length &&
|
|
201
|
-
this.compareFn(this.heap[rightChild], this.heap[smallest]) < 0) {
|
|
202
|
-
smallest = rightChild;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (smallest === index) break;
|
|
206
|
-
|
|
207
|
-
this.swap(index, smallest);
|
|
208
|
-
index = smallest;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Swap two elements in the heap
|
|
214
|
-
*/
|
|
215
|
-
private swap(i: number, j: number): void {
|
|
216
|
-
const temp = this.heap[i];
|
|
217
|
-
this.heap[i] = this.heap[j];
|
|
218
|
-
this.heap[j] = temp;
|
|
219
|
-
|
|
220
|
-
if (this.keyMap && this.extractKey) {
|
|
221
|
-
this.keyMap.set(this.extractKey(this.heap[i]), i);
|
|
222
|
-
this.keyMap.set(this.extractKey(this.heap[j]), j);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|