recker 1.0.79 ā 1.0.80-next.70ea84d
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/browser/browser/mini.d.ts +2 -2
- package/dist/browser/browser/recker-mini.d.ts +8 -8
- package/dist/browser/browser/recker.d.ts +11 -8
- package/dist/browser/browser/recker.js +54 -6
- package/dist/browser/core/client.d.ts +15 -10
- package/dist/browser/core/client.js +54 -38
- package/dist/browser/index.iife.min.js +129 -130
- package/dist/browser/index.min.js +129 -130
- package/dist/browser/index.mini.iife.js +5697 -636
- package/dist/browser/index.mini.iife.min.js +47 -48
- package/dist/browser/index.mini.min.js +47 -48
- package/dist/browser/index.mini.umd.js +5697 -636
- package/dist/browser/index.mini.umd.min.js +47 -48
- package/dist/browser/index.umd.min.js +129 -130
- package/dist/browser/mini.d.ts +2 -2
- package/dist/browser/plugins/proxy-rotator.d.ts +2 -2
- package/dist/browser/plugins/proxy-rotator.js +6 -28
- package/dist/browser/recker-mini.d.ts +8 -8
- package/dist/browser/recker.d.ts +11 -8
- package/dist/browser/recker.js +54 -6
- package/dist/browser/scrape/document.js +2 -2
- package/dist/browser/scrape/element.js +7 -1
- package/dist/browser/scrape/parser/nodes/html.js +1 -1
- package/dist/browser/scrape/spider.d.ts +52 -0
- package/dist/browser/scrape/spider.js +620 -38
- package/dist/browser/scrape/types.d.ts +2 -0
- package/dist/browser/search/google.d.ts +26 -1
- package/dist/browser/search/google.js +427 -45
- package/dist/browser/seo/analyzer.d.ts +1 -0
- package/dist/browser/seo/analyzer.js +144 -1
- package/dist/browser/seo/index.d.ts +1 -1
- package/dist/browser/seo/keyword-campaign-analyzer.d.ts +2 -0
- package/dist/browser/seo/keyword-campaign-analyzer.js +538 -0
- package/dist/browser/seo/keyword-campaign-seed-advanced.d.ts +17 -0
- package/dist/browser/seo/keyword-campaign-seed-advanced.js +269 -0
- package/dist/browser/seo/keyword-campaign-seed-core.d.ts +29 -0
- package/dist/browser/seo/keyword-campaign-seed-core.js +525 -0
- package/dist/browser/seo/keyword-campaign-shared.d.ts +165 -0
- package/dist/browser/seo/keyword-campaign-shared.js +59 -0
- package/dist/browser/seo/keyword-campaign.d.ts +4 -107
- package/dist/browser/seo/keyword-campaign.js +2 -380
- package/dist/browser/seo/keywords.js +5 -22
- package/dist/browser/seo/types.d.ts +19 -0
- package/dist/browser/transport/curl.d.ts +5 -1
- package/dist/browser/transport/curl.js +207 -50
- package/dist/browser/transport/undici.d.ts +4 -3
- package/dist/browser/transport/undici.js +123 -49
- package/dist/browser/types/index.d.ts +9 -3
- package/dist/browser/utils/binary-manager.js +26 -3
- package/dist/browser/utils/block-detector.d.ts +8 -0
- package/dist/browser/utils/block-detector.js +542 -7
- package/dist/cli/commands/hls-runner.js +5 -4
- package/dist/cli/commands/live-runner.js +5 -4
- package/dist/cli/commands/loadtest-runner.js +3 -2
- package/dist/cli/commands/search.d.ts +2 -0
- package/dist/cli/commands/search.js +105 -0
- package/dist/cli/commands/seo-runner.js +9 -7
- package/dist/cli/commands/seo.js +140 -1
- package/dist/cli/commands/serve.js +75 -131
- package/dist/cli/commands/server-runner.js +59 -82
- package/dist/cli/commands/spider-runner.d.ts +37 -1
- package/dist/cli/commands/spider-runner.js +134 -10
- package/dist/cli/commands/spider.d.ts +18 -1
- package/dist/cli/commands/spider.js +457 -27
- package/dist/cli/events/handlers/cli.js +30 -1
- package/dist/cli/events/handlers/tui.js +26 -0
- package/dist/cli/events/types.d.ts +27 -0
- package/dist/cli/handler.d.ts +2 -12
- package/dist/cli/handler.js +20 -15
- package/dist/cli/handlers/protocols.js +39 -12
- package/dist/cli/handlers/search.d.ts +2 -0
- package/dist/cli/handlers/search.js +171 -0
- package/dist/cli/handlers/seo-analyze.d.ts +1 -0
- package/dist/cli/handlers/seo-analyze.js +666 -0
- package/dist/cli/handlers/seo-robots.d.ts +1 -0
- package/dist/cli/handlers/seo-robots.js +76 -0
- package/dist/cli/handlers/seo-serp.d.ts +54 -0
- package/dist/cli/handlers/seo-serp.js +243 -0
- package/dist/cli/handlers/seo-sitemap.d.ts +1 -0
- package/dist/cli/handlers/seo-sitemap.js +55 -0
- package/dist/cli/handlers/seo-spider.d.ts +1 -0
- package/dist/cli/handlers/seo-spider.js +334 -0
- package/dist/cli/handlers/seo.d.ts +8 -4
- package/dist/cli/handlers/seo.js +294 -442
- package/dist/cli/handlers/spider.js +94 -17
- package/dist/cli/handlers/streaming.js +5 -1
- package/dist/cli/index.js +11 -2
- package/dist/cli/presets.d.ts +1 -1
- package/dist/cli/presets.js +15 -4
- package/dist/cli/tui/app.js +6 -1
- package/dist/cli/tui/components/rich-response.d.ts +72 -0
- package/dist/cli/tui/components/rich-response.js +117 -0
- package/dist/cli/tui/executor-commands/background.js +30 -24
- package/dist/cli/tui/executor-commands/testing.js +3 -2
- package/dist/cli/tui/hooks/useDomains.d.ts +17 -0
- package/dist/cli/tui/hooks/useHelp.js +15 -2
- package/dist/cli/tui/job-manager.d.ts +4 -4
- package/dist/cli/tui/job-manager.js +5 -1
- package/dist/cli/tui/spider-tui.d.ts +63 -0
- package/dist/cli/tui/spider-tui.js +120 -2
- package/dist/cli/types.d.ts +12 -0
- package/dist/cli/types.js +1 -0
- package/dist/cli/utils/option-helpers.d.ts +10 -0
- package/dist/cli/utils/option-helpers.js +63 -0
- package/dist/cli/utils/score-color.d.ts +11 -0
- package/dist/cli/utils/score-color.js +11 -0
- package/dist/cli/utils/serp-campaign.d.ts +53 -0
- package/dist/cli/utils/serp-campaign.js +53 -0
- package/dist/cli/utils/serp-config.d.ts +26 -0
- package/dist/cli/utils/serp-config.js +125 -0
- package/dist/core/client.d.ts +15 -10
- package/dist/core/client.js +54 -38
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/mcp/cli.js +35 -34
- package/dist/mcp/client.d.ts +2 -2
- package/dist/mcp/client.js +20 -2
- package/dist/mcp/contract.d.ts +1 -1
- package/dist/mcp/profiles.js +5 -1
- package/dist/mcp/prompts/index.js +8 -4
- package/dist/mcp/resources/index.js +46 -23
- package/dist/mcp/server.js +9 -6
- package/dist/mcp/tools/protocols.js +9 -2
- package/dist/mcp/tools/registry.js +13 -3
- package/dist/mcp/tools/seo.js +427 -2
- package/dist/mcp/types.d.ts +5 -1
- package/dist/plugins/proxy-rotator.d.ts +2 -2
- package/dist/plugins/proxy-rotator.js +6 -28
- package/dist/raffel/client.d.ts +38 -0
- package/dist/raffel/client.js +282 -0
- package/dist/raffel/index.d.ts +2 -0
- package/dist/raffel/index.js +2 -0
- package/dist/raffel/types.d.ts +40 -0
- package/dist/raffel/types.js +14 -0
- package/dist/recker.d.ts +13 -7
- package/dist/recker.js +58 -6
- package/dist/scrape/document.js +2 -2
- package/dist/scrape/element.js +7 -1
- package/dist/scrape/parser/nodes/html.js +1 -1
- package/dist/scrape/spider.d.ts +52 -0
- package/dist/scrape/spider.js +620 -38
- package/dist/scrape/types.d.ts +2 -0
- package/dist/search/google.d.ts +26 -1
- package/dist/search/google.js +427 -45
- package/dist/search/index.d.ts +1 -1
- package/dist/seo/analyzer.d.ts +1 -0
- package/dist/seo/analyzer.js +144 -1
- package/dist/seo/index.d.ts +1 -1
- package/dist/seo/keyword-campaign-analyzer.d.ts +2 -0
- package/dist/seo/keyword-campaign-analyzer.js +538 -0
- package/dist/seo/keyword-campaign-seed-advanced.d.ts +17 -0
- package/dist/seo/keyword-campaign-seed-advanced.js +269 -0
- package/dist/seo/keyword-campaign-seed-core.d.ts +29 -0
- package/dist/seo/keyword-campaign-seed-core.js +525 -0
- package/dist/seo/keyword-campaign-shared.d.ts +165 -0
- package/dist/seo/keyword-campaign-shared.js +59 -0
- package/dist/seo/keyword-campaign.d.ts +4 -107
- package/dist/seo/keyword-campaign.js +2 -380
- package/dist/seo/keywords.js +5 -22
- package/dist/seo/types.d.ts +19 -0
- package/dist/template/index.d.ts +1 -1
- package/dist/template/types.d.ts +0 -2
- package/dist/testing/index.d.ts +1 -22
- package/dist/testing/index.js +1 -11
- package/dist/transport/curl.d.ts +5 -1
- package/dist/transport/curl.js +207 -50
- package/dist/transport/undici.d.ts +4 -3
- package/dist/transport/undici.js +123 -49
- package/dist/types/index.d.ts +9 -3
- package/dist/utils/binary-manager.js +26 -3
- package/dist/utils/block-detector.d.ts +8 -0
- package/dist/utils/block-detector.js +542 -7
- package/dist/version.js +1 -1
- package/package.json +12 -1
- package/dist/testing/mock-dns-server.d.ts +0 -69
- package/dist/testing/mock-dns-server.js +0 -269
- package/dist/testing/mock-ftp-server.d.ts +0 -89
- package/dist/testing/mock-ftp-server.js +0 -562
- package/dist/testing/mock-hls-server.d.ts +0 -80
- package/dist/testing/mock-hls-server.js +0 -381
- package/dist/testing/mock-http-server.d.ts +0 -124
- package/dist/testing/mock-http-server.js +0 -343
- package/dist/testing/mock-proxy-server.d.ts +0 -108
- package/dist/testing/mock-proxy-server.js +0 -615
- package/dist/testing/mock-sse-server.d.ts +0 -76
- package/dist/testing/mock-sse-server.js +0 -291
- package/dist/testing/mock-telnet-server.d.ts +0 -59
- package/dist/testing/mock-telnet-server.js +0 -274
- package/dist/testing/mock-udp-server.d.ts +0 -43
- package/dist/testing/mock-udp-server.js +0 -188
- package/dist/testing/mock-websocket-server.d.ts +0 -76
- package/dist/testing/mock-websocket-server.js +0 -334
- package/dist/testing/mock-whois-server.d.ts +0 -56
- package/dist/testing/mock-whois-server.js +0 -234
- package/dist/testing/proxy-certs.d.ts +0 -19
- package/dist/testing/proxy-certs.js +0 -208
|
@@ -1,343 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'node:events';
|
|
2
|
-
import { createServer } from 'node:http';
|
|
3
|
-
export class MockHttpServer extends EventEmitter {
|
|
4
|
-
options;
|
|
5
|
-
httpServer = null;
|
|
6
|
-
routes = [];
|
|
7
|
-
_port = 0;
|
|
8
|
-
_started = false;
|
|
9
|
-
stats = {
|
|
10
|
-
totalRequests: 0,
|
|
11
|
-
requestsByMethod: {},
|
|
12
|
-
requestsByPath: {},
|
|
13
|
-
requestLog: [],
|
|
14
|
-
};
|
|
15
|
-
constructor(options = {}) {
|
|
16
|
-
super();
|
|
17
|
-
this.options = {
|
|
18
|
-
port: 0,
|
|
19
|
-
host: '127.0.0.1',
|
|
20
|
-
defaultResponse: { status: 404, body: { error: 'Not Found' } },
|
|
21
|
-
delay: 0,
|
|
22
|
-
cors: true,
|
|
23
|
-
corsOrigin: '*',
|
|
24
|
-
...options,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
get port() {
|
|
28
|
-
return this._port;
|
|
29
|
-
}
|
|
30
|
-
get address() {
|
|
31
|
-
return this.options.host;
|
|
32
|
-
}
|
|
33
|
-
get url() {
|
|
34
|
-
return `http://${this.options.host}:${this._port}`;
|
|
35
|
-
}
|
|
36
|
-
get isRunning() {
|
|
37
|
-
return this._started;
|
|
38
|
-
}
|
|
39
|
-
get statistics() {
|
|
40
|
-
return { ...this.stats };
|
|
41
|
-
}
|
|
42
|
-
get routeCount() {
|
|
43
|
-
return this.routes.length;
|
|
44
|
-
}
|
|
45
|
-
async start() {
|
|
46
|
-
if (this._started) {
|
|
47
|
-
throw new Error('Server already started');
|
|
48
|
-
}
|
|
49
|
-
return new Promise((resolve, reject) => {
|
|
50
|
-
this.httpServer = createServer((req, res) => this.handleRequest(req, res));
|
|
51
|
-
this.httpServer.on('error', reject);
|
|
52
|
-
this.httpServer.listen(this.options.port, this.options.host, () => {
|
|
53
|
-
const addr = this.httpServer.address();
|
|
54
|
-
this._port = typeof addr === 'string' ? 0 : addr?.port ?? 0;
|
|
55
|
-
this._started = true;
|
|
56
|
-
this.emit('listening', this._port);
|
|
57
|
-
resolve();
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
async stop() {
|
|
62
|
-
if (!this._started)
|
|
63
|
-
return;
|
|
64
|
-
return new Promise((resolve) => {
|
|
65
|
-
this.httpServer?.close(() => {
|
|
66
|
-
this._started = false;
|
|
67
|
-
this.httpServer = null;
|
|
68
|
-
this.emit('close');
|
|
69
|
-
resolve();
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
reset() {
|
|
74
|
-
this.routes = [];
|
|
75
|
-
this.stats = {
|
|
76
|
-
totalRequests: 0,
|
|
77
|
-
requestsByMethod: {},
|
|
78
|
-
requestsByPath: {},
|
|
79
|
-
requestLog: [],
|
|
80
|
-
};
|
|
81
|
-
this.emit('reset');
|
|
82
|
-
}
|
|
83
|
-
route(method, path, handler, options = {}) {
|
|
84
|
-
const pattern = this.pathToRegex(path);
|
|
85
|
-
this.routes.push({
|
|
86
|
-
method: method.toUpperCase(),
|
|
87
|
-
pattern,
|
|
88
|
-
pathPattern: path,
|
|
89
|
-
handler,
|
|
90
|
-
times: options.times,
|
|
91
|
-
callCount: 0,
|
|
92
|
-
});
|
|
93
|
-
return this;
|
|
94
|
-
}
|
|
95
|
-
get(path, handler, options) {
|
|
96
|
-
return this.route('GET', path, handler, options);
|
|
97
|
-
}
|
|
98
|
-
post(path, handler, options) {
|
|
99
|
-
return this.route('POST', path, handler, options);
|
|
100
|
-
}
|
|
101
|
-
put(path, handler, options) {
|
|
102
|
-
return this.route('PUT', path, handler, options);
|
|
103
|
-
}
|
|
104
|
-
patch(path, handler, options) {
|
|
105
|
-
return this.route('PATCH', path, handler, options);
|
|
106
|
-
}
|
|
107
|
-
delete(path, handler, options) {
|
|
108
|
-
return this.route('DELETE', path, handler, options);
|
|
109
|
-
}
|
|
110
|
-
head(path, handler, options) {
|
|
111
|
-
return this.route('HEAD', path, handler, options);
|
|
112
|
-
}
|
|
113
|
-
optionsRoute(path, handler, options) {
|
|
114
|
-
return this.route('OPTIONS', path, handler, options);
|
|
115
|
-
}
|
|
116
|
-
trace(path, handler, options) {
|
|
117
|
-
return this.route('TRACE', path, handler, options);
|
|
118
|
-
}
|
|
119
|
-
connect(path, handler, options) {
|
|
120
|
-
return this.route('CONNECT', path, handler, options);
|
|
121
|
-
}
|
|
122
|
-
purge(path, handler, options) {
|
|
123
|
-
return this.route('PURGE', path, handler, options);
|
|
124
|
-
}
|
|
125
|
-
any(path, handler, options) {
|
|
126
|
-
return this.route('*', path, handler, options);
|
|
127
|
-
}
|
|
128
|
-
removeRoute(method, path) {
|
|
129
|
-
const index = this.routes.findIndex((r) => r.method === method.toUpperCase() && r.pathPattern === path);
|
|
130
|
-
if (index >= 0) {
|
|
131
|
-
this.routes.splice(index, 1);
|
|
132
|
-
return true;
|
|
133
|
-
}
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
|
-
clearRoutes() {
|
|
137
|
-
this.routes = [];
|
|
138
|
-
}
|
|
139
|
-
async handleRequest(req, res) {
|
|
140
|
-
const startTime = Date.now();
|
|
141
|
-
const method = req.method?.toUpperCase() ?? 'GET';
|
|
142
|
-
const urlParts = new URL(req.url ?? '/', `http://${req.headers.host}`);
|
|
143
|
-
const path = urlParts.pathname;
|
|
144
|
-
const query = Object.fromEntries(urlParts.searchParams);
|
|
145
|
-
this.stats.totalRequests++;
|
|
146
|
-
this.stats.requestsByMethod[method] = (this.stats.requestsByMethod[method] ?? 0) + 1;
|
|
147
|
-
this.stats.requestsByPath[path] = (this.stats.requestsByPath[path] ?? 0) + 1;
|
|
148
|
-
if (this.options.cors && method === 'OPTIONS') {
|
|
149
|
-
this.sendCorsHeaders(res);
|
|
150
|
-
res.writeHead(204);
|
|
151
|
-
res.end();
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
const body = await this.parseBody(req);
|
|
155
|
-
const mockReq = {
|
|
156
|
-
method,
|
|
157
|
-
path,
|
|
158
|
-
query,
|
|
159
|
-
headers: req.headers,
|
|
160
|
-
body,
|
|
161
|
-
raw: req,
|
|
162
|
-
};
|
|
163
|
-
this.emit('request', mockReq);
|
|
164
|
-
const route = this.findRoute(method, path);
|
|
165
|
-
let response;
|
|
166
|
-
if (route) {
|
|
167
|
-
route.callCount++;
|
|
168
|
-
if (route.times !== undefined && route.callCount > route.times) {
|
|
169
|
-
response = this.options.defaultResponse;
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
response = typeof route.handler === 'function'
|
|
173
|
-
? await route.handler(mockReq)
|
|
174
|
-
: route.handler;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
response = this.options.defaultResponse;
|
|
179
|
-
}
|
|
180
|
-
await this.sendResponse(res, response);
|
|
181
|
-
const duration = Date.now() - startTime;
|
|
182
|
-
this.stats.requestLog.push({
|
|
183
|
-
method,
|
|
184
|
-
path,
|
|
185
|
-
status: response.status ?? 200,
|
|
186
|
-
timestamp: startTime,
|
|
187
|
-
duration,
|
|
188
|
-
});
|
|
189
|
-
this.emit('response', mockReq, response, duration);
|
|
190
|
-
}
|
|
191
|
-
findRoute(method, path) {
|
|
192
|
-
for (const route of this.routes) {
|
|
193
|
-
if ((route.method === method || route.method === '*') && route.pattern.test(path)) {
|
|
194
|
-
return route;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
return undefined;
|
|
198
|
-
}
|
|
199
|
-
async sendResponse(res, response) {
|
|
200
|
-
if (response.drop) {
|
|
201
|
-
res.destroy();
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
const delay = response.delay ?? this.options.delay;
|
|
205
|
-
if (delay > 0) {
|
|
206
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
207
|
-
}
|
|
208
|
-
if (this.options.cors) {
|
|
209
|
-
this.sendCorsHeaders(res);
|
|
210
|
-
}
|
|
211
|
-
const status = response.status ?? 200;
|
|
212
|
-
const headers = {
|
|
213
|
-
'Content-Type': 'application/json',
|
|
214
|
-
...response.headers,
|
|
215
|
-
};
|
|
216
|
-
if (response.stream) {
|
|
217
|
-
res.writeHead(status, headers);
|
|
218
|
-
for (const chunk of response.stream.chunks) {
|
|
219
|
-
res.write(chunk);
|
|
220
|
-
await new Promise((resolve) => setTimeout(resolve, response.stream.interval));
|
|
221
|
-
}
|
|
222
|
-
res.end();
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
let body = '';
|
|
226
|
-
if (response.body !== undefined) {
|
|
227
|
-
if (typeof response.body === 'string' || Buffer.isBuffer(response.body)) {
|
|
228
|
-
body = response.body;
|
|
229
|
-
if (typeof response.body === 'string' && !headers['Content-Type'].includes('json')) {
|
|
230
|
-
headers['Content-Type'] = 'text/plain';
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
else {
|
|
234
|
-
body = JSON.stringify(response.body);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
headers['Content-Length'] = String(Buffer.byteLength(body));
|
|
238
|
-
res.writeHead(status, headers);
|
|
239
|
-
res.end(body);
|
|
240
|
-
}
|
|
241
|
-
sendCorsHeaders(res) {
|
|
242
|
-
res.setHeader('Access-Control-Allow-Origin', this.options.corsOrigin);
|
|
243
|
-
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS');
|
|
244
|
-
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
245
|
-
res.setHeader('Access-Control-Max-Age', '86400');
|
|
246
|
-
}
|
|
247
|
-
async parseBody(req) {
|
|
248
|
-
return new Promise((resolve) => {
|
|
249
|
-
const chunks = [];
|
|
250
|
-
req.on('data', (chunk) => chunks.push(chunk));
|
|
251
|
-
req.on('end', () => {
|
|
252
|
-
if (chunks.length === 0) {
|
|
253
|
-
resolve(undefined);
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
const raw = Buffer.concat(chunks).toString('utf-8');
|
|
257
|
-
const contentType = req.headers['content-type'] ?? '';
|
|
258
|
-
if (contentType.includes('application/json')) {
|
|
259
|
-
try {
|
|
260
|
-
resolve(JSON.parse(raw));
|
|
261
|
-
}
|
|
262
|
-
catch {
|
|
263
|
-
resolve(raw);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
else {
|
|
267
|
-
resolve(raw);
|
|
268
|
-
}
|
|
269
|
-
});
|
|
270
|
-
req.on('error', () => resolve(undefined));
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
pathToRegex(path) {
|
|
274
|
-
const escaped = path.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
275
|
-
const withParams = escaped.replace(/:(\w+)/g, '([^/]+)');
|
|
276
|
-
return new RegExp(`^${withParams}$`);
|
|
277
|
-
}
|
|
278
|
-
async waitForRequests(count, timeout = 5000) {
|
|
279
|
-
const start = Date.now();
|
|
280
|
-
while (this.stats.totalRequests < count) {
|
|
281
|
-
if (Date.now() - start > timeout) {
|
|
282
|
-
throw new Error(`Timeout waiting for ${count} requests (have ${this.stats.totalRequests})`);
|
|
283
|
-
}
|
|
284
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
getCallCount(method, path) {
|
|
288
|
-
const route = this.routes.find((r) => r.method === method.toUpperCase() && r.pathPattern === path);
|
|
289
|
-
return route?.callCount ?? 0;
|
|
290
|
-
}
|
|
291
|
-
static async create(options = {}) {
|
|
292
|
-
const server = new MockHttpServer(options);
|
|
293
|
-
await server.start();
|
|
294
|
-
return server;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
export async function createMockHttpServer(routes, options) {
|
|
298
|
-
const server = new MockHttpServer(options);
|
|
299
|
-
if (routes) {
|
|
300
|
-
for (const [key, response] of Object.entries(routes)) {
|
|
301
|
-
const [method, path] = key.includes(' ') ? key.split(' ') : ['GET', key];
|
|
302
|
-
server.route(method, path, response);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
await server.start();
|
|
306
|
-
return server;
|
|
307
|
-
}
|
|
308
|
-
export async function createWebhookServer(options = {}) {
|
|
309
|
-
const { log = true, logger, status = 204, ...serverOptions } = options;
|
|
310
|
-
const server = new MockHttpServer(serverOptions);
|
|
311
|
-
const webhooks = [];
|
|
312
|
-
const handleWebhook = (req, id) => {
|
|
313
|
-
const payload = {
|
|
314
|
-
id,
|
|
315
|
-
timestamp: new Date(),
|
|
316
|
-
method: req.method,
|
|
317
|
-
path: req.path,
|
|
318
|
-
headers: req.headers,
|
|
319
|
-
body: req.body,
|
|
320
|
-
};
|
|
321
|
-
webhooks.push(payload);
|
|
322
|
-
if (logger) {
|
|
323
|
-
logger(payload);
|
|
324
|
-
}
|
|
325
|
-
else if (log) {
|
|
326
|
-
const idStr = id ? ` [${id}]` : '';
|
|
327
|
-
console.log(`\nš„ Webhook received${idStr} at ${payload.timestamp.toISOString()}`);
|
|
328
|
-
console.log(` Path: ${req.path}`);
|
|
329
|
-
if (req.body !== undefined) {
|
|
330
|
-
console.log(` Body:`, typeof req.body === 'object' ? JSON.stringify(req.body, null, 2) : req.body);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
return { status };
|
|
334
|
-
};
|
|
335
|
-
server.any('/', (req) => handleWebhook(req, null));
|
|
336
|
-
server.any('/:id', (req) => {
|
|
337
|
-
const match = req.path.match(/^\/([^/]+)$/);
|
|
338
|
-
const id = match ? match[1] : null;
|
|
339
|
-
return handleWebhook(req, id);
|
|
340
|
-
});
|
|
341
|
-
await server.start();
|
|
342
|
-
return Object.assign(server, { webhooks });
|
|
343
|
-
}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'node:events';
|
|
2
|
-
export type ProxyMode = 'forward' | 'intercept';
|
|
3
|
-
export interface ProxyServerOptions {
|
|
4
|
-
port?: number;
|
|
5
|
-
host?: string;
|
|
6
|
-
mode?: ProxyMode;
|
|
7
|
-
mtls?: {
|
|
8
|
-
enabled: boolean;
|
|
9
|
-
caCert?: string;
|
|
10
|
-
caKey?: string;
|
|
11
|
-
clientCert?: string;
|
|
12
|
-
clientKey?: string;
|
|
13
|
-
requireClientCert?: boolean;
|
|
14
|
-
};
|
|
15
|
-
intercept?: {
|
|
16
|
-
logPayloads?: boolean;
|
|
17
|
-
maxPayloadSize?: number;
|
|
18
|
-
modifyRequest?: (req: ProxyRequest) => ProxyRequest | Promise<ProxyRequest>;
|
|
19
|
-
modifyResponse?: (res: ProxyResponse) => ProxyResponse | Promise<ProxyResponse>;
|
|
20
|
-
};
|
|
21
|
-
timeout?: number;
|
|
22
|
-
verbose?: boolean;
|
|
23
|
-
}
|
|
24
|
-
export interface ProxyRequest {
|
|
25
|
-
id: string;
|
|
26
|
-
timestamp: number;
|
|
27
|
-
method: string;
|
|
28
|
-
url: string;
|
|
29
|
-
headers: Record<string, string>;
|
|
30
|
-
body?: Buffer;
|
|
31
|
-
clientIp: string;
|
|
32
|
-
targetHost: string;
|
|
33
|
-
targetPort: number;
|
|
34
|
-
isHttps: boolean;
|
|
35
|
-
}
|
|
36
|
-
export interface ProxyResponse {
|
|
37
|
-
id: string;
|
|
38
|
-
timestamp: number;
|
|
39
|
-
statusCode: number;
|
|
40
|
-
statusText: string;
|
|
41
|
-
headers: Record<string, string>;
|
|
42
|
-
body?: Buffer;
|
|
43
|
-
latency: number;
|
|
44
|
-
size: number;
|
|
45
|
-
}
|
|
46
|
-
export interface ProxyError {
|
|
47
|
-
requestId?: string;
|
|
48
|
-
type: 'connection' | 'timeout' | 'tls' | 'upstream' | 'parse';
|
|
49
|
-
message: string;
|
|
50
|
-
error?: Error;
|
|
51
|
-
targetHost?: string;
|
|
52
|
-
targetPort?: number;
|
|
53
|
-
}
|
|
54
|
-
export interface ProxyStats {
|
|
55
|
-
totalRequests: number;
|
|
56
|
-
successCount: number;
|
|
57
|
-
errorCount: number;
|
|
58
|
-
bytesIn: number;
|
|
59
|
-
bytesOut: number;
|
|
60
|
-
avgLatency: number;
|
|
61
|
-
requestsPerSecond: number;
|
|
62
|
-
activeConnections: number;
|
|
63
|
-
byStatusCode: Record<number, number>;
|
|
64
|
-
byMethod: Record<string, number>;
|
|
65
|
-
topHosts: Array<{
|
|
66
|
-
host: string;
|
|
67
|
-
count: number;
|
|
68
|
-
}>;
|
|
69
|
-
}
|
|
70
|
-
export declare class MockProxyServer extends EventEmitter {
|
|
71
|
-
private options;
|
|
72
|
-
private httpServer;
|
|
73
|
-
private _port;
|
|
74
|
-
private _started;
|
|
75
|
-
private _stats;
|
|
76
|
-
private hostCounts;
|
|
77
|
-
private latencies;
|
|
78
|
-
private requestTimestamps;
|
|
79
|
-
private activeConnections;
|
|
80
|
-
private certCache;
|
|
81
|
-
constructor(options?: ProxyServerOptions);
|
|
82
|
-
get port(): number;
|
|
83
|
-
get address(): string;
|
|
84
|
-
get url(): string;
|
|
85
|
-
get isRunning(): boolean;
|
|
86
|
-
get mode(): ProxyMode;
|
|
87
|
-
get stats(): ProxyStats;
|
|
88
|
-
start(): Promise<void>;
|
|
89
|
-
stop(): Promise<void>;
|
|
90
|
-
reset(): void;
|
|
91
|
-
private handleHttpRequest;
|
|
92
|
-
private forwardHttpRequest;
|
|
93
|
-
private handleConnect;
|
|
94
|
-
private tunnel;
|
|
95
|
-
private intercept;
|
|
96
|
-
private handleInterceptedConnection;
|
|
97
|
-
private forwardInterceptedRequest;
|
|
98
|
-
private getCertificateForHost;
|
|
99
|
-
private sendError;
|
|
100
|
-
private emitError;
|
|
101
|
-
private updateStats;
|
|
102
|
-
private updateLatency;
|
|
103
|
-
private headersToRecord;
|
|
104
|
-
private readBody;
|
|
105
|
-
static create(options?: ProxyServerOptions): Promise<MockProxyServer>;
|
|
106
|
-
}
|
|
107
|
-
export declare function createForwardProxy(port?: number, options?: Omit<ProxyServerOptions, 'port' | 'mode'>): Promise<MockProxyServer>;
|
|
108
|
-
export declare function createInterceptProxy(port?: number, options?: Omit<ProxyServerOptions, 'port' | 'mode'>): Promise<MockProxyServer>;
|