@hyperttp/core 1.2.6 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Core/HyperCore.d.ts +145 -23
- package/Core/HyperCore.d.ts.map +1 -1
- package/Core/HyperCore.js +325 -231
- package/Core/HyperCore.js.map +1 -1
- package/package.json +6 -3
- package/transports/manager.d.ts +102 -0
- package/transports/manager.d.ts.map +1 -0
- package/transports/manager.js +293 -0
- package/transports/manager.js.map +1 -0
- package/transports/node.d.ts +40 -10
- package/transports/node.d.ts.map +1 -1
- package/transports/node.js +106 -325
- package/transports/node.js.map +1 -1
- package/utils/decompress.d.ts +29 -0
- package/utils/decompress.d.ts.map +1 -0
- package/utils/decompress.js +117 -0
- package/utils/decompress.js.map +1 -0
- package/utils/normalize.d.ts +28 -1
- package/utils/normalize.d.ts.map +1 -1
- package/utils/normalize.js +173 -61
- package/utils/normalize.js.map +1 -1
- package/utils/pipeline.d.ts +51 -10
- package/utils/pipeline.d.ts.map +1 -1
- package/utils/pipeline.js +126 -21
- package/utils/pipeline.js.map +1 -1
- package/utils/response.d.ts +0 -3
- package/utils/response.d.ts.map +1 -1
- package/utils/response.js +0 -3
- package/utils/response.js.map +1 -1
- package/utils/retryUtils.d.ts +20 -0
- package/utils/retryUtils.d.ts.map +1 -1
- package/utils/retryUtils.js +24 -0
- package/utils/retryUtils.js.map +1 -1
package/Core/HyperCore.js
CHANGED
|
@@ -1,124 +1,88 @@
|
|
|
1
1
|
import { defaultConfig } from "../defaultConfig.js";
|
|
2
2
|
import { mapResponseFast, mapStreamFast, mergeHeadersFast, } from "../utils/response.js";
|
|
3
|
-
import {
|
|
4
|
-
import { createPipelines, executeErrorPipeline, executeRequestPipeline, executeResponsePipeline, insertHookSorted, } from "../utils/pipeline.js";
|
|
5
|
-
import { normalizeBody, normalizeHeaders,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export const TRANSPORTS = [
|
|
12
|
-
{
|
|
13
|
-
name: "Bun",
|
|
14
|
-
runtime: ["bun"],
|
|
15
|
-
pkg: "@hyperttp/transport-bun",
|
|
16
|
-
export: "BunTransport",
|
|
17
|
-
priority: 100,
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
name: "Undici",
|
|
21
|
-
runtime: ["node"],
|
|
22
|
-
pkg: "@hyperttp/transport-undici",
|
|
23
|
-
export: "UndiciTransport",
|
|
24
|
-
priority: 90,
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
name: "Node",
|
|
28
|
-
runtime: ["node", "bun"],
|
|
29
|
-
pkg: "../transports/node.js",
|
|
30
|
-
export: "NodeTransport",
|
|
31
|
-
priority: 10,
|
|
32
|
-
},
|
|
33
|
-
];
|
|
34
|
-
export async function resolveTransport(config) {
|
|
35
|
-
if (config.customTransport) {
|
|
36
|
-
config.logger?.("debug", "Using user-provided custom transport.");
|
|
37
|
-
return config.customTransport;
|
|
38
|
-
}
|
|
39
|
-
const runtime = getRuntime();
|
|
40
|
-
const candidates = TRANSPORTS.filter((t) => t.runtime.includes(runtime)).sort((a, b) => b.priority - a.priority);
|
|
41
|
-
const localRequire = createRequire(process.cwd() + "/package.json");
|
|
42
|
-
for (const t of candidates) {
|
|
43
|
-
config.logger?.("debug", `Loading transport: ${t.name}`);
|
|
44
|
-
try {
|
|
45
|
-
const path = t.pkg.startsWith(".")
|
|
46
|
-
? new URL(t.pkg, import.meta.url).href
|
|
47
|
-
: localRequire.resolve(t.pkg);
|
|
48
|
-
const mod = await import(path);
|
|
49
|
-
const Transport = mod[t.export] || mod.default?.[t.export] || mod.default;
|
|
50
|
-
if (!Transport)
|
|
51
|
-
continue;
|
|
52
|
-
config.logger?.("info", `Selected transport: ${t.name}`);
|
|
53
|
-
return new Transport(config);
|
|
54
|
-
}
|
|
55
|
-
catch (e) {
|
|
56
|
-
config.logger?.("debug", `Skip ${t.name}: ${e}`);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
throw new Error(`No compatible transport implementation available for runtime: ${runtime}`);
|
|
60
|
-
}
|
|
3
|
+
import { TransportManager } from "../transports/manager.js";
|
|
4
|
+
import { createPipelines, executeErrorPipeline, executeRequestPipeline, executeResponsePipeline, executeResponseDataPipeline, insertHookSorted, } from "../utils/pipeline.js";
|
|
5
|
+
import { normalizeBody, normalizeHeaders, normalizeUrl, } from "../utils/normalize.js";
|
|
6
|
+
import { decompressBuffer, createDecompressStream, } from "../utils/decompress.js";
|
|
7
|
+
/**
|
|
8
|
+
* @ru Основной класс HTTP-клиента Hyperttp. Управляет транспортами, плагинами, перехватчиками, повторными попытками и сжатием.
|
|
9
|
+
* @en Core HTTP client class for Hyperttp. Manages transports, plugins, interceptors, retries, and compression.
|
|
10
|
+
*/
|
|
61
11
|
export class HyperCore {
|
|
12
|
+
/** @ru Конфигурация клиента (базовый URL, таймауты, заголовки и т.д.). @en Client configuration (base URL, timeouts, headers, etc.). */
|
|
62
13
|
config;
|
|
63
|
-
|
|
64
|
-
transportPromise = null;
|
|
14
|
+
transportManager;
|
|
65
15
|
defaultHeaders;
|
|
66
16
|
pluginCtx;
|
|
67
17
|
pipelines = createPipelines();
|
|
18
|
+
/**
|
|
19
|
+
* @ru Создаёт экземпляр HyperCore.
|
|
20
|
+
* @en Creates an instance of HyperCore.
|
|
21
|
+
* @param config - Client configuration options.
|
|
22
|
+
* @param transport - Optional custom transport implementation.
|
|
23
|
+
*/
|
|
68
24
|
constructor(config = defaultConfig, transport) {
|
|
69
25
|
this.config = {
|
|
70
26
|
...defaultConfig,
|
|
71
27
|
...config,
|
|
72
28
|
network: { ...defaultConfig.network, ...config.network },
|
|
73
29
|
};
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
this.transportPromise = Promise.resolve(transport);
|
|
77
|
-
if ("config" in transport) {
|
|
78
|
-
transport.config = this.config;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
this.defaultHeaders = {
|
|
30
|
+
this.transportManager = new TransportManager(this.config, transport);
|
|
31
|
+
this.defaultHeaders = normalizeHeaders({
|
|
82
32
|
Accept: "application/json, text/plain, */*",
|
|
83
33
|
"Accept-Encoding": "gzip, deflate, br",
|
|
84
34
|
"User-Agent": this.config.network?.userAgent ?? "Hyperttp/2.0",
|
|
85
35
|
...this.config.network?.headers,
|
|
86
|
-
};
|
|
36
|
+
});
|
|
87
37
|
this.pluginCtx = { config: this.config, core: this };
|
|
88
38
|
}
|
|
89
|
-
|
|
90
|
-
return
|
|
39
|
+
get transport() {
|
|
40
|
+
return this.transportManager.instance;
|
|
91
41
|
}
|
|
92
42
|
ensureTransport() {
|
|
93
|
-
return
|
|
94
|
-
(this.transportPromise = this.createTransport().then((t) => {
|
|
95
|
-
this.transport = t;
|
|
96
|
-
return t;
|
|
97
|
-
})));
|
|
43
|
+
return this.transportManager.get();
|
|
98
44
|
}
|
|
99
|
-
async
|
|
45
|
+
async dispatchInternal(req) {
|
|
100
46
|
try {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
47
|
+
if (this.pipelines.request.length > 0) {
|
|
48
|
+
const shortCircuit = await executeRequestPipeline(this.pipelines.request, req, this.pluginCtx);
|
|
49
|
+
if (shortCircuit) {
|
|
50
|
+
await this.runResponsePipeline(shortCircuit, req);
|
|
51
|
+
return shortCircuit;
|
|
52
|
+
}
|
|
105
53
|
}
|
|
106
54
|
const transport = this.transport || (await this.ensureTransport());
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
55
|
+
let rawResponse = await transport.execute(req);
|
|
56
|
+
if (this.pipelines.responseData.length > 0) {
|
|
57
|
+
rawResponse = await executeResponseDataPipeline(this.pipelines.responseData, rawResponse, this.pluginCtx);
|
|
58
|
+
}
|
|
59
|
+
this.applyDecompression(rawResponse);
|
|
60
|
+
const isStream = req.meta?.responseType === "stream";
|
|
61
|
+
const response = isStream
|
|
62
|
+
? mapStreamFast(rawResponse)
|
|
63
|
+
: mapResponseFast(rawResponse);
|
|
64
|
+
await this.runResponsePipeline(response, req);
|
|
110
65
|
return response;
|
|
111
66
|
}
|
|
112
67
|
catch (error) {
|
|
113
|
-
|
|
114
|
-
const recovered = await executeErrorPipeline(this.pipelines.error, httpError, req, this.pluginCtx);
|
|
115
|
-
if (recovered) {
|
|
116
|
-
await executeResponsePipeline(this.pipelines.responseMutators, this.pipelines.responseSideEffects, recovered, req, this.pluginCtx, this.config.logger);
|
|
117
|
-
return recovered;
|
|
118
|
-
}
|
|
119
|
-
throw error;
|
|
68
|
+
return this.handleDispatchError(error, req);
|
|
120
69
|
}
|
|
121
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* @ru Выполняет HTTP-запрос с полным контролем (через объект InternalRequest).
|
|
73
|
+
* @en Performs an HTTP request with full control (via InternalRequest object).
|
|
74
|
+
* @param req - Internal request object.
|
|
75
|
+
* @returns Promise with the HTTP response.
|
|
76
|
+
*/
|
|
77
|
+
async dispatch(req) {
|
|
78
|
+
return this.dispatchInternal(req);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* @ru Регистрирует плагин для расширения функциональности клиента.
|
|
82
|
+
* @en Registers a plugin to extend client functionality.
|
|
83
|
+
* @param plugin - Plugin instance.
|
|
84
|
+
* @returns This instance for chaining.
|
|
85
|
+
*/
|
|
122
86
|
use(plugin) {
|
|
123
87
|
const isEnabled = plugin.enabled ? plugin.enabled(this.config) : true;
|
|
124
88
|
if (!isEnabled)
|
|
@@ -134,20 +98,21 @@ export class HyperCore {
|
|
|
134
98
|
});
|
|
135
99
|
}
|
|
136
100
|
if (plugin.onResponse) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
101
|
+
const targetPipeline = plugin.mode === "background"
|
|
102
|
+
? this.pipelines.responseSideEffects
|
|
103
|
+
: this.pipelines.responseMutators;
|
|
104
|
+
insertHookSorted(targetPipeline, {
|
|
105
|
+
name: plugin.name,
|
|
106
|
+
priority,
|
|
107
|
+
run: plugin.onResponse,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
if (plugin.onResponseData) {
|
|
111
|
+
insertHookSorted(this.pipelines.responseData, {
|
|
112
|
+
name: plugin.name,
|
|
113
|
+
priority,
|
|
114
|
+
run: plugin.onResponseData,
|
|
115
|
+
});
|
|
151
116
|
}
|
|
152
117
|
if (plugin.onError) {
|
|
153
118
|
insertHookSorted(this.pipelines.error, {
|
|
@@ -158,176 +123,305 @@ export class HyperCore {
|
|
|
158
123
|
}
|
|
159
124
|
return this;
|
|
160
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* @ru Выполняет GET-запрос и возвращает ответ в виде потока (StreamResponse).
|
|
128
|
+
* @en Performs a GET request and returns the response as a stream (StreamResponse).
|
|
129
|
+
* @param req - Request URL or RequestInterface object.
|
|
130
|
+
* @param signal - Optional abort signal.
|
|
131
|
+
* @returns Promise with the stream response.
|
|
132
|
+
*/
|
|
161
133
|
async stream(req, signal) {
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const finalSignal = isStr ? signal : (req.signal ?? signal);
|
|
166
|
-
const transportArgs = {
|
|
167
|
-
method: normalizeMethod("GET"),
|
|
168
|
-
url,
|
|
169
|
-
headers: normalizeHeaders(mergeHeadersFast(this.defaultHeaders, reqHeaders)),
|
|
170
|
-
signal: finalSignal,
|
|
171
|
-
};
|
|
172
|
-
const transport = this.transport || (await this.ensureTransport());
|
|
173
|
-
const rawResponse = await transport.execute(transportArgs);
|
|
174
|
-
return mapStreamFast(rawResponse);
|
|
134
|
+
const internalReq = this.buildInternalRequest("GET", req, undefined, signal);
|
|
135
|
+
internalReq.meta = { ...internalReq.meta, responseType: "stream" };
|
|
136
|
+
return this.dispatchInternal(internalReq);
|
|
175
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* @ru Выполняет POST-запрос и возвращает ответ в виде потока (StreamResponse).
|
|
140
|
+
* @en Performs a POST request and returns the response as a stream (StreamResponse).
|
|
141
|
+
* @param req - Request URL or RequestInterface object.
|
|
142
|
+
* @param body - Request body data.
|
|
143
|
+
* @param signal - Optional abort signal.
|
|
144
|
+
* @returns Promise with the stream response.
|
|
145
|
+
*/
|
|
146
|
+
async postStream(req, body, signal) {
|
|
147
|
+
const internalReq = this.buildInternalRequest("POST", req, body, signal);
|
|
148
|
+
internalReq.meta = { ...internalReq.meta, responseType: "stream" };
|
|
149
|
+
return this.dispatchInternal(internalReq);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* @ru Выполняет GET-запрос.
|
|
153
|
+
* @en Performs a GET request.
|
|
154
|
+
* @param req - Request URL or RequestInterface object.
|
|
155
|
+
* @param signal - Optional abort signal.
|
|
156
|
+
* @returns Promise with the HTTP response.
|
|
157
|
+
*/
|
|
176
158
|
get(req, signal) {
|
|
177
159
|
return this.dispatch(this.buildInternalRequest("GET", req, undefined, signal));
|
|
178
160
|
}
|
|
161
|
+
/**
|
|
162
|
+
* @ru Выполняет POST-запрос.
|
|
163
|
+
* @en Performs a POST request.
|
|
164
|
+
* @param req - Request URL or RequestInterface object.
|
|
165
|
+
* @param body - Request body data.
|
|
166
|
+
* @param signal - Optional abort signal.
|
|
167
|
+
* @returns Promise with the HTTP response.
|
|
168
|
+
*/
|
|
179
169
|
post(req, body, signal) {
|
|
180
170
|
return this.dispatch(this.buildInternalRequest("POST", req, body, signal));
|
|
181
171
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
headers: normalizeHeaders(mergeHeadersFast(this.defaultHeaders, reqHeaders)),
|
|
191
|
-
body: normalizeBody("POST", isStr ? body : (req.body ?? body)),
|
|
192
|
-
signal: finalSignal,
|
|
193
|
-
};
|
|
194
|
-
const transport = this.transport || (await this.ensureTransport());
|
|
195
|
-
const rawResponse = await transport.execute(transportArgs);
|
|
196
|
-
return mapStreamFast(rawResponse);
|
|
197
|
-
}
|
|
172
|
+
/**
|
|
173
|
+
* @ru Выполняет PUT-запрос.
|
|
174
|
+
* @en Performs a PUT request.
|
|
175
|
+
* @param req - Request URL or RequestInterface object.
|
|
176
|
+
* @param body - Request body data.
|
|
177
|
+
* @param signal - Optional abort signal.
|
|
178
|
+
* @returns Promise with the HTTP response.
|
|
179
|
+
*/
|
|
198
180
|
put(req, body, signal) {
|
|
199
181
|
return this.dispatch(this.buildInternalRequest("PUT", req, body, signal));
|
|
200
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* @ru Выполняет PATCH-запрос.
|
|
185
|
+
* @en Performs a PATCH request.
|
|
186
|
+
* @param req - Request URL or RequestInterface object.
|
|
187
|
+
* @param body - Request body data.
|
|
188
|
+
* @param signal - Optional abort signal.
|
|
189
|
+
* @returns Promise with the HTTP response.
|
|
190
|
+
*/
|
|
201
191
|
patch(req, body, signal) {
|
|
202
192
|
return this.dispatch(this.buildInternalRequest("PATCH", req, body, signal));
|
|
203
193
|
}
|
|
194
|
+
/**
|
|
195
|
+
* @ru Выполняет DELETE-запрос.
|
|
196
|
+
* @en Performs a DELETE request.
|
|
197
|
+
* @param req - Request URL or RequestInterface object.
|
|
198
|
+
* @param signal - Optional abort signal.
|
|
199
|
+
* @returns Promise with the HTTP response.
|
|
200
|
+
*/
|
|
204
201
|
delete(req, signal) {
|
|
205
202
|
return this.dispatch(this.buildInternalRequest("DELETE", req, undefined, signal));
|
|
206
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* @ru Выполняет OPTIONS-запрос.
|
|
206
|
+
* @en Performs an OPTIONS request.
|
|
207
|
+
* @param req - Request URL or RequestInterface object.
|
|
208
|
+
* @param body - Optional request body data.
|
|
209
|
+
* @param signal - Optional abort signal.
|
|
210
|
+
* @returns Promise with the HTTP response.
|
|
211
|
+
*/
|
|
207
212
|
options(req, body, signal) {
|
|
208
213
|
return this.dispatch(this.buildInternalRequest("OPTIONS", req, body, signal));
|
|
209
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* @ru Выполняет HEAD-запрос.
|
|
217
|
+
* @en Performs a HEAD request.
|
|
218
|
+
* @param req - Request URL or RequestInterface object.
|
|
219
|
+
* @param signal - Optional abort signal.
|
|
220
|
+
* @returns Promise with the HTTP response (body is always null).
|
|
221
|
+
*/
|
|
210
222
|
head(req, signal) {
|
|
211
223
|
return this.dispatch(this.buildInternalRequest("HEAD", req, undefined, signal));
|
|
212
224
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
225
|
+
/**
|
|
226
|
+
* @ru Создаёт новый экземпляр HyperCore с расширенной конфигурацией (поверх текущей).
|
|
227
|
+
* @en Creates a new HyperCore instance with extended configuration (on top of current).
|
|
228
|
+
* @param options - Additional configuration options.
|
|
229
|
+
* @returns New HyperCore instance.
|
|
230
|
+
*/
|
|
231
|
+
extend(options) {
|
|
232
|
+
return new HyperCore({
|
|
233
|
+
...this.config,
|
|
234
|
+
...options,
|
|
235
|
+
network: { ...this.config.network, ...options.network },
|
|
236
|
+
}, this.transport ?? undefined);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* @ru Алиас для extend(). Создаёт новый экземпляр HyperCore.
|
|
240
|
+
* @en Alias for extend(). Creates a new HyperCore instance.
|
|
241
|
+
* @param options - Configuration options.
|
|
242
|
+
* @returns New HyperCore instance.
|
|
243
|
+
*/
|
|
244
|
+
create(options) {
|
|
245
|
+
return this.extend(options);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* @ru Уничтожает клиент, закрывая соединения и очищая ресурсы.
|
|
249
|
+
* @en Destroys the client, closing connections and cleaning up resources.
|
|
250
|
+
* @param graceful - If true, attempts graceful shutdown (default: true).
|
|
251
|
+
* @returns Promise that resolves when destruction is complete.
|
|
252
|
+
*/
|
|
253
|
+
async destroy(graceful = true) {
|
|
254
|
+
await this.transportManager.destroy(graceful);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* @ru Выполняет запрос и сразу возвращает распарсенный JSON (сокращённый метод).
|
|
258
|
+
* @en Performs a request and immediately returns parsed JSON (shortcut method).
|
|
259
|
+
* @param req - Request URL or RequestInterface object.
|
|
260
|
+
* @param signal - Optional abort signal.
|
|
261
|
+
* @returns Promise with the parsed JSON value.
|
|
262
|
+
* @throws If the response does not contain a json() method.
|
|
263
|
+
*/
|
|
264
|
+
async json(req, signal) {
|
|
265
|
+
const res = await this.dispatchShortcut(req, signal);
|
|
266
|
+
if (!res.json)
|
|
267
|
+
throw new Error("[HyperCore] Method 'json()' is missing on response object.");
|
|
268
|
+
return res.json();
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* @ru Выполняет запрос и возвращает тело как строку (сокращённый метод).
|
|
272
|
+
* @en Performs a request and returns the body as a string (shortcut method).
|
|
273
|
+
* @param req - Request URL or RequestInterface object.
|
|
274
|
+
* @param signal - Optional abort signal.
|
|
275
|
+
* @returns Promise with the response text.
|
|
276
|
+
* @throws If the response does not contain a text() method.
|
|
277
|
+
*/
|
|
278
|
+
async text(req, signal) {
|
|
279
|
+
const res = await this.dispatchShortcut(req, signal);
|
|
280
|
+
if (!res.text)
|
|
281
|
+
throw new Error("[HyperCore] Method 'text()' is missing on response object.");
|
|
282
|
+
return res.text();
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* @ru Выполняет запрос и немедленно отменяет (сбрасывает) тело ответа без чтения.
|
|
286
|
+
* @en Performs a request and immediately discards the response body without reading.
|
|
287
|
+
* @param req - Request URL or RequestInterface object.
|
|
288
|
+
* @param signal - Optional abort signal.
|
|
289
|
+
* @returns Promise that resolves after dumping the response.
|
|
290
|
+
* @throws If the response does not contain a dump() method.
|
|
291
|
+
*/
|
|
292
|
+
async dump(req, signal) {
|
|
293
|
+
const res = await this.dispatchShortcut(req, signal);
|
|
294
|
+
if (!res.dump)
|
|
295
|
+
throw new Error("[HyperCore] Method 'dump()' is missing on response object.");
|
|
296
|
+
await res.dump();
|
|
297
|
+
}
|
|
298
|
+
async runResponsePipeline(response, req) {
|
|
299
|
+
const hasMutators = this.pipelines.responseMutators.length > 0;
|
|
300
|
+
const hasSideEffects = this.pipelines.responseSideEffects.length > 0;
|
|
301
|
+
if (hasMutators || hasSideEffects) {
|
|
302
|
+
await executeResponsePipeline(this.pipelines.responseMutators, this.pipelines.responseSideEffects, response, req, this.pluginCtx, this.config.logger);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
async handleDispatchError(error, req) {
|
|
306
|
+
if (this.pipelines.error.length > 0) {
|
|
307
|
+
const recovered = await executeErrorPipeline(this.pipelines.error, error, req, this.pluginCtx);
|
|
308
|
+
if (recovered) {
|
|
309
|
+
await this.runResponsePipeline(recovered, req);
|
|
310
|
+
return recovered;
|
|
242
311
|
}
|
|
243
312
|
}
|
|
244
|
-
|
|
245
|
-
|
|
313
|
+
throw error;
|
|
314
|
+
}
|
|
315
|
+
applyDecompression(rawResponse) {
|
|
316
|
+
if (!rawResponse.body)
|
|
317
|
+
return;
|
|
318
|
+
const encodingHeader = rawResponse.headers?.["content-encoding"] ??
|
|
319
|
+
rawResponse.headers?.["Content-Encoding"];
|
|
320
|
+
if (!encodingHeader)
|
|
321
|
+
return;
|
|
322
|
+
const contentEncoding = typeof encodingHeader === "string"
|
|
323
|
+
? encodingHeader
|
|
324
|
+
: Array.isArray(encodingHeader)
|
|
325
|
+
? encodingHeader[0]
|
|
326
|
+
: undefined;
|
|
327
|
+
if (!contentEncoding)
|
|
328
|
+
return;
|
|
329
|
+
if (rawResponse.body instanceof Uint8Array) {
|
|
330
|
+
rawResponse.body = decompressBuffer(rawResponse.body, contentEncoding);
|
|
246
331
|
}
|
|
332
|
+
else {
|
|
333
|
+
rawResponse.body = createDecompressStream(rawResponse.body, contentEncoding);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
buildInternalRequest(method, req, body, signal) {
|
|
337
|
+
const isStr = typeof req === "string";
|
|
338
|
+
const rawUrl = normalizeUrl(req);
|
|
247
339
|
if (!rawUrl) {
|
|
248
|
-
throw new Error(`[
|
|
249
|
-
|
|
340
|
+
throw new Error(`[HyperCore] Critical failure: 'url' resolved to undefined for ${method}.`);
|
|
341
|
+
}
|
|
342
|
+
const urlObj = new URL(rawUrl);
|
|
343
|
+
const castedReq = isStr
|
|
344
|
+
? undefined
|
|
345
|
+
: req;
|
|
346
|
+
if (castedReq?.query) {
|
|
347
|
+
this.appendQueryParams(urlObj, castedReq.query);
|
|
250
348
|
}
|
|
349
|
+
const context = {
|
|
350
|
+
method,
|
|
351
|
+
url: urlObj.href,
|
|
352
|
+
origin: urlObj.origin,
|
|
353
|
+
path: urlObj.pathname + urlObj.search,
|
|
354
|
+
};
|
|
251
355
|
if (isStr) {
|
|
252
356
|
return {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
headers: normalizeHeaders(this.defaultHeaders),
|
|
357
|
+
...context,
|
|
358
|
+
headers: { ...this.defaultHeaders },
|
|
256
359
|
body,
|
|
257
360
|
signal,
|
|
258
|
-
meta:
|
|
361
|
+
meta: {},
|
|
259
362
|
};
|
|
260
363
|
}
|
|
261
|
-
const
|
|
262
|
-
const rawHeaders = req.headers ?? castedReq._headers;
|
|
364
|
+
const rawHeaders = (req.headers ?? castedReq._headers);
|
|
263
365
|
const headers = rawHeaders
|
|
264
|
-
? mergeHeadersFast(this.defaultHeaders, rawHeaders)
|
|
366
|
+
? normalizeHeaders(mergeHeadersFast(this.defaultHeaders, rawHeaders))
|
|
265
367
|
: { ...this.defaultHeaders };
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
`bodyLength: ${typeof internalRequest.body === "string" ? internalRequest.body.length : 0} ` +
|
|
280
|
-
`}`);
|
|
281
|
-
return internalRequest;
|
|
282
|
-
}
|
|
283
|
-
extend(options) {
|
|
284
|
-
this.config = {
|
|
285
|
-
...this.config,
|
|
286
|
-
...options,
|
|
287
|
-
network: { ...this.config.network, ...options.network },
|
|
288
|
-
};
|
|
289
|
-
this.pluginCtx.config = this.config;
|
|
290
|
-
return this;
|
|
291
|
-
}
|
|
292
|
-
create(options) {
|
|
293
|
-
return new HyperCore({
|
|
294
|
-
...this.config,
|
|
295
|
-
...options,
|
|
296
|
-
network: { ...this.config.network, ...options.network },
|
|
297
|
-
}, this.transport ?? undefined);
|
|
368
|
+
const rawBody = castedReq.body ?? castedReq.bodyData ?? castedReq._bodyData ?? body;
|
|
369
|
+
const computedBody = normalizeBody(method, rawBody);
|
|
370
|
+
const computedSignal = req.signal ?? castedReq._signal ?? signal;
|
|
371
|
+
const meta = (req.meta ??
|
|
372
|
+
castedReq._meta ??
|
|
373
|
+
{});
|
|
374
|
+
return this.createInternalRequestObject(castedReq, {
|
|
375
|
+
...context,
|
|
376
|
+
headers,
|
|
377
|
+
body: computedBody,
|
|
378
|
+
signal: computedSignal,
|
|
379
|
+
meta,
|
|
380
|
+
});
|
|
298
381
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
382
|
+
createInternalRequestObject(sourceReq, overrides) {
|
|
383
|
+
const proto = Object.getPrototypeOf(sourceReq);
|
|
384
|
+
const target = proto && proto !== Object.prototype ? Object.create(proto) : {};
|
|
385
|
+
for (const key in sourceReq) {
|
|
386
|
+
if (Object.prototype.hasOwnProperty.call(sourceReq, key)) {
|
|
387
|
+
target[key] = sourceReq[key];
|
|
388
|
+
}
|
|
306
389
|
}
|
|
307
|
-
|
|
308
|
-
|
|
390
|
+
for (const key in overrides) {
|
|
391
|
+
if (Object.prototype.hasOwnProperty.call(overrides, key)) {
|
|
392
|
+
target[key] = overrides[key];
|
|
393
|
+
}
|
|
309
394
|
}
|
|
395
|
+
return target;
|
|
310
396
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
397
|
+
appendQueryParams(url, query) {
|
|
398
|
+
if (!query)
|
|
399
|
+
return;
|
|
400
|
+
for (const key in query) {
|
|
401
|
+
if (Object.prototype.hasOwnProperty.call(query, key)) {
|
|
402
|
+
const value = query[key];
|
|
403
|
+
if (value === undefined || value === null)
|
|
404
|
+
continue;
|
|
405
|
+
if (Array.isArray(value)) {
|
|
406
|
+
const len = value.length;
|
|
407
|
+
for (let i = 0; i < len; i++) {
|
|
408
|
+
const item = value[i];
|
|
409
|
+
if (item === undefined || item === null)
|
|
410
|
+
continue;
|
|
411
|
+
url.searchParams.append(key, String(item));
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
url.searchParams.set(key, String(value));
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
324
419
|
}
|
|
325
|
-
async
|
|
420
|
+
async dispatchShortcut(req, signal) {
|
|
326
421
|
const method = typeof req === "string"
|
|
327
422
|
? "GET"
|
|
328
423
|
: (req.method ?? "GET");
|
|
329
|
-
|
|
330
|
-
await res.dump();
|
|
424
|
+
return this.dispatch(this.buildInternalRequest(method, req, undefined, signal));
|
|
331
425
|
}
|
|
332
426
|
}
|
|
333
427
|
//# sourceMappingURL=HyperCore.js.map
|