@putuofc/fastp 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +41 -0
- package/dist/index.js +235 -0
- package/package.json +19 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Readable } from 'stream';
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
interface RequestOptions {
|
|
4
|
+
method?: string;
|
|
5
|
+
headers?: Record<string, string>;
|
|
6
|
+
body?: string | Buffer | Readable;
|
|
7
|
+
cookies?: Record<string, string>;
|
|
8
|
+
decompress?: boolean;
|
|
9
|
+
followRedirects?: boolean;
|
|
10
|
+
maxRedirects?: number;
|
|
11
|
+
timeout?: number;
|
|
12
|
+
stream?: boolean;
|
|
13
|
+
}
|
|
14
|
+
interface Response extends EventEmitter {
|
|
15
|
+
statusCode: number;
|
|
16
|
+
headers: Record<string, string | string[]>;
|
|
17
|
+
body: Buffer | Readable;
|
|
18
|
+
text?: string;
|
|
19
|
+
json?: any;
|
|
20
|
+
timing: {
|
|
21
|
+
socket: number;
|
|
22
|
+
lookup: number;
|
|
23
|
+
connect: number;
|
|
24
|
+
secureConnect: number;
|
|
25
|
+
response: number;
|
|
26
|
+
end: number;
|
|
27
|
+
total: number;
|
|
28
|
+
};
|
|
29
|
+
fingerprints: {
|
|
30
|
+
ja3: string;
|
|
31
|
+
ja3Hash: string;
|
|
32
|
+
akamai: string;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export declare class FastProxiedClient {
|
|
36
|
+
private cookieJar;
|
|
37
|
+
constructor();
|
|
38
|
+
request(url: string, options?: RequestOptions): Promise<Response>;
|
|
39
|
+
destroy(): void;
|
|
40
|
+
}
|
|
41
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.FastProxiedClient = void 0;
|
|
37
|
+
const https = __importStar(require("https"));
|
|
38
|
+
const zlib = __importStar(require("zlib"));
|
|
39
|
+
const util_1 = require("util");
|
|
40
|
+
const stream_1 = require("stream");
|
|
41
|
+
const url_1 = require("url");
|
|
42
|
+
const events_1 = require("events");
|
|
43
|
+
const gunzip = (0, util_1.promisify)(zlib.gunzip);
|
|
44
|
+
const brotliDecompress = (0, util_1.promisify)(zlib.brotliDecompress);
|
|
45
|
+
const inflate = (0, util_1.promisify)(zlib.inflate);
|
|
46
|
+
const PROXIES = [
|
|
47
|
+
'https://snowy-hill-f293.apis8.workers.dev/',
|
|
48
|
+
'https://polished-resonance-0c97.apis9.workers.dev/',
|
|
49
|
+
'https://mute-wind-ee8d.apis10.workers.dev/',
|
|
50
|
+
'https://billowing-hall-ebe5.proxyserver2.workers.dev/',
|
|
51
|
+
'https://dark-shadow-1776.apis7.workers.dev/',
|
|
52
|
+
'https://aged-breeze-9d12.apis4.workers.dev/'
|
|
53
|
+
];
|
|
54
|
+
function getRandomProxy() {
|
|
55
|
+
return PROXIES[Math.floor(Math.random() * PROXIES.length)];
|
|
56
|
+
}
|
|
57
|
+
class CookieJar {
|
|
58
|
+
constructor() {
|
|
59
|
+
this.cookies = new Map();
|
|
60
|
+
}
|
|
61
|
+
setCookie(domain, name, value, options = {}) {
|
|
62
|
+
if (!this.cookies.has(domain))
|
|
63
|
+
this.cookies.set(domain, new Map());
|
|
64
|
+
this.cookies.get(domain).set(name, { value, ...options, path: options.path || '/', domain });
|
|
65
|
+
}
|
|
66
|
+
getCookies(domain, path = '/', secure = true) {
|
|
67
|
+
const domainCookies = this.cookies.get(domain);
|
|
68
|
+
if (!domainCookies)
|
|
69
|
+
return '';
|
|
70
|
+
const validCookies = [];
|
|
71
|
+
const now = new Date();
|
|
72
|
+
for (const [name, cookie] of domainCookies) {
|
|
73
|
+
if (cookie.expires && cookie.expires < now) {
|
|
74
|
+
domainCookies.delete(name);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (cookie.secure && !secure)
|
|
78
|
+
continue;
|
|
79
|
+
if (path.startsWith(cookie.path))
|
|
80
|
+
validCookies.push(`${name}=${cookie.value}`);
|
|
81
|
+
}
|
|
82
|
+
return validCookies.join('; ');
|
|
83
|
+
}
|
|
84
|
+
parseSetCookie(domain, setCookieHeaders) {
|
|
85
|
+
const headers = Array.isArray(setCookieHeaders) ? setCookieHeaders : [setCookieHeaders];
|
|
86
|
+
for (const header of headers) {
|
|
87
|
+
if (!header)
|
|
88
|
+
continue;
|
|
89
|
+
const parts = header.split(';').map(p => p.trim());
|
|
90
|
+
const [nameValue] = parts;
|
|
91
|
+
if (!nameValue)
|
|
92
|
+
continue;
|
|
93
|
+
const [name, value = ''] = nameValue.split('=', 2);
|
|
94
|
+
const options = { path: '/' };
|
|
95
|
+
for (let i = 1; i < parts.length; i++) {
|
|
96
|
+
const [key, val = ''] = parts[i].split('=', 2);
|
|
97
|
+
const lowerKey = key.toLowerCase();
|
|
98
|
+
if (lowerKey === 'expires')
|
|
99
|
+
options.expires = new Date(val);
|
|
100
|
+
else if (lowerKey === 'path')
|
|
101
|
+
options.path = val;
|
|
102
|
+
else if (lowerKey === 'secure')
|
|
103
|
+
options.secure = true;
|
|
104
|
+
else if (lowerKey === 'httponly')
|
|
105
|
+
options.httpOnly = true;
|
|
106
|
+
else if (lowerKey === 'samesite')
|
|
107
|
+
options.sameSite = val;
|
|
108
|
+
}
|
|
109
|
+
this.setCookie(domain, name, value, options);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
clear() {
|
|
113
|
+
this.cookies.clear();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
class FastProxiedClient {
|
|
117
|
+
constructor() {
|
|
118
|
+
this.cookieJar = new CookieJar();
|
|
119
|
+
}
|
|
120
|
+
async request(url, options = {}) {
|
|
121
|
+
const targetUrl = new url_1.URL(url);
|
|
122
|
+
const proxyBase = getRandomProxy();
|
|
123
|
+
const proxyUrl = new url_1.URL(proxyBase + url);
|
|
124
|
+
const startTime = Date.now();
|
|
125
|
+
const headers = {
|
|
126
|
+
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
|
|
127
|
+
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
|
|
128
|
+
'accept-language': 'en-US,en;q=0.9',
|
|
129
|
+
'accept-encoding': 'gzip, deflate, br, zstd',
|
|
130
|
+
...options.headers
|
|
131
|
+
};
|
|
132
|
+
const cookieString = this.cookieJar.getCookies(targetUrl.hostname, targetUrl.pathname, true);
|
|
133
|
+
if (cookieString) {
|
|
134
|
+
headers['cookie'] = headers['cookie'] ? `${headers['cookie']}; ${cookieString}` : cookieString;
|
|
135
|
+
}
|
|
136
|
+
if (options.cookies) {
|
|
137
|
+
const manualCookies = Object.entries(options.cookies).map(([k, v]) => `${k}=${v}`).join('; ');
|
|
138
|
+
headers['cookie'] = headers['cookie'] ? `${headers['cookie']}; ${manualCookies}` : manualCookies;
|
|
139
|
+
}
|
|
140
|
+
const reqOptions = {
|
|
141
|
+
method: options.method?.toUpperCase() || 'GET',
|
|
142
|
+
headers,
|
|
143
|
+
timeout: options.timeout || 30000
|
|
144
|
+
};
|
|
145
|
+
return new Promise((resolve, reject) => {
|
|
146
|
+
const req = https.request(proxyUrl.toString(), reqOptions, async (res) => {
|
|
147
|
+
const response = new events_1.EventEmitter();
|
|
148
|
+
response.statusCode = res.statusCode || 500;
|
|
149
|
+
response.headers = res.headers;
|
|
150
|
+
response.timing = {
|
|
151
|
+
socket: startTime,
|
|
152
|
+
lookup: startTime,
|
|
153
|
+
connect: startTime,
|
|
154
|
+
secureConnect: startTime,
|
|
155
|
+
response: Date.now() - startTime,
|
|
156
|
+
end: 0,
|
|
157
|
+
total: 0
|
|
158
|
+
};
|
|
159
|
+
response.fingerprints = { ja3: '', ja3Hash: '', akamai: '' };
|
|
160
|
+
if (res.headers['set-cookie']) {
|
|
161
|
+
this.cookieJar.parseSetCookie(targetUrl.hostname, res.headers['set-cookie']);
|
|
162
|
+
}
|
|
163
|
+
if (options.stream) {
|
|
164
|
+
response.body = res;
|
|
165
|
+
response.timing.end = Date.now() - startTime;
|
|
166
|
+
response.timing.total = response.timing.end;
|
|
167
|
+
resolve(response);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const chunks = [];
|
|
171
|
+
res.on('data', chunk => chunks.push(chunk));
|
|
172
|
+
res.on('end', async () => {
|
|
173
|
+
let body = Buffer.concat(chunks);
|
|
174
|
+
if (options.decompress !== false) {
|
|
175
|
+
const encoding = (res.headers['content-encoding'] || '').toString().toLowerCase();
|
|
176
|
+
try {
|
|
177
|
+
if (encoding.includes('gzip'))
|
|
178
|
+
body = await gunzip(body);
|
|
179
|
+
else if (encoding.includes('br'))
|
|
180
|
+
body = await brotliDecompress(body);
|
|
181
|
+
else if (encoding.includes('deflate'))
|
|
182
|
+
body = await inflate(body);
|
|
183
|
+
}
|
|
184
|
+
catch (e) { }
|
|
185
|
+
}
|
|
186
|
+
response.body = body;
|
|
187
|
+
try {
|
|
188
|
+
response.text = body.toString('utf-8');
|
|
189
|
+
}
|
|
190
|
+
catch { }
|
|
191
|
+
try {
|
|
192
|
+
if ((res.headers['content-type'] || '').includes('application/json')) {
|
|
193
|
+
response.json = JSON.parse(response.text);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
catch { }
|
|
197
|
+
response.timing.end = Date.now() - startTime;
|
|
198
|
+
response.timing.total = response.timing.end;
|
|
199
|
+
if (options.followRedirects !== false &&
|
|
200
|
+
[301, 302, 303, 307, 308].includes(response.statusCode) &&
|
|
201
|
+
(options.maxRedirects ?? 10) > 0) {
|
|
202
|
+
const location = res.headers['location'];
|
|
203
|
+
if (location) {
|
|
204
|
+
const newUrl = new url_1.URL(location, url).toString();
|
|
205
|
+
const newOptions = { ...options, maxRedirects: (options.maxRedirects ?? 10) - 1 };
|
|
206
|
+
return this.request(newUrl, newOptions).then(resolve).catch(reject);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
resolve(response);
|
|
210
|
+
});
|
|
211
|
+
res.on('error', reject);
|
|
212
|
+
});
|
|
213
|
+
req.on('error', reject);
|
|
214
|
+
req.on('timeout', () => {
|
|
215
|
+
req.destroy();
|
|
216
|
+
reject(new Error('Request timeout'));
|
|
217
|
+
});
|
|
218
|
+
if (options.body) {
|
|
219
|
+
if (typeof options.body === 'string' || Buffer.isBuffer(options.body)) {
|
|
220
|
+
req.end(options.body);
|
|
221
|
+
}
|
|
222
|
+
else if (options.body instanceof stream_1.Readable) {
|
|
223
|
+
options.body.pipe(req);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
req.end();
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
destroy() {
|
|
232
|
+
this.cookieJar.clear();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
exports.FastProxiedClient = FastProxiedClient;
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@putuofc/fastp",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc",
|
|
8
|
+
"prepublishOnly": "npm run build"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"typescript": "^5.9.3"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/node": "^25.0.3"
|
|
18
|
+
}
|
|
19
|
+
}
|