@hyperttp/core 1.3.3 → 1.4.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 +142 -152
- package/Core/HyperCore.d.ts.map +1 -1
- package/Core/HyperCore.js +289 -286
- package/Core/HyperCore.js.map +1 -1
- package/README.md +279 -134
- package/package.json +14 -8
- package/transports/browser.d.ts +228 -0
- package/transports/browser.d.ts.map +1 -0
- package/transports/browser.js +451 -0
- package/transports/browser.js.map +1 -0
- package/transports/manager.d.ts +7 -67
- package/transports/manager.d.ts.map +1 -1
- package/transports/manager.js +138 -145
- package/transports/manager.js.map +1 -1
- package/transports/node.d.ts +0 -20
- package/transports/node.d.ts.map +1 -1
- package/transports/node.js +104 -48
- package/transports/node.js.map +1 -1
- package/utils/decompress.d.ts +16 -18
- package/utils/decompress.d.ts.map +1 -1
- package/utils/decompress.js +143 -63
- package/utils/decompress.js.map +1 -1
- package/utils/errors.d.ts +0 -10
- package/utils/errors.d.ts.map +1 -1
- package/utils/errors.js +1 -11
- package/utils/errors.js.map +1 -1
- package/utils/merge.d.ts +0 -3
- package/utils/merge.d.ts.map +1 -1
- package/utils/merge.js +0 -4
- package/utils/merge.js.map +1 -1
- package/utils/normalize.d.ts +40 -20
- package/utils/normalize.d.ts.map +1 -1
- package/utils/normalize.js +197 -63
- package/utils/normalize.js.map +1 -1
- package/utils/pipeline.d.ts +10 -30
- package/utils/pipeline.d.ts.map +1 -1
- package/utils/pipeline.js +44 -44
- package/utils/pipeline.js.map +1 -1
- package/utils/response.d.ts +35 -44
- package/utils/response.d.ts.map +1 -1
- package/utils/response.js +228 -69
- package/utils/response.js.map +1 -1
- package/utils/retryUtils.d.ts +2 -10
- package/utils/retryUtils.d.ts.map +1 -1
- package/utils/retryUtils.js +17 -21
- package/utils/retryUtils.js.map +1 -1
package/transports/manager.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
export const CURRENT_RUNTIME = (() => {
|
|
2
|
+
if (typeof Bun !== "undefined")
|
|
3
|
+
return "bun";
|
|
4
|
+
if (typeof Deno !== "undefined")
|
|
5
|
+
return "deno";
|
|
6
|
+
if (typeof process !== "undefined" && process.versions?.node)
|
|
7
|
+
return "node";
|
|
8
|
+
return "browser";
|
|
9
|
+
})();
|
|
8
10
|
export const TRANSPORTS = [
|
|
9
11
|
{
|
|
10
12
|
name: "Bun",
|
|
@@ -13,6 +15,13 @@ export const TRANSPORTS = [
|
|
|
13
15
|
export: "BunTransport",
|
|
14
16
|
priority: 100,
|
|
15
17
|
},
|
|
18
|
+
{
|
|
19
|
+
name: "Deno",
|
|
20
|
+
runtime: ["deno"],
|
|
21
|
+
pkg: "@hyperttp/transport-deno",
|
|
22
|
+
export: "DenoTransport",
|
|
23
|
+
priority: 95,
|
|
24
|
+
},
|
|
16
25
|
{
|
|
17
26
|
name: "Undici",
|
|
18
27
|
runtime: ["node"],
|
|
@@ -20,95 +29,125 @@ export const TRANSPORTS = [
|
|
|
20
29
|
export: "UndiciTransport",
|
|
21
30
|
priority: 90,
|
|
22
31
|
},
|
|
32
|
+
{
|
|
33
|
+
name: "Browser",
|
|
34
|
+
runtime: ["browser"],
|
|
35
|
+
pkg: "../transports/browser.js",
|
|
36
|
+
export: "BrowserTransport",
|
|
37
|
+
priority: 80,
|
|
38
|
+
},
|
|
23
39
|
{
|
|
24
40
|
name: "Node",
|
|
25
|
-
runtime: ["node", "bun"],
|
|
41
|
+
runtime: ["node", "bun", "deno"],
|
|
26
42
|
pkg: "../transports/node.js",
|
|
27
43
|
export: "NodeTransport",
|
|
28
44
|
priority: 10,
|
|
29
45
|
},
|
|
30
46
|
];
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
const DEBUG = false;
|
|
37
|
-
const trace = (...args) => {
|
|
38
|
-
if (DEBUG)
|
|
39
|
-
console.log("[hyperttp]", ...args);
|
|
40
|
-
};
|
|
47
|
+
const CANDIDATES = TRANSPORTS.filter((t) => t.runtime.includes(CURRENT_RUNTIME)).sort((a, b) => b.priority - a.priority);
|
|
48
|
+
let RESOLVED_RUNTIME_CTOR = null;
|
|
49
|
+
let NODE_RESOLVE_TOOLS = null;
|
|
50
|
+
let ATTEMPTED_TOOLS_LOAD = false;
|
|
51
|
+
export const runtimeImport = Function("s", "return import(s)");
|
|
41
52
|
function isModuleNotFoundError(err) {
|
|
42
53
|
if (!err || typeof err !== "object")
|
|
43
54
|
return false;
|
|
44
|
-
const
|
|
55
|
+
const code = err.code;
|
|
56
|
+
if (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND")
|
|
57
|
+
return true;
|
|
45
58
|
const msg = err instanceof Error ? err.message : "";
|
|
46
|
-
return (
|
|
47
|
-
msg.includes("
|
|
48
|
-
msg.includes("Failed to
|
|
59
|
+
return (msg.includes("Cannot find module") ||
|
|
60
|
+
msg.includes("Failed to resolve") ||
|
|
61
|
+
msg.includes("Failed to load"));
|
|
49
62
|
}
|
|
50
|
-
async function
|
|
51
|
-
|
|
52
|
-
|
|
63
|
+
async function resolveExternalModule(pkg) {
|
|
64
|
+
try {
|
|
65
|
+
if (typeof import.meta.resolve === "function") {
|
|
53
66
|
return import.meta.resolve(pkg, import.meta.url);
|
|
54
67
|
}
|
|
55
|
-
catch {
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
try {
|
|
60
|
-
return import.meta.resolve(pkg, import.meta.url);
|
|
61
68
|
}
|
|
62
69
|
catch {
|
|
63
70
|
//
|
|
64
71
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
72
|
+
if (CURRENT_RUNTIME !== "browser") {
|
|
73
|
+
try {
|
|
74
|
+
if (!NODE_RESOLVE_TOOLS && !ATTEMPTED_TOOLS_LOAD) {
|
|
75
|
+
ATTEMPTED_TOOLS_LOAD = true;
|
|
76
|
+
NODE_RESOLVE_TOOLS = await Promise.all([
|
|
77
|
+
runtimeImport("resolve-from").catch(() => null),
|
|
78
|
+
runtimeImport("node:url").catch(() => null),
|
|
79
|
+
]);
|
|
80
|
+
}
|
|
81
|
+
if (!NODE_RESOLVE_TOOLS || !NODE_RESOLVE_TOOLS[0] || !NODE_RESOLVE_TOOLS[1])
|
|
82
|
+
return null;
|
|
83
|
+
const resolveFrom = NODE_RESOLVE_TOOLS[0].default ?? NODE_RESOLVE_TOOLS[0];
|
|
84
|
+
const url = NODE_RESOLVE_TOOLS[1].default ?? NODE_RESOLVE_TOOLS[1];
|
|
85
|
+
let cwd = ".";
|
|
86
|
+
try {
|
|
87
|
+
cwd = process.cwd();
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
//
|
|
91
|
+
}
|
|
92
|
+
const physicalPath = resolveFrom.silent?.(cwd, pkg) ?? resolveFrom(cwd, pkg);
|
|
93
|
+
if (physicalPath) {
|
|
94
|
+
return url.pathToFileURL(physicalPath).href;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
//
|
|
99
|
+
}
|
|
100
|
+
}
|
|
68
101
|
return null;
|
|
69
102
|
}
|
|
70
103
|
async function loadCtor(pkg, exportName) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
104
|
+
if (CURRENT_RUNTIME === "browser") {
|
|
105
|
+
if (pkg !== "../transports/browser.js")
|
|
106
|
+
return null;
|
|
107
|
+
const mod = (await import("../transports/browser.js"));
|
|
108
|
+
const candidate = mod[exportName] ?? mod.default;
|
|
109
|
+
return typeof candidate === "function" ? candidate : null;
|
|
75
110
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
111
|
+
let specifier = pkg;
|
|
112
|
+
if (pkg[0] === "." || pkg[0] === "/") {
|
|
113
|
+
try {
|
|
114
|
+
specifier = import.meta.resolve(pkg, import.meta.url);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
//
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const resolved = await resolveExternalModule(pkg);
|
|
122
|
+
if (resolved)
|
|
123
|
+
specifier = resolved;
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
const mod = await runtimeImport(specifier);
|
|
127
|
+
const candidate = mod[exportName] ?? mod.default;
|
|
128
|
+
return typeof candidate === "function" ? candidate : null;
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
if (isModuleNotFoundError(err))
|
|
132
|
+
return null;
|
|
133
|
+
throw err;
|
|
81
134
|
}
|
|
82
|
-
return candidate;
|
|
83
135
|
}
|
|
84
|
-
/**
|
|
85
|
-
* @ru Главный резолвер транспорта (диагностический и детерминированный).
|
|
86
|
-
* @en Main transport resolver (diagnostic and deterministic).
|
|
87
|
-
* @param config - Client configuration (may contain customTransport).
|
|
88
|
-
* @returns Promise resolving to a HyperTransport instance.
|
|
89
|
-
* @throws If no compatible transport can be loaded.
|
|
90
|
-
*/
|
|
91
136
|
export async function resolveTransport(config) {
|
|
92
137
|
if (config.customTransport)
|
|
93
138
|
return config.customTransport;
|
|
94
|
-
|
|
95
|
-
|
|
139
|
+
if (RESOLVED_RUNTIME_CTOR)
|
|
140
|
+
return new RESOLVED_RUNTIME_CTOR(config);
|
|
96
141
|
const failures = [];
|
|
97
|
-
for (
|
|
98
|
-
|
|
142
|
+
for (let i = 0; i < CANDIDATES.length; i++) {
|
|
143
|
+
const t = CANDIDATES[i];
|
|
99
144
|
try {
|
|
100
|
-
const cached = CACHE.get(t.pkg);
|
|
101
|
-
if (cached) {
|
|
102
|
-
trace("cache hit:", t.pkg);
|
|
103
|
-
return new cached(config);
|
|
104
|
-
}
|
|
105
145
|
const ctor = await loadCtor(t.pkg, t.export);
|
|
106
146
|
if (!ctor) {
|
|
107
|
-
failures.push(`${t.pkg} (
|
|
147
|
+
failures.push(`${t.pkg} (missing export or not installed)`);
|
|
108
148
|
continue;
|
|
109
149
|
}
|
|
110
|
-
|
|
111
|
-
trace("selected:", t.pkg);
|
|
150
|
+
RESOLVED_RUNTIME_CTOR = ctor;
|
|
112
151
|
return new ctor(config);
|
|
113
152
|
}
|
|
114
153
|
catch (err) {
|
|
@@ -116,114 +155,68 @@ export async function resolveTransport(config) {
|
|
|
116
155
|
failures.push(`${t.pkg} (not installed)`);
|
|
117
156
|
continue;
|
|
118
157
|
}
|
|
119
|
-
throw new Error(`[Hyperttp] transport crash in ${t.pkg}: ${err?.message}`, {
|
|
158
|
+
throw new Error(`[Hyperttp] transport crash in ${t.pkg}: ${err?.message}`, {
|
|
159
|
+
cause: err,
|
|
160
|
+
});
|
|
120
161
|
}
|
|
121
162
|
}
|
|
122
|
-
throw new Error(`No compatible transport for runtime="${
|
|
123
|
-
`Failures:\n- ${failures.join("\n- ")}`);
|
|
163
|
+
throw new Error(`No compatible transport for runtime="${CURRENT_RUNTIME}".\nFailures:\n- ${failures.join("\n- ")}`);
|
|
124
164
|
}
|
|
125
|
-
/**
|
|
126
|
-
* @ru Управляет жизненным циклом транспортного слоя: ленивая инициализация, кеширование, синхронизация конфигурации.
|
|
127
|
-
* @en Manages the transport layer lifecycle: lazy initialization, caching, configuration synchronization.
|
|
128
|
-
*/
|
|
129
165
|
export class TransportManager {
|
|
130
166
|
transport = null;
|
|
131
167
|
promise = null;
|
|
132
168
|
config;
|
|
133
|
-
/**
|
|
134
|
-
* @ru Создаёт менеджер транспорта.
|
|
135
|
-
* @en Creates a transport manager.
|
|
136
|
-
* @param config - Client configuration.
|
|
137
|
-
* @param custom - Optional externally provided transport instance.
|
|
138
|
-
*/
|
|
139
169
|
constructor(config, custom) {
|
|
140
170
|
this.config = config;
|
|
141
171
|
if (custom) {
|
|
142
172
|
this.transport = custom;
|
|
143
|
-
|
|
173
|
+
}
|
|
174
|
+
else if (config.customTransport) {
|
|
175
|
+
this.transport = config.customTransport;
|
|
176
|
+
}
|
|
177
|
+
else if (RESOLVED_RUNTIME_CTOR) {
|
|
178
|
+
this.transport = new RESOLVED_RUNTIME_CTOR(config);
|
|
144
179
|
}
|
|
145
180
|
}
|
|
146
|
-
|
|
147
|
-
* @ru Обновляет конфигурацию клиента.
|
|
148
|
-
* @en Updates the client configuration.
|
|
149
|
-
* @param config - New configuration.
|
|
150
|
-
*/
|
|
151
|
-
setConfig(config) {
|
|
152
|
-
this.config = config;
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* @ru Возвращает текущий экземпляр транспорта (если уже инициализирован).
|
|
156
|
-
* @en Returns the current transport instance (if already initialised).
|
|
157
|
-
*/
|
|
158
|
-
get instance() {
|
|
181
|
+
getSync() {
|
|
159
182
|
return this.transport;
|
|
160
183
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
async get() {
|
|
167
|
-
if (this.transport)
|
|
168
|
-
return this.transport;
|
|
169
|
-
if (this.promise)
|
|
184
|
+
ensure() {
|
|
185
|
+
if (this.transport !== null) {
|
|
186
|
+
return this.promise || (this.promise = Promise.resolve(this.transport));
|
|
187
|
+
}
|
|
188
|
+
if (this.promise !== null)
|
|
170
189
|
return this.promise;
|
|
171
|
-
this.promise = resolveTransport(this.config).then((t) => {
|
|
190
|
+
return (this.promise = resolveTransport(this.config).then((t) => {
|
|
172
191
|
this.transport = t;
|
|
173
192
|
return t;
|
|
174
|
-
});
|
|
175
|
-
return this.promise;
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* @ru Выполняет запрос через транспорт и возвращает обычный (не стриминговый) ответ.
|
|
179
|
-
* @en Executes a request through the transport and returns a regular (non‑streaming) response.
|
|
180
|
-
* @param req - Request parameters.
|
|
181
|
-
* @returns Promise resolving to HttpResponse.
|
|
182
|
-
*/
|
|
183
|
-
async execute(req) {
|
|
184
|
-
const t = this.transport || (await this.get());
|
|
185
|
-
return mapResponseFast(await t.execute(req));
|
|
193
|
+
}));
|
|
186
194
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
* @en Executes a request through the transport and returns a streaming response.
|
|
190
|
-
* @param req - Request parameters.
|
|
191
|
-
* @returns Promise resolving to StreamResponse.
|
|
192
|
-
*/
|
|
193
|
-
async executeStream(req) {
|
|
194
|
-
const t = this.transport || (await this.get());
|
|
195
|
-
return mapStreamFast(await t.execute(req));
|
|
195
|
+
get() {
|
|
196
|
+
return this.transport ?? this.ensure();
|
|
196
197
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
const t = this.transport;
|
|
203
|
-
if (!t)
|
|
204
|
-
return null;
|
|
205
|
-
return {
|
|
206
|
-
name: t.__name ?? t.constructor?.name,
|
|
207
|
-
pkg: t.__pkg ?? "unknown",
|
|
208
|
-
runtime: getRuntime(),
|
|
209
|
-
};
|
|
198
|
+
setConfig(config) {
|
|
199
|
+
this.config = config;
|
|
200
|
+
if (this.transport && typeof this.transport.setConfig === "function") {
|
|
201
|
+
this.transport.setConfig(config);
|
|
202
|
+
}
|
|
210
203
|
}
|
|
211
|
-
/**
|
|
212
|
-
* @ru Завершает работу транспорта (закрывает соединения при graceful shutdown, иначе принудительно уничтожает).
|
|
213
|
-
* @en Shuts down the transport (gracefully closes connections or forcefully destroys).
|
|
214
|
-
* @param graceful - If true, attempt graceful close; otherwise call destroy.
|
|
215
|
-
* @returns Promise that resolves when shutdown is complete.
|
|
216
|
-
*/
|
|
217
204
|
async destroy(graceful = true) {
|
|
218
205
|
const t = this.transport;
|
|
219
206
|
if (!t)
|
|
220
207
|
return;
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
208
|
+
try {
|
|
209
|
+
if (graceful && typeof t.close === "function") {
|
|
210
|
+
await t.close();
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (typeof t.destroy === "function") {
|
|
214
|
+
await t.destroy();
|
|
215
|
+
}
|
|
224
216
|
}
|
|
225
|
-
|
|
226
|
-
|
|
217
|
+
finally {
|
|
218
|
+
this.transport = null;
|
|
219
|
+
this.promise = null;
|
|
227
220
|
}
|
|
228
221
|
}
|
|
229
222
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/transports/manager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/transports/manager.ts"],"names":[],"mappings":"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"}
|
package/transports/node.d.ts
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @ru Транспорт на основе глобального fetch (Node.js 18+). Обрабатывает нормализацию URL, сериализацию тела и очистку потока.
|
|
3
|
-
* @en Transport based on the global fetch API (Node.js 18+). Handles URL normalisation, body serialisation, and stream cleanup.
|
|
4
|
-
*/
|
|
5
1
|
import type { HttpClientOptions, HyperTransport, TransportRequest, TransportResponse } from "@hyperttp/types";
|
|
6
2
|
export interface NodeTransportConfig extends HttpClientOptions {
|
|
7
3
|
baseUrl?: string;
|
|
@@ -11,26 +7,10 @@ export interface NodeTransportConfig extends HttpClientOptions {
|
|
|
11
7
|
* @en Node.js transport implementation using fetch.
|
|
12
8
|
*/
|
|
13
9
|
export declare class NodeTransport implements HyperTransport {
|
|
14
|
-
/**
|
|
15
|
-
* @ru Конфигурация клиента.
|
|
16
|
-
* @en Client configuration.
|
|
17
|
-
*/
|
|
18
10
|
config: NodeTransportConfig;
|
|
19
11
|
private readonly isProduction;
|
|
20
12
|
private readonly cleanBaseUrl;
|
|
21
|
-
/**
|
|
22
|
-
* @ru Создаёт экземпляр NodeTransport.
|
|
23
|
-
* @en Creates a NodeTransport instance.
|
|
24
|
-
* @param config - Transport configuration (may include baseUrl).
|
|
25
|
-
*/
|
|
26
13
|
constructor(config: NodeTransportConfig);
|
|
27
|
-
/**
|
|
28
|
-
* @ru Выполняет HTTP-запрос через fetch.
|
|
29
|
-
* @en Executes an HTTP request via fetch.
|
|
30
|
-
* @param req - Transport request object (method, url, headers, body, signal).
|
|
31
|
-
* @returns Promise resolving to a TransportResponse.
|
|
32
|
-
* @throws If a localhost URL is requested in production environment.
|
|
33
|
-
*/
|
|
34
14
|
execute(req: TransportRequest): Promise<TransportResponse>;
|
|
35
15
|
}
|
|
36
16
|
//# sourceMappingURL=node.d.ts.map
|
package/transports/node.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/transports/node.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/transports/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EAElB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAiHD;;;GAGG;AACH,qBAAa,aAAc,YAAW,cAAc;IAC3C,MAAM,EAAE,mBAAmB,CAAC;IAEnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IACvC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAE1B,MAAM,EAAE,mBAAmB;IAQ1B,OAAO,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CA+BxE"}
|
package/transports/node.js
CHANGED
|
@@ -1,76 +1,132 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
const fetchFn = globalThis.fetch;
|
|
2
|
+
function installReadableStreamDump() {
|
|
3
|
+
if (typeof ReadableStream === "undefined")
|
|
4
|
+
return;
|
|
5
|
+
const proto = ReadableStream.prototype;
|
|
6
|
+
if (typeof proto.dump === "function")
|
|
7
|
+
return;
|
|
8
|
+
Object.defineProperty(proto, "dump", {
|
|
9
|
+
value: async function () {
|
|
10
|
+
try {
|
|
11
|
+
return await this.cancel();
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
//
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
writable: true,
|
|
18
|
+
configurable: true,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
installReadableStreamDump();
|
|
22
|
+
function isAbsoluteHttpUrl(url) {
|
|
23
|
+
return url.startsWith("http://") || url.startsWith("https://");
|
|
24
|
+
}
|
|
25
|
+
function resolveUrl(baseUrl, url) {
|
|
26
|
+
if (isAbsoluteHttpUrl(url))
|
|
27
|
+
return url;
|
|
28
|
+
return url.charCodeAt(0) === 47 ? baseUrl + url : baseUrl + "/" + url;
|
|
29
|
+
}
|
|
30
|
+
function isLocalhostUrl(url) {
|
|
31
|
+
const schemeIdx = url.indexOf("://");
|
|
32
|
+
if (schemeIdx === -1)
|
|
33
|
+
return false;
|
|
34
|
+
const hostStart = schemeIdx + 3;
|
|
35
|
+
let hostEnd = url.indexOf("/", hostStart);
|
|
36
|
+
if (hostEnd === -1)
|
|
37
|
+
hostEnd = url.length;
|
|
38
|
+
const host = url.slice(hostStart, hostEnd);
|
|
39
|
+
return host === "localhost" || host.startsWith("localhost:");
|
|
40
|
+
}
|
|
41
|
+
function normalizeHeaders(headers) {
|
|
42
|
+
if (!headers)
|
|
43
|
+
return undefined;
|
|
44
|
+
if (headers instanceof Headers) {
|
|
45
|
+
const out = Object.create(null);
|
|
46
|
+
headers.forEach((value, key) => {
|
|
47
|
+
out[key] = value;
|
|
48
|
+
});
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
51
|
+
if (Array.isArray(headers)) {
|
|
52
|
+
const out = Object.create(null);
|
|
53
|
+
for (let i = 0; i < headers.length; i++) {
|
|
54
|
+
const pair = headers[i];
|
|
55
|
+
if (!pair)
|
|
56
|
+
continue;
|
|
57
|
+
out[pair[0]] = pair[1];
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
const out = Object.create(null);
|
|
62
|
+
const src = headers;
|
|
63
|
+
for (const key in src) {
|
|
64
|
+
const value = src[key];
|
|
65
|
+
if (value == null)
|
|
66
|
+
continue;
|
|
67
|
+
if (Array.isArray(value)) {
|
|
68
|
+
out[key] = key.toLowerCase() === "cookie" ? value.join("; ") : value.join(", ");
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
out[key] = String(value);
|
|
72
|
+
}
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
function normalizeBody(body) {
|
|
76
|
+
if (body === undefined || body === null)
|
|
77
|
+
return undefined;
|
|
78
|
+
if (typeof body === "string" ||
|
|
79
|
+
body instanceof Uint8Array ||
|
|
80
|
+
body instanceof ArrayBuffer ||
|
|
81
|
+
ArrayBuffer.isView(body) ||
|
|
82
|
+
(typeof ReadableStream !== "undefined" && body instanceof ReadableStream) ||
|
|
83
|
+
(typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams) ||
|
|
84
|
+
(typeof FormData !== "undefined" && body instanceof FormData) ||
|
|
85
|
+
(typeof Blob !== "undefined" && body instanceof Blob)) {
|
|
86
|
+
return body;
|
|
87
|
+
}
|
|
88
|
+
if (typeof body === "object") {
|
|
89
|
+
return JSON.stringify(body);
|
|
90
|
+
}
|
|
91
|
+
return String(body);
|
|
92
|
+
}
|
|
5
93
|
/**
|
|
6
94
|
* @ru Реализация транспорта для Node.js с использованием fetch.
|
|
7
95
|
* @en Node.js transport implementation using fetch.
|
|
8
96
|
*/
|
|
9
97
|
export class NodeTransport {
|
|
10
|
-
/**
|
|
11
|
-
* @ru Конфигурация клиента.
|
|
12
|
-
* @en Client configuration.
|
|
13
|
-
*/
|
|
14
98
|
config;
|
|
15
99
|
isProduction;
|
|
16
100
|
cleanBaseUrl;
|
|
17
|
-
/**
|
|
18
|
-
* @ru Создаёт экземпляр NodeTransport.
|
|
19
|
-
* @en Creates a NodeTransport instance.
|
|
20
|
-
* @param config - Transport configuration (may include baseUrl).
|
|
21
|
-
*/
|
|
22
101
|
constructor(config) {
|
|
23
102
|
this.config = config;
|
|
24
103
|
this.isProduction = process.env.NODE_ENV === "production";
|
|
25
104
|
const base = config.baseUrl ?? "http://localhost:3000";
|
|
26
105
|
this.cleanBaseUrl = base.endsWith("/") ? base.slice(0, -1) : base;
|
|
27
106
|
}
|
|
28
|
-
/**
|
|
29
|
-
* @ru Выполняет HTTP-запрос через fetch.
|
|
30
|
-
* @en Executes an HTTP request via fetch.
|
|
31
|
-
* @param req - Transport request object (method, url, headers, body, signal).
|
|
32
|
-
* @returns Promise resolving to a TransportResponse.
|
|
33
|
-
* @throws If a localhost URL is requested in production environment.
|
|
34
|
-
*/
|
|
35
107
|
async execute(req) {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
? urlStr
|
|
39
|
-
: urlStr.charCodeAt(0) === 47
|
|
40
|
-
? this.cleanBaseUrl + urlStr
|
|
41
|
-
: this.cleanBaseUrl + "/" + urlStr;
|
|
42
|
-
if (this.isProduction && fullUrl.includes("//localhost")) {
|
|
108
|
+
const fullUrl = resolveUrl(this.cleanBaseUrl, req.url);
|
|
109
|
+
if (this.isProduction && isLocalhostUrl(fullUrl)) {
|
|
43
110
|
throw new Error("Localhost URL detected in production environment");
|
|
44
111
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
typeof finalBody === "object" &&
|
|
49
|
-
!Buffer.isBuffer(finalBody) &&
|
|
50
|
-
!(finalBody instanceof ReadableStream)) {
|
|
51
|
-
finalBody = JSON.stringify(finalBody);
|
|
52
|
-
}
|
|
53
|
-
const res = await globalThis.fetch(fullUrl, {
|
|
112
|
+
const headers = normalizeHeaders(req.headers);
|
|
113
|
+
const body = normalizeBody(req.body);
|
|
114
|
+
const res = await fetchFn(fullUrl, {
|
|
54
115
|
method: req.method,
|
|
55
|
-
headers
|
|
56
|
-
body
|
|
116
|
+
headers,
|
|
117
|
+
body,
|
|
57
118
|
signal: req.signal,
|
|
58
119
|
});
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
await res.body.cancel();
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
const resHeaders = {};
|
|
66
|
-
for (const [key, value] of res.headers) {
|
|
120
|
+
const stream = (res.body ?? new ReadableStream());
|
|
121
|
+
const resHeaders = Object.create(null);
|
|
122
|
+
res.headers.forEach((value, key) => {
|
|
67
123
|
resHeaders[key] = value;
|
|
68
|
-
}
|
|
124
|
+
});
|
|
69
125
|
return {
|
|
70
126
|
status: res.status,
|
|
71
127
|
headers: resHeaders,
|
|
72
128
|
url: res.url,
|
|
73
|
-
body:
|
|
129
|
+
body: stream,
|
|
74
130
|
};
|
|
75
131
|
}
|
|
76
132
|
}
|