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.
Files changed (196) hide show
  1. package/dist/browser/browser/mini.d.ts +2 -2
  2. package/dist/browser/browser/recker-mini.d.ts +8 -8
  3. package/dist/browser/browser/recker.d.ts +11 -8
  4. package/dist/browser/browser/recker.js +54 -6
  5. package/dist/browser/core/client.d.ts +15 -10
  6. package/dist/browser/core/client.js +54 -38
  7. package/dist/browser/index.iife.min.js +129 -130
  8. package/dist/browser/index.min.js +129 -130
  9. package/dist/browser/index.mini.iife.js +5697 -636
  10. package/dist/browser/index.mini.iife.min.js +47 -48
  11. package/dist/browser/index.mini.min.js +47 -48
  12. package/dist/browser/index.mini.umd.js +5697 -636
  13. package/dist/browser/index.mini.umd.min.js +47 -48
  14. package/dist/browser/index.umd.min.js +129 -130
  15. package/dist/browser/mini.d.ts +2 -2
  16. package/dist/browser/plugins/proxy-rotator.d.ts +2 -2
  17. package/dist/browser/plugins/proxy-rotator.js +6 -28
  18. package/dist/browser/recker-mini.d.ts +8 -8
  19. package/dist/browser/recker.d.ts +11 -8
  20. package/dist/browser/recker.js +54 -6
  21. package/dist/browser/scrape/document.js +2 -2
  22. package/dist/browser/scrape/element.js +7 -1
  23. package/dist/browser/scrape/parser/nodes/html.js +1 -1
  24. package/dist/browser/scrape/spider.d.ts +52 -0
  25. package/dist/browser/scrape/spider.js +620 -38
  26. package/dist/browser/scrape/types.d.ts +2 -0
  27. package/dist/browser/search/google.d.ts +26 -1
  28. package/dist/browser/search/google.js +427 -45
  29. package/dist/browser/seo/analyzer.d.ts +1 -0
  30. package/dist/browser/seo/analyzer.js +144 -1
  31. package/dist/browser/seo/index.d.ts +1 -1
  32. package/dist/browser/seo/keyword-campaign-analyzer.d.ts +2 -0
  33. package/dist/browser/seo/keyword-campaign-analyzer.js +538 -0
  34. package/dist/browser/seo/keyword-campaign-seed-advanced.d.ts +17 -0
  35. package/dist/browser/seo/keyword-campaign-seed-advanced.js +269 -0
  36. package/dist/browser/seo/keyword-campaign-seed-core.d.ts +29 -0
  37. package/dist/browser/seo/keyword-campaign-seed-core.js +525 -0
  38. package/dist/browser/seo/keyword-campaign-shared.d.ts +165 -0
  39. package/dist/browser/seo/keyword-campaign-shared.js +59 -0
  40. package/dist/browser/seo/keyword-campaign.d.ts +4 -107
  41. package/dist/browser/seo/keyword-campaign.js +2 -380
  42. package/dist/browser/seo/keywords.js +5 -22
  43. package/dist/browser/seo/types.d.ts +19 -0
  44. package/dist/browser/transport/curl.d.ts +5 -1
  45. package/dist/browser/transport/curl.js +207 -50
  46. package/dist/browser/transport/undici.d.ts +4 -3
  47. package/dist/browser/transport/undici.js +123 -49
  48. package/dist/browser/types/index.d.ts +9 -3
  49. package/dist/browser/utils/binary-manager.js +26 -3
  50. package/dist/browser/utils/block-detector.d.ts +8 -0
  51. package/dist/browser/utils/block-detector.js +542 -7
  52. package/dist/cli/commands/hls-runner.js +5 -4
  53. package/dist/cli/commands/live-runner.js +5 -4
  54. package/dist/cli/commands/loadtest-runner.js +3 -2
  55. package/dist/cli/commands/search.d.ts +2 -0
  56. package/dist/cli/commands/search.js +105 -0
  57. package/dist/cli/commands/seo-runner.js +9 -7
  58. package/dist/cli/commands/seo.js +140 -1
  59. package/dist/cli/commands/serve.js +75 -131
  60. package/dist/cli/commands/server-runner.js +59 -82
  61. package/dist/cli/commands/spider-runner.d.ts +37 -1
  62. package/dist/cli/commands/spider-runner.js +134 -10
  63. package/dist/cli/commands/spider.d.ts +18 -1
  64. package/dist/cli/commands/spider.js +457 -27
  65. package/dist/cli/events/handlers/cli.js +30 -1
  66. package/dist/cli/events/handlers/tui.js +26 -0
  67. package/dist/cli/events/types.d.ts +27 -0
  68. package/dist/cli/handler.d.ts +2 -12
  69. package/dist/cli/handler.js +20 -15
  70. package/dist/cli/handlers/protocols.js +39 -12
  71. package/dist/cli/handlers/search.d.ts +2 -0
  72. package/dist/cli/handlers/search.js +171 -0
  73. package/dist/cli/handlers/seo-analyze.d.ts +1 -0
  74. package/dist/cli/handlers/seo-analyze.js +666 -0
  75. package/dist/cli/handlers/seo-robots.d.ts +1 -0
  76. package/dist/cli/handlers/seo-robots.js +76 -0
  77. package/dist/cli/handlers/seo-serp.d.ts +54 -0
  78. package/dist/cli/handlers/seo-serp.js +243 -0
  79. package/dist/cli/handlers/seo-sitemap.d.ts +1 -0
  80. package/dist/cli/handlers/seo-sitemap.js +55 -0
  81. package/dist/cli/handlers/seo-spider.d.ts +1 -0
  82. package/dist/cli/handlers/seo-spider.js +334 -0
  83. package/dist/cli/handlers/seo.d.ts +8 -4
  84. package/dist/cli/handlers/seo.js +294 -442
  85. package/dist/cli/handlers/spider.js +94 -17
  86. package/dist/cli/handlers/streaming.js +5 -1
  87. package/dist/cli/index.js +11 -2
  88. package/dist/cli/presets.d.ts +1 -1
  89. package/dist/cli/presets.js +15 -4
  90. package/dist/cli/tui/app.js +6 -1
  91. package/dist/cli/tui/components/rich-response.d.ts +72 -0
  92. package/dist/cli/tui/components/rich-response.js +117 -0
  93. package/dist/cli/tui/executor-commands/background.js +30 -24
  94. package/dist/cli/tui/executor-commands/testing.js +3 -2
  95. package/dist/cli/tui/hooks/useDomains.d.ts +17 -0
  96. package/dist/cli/tui/hooks/useHelp.js +15 -2
  97. package/dist/cli/tui/job-manager.d.ts +4 -4
  98. package/dist/cli/tui/job-manager.js +5 -1
  99. package/dist/cli/tui/spider-tui.d.ts +63 -0
  100. package/dist/cli/tui/spider-tui.js +120 -2
  101. package/dist/cli/types.d.ts +12 -0
  102. package/dist/cli/types.js +1 -0
  103. package/dist/cli/utils/option-helpers.d.ts +10 -0
  104. package/dist/cli/utils/option-helpers.js +63 -0
  105. package/dist/cli/utils/score-color.d.ts +11 -0
  106. package/dist/cli/utils/score-color.js +11 -0
  107. package/dist/cli/utils/serp-campaign.d.ts +53 -0
  108. package/dist/cli/utils/serp-campaign.js +53 -0
  109. package/dist/cli/utils/serp-config.d.ts +26 -0
  110. package/dist/cli/utils/serp-config.js +125 -0
  111. package/dist/core/client.d.ts +15 -10
  112. package/dist/core/client.js +54 -38
  113. package/dist/index.d.ts +1 -0
  114. package/dist/index.js +1 -0
  115. package/dist/mcp/cli.js +35 -34
  116. package/dist/mcp/client.d.ts +2 -2
  117. package/dist/mcp/client.js +20 -2
  118. package/dist/mcp/contract.d.ts +1 -1
  119. package/dist/mcp/profiles.js +5 -1
  120. package/dist/mcp/prompts/index.js +8 -4
  121. package/dist/mcp/resources/index.js +46 -23
  122. package/dist/mcp/server.js +9 -6
  123. package/dist/mcp/tools/protocols.js +9 -2
  124. package/dist/mcp/tools/registry.js +13 -3
  125. package/dist/mcp/tools/seo.js +427 -2
  126. package/dist/mcp/types.d.ts +5 -1
  127. package/dist/plugins/proxy-rotator.d.ts +2 -2
  128. package/dist/plugins/proxy-rotator.js +6 -28
  129. package/dist/raffel/client.d.ts +38 -0
  130. package/dist/raffel/client.js +282 -0
  131. package/dist/raffel/index.d.ts +2 -0
  132. package/dist/raffel/index.js +2 -0
  133. package/dist/raffel/types.d.ts +40 -0
  134. package/dist/raffel/types.js +14 -0
  135. package/dist/recker.d.ts +13 -7
  136. package/dist/recker.js +58 -6
  137. package/dist/scrape/document.js +2 -2
  138. package/dist/scrape/element.js +7 -1
  139. package/dist/scrape/parser/nodes/html.js +1 -1
  140. package/dist/scrape/spider.d.ts +52 -0
  141. package/dist/scrape/spider.js +620 -38
  142. package/dist/scrape/types.d.ts +2 -0
  143. package/dist/search/google.d.ts +26 -1
  144. package/dist/search/google.js +427 -45
  145. package/dist/search/index.d.ts +1 -1
  146. package/dist/seo/analyzer.d.ts +1 -0
  147. package/dist/seo/analyzer.js +144 -1
  148. package/dist/seo/index.d.ts +1 -1
  149. package/dist/seo/keyword-campaign-analyzer.d.ts +2 -0
  150. package/dist/seo/keyword-campaign-analyzer.js +538 -0
  151. package/dist/seo/keyword-campaign-seed-advanced.d.ts +17 -0
  152. package/dist/seo/keyword-campaign-seed-advanced.js +269 -0
  153. package/dist/seo/keyword-campaign-seed-core.d.ts +29 -0
  154. package/dist/seo/keyword-campaign-seed-core.js +525 -0
  155. package/dist/seo/keyword-campaign-shared.d.ts +165 -0
  156. package/dist/seo/keyword-campaign-shared.js +59 -0
  157. package/dist/seo/keyword-campaign.d.ts +4 -107
  158. package/dist/seo/keyword-campaign.js +2 -380
  159. package/dist/seo/keywords.js +5 -22
  160. package/dist/seo/types.d.ts +19 -0
  161. package/dist/template/index.d.ts +1 -1
  162. package/dist/template/types.d.ts +0 -2
  163. package/dist/testing/index.d.ts +1 -22
  164. package/dist/testing/index.js +1 -11
  165. package/dist/transport/curl.d.ts +5 -1
  166. package/dist/transport/curl.js +207 -50
  167. package/dist/transport/undici.d.ts +4 -3
  168. package/dist/transport/undici.js +123 -49
  169. package/dist/types/index.d.ts +9 -3
  170. package/dist/utils/binary-manager.js +26 -3
  171. package/dist/utils/block-detector.d.ts +8 -0
  172. package/dist/utils/block-detector.js +542 -7
  173. package/dist/version.js +1 -1
  174. package/package.json +12 -1
  175. package/dist/testing/mock-dns-server.d.ts +0 -69
  176. package/dist/testing/mock-dns-server.js +0 -269
  177. package/dist/testing/mock-ftp-server.d.ts +0 -89
  178. package/dist/testing/mock-ftp-server.js +0 -562
  179. package/dist/testing/mock-hls-server.d.ts +0 -80
  180. package/dist/testing/mock-hls-server.js +0 -381
  181. package/dist/testing/mock-http-server.d.ts +0 -124
  182. package/dist/testing/mock-http-server.js +0 -343
  183. package/dist/testing/mock-proxy-server.d.ts +0 -108
  184. package/dist/testing/mock-proxy-server.js +0 -615
  185. package/dist/testing/mock-sse-server.d.ts +0 -76
  186. package/dist/testing/mock-sse-server.js +0 -291
  187. package/dist/testing/mock-telnet-server.d.ts +0 -59
  188. package/dist/testing/mock-telnet-server.js +0 -274
  189. package/dist/testing/mock-udp-server.d.ts +0 -43
  190. package/dist/testing/mock-udp-server.js +0 -188
  191. package/dist/testing/mock-websocket-server.d.ts +0 -76
  192. package/dist/testing/mock-websocket-server.js +0 -334
  193. package/dist/testing/mock-whois-server.d.ts +0 -56
  194. package/dist/testing/mock-whois-server.js +0 -234
  195. package/dist/testing/proxy-certs.d.ts +0 -19
  196. package/dist/testing/proxy-certs.js +0 -208
@@ -1,188 +0,0 @@
1
- import dgram from 'node:dgram';
2
- import { EventEmitter } from 'node:events';
3
- export class MockUDPServer extends EventEmitter {
4
- socket = null;
5
- options;
6
- responses = new Map();
7
- _port = 0;
8
- _receivedMessages = [];
9
- _started = false;
10
- constructor(options = {}) {
11
- super();
12
- this.options = {
13
- port: 0,
14
- host: '127.0.0.1',
15
- type: 'udp4',
16
- echo: true,
17
- delay: 0,
18
- dropRate: 0,
19
- ...options,
20
- };
21
- }
22
- get port() {
23
- return this._port;
24
- }
25
- get address() {
26
- return this.options.host;
27
- }
28
- get isRunning() {
29
- return this._started;
30
- }
31
- get receivedMessages() {
32
- return [...this._receivedMessages];
33
- }
34
- get messageCount() {
35
- return this._receivedMessages.length;
36
- }
37
- async start() {
38
- if (this._started) {
39
- throw new Error('Server already started');
40
- }
41
- this.socket = dgram.createSocket(this.options.type);
42
- this.socket.on('message', async (msg, rinfo) => {
43
- this._receivedMessages.push({
44
- data: msg,
45
- rinfo,
46
- timestamp: Date.now(),
47
- });
48
- this.emit('message', msg, rinfo);
49
- if (this.options.dropRate > 0 && Math.random() < this.options.dropRate) {
50
- this.emit('dropped', msg, rinfo);
51
- return;
52
- }
53
- if (this.options.delay > 0) {
54
- await new Promise((resolve) => setTimeout(resolve, this.options.delay));
55
- }
56
- const response = this.getResponse(msg, rinfo);
57
- if (response) {
58
- this.socket.send(response, rinfo.port, rinfo.address, (err) => {
59
- if (err) {
60
- this.emit('error', err);
61
- }
62
- else {
63
- this.emit('sent', response, rinfo);
64
- }
65
- });
66
- }
67
- });
68
- this.socket.on('error', (err) => {
69
- this.emit('error', err);
70
- });
71
- return new Promise((resolve) => {
72
- this.socket.bind(this.options.port, this.options.host, () => {
73
- const addr = this.socket.address();
74
- this._port = typeof addr === 'string' ? 0 : addr.port;
75
- this._started = true;
76
- this.emit('listening', this._port);
77
- resolve();
78
- });
79
- });
80
- }
81
- async stop() {
82
- if (!this._started || !this.socket) {
83
- return;
84
- }
85
- return new Promise((resolve) => {
86
- this.socket.close(() => {
87
- this._started = false;
88
- this.socket = null;
89
- this.emit('close');
90
- resolve();
91
- });
92
- });
93
- }
94
- setResponse(pattern, response) {
95
- const key = pattern instanceof RegExp ? pattern.source : pattern;
96
- const handler = typeof response === 'function'
97
- ? (msg, rinfo) => {
98
- const result = response(msg, rinfo);
99
- if (result === null)
100
- return null;
101
- return typeof result === 'string' ? Buffer.from(result) : result;
102
- }
103
- : typeof response === 'string'
104
- ? Buffer.from(response)
105
- : response;
106
- this.responses.set(key, handler);
107
- }
108
- setDelay(delay) {
109
- this.options.delay = delay;
110
- }
111
- setDropRate(rate) {
112
- this.options.dropRate = Math.max(0, Math.min(1, rate));
113
- }
114
- setEcho(enabled) {
115
- this.options.echo = enabled;
116
- }
117
- clearMessages() {
118
- this._receivedMessages = [];
119
- }
120
- clearResponses() {
121
- this.responses.clear();
122
- }
123
- reset() {
124
- this.clearMessages();
125
- this.clearResponses();
126
- this.options.delay = 0;
127
- this.options.dropRate = 0;
128
- this.options.echo = true;
129
- }
130
- getResponse(msg, rinfo) {
131
- const msgStr = msg.toString();
132
- for (const [pattern, response] of this.responses) {
133
- const regex = new RegExp(pattern);
134
- if (regex.test(msgStr)) {
135
- if (typeof response === 'function') {
136
- return response(msg, rinfo);
137
- }
138
- return response;
139
- }
140
- }
141
- if (this.options.echo) {
142
- return msg;
143
- }
144
- return null;
145
- }
146
- async sendTo(data, port, address = '127.0.0.1') {
147
- if (!this.socket || !this._started) {
148
- throw new Error('Server not started');
149
- }
150
- const buffer = typeof data === 'string' ? Buffer.from(data) : data;
151
- return new Promise((resolve, reject) => {
152
- this.socket.send(buffer, port, address, (err) => {
153
- if (err) {
154
- reject(err);
155
- }
156
- else {
157
- resolve();
158
- }
159
- });
160
- });
161
- }
162
- async waitForMessages(count, timeout = 5000) {
163
- const startTime = Date.now();
164
- while (this._receivedMessages.length < count) {
165
- if (Date.now() - startTime > timeout) {
166
- throw new Error(`Timeout waiting for ${count} messages (received ${this._receivedMessages.length})`);
167
- }
168
- await new Promise((resolve) => setTimeout(resolve, 10));
169
- }
170
- return this._receivedMessages.slice(0, count);
171
- }
172
- static async create(options = {}) {
173
- const server = new MockUDPServer(options);
174
- await server.start();
175
- return server;
176
- }
177
- }
178
- export async function createMockUDPServer(responses, options) {
179
- const server = new MockUDPServer(options);
180
- if (responses) {
181
- for (const [pattern, response] of Object.entries(responses)) {
182
- server.setResponse(pattern, response);
183
- }
184
- server.setEcho(false);
185
- }
186
- await server.start();
187
- return server;
188
- }
@@ -1,76 +0,0 @@
1
- import { EventEmitter } from 'node:events';
2
- export interface MockWebSocketServerOptions {
3
- port?: number;
4
- host?: string;
5
- path?: string;
6
- echo?: boolean;
7
- delay?: number;
8
- protocols?: string[];
9
- autoCloseAfter?: number;
10
- dropRate?: number;
11
- maxConnections?: number;
12
- }
13
- export interface MockWebSocketClient {
14
- id: string;
15
- socket: import('ws').WebSocket;
16
- connectedAt: number;
17
- messageCount: number;
18
- lastMessage?: import('ws').RawData;
19
- metadata: Record<string, any>;
20
- }
21
- export interface MockWebSocketMessage {
22
- clientId: string;
23
- data: import('ws').RawData;
24
- timestamp: number;
25
- isBinary: boolean;
26
- }
27
- export interface MockWebSocketStats {
28
- totalConnections: number;
29
- currentConnections: number;
30
- totalMessages: number;
31
- totalBytesSent: number;
32
- totalBytesReceived: number;
33
- messageLog: MockWebSocketMessage[];
34
- }
35
- export declare class MockWebSocketServer extends EventEmitter {
36
- private options;
37
- private httpServer;
38
- private wss;
39
- private clients;
40
- private responses;
41
- private _port;
42
- private _started;
43
- private clientIdCounter;
44
- private stats;
45
- constructor(options?: MockWebSocketServerOptions);
46
- get port(): number;
47
- get address(): string;
48
- get url(): string;
49
- get isRunning(): boolean;
50
- get connectionCount(): number;
51
- get statistics(): MockWebSocketStats;
52
- get allClients(): MockWebSocketClient[];
53
- start(): Promise<void>;
54
- stop(): Promise<void>;
55
- reset(): void;
56
- setResponse(pattern: string | RegExp, response: string | Buffer | ((msg: string, client: MockWebSocketClient) => string | Buffer | null)): void;
57
- clearResponses(): void;
58
- setEcho(enabled: boolean): void;
59
- setDelay(delay: number): void;
60
- setDropRate(rate: number): void;
61
- getClient(id: string): MockWebSocketClient | undefined;
62
- disconnectClient(id: string, code?: number, reason?: string): void;
63
- disconnectAll(code?: number, reason?: string): void;
64
- send(clientId: string, data: string | Buffer | object): boolean;
65
- broadcast(data: string | Buffer | object): number;
66
- sendToAll(data: string | Buffer | object): number;
67
- simulateMessage(clientId: string, data: string | Buffer): void;
68
- ping(clientId?: string): void;
69
- waitForConnections(count: number, timeout?: number): Promise<MockWebSocketClient[]>;
70
- waitForMessages(count: number, timeout?: number): Promise<MockWebSocketMessage[]>;
71
- private handleConnection;
72
- private handleMessage;
73
- private getResponse;
74
- static create(options?: MockWebSocketServerOptions): Promise<MockWebSocketServer>;
75
- }
76
- export declare function createMockWebSocketServer(responses?: Record<string, string>, options?: MockWebSocketServerOptions): Promise<MockWebSocketServer>;
@@ -1,334 +0,0 @@
1
- import { EventEmitter } from 'node:events';
2
- import { createServer } from 'node:http';
3
- let wsModule = null;
4
- let WebSocketServer;
5
- const WS_OPEN = 1;
6
- async function loadWsModule() {
7
- if (wsModule)
8
- return wsModule;
9
- try {
10
- wsModule = await import('ws');
11
- WebSocketServer = wsModule.WebSocketServer;
12
- return wsModule;
13
- }
14
- catch {
15
- throw new Error('MockWebSocketServer requires the "ws" package. Install it with:\n\n' +
16
- ' pnpm add ws\n' +
17
- ' # or\n' +
18
- ' npm install ws\n');
19
- }
20
- }
21
- export class MockWebSocketServer extends EventEmitter {
22
- options;
23
- httpServer = null;
24
- wss = null;
25
- clients = new Map();
26
- responses = new Map();
27
- _port = 0;
28
- _started = false;
29
- clientIdCounter = 0;
30
- stats = {
31
- totalConnections: 0,
32
- currentConnections: 0,
33
- totalMessages: 0,
34
- totalBytesSent: 0,
35
- totalBytesReceived: 0,
36
- messageLog: [],
37
- };
38
- constructor(options = {}) {
39
- super();
40
- this.options = {
41
- port: 0,
42
- host: '127.0.0.1',
43
- path: '/',
44
- echo: true,
45
- delay: 0,
46
- protocols: [],
47
- autoCloseAfter: 0,
48
- dropRate: 0,
49
- maxConnections: 0,
50
- ...options,
51
- };
52
- }
53
- get port() {
54
- return this._port;
55
- }
56
- get address() {
57
- return this.options.host;
58
- }
59
- get url() {
60
- return `ws://${this.options.host}:${this._port}${this.options.path}`;
61
- }
62
- get isRunning() {
63
- return this._started;
64
- }
65
- get connectionCount() {
66
- return this.clients.size;
67
- }
68
- get statistics() {
69
- return { ...this.stats };
70
- }
71
- get allClients() {
72
- return [...this.clients.values()];
73
- }
74
- async start() {
75
- if (this._started) {
76
- throw new Error('Server already started');
77
- }
78
- await loadWsModule();
79
- return new Promise((resolve, reject) => {
80
- this.httpServer = createServer();
81
- this.wss = new WebSocketServer({
82
- server: this.httpServer,
83
- path: this.options.path,
84
- handleProtocols: this.options.protocols.length > 0
85
- ? (protocols) => {
86
- for (const p of protocols) {
87
- if (this.options.protocols.includes(p)) {
88
- return p;
89
- }
90
- }
91
- return false;
92
- }
93
- : undefined,
94
- });
95
- this.wss.on('connection', (socket, req) => this.handleConnection(socket, req));
96
- this.wss.on('error', (err) => this.emit('error', err));
97
- this.httpServer.on('error', reject);
98
- this.httpServer.listen(this.options.port, this.options.host, () => {
99
- const addr = this.httpServer.address();
100
- this._port = typeof addr === 'string' ? 0 : addr?.port ?? 0;
101
- this._started = true;
102
- this.emit('listening', this._port);
103
- resolve();
104
- });
105
- });
106
- }
107
- async stop() {
108
- if (!this._started)
109
- return;
110
- for (const client of this.clients.values()) {
111
- client.socket.close(1001, 'Server shutting down');
112
- }
113
- this.clients.clear();
114
- return new Promise((resolve) => {
115
- this.wss?.close(() => {
116
- this.httpServer?.close(() => {
117
- this._started = false;
118
- this.wss = null;
119
- this.httpServer = null;
120
- this.emit('close');
121
- resolve();
122
- });
123
- });
124
- });
125
- }
126
- reset() {
127
- this.responses.clear();
128
- this.stats = {
129
- totalConnections: 0,
130
- currentConnections: 0,
131
- totalMessages: 0,
132
- totalBytesSent: 0,
133
- totalBytesReceived: 0,
134
- messageLog: [],
135
- };
136
- this.options.echo = true;
137
- this.options.delay = 0;
138
- this.options.dropRate = 0;
139
- this.emit('reset');
140
- }
141
- setResponse(pattern, response) {
142
- const key = pattern instanceof RegExp ? pattern.source : pattern;
143
- this.responses.set(key, response);
144
- }
145
- clearResponses() {
146
- this.responses.clear();
147
- }
148
- setEcho(enabled) {
149
- this.options.echo = enabled;
150
- }
151
- setDelay(delay) {
152
- this.options.delay = delay;
153
- }
154
- setDropRate(rate) {
155
- this.options.dropRate = Math.max(0, Math.min(1, rate));
156
- }
157
- getClient(id) {
158
- return this.clients.get(id);
159
- }
160
- disconnectClient(id, code = 1000, reason = 'Disconnected by server') {
161
- const client = this.clients.get(id);
162
- if (client) {
163
- client.socket.close(code, reason);
164
- }
165
- }
166
- disconnectAll(code = 1000, reason = 'Disconnected by server') {
167
- for (const client of this.clients.values()) {
168
- client.socket.close(code, reason);
169
- }
170
- }
171
- send(clientId, data) {
172
- const client = this.clients.get(clientId);
173
- if (!client || client.socket.readyState !== WS_OPEN) {
174
- return false;
175
- }
176
- const message = typeof data === 'object' && !Buffer.isBuffer(data)
177
- ? JSON.stringify(data)
178
- : data;
179
- client.socket.send(message);
180
- this.stats.totalBytesSent += Buffer.byteLength(message);
181
- return true;
182
- }
183
- broadcast(data) {
184
- let sent = 0;
185
- for (const client of this.clients.values()) {
186
- if (this.send(client.id, data)) {
187
- sent++;
188
- }
189
- }
190
- return sent;
191
- }
192
- sendToAll(data) {
193
- return this.broadcast(data);
194
- }
195
- simulateMessage(clientId, data) {
196
- const client = this.clients.get(clientId);
197
- if (client) {
198
- const rawData = Buffer.isBuffer(data) ? data : Buffer.from(data);
199
- this.handleMessage(client, rawData, Buffer.isBuffer(data));
200
- }
201
- }
202
- ping(clientId) {
203
- if (clientId) {
204
- const client = this.clients.get(clientId);
205
- client?.socket.ping();
206
- }
207
- else {
208
- for (const client of this.clients.values()) {
209
- client.socket.ping();
210
- }
211
- }
212
- }
213
- async waitForConnections(count, timeout = 5000) {
214
- const start = Date.now();
215
- while (this.clients.size < count) {
216
- if (Date.now() - start > timeout) {
217
- throw new Error(`Timeout waiting for ${count} connections (have ${this.clients.size})`);
218
- }
219
- await new Promise((resolve) => setTimeout(resolve, 10));
220
- }
221
- return [...this.clients.values()].slice(0, count);
222
- }
223
- async waitForMessages(count, timeout = 5000) {
224
- const start = Date.now();
225
- while (this.stats.messageLog.length < count) {
226
- if (Date.now() - start > timeout) {
227
- throw new Error(`Timeout waiting for ${count} messages (have ${this.stats.messageLog.length})`);
228
- }
229
- await new Promise((resolve) => setTimeout(resolve, 10));
230
- }
231
- return this.stats.messageLog.slice(0, count);
232
- }
233
- handleConnection(socket, _req) {
234
- if (this.options.maxConnections > 0 && this.clients.size >= this.options.maxConnections) {
235
- socket.close(1013, 'Max connections reached');
236
- return;
237
- }
238
- if (this.options.dropRate > 0 && Math.random() < this.options.dropRate) {
239
- socket.close(1006, 'Connection dropped');
240
- this.emit('dropped');
241
- return;
242
- }
243
- const clientId = `client-${++this.clientIdCounter}`;
244
- const client = {
245
- id: clientId,
246
- socket,
247
- connectedAt: Date.now(),
248
- messageCount: 0,
249
- metadata: {},
250
- };
251
- this.clients.set(clientId, client);
252
- this.stats.totalConnections++;
253
- this.stats.currentConnections++;
254
- this.emit('connection', client);
255
- if (this.options.autoCloseAfter > 0) {
256
- setTimeout(() => {
257
- if (socket.readyState === WS_OPEN) {
258
- socket.close(1000, 'Auto-close timeout');
259
- }
260
- }, this.options.autoCloseAfter);
261
- }
262
- socket.on('message', (data, isBinary) => {
263
- this.handleMessage(client, data, isBinary);
264
- });
265
- socket.on('close', (code, reason) => {
266
- this.clients.delete(clientId);
267
- this.stats.currentConnections--;
268
- this.emit('disconnect', client, code, reason.toString());
269
- });
270
- socket.on('error', (err) => {
271
- this.emit('clientError', client, err);
272
- });
273
- socket.on('ping', () => {
274
- this.emit('ping', client);
275
- });
276
- socket.on('pong', () => {
277
- this.emit('pong', client);
278
- });
279
- }
280
- async handleMessage(client, data, isBinary) {
281
- const bytes = Buffer.isBuffer(data) ? data.length : Buffer.byteLength(data.toString());
282
- this.stats.totalBytesReceived += bytes;
283
- this.stats.totalMessages++;
284
- client.messageCount++;
285
- client.lastMessage = data;
286
- const message = {
287
- clientId: client.id,
288
- data,
289
- timestamp: Date.now(),
290
- isBinary,
291
- };
292
- this.stats.messageLog.push(message);
293
- this.emit('message', message, client);
294
- if (this.options.delay > 0) {
295
- await new Promise((resolve) => setTimeout(resolve, this.options.delay));
296
- }
297
- const response = this.getResponse(data.toString(), client);
298
- if (response !== null && client.socket.readyState === WS_OPEN) {
299
- client.socket.send(response);
300
- this.stats.totalBytesSent += Buffer.byteLength(response);
301
- }
302
- }
303
- getResponse(msg, client) {
304
- for (const [pattern, response] of this.responses) {
305
- const regex = new RegExp(pattern);
306
- if (regex.test(msg)) {
307
- if (typeof response === 'function') {
308
- return response(msg, client);
309
- }
310
- return response;
311
- }
312
- }
313
- if (this.options.echo) {
314
- return msg;
315
- }
316
- return null;
317
- }
318
- static async create(options = {}) {
319
- const server = new MockWebSocketServer(options);
320
- await server.start();
321
- return server;
322
- }
323
- }
324
- export async function createMockWebSocketServer(responses, options) {
325
- const server = new MockWebSocketServer(options);
326
- if (responses) {
327
- for (const [pattern, response] of Object.entries(responses)) {
328
- server.setResponse(pattern, response);
329
- }
330
- server.setEcho(false);
331
- }
332
- await server.start();
333
- return server;
334
- }
@@ -1,56 +0,0 @@
1
- import { EventEmitter } from 'node:events';
2
- export interface MockWhoisServerOptions {
3
- port?: number;
4
- host?: string;
5
- delay?: number;
6
- }
7
- export interface WhoisDomainData {
8
- registrar?: string;
9
- registrarUrl?: string;
10
- createdDate?: string;
11
- updatedDate?: string;
12
- expiryDate?: string;
13
- status?: string[];
14
- nameservers?: string[];
15
- registrantName?: string;
16
- registrantOrg?: string;
17
- registrantEmail?: string;
18
- adminEmail?: string;
19
- techEmail?: string;
20
- dnssec?: string;
21
- }
22
- export interface MockWhoisStats {
23
- queriesReceived: number;
24
- responseSent: number;
25
- queryLog: Array<{
26
- query: string;
27
- timestamp: number;
28
- }>;
29
- }
30
- export declare class MockWhoisServer extends EventEmitter {
31
- private options;
32
- private server;
33
- private domains;
34
- private started;
35
- private stats;
36
- constructor(options?: MockWhoisServerOptions);
37
- get isRunning(): boolean;
38
- get port(): number;
39
- get host(): string;
40
- get url(): string;
41
- get statistics(): MockWhoisStats;
42
- addDomain(domain: string, data: WhoisDomainData): void;
43
- removeDomain(domain: string): void;
44
- getDomain(domain: string): WhoisDomainData | undefined;
45
- clearDomains(): void;
46
- private addDefaultDomains;
47
- start(): Promise<void>;
48
- stop(): Promise<void>;
49
- reset(): void;
50
- private handleConnection;
51
- private handleQuery;
52
- private buildResponse;
53
- private buildNotFoundResponse;
54
- private buildDomainResponse;
55
- static create(options?: MockWhoisServerOptions): Promise<MockWhoisServer>;
56
- }