recker 1.0.2-0 → 1.0.4
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/LICENSE +0 -2
- package/README.md +121 -72
- package/dist/cache/memory-storage.d.ts.map +1 -1
- package/dist/cache/memory-storage.js +7 -1
- package/dist/constants/http-status.d.ts +74 -0
- package/dist/constants/http-status.d.ts.map +1 -0
- package/dist/constants/http-status.js +156 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +6 -6
- package/dist/cookies/memory-cookie-jar.d.ts +31 -0
- package/dist/cookies/memory-cookie-jar.d.ts.map +1 -0
- package/dist/cookies/memory-cookie-jar.js +210 -0
- package/dist/core/client.d.ts +9 -0
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/client.js +252 -53
- package/dist/core/errors.d.ts +18 -2
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +66 -5
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +5 -0
- package/dist/core/request-promise.d.ts.map +1 -1
- package/dist/core/request-promise.js +8 -2
- package/dist/core/request.d.ts +7 -1
- package/dist/core/request.d.ts.map +1 -1
- package/dist/core/request.js +32 -0
- package/dist/core/response.d.ts +2 -0
- package/dist/core/response.d.ts.map +1 -1
- package/dist/core/response.js +44 -19
- package/dist/events/request-events.d.ts +48 -0
- package/dist/events/request-events.d.ts.map +1 -0
- package/dist/events/request-events.js +85 -0
- package/dist/index.d.ts +28 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -2
- package/dist/mcp/client.d.ts.map +1 -1
- package/dist/mcp/client.js +16 -5
- package/dist/mcp/contract.d.ts +77 -0
- package/dist/mcp/contract.d.ts.map +1 -0
- package/dist/mcp/contract.js +278 -0
- package/dist/mcp/types.d.ts +1 -0
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/plugins/auth.d.ts +45 -0
- package/dist/plugins/auth.d.ts.map +1 -0
- package/dist/plugins/auth.js +268 -0
- package/dist/plugins/cache.d.ts +7 -1
- package/dist/plugins/cache.d.ts.map +1 -1
- package/dist/plugins/cache.js +470 -49
- package/dist/plugins/circuit-breaker.js +1 -1
- package/dist/plugins/compression.d.ts.map +1 -1
- package/dist/plugins/compression.js +3 -3
- package/dist/plugins/dedup.d.ts.map +1 -1
- package/dist/plugins/dedup.js +2 -1
- package/dist/plugins/graphql.d.ts +4 -3
- package/dist/plugins/graphql.d.ts.map +1 -1
- package/dist/plugins/graphql.js +24 -5
- package/dist/plugins/grpc-web.d.ts +80 -0
- package/dist/plugins/grpc-web.d.ts.map +1 -0
- package/dist/plugins/grpc-web.js +261 -0
- package/dist/plugins/har-player.d.ts.map +1 -1
- package/dist/plugins/har-player.js +11 -2
- package/dist/plugins/hls.d.ts +33 -0
- package/dist/plugins/hls.d.ts.map +1 -0
- package/dist/plugins/hls.js +225 -0
- package/dist/plugins/http2-push.d.ts +64 -0
- package/dist/plugins/http2-push.d.ts.map +1 -0
- package/dist/plugins/http2-push.js +274 -0
- package/dist/plugins/http3.d.ts +76 -0
- package/dist/plugins/http3.d.ts.map +1 -0
- package/dist/plugins/http3.js +231 -0
- package/dist/plugins/interface-rotator.d.ts +10 -0
- package/dist/plugins/interface-rotator.d.ts.map +1 -0
- package/dist/plugins/interface-rotator.js +57 -0
- package/dist/plugins/jsonrpc.d.ts +76 -0
- package/dist/plugins/jsonrpc.d.ts.map +1 -0
- package/dist/plugins/jsonrpc.js +143 -0
- package/dist/plugins/logger.d.ts +8 -5
- package/dist/plugins/logger.d.ts.map +1 -1
- package/dist/plugins/logger.js +66 -30
- package/dist/plugins/odata.d.ts +182 -0
- package/dist/plugins/odata.d.ts.map +1 -0
- package/dist/plugins/odata.js +561 -0
- package/dist/plugins/retry.d.ts +1 -0
- package/dist/plugins/retry.d.ts.map +1 -1
- package/dist/plugins/retry.js +26 -2
- package/dist/plugins/scrape.d.ts +22 -0
- package/dist/plugins/scrape.d.ts.map +1 -0
- package/dist/plugins/scrape.js +87 -0
- package/dist/plugins/soap.d.ts +73 -0
- package/dist/plugins/soap.d.ts.map +1 -0
- package/dist/plugins/soap.js +347 -0
- package/dist/plugins/user-agent.d.ts +8 -0
- package/dist/plugins/user-agent.d.ts.map +1 -0
- package/dist/plugins/user-agent.js +46 -0
- package/dist/plugins/xml.d.ts +10 -0
- package/dist/plugins/xml.d.ts.map +1 -0
- package/dist/plugins/xml.js +194 -0
- package/dist/presets/anthropic.d.ts +7 -0
- package/dist/presets/anthropic.d.ts.map +1 -0
- package/dist/presets/anthropic.js +17 -0
- package/dist/presets/azure-openai.d.ts +9 -0
- package/dist/presets/azure-openai.d.ts.map +1 -0
- package/dist/presets/azure-openai.js +25 -0
- package/dist/presets/cloudflare.d.ts +13 -0
- package/dist/presets/cloudflare.d.ts.map +1 -0
- package/dist/presets/cloudflare.js +39 -0
- package/dist/presets/cohere.d.ts +6 -0
- package/dist/presets/cohere.d.ts.map +1 -0
- package/dist/presets/cohere.js +16 -0
- package/dist/presets/deepseek.d.ts +6 -0
- package/dist/presets/deepseek.d.ts.map +1 -0
- package/dist/presets/deepseek.js +16 -0
- package/dist/presets/digitalocean.d.ts +6 -0
- package/dist/presets/digitalocean.d.ts.map +1 -0
- package/dist/presets/digitalocean.js +16 -0
- package/dist/presets/discord.d.ts +7 -0
- package/dist/presets/discord.d.ts.map +1 -0
- package/dist/presets/discord.js +17 -0
- package/dist/presets/fireworks.d.ts +6 -0
- package/dist/presets/fireworks.d.ts.map +1 -0
- package/dist/presets/fireworks.js +16 -0
- package/dist/presets/gemini.d.ts +6 -0
- package/dist/presets/gemini.d.ts.map +1 -0
- package/dist/presets/gemini.js +16 -0
- package/dist/presets/github.d.ts +7 -0
- package/dist/presets/github.d.ts.map +1 -0
- package/dist/presets/github.js +17 -0
- package/dist/presets/gitlab.d.ts +7 -0
- package/dist/presets/gitlab.d.ts.map +1 -0
- package/dist/presets/gitlab.js +16 -0
- package/dist/presets/groq.d.ts +6 -0
- package/dist/presets/groq.d.ts.map +1 -0
- package/dist/presets/groq.js +16 -0
- package/dist/presets/huggingface.d.ts +6 -0
- package/dist/presets/huggingface.d.ts.map +1 -0
- package/dist/presets/huggingface.js +16 -0
- package/dist/presets/index.d.ts +28 -0
- package/dist/presets/index.d.ts.map +1 -0
- package/dist/presets/index.js +27 -0
- package/dist/presets/linear.d.ts +6 -0
- package/dist/presets/linear.d.ts.map +1 -0
- package/dist/presets/linear.js +16 -0
- package/dist/presets/mistral.d.ts +6 -0
- package/dist/presets/mistral.d.ts.map +1 -0
- package/dist/presets/mistral.js +16 -0
- package/dist/presets/notion.d.ts +7 -0
- package/dist/presets/notion.d.ts.map +1 -0
- package/dist/presets/notion.js +17 -0
- package/dist/presets/openai.d.ts +8 -0
- package/dist/presets/openai.d.ts.map +1 -0
- package/dist/presets/openai.js +23 -0
- package/dist/presets/perplexity.d.ts +6 -0
- package/dist/presets/perplexity.d.ts.map +1 -0
- package/dist/presets/perplexity.js +16 -0
- package/dist/presets/registry.d.ts +20 -0
- package/dist/presets/registry.d.ts.map +1 -0
- package/dist/presets/registry.js +311 -0
- package/dist/presets/replicate.d.ts +6 -0
- package/dist/presets/replicate.d.ts.map +1 -0
- package/dist/presets/replicate.js +16 -0
- package/dist/presets/slack.d.ts +6 -0
- package/dist/presets/slack.d.ts.map +1 -0
- package/dist/presets/slack.js +16 -0
- package/dist/presets/stripe.d.ts +8 -0
- package/dist/presets/stripe.d.ts.map +1 -0
- package/dist/presets/stripe.js +23 -0
- package/dist/presets/supabase.d.ts +7 -0
- package/dist/presets/supabase.d.ts.map +1 -0
- package/dist/presets/supabase.js +18 -0
- package/dist/presets/together.d.ts +6 -0
- package/dist/presets/together.d.ts.map +1 -0
- package/dist/presets/together.js +16 -0
- package/dist/presets/twilio.d.ts +7 -0
- package/dist/presets/twilio.d.ts.map +1 -0
- package/dist/presets/twilio.js +17 -0
- package/dist/presets/vercel.d.ts +7 -0
- package/dist/presets/vercel.d.ts.map +1 -0
- package/dist/presets/vercel.js +23 -0
- package/dist/presets/xai.d.ts +7 -0
- package/dist/presets/xai.d.ts.map +1 -0
- package/dist/presets/xai.js +17 -0
- package/dist/protocols/ftp.d.ts +63 -0
- package/dist/protocols/ftp.d.ts.map +1 -0
- package/dist/protocols/ftp.js +388 -0
- package/dist/protocols/index.d.ts +4 -0
- package/dist/protocols/index.d.ts.map +1 -0
- package/dist/protocols/index.js +3 -0
- package/dist/protocols/sftp.d.ts +65 -0
- package/dist/protocols/sftp.d.ts.map +1 -0
- package/dist/protocols/sftp.js +346 -0
- package/dist/protocols/telnet.d.ts +50 -0
- package/dist/protocols/telnet.d.ts.map +1 -0
- package/dist/protocols/telnet.js +139 -0
- package/dist/runner/request-runner.d.ts.map +1 -1
- package/dist/runner/request-runner.js +1 -0
- package/dist/scrape/document.d.ts +44 -0
- package/dist/scrape/document.d.ts.map +1 -0
- package/dist/scrape/document.js +198 -0
- package/dist/scrape/element.d.ts +50 -0
- package/dist/scrape/element.d.ts.map +1 -0
- package/dist/scrape/element.js +176 -0
- package/dist/scrape/extractors.d.ts +17 -0
- package/dist/scrape/extractors.d.ts.map +1 -0
- package/dist/scrape/extractors.js +356 -0
- package/dist/scrape/index.d.ts +5 -0
- package/dist/scrape/index.d.ts.map +1 -0
- package/dist/scrape/index.js +3 -0
- package/dist/scrape/types.d.ts +108 -0
- package/dist/scrape/types.d.ts.map +1 -0
- package/dist/scrape/types.js +1 -0
- package/dist/testing/index.d.ts +3 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +1 -0
- package/dist/testing/mock.d.ts +58 -0
- package/dist/testing/mock.d.ts.map +1 -0
- package/dist/testing/mock.js +252 -0
- package/dist/transport/fetch.d.ts.map +1 -1
- package/dist/transport/fetch.js +12 -4
- package/dist/transport/undici.d.ts +17 -1
- package/dist/transport/undici.d.ts.map +1 -1
- package/dist/transport/undici.js +708 -47
- package/dist/types/index.d.ts +111 -10
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -1
- package/dist/types/logger.d.ts +17 -0
- package/dist/types/logger.d.ts.map +1 -0
- package/dist/types/logger.js +66 -0
- package/dist/utils/agent-manager.d.ts.map +1 -1
- package/dist/utils/agent-manager.js +20 -4
- package/dist/utils/body.d.ts.map +1 -1
- package/dist/utils/body.js +14 -2
- package/dist/utils/charset.d.ts +16 -0
- package/dist/utils/charset.d.ts.map +1 -0
- package/dist/utils/charset.js +169 -0
- package/dist/utils/client-pool.d.ts +21 -0
- package/dist/utils/client-pool.d.ts.map +1 -0
- package/dist/utils/client-pool.js +49 -0
- package/dist/utils/concurrency.d.ts.map +1 -1
- package/dist/utils/concurrency.js +8 -4
- package/dist/utils/dns-toolkit.d.ts +13 -0
- package/dist/utils/dns-toolkit.d.ts.map +1 -0
- package/dist/utils/dns-toolkit.js +48 -0
- package/dist/utils/doh.d.ts.map +1 -1
- package/dist/utils/doh.js +16 -3
- package/dist/utils/download.d.ts +15 -0
- package/dist/utils/download.d.ts.map +1 -0
- package/dist/utils/download.js +44 -0
- package/dist/utils/env-proxy.d.ts +13 -0
- package/dist/utils/env-proxy.d.ts.map +1 -0
- package/dist/utils/env-proxy.js +105 -0
- package/dist/utils/header-parser.d.ts +15 -1
- package/dist/utils/header-parser.d.ts.map +1 -1
- package/dist/utils/header-parser.js +161 -1
- package/dist/utils/link-header.d.ts +70 -0
- package/dist/utils/link-header.d.ts.map +1 -0
- package/dist/utils/link-header.js +190 -0
- package/dist/utils/progress.d.ts +7 -2
- package/dist/utils/progress.d.ts.map +1 -1
- package/dist/utils/progress.js +48 -15
- package/dist/utils/rdap.d.ts +17 -0
- package/dist/utils/rdap.d.ts.map +1 -0
- package/dist/utils/rdap.js +32 -0
- package/dist/utils/request-pool.d.ts.map +1 -1
- package/dist/utils/request-pool.js +4 -3
- package/dist/utils/sse.d.ts.map +1 -1
- package/dist/utils/sse.js +8 -2
- package/dist/utils/status-codes.d.ts +84 -0
- package/dist/utils/status-codes.d.ts.map +1 -0
- package/dist/utils/status-codes.js +204 -0
- package/dist/utils/streaming.d.ts.map +1 -1
- package/dist/utils/streaming.js +1 -0
- package/dist/utils/tls-inspector.d.ts +21 -0
- package/dist/utils/tls-inspector.d.ts.map +1 -0
- package/dist/utils/tls-inspector.js +39 -0
- package/dist/utils/try-fn.d.ts.map +1 -1
- package/dist/utils/try-fn.js +11 -5
- package/dist/utils/upload.d.ts +1 -0
- package/dist/utils/upload.d.ts.map +1 -1
- package/dist/utils/upload.js +20 -3
- package/dist/utils/user-agent.d.ts +9 -9
- package/dist/utils/user-agent.js +9 -9
- package/dist/utils/whois.d.ts.map +1 -1
- package/dist/utils/whois.js +11 -2
- package/dist/websocket/client.d.ts +29 -1
- package/dist/websocket/client.d.ts.map +1 -1
- package/dist/websocket/client.js +145 -13
- package/package.json +45 -8
package/dist/websocket/client.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { WebSocket } from 'undici';
|
|
2
2
|
import { EventEmitter } from 'events';
|
|
3
|
+
import { pipeline } from 'node:stream/promises';
|
|
4
|
+
import { webToNodeStream } from '../utils/streaming.js';
|
|
5
|
+
import { ReckerError } from '../core/errors.js';
|
|
3
6
|
export class ReckerWebSocket extends EventEmitter {
|
|
4
7
|
ws = null;
|
|
5
8
|
url;
|
|
@@ -9,6 +12,9 @@ export class ReckerWebSocket extends EventEmitter {
|
|
|
9
12
|
heartbeatTimer;
|
|
10
13
|
isClosed = false;
|
|
11
14
|
isReconnecting = false;
|
|
15
|
+
pongWatchdog;
|
|
16
|
+
backoff;
|
|
17
|
+
closedByUser = false;
|
|
12
18
|
constructor(url, options = {}) {
|
|
13
19
|
super();
|
|
14
20
|
this.url = url;
|
|
@@ -19,12 +25,38 @@ export class ReckerWebSocket extends EventEmitter {
|
|
|
19
25
|
reconnectDelay: options.reconnectDelay ?? 1000,
|
|
20
26
|
maxReconnectAttempts: options.maxReconnectAttempts ?? 5,
|
|
21
27
|
heartbeatInterval: options.heartbeatInterval ?? 30000,
|
|
28
|
+
heartbeatTimeout: options.heartbeatTimeout ?? 10000,
|
|
29
|
+
dispatcher: options.dispatcher,
|
|
30
|
+
proxy: options.proxy,
|
|
31
|
+
tls: options.tls,
|
|
32
|
+
perMessageDeflate: options.perMessageDeflate ?? false
|
|
33
|
+
};
|
|
34
|
+
this.backoff = {
|
|
35
|
+
base: this.options.reconnectDelay,
|
|
36
|
+
factor: 2,
|
|
37
|
+
jitter: true,
|
|
38
|
+
max: 30000
|
|
22
39
|
};
|
|
23
40
|
}
|
|
24
41
|
async connect() {
|
|
25
42
|
return new Promise((resolve, reject) => {
|
|
26
43
|
try {
|
|
27
|
-
|
|
44
|
+
const wsOptions = {
|
|
45
|
+
headers: this.options.headers,
|
|
46
|
+
dispatcher: this.options.dispatcher,
|
|
47
|
+
perMessageDeflate: this.options.perMessageDeflate,
|
|
48
|
+
};
|
|
49
|
+
if (this.options.proxy) {
|
|
50
|
+
const proxyConfig = typeof this.options.proxy === 'string'
|
|
51
|
+
? { url: this.options.proxy }
|
|
52
|
+
: this.options.proxy;
|
|
53
|
+
const { ProxyAgent } = require('undici');
|
|
54
|
+
wsOptions.dispatcher = new ProxyAgent(proxyConfig.url);
|
|
55
|
+
}
|
|
56
|
+
if (this.options.tls) {
|
|
57
|
+
wsOptions.tls = this.options.tls;
|
|
58
|
+
}
|
|
59
|
+
this.ws = new WebSocket(this.url, this.options.protocols, wsOptions);
|
|
28
60
|
this.ws.addEventListener('open', () => {
|
|
29
61
|
this.reconnectAttempts = 0;
|
|
30
62
|
this.isReconnecting = false;
|
|
@@ -38,17 +70,26 @@ export class ReckerWebSocket extends EventEmitter {
|
|
|
38
70
|
isBinary: event.data instanceof Buffer
|
|
39
71
|
};
|
|
40
72
|
this.emit('message', message);
|
|
73
|
+
this.stopPongWatchdog();
|
|
41
74
|
});
|
|
42
75
|
this.ws.addEventListener('close', (event) => {
|
|
43
76
|
this.stopHeartbeat();
|
|
77
|
+
this.stopPongWatchdog();
|
|
44
78
|
this.emit('close', event.code, event.reason);
|
|
45
|
-
if (!this.isClosed && this.options.reconnect) {
|
|
79
|
+
if (!this.closedByUser && !this.isClosed && this.options.reconnect) {
|
|
46
80
|
this.attemptReconnect();
|
|
47
81
|
}
|
|
48
82
|
});
|
|
49
83
|
this.ws.addEventListener('error', (event) => {
|
|
50
|
-
|
|
51
|
-
|
|
84
|
+
const err = event.error instanceof Error
|
|
85
|
+
? event.error
|
|
86
|
+
: new ReckerError('WebSocket connection error', undefined, undefined, [
|
|
87
|
+
'Verify the WebSocket endpoint URL and protocol (ws/wss).',
|
|
88
|
+
'Check proxy/TLS settings if connecting through a proxy.',
|
|
89
|
+
'Inspect server logs for handshake failures.'
|
|
90
|
+
]);
|
|
91
|
+
this.emit('error', err);
|
|
92
|
+
reject(err);
|
|
52
93
|
});
|
|
53
94
|
}
|
|
54
95
|
catch (error) {
|
|
@@ -56,17 +97,32 @@ export class ReckerWebSocket extends EventEmitter {
|
|
|
56
97
|
}
|
|
57
98
|
});
|
|
58
99
|
}
|
|
59
|
-
send(data) {
|
|
100
|
+
async send(data, options) {
|
|
60
101
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
61
|
-
throw new
|
|
102
|
+
throw new ReckerError('WebSocket is not connected', undefined, undefined, [
|
|
103
|
+
'Call connect() before sending messages.',
|
|
104
|
+
'Listen to the open event to ensure the socket is ready.',
|
|
105
|
+
'Check for prior connection errors or closed states.'
|
|
106
|
+
]);
|
|
62
107
|
}
|
|
108
|
+
const awaitDrain = options?.awaitDrain ?? false;
|
|
109
|
+
const highWaterMark = options?.highWaterMark ?? 16 * 1024;
|
|
63
110
|
this.ws.send(data);
|
|
111
|
+
if (awaitDrain) {
|
|
112
|
+
await this.waitForDrain(highWaterMark);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async sendStream(stream, options) {
|
|
116
|
+
for await (const chunk of stream) {
|
|
117
|
+
await this.send(chunk, options);
|
|
118
|
+
}
|
|
64
119
|
}
|
|
65
120
|
sendJSON(data) {
|
|
66
|
-
this.send(JSON.stringify(data));
|
|
121
|
+
void this.send(JSON.stringify(data));
|
|
67
122
|
}
|
|
68
123
|
close(code = 1000, reason = '') {
|
|
69
124
|
this.isClosed = true;
|
|
125
|
+
this.closedByUser = true;
|
|
70
126
|
this.stopHeartbeat();
|
|
71
127
|
this.clearReconnectTimer();
|
|
72
128
|
if (this.ws) {
|
|
@@ -75,13 +131,22 @@ export class ReckerWebSocket extends EventEmitter {
|
|
|
75
131
|
}
|
|
76
132
|
}
|
|
77
133
|
ping() {
|
|
78
|
-
if (this.ws
|
|
134
|
+
if (!this.ws || this.ws.readyState !== WebSocket.OPEN)
|
|
135
|
+
return;
|
|
136
|
+
const anyWs = this.ws;
|
|
137
|
+
if (typeof anyWs.ping === 'function') {
|
|
79
138
|
try {
|
|
80
|
-
|
|
139
|
+
anyWs.ping();
|
|
140
|
+
return;
|
|
81
141
|
}
|
|
82
|
-
catch
|
|
142
|
+
catch {
|
|
83
143
|
}
|
|
84
144
|
}
|
|
145
|
+
try {
|
|
146
|
+
this.ws.send('__heartbeat__');
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
}
|
|
85
150
|
}
|
|
86
151
|
get readyState() {
|
|
87
152
|
return this.ws?.readyState ?? WebSocket.CLOSED;
|
|
@@ -89,6 +154,29 @@ export class ReckerWebSocket extends EventEmitter {
|
|
|
89
154
|
get isConnected() {
|
|
90
155
|
return this.ws?.readyState === WebSocket.OPEN;
|
|
91
156
|
}
|
|
157
|
+
toReadable() {
|
|
158
|
+
if (!this.ws)
|
|
159
|
+
return null;
|
|
160
|
+
const wsAny = this.ws;
|
|
161
|
+
if (wsAny.readable) {
|
|
162
|
+
return webToNodeStream(wsAny.readable);
|
|
163
|
+
}
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
async pipeFrom(source, options) {
|
|
167
|
+
await this.sendStream(source, options);
|
|
168
|
+
}
|
|
169
|
+
async pipeTo(destination) {
|
|
170
|
+
const readable = this.toReadable();
|
|
171
|
+
if (!readable) {
|
|
172
|
+
throw new ReckerError('WebSocket has no readable stream', undefined, undefined, [
|
|
173
|
+
'Ensure the WebSocket is connected before piping.',
|
|
174
|
+
'Verify the runtime supports readable streams on WebSocket.',
|
|
175
|
+
'Fallback to event-based message handling if streaming is unavailable.'
|
|
176
|
+
]);
|
|
177
|
+
}
|
|
178
|
+
await pipeline(readable, destination);
|
|
179
|
+
}
|
|
92
180
|
async *[Symbol.asyncIterator]() {
|
|
93
181
|
const queue = [];
|
|
94
182
|
let resolveNext = null;
|
|
@@ -146,13 +234,15 @@ export class ReckerWebSocket extends EventEmitter {
|
|
|
146
234
|
}
|
|
147
235
|
this.isReconnecting = true;
|
|
148
236
|
this.reconnectAttempts++;
|
|
149
|
-
const
|
|
150
|
-
this.
|
|
237
|
+
const baseDelay = this.backoff.base * Math.pow(this.backoff.factor, this.reconnectAttempts - 1);
|
|
238
|
+
const capped = this.backoff.max ? Math.min(baseDelay, this.backoff.max) : baseDelay;
|
|
239
|
+
const jittered = this.backoff.jitter ? randomJitter(capped) : capped;
|
|
240
|
+
this.emit('reconnecting', this.reconnectAttempts, jittered);
|
|
151
241
|
this.reconnectTimer = setTimeout(() => {
|
|
152
242
|
this.connect().catch((error) => {
|
|
153
243
|
this.emit('reconnect-error', error);
|
|
154
244
|
});
|
|
155
|
-
},
|
|
245
|
+
}, jittered);
|
|
156
246
|
}
|
|
157
247
|
clearReconnectTimer() {
|
|
158
248
|
if (this.reconnectTimer) {
|
|
@@ -166,6 +256,7 @@ export class ReckerWebSocket extends EventEmitter {
|
|
|
166
256
|
this.heartbeatTimer = setInterval(() => {
|
|
167
257
|
if (this.isConnected) {
|
|
168
258
|
this.ping();
|
|
259
|
+
this.startPongWatchdog();
|
|
169
260
|
}
|
|
170
261
|
}, this.options.heartbeatInterval);
|
|
171
262
|
}
|
|
@@ -174,6 +265,43 @@ export class ReckerWebSocket extends EventEmitter {
|
|
|
174
265
|
clearInterval(this.heartbeatTimer);
|
|
175
266
|
this.heartbeatTimer = undefined;
|
|
176
267
|
}
|
|
268
|
+
this.stopPongWatchdog();
|
|
269
|
+
}
|
|
270
|
+
startPongWatchdog() {
|
|
271
|
+
this.stopPongWatchdog();
|
|
272
|
+
if (this.options.heartbeatTimeout <= 0)
|
|
273
|
+
return;
|
|
274
|
+
this.pongWatchdog = setTimeout(() => {
|
|
275
|
+
this.emit('heartbeat-timeout');
|
|
276
|
+
if (!this.closedByUser && this.options.reconnect) {
|
|
277
|
+
this.ws?.close(4000, 'heartbeat timeout');
|
|
278
|
+
}
|
|
279
|
+
}, this.options.heartbeatTimeout);
|
|
280
|
+
}
|
|
281
|
+
stopPongWatchdog() {
|
|
282
|
+
if (this.pongWatchdog) {
|
|
283
|
+
clearTimeout(this.pongWatchdog);
|
|
284
|
+
this.pongWatchdog = undefined;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
getBufferedAmount() {
|
|
288
|
+
return this.ws?.bufferedAmount ?? 0;
|
|
289
|
+
}
|
|
290
|
+
async waitForDrain(highWaterMark) {
|
|
291
|
+
const buffered = this.getBufferedAmount();
|
|
292
|
+
if (buffered <= highWaterMark)
|
|
293
|
+
return;
|
|
294
|
+
await new Promise((resolve) => {
|
|
295
|
+
const check = () => {
|
|
296
|
+
if (this.getBufferedAmount() <= highWaterMark || !this.isConnected) {
|
|
297
|
+
resolve();
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
setTimeout(check, 10);
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
setTimeout(check, 10);
|
|
304
|
+
});
|
|
177
305
|
}
|
|
178
306
|
}
|
|
179
307
|
export function websocket(url, options) {
|
|
@@ -182,3 +310,7 @@ export function websocket(url, options) {
|
|
|
182
310
|
});
|
|
183
311
|
return ws;
|
|
184
312
|
}
|
|
313
|
+
function randomJitter(value) {
|
|
314
|
+
const jitter = 0.2 * value;
|
|
315
|
+
return value - jitter + Math.random() * (2 * jitter);
|
|
316
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "recker",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "AI & DevX focused HTTP client for Node.js 18+",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -26,9 +26,12 @@
|
|
|
26
26
|
"whois",
|
|
27
27
|
"dns",
|
|
28
28
|
"proxy",
|
|
29
|
-
"ai"
|
|
29
|
+
"ai",
|
|
30
|
+
"scraping",
|
|
31
|
+
"cheerio",
|
|
32
|
+
"html-parser"
|
|
30
33
|
],
|
|
31
|
-
"author": "
|
|
34
|
+
"author": "fforattini",
|
|
32
35
|
"license": "MIT",
|
|
33
36
|
"homepage": "https://forattini-dev.github.io/recker",
|
|
34
37
|
"repository": {
|
|
@@ -53,10 +56,22 @@
|
|
|
53
56
|
"types": "./dist/core/client.d.ts",
|
|
54
57
|
"import": "./dist/core/client.js"
|
|
55
58
|
},
|
|
59
|
+
"./testing": {
|
|
60
|
+
"types": "./dist/testing/index.d.ts",
|
|
61
|
+
"import": "./dist/testing/index.js"
|
|
62
|
+
},
|
|
63
|
+
"./presets": {
|
|
64
|
+
"types": "./dist/presets/index.d.ts",
|
|
65
|
+
"import": "./dist/presets/index.js"
|
|
66
|
+
},
|
|
56
67
|
"./plugins/*": {
|
|
57
68
|
"types": "./dist/plugins/*.d.ts",
|
|
58
69
|
"import": "./dist/plugins/*.js"
|
|
59
70
|
},
|
|
71
|
+
"./scrape": {
|
|
72
|
+
"types": "./dist/scrape/index.d.ts",
|
|
73
|
+
"import": "./dist/scrape/index.js"
|
|
74
|
+
},
|
|
60
75
|
"./utils/*": {
|
|
61
76
|
"types": "./dist/utils/*.d.ts",
|
|
62
77
|
"import": "./dist/utils/*.js"
|
|
@@ -70,20 +85,41 @@
|
|
|
70
85
|
"access": "public"
|
|
71
86
|
},
|
|
72
87
|
"dependencies": {
|
|
88
|
+
"basic-ftp": "^5.0.5",
|
|
89
|
+
"glob": "^13.0.0",
|
|
90
|
+
"ssh2-sftp-client": "^12.0.1",
|
|
91
|
+
"telnet-client": "^2.2.9",
|
|
73
92
|
"undici": "^7.16.0",
|
|
74
93
|
"zod": "^4.1.13"
|
|
75
94
|
},
|
|
95
|
+
"peerDependencies": {
|
|
96
|
+
"cheerio": "^1.0.0",
|
|
97
|
+
"ioredis": "^5.0.0"
|
|
98
|
+
},
|
|
99
|
+
"peerDependenciesMeta": {
|
|
100
|
+
"cheerio": {
|
|
101
|
+
"optional": true
|
|
102
|
+
},
|
|
103
|
+
"ioredis": {
|
|
104
|
+
"optional": true
|
|
105
|
+
}
|
|
106
|
+
},
|
|
76
107
|
"devDependencies": {
|
|
108
|
+
"@types/needle": "^3.3.0",
|
|
77
109
|
"@types/node": "^24.10.1",
|
|
110
|
+
"@types/ssh2-sftp-client": "^9.0.5",
|
|
111
|
+
"@types/superagent": "^8.1.9",
|
|
78
112
|
"@vitest/coverage-v8": "^3.2.4",
|
|
79
113
|
"axios": "^1.13.2",
|
|
80
|
-
"
|
|
81
|
-
"docsify-
|
|
114
|
+
"cheerio": "^1.0.0",
|
|
115
|
+
"docsify-cli": "^4.4.4",
|
|
116
|
+
"domhandler": "^5.0.3",
|
|
82
117
|
"got": "^14.6.5",
|
|
83
118
|
"husky": "^9.1.7",
|
|
84
119
|
"ky": "^1.14.0",
|
|
85
|
-
"mermaid": "^11.12.1",
|
|
86
120
|
"mitata": "^1.0.34",
|
|
121
|
+
"needle": "^3.3.1",
|
|
122
|
+
"superagent": "^10.2.3",
|
|
87
123
|
"tsx": "^4.20.6",
|
|
88
124
|
"typescript": "^5.9.3",
|
|
89
125
|
"vitest": "^3.2.4"
|
|
@@ -94,7 +130,8 @@
|
|
|
94
130
|
"test:coverage": "vitest run --coverage",
|
|
95
131
|
"bench": "tsx benchmark/index.ts",
|
|
96
132
|
"bench:all": "tsx benchmark/run-all.ts",
|
|
97
|
-
"docs:dev": "
|
|
98
|
-
"docs:preview": "npx -y docsify-cli serve docs --port 3000 --open"
|
|
133
|
+
"docs:dev": "docsify serve docs --port 3000",
|
|
134
|
+
"docs:preview": "npx -y docsify-cli serve docs --port 3000 --open",
|
|
135
|
+
"lint": "echo \"No linting configured for this project.\" && exit 0"
|
|
99
136
|
}
|
|
100
137
|
}
|