@npy/fetch 0.1.0 → 0.1.2

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 (102) hide show
  1. package/_internal/consts.cjs +4 -0
  2. package/_internal/consts.d.cts +3 -0
  3. package/_internal/consts.d.ts +3 -0
  4. package/_internal/consts.js +4 -0
  5. package/_internal/decode-stream-error.cjs +18 -0
  6. package/_internal/decode-stream-error.d.cts +11 -0
  7. package/_internal/decode-stream-error.d.ts +11 -0
  8. package/_internal/decode-stream-error.js +18 -0
  9. package/_internal/error-mapping.cjs +44 -0
  10. package/_internal/error-mapping.d.cts +15 -0
  11. package/_internal/error-mapping.d.ts +15 -0
  12. package/_internal/error-mapping.js +41 -0
  13. package/_internal/guards.cjs +23 -0
  14. package/_internal/guards.d.cts +15 -0
  15. package/_internal/guards.d.ts +15 -0
  16. package/_internal/guards.js +15 -0
  17. package/_internal/net.cjs +95 -0
  18. package/_internal/net.d.cts +11 -0
  19. package/_internal/net.d.ts +11 -0
  20. package/_internal/net.js +92 -0
  21. package/_internal/promises.cjs +18 -0
  22. package/_internal/promises.d.cts +1 -0
  23. package/_internal/promises.d.ts +1 -0
  24. package/_internal/promises.js +18 -0
  25. package/_internal/streams.cjs +37 -0
  26. package/_internal/streams.d.cts +21 -0
  27. package/_internal/streams.d.ts +21 -0
  28. package/_internal/streams.js +36 -0
  29. package/_internal/symbols.cjs +4 -0
  30. package/_internal/symbols.d.cts +1 -0
  31. package/_internal/symbols.d.ts +1 -0
  32. package/_internal/symbols.js +4 -0
  33. package/_virtual/_rolldown/runtime.cjs +23 -0
  34. package/agent-pool.cjs +96 -0
  35. package/agent-pool.d.cts +2 -0
  36. package/agent-pool.d.ts +2 -0
  37. package/agent-pool.js +95 -0
  38. package/agent.cjs +260 -0
  39. package/agent.d.cts +3 -0
  40. package/agent.d.ts +3 -0
  41. package/agent.js +259 -0
  42. package/body.cjs +105 -0
  43. package/body.d.cts +12 -0
  44. package/body.d.ts +12 -0
  45. package/body.js +102 -0
  46. package/dialers/index.d.cts +3 -0
  47. package/dialers/index.d.ts +3 -0
  48. package/dialers/proxy.cjs +56 -0
  49. package/dialers/proxy.d.cts +27 -0
  50. package/dialers/proxy.d.ts +27 -0
  51. package/dialers/proxy.js +55 -0
  52. package/dialers/tcp.cjs +92 -0
  53. package/dialers/tcp.d.cts +57 -0
  54. package/dialers/tcp.d.ts +57 -0
  55. package/dialers/tcp.js +89 -0
  56. package/encoding.cjs +114 -0
  57. package/encoding.d.cts +35 -0
  58. package/encoding.d.ts +35 -0
  59. package/encoding.js +110 -0
  60. package/errors.cjs +275 -0
  61. package/errors.d.cts +110 -0
  62. package/errors.d.ts +110 -0
  63. package/errors.js +259 -0
  64. package/fetch.cjs +353 -0
  65. package/fetch.d.cts +58 -0
  66. package/fetch.d.ts +58 -0
  67. package/fetch.js +350 -0
  68. package/http-client.cjs +75 -0
  69. package/http-client.d.cts +39 -0
  70. package/http-client.d.ts +39 -0
  71. package/http-client.js +75 -0
  72. package/index.cjs +49 -0
  73. package/index.d.cts +14 -0
  74. package/index.d.ts +14 -0
  75. package/index.js +11 -0
  76. package/io/_utils.cjs +56 -0
  77. package/io/_utils.d.cts +10 -0
  78. package/io/_utils.d.ts +10 -0
  79. package/io/_utils.js +51 -0
  80. package/io/buf-writer.cjs +149 -0
  81. package/io/buf-writer.d.cts +13 -0
  82. package/io/buf-writer.d.ts +13 -0
  83. package/io/buf-writer.js +148 -0
  84. package/io/io.cjs +199 -0
  85. package/io/io.d.cts +5 -0
  86. package/io/io.d.ts +5 -0
  87. package/io/io.js +198 -0
  88. package/io/readers.cjs +337 -0
  89. package/io/readers.d.cts +69 -0
  90. package/io/readers.d.ts +69 -0
  91. package/io/readers.js +333 -0
  92. package/io/writers.cjs +196 -0
  93. package/io/writers.d.cts +22 -0
  94. package/io/writers.d.ts +22 -0
  95. package/io/writers.js +195 -0
  96. package/package.json +23 -10
  97. package/types/agent.d.cts +72 -0
  98. package/types/agent.d.ts +72 -0
  99. package/types/dialer.d.cts +30 -0
  100. package/types/dialer.d.ts +30 -0
  101. package/types/index.d.cts +2 -0
  102. package/types/index.d.ts +2 -0
@@ -0,0 +1,36 @@
1
+ //#region src/_internal/streams.ts
2
+ /**
3
+ * Create a ReadableStream from a Uint8Array.
4
+ *
5
+ * The stream will emit the entire byte array as a single chunk,
6
+ * then close immediately.
7
+ *
8
+ * @param bytes - The byte array to wrap.
9
+ * @returns A ReadableStream that emits the bytes.
10
+ */
11
+ function bytesToStream(bytes) {
12
+ return new ReadableStream({ start(controller) {
13
+ controller.enqueue(bytes);
14
+ controller.close();
15
+ } });
16
+ }
17
+ /**
18
+ * A TransformStream that limits the total number of bytes passed through.
19
+ *
20
+ * It accumulates the byte count from incoming chunks and enqueues them
21
+ * if the total remains within the limit; otherwise, it errors.
22
+ *
23
+ * @param maxBytes - The maximum allowed bytes before erroring.
24
+ */
25
+ var MaxBytesTransformStream = class extends TransformStream {
26
+ constructor(maxBytes) {
27
+ if (!(maxBytes >= 0)) throw new TypeError("maxBytes must be a non-negative number");
28
+ let bytesRead = 0;
29
+ super({ transform: (chunk, ctrl) => {
30
+ if ((bytesRead += chunk.length) <= maxBytes) ctrl.enqueue(chunk);
31
+ else ctrl.error(/* @__PURE__ */ new Error("Response too large"));
32
+ } });
33
+ }
34
+ };
35
+ //#endregion
36
+ export { MaxBytesTransformStream, bytesToStream };
@@ -0,0 +1,4 @@
1
+ //#region src/_internal/symbols.ts
2
+ var bodyErrorMapperSymbol = Symbol("fetch.bodyErrorMapper");
3
+ //#endregion
4
+ exports.bodyErrorMapperSymbol = bodyErrorMapperSymbol;
@@ -0,0 +1 @@
1
+ export declare const bodyErrorMapperSymbol: unique symbol;
@@ -0,0 +1 @@
1
+ export declare const bodyErrorMapperSymbol: unique symbol;
@@ -0,0 +1,4 @@
1
+ //#region src/_internal/symbols.ts
2
+ var bodyErrorMapperSymbol = Symbol("fetch.bodyErrorMapper");
3
+ //#endregion
4
+ export { bodyErrorMapperSymbol };
@@ -0,0 +1,23 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+ //#endregion
23
+ exports.__toESM = __toESM;
package/agent-pool.cjs ADDED
@@ -0,0 +1,96 @@
1
+ require("./_virtual/_rolldown/runtime.cjs");
2
+ const require_errors = require("./errors.cjs");
3
+ const require_agent = require("./agent.cjs");
4
+ const require_tcp = require("./dialers/tcp.cjs");
5
+ let generic_pool = require("generic-pool");
6
+ //#region src/agent-pool.ts
7
+ var defaultEvictionInterval = 1e4;
8
+ var defaultMax = Number.MAX_SAFE_INTEGER;
9
+ var defaultIdleTimeout = 3e4;
10
+ function createAgentPool(baseUrl, options = {}) {
11
+ const poolUrl = new URL(baseUrl);
12
+ const evictionRunIntervalMillis = options.poolIdleTimeout !== false ? Math.min(options.poolIdleTimeout || defaultEvictionInterval, defaultEvictionInterval) : 0;
13
+ const max = options.poolMaxPerHost ? Math.max(1, options.poolMaxPerHost) : defaultMax;
14
+ const softIdleTimeoutMillis = options.poolIdleTimeout !== false ? Math.max(1, options.poolIdleTimeout || defaultIdleTimeout) : -1;
15
+ const min = softIdleTimeoutMillis > 0 && options.poolMaxIdlePerHost ? Math.max(0, options.poolMaxIdlePerHost) : 0;
16
+ if (poolUrl.protocol !== "http:" && poolUrl.protocol !== "https:") throw new require_errors.UnsupportedProtocolError(poolUrl.protocol, {
17
+ origin: poolUrl.origin,
18
+ scheme: poolUrl.protocol,
19
+ host: poolUrl.hostname,
20
+ port: poolUrl.port ? Number.parseInt(poolUrl.port, 10) : void 0
21
+ });
22
+ const dialer = options.dialer ?? new require_tcp.AutoDialer();
23
+ const connectOptions = options.connect ?? {};
24
+ const ioOptions = options.io;
25
+ const pool = (0, generic_pool.createPool)({
26
+ async create() {
27
+ return require_agent.createAgent(dialer, baseUrl, {
28
+ connect: connectOptions,
29
+ io: ioOptions
30
+ });
31
+ },
32
+ async destroy(agent) {
33
+ agent.close();
34
+ }
35
+ }, {
36
+ autostart: false,
37
+ evictionRunIntervalMillis,
38
+ softIdleTimeoutMillis,
39
+ max,
40
+ min
41
+ });
42
+ let releaseAgentFns = [];
43
+ let closePromise;
44
+ async function send(sendOptions) {
45
+ let agent;
46
+ let agentReleased = false;
47
+ const releaseAgentFn = async (forceClose = false) => {
48
+ if (!agent || agentReleased) return;
49
+ agentReleased = true;
50
+ releaseAgentFns = releaseAgentFns.filter((release) => release !== releaseAgentFn);
51
+ if (forceClose) agent.close();
52
+ if (pool.isBorrowedResource(agent)) await pool.release(agent);
53
+ };
54
+ releaseAgentFns.push(releaseAgentFn);
55
+ try {
56
+ agent = await pool.acquire();
57
+ const responsePromise = agent.send(sendOptions);
58
+ agent.whenIdle().then(() => releaseAgentFn(), () => releaseAgentFn(true));
59
+ return responsePromise;
60
+ } catch (error) {
61
+ await releaseAgentFn(true);
62
+ throw error;
63
+ }
64
+ }
65
+ async function close() {
66
+ if (closePromise) return closePromise;
67
+ const promise = (async () => {
68
+ const pendingReleases = releaseAgentFns;
69
+ releaseAgentFns = [];
70
+ const errors = (await Promise.allSettled([...pendingReleases.map((release) => release(true)), (async () => {
71
+ try {
72
+ await pool.drain();
73
+ } finally {
74
+ await pool.clear();
75
+ }
76
+ })()])).flatMap((result) => result.status === "rejected" ? [result.reason] : []);
77
+ if (errors.length === 1) throw errors[0];
78
+ if (errors.length > 1) throw new AggregateError(errors, "Failed to close agent pool cleanly");
79
+ })();
80
+ closePromise = promise;
81
+ try {
82
+ await promise;
83
+ } finally {
84
+ if (closePromise === promise) closePromise = void 0;
85
+ }
86
+ }
87
+ return {
88
+ [Symbol.asyncDispose]: close,
89
+ close,
90
+ hostname: poolUrl.hostname,
91
+ port: poolUrl.port ? Number.parseInt(poolUrl.port, 10) : poolUrl.protocol === "https:" ? 443 : 80,
92
+ send
93
+ };
94
+ }
95
+ //#endregion
96
+ exports.createAgentPool = createAgentPool;
@@ -0,0 +1,2 @@
1
+ import { AgentPool } from './types/agent';
2
+ export declare function createAgentPool(baseUrl: string, options?: AgentPool.Options): AgentPool;
@@ -0,0 +1,2 @@
1
+ import { AgentPool } from './types/agent';
2
+ export declare function createAgentPool(baseUrl: string, options?: AgentPool.Options): AgentPool;
package/agent-pool.js ADDED
@@ -0,0 +1,95 @@
1
+ import { UnsupportedProtocolError } from "./errors.js";
2
+ import { createAgent } from "./agent.js";
3
+ import { AutoDialer } from "./dialers/tcp.js";
4
+ import { createPool } from "generic-pool";
5
+ //#region src/agent-pool.ts
6
+ var defaultEvictionInterval = 1e4;
7
+ var defaultMax = Number.MAX_SAFE_INTEGER;
8
+ var defaultIdleTimeout = 3e4;
9
+ function createAgentPool(baseUrl, options = {}) {
10
+ const poolUrl = new URL(baseUrl);
11
+ const evictionRunIntervalMillis = options.poolIdleTimeout !== false ? Math.min(options.poolIdleTimeout || defaultEvictionInterval, defaultEvictionInterval) : 0;
12
+ const max = options.poolMaxPerHost ? Math.max(1, options.poolMaxPerHost) : defaultMax;
13
+ const softIdleTimeoutMillis = options.poolIdleTimeout !== false ? Math.max(1, options.poolIdleTimeout || defaultIdleTimeout) : -1;
14
+ const min = softIdleTimeoutMillis > 0 && options.poolMaxIdlePerHost ? Math.max(0, options.poolMaxIdlePerHost) : 0;
15
+ if (poolUrl.protocol !== "http:" && poolUrl.protocol !== "https:") throw new UnsupportedProtocolError(poolUrl.protocol, {
16
+ origin: poolUrl.origin,
17
+ scheme: poolUrl.protocol,
18
+ host: poolUrl.hostname,
19
+ port: poolUrl.port ? Number.parseInt(poolUrl.port, 10) : void 0
20
+ });
21
+ const dialer = options.dialer ?? new AutoDialer();
22
+ const connectOptions = options.connect ?? {};
23
+ const ioOptions = options.io;
24
+ const pool = createPool({
25
+ async create() {
26
+ return createAgent(dialer, baseUrl, {
27
+ connect: connectOptions,
28
+ io: ioOptions
29
+ });
30
+ },
31
+ async destroy(agent) {
32
+ agent.close();
33
+ }
34
+ }, {
35
+ autostart: false,
36
+ evictionRunIntervalMillis,
37
+ softIdleTimeoutMillis,
38
+ max,
39
+ min
40
+ });
41
+ let releaseAgentFns = [];
42
+ let closePromise;
43
+ async function send(sendOptions) {
44
+ let agent;
45
+ let agentReleased = false;
46
+ const releaseAgentFn = async (forceClose = false) => {
47
+ if (!agent || agentReleased) return;
48
+ agentReleased = true;
49
+ releaseAgentFns = releaseAgentFns.filter((release) => release !== releaseAgentFn);
50
+ if (forceClose) agent.close();
51
+ if (pool.isBorrowedResource(agent)) await pool.release(agent);
52
+ };
53
+ releaseAgentFns.push(releaseAgentFn);
54
+ try {
55
+ agent = await pool.acquire();
56
+ const responsePromise = agent.send(sendOptions);
57
+ agent.whenIdle().then(() => releaseAgentFn(), () => releaseAgentFn(true));
58
+ return responsePromise;
59
+ } catch (error) {
60
+ await releaseAgentFn(true);
61
+ throw error;
62
+ }
63
+ }
64
+ async function close() {
65
+ if (closePromise) return closePromise;
66
+ const promise = (async () => {
67
+ const pendingReleases = releaseAgentFns;
68
+ releaseAgentFns = [];
69
+ const errors = (await Promise.allSettled([...pendingReleases.map((release) => release(true)), (async () => {
70
+ try {
71
+ await pool.drain();
72
+ } finally {
73
+ await pool.clear();
74
+ }
75
+ })()])).flatMap((result) => result.status === "rejected" ? [result.reason] : []);
76
+ if (errors.length === 1) throw errors[0];
77
+ if (errors.length > 1) throw new AggregateError(errors, "Failed to close agent pool cleanly");
78
+ })();
79
+ closePromise = promise;
80
+ try {
81
+ await promise;
82
+ } finally {
83
+ if (closePromise === promise) closePromise = void 0;
84
+ }
85
+ }
86
+ return {
87
+ [Symbol.asyncDispose]: close,
88
+ close,
89
+ hostname: poolUrl.hostname,
90
+ port: poolUrl.port ? Number.parseInt(poolUrl.port, 10) : poolUrl.protocol === "https:" ? 443 : 80,
91
+ send
92
+ };
93
+ }
94
+ //#endregion
95
+ export { createAgentPool };
package/agent.cjs ADDED
@@ -0,0 +1,260 @@
1
+ require("./_virtual/_rolldown/runtime.cjs");
2
+ const require_errors = require("./errors.cjs");
3
+ const require_error_mapping = require("./_internal/error-mapping.cjs");
4
+ const require_promises = require("./_internal/promises.cjs");
5
+ const require_symbols = require("./_internal/symbols.cjs");
6
+ const require_io = require("./io/io.cjs");
7
+ let _fuman_utils = require("@fuman/utils");
8
+ //#region src/agent.ts
9
+ var PORT_MAP = {
10
+ "http:": 80,
11
+ "https:": 443
12
+ };
13
+ var DEFAULT_ALPN_PROTOCOLS = ["http/1.1"];
14
+ function resolvedDeferred() {
15
+ const deferred = new _fuman_utils.Deferred();
16
+ deferred.resolve();
17
+ return deferred;
18
+ }
19
+ function withSignal(promise, signal) {
20
+ return signal ? require_promises.raceSignal(promise, signal) : promise;
21
+ }
22
+ function isTlsConnection(conn) {
23
+ return "getAlpnProtocol" in conn && typeof conn.getAlpnProtocol === "function";
24
+ }
25
+ function createAgent(dialer, baseUrl, options = {}) {
26
+ const base = new URL(baseUrl);
27
+ if (base.protocol !== "http:" && base.protocol !== "https:") throw new require_errors.UnsupportedProtocolError(base.protocol, {
28
+ origin: base.origin,
29
+ scheme: base.protocol,
30
+ host: base.hostname,
31
+ port: base.port ? Number.parseInt(base.port, 10) : void 0,
32
+ url: base.toString()
33
+ });
34
+ const secure = base.protocol === "https:";
35
+ const hostname = base.hostname;
36
+ const port = base.port ? Number.parseInt(base.port, 10) : PORT_MAP[base.protocol];
37
+ if (!Number.isFinite(port) || port <= 0 || port > 65535) throw new TypeError(`Invalid port in base URL: ${baseUrl}`);
38
+ const target = {
39
+ address: hostname,
40
+ port,
41
+ secure,
42
+ sni: secure ? hostname : void 0,
43
+ alpnProtocols: secure ? [...DEFAULT_ALPN_PROTOCOLS] : void 0
44
+ };
45
+ const connectOptions = options.connect ?? {};
46
+ const readerOptions = options.io?.reader ?? {};
47
+ const writerOptions = options.io?.writer ?? {};
48
+ let conn;
49
+ let connectPromise;
50
+ let closed = false;
51
+ let isBusy = false;
52
+ let lastUsedTime = Date.now();
53
+ let idleDeferred = resolvedDeferred();
54
+ function createBaseErrorContext() {
55
+ return {
56
+ origin: base.origin,
57
+ scheme: base.protocol,
58
+ host: hostname,
59
+ port
60
+ };
61
+ }
62
+ function createRequestErrorContext(url, method) {
63
+ return {
64
+ ...createBaseErrorContext(),
65
+ url: url.toString(),
66
+ method
67
+ };
68
+ }
69
+ function markIdle() {
70
+ isBusy = false;
71
+ lastUsedTime = Date.now();
72
+ idleDeferred.resolve();
73
+ }
74
+ function disposeConn() {
75
+ const current = conn;
76
+ conn = void 0;
77
+ if (!current) return;
78
+ try {
79
+ current.close();
80
+ } catch {}
81
+ }
82
+ function forceClose() {
83
+ if (closed) return;
84
+ closed = true;
85
+ disposeConn();
86
+ if (!isBusy) markIdle();
87
+ }
88
+ function assertUsable() {
89
+ if (closed) throw new require_errors.AgentClosedError(createBaseErrorContext());
90
+ }
91
+ function assertSameOrigin(url) {
92
+ if (url.origin !== base.origin) throw new require_errors.OriginMismatchError(base.origin, url.origin, {
93
+ ...createBaseErrorContext(),
94
+ url: url.toString()
95
+ });
96
+ }
97
+ function configureConnection(nextConn) {
98
+ nextConn.setNoDelay(connectOptions.noDelay ?? true);
99
+ if (connectOptions.keepAlive !== null) nextConn.setKeepAlive(connectOptions.keepAlive ?? true);
100
+ }
101
+ async function connect(signal) {
102
+ assertUsable();
103
+ if (conn) return conn;
104
+ if (connectPromise) return withSignal(connectPromise, signal);
105
+ let timedOut = false;
106
+ let timeoutId;
107
+ const abortController = new AbortController();
108
+ const onAbort = () => abortController.abort(signal?.reason);
109
+ const cleanup = () => {
110
+ if (timeoutId !== void 0) {
111
+ clearTimeout(timeoutId);
112
+ timeoutId = void 0;
113
+ }
114
+ if (signal) signal.removeEventListener("abort", onAbort);
115
+ };
116
+ if (signal) if (signal.aborted) abortController.abort(signal.reason);
117
+ else signal.addEventListener("abort", onAbort, { once: true });
118
+ if (connectOptions.timeout != null && Number.isFinite(connectOptions.timeout) && connectOptions.timeout > 0) timeoutId = setTimeout(() => {
119
+ timedOut = true;
120
+ abortController.abort(new DOMException("Connection timed out", "TimeoutError"));
121
+ }, connectOptions.timeout);
122
+ connectPromise = (async () => {
123
+ try {
124
+ const nextConn = await dialer.dial(target, { signal: abortController.signal });
125
+ if (closed) {
126
+ try {
127
+ nextConn.close();
128
+ } catch {}
129
+ throw new require_errors.AgentClosedError(createBaseErrorContext());
130
+ }
131
+ configureConnection(nextConn);
132
+ if (secure && isTlsConnection(nextConn)) {
133
+ const alpn = nextConn.getAlpnProtocol();
134
+ if (alpn != null && alpn !== "" && alpn !== "http/1.1") {
135
+ try {
136
+ nextConn.close();
137
+ } catch {}
138
+ throw new require_errors.UnsupportedAlpnProtocolError(alpn, createBaseErrorContext());
139
+ }
140
+ }
141
+ conn = nextConn;
142
+ return nextConn;
143
+ } catch (error) {
144
+ throw require_error_mapping.toConnectError(error, {
145
+ signal,
146
+ timedOut,
147
+ context: createBaseErrorContext()
148
+ });
149
+ } finally {
150
+ cleanup();
151
+ connectPromise = void 0;
152
+ }
153
+ })();
154
+ return withSignal(connectPromise, signal);
155
+ }
156
+ async function executeRequest(sendOptions, mapBodyError) {
157
+ assertUsable();
158
+ const url = typeof sendOptions.url === "string" ? new URL(sendOptions.url) : sendOptions.url;
159
+ const method = sendOptions.method.toUpperCase();
160
+ const errorContext = createRequestErrorContext(url, method);
161
+ if (sendOptions.signal?.aborted) throw new require_errors.RequestAbortedError(sendOptions.signal.reason, errorContext);
162
+ if (isBusy) throw new require_errors.AgentBusyError(errorContext);
163
+ assertSameOrigin(url);
164
+ if (method === "CONNECT") throw new require_errors.UnsupportedMethodError("CONNECT", errorContext);
165
+ isBusy = true;
166
+ idleDeferred = new _fuman_utils.Deferred();
167
+ let finalized = false;
168
+ let activeConn;
169
+ const finalize = (reusable) => {
170
+ if (finalized) return;
171
+ finalized = true;
172
+ if (!reusable || closed) {
173
+ if (conn === activeConn) disposeConn();
174
+ else if (activeConn) try {
175
+ activeConn.close();
176
+ } catch {}
177
+ }
178
+ markIdle();
179
+ };
180
+ const abortListener = () => {
181
+ if (activeConn) {
182
+ if (conn === activeConn) conn = void 0;
183
+ try {
184
+ activeConn.close();
185
+ } catch {}
186
+ }
187
+ };
188
+ try {
189
+ activeConn = await connect(sendOptions.signal);
190
+ sendOptions.signal?.addEventListener("abort", abortListener, { once: true });
191
+ try {
192
+ await withSignal(require_io.writeRequest(activeConn, {
193
+ url,
194
+ method,
195
+ headers: sendOptions.headers,
196
+ body: sendOptions.body ?? null,
197
+ signal: sendOptions.signal
198
+ }, writerOptions), sendOptions.signal);
199
+ } catch (error) {
200
+ throw require_error_mapping.toSendError(error, {
201
+ signal: sendOptions.signal,
202
+ context: errorContext,
203
+ phase: "request"
204
+ });
205
+ }
206
+ const isHeadRequest = method === "HEAD";
207
+ const shouldIgnoreBody = (status) => isHeadRequest || status >= 100 && status < 200 || status === 204 || status === 304;
208
+ let response;
209
+ try {
210
+ response = await withSignal(require_io.readResponse(activeConn, readerOptions, shouldIgnoreBody, (reusable) => {
211
+ sendOptions.signal?.removeEventListener("abort", abortListener);
212
+ finalize(reusable);
213
+ }, mapBodyError), sendOptions.signal);
214
+ } catch (error) {
215
+ throw require_error_mapping.toSendError(error, {
216
+ signal: sendOptions.signal,
217
+ context: errorContext,
218
+ phase: "response"
219
+ });
220
+ }
221
+ return response;
222
+ } catch (error) {
223
+ sendOptions.signal?.removeEventListener("abort", abortListener);
224
+ if (activeConn) {
225
+ if (conn === activeConn) conn = void 0;
226
+ try {
227
+ activeConn.close();
228
+ } catch {}
229
+ }
230
+ finalize(false);
231
+ throw error;
232
+ }
233
+ }
234
+ async function send(sendOptions) {
235
+ const errorContext = createRequestErrorContext(typeof sendOptions.url === "string" ? new URL(sendOptions.url) : sendOptions.url, sendOptions.method.toUpperCase());
236
+ return executeRequest(sendOptions, sendOptions[require_symbols.bodyErrorMapperSymbol] ?? ((error) => require_error_mapping.toSendError(error, {
237
+ signal: sendOptions.signal,
238
+ context: errorContext,
239
+ phase: "body"
240
+ })));
241
+ }
242
+ return {
243
+ [Symbol.dispose]: forceClose,
244
+ close: forceClose,
245
+ hostname,
246
+ port,
247
+ send,
248
+ whenIdle() {
249
+ return idleDeferred.promise;
250
+ },
251
+ get isIdle() {
252
+ return !isBusy;
253
+ },
254
+ get lastUsed() {
255
+ return lastUsedTime;
256
+ }
257
+ };
258
+ }
259
+ //#endregion
260
+ exports.createAgent = createAgent;
package/agent.d.cts ADDED
@@ -0,0 +1,3 @@
1
+ import { Agent } from './types/agent';
2
+ import { Dialer } from './types/dialer';
3
+ export declare function createAgent(dialer: Dialer, baseUrl: string, options?: Agent.Options): Agent;
package/agent.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { Agent } from './types/agent';
2
+ import { Dialer } from './types/dialer';
3
+ export declare function createAgent(dialer: Dialer, baseUrl: string, options?: Agent.Options): Agent;