@hyperttp/core 1.2.6 → 1.3.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.
@@ -1,48 +1,61 @@
1
1
  import type { IHyperCore, HyperTransport, HttpClientOptions, HyperPlugin, InternalRequest, HttpResponse, RequestInterface, StreamResponse, RequestBodyData } from "@hyperttp/types";
2
- declare module "@hyperttp/types" {
3
- interface HyperttpPluginsExtension {
4
- baseURL?: string;
5
- }
6
- }
7
- export type Runtime = "bun" | "node";
8
- export declare function getRuntime(): Runtime;
9
- type TransportDef = {
10
- name: string;
11
- runtime: Runtime[];
12
- pkg: string;
13
- export: string;
14
- priority: number;
15
- };
16
- export declare const TRANSPORTS: TransportDef[];
17
- export declare function resolveTransport(config: HttpClientOptions): Promise<HyperTransport>;
18
2
  export declare class HyperCore implements IHyperCore {
19
3
  config: HttpClientOptions;
20
- private transport;
21
- private transportPromise;
4
+ private readonly transportManager;
22
5
  private readonly defaultHeaders;
23
6
  private readonly pluginCtx;
24
7
  private readonly pipelines;
25
8
  constructor(config?: HttpClientOptions, transport?: HyperTransport);
26
- private createTransport;
9
+ private get transport();
27
10
  private ensureTransport;
11
+ /**
12
+ * Центральный метод обработки запросов
13
+ */
14
+ private dispatchInternal;
28
15
  dispatch<T = unknown>(req: InternalRequest): Promise<HttpResponse<T>>;
16
+ /**
17
+ * Регистрация плагинов
18
+ */
29
19
  use(plugin: HyperPlugin): this;
20
+ /**
21
+ * Публичные HTTP методы-помощники
22
+ */
30
23
  stream(req: RequestInterface | string, signal?: AbortSignal): Promise<StreamResponse<unknown>>;
24
+ postStream<T = unknown>(req: RequestInterface | string, body?: RequestBodyData, signal?: AbortSignal): Promise<StreamResponse<T>>;
31
25
  get<T = unknown>(req: RequestInterface | string, signal?: AbortSignal): Promise<HttpResponse<T>>;
32
26
  post<T = unknown>(req: RequestInterface | string, body?: RequestBodyData, signal?: AbortSignal): Promise<HttpResponse<T>>;
33
- postStream<T = unknown>(req: RequestInterface | string, body?: RequestBodyData, signal?: AbortSignal): Promise<StreamResponse<T>>;
34
27
  put<T = unknown>(req: RequestInterface | string, body?: RequestBodyData, signal?: AbortSignal): Promise<HttpResponse<T>>;
35
28
  patch<T = unknown>(req: RequestInterface | string, body?: RequestBodyData, signal?: AbortSignal): Promise<HttpResponse<T>>;
36
29
  delete<T = unknown>(req: RequestInterface | string, signal?: AbortSignal): Promise<HttpResponse<T>>;
37
30
  options<T = unknown>(req: RequestInterface | string, body?: RequestBodyData, signal?: AbortSignal): Promise<HttpResponse<T>>;
38
31
  head(req: RequestInterface | string, signal?: AbortSignal): Promise<HttpResponse<null>>;
39
- private buildInternalRequest;
40
- extend(options: Partial<HttpClientOptions>): this;
32
+ extend(options: Partial<HttpClientOptions>): HyperCore;
41
33
  create(options: Partial<HttpClientOptions>): HyperCore;
42
34
  destroy(graceful?: boolean): Promise<void>;
43
35
  json<T = unknown>(req: RequestInterface | string, signal?: AbortSignal): Promise<T>;
44
36
  text(req: RequestInterface | string, signal?: AbortSignal): Promise<string>;
45
37
  dump(req: RequestInterface | string, signal?: AbortSignal): Promise<void>;
38
+ /**
39
+ * ПРИВАТНЫЕ МЕТОДЫ-ПОМОЩНИКИ (РЕФАКТОРИНГ)
40
+ */
41
+ private runResponsePipeline;
42
+ /**
43
+ * Изолированная обработка ошибок пайплайна ответа
44
+ */
45
+ private handleDispatchError;
46
+ /**
47
+ * Применение встроенной декомпрессии на основе заголовков ответа транспорта
48
+ */
49
+ private applyDecompression;
50
+ /**
51
+ * Сборка внутреннего объекта запроса InternalRequest
52
+ */
53
+ private buildInternalRequest;
54
+ /**
55
+ * Фабрика сохранения прототипа исходного запроса с подменой дескрипторов базовых свойств
56
+ */
57
+ private createInternalRequestObject;
58
+ private appendQueryParams;
59
+ private dispatchShortcut;
46
60
  }
47
- export {};
48
61
  //# sourceMappingURL=HyperCore.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"HyperCore.d.ts","sourceRoot":"","sources":["../../src/Core/HyperCore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"HyperCore.d.ts","sourceRoot":"","sources":["../../src/Core/HyperCore.ts"],"names":[],"mappings":"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"}
package/Core/HyperCore.js CHANGED
@@ -1,67 +1,12 @@
1
1
  import { defaultConfig } from "../defaultConfig.js";
2
2
  import { mapResponseFast, mapStreamFast, mergeHeadersFast, } from "../utils/response.js";
3
- import { createRequire } from "node:module";
4
- import { createPipelines, executeErrorPipeline, executeRequestPipeline, executeResponsePipeline, insertHookSorted, } from "../utils/pipeline.js";
5
- import { normalizeBody, normalizeHeaders, normalizeMethod, } from "../utils/normalize.js";
6
- export function getRuntime() {
7
- if (typeof Bun !== "undefined")
8
- return "bun";
9
- return "node";
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";
61
7
  export class HyperCore {
62
8
  config;
63
- transport = null;
64
- transportPromise = null;
9
+ transportManager;
65
10
  defaultHeaders;
66
11
  pluginCtx;
67
12
  pipelines = createPipelines();
@@ -71,54 +16,57 @@ export class HyperCore {
71
16
  ...config,
72
17
  network: { ...defaultConfig.network, ...config.network },
73
18
  };
74
- if (transport) {
75
- this.transport = transport;
76
- this.transportPromise = Promise.resolve(transport);
77
- if ("config" in transport) {
78
- transport.config = this.config;
79
- }
80
- }
81
- this.defaultHeaders = {
19
+ this.transportManager = new TransportManager(this.config, transport);
20
+ this.defaultHeaders = normalizeHeaders({
82
21
  Accept: "application/json, text/plain, */*",
83
22
  "Accept-Encoding": "gzip, deflate, br",
84
23
  "User-Agent": this.config.network?.userAgent ?? "Hyperttp/2.0",
85
24
  ...this.config.network?.headers,
86
- };
25
+ });
87
26
  this.pluginCtx = { config: this.config, core: this };
88
27
  }
89
- async createTransport() {
90
- return resolveTransport(this.config);
28
+ get transport() {
29
+ return this.transportManager.instance;
91
30
  }
92
31
  ensureTransport() {
93
- return (this.transportPromise ||
94
- (this.transportPromise = this.createTransport().then((t) => {
95
- this.transport = t;
96
- return t;
97
- })));
32
+ return this.transportManager.get();
98
33
  }
99
- async dispatch(req) {
34
+ /**
35
+ * Центральный метод обработки запросов
36
+ */
37
+ async dispatchInternal(req) {
100
38
  try {
101
- const shortCircuit = await executeRequestPipeline(this.pipelines.request, req, this.pluginCtx);
102
- if (shortCircuit) {
103
- await executeResponsePipeline(this.pipelines.responseMutators, this.pipelines.responseSideEffects, shortCircuit, req, this.pluginCtx, this.config.logger);
104
- return shortCircuit;
39
+ if (this.pipelines.request.length > 0) {
40
+ const shortCircuit = await executeRequestPipeline(this.pipelines.request, req, this.pluginCtx);
41
+ if (shortCircuit) {
42
+ await this.runResponsePipeline(shortCircuit, req);
43
+ return shortCircuit;
44
+ }
105
45
  }
46
+ req.headers = normalizeHeaders(req.headers);
106
47
  const transport = this.transport || (await this.ensureTransport());
107
- const rawResponse = await transport.execute(req);
108
- const response = mapResponseFast(rawResponse);
109
- await executeResponsePipeline(this.pipelines.responseMutators, this.pipelines.responseSideEffects, response, req, this.pluginCtx, this.config.logger);
48
+ let rawResponse = await transport.execute(req);
49
+ if (this.pipelines.responseData.length > 0) {
50
+ rawResponse = await executeResponseDataPipeline(this.pipelines.responseData, rawResponse, this.pluginCtx);
51
+ }
52
+ this.applyDecompression(rawResponse);
53
+ const isStream = req.meta?.responseType === "stream";
54
+ const response = isStream
55
+ ? mapStreamFast(rawResponse)
56
+ : mapResponseFast(rawResponse);
57
+ await this.runResponsePipeline(response, req);
110
58
  return response;
111
59
  }
112
60
  catch (error) {
113
- const httpError = error;
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;
61
+ return this.handleDispatchError(error, req);
120
62
  }
121
63
  }
64
+ async dispatch(req) {
65
+ return this.dispatchInternal(req);
66
+ }
67
+ /**
68
+ * Регистрация плагинов
69
+ */
122
70
  use(plugin) {
123
71
  const isEnabled = plugin.enabled ? plugin.enabled(this.config) : true;
124
72
  if (!isEnabled)
@@ -134,20 +82,21 @@ export class HyperCore {
134
82
  });
135
83
  }
136
84
  if (plugin.onResponse) {
137
- if (plugin.mode === "background") {
138
- insertHookSorted(this.pipelines.responseSideEffects, {
139
- name: plugin.name,
140
- priority,
141
- run: plugin.onResponse,
142
- });
143
- }
144
- else {
145
- insertHookSorted(this.pipelines.responseMutators, {
146
- name: plugin.name,
147
- priority,
148
- run: plugin.onResponse,
149
- });
150
- }
85
+ const targetPipeline = plugin.mode === "background"
86
+ ? this.pipelines.responseSideEffects
87
+ : this.pipelines.responseMutators;
88
+ insertHookSorted(targetPipeline, {
89
+ name: plugin.name,
90
+ priority,
91
+ run: plugin.onResponse,
92
+ });
93
+ }
94
+ if (plugin.onResponseData) {
95
+ insertHookSorted(this.pipelines.responseData, {
96
+ name: plugin.name,
97
+ priority,
98
+ run: plugin.onResponseData,
99
+ });
151
100
  }
152
101
  if (plugin.onError) {
153
102
  insertHookSorted(this.pipelines.error, {
@@ -158,20 +107,18 @@ export class HyperCore {
158
107
  }
159
108
  return this;
160
109
  }
110
+ /**
111
+ * Публичные HTTP методы-помощники
112
+ */
161
113
  async stream(req, signal) {
162
- const isStr = typeof req === "string";
163
- const url = isStr ? req : req.url;
164
- const reqHeaders = isStr ? undefined : req.headers;
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);
114
+ const internalReq = this.buildInternalRequest("GET", req, undefined, signal);
115
+ internalReq.meta = { ...internalReq.meta, responseType: "stream" };
116
+ return this.dispatchInternal(internalReq);
117
+ }
118
+ async postStream(req, body, signal) {
119
+ const internalReq = this.buildInternalRequest("POST", req, body, signal);
120
+ internalReq.meta = { ...internalReq.meta, responseType: "stream" };
121
+ return this.dispatchInternal(internalReq);
175
122
  }
176
123
  get(req, signal) {
177
124
  return this.dispatch(this.buildInternalRequest("GET", req, undefined, signal));
@@ -179,22 +126,6 @@ export class HyperCore {
179
126
  post(req, body, signal) {
180
127
  return this.dispatch(this.buildInternalRequest("POST", req, body, signal));
181
128
  }
182
- async postStream(req, body, signal) {
183
- const isStr = typeof req === "string";
184
- const url = isStr ? req : req.url;
185
- const reqHeaders = isStr ? undefined : req.headers;
186
- const finalSignal = isStr ? signal : (req.signal ?? signal);
187
- const transportArgs = {
188
- method: normalizeMethod("POST"),
189
- url,
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
- }
198
129
  put(req, body, signal) {
199
130
  return this.dispatch(this.buildInternalRequest("PUT", req, body, signal));
200
131
  }
@@ -210,124 +141,175 @@ export class HyperCore {
210
141
  head(req, signal) {
211
142
  return this.dispatch(this.buildInternalRequest("HEAD", req, undefined, signal));
212
143
  }
213
- buildInternalRequest(method, req, body, signal) {
214
- const isStr = typeof req === "string";
215
- let rawUrl = isStr ? req : req?.url;
216
- if (!rawUrl && !isStr && req && "scheme" in req && "host" in req) {
217
- const casted = req;
218
- try {
219
- const cleanHost = String(casted.host).replace(/^https?:\/\//i, "");
220
- const urlObj = new URL(`${casted.scheme}://${cleanHost}`);
221
- if (casted.port)
222
- urlObj.port = String(casted.port);
223
- if (casted.path)
224
- urlObj.pathname = casted.path;
225
- if (casted.query) {
226
- for (const [key, value] of Object.entries(casted.query)) {
227
- if (value == null)
228
- continue;
229
- if (Array.isArray(value)) {
230
- value.forEach((v) => urlObj.searchParams.append(key, String(v)));
231
- }
232
- else {
233
- urlObj.searchParams.set(key, String(value));
234
- }
235
- }
236
- }
237
- rawUrl = urlObj.toString();
238
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
239
- }
240
- catch (_e) {
241
- //
144
+ extend(options) {
145
+ return new HyperCore({
146
+ ...this.config,
147
+ ...options,
148
+ network: { ...this.config.network, ...options.network },
149
+ }, this.transport ?? undefined);
150
+ }
151
+ create(options) {
152
+ return this.extend(options);
153
+ }
154
+ async destroy(graceful = true) {
155
+ await this.transportManager.destroy(graceful);
156
+ }
157
+ async json(req, signal) {
158
+ const res = await this.dispatchShortcut(req, signal);
159
+ if (!res.json)
160
+ throw new Error("[HyperCore] Method 'json()' is missing on response object.");
161
+ return res.json();
162
+ }
163
+ async text(req, signal) {
164
+ const res = await this.dispatchShortcut(req, signal);
165
+ if (!res.text)
166
+ throw new Error("[HyperCore] Method 'text()' is missing on response object.");
167
+ return res.text();
168
+ }
169
+ async dump(req, signal) {
170
+ const res = await this.dispatchShortcut(req, signal);
171
+ if (!res.dump)
172
+ throw new Error("[HyperCore] Method 'dump()' is missing on response object.");
173
+ await res.dump();
174
+ }
175
+ /**
176
+ * ПРИВАТНЫЕ МЕТОДЫ-ПОМОЩНИКИ (РЕФАКТОРИНГ)
177
+ */
178
+ async runResponsePipeline(response, req) {
179
+ const hasMutators = this.pipelines.responseMutators.length > 0;
180
+ const hasSideEffects = this.pipelines.responseSideEffects.length > 0;
181
+ if (hasMutators || hasSideEffects) {
182
+ await executeResponsePipeline(this.pipelines.responseMutators, this.pipelines.responseSideEffects, response, req, this.pluginCtx, this.config.logger);
183
+ }
184
+ }
185
+ /**
186
+ * Изолированная обработка ошибок пайплайна ответа
187
+ */
188
+ async handleDispatchError(error, req) {
189
+ if (this.pipelines.error.length > 0) {
190
+ const recovered = await executeErrorPipeline(this.pipelines.error, error, req, this.pluginCtx);
191
+ if (recovered) {
192
+ await this.runResponsePipeline(recovered, req);
193
+ return recovered;
242
194
  }
243
195
  }
244
- if (this.config.baseURL && rawUrl && !/^https?:\/\//i.test(rawUrl)) {
245
- rawUrl = new URL(rawUrl, this.config.baseURL).toString();
196
+ throw error;
197
+ }
198
+ /**
199
+ * Применение встроенной декомпрессии на основе заголовков ответа транспорта
200
+ */
201
+ applyDecompression(rawResponse) {
202
+ if (!rawResponse.body)
203
+ return;
204
+ const encodingHeader = rawResponse.headers?.["content-encoding"] ??
205
+ rawResponse.headers?.["Content-Encoding"];
206
+ if (!encodingHeader)
207
+ return;
208
+ const contentEncoding = typeof encodingHeader === "string"
209
+ ? encodingHeader
210
+ : Array.isArray(encodingHeader)
211
+ ? encodingHeader[0]
212
+ : undefined;
213
+ if (!contentEncoding)
214
+ return;
215
+ if (rawResponse.body instanceof Uint8Array) {
216
+ rawResponse.body = decompressBuffer(rawResponse.body, contentEncoding);
217
+ }
218
+ else {
219
+ rawResponse.body = createDecompressStream(rawResponse.body, contentEncoding);
246
220
  }
221
+ }
222
+ /**
223
+ * Сборка внутреннего объекта запроса InternalRequest
224
+ */
225
+ buildInternalRequest(method, req, body, signal) {
226
+ const isStr = typeof req === "string";
227
+ const rawUrl = normalizeUrl(req);
247
228
  if (!rawUrl) {
248
- throw new Error(`[HyperttpCore] Critical execution failure during ${method} method invocation: 'url' resolved to undefined. ` +
249
- `Verify incoming arguments or environment configurations.`);
229
+ throw new Error(`[HyperCore] Critical failure: 'url' resolved to undefined for ${method}.`);
250
230
  }
231
+ const urlObj = new URL(rawUrl);
232
+ const castedReq = isStr
233
+ ? undefined
234
+ : req;
235
+ if (castedReq?.query) {
236
+ this.appendQueryParams(urlObj, castedReq.query);
237
+ }
238
+ const context = {
239
+ method,
240
+ url: urlObj.href,
241
+ origin: urlObj.origin,
242
+ path: urlObj.pathname + urlObj.search,
243
+ };
251
244
  if (isStr) {
252
245
  return {
253
- method: normalizeMethod(method),
254
- url: rawUrl,
255
- headers: normalizeHeaders(this.defaultHeaders),
246
+ ...context,
247
+ headers: { ...this.defaultHeaders },
256
248
  body,
257
249
  signal,
258
- meta: undefined,
250
+ meta: {},
259
251
  };
260
252
  }
261
- const castedReq = req;
262
- const rawHeaders = req.headers ?? castedReq._headers;
253
+ const rawHeaders = (req.headers ?? castedReq._headers);
263
254
  const headers = rawHeaders
264
- ? mergeHeadersFast(this.defaultHeaders, rawHeaders)
255
+ ? normalizeHeaders(mergeHeadersFast(this.defaultHeaders, rawHeaders))
265
256
  : { ...this.defaultHeaders };
266
- const internalRequest = {
267
- method: normalizeMethod(method),
268
- url: rawUrl,
269
- headers: normalizeHeaders(headers),
270
- body: normalizeBody(method, castedReq.body ?? castedReq._bodyData ?? body),
271
- signal: req.signal ?? castedReq._signal ?? signal,
272
- meta: (req.meta ?? castedReq._meta),
273
- };
274
- this.config.logger?.("debug", `[HyperttpCore] Internal request dispatched: { ` +
275
- `method: "${internalRequest.method}", ` +
276
- `url: "${internalRequest.url}", ` +
277
- `headersCount: ${Object.keys(internalRequest.headers).length}, ` +
278
- `bodyType: "${typeof internalRequest.body}", ` +
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;
257
+ const rawBody = castedReq.body ?? castedReq.bodyData ?? castedReq._bodyData ?? body;
258
+ const computedBody = normalizeBody(method, rawBody);
259
+ const computedSignal = req.signal ?? castedReq._signal ?? signal;
260
+ const meta = (req.meta ??
261
+ castedReq._meta ??
262
+ {});
263
+ return this.createInternalRequestObject(castedReq, {
264
+ ...context,
265
+ headers,
266
+ body: computedBody,
267
+ signal: computedSignal,
268
+ meta,
269
+ });
291
270
  }
292
- create(options) {
293
- return new HyperCore({
294
- ...this.config,
295
- ...options,
296
- network: { ...this.config.network, ...options.network },
297
- }, this.transport ?? undefined);
271
+ /**
272
+ * Фабрика сохранения прототипа исходного запроса с подменой дескрипторов базовых свойств
273
+ */
274
+ createInternalRequestObject(sourceReq, overrides) {
275
+ const proto = Object.getPrototypeOf(sourceReq);
276
+ const target = proto && proto !== Object.prototype ? Object.create(proto) : {};
277
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(sourceReq));
278
+ const propertyDescriptors = {};
279
+ for (const [key, value] of Object.entries(overrides)) {
280
+ propertyDescriptors[key] = {
281
+ value,
282
+ enumerable: true,
283
+ writable: true,
284
+ configurable: true,
285
+ };
286
+ }
287
+ Object.defineProperties(target, propertyDescriptors);
288
+ return target;
298
289
  }
299
- async destroy(graceful = true) {
300
- this.config.logger?.("debug", "Destroying transport...");
301
- const transport = this.transport;
302
- if (!transport)
290
+ appendQueryParams(url, query) {
291
+ if (!query)
303
292
  return;
304
- if (graceful && typeof transport.close === "function") {
305
- await transport.close();
306
- }
307
- else if (typeof transport.destroy === "function") {
308
- await transport.destroy();
293
+ for (const [key, value] of Object.entries(query)) {
294
+ if (value === undefined || value === null)
295
+ continue;
296
+ if (Array.isArray(value)) {
297
+ for (const item of value) {
298
+ if (item === undefined || item === null)
299
+ continue;
300
+ url.searchParams.append(key, String(item));
301
+ }
302
+ }
303
+ else {
304
+ url.searchParams.set(key, String(value));
305
+ }
309
306
  }
310
307
  }
311
- async json(req, signal) {
312
- const method = typeof req === "string"
313
- ? "GET"
314
- : (req.method ?? "GET");
315
- const res = await this.dispatch(this.buildInternalRequest(method, req, undefined, signal));
316
- return res.json();
317
- }
318
- async text(req, signal) {
308
+ async dispatchShortcut(req, signal) {
319
309
  const method = typeof req === "string"
320
310
  ? "GET"
321
311
  : (req.method ?? "GET");
322
- const res = await this.dispatch(this.buildInternalRequest(method, req, undefined, signal));
323
- return res.text();
324
- }
325
- async dump(req, signal) {
326
- const method = typeof req === "string"
327
- ? "GET"
328
- : (req.method ?? "GET");
329
- const res = await this.dispatch(this.buildInternalRequest(method, req, undefined, signal));
330
- await res.dump();
312
+ return this.dispatch(this.buildInternalRequest(method, req, undefined, signal));
331
313
  }
332
314
  }
333
315
  //# sourceMappingURL=HyperCore.js.map