rezo 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +1507 -0
- package/assets/icon.svg +37 -0
- package/assets/logo-dark.svg +47 -0
- package/assets/logo.svg +58 -0
- package/dist/adapters/curl.cjs +1034 -0
- package/dist/adapters/curl.js +1031 -0
- package/dist/adapters/entries/curl.cjs +4 -0
- package/dist/adapters/entries/curl.d.ts +2136 -0
- package/dist/adapters/entries/curl.js +2 -0
- package/dist/adapters/entries/fetch.cjs +2 -0
- package/dist/adapters/entries/fetch.d.ts +2127 -0
- package/dist/adapters/entries/fetch.js +1 -0
- package/dist/adapters/entries/http.cjs +2 -0
- package/dist/adapters/entries/http.d.ts +2126 -0
- package/dist/adapters/entries/http.js +1 -0
- package/dist/adapters/entries/http2.cjs +4 -0
- package/dist/adapters/entries/http2.d.ts +2136 -0
- package/dist/adapters/entries/http2.js +2 -0
- package/dist/adapters/entries/react-native.cjs +2 -0
- package/dist/adapters/entries/react-native.d.ts +2126 -0
- package/dist/adapters/entries/react-native.js +1 -0
- package/dist/adapters/entries/xhr.cjs +2 -0
- package/dist/adapters/entries/xhr.d.ts +2127 -0
- package/dist/adapters/entries/xhr.js +1 -0
- package/dist/adapters/fetch.cjs +740 -0
- package/dist/adapters/fetch.js +739 -0
- package/dist/adapters/http.cjs +1153 -0
- package/dist/adapters/http.js +1151 -0
- package/dist/adapters/http2.cjs +957 -0
- package/dist/adapters/http2.js +956 -0
- package/dist/adapters/index.cjs +6 -0
- package/dist/adapters/index.js +7 -0
- package/dist/adapters/picker.cjs +342 -0
- package/dist/adapters/picker.js +331 -0
- package/dist/adapters/react-native.cjs +545 -0
- package/dist/adapters/react-native.js +544 -0
- package/dist/adapters/xhr.cjs +622 -0
- package/dist/adapters/xhr.js +621 -0
- package/dist/cache/dns-cache.cjs +118 -0
- package/dist/cache/dns-cache.js +113 -0
- package/dist/cache/file-cacher.cjs +264 -0
- package/dist/cache/file-cacher.js +261 -0
- package/dist/cache/index.cjs +13 -0
- package/dist/cache/index.js +5 -0
- package/dist/cache/lru-cache.cjs +96 -0
- package/dist/cache/lru-cache.js +93 -0
- package/dist/cache/response-cache.cjs +314 -0
- package/dist/cache/response-cache.js +310 -0
- package/dist/cache/url-store.cjs +288 -0
- package/dist/cache/url-store.js +285 -0
- package/dist/core/hooks.cjs +133 -0
- package/dist/core/hooks.js +120 -0
- package/dist/core/rezo.cjs +464 -0
- package/dist/core/rezo.js +458 -0
- package/dist/crawler.d.ts +6255 -0
- package/dist/dom/index.cjs +1 -0
- package/dist/dom/index.d.ts +23 -0
- package/dist/dom/index.js +1 -0
- package/dist/entries/crawler.cjs +5 -0
- package/dist/entries/crawler.js +2 -0
- package/dist/errors/rezo-error.cjs +722 -0
- package/dist/errors/rezo-error.js +716 -0
- package/dist/index.cjs +34 -0
- package/dist/index.d.ts +3335 -0
- package/dist/index.js +26 -0
- package/dist/platform/browser.cjs +9 -0
- package/dist/platform/browser.d.ts +3203 -0
- package/dist/platform/browser.js +7 -0
- package/dist/platform/bun.cjs +9 -0
- package/dist/platform/bun.d.ts +3203 -0
- package/dist/platform/bun.js +7 -0
- package/dist/platform/deno.cjs +9 -0
- package/dist/platform/deno.d.ts +3203 -0
- package/dist/platform/deno.js +7 -0
- package/dist/platform/node.cjs +9 -0
- package/dist/platform/node.d.ts +3203 -0
- package/dist/platform/node.js +7 -0
- package/dist/platform/react-native.cjs +9 -0
- package/dist/platform/react-native.d.ts +3203 -0
- package/dist/platform/react-native.js +7 -0
- package/dist/platform/worker.cjs +9 -0
- package/dist/platform/worker.d.ts +3203 -0
- package/dist/platform/worker.js +7 -0
- package/dist/plugin/addon/decodo/index.cjs +1 -0
- package/dist/plugin/addon/decodo/index.js +1 -0
- package/dist/plugin/addon/decodo/options.cjs +1 -0
- package/dist/plugin/addon/decodo/options.js +1 -0
- package/dist/plugin/addon/oxylabs/index.cjs +1 -0
- package/dist/plugin/addon/oxylabs/index.js +1 -0
- package/dist/plugin/addon/oxylabs/options.cjs +1 -0
- package/dist/plugin/addon/oxylabs/options.js +1 -0
- package/dist/plugin/crawler-options.cjs +1 -0
- package/dist/plugin/crawler-options.js +1 -0
- package/dist/plugin/crawler.cjs +519 -0
- package/dist/plugin/crawler.js +517 -0
- package/dist/plugin/index.cjs +36 -0
- package/dist/plugin/index.js +32 -0
- package/dist/proxy/index.cjs +142 -0
- package/dist/proxy/index.js +139 -0
- package/dist/responses/buildError.cjs +452 -0
- package/dist/responses/buildError.js +441 -0
- package/dist/responses/buildResponse.cjs +365 -0
- package/dist/responses/buildResponse.js +361 -0
- package/dist/responses/download.cjs +54 -0
- package/dist/responses/download.js +52 -0
- package/dist/responses/stream.cjs +60 -0
- package/dist/responses/stream.js +58 -0
- package/dist/responses/upload.cjs +54 -0
- package/dist/responses/upload.js +52 -0
- package/dist/types/cookies.cjs +394 -0
- package/dist/types/cookies.js +391 -0
- package/dist/types/download.cjs +10 -0
- package/dist/types/download.js +10 -0
- package/dist/types/rezo-request.cjs +131 -0
- package/dist/types/rezo-request.js +131 -0
- package/dist/utils/agent-merger.cjs +111 -0
- package/dist/utils/agent-merger.js +108 -0
- package/dist/utils/compression.cjs +84 -0
- package/dist/utils/compression.js +82 -0
- package/dist/utils/cookies.cjs +514 -0
- package/dist/utils/cookies.js +511 -0
- package/dist/utils/data-operations.cjs +75 -0
- package/dist/utils/data-operations.js +73 -0
- package/dist/utils/form-data.cjs +164 -0
- package/dist/utils/form-data.js +161 -0
- package/dist/utils/headers.cjs +162 -0
- package/dist/utils/headers.js +161 -0
- package/dist/utils/http-config.cjs +723 -0
- package/dist/utils/http-config.js +718 -0
- package/dist/utils/index.cjs +8 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/tools.cjs +18 -0
- package/dist/utils/tools.js +15 -0
- package/package.json +172 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const http = require("node:http");
|
|
2
|
+
const https = require("node:https");
|
|
3
|
+
const { rezoProxy } = require('../proxy/index.cjs');
|
|
4
|
+
|
|
5
|
+
class AgentMerger {
|
|
6
|
+
static merge(options) {
|
|
7
|
+
const { proxy, httpAgent, httpsAgent, isSecure = false, mergeOptions = {} } = options;
|
|
8
|
+
if (!proxy && !httpAgent && !httpsAgent) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (!proxy) {
|
|
12
|
+
return isSecure ? httpsAgent : httpAgent;
|
|
13
|
+
}
|
|
14
|
+
if (!httpAgent && !httpsAgent) {
|
|
15
|
+
return this.createProxyAgent(proxy);
|
|
16
|
+
}
|
|
17
|
+
return this.mergeProxyWithCustomAgent(proxy, isSecure ? httpsAgent : httpAgent, isSecure, mergeOptions);
|
|
18
|
+
}
|
|
19
|
+
static createProxyAgent(proxy) {
|
|
20
|
+
if (!proxy) {
|
|
21
|
+
throw new Error("Proxy configuration is required");
|
|
22
|
+
}
|
|
23
|
+
if (typeof proxy === "string") {
|
|
24
|
+
return rezoProxy(proxy);
|
|
25
|
+
}
|
|
26
|
+
return rezoProxy(proxy);
|
|
27
|
+
}
|
|
28
|
+
static mergeProxyWithCustomAgent(proxy, customAgent, isSecure, mergeOptions = {}) {
|
|
29
|
+
if (!customAgent) {
|
|
30
|
+
return this.createProxyAgent(proxy);
|
|
31
|
+
}
|
|
32
|
+
const customOptions = this.extractAgentOptions(customAgent);
|
|
33
|
+
const proxyAgent = this.createProxyAgent(proxy);
|
|
34
|
+
const proxyOptions = this.extractAgentOptions(proxyAgent);
|
|
35
|
+
const mergedOptions = {
|
|
36
|
+
...proxyOptions,
|
|
37
|
+
...customOptions,
|
|
38
|
+
...mergeOptions,
|
|
39
|
+
proxy: this.extractProxyConfig(proxyAgent)
|
|
40
|
+
};
|
|
41
|
+
if (isSecure) {
|
|
42
|
+
return new https.Agent(mergedOptions);
|
|
43
|
+
} else {
|
|
44
|
+
return new http.Agent(mergedOptions);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
static extractAgentOptions(agent) {
|
|
48
|
+
const options = {};
|
|
49
|
+
if (agent.keepAlive !== undefined)
|
|
50
|
+
options.keepAlive = agent.keepAlive;
|
|
51
|
+
if (agent.keepAliveMsecs !== undefined)
|
|
52
|
+
options.keepAliveMsecs = agent.keepAliveMsecs;
|
|
53
|
+
if (agent.maxSockets !== undefined)
|
|
54
|
+
options.maxSockets = agent.maxSockets;
|
|
55
|
+
if (agent.maxFreeSockets !== undefined)
|
|
56
|
+
options.maxFreeSockets = agent.maxFreeSockets;
|
|
57
|
+
if (agent.timeout !== undefined)
|
|
58
|
+
options.timeout = agent.timeout;
|
|
59
|
+
if (agent instanceof https.Agent) {
|
|
60
|
+
const httpsAgent = agent;
|
|
61
|
+
if (httpsAgent.options?.rejectUnauthorized !== undefined) {
|
|
62
|
+
options.rejectUnauthorized = httpsAgent.options.rejectUnauthorized;
|
|
63
|
+
}
|
|
64
|
+
if (httpsAgent.options?.ca)
|
|
65
|
+
options.ca = httpsAgent.options.ca;
|
|
66
|
+
if (httpsAgent.options?.cert)
|
|
67
|
+
options.cert = httpsAgent.options.cert;
|
|
68
|
+
if (httpsAgent.options?.key)
|
|
69
|
+
options.key = httpsAgent.options.key;
|
|
70
|
+
if (httpsAgent.options?.pfx)
|
|
71
|
+
options.pfx = httpsAgent.options.pfx;
|
|
72
|
+
if (httpsAgent.options?.passphrase)
|
|
73
|
+
options.passphrase = httpsAgent.options.passphrase;
|
|
74
|
+
if (httpsAgent.options?.ciphers)
|
|
75
|
+
options.ciphers = httpsAgent.options.ciphers;
|
|
76
|
+
if (httpsAgent.options?.secureProtocol)
|
|
77
|
+
options.secureProtocol = httpsAgent.options.secureProtocol;
|
|
78
|
+
}
|
|
79
|
+
return options;
|
|
80
|
+
}
|
|
81
|
+
static extractProxyConfig(proxyAgent) {
|
|
82
|
+
return proxyAgent.proxy || proxyAgent.proxyOptions || undefined;
|
|
83
|
+
}
|
|
84
|
+
static createMergedAgent(options) {
|
|
85
|
+
const { proxy, customAgent, isSecure = false, capabilities = {} } = options;
|
|
86
|
+
return this.merge({
|
|
87
|
+
proxy,
|
|
88
|
+
httpAgent: !isSecure ? customAgent : undefined,
|
|
89
|
+
httpsAgent: isSecure ? customAgent : undefined,
|
|
90
|
+
isSecure,
|
|
91
|
+
mergeOptions: capabilities
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
static isProxyAgent(agent) {
|
|
95
|
+
return !!agent.proxy || !!agent.proxyOptions;
|
|
96
|
+
}
|
|
97
|
+
static getProxyInfo(agent) {
|
|
98
|
+
return agent.proxy || agent.proxyOptions || null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function mergeAgents(proxy, customAgent, isSecure = false) {
|
|
102
|
+
return AgentMerger.merge({
|
|
103
|
+
proxy,
|
|
104
|
+
httpAgent: !isSecure ? customAgent : undefined,
|
|
105
|
+
httpsAgent: isSecure ? customAgent : undefined,
|
|
106
|
+
isSecure
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
exports.AgentMerger = AgentMerger;
|
|
111
|
+
exports.mergeAgents = mergeAgents;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import * as http from "node:http";
|
|
2
|
+
import * as https from "node:https";
|
|
3
|
+
import { rezoProxy } from '../proxy/index.js';
|
|
4
|
+
|
|
5
|
+
export class AgentMerger {
|
|
6
|
+
static merge(options) {
|
|
7
|
+
const { proxy, httpAgent, httpsAgent, isSecure = false, mergeOptions = {} } = options;
|
|
8
|
+
if (!proxy && !httpAgent && !httpsAgent) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (!proxy) {
|
|
12
|
+
return isSecure ? httpsAgent : httpAgent;
|
|
13
|
+
}
|
|
14
|
+
if (!httpAgent && !httpsAgent) {
|
|
15
|
+
return this.createProxyAgent(proxy);
|
|
16
|
+
}
|
|
17
|
+
return this.mergeProxyWithCustomAgent(proxy, isSecure ? httpsAgent : httpAgent, isSecure, mergeOptions);
|
|
18
|
+
}
|
|
19
|
+
static createProxyAgent(proxy) {
|
|
20
|
+
if (!proxy) {
|
|
21
|
+
throw new Error("Proxy configuration is required");
|
|
22
|
+
}
|
|
23
|
+
if (typeof proxy === "string") {
|
|
24
|
+
return rezoProxy(proxy);
|
|
25
|
+
}
|
|
26
|
+
return rezoProxy(proxy);
|
|
27
|
+
}
|
|
28
|
+
static mergeProxyWithCustomAgent(proxy, customAgent, isSecure, mergeOptions = {}) {
|
|
29
|
+
if (!customAgent) {
|
|
30
|
+
return this.createProxyAgent(proxy);
|
|
31
|
+
}
|
|
32
|
+
const customOptions = this.extractAgentOptions(customAgent);
|
|
33
|
+
const proxyAgent = this.createProxyAgent(proxy);
|
|
34
|
+
const proxyOptions = this.extractAgentOptions(proxyAgent);
|
|
35
|
+
const mergedOptions = {
|
|
36
|
+
...proxyOptions,
|
|
37
|
+
...customOptions,
|
|
38
|
+
...mergeOptions,
|
|
39
|
+
proxy: this.extractProxyConfig(proxyAgent)
|
|
40
|
+
};
|
|
41
|
+
if (isSecure) {
|
|
42
|
+
return new https.Agent(mergedOptions);
|
|
43
|
+
} else {
|
|
44
|
+
return new http.Agent(mergedOptions);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
static extractAgentOptions(agent) {
|
|
48
|
+
const options = {};
|
|
49
|
+
if (agent.keepAlive !== undefined)
|
|
50
|
+
options.keepAlive = agent.keepAlive;
|
|
51
|
+
if (agent.keepAliveMsecs !== undefined)
|
|
52
|
+
options.keepAliveMsecs = agent.keepAliveMsecs;
|
|
53
|
+
if (agent.maxSockets !== undefined)
|
|
54
|
+
options.maxSockets = agent.maxSockets;
|
|
55
|
+
if (agent.maxFreeSockets !== undefined)
|
|
56
|
+
options.maxFreeSockets = agent.maxFreeSockets;
|
|
57
|
+
if (agent.timeout !== undefined)
|
|
58
|
+
options.timeout = agent.timeout;
|
|
59
|
+
if (agent instanceof https.Agent) {
|
|
60
|
+
const httpsAgent = agent;
|
|
61
|
+
if (httpsAgent.options?.rejectUnauthorized !== undefined) {
|
|
62
|
+
options.rejectUnauthorized = httpsAgent.options.rejectUnauthorized;
|
|
63
|
+
}
|
|
64
|
+
if (httpsAgent.options?.ca)
|
|
65
|
+
options.ca = httpsAgent.options.ca;
|
|
66
|
+
if (httpsAgent.options?.cert)
|
|
67
|
+
options.cert = httpsAgent.options.cert;
|
|
68
|
+
if (httpsAgent.options?.key)
|
|
69
|
+
options.key = httpsAgent.options.key;
|
|
70
|
+
if (httpsAgent.options?.pfx)
|
|
71
|
+
options.pfx = httpsAgent.options.pfx;
|
|
72
|
+
if (httpsAgent.options?.passphrase)
|
|
73
|
+
options.passphrase = httpsAgent.options.passphrase;
|
|
74
|
+
if (httpsAgent.options?.ciphers)
|
|
75
|
+
options.ciphers = httpsAgent.options.ciphers;
|
|
76
|
+
if (httpsAgent.options?.secureProtocol)
|
|
77
|
+
options.secureProtocol = httpsAgent.options.secureProtocol;
|
|
78
|
+
}
|
|
79
|
+
return options;
|
|
80
|
+
}
|
|
81
|
+
static extractProxyConfig(proxyAgent) {
|
|
82
|
+
return proxyAgent.proxy || proxyAgent.proxyOptions || undefined;
|
|
83
|
+
}
|
|
84
|
+
static createMergedAgent(options) {
|
|
85
|
+
const { proxy, customAgent, isSecure = false, capabilities = {} } = options;
|
|
86
|
+
return this.merge({
|
|
87
|
+
proxy,
|
|
88
|
+
httpAgent: !isSecure ? customAgent : undefined,
|
|
89
|
+
httpsAgent: isSecure ? customAgent : undefined,
|
|
90
|
+
isSecure,
|
|
91
|
+
mergeOptions: capabilities
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
static isProxyAgent(agent) {
|
|
95
|
+
return !!agent.proxy || !!agent.proxyOptions;
|
|
96
|
+
}
|
|
97
|
+
static getProxyInfo(agent) {
|
|
98
|
+
return agent.proxy || agent.proxyOptions || null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export function mergeAgents(proxy, customAgent, isSecure = false) {
|
|
102
|
+
return AgentMerger.merge({
|
|
103
|
+
proxy,
|
|
104
|
+
httpAgent: !isSecure ? customAgent : undefined,
|
|
105
|
+
httpsAgent: isSecure ? customAgent : undefined,
|
|
106
|
+
isSecure
|
|
107
|
+
});
|
|
108
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
const { createGunzip, createInflate, createBrotliDecompress } = require("node:zlib");
|
|
2
|
+
const { Transform } = require("node:stream");
|
|
3
|
+
let createZstdDecompress = null;
|
|
4
|
+
let zstdAvailable = null;
|
|
5
|
+
function getZstdDecompressor() {
|
|
6
|
+
if (zstdAvailable === null) {
|
|
7
|
+
try {
|
|
8
|
+
const zlib = require("node:zlib");
|
|
9
|
+
if (typeof zlib.createZstdDecompress === "function") {
|
|
10
|
+
createZstdDecompress = zlib.createZstdDecompress;
|
|
11
|
+
zstdAvailable = true;
|
|
12
|
+
} else {
|
|
13
|
+
zstdAvailable = false;
|
|
14
|
+
}
|
|
15
|
+
} catch {
|
|
16
|
+
zstdAvailable = false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return createZstdDecompress;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class CompressionUtil {
|
|
23
|
+
static decompressStream(response, contentEncoding, config) {
|
|
24
|
+
if (!contentEncoding) {
|
|
25
|
+
return response;
|
|
26
|
+
}
|
|
27
|
+
if (!this.shouldDecompress(contentEncoding, config)) {
|
|
28
|
+
return response;
|
|
29
|
+
}
|
|
30
|
+
const encoding = contentEncoding.toLowerCase();
|
|
31
|
+
switch (encoding) {
|
|
32
|
+
case "gzip":
|
|
33
|
+
case "x-gzip":
|
|
34
|
+
return response.pipe(createGunzip());
|
|
35
|
+
case "deflate":
|
|
36
|
+
case "x-deflate":
|
|
37
|
+
return response.pipe(createInflate());
|
|
38
|
+
case "gzip-raw":
|
|
39
|
+
return response.pipe(createInflate({ windowBits: 15 }));
|
|
40
|
+
case "br":
|
|
41
|
+
case "brotli":
|
|
42
|
+
return response.pipe(createBrotliDecompress());
|
|
43
|
+
case "zstd":
|
|
44
|
+
return this.createZstdDecompressStream(response);
|
|
45
|
+
default:
|
|
46
|
+
return response;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
static shouldDecompress(contentEncoding, config) {
|
|
50
|
+
if (!config) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
if (config.compression?.enabled === false) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
if (config.compression?.enabled === undefined) {
|
|
57
|
+
if (config.compression?.algorithms) {
|
|
58
|
+
return config.compression.algorithms.includes(contentEncoding.toLowerCase());
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return config.compression.enabled;
|
|
63
|
+
}
|
|
64
|
+
static createZstdDecompressStream(response) {
|
|
65
|
+
const decompressor = getZstdDecompressor();
|
|
66
|
+
if (!decompressor) {
|
|
67
|
+
const passthrough = new Transform({
|
|
68
|
+
transform(chunk, encoding, callback) {
|
|
69
|
+
callback(new Error("zstd decompression not available: requires Node.js 22.15+ with native zstd support"));
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
return response.pipe(passthrough);
|
|
73
|
+
}
|
|
74
|
+
return response.pipe(decompressor());
|
|
75
|
+
}
|
|
76
|
+
static getSupportedAlgorithms() {
|
|
77
|
+
return ["gzip", "x-gzip", "deflate", "x-deflate", "gzip-raw", "br", "brotli", "zstd"];
|
|
78
|
+
}
|
|
79
|
+
static isSupported(contentEncoding) {
|
|
80
|
+
return this.getSupportedAlgorithms().includes(contentEncoding.toLowerCase());
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
exports.CompressionUtil = CompressionUtil;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { createGunzip, createInflate, createBrotliDecompress } from "node:zlib";
|
|
2
|
+
import { Transform } from "node:stream";
|
|
3
|
+
let createZstdDecompress = null;
|
|
4
|
+
let zstdAvailable = null;
|
|
5
|
+
function getZstdDecompressor() {
|
|
6
|
+
if (zstdAvailable === null) {
|
|
7
|
+
try {
|
|
8
|
+
const zlib = require("node:zlib");
|
|
9
|
+
if (typeof zlib.createZstdDecompress === "function") {
|
|
10
|
+
createZstdDecompress = zlib.createZstdDecompress;
|
|
11
|
+
zstdAvailable = true;
|
|
12
|
+
} else {
|
|
13
|
+
zstdAvailable = false;
|
|
14
|
+
}
|
|
15
|
+
} catch {
|
|
16
|
+
zstdAvailable = false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return createZstdDecompress;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class CompressionUtil {
|
|
23
|
+
static decompressStream(response, contentEncoding, config) {
|
|
24
|
+
if (!contentEncoding) {
|
|
25
|
+
return response;
|
|
26
|
+
}
|
|
27
|
+
if (!this.shouldDecompress(contentEncoding, config)) {
|
|
28
|
+
return response;
|
|
29
|
+
}
|
|
30
|
+
const encoding = contentEncoding.toLowerCase();
|
|
31
|
+
switch (encoding) {
|
|
32
|
+
case "gzip":
|
|
33
|
+
case "x-gzip":
|
|
34
|
+
return response.pipe(createGunzip());
|
|
35
|
+
case "deflate":
|
|
36
|
+
case "x-deflate":
|
|
37
|
+
return response.pipe(createInflate());
|
|
38
|
+
case "gzip-raw":
|
|
39
|
+
return response.pipe(createInflate({ windowBits: 15 }));
|
|
40
|
+
case "br":
|
|
41
|
+
case "brotli":
|
|
42
|
+
return response.pipe(createBrotliDecompress());
|
|
43
|
+
case "zstd":
|
|
44
|
+
return this.createZstdDecompressStream(response);
|
|
45
|
+
default:
|
|
46
|
+
return response;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
static shouldDecompress(contentEncoding, config) {
|
|
50
|
+
if (!config) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
if (config.compression?.enabled === false) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
if (config.compression?.enabled === undefined) {
|
|
57
|
+
if (config.compression?.algorithms) {
|
|
58
|
+
return config.compression.algorithms.includes(contentEncoding.toLowerCase());
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return config.compression.enabled;
|
|
63
|
+
}
|
|
64
|
+
static createZstdDecompressStream(response) {
|
|
65
|
+
const decompressor = getZstdDecompressor();
|
|
66
|
+
if (!decompressor) {
|
|
67
|
+
const passthrough = new Transform({
|
|
68
|
+
transform(chunk, encoding, callback) {
|
|
69
|
+
callback(new Error("zstd decompression not available: requires Node.js 22.15+ with native zstd support"));
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
return response.pipe(passthrough);
|
|
73
|
+
}
|
|
74
|
+
return response.pipe(decompressor());
|
|
75
|
+
}
|
|
76
|
+
static getSupportedAlgorithms() {
|
|
77
|
+
return ["gzip", "x-gzip", "deflate", "x-deflate", "gzip-raw", "br", "brotli", "zstd"];
|
|
78
|
+
}
|
|
79
|
+
static isSupported(contentEncoding) {
|
|
80
|
+
return this.getSupportedAlgorithms().includes(contentEncoding.toLowerCase());
|
|
81
|
+
}
|
|
82
|
+
}
|