@npy/fetch 0.1.2 → 0.1.3

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.
Files changed (142) hide show
  1. package/README.md +143 -50
  2. package/bun.lock +68 -0
  3. package/examples/custom-proxy-client.ts +32 -0
  4. package/examples/http-client.ts +47 -0
  5. package/examples/proxy.ts +16 -0
  6. package/examples/simple.ts +15 -0
  7. package/package.json +25 -30
  8. package/src/_internal/consts.ts +3 -0
  9. package/{_internal/decode-stream-error.d.cts → src/_internal/decode-stream-error.ts} +7 -2
  10. package/src/_internal/error-mapping.ts +160 -0
  11. package/src/_internal/guards.ts +78 -0
  12. package/src/_internal/net.ts +173 -0
  13. package/src/_internal/promises.ts +22 -0
  14. package/src/_internal/streams.ts +52 -0
  15. package/src/_internal/symbols.ts +1 -0
  16. package/src/agent-pool.ts +157 -0
  17. package/src/agent.ts +408 -0
  18. package/src/body.ts +179 -0
  19. package/src/dialers/index.ts +3 -0
  20. package/src/dialers/proxy.ts +102 -0
  21. package/src/dialers/tcp.ts +162 -0
  22. package/src/encoding.ts +222 -0
  23. package/src/errors.ts +357 -0
  24. package/src/fetch.ts +626 -0
  25. package/src/http-client.ts +111 -0
  26. package/src/index.ts +14 -0
  27. package/src/io/_utils.ts +82 -0
  28. package/src/io/buf-writer.ts +183 -0
  29. package/src/io/io.ts +322 -0
  30. package/src/io/readers.ts +576 -0
  31. package/src/io/writers.ts +331 -0
  32. package/{types/agent.d.cts → src/types/agent.ts} +47 -21
  33. package/{types/dialer.d.cts → src/types/dialer.ts} +19 -9
  34. package/src/types/index.ts +2 -0
  35. package/tests/agent-pool.test.ts +111 -0
  36. package/tests/agent.test.ts +134 -0
  37. package/tests/body.test.ts +228 -0
  38. package/tests/errors.test.ts +152 -0
  39. package/tests/fetch.test.ts +421 -0
  40. package/tests/io-options.test.ts +127 -0
  41. package/tests/multipart.test.ts +348 -0
  42. package/tests/test-utils.ts +335 -0
  43. package/tsconfig.json +15 -0
  44. package/LICENSE +0 -21
  45. package/_internal/consts.cjs +0 -4
  46. package/_internal/consts.d.cts +0 -3
  47. package/_internal/consts.d.ts +0 -3
  48. package/_internal/consts.js +0 -4
  49. package/_internal/decode-stream-error.cjs +0 -18
  50. package/_internal/decode-stream-error.d.ts +0 -11
  51. package/_internal/decode-stream-error.js +0 -18
  52. package/_internal/error-mapping.cjs +0 -44
  53. package/_internal/error-mapping.d.cts +0 -15
  54. package/_internal/error-mapping.d.ts +0 -15
  55. package/_internal/error-mapping.js +0 -41
  56. package/_internal/guards.cjs +0 -23
  57. package/_internal/guards.d.cts +0 -15
  58. package/_internal/guards.d.ts +0 -15
  59. package/_internal/guards.js +0 -15
  60. package/_internal/net.cjs +0 -95
  61. package/_internal/net.d.cts +0 -11
  62. package/_internal/net.d.ts +0 -11
  63. package/_internal/net.js +0 -92
  64. package/_internal/promises.cjs +0 -18
  65. package/_internal/promises.d.cts +0 -1
  66. package/_internal/promises.d.ts +0 -1
  67. package/_internal/promises.js +0 -18
  68. package/_internal/streams.cjs +0 -37
  69. package/_internal/streams.d.cts +0 -21
  70. package/_internal/streams.d.ts +0 -21
  71. package/_internal/streams.js +0 -36
  72. package/_internal/symbols.cjs +0 -4
  73. package/_internal/symbols.d.cts +0 -1
  74. package/_internal/symbols.d.ts +0 -1
  75. package/_internal/symbols.js +0 -4
  76. package/_virtual/_rolldown/runtime.cjs +0 -23
  77. package/agent-pool.cjs +0 -96
  78. package/agent-pool.d.cts +0 -2
  79. package/agent-pool.d.ts +0 -2
  80. package/agent-pool.js +0 -95
  81. package/agent.cjs +0 -260
  82. package/agent.d.cts +0 -3
  83. package/agent.d.ts +0 -3
  84. package/agent.js +0 -259
  85. package/body.cjs +0 -105
  86. package/body.d.cts +0 -12
  87. package/body.d.ts +0 -12
  88. package/body.js +0 -102
  89. package/dialers/index.d.cts +0 -3
  90. package/dialers/index.d.ts +0 -3
  91. package/dialers/proxy.cjs +0 -56
  92. package/dialers/proxy.d.cts +0 -27
  93. package/dialers/proxy.d.ts +0 -27
  94. package/dialers/proxy.js +0 -55
  95. package/dialers/tcp.cjs +0 -92
  96. package/dialers/tcp.d.cts +0 -57
  97. package/dialers/tcp.d.ts +0 -57
  98. package/dialers/tcp.js +0 -89
  99. package/encoding.cjs +0 -114
  100. package/encoding.d.cts +0 -35
  101. package/encoding.d.ts +0 -35
  102. package/encoding.js +0 -110
  103. package/errors.cjs +0 -275
  104. package/errors.d.cts +0 -110
  105. package/errors.d.ts +0 -110
  106. package/errors.js +0 -259
  107. package/fetch.cjs +0 -353
  108. package/fetch.d.cts +0 -58
  109. package/fetch.d.ts +0 -58
  110. package/fetch.js +0 -350
  111. package/http-client.cjs +0 -75
  112. package/http-client.d.cts +0 -39
  113. package/http-client.d.ts +0 -39
  114. package/http-client.js +0 -75
  115. package/index.cjs +0 -49
  116. package/index.d.cts +0 -14
  117. package/index.d.ts +0 -14
  118. package/index.js +0 -11
  119. package/io/_utils.cjs +0 -56
  120. package/io/_utils.d.cts +0 -10
  121. package/io/_utils.d.ts +0 -10
  122. package/io/_utils.js +0 -51
  123. package/io/buf-writer.cjs +0 -149
  124. package/io/buf-writer.d.cts +0 -13
  125. package/io/buf-writer.d.ts +0 -13
  126. package/io/buf-writer.js +0 -148
  127. package/io/io.cjs +0 -199
  128. package/io/io.d.cts +0 -5
  129. package/io/io.d.ts +0 -5
  130. package/io/io.js +0 -198
  131. package/io/readers.cjs +0 -337
  132. package/io/readers.d.cts +0 -69
  133. package/io/readers.d.ts +0 -69
  134. package/io/readers.js +0 -333
  135. package/io/writers.cjs +0 -196
  136. package/io/writers.d.cts +0 -22
  137. package/io/writers.d.ts +0 -22
  138. package/io/writers.js +0 -195
  139. package/types/agent.d.ts +0 -72
  140. package/types/dialer.d.ts +0 -30
  141. package/types/index.d.cts +0 -2
  142. package/types/index.d.ts +0 -2
package/agent.js DELETED
@@ -1,259 +0,0 @@
1
- import { AgentBusyError, AgentClosedError, OriginMismatchError, RequestAbortedError, UnsupportedAlpnProtocolError, UnsupportedMethodError, UnsupportedProtocolError } from "./errors.js";
2
- import { toConnectError, toSendError } from "./_internal/error-mapping.js";
3
- import { raceSignal } from "./_internal/promises.js";
4
- import { bodyErrorMapperSymbol } from "./_internal/symbols.js";
5
- import { readResponse, writeRequest } from "./io/io.js";
6
- import { Deferred } from "@fuman/utils";
7
- //#region src/agent.ts
8
- var PORT_MAP = {
9
- "http:": 80,
10
- "https:": 443
11
- };
12
- var DEFAULT_ALPN_PROTOCOLS = ["http/1.1"];
13
- function resolvedDeferred() {
14
- const deferred = new Deferred();
15
- deferred.resolve();
16
- return deferred;
17
- }
18
- function withSignal(promise, signal) {
19
- return signal ? raceSignal(promise, signal) : promise;
20
- }
21
- function isTlsConnection(conn) {
22
- return "getAlpnProtocol" in conn && typeof conn.getAlpnProtocol === "function";
23
- }
24
- function createAgent(dialer, baseUrl, options = {}) {
25
- const base = new URL(baseUrl);
26
- if (base.protocol !== "http:" && base.protocol !== "https:") throw new UnsupportedProtocolError(base.protocol, {
27
- origin: base.origin,
28
- scheme: base.protocol,
29
- host: base.hostname,
30
- port: base.port ? Number.parseInt(base.port, 10) : void 0,
31
- url: base.toString()
32
- });
33
- const secure = base.protocol === "https:";
34
- const hostname = base.hostname;
35
- const port = base.port ? Number.parseInt(base.port, 10) : PORT_MAP[base.protocol];
36
- if (!Number.isFinite(port) || port <= 0 || port > 65535) throw new TypeError(`Invalid port in base URL: ${baseUrl}`);
37
- const target = {
38
- address: hostname,
39
- port,
40
- secure,
41
- sni: secure ? hostname : void 0,
42
- alpnProtocols: secure ? [...DEFAULT_ALPN_PROTOCOLS] : void 0
43
- };
44
- const connectOptions = options.connect ?? {};
45
- const readerOptions = options.io?.reader ?? {};
46
- const writerOptions = options.io?.writer ?? {};
47
- let conn;
48
- let connectPromise;
49
- let closed = false;
50
- let isBusy = false;
51
- let lastUsedTime = Date.now();
52
- let idleDeferred = resolvedDeferred();
53
- function createBaseErrorContext() {
54
- return {
55
- origin: base.origin,
56
- scheme: base.protocol,
57
- host: hostname,
58
- port
59
- };
60
- }
61
- function createRequestErrorContext(url, method) {
62
- return {
63
- ...createBaseErrorContext(),
64
- url: url.toString(),
65
- method
66
- };
67
- }
68
- function markIdle() {
69
- isBusy = false;
70
- lastUsedTime = Date.now();
71
- idleDeferred.resolve();
72
- }
73
- function disposeConn() {
74
- const current = conn;
75
- conn = void 0;
76
- if (!current) return;
77
- try {
78
- current.close();
79
- } catch {}
80
- }
81
- function forceClose() {
82
- if (closed) return;
83
- closed = true;
84
- disposeConn();
85
- if (!isBusy) markIdle();
86
- }
87
- function assertUsable() {
88
- if (closed) throw new AgentClosedError(createBaseErrorContext());
89
- }
90
- function assertSameOrigin(url) {
91
- if (url.origin !== base.origin) throw new OriginMismatchError(base.origin, url.origin, {
92
- ...createBaseErrorContext(),
93
- url: url.toString()
94
- });
95
- }
96
- function configureConnection(nextConn) {
97
- nextConn.setNoDelay(connectOptions.noDelay ?? true);
98
- if (connectOptions.keepAlive !== null) nextConn.setKeepAlive(connectOptions.keepAlive ?? true);
99
- }
100
- async function connect(signal) {
101
- assertUsable();
102
- if (conn) return conn;
103
- if (connectPromise) return withSignal(connectPromise, signal);
104
- let timedOut = false;
105
- let timeoutId;
106
- const abortController = new AbortController();
107
- const onAbort = () => abortController.abort(signal?.reason);
108
- const cleanup = () => {
109
- if (timeoutId !== void 0) {
110
- clearTimeout(timeoutId);
111
- timeoutId = void 0;
112
- }
113
- if (signal) signal.removeEventListener("abort", onAbort);
114
- };
115
- if (signal) if (signal.aborted) abortController.abort(signal.reason);
116
- else signal.addEventListener("abort", onAbort, { once: true });
117
- if (connectOptions.timeout != null && Number.isFinite(connectOptions.timeout) && connectOptions.timeout > 0) timeoutId = setTimeout(() => {
118
- timedOut = true;
119
- abortController.abort(new DOMException("Connection timed out", "TimeoutError"));
120
- }, connectOptions.timeout);
121
- connectPromise = (async () => {
122
- try {
123
- const nextConn = await dialer.dial(target, { signal: abortController.signal });
124
- if (closed) {
125
- try {
126
- nextConn.close();
127
- } catch {}
128
- throw new AgentClosedError(createBaseErrorContext());
129
- }
130
- configureConnection(nextConn);
131
- if (secure && isTlsConnection(nextConn)) {
132
- const alpn = nextConn.getAlpnProtocol();
133
- if (alpn != null && alpn !== "" && alpn !== "http/1.1") {
134
- try {
135
- nextConn.close();
136
- } catch {}
137
- throw new UnsupportedAlpnProtocolError(alpn, createBaseErrorContext());
138
- }
139
- }
140
- conn = nextConn;
141
- return nextConn;
142
- } catch (error) {
143
- throw toConnectError(error, {
144
- signal,
145
- timedOut,
146
- context: createBaseErrorContext()
147
- });
148
- } finally {
149
- cleanup();
150
- connectPromise = void 0;
151
- }
152
- })();
153
- return withSignal(connectPromise, signal);
154
- }
155
- async function executeRequest(sendOptions, mapBodyError) {
156
- assertUsable();
157
- const url = typeof sendOptions.url === "string" ? new URL(sendOptions.url) : sendOptions.url;
158
- const method = sendOptions.method.toUpperCase();
159
- const errorContext = createRequestErrorContext(url, method);
160
- if (sendOptions.signal?.aborted) throw new RequestAbortedError(sendOptions.signal.reason, errorContext);
161
- if (isBusy) throw new AgentBusyError(errorContext);
162
- assertSameOrigin(url);
163
- if (method === "CONNECT") throw new UnsupportedMethodError("CONNECT", errorContext);
164
- isBusy = true;
165
- idleDeferred = new Deferred();
166
- let finalized = false;
167
- let activeConn;
168
- const finalize = (reusable) => {
169
- if (finalized) return;
170
- finalized = true;
171
- if (!reusable || closed) {
172
- if (conn === activeConn) disposeConn();
173
- else if (activeConn) try {
174
- activeConn.close();
175
- } catch {}
176
- }
177
- markIdle();
178
- };
179
- const abortListener = () => {
180
- if (activeConn) {
181
- if (conn === activeConn) conn = void 0;
182
- try {
183
- activeConn.close();
184
- } catch {}
185
- }
186
- };
187
- try {
188
- activeConn = await connect(sendOptions.signal);
189
- sendOptions.signal?.addEventListener("abort", abortListener, { once: true });
190
- try {
191
- await withSignal(writeRequest(activeConn, {
192
- url,
193
- method,
194
- headers: sendOptions.headers,
195
- body: sendOptions.body ?? null,
196
- signal: sendOptions.signal
197
- }, writerOptions), sendOptions.signal);
198
- } catch (error) {
199
- throw toSendError(error, {
200
- signal: sendOptions.signal,
201
- context: errorContext,
202
- phase: "request"
203
- });
204
- }
205
- const isHeadRequest = method === "HEAD";
206
- const shouldIgnoreBody = (status) => isHeadRequest || status >= 100 && status < 200 || status === 204 || status === 304;
207
- let response;
208
- try {
209
- response = await withSignal(readResponse(activeConn, readerOptions, shouldIgnoreBody, (reusable) => {
210
- sendOptions.signal?.removeEventListener("abort", abortListener);
211
- finalize(reusable);
212
- }, mapBodyError), sendOptions.signal);
213
- } catch (error) {
214
- throw toSendError(error, {
215
- signal: sendOptions.signal,
216
- context: errorContext,
217
- phase: "response"
218
- });
219
- }
220
- return response;
221
- } catch (error) {
222
- sendOptions.signal?.removeEventListener("abort", abortListener);
223
- if (activeConn) {
224
- if (conn === activeConn) conn = void 0;
225
- try {
226
- activeConn.close();
227
- } catch {}
228
- }
229
- finalize(false);
230
- throw error;
231
- }
232
- }
233
- async function send(sendOptions) {
234
- const errorContext = createRequestErrorContext(typeof sendOptions.url === "string" ? new URL(sendOptions.url) : sendOptions.url, sendOptions.method.toUpperCase());
235
- return executeRequest(sendOptions, sendOptions[bodyErrorMapperSymbol] ?? ((error) => toSendError(error, {
236
- signal: sendOptions.signal,
237
- context: errorContext,
238
- phase: "body"
239
- })));
240
- }
241
- return {
242
- [Symbol.dispose]: forceClose,
243
- close: forceClose,
244
- hostname,
245
- port,
246
- send,
247
- whenIdle() {
248
- return idleDeferred.promise;
249
- },
250
- get isIdle() {
251
- return !isBusy;
252
- },
253
- get lastUsed() {
254
- return lastUsedTime;
255
- }
256
- };
257
- }
258
- //#endregion
259
- export { createAgent };
package/body.cjs DELETED
@@ -1,105 +0,0 @@
1
- require("./_virtual/_rolldown/runtime.cjs");
2
- const require_guards = require("./_internal/guards.cjs");
3
- let _fuman_utils = require("@fuman/utils");
4
- let node_stream = require("node:stream");
5
- let _fuman_io = require("@fuman/io");
6
- let node_crypto = require("node:crypto");
7
- let node_util_types = require("node:util/types");
8
- //#region src/body.ts
9
- var BOUNDARY = "-".repeat(2);
10
- var makeFormBoundary = () => `formdata-${(0, node_crypto.randomBytes)(8).toString("hex")}`;
11
- var getFormHeader = (boundary, name, field) => {
12
- let header = `${BOUNDARY}${boundary}\r
13
- `;
14
- header += `Content-Disposition: form-data; name="${name}"`;
15
- if (require_guards.isBlob(field)) {
16
- header += `; filename="${field.name ?? "blob"}"\r
17
- `;
18
- header += `Content-Type: ${field.type || "application/octet-stream"}`;
19
- }
20
- return `${header}\r
21
- \r
22
- `;
23
- };
24
- var getFormFooter = (boundary) => `${BOUNDARY}${boundary}${BOUNDARY}\r
25
- \r
26
- `;
27
- var getFormDataLength = (form, boundary) => {
28
- let length = Buffer.byteLength(getFormFooter(boundary));
29
- for (const [name, value] of form) length += Buffer.byteLength(getFormHeader(boundary, name, value)) + (require_guards.isBlob(value) ? value.size : Buffer.byteLength(`${value}`)) + 2;
30
- return length;
31
- };
32
- async function* generatorOfFormData(form, boundary) {
33
- for (const [name, value] of form) if (require_guards.isBlob(value)) {
34
- yield _fuman_utils.utf8.encoder.encode(getFormHeader(boundary, name, value));
35
- for await (const chunk of value.stream()) yield chunk;
36
- yield _fuman_utils.utf8.encoder.encode("\r\n");
37
- } else yield _fuman_utils.utf8.encoder.encode(getFormHeader(boundary, name, value) + value + "\r\n");
38
- yield _fuman_utils.utf8.encoder.encode(getFormFooter(boundary));
39
- }
40
- var extractBody = (object) => {
41
- let type = null;
42
- let body;
43
- let size = null;
44
- if (object == null) {
45
- body = null;
46
- size = 0;
47
- } else if (typeof object === "string") {
48
- const bytes = _fuman_utils.utf8.encoder.encode(`${object}`);
49
- type = "text/plain;charset=UTF-8";
50
- size = bytes.byteLength;
51
- body = bytes;
52
- } else if (require_guards.isURLSearchParameters(object)) {
53
- const bytes = _fuman_utils.utf8.encoder.encode(object.toString());
54
- body = bytes;
55
- size = bytes.byteLength;
56
- type = "application/x-www-form-urlencoded;charset=UTF-8";
57
- } else if (require_guards.isBlob(object)) {
58
- size = object.size;
59
- type = object.type || null;
60
- body = object.stream();
61
- } else if (object instanceof Uint8Array) {
62
- body = object;
63
- size = object.byteLength;
64
- } else if ((0, node_util_types.isAnyArrayBuffer)(object)) {
65
- const bytes = new Uint8Array(object);
66
- body = bytes;
67
- size = bytes.byteLength;
68
- } else if (ArrayBuffer.isView(object)) {
69
- const bytes = new Uint8Array(object.buffer, object.byteOffset, object.byteLength);
70
- body = bytes;
71
- size = bytes.byteLength;
72
- } else if (require_guards.isReadableStream(object)) body = object;
73
- else if (require_guards.isFumanReadable(object)) body = object;
74
- else if (require_guards.isFormData(object)) {
75
- const boundary = makeFormBoundary();
76
- type = `multipart/form-data; boundary=${boundary}`;
77
- size = getFormDataLength(object, boundary);
78
- body = node_stream.Readable.from(generatorOfFormData(object, boundary));
79
- } else if (require_guards.isMultipartFormDataStream(object)) {
80
- type = `multipart/form-data; boundary=${object.getBoundary()}`;
81
- size = object.hasKnownLength() ? object.getLengthSync() : null;
82
- body = object;
83
- } else if (require_guards.isReadable(object)) body = object;
84
- else if (require_guards.isIterable(object)) body = node_stream.Readable.from(object);
85
- else {
86
- const bytes = _fuman_utils.utf8.encoder.encode(`${object}`);
87
- type = "text/plain;charset=UTF-8";
88
- body = bytes;
89
- size = bytes.byteLength;
90
- }
91
- return {
92
- contentLength: size,
93
- contentType: type,
94
- body
95
- };
96
- };
97
- function fromRequestBody(request) {
98
- if (request.bodyUsed) throw new TypeError("Request body has already been used");
99
- if (request.body == null) return null;
100
- return (0, _fuman_io.webReadableToFuman)(request.body);
101
- }
102
- //#endregion
103
- exports.extractBody = extractBody;
104
- exports.fromRequestBody = fromRequestBody;
105
- exports.getFormDataLength = getFormDataLength;
package/body.d.cts DELETED
@@ -1,12 +0,0 @@
1
- import { Readable } from 'node:stream';
2
- import { IClosable, IReadable } from '@fuman/io';
3
- import { FormDataPolyfill } from './_internal/guards';
4
- export type BodyInit = Exclude<RequestInit["body"], undefined | null> | FormDataPolyfill | Readable | (IReadable & IClosable);
5
- export interface BodyState {
6
- contentLength: number | null;
7
- contentType: string | null;
8
- body: Readable | ReadableStream | Uint8Array | (IReadable & IClosable) | null;
9
- }
10
- export declare const getFormDataLength: (form: FormData, boundary: string) => number;
11
- export declare const extractBody: (object: BodyInit | null) => BodyState;
12
- export declare function fromRequestBody(request: Request): BodyInit | null;
package/body.d.ts DELETED
@@ -1,12 +0,0 @@
1
- import { Readable } from 'node:stream';
2
- import { IClosable, IReadable } from '@fuman/io';
3
- import { FormDataPolyfill } from './_internal/guards';
4
- export type BodyInit = Exclude<RequestInit["body"], undefined | null> | FormDataPolyfill | Readable | (IReadable & IClosable);
5
- export interface BodyState {
6
- contentLength: number | null;
7
- contentType: string | null;
8
- body: Readable | ReadableStream | Uint8Array | (IReadable & IClosable) | null;
9
- }
10
- export declare const getFormDataLength: (form: FormData, boundary: string) => number;
11
- export declare const extractBody: (object: BodyInit | null) => BodyState;
12
- export declare function fromRequestBody(request: Request): BodyInit | null;
package/body.js DELETED
@@ -1,102 +0,0 @@
1
- import { isBlob, isFormData, isFumanReadable, isIterable, isMultipartFormDataStream, isReadable, isReadableStream, isURLSearchParameters } from "./_internal/guards.js";
2
- import { utf8 } from "@fuman/utils";
3
- import { Readable } from "node:stream";
4
- import { webReadableToFuman } from "@fuman/io";
5
- import { randomBytes } from "node:crypto";
6
- import { isAnyArrayBuffer } from "node:util/types";
7
- //#region src/body.ts
8
- var BOUNDARY = "-".repeat(2);
9
- var makeFormBoundary = () => `formdata-${randomBytes(8).toString("hex")}`;
10
- var getFormHeader = (boundary, name, field) => {
11
- let header = `${BOUNDARY}${boundary}\r
12
- `;
13
- header += `Content-Disposition: form-data; name="${name}"`;
14
- if (isBlob(field)) {
15
- header += `; filename="${field.name ?? "blob"}"\r
16
- `;
17
- header += `Content-Type: ${field.type || "application/octet-stream"}`;
18
- }
19
- return `${header}\r
20
- \r
21
- `;
22
- };
23
- var getFormFooter = (boundary) => `${BOUNDARY}${boundary}${BOUNDARY}\r
24
- \r
25
- `;
26
- var getFormDataLength = (form, boundary) => {
27
- let length = Buffer.byteLength(getFormFooter(boundary));
28
- for (const [name, value] of form) length += Buffer.byteLength(getFormHeader(boundary, name, value)) + (isBlob(value) ? value.size : Buffer.byteLength(`${value}`)) + 2;
29
- return length;
30
- };
31
- async function* generatorOfFormData(form, boundary) {
32
- for (const [name, value] of form) if (isBlob(value)) {
33
- yield utf8.encoder.encode(getFormHeader(boundary, name, value));
34
- for await (const chunk of value.stream()) yield chunk;
35
- yield utf8.encoder.encode("\r\n");
36
- } else yield utf8.encoder.encode(getFormHeader(boundary, name, value) + value + "\r\n");
37
- yield utf8.encoder.encode(getFormFooter(boundary));
38
- }
39
- var extractBody = (object) => {
40
- let type = null;
41
- let body;
42
- let size = null;
43
- if (object == null) {
44
- body = null;
45
- size = 0;
46
- } else if (typeof object === "string") {
47
- const bytes = utf8.encoder.encode(`${object}`);
48
- type = "text/plain;charset=UTF-8";
49
- size = bytes.byteLength;
50
- body = bytes;
51
- } else if (isURLSearchParameters(object)) {
52
- const bytes = utf8.encoder.encode(object.toString());
53
- body = bytes;
54
- size = bytes.byteLength;
55
- type = "application/x-www-form-urlencoded;charset=UTF-8";
56
- } else if (isBlob(object)) {
57
- size = object.size;
58
- type = object.type || null;
59
- body = object.stream();
60
- } else if (object instanceof Uint8Array) {
61
- body = object;
62
- size = object.byteLength;
63
- } else if (isAnyArrayBuffer(object)) {
64
- const bytes = new Uint8Array(object);
65
- body = bytes;
66
- size = bytes.byteLength;
67
- } else if (ArrayBuffer.isView(object)) {
68
- const bytes = new Uint8Array(object.buffer, object.byteOffset, object.byteLength);
69
- body = bytes;
70
- size = bytes.byteLength;
71
- } else if (isReadableStream(object)) body = object;
72
- else if (isFumanReadable(object)) body = object;
73
- else if (isFormData(object)) {
74
- const boundary = makeFormBoundary();
75
- type = `multipart/form-data; boundary=${boundary}`;
76
- size = getFormDataLength(object, boundary);
77
- body = Readable.from(generatorOfFormData(object, boundary));
78
- } else if (isMultipartFormDataStream(object)) {
79
- type = `multipart/form-data; boundary=${object.getBoundary()}`;
80
- size = object.hasKnownLength() ? object.getLengthSync() : null;
81
- body = object;
82
- } else if (isReadable(object)) body = object;
83
- else if (isIterable(object)) body = Readable.from(object);
84
- else {
85
- const bytes = utf8.encoder.encode(`${object}`);
86
- type = "text/plain;charset=UTF-8";
87
- body = bytes;
88
- size = bytes.byteLength;
89
- }
90
- return {
91
- contentLength: size,
92
- contentType: type,
93
- body
94
- };
95
- };
96
- function fromRequestBody(request) {
97
- if (request.bodyUsed) throw new TypeError("Request body has already been used");
98
- if (request.body == null) return null;
99
- return webReadableToFuman(request.body);
100
- }
101
- //#endregion
102
- export { extractBody, fromRequestBody, getFormDataLength };
@@ -1,3 +0,0 @@
1
- export type { ConnectionLike, Dialer, DialTarget } from '../types/dialer';
2
- export * from './proxy';
3
- export * from './tcp';
@@ -1,3 +0,0 @@
1
- export type { ConnectionLike, Dialer, DialTarget } from '../types/dialer';
2
- export * from './proxy';
3
- export * from './tcp';
package/dialers/proxy.cjs DELETED
@@ -1,56 +0,0 @@
1
- require("../_virtual/_rolldown/runtime.cjs");
2
- const require_net = require("../_internal/net.cjs");
3
- let _npy_proxy_kit = require("@npy/proxy-kit");
4
- //#region src/dialers/proxy.ts
5
- var DEFAULT_HTTP_ALPN_PROTOCOLS = ["http/1.1"];
6
- function normalizeProxy(proxy) {
7
- if (typeof proxy !== "string") return proxy;
8
- const parsed = (0, _npy_proxy_kit.parse)(proxy, { strict: true });
9
- if (parsed == null) throw new TypeError(`Invalid proxy string: ${proxy}`);
10
- return parsed;
11
- }
12
- /**
13
- * Dialer that routes connections through an HTTP, HTTPS or SOCKS proxy.
14
- *
15
- * @remarks
16
- * Secure targets are tunneled and then upgraded to TLS after the proxy connection
17
- * has been established.
18
- */
19
- var ProxyDialer = class {
20
- proxy;
21
- #options;
22
- #connectThroughProxy;
23
- constructor(proxy, options = {}) {
24
- this.proxy = normalizeProxy(proxy);
25
- this.#options = { ...options };
26
- this.#connectThroughProxy = (0, _npy_proxy_kit.createProxyConnection)({
27
- proxy: this.proxy,
28
- connectionFn: require_net.connectTcp
29
- });
30
- }
31
- async dial(target, options = {}) {
32
- const tunneled = await this.#connectThroughProxy({
33
- address: target.address,
34
- port: target.port,
35
- signal: options.signal
36
- });
37
- if (!target.secure) return tunneled;
38
- return this.#upgradeSecureTarget(tunneled, target, options.signal);
39
- }
40
- async #upgradeSecureTarget(conn, target, signal) {
41
- const sni = target.sni ?? this.#options.sni ?? target.address;
42
- const extraOptions = this.#options.extraOptions || target.extraOptions ? {
43
- ...this.#options.extraOptions,
44
- ...target.extraOptions
45
- } : void 0;
46
- return require_net.upgradeTls(conn, {
47
- signal,
48
- caCerts: this.#options.caCerts,
49
- sni,
50
- alpnProtocols: target.alpnProtocols ?? this.#options.alpnProtocols ?? [...DEFAULT_HTTP_ALPN_PROTOCOLS],
51
- extraOptions
52
- });
53
- }
54
- };
55
- //#endregion
56
- exports.ProxyDialer = ProxyDialer;
@@ -1,27 +0,0 @@
1
- import { NodeTlsUpgradeOptions } from '@fuman/node';
2
- import { createProxyConnection, ProxyInfo } from '@npy/proxy-kit';
3
- import { Dialer } from '../types/dialer';
4
- type ResolvedProxy = Parameters<typeof createProxyConnection>[0]["proxy"];
5
- /**
6
- * Dialer that routes connections through an HTTP, HTTPS or SOCKS proxy.
7
- *
8
- * @remarks
9
- * Secure targets are tunneled and then upgraded to TLS after the proxy connection
10
- * has been established.
11
- */
12
- export declare class ProxyDialer implements Dialer {
13
- #private;
14
- readonly proxy: ResolvedProxy;
15
- constructor(proxy: ProxyDialer.Input, options?: ProxyDialer.Options);
16
- dial(target: Dialer.Target, options?: Dialer.Options): Promise<Dialer.ConnectionLike>;
17
- }
18
- export declare namespace ProxyDialer {
19
- type Input = string | ProxyInfo;
20
- interface Options {
21
- caCerts?: string[];
22
- sni?: string;
23
- alpnProtocols?: string[];
24
- extraOptions?: NodeTlsUpgradeOptions["extraOptions"];
25
- }
26
- }
27
- export {};
@@ -1,27 +0,0 @@
1
- import { NodeTlsUpgradeOptions } from '@fuman/node';
2
- import { createProxyConnection, ProxyInfo } from '@npy/proxy-kit';
3
- import { Dialer } from '../types/dialer';
4
- type ResolvedProxy = Parameters<typeof createProxyConnection>[0]["proxy"];
5
- /**
6
- * Dialer that routes connections through an HTTP, HTTPS or SOCKS proxy.
7
- *
8
- * @remarks
9
- * Secure targets are tunneled and then upgraded to TLS after the proxy connection
10
- * has been established.
11
- */
12
- export declare class ProxyDialer implements Dialer {
13
- #private;
14
- readonly proxy: ResolvedProxy;
15
- constructor(proxy: ProxyDialer.Input, options?: ProxyDialer.Options);
16
- dial(target: Dialer.Target, options?: Dialer.Options): Promise<Dialer.ConnectionLike>;
17
- }
18
- export declare namespace ProxyDialer {
19
- type Input = string | ProxyInfo;
20
- interface Options {
21
- caCerts?: string[];
22
- sni?: string;
23
- alpnProtocols?: string[];
24
- extraOptions?: NodeTlsUpgradeOptions["extraOptions"];
25
- }
26
- }
27
- export {};
package/dialers/proxy.js DELETED
@@ -1,55 +0,0 @@
1
- import { connectTcp, upgradeTls } from "../_internal/net.js";
2
- import { createProxyConnection, parse } from "@npy/proxy-kit";
3
- //#region src/dialers/proxy.ts
4
- var DEFAULT_HTTP_ALPN_PROTOCOLS = ["http/1.1"];
5
- function normalizeProxy(proxy) {
6
- if (typeof proxy !== "string") return proxy;
7
- const parsed = parse(proxy, { strict: true });
8
- if (parsed == null) throw new TypeError(`Invalid proxy string: ${proxy}`);
9
- return parsed;
10
- }
11
- /**
12
- * Dialer that routes connections through an HTTP, HTTPS or SOCKS proxy.
13
- *
14
- * @remarks
15
- * Secure targets are tunneled and then upgraded to TLS after the proxy connection
16
- * has been established.
17
- */
18
- var ProxyDialer = class {
19
- proxy;
20
- #options;
21
- #connectThroughProxy;
22
- constructor(proxy, options = {}) {
23
- this.proxy = normalizeProxy(proxy);
24
- this.#options = { ...options };
25
- this.#connectThroughProxy = createProxyConnection({
26
- proxy: this.proxy,
27
- connectionFn: connectTcp
28
- });
29
- }
30
- async dial(target, options = {}) {
31
- const tunneled = await this.#connectThroughProxy({
32
- address: target.address,
33
- port: target.port,
34
- signal: options.signal
35
- });
36
- if (!target.secure) return tunneled;
37
- return this.#upgradeSecureTarget(tunneled, target, options.signal);
38
- }
39
- async #upgradeSecureTarget(conn, target, signal) {
40
- const sni = target.sni ?? this.#options.sni ?? target.address;
41
- const extraOptions = this.#options.extraOptions || target.extraOptions ? {
42
- ...this.#options.extraOptions,
43
- ...target.extraOptions
44
- } : void 0;
45
- return upgradeTls(conn, {
46
- signal,
47
- caCerts: this.#options.caCerts,
48
- sni,
49
- alpnProtocols: target.alpnProtocols ?? this.#options.alpnProtocols ?? [...DEFAULT_HTTP_ALPN_PROTOCOLS],
50
- extraOptions
51
- });
52
- }
53
- };
54
- //#endregion
55
- export { ProxyDialer };