@npy/fetch 0.1.1 → 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 (109) hide show
  1. package/_internal/decode-stream-error.cjs +18 -0
  2. package/_internal/decode-stream-error.d.cts +11 -0
  3. package/_internal/decode-stream-error.d.ts +11 -0
  4. package/_internal/decode-stream-error.js +18 -0
  5. package/_internal/error-mapping.cjs +44 -0
  6. package/_internal/error-mapping.d.cts +15 -0
  7. package/_internal/error-mapping.d.ts +15 -0
  8. package/_internal/error-mapping.js +41 -0
  9. package/_internal/guards.cjs +5 -6
  10. package/{src/_internal → _internal}/guards.d.cts +2 -0
  11. package/{src/_internal → _internal}/guards.d.ts +2 -0
  12. package/_internal/guards.js +5 -7
  13. package/{src/_internal → _internal}/net.d.cts +1 -2
  14. package/{src/_internal → _internal}/net.d.ts +1 -2
  15. package/_internal/symbols.cjs +4 -0
  16. package/_internal/symbols.d.cts +1 -0
  17. package/_internal/symbols.d.ts +1 -0
  18. package/_internal/symbols.js +4 -0
  19. package/agent-pool.cjs +23 -5
  20. package/agent-pool.d.cts +2 -0
  21. package/agent-pool.d.ts +2 -0
  22. package/agent-pool.js +23 -5
  23. package/agent.cjs +17 -14
  24. package/agent.js +17 -14
  25. package/body.cjs +10 -59
  26. package/body.d.cts +12 -0
  27. package/body.d.ts +12 -0
  28. package/body.js +11 -60
  29. package/dialers/proxy.cjs +7 -0
  30. package/{src/dialers → dialers}/proxy.d.cts +11 -3
  31. package/{src/dialers → dialers}/proxy.d.ts +11 -3
  32. package/dialers/proxy.js +7 -0
  33. package/dialers/tcp.cjs +22 -0
  34. package/{src/dialers → dialers}/tcp.d.cts +23 -2
  35. package/{src/dialers → dialers}/tcp.d.ts +23 -2
  36. package/dialers/tcp.js +22 -0
  37. package/encoding.cjs +32 -13
  38. package/encoding.d.cts +35 -0
  39. package/encoding.d.ts +35 -0
  40. package/encoding.js +32 -13
  41. package/fetch.cjs +279 -43
  42. package/fetch.d.cts +58 -0
  43. package/fetch.d.ts +58 -0
  44. package/fetch.js +278 -43
  45. package/http-client.cjs +47 -5
  46. package/http-client.d.cts +39 -0
  47. package/http-client.d.ts +39 -0
  48. package/http-client.js +47 -5
  49. package/index.cjs +7 -3
  50. package/index.d.cts +14 -1
  51. package/index.d.ts +14 -1
  52. package/index.js +6 -4
  53. package/io/io.cjs +68 -4
  54. package/{src/io → io}/io.d.cts +1 -1
  55. package/{src/io → io}/io.d.ts +1 -1
  56. package/io/io.js +68 -4
  57. package/io/readers.cjs +14 -54
  58. package/io/readers.d.cts +69 -0
  59. package/io/readers.d.ts +69 -0
  60. package/io/readers.js +14 -54
  61. package/io/writers.cjs +10 -5
  62. package/{src/io → io}/writers.d.cts +1 -1
  63. package/{src/io → io}/writers.d.ts +1 -1
  64. package/io/writers.js +11 -6
  65. package/package.json +18 -2
  66. package/types/agent.d.cts +72 -0
  67. package/types/agent.d.ts +72 -0
  68. package/{src/types → types}/dialer.d.cts +3 -0
  69. package/{src/types → types}/dialer.d.ts +3 -0
  70. package/_internal/error-adapters.cjs +0 -146
  71. package/_internal/error-adapters.js +0 -142
  72. package/src/_internal/error-adapters.d.cts +0 -22
  73. package/src/_internal/error-adapters.d.ts +0 -22
  74. package/src/agent-pool.d.cts +0 -2
  75. package/src/agent-pool.d.ts +0 -2
  76. package/src/body.d.cts +0 -23
  77. package/src/body.d.ts +0 -23
  78. package/src/encoding.d.cts +0 -24
  79. package/src/encoding.d.ts +0 -24
  80. package/src/fetch.d.cts +0 -36
  81. package/src/fetch.d.ts +0 -36
  82. package/src/http-client.d.cts +0 -23
  83. package/src/http-client.d.ts +0 -23
  84. package/src/index.d.cts +0 -7
  85. package/src/index.d.ts +0 -7
  86. package/src/io/readers.d.cts +0 -199
  87. package/src/io/readers.d.ts +0 -199
  88. package/src/types/agent.d.cts +0 -128
  89. package/src/types/agent.d.ts +0 -128
  90. package/tests/test-utils.d.cts +0 -8
  91. package/tests/test-utils.d.ts +0 -8
  92. /package/{src/_internal → _internal}/consts.d.cts +0 -0
  93. /package/{src/_internal → _internal}/consts.d.ts +0 -0
  94. /package/{src/_internal → _internal}/promises.d.cts +0 -0
  95. /package/{src/_internal → _internal}/promises.d.ts +0 -0
  96. /package/{src/_internal → _internal}/streams.d.cts +0 -0
  97. /package/{src/_internal → _internal}/streams.d.ts +0 -0
  98. /package/{src/agent.d.cts → agent.d.cts} +0 -0
  99. /package/{src/agent.d.ts → agent.d.ts} +0 -0
  100. /package/{src/dialers → dialers}/index.d.cts +0 -0
  101. /package/{src/dialers → dialers}/index.d.ts +0 -0
  102. /package/{src/errors.d.cts → errors.d.cts} +0 -0
  103. /package/{src/errors.d.ts → errors.d.ts} +0 -0
  104. /package/{src/io → io}/_utils.d.cts +0 -0
  105. /package/{src/io → io}/_utils.d.ts +0 -0
  106. /package/{src/io → io}/buf-writer.d.cts +0 -0
  107. /package/{src/io → io}/buf-writer.d.ts +0 -0
  108. /package/{src/types → types}/index.d.cts +0 -0
  109. /package/{src/types → types}/index.d.ts +0 -0
@@ -0,0 +1,18 @@
1
+ //#region src/_internal/decode-stream-error.ts
2
+ /**
3
+ * Internal sentinel thrown when a decompression stream fails.
4
+ *
5
+ * Tagged at the source (inside createDecoder) so that error classifiers
6
+ * can use `instanceof` instead of heuristics on error messages or codes.
7
+ * Never exposed in the public API — callers receive ResponseDecodeError.
8
+ */
9
+ var DecodeStreamError = class extends Error {
10
+ cause;
11
+ constructor(cause) {
12
+ super("Response decode failed", { cause });
13
+ this.name = "DecodeStreamError";
14
+ this.cause = cause;
15
+ }
16
+ };
17
+ //#endregion
18
+ exports.DecodeStreamError = DecodeStreamError;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Internal sentinel thrown when a decompression stream fails.
3
+ *
4
+ * Tagged at the source (inside createDecoder) so that error classifiers
5
+ * can use `instanceof` instead of heuristics on error messages or codes.
6
+ * Never exposed in the public API — callers receive ResponseDecodeError.
7
+ */
8
+ export declare class DecodeStreamError extends Error {
9
+ readonly cause: unknown;
10
+ constructor(cause: unknown);
11
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Internal sentinel thrown when a decompression stream fails.
3
+ *
4
+ * Tagged at the source (inside createDecoder) so that error classifiers
5
+ * can use `instanceof` instead of heuristics on error messages or codes.
6
+ * Never exposed in the public API — callers receive ResponseDecodeError.
7
+ */
8
+ export declare class DecodeStreamError extends Error {
9
+ readonly cause: unknown;
10
+ constructor(cause: unknown);
11
+ }
@@ -0,0 +1,18 @@
1
+ //#region src/_internal/decode-stream-error.ts
2
+ /**
3
+ * Internal sentinel thrown when a decompression stream fails.
4
+ *
5
+ * Tagged at the source (inside createDecoder) so that error classifiers
6
+ * can use `instanceof` instead of heuristics on error messages or codes.
7
+ * Never exposed in the public API — callers receive ResponseDecodeError.
8
+ */
9
+ var DecodeStreamError = class extends Error {
10
+ cause;
11
+ constructor(cause) {
12
+ super("Response decode failed", { cause });
13
+ this.name = "DecodeStreamError";
14
+ this.cause = cause;
15
+ }
16
+ };
17
+ //#endregion
18
+ export { DecodeStreamError };
@@ -0,0 +1,44 @@
1
+ const require_decode_stream_error = require("./decode-stream-error.cjs");
2
+ const require_errors = require("../errors.cjs");
3
+ //#region src/_internal/error-mapping.ts
4
+ /** Casts or converts the unknown into an Error */
5
+ function unknownToError(err) {
6
+ if (err instanceof Error) return err;
7
+ if (typeof err === "string") return new Error(err);
8
+ return new Error("unknown error", { cause: err });
9
+ }
10
+ function isAbortOrTimeoutError(error) {
11
+ if (!error || typeof error !== "object") return false;
12
+ const name = String(error.name ?? "");
13
+ return name === "AbortError" || name === "TimeoutError";
14
+ }
15
+ function toConnectError(error, { signal, context, timedOut }) {
16
+ if (error instanceof require_errors.FetchError) return error;
17
+ if (timedOut || signal?.reason?.name === "TimeoutError") return new require_errors.ConnectTimeoutError(unknownToError(error), context, "Connection timeout");
18
+ if (signal?.aborted || isAbortOrTimeoutError(error)) return new require_errors.RequestAbortedError(unknownToError(signal?.reason ?? error ?? new DOMException("This operation was aborted", "AbortError")), context, "The request was aborted while connecting");
19
+ return new require_errors.ConnectionError(unknownToError(error), context, "Connection failed");
20
+ }
21
+ function toSendError(error, { signal, context, phase }) {
22
+ if (error instanceof require_errors.FetchError) return error;
23
+ if (signal?.aborted || isAbortOrTimeoutError(error)) return new require_errors.RequestAbortedError(unknownToError(signal?.reason ?? error ?? new DOMException("This operation was aborted", "AbortError")), context, phase === "body" ? "The request was aborted while reading the response body" : "The request was aborted");
24
+ const cause = unknownToError(error);
25
+ if (phase === "request") return new require_errors.RequestWriteError(cause, context);
26
+ if (phase === "response") return new require_errors.ResponseHeaderError(cause, context);
27
+ if (error instanceof require_decode_stream_error.DecodeStreamError) return new require_errors.ResponseDecodeError(unknownToError(error.cause), context);
28
+ return new require_errors.ResponseBodyError(cause, context);
29
+ }
30
+ function toWebFetchError(error, signal) {
31
+ if (signal?.aborted) return signal.reason ?? new DOMException("This operation was aborted", "AbortError");
32
+ if (error instanceof DOMException || error instanceof TypeError) return error;
33
+ return new TypeError("fetch failed", { cause: unknownToError(error) });
34
+ }
35
+ function toWebBodyReadError(error, signal) {
36
+ if (signal?.aborted) return signal.reason ?? new DOMException("This operation was aborted", "AbortError");
37
+ if (error instanceof DOMException || error instanceof TypeError || error instanceof RangeError) return error;
38
+ return new TypeError("Failed to read response body", { cause: unknownToError(error) });
39
+ }
40
+ //#endregion
41
+ exports.toConnectError = toConnectError;
42
+ exports.toSendError = toSendError;
43
+ exports.toWebBodyReadError = toWebBodyReadError;
44
+ exports.toWebFetchError = toWebFetchError;
@@ -0,0 +1,15 @@
1
+ import { FetchError, FetchErrorContext } from '../errors';
2
+ /** Casts or converts the unknown into an Error */
3
+ export declare function unknownToError(err: unknown): Error;
4
+ export declare function toConnectError(error: unknown, { signal, context, timedOut, }: {
5
+ signal?: AbortSignal;
6
+ context?: FetchErrorContext;
7
+ timedOut?: boolean;
8
+ }): FetchError;
9
+ export declare function toSendError(error: unknown, { signal, context, phase, }: {
10
+ signal?: AbortSignal;
11
+ context?: FetchErrorContext;
12
+ phase: "request" | "response" | "body";
13
+ }): FetchError;
14
+ export declare function toWebFetchError(error: unknown, signal?: AbortSignal): unknown;
15
+ export declare function toWebBodyReadError(error: unknown, signal?: AbortSignal): unknown;
@@ -0,0 +1,15 @@
1
+ import { FetchError, FetchErrorContext } from '../errors';
2
+ /** Casts or converts the unknown into an Error */
3
+ export declare function unknownToError(err: unknown): Error;
4
+ export declare function toConnectError(error: unknown, { signal, context, timedOut, }: {
5
+ signal?: AbortSignal;
6
+ context?: FetchErrorContext;
7
+ timedOut?: boolean;
8
+ }): FetchError;
9
+ export declare function toSendError(error: unknown, { signal, context, phase, }: {
10
+ signal?: AbortSignal;
11
+ context?: FetchErrorContext;
12
+ phase: "request" | "response" | "body";
13
+ }): FetchError;
14
+ export declare function toWebFetchError(error: unknown, signal?: AbortSignal): unknown;
15
+ export declare function toWebBodyReadError(error: unknown, signal?: AbortSignal): unknown;
@@ -0,0 +1,41 @@
1
+ import { DecodeStreamError } from "./decode-stream-error.js";
2
+ import { ConnectTimeoutError, ConnectionError, FetchError, RequestAbortedError, RequestWriteError, ResponseBodyError, ResponseDecodeError, ResponseHeaderError } from "../errors.js";
3
+ //#region src/_internal/error-mapping.ts
4
+ /** Casts or converts the unknown into an Error */
5
+ function unknownToError(err) {
6
+ if (err instanceof Error) return err;
7
+ if (typeof err === "string") return new Error(err);
8
+ return new Error("unknown error", { cause: err });
9
+ }
10
+ function isAbortOrTimeoutError(error) {
11
+ if (!error || typeof error !== "object") return false;
12
+ const name = String(error.name ?? "");
13
+ return name === "AbortError" || name === "TimeoutError";
14
+ }
15
+ function toConnectError(error, { signal, context, timedOut }) {
16
+ if (error instanceof FetchError) return error;
17
+ if (timedOut || signal?.reason?.name === "TimeoutError") return new ConnectTimeoutError(unknownToError(error), context, "Connection timeout");
18
+ if (signal?.aborted || isAbortOrTimeoutError(error)) return new RequestAbortedError(unknownToError(signal?.reason ?? error ?? new DOMException("This operation was aborted", "AbortError")), context, "The request was aborted while connecting");
19
+ return new ConnectionError(unknownToError(error), context, "Connection failed");
20
+ }
21
+ function toSendError(error, { signal, context, phase }) {
22
+ if (error instanceof FetchError) return error;
23
+ if (signal?.aborted || isAbortOrTimeoutError(error)) return new RequestAbortedError(unknownToError(signal?.reason ?? error ?? new DOMException("This operation was aborted", "AbortError")), context, phase === "body" ? "The request was aborted while reading the response body" : "The request was aborted");
24
+ const cause = unknownToError(error);
25
+ if (phase === "request") return new RequestWriteError(cause, context);
26
+ if (phase === "response") return new ResponseHeaderError(cause, context);
27
+ if (error instanceof DecodeStreamError) return new ResponseDecodeError(unknownToError(error.cause), context);
28
+ return new ResponseBodyError(cause, context);
29
+ }
30
+ function toWebFetchError(error, signal) {
31
+ if (signal?.aborted) return signal.reason ?? new DOMException("This operation was aborted", "AbortError");
32
+ if (error instanceof DOMException || error instanceof TypeError) return error;
33
+ return new TypeError("fetch failed", { cause: unknownToError(error) });
34
+ }
35
+ function toWebBodyReadError(error, signal) {
36
+ if (signal?.aborted) return signal.reason ?? new DOMException("This operation was aborted", "AbortError");
37
+ if (error instanceof DOMException || error instanceof TypeError || error instanceof RangeError) return error;
38
+ return new TypeError("Failed to read response body", { cause: unknownToError(error) });
39
+ }
40
+ //#endregion
41
+ export { toConnectError, toSendError, toWebBodyReadError, toWebFetchError };
@@ -1,22 +1,21 @@
1
1
  require("../_virtual/_rolldown/runtime.cjs");
2
2
  let node_stream = require("node:stream");
3
3
  //#region src/_internal/guards.ts
4
- var isReadable = (object) => node_stream.Readable.isReadable(object);
4
+ var isReadable = (object) => Boolean(node_stream.Readable.isReadable(object));
5
5
  var isIterable = (object) => typeof object?.[Symbol.asyncIterator] === "function" || typeof object?.[Symbol.iterator] === "function";
6
- var isMultipartFormDataStream = (object) => typeof object?.getBoundary === "function" && typeof object?.hasKnownLength === "function" && typeof object?.getLengthSync === "function" && node_stream.Readable.isReadable(object);
6
+ var isMultipartFormDataStream = (object) => typeof object?.getBoundary === "function" && typeof object?.hasKnownLength === "function" && typeof object?.getLengthSync === "function" && Boolean(node_stream.Readable.isReadable(object));
7
7
  var isFormData = (object) => typeof object === "object" && typeof object?.append === "function" && typeof object?.set === "function" && typeof object?.get === "function" && typeof object?.getAll === "function" && typeof object?.delete === "function" && typeof object?.keys === "function" && typeof object?.values === "function" && typeof object?.entries === "function" && typeof object?.constructor === "function" && object?.[Symbol.toStringTag] === "FormData";
8
8
  var isURLSearchParameters = (object) => typeof object === "object" && typeof object?.append === "function" && typeof object?.delete === "function" && typeof object?.get === "function" && typeof object?.getAll === "function" && typeof object?.has === "function" && typeof object?.set === "function" && typeof object?.sort === "function" && object?.[Symbol.toStringTag] === "URLSearchParams";
9
9
  var isReadableStream = (object) => typeof object === "object" && typeof object?.getReader === "function" && typeof object?.cancel === "function" && typeof object?.tee === "function";
10
+ var isFumanReadable = (object) => typeof object?.read === "function" && typeof object?.close === "function" && !isReadable(object) && !isReadableStream(object);
10
11
  var isBlob = (object) => {
11
- if (typeof object === "object" && typeof object?.arrayBuffer === "function" && typeof object?.type === "string" && typeof object?.stream === "function" && typeof object?.constructor === "function") {
12
- const tag = object[Symbol.toStringTag];
13
- return typeof tag === "string" && (tag.startsWith("Blob") || tag.startsWith("File"));
14
- }
12
+ if (typeof object === "object" && object !== null && typeof object.arrayBuffer === "function" && typeof object.size === "number" && typeof object.slice === "function" && typeof object.stream === "function" && typeof object.text === "function" && typeof object.type === "string") return true;
15
13
  return false;
16
14
  };
17
15
  //#endregion
18
16
  exports.isBlob = isBlob;
19
17
  exports.isFormData = isFormData;
18
+ exports.isFumanReadable = isFumanReadable;
20
19
  exports.isIterable = isIterable;
21
20
  exports.isMultipartFormDataStream = isMultipartFormDataStream;
22
21
  exports.isReadable = isReadable;
@@ -1,4 +1,5 @@
1
1
  import { Readable } from 'node:stream';
2
+ import { IClosable, IReadable } from '@fuman/io';
2
3
  export interface FormDataPolyfill extends Readable {
3
4
  getBoundary(): string;
4
5
  getLengthSync(): number;
@@ -10,4 +11,5 @@ export declare const isMultipartFormDataStream: (object: any) => object is FormD
10
11
  export declare const isFormData: (object: any) => object is FormData;
11
12
  export declare const isURLSearchParameters: (object: any) => object is URLSearchParams;
12
13
  export declare const isReadableStream: (object: any) => object is ReadableStream;
14
+ export declare const isFumanReadable: (object: any) => object is IReadable & IClosable;
13
15
  export declare const isBlob: (object: any) => object is Blob;
@@ -1,4 +1,5 @@
1
1
  import { Readable } from 'node:stream';
2
+ import { IClosable, IReadable } from '@fuman/io';
2
3
  export interface FormDataPolyfill extends Readable {
3
4
  getBoundary(): string;
4
5
  getLengthSync(): number;
@@ -10,4 +11,5 @@ export declare const isMultipartFormDataStream: (object: any) => object is FormD
10
11
  export declare const isFormData: (object: any) => object is FormData;
11
12
  export declare const isURLSearchParameters: (object: any) => object is URLSearchParams;
12
13
  export declare const isReadableStream: (object: any) => object is ReadableStream;
14
+ export declare const isFumanReadable: (object: any) => object is IReadable & IClosable;
13
15
  export declare const isBlob: (object: any) => object is Blob;
@@ -1,17 +1,15 @@
1
1
  import { Readable } from "node:stream";
2
2
  //#region src/_internal/guards.ts
3
- var isReadable = (object) => Readable.isReadable(object);
3
+ var isReadable = (object) => Boolean(Readable.isReadable(object));
4
4
  var isIterable = (object) => typeof object?.[Symbol.asyncIterator] === "function" || typeof object?.[Symbol.iterator] === "function";
5
- var isMultipartFormDataStream = (object) => typeof object?.getBoundary === "function" && typeof object?.hasKnownLength === "function" && typeof object?.getLengthSync === "function" && Readable.isReadable(object);
5
+ var isMultipartFormDataStream = (object) => typeof object?.getBoundary === "function" && typeof object?.hasKnownLength === "function" && typeof object?.getLengthSync === "function" && Boolean(Readable.isReadable(object));
6
6
  var isFormData = (object) => typeof object === "object" && typeof object?.append === "function" && typeof object?.set === "function" && typeof object?.get === "function" && typeof object?.getAll === "function" && typeof object?.delete === "function" && typeof object?.keys === "function" && typeof object?.values === "function" && typeof object?.entries === "function" && typeof object?.constructor === "function" && object?.[Symbol.toStringTag] === "FormData";
7
7
  var isURLSearchParameters = (object) => typeof object === "object" && typeof object?.append === "function" && typeof object?.delete === "function" && typeof object?.get === "function" && typeof object?.getAll === "function" && typeof object?.has === "function" && typeof object?.set === "function" && typeof object?.sort === "function" && object?.[Symbol.toStringTag] === "URLSearchParams";
8
8
  var isReadableStream = (object) => typeof object === "object" && typeof object?.getReader === "function" && typeof object?.cancel === "function" && typeof object?.tee === "function";
9
+ var isFumanReadable = (object) => typeof object?.read === "function" && typeof object?.close === "function" && !isReadable(object) && !isReadableStream(object);
9
10
  var isBlob = (object) => {
10
- if (typeof object === "object" && typeof object?.arrayBuffer === "function" && typeof object?.type === "string" && typeof object?.stream === "function" && typeof object?.constructor === "function") {
11
- const tag = object[Symbol.toStringTag];
12
- return typeof tag === "string" && (tag.startsWith("Blob") || tag.startsWith("File"));
13
- }
11
+ if (typeof object === "object" && object !== null && typeof object.arrayBuffer === "function" && typeof object.size === "number" && typeof object.slice === "function" && typeof object.stream === "function" && typeof object.text === "function" && typeof object.type === "string") return true;
14
12
  return false;
15
13
  };
16
14
  //#endregion
17
- export { isBlob, isFormData, isIterable, isMultipartFormDataStream, isReadable, isReadableStream, isURLSearchParameters };
15
+ export { isBlob, isFormData, isFumanReadable, isIterable, isMultipartFormDataStream, isReadable, isReadableStream, isURLSearchParameters };
@@ -1,6 +1,6 @@
1
1
  import { ConnectFunction, TcpEndpoint, TlsUpgradeFunction } from '@fuman/net';
2
2
  import { NodeTlsConnectOptions, NodeTlsUpgradeOptions, TcpConnection, TlsConnection } from '@fuman/node';
3
- type WithSignal<T = {}> = T & {
3
+ export type WithSignal<T = {}> = T & {
4
4
  signal?: AbortSignal;
5
5
  };
6
6
  export interface AbortError extends Error {
@@ -9,4 +9,3 @@ export interface AbortError extends Error {
9
9
  export declare const connectTcp: ConnectFunction<WithSignal<TcpEndpoint>, TcpConnection>;
10
10
  export declare const connectTls: ConnectFunction<WithSignal<NodeTlsConnectOptions>, TlsConnection>;
11
11
  export declare const upgradeTls: TlsUpgradeFunction<WithSignal<NodeTlsUpgradeOptions>, TcpConnection, TlsConnection>;
12
- export {};
@@ -1,6 +1,6 @@
1
1
  import { ConnectFunction, TcpEndpoint, TlsUpgradeFunction } from '@fuman/net';
2
2
  import { NodeTlsConnectOptions, NodeTlsUpgradeOptions, TcpConnection, TlsConnection } from '@fuman/node';
3
- type WithSignal<T = {}> = T & {
3
+ export type WithSignal<T = {}> = T & {
4
4
  signal?: AbortSignal;
5
5
  };
6
6
  export interface AbortError extends Error {
@@ -9,4 +9,3 @@ export interface AbortError extends Error {
9
9
  export declare const connectTcp: ConnectFunction<WithSignal<TcpEndpoint>, TcpConnection>;
10
10
  export declare const connectTls: ConnectFunction<WithSignal<NodeTlsConnectOptions>, TlsConnection>;
11
11
  export declare const upgradeTls: TlsUpgradeFunction<WithSignal<NodeTlsUpgradeOptions>, TcpConnection, TlsConnection>;
12
- export {};
@@ -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 };
package/agent-pool.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  require("./_virtual/_rolldown/runtime.cjs");
2
- const require_tcp = require("./dialers/tcp.cjs");
3
2
  const require_errors = require("./errors.cjs");
4
3
  const require_agent = require("./agent.cjs");
4
+ const require_tcp = require("./dialers/tcp.cjs");
5
5
  let generic_pool = require("generic-pool");
6
6
  //#region src/agent-pool.ts
7
7
  var defaultEvictionInterval = 1e4;
@@ -40,13 +40,14 @@ function createAgentPool(baseUrl, options = {}) {
40
40
  min
41
41
  });
42
42
  let releaseAgentFns = [];
43
+ let closePromise;
43
44
  async function send(sendOptions) {
44
45
  let agent;
45
46
  let agentReleased = false;
46
47
  const releaseAgentFn = async (forceClose = false) => {
47
48
  if (!agent || agentReleased) return;
48
49
  agentReleased = true;
49
- releaseAgentFns = releaseAgentFns.filter((r) => r !== releaseAgentFn);
50
+ releaseAgentFns = releaseAgentFns.filter((release) => release !== releaseAgentFn);
50
51
  if (forceClose) agent.close();
51
52
  if (pool.isBorrowedResource(agent)) await pool.release(agent);
52
53
  };
@@ -62,9 +63,26 @@ function createAgentPool(baseUrl, options = {}) {
62
63
  }
63
64
  }
64
65
  async function close() {
65
- await Promise.all(releaseAgentFns.map((release) => release(true)));
66
- await pool.drain();
67
- await pool.clear();
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
+ }
68
86
  }
69
87
  return {
70
88
  [Symbol.asyncDispose]: close,
@@ -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 CHANGED
@@ -1,6 +1,6 @@
1
- import { AutoDialer } from "./dialers/tcp.js";
2
1
  import { UnsupportedProtocolError } from "./errors.js";
3
2
  import { createAgent } from "./agent.js";
3
+ import { AutoDialer } from "./dialers/tcp.js";
4
4
  import { createPool } from "generic-pool";
5
5
  //#region src/agent-pool.ts
6
6
  var defaultEvictionInterval = 1e4;
@@ -39,13 +39,14 @@ function createAgentPool(baseUrl, options = {}) {
39
39
  min
40
40
  });
41
41
  let releaseAgentFns = [];
42
+ let closePromise;
42
43
  async function send(sendOptions) {
43
44
  let agent;
44
45
  let agentReleased = false;
45
46
  const releaseAgentFn = async (forceClose = false) => {
46
47
  if (!agent || agentReleased) return;
47
48
  agentReleased = true;
48
- releaseAgentFns = releaseAgentFns.filter((r) => r !== releaseAgentFn);
49
+ releaseAgentFns = releaseAgentFns.filter((release) => release !== releaseAgentFn);
49
50
  if (forceClose) agent.close();
50
51
  if (pool.isBorrowedResource(agent)) await pool.release(agent);
51
52
  };
@@ -61,9 +62,26 @@ function createAgentPool(baseUrl, options = {}) {
61
62
  }
62
63
  }
63
64
  async function close() {
64
- await Promise.all(releaseAgentFns.map((release) => release(true)));
65
- await pool.drain();
66
- await pool.clear();
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
+ }
67
85
  }
68
86
  return {
69
87
  [Symbol.asyncDispose]: close,
package/agent.cjs CHANGED
@@ -1,7 +1,8 @@
1
1
  require("./_virtual/_rolldown/runtime.cjs");
2
2
  const require_errors = require("./errors.cjs");
3
- const require_error_adapters = require("./_internal/error-adapters.cjs");
3
+ const require_error_mapping = require("./_internal/error-mapping.cjs");
4
4
  const require_promises = require("./_internal/promises.cjs");
5
+ const require_symbols = require("./_internal/symbols.cjs");
5
6
  const require_io = require("./io/io.cjs");
6
7
  let _fuman_utils = require("@fuman/utils");
7
8
  //#region src/agent.ts
@@ -104,9 +105,7 @@ function createAgent(dialer, baseUrl, options = {}) {
104
105
  let timedOut = false;
105
106
  let timeoutId;
106
107
  const abortController = new AbortController();
107
- const onAbort = () => {
108
- abortController.abort(signal?.reason);
109
- };
108
+ const onAbort = () => abortController.abort(signal?.reason);
110
109
  const cleanup = () => {
111
110
  if (timeoutId !== void 0) {
112
111
  clearTimeout(timeoutId);
@@ -142,7 +141,7 @@ function createAgent(dialer, baseUrl, options = {}) {
142
141
  conn = nextConn;
143
142
  return nextConn;
144
143
  } catch (error) {
145
- throw require_error_adapters.mapAdvancedConnectError(error, {
144
+ throw require_error_mapping.toConnectError(error, {
146
145
  signal,
147
146
  timedOut,
148
147
  context: createBaseErrorContext()
@@ -154,7 +153,7 @@ function createAgent(dialer, baseUrl, options = {}) {
154
153
  })();
155
154
  return withSignal(connectPromise, signal);
156
155
  }
157
- async function send(sendOptions) {
156
+ async function executeRequest(sendOptions, mapBodyError) {
158
157
  assertUsable();
159
158
  const url = typeof sendOptions.url === "string" ? new URL(sendOptions.url) : sendOptions.url;
160
159
  const method = sendOptions.method.toUpperCase();
@@ -198,7 +197,7 @@ function createAgent(dialer, baseUrl, options = {}) {
198
197
  signal: sendOptions.signal
199
198
  }, writerOptions), sendOptions.signal);
200
199
  } catch (error) {
201
- throw require_error_adapters.mapAdvancedSendError(error, {
200
+ throw require_error_mapping.toSendError(error, {
202
201
  signal: sendOptions.signal,
203
202
  context: errorContext,
204
203
  phase: "request"
@@ -211,19 +210,15 @@ function createAgent(dialer, baseUrl, options = {}) {
211
210
  response = await withSignal(require_io.readResponse(activeConn, readerOptions, shouldIgnoreBody, (reusable) => {
212
211
  sendOptions.signal?.removeEventListener("abort", abortListener);
213
212
  finalize(reusable);
214
- }), sendOptions.signal);
213
+ }, mapBodyError), sendOptions.signal);
215
214
  } catch (error) {
216
- throw require_error_adapters.mapAdvancedSendError(error, {
215
+ throw require_error_mapping.toSendError(error, {
217
216
  signal: sendOptions.signal,
218
217
  context: errorContext,
219
218
  phase: "response"
220
219
  });
221
220
  }
222
- return require_error_adapters.wrapResponseBodyErrors(response, (error) => require_error_adapters.mapAdvancedSendError(error, {
223
- signal: sendOptions.signal,
224
- context: errorContext,
225
- phase: "body"
226
- }));
221
+ return response;
227
222
  } catch (error) {
228
223
  sendOptions.signal?.removeEventListener("abort", abortListener);
229
224
  if (activeConn) {
@@ -236,6 +231,14 @@ function createAgent(dialer, baseUrl, options = {}) {
236
231
  throw error;
237
232
  }
238
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
+ }
239
242
  return {
240
243
  [Symbol.dispose]: forceClose,
241
244
  close: forceClose,
package/agent.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { AgentBusyError, AgentClosedError, OriginMismatchError, RequestAbortedError, UnsupportedAlpnProtocolError, UnsupportedMethodError, UnsupportedProtocolError } from "./errors.js";
2
- import { mapAdvancedConnectError, mapAdvancedSendError, wrapResponseBodyErrors } from "./_internal/error-adapters.js";
2
+ import { toConnectError, toSendError } from "./_internal/error-mapping.js";
3
3
  import { raceSignal } from "./_internal/promises.js";
4
+ import { bodyErrorMapperSymbol } from "./_internal/symbols.js";
4
5
  import { readResponse, writeRequest } from "./io/io.js";
5
6
  import { Deferred } from "@fuman/utils";
6
7
  //#region src/agent.ts
@@ -103,9 +104,7 @@ function createAgent(dialer, baseUrl, options = {}) {
103
104
  let timedOut = false;
104
105
  let timeoutId;
105
106
  const abortController = new AbortController();
106
- const onAbort = () => {
107
- abortController.abort(signal?.reason);
108
- };
107
+ const onAbort = () => abortController.abort(signal?.reason);
109
108
  const cleanup = () => {
110
109
  if (timeoutId !== void 0) {
111
110
  clearTimeout(timeoutId);
@@ -141,7 +140,7 @@ function createAgent(dialer, baseUrl, options = {}) {
141
140
  conn = nextConn;
142
141
  return nextConn;
143
142
  } catch (error) {
144
- throw mapAdvancedConnectError(error, {
143
+ throw toConnectError(error, {
145
144
  signal,
146
145
  timedOut,
147
146
  context: createBaseErrorContext()
@@ -153,7 +152,7 @@ function createAgent(dialer, baseUrl, options = {}) {
153
152
  })();
154
153
  return withSignal(connectPromise, signal);
155
154
  }
156
- async function send(sendOptions) {
155
+ async function executeRequest(sendOptions, mapBodyError) {
157
156
  assertUsable();
158
157
  const url = typeof sendOptions.url === "string" ? new URL(sendOptions.url) : sendOptions.url;
159
158
  const method = sendOptions.method.toUpperCase();
@@ -197,7 +196,7 @@ function createAgent(dialer, baseUrl, options = {}) {
197
196
  signal: sendOptions.signal
198
197
  }, writerOptions), sendOptions.signal);
199
198
  } catch (error) {
200
- throw mapAdvancedSendError(error, {
199
+ throw toSendError(error, {
201
200
  signal: sendOptions.signal,
202
201
  context: errorContext,
203
202
  phase: "request"
@@ -210,19 +209,15 @@ function createAgent(dialer, baseUrl, options = {}) {
210
209
  response = await withSignal(readResponse(activeConn, readerOptions, shouldIgnoreBody, (reusable) => {
211
210
  sendOptions.signal?.removeEventListener("abort", abortListener);
212
211
  finalize(reusable);
213
- }), sendOptions.signal);
212
+ }, mapBodyError), sendOptions.signal);
214
213
  } catch (error) {
215
- throw mapAdvancedSendError(error, {
214
+ throw toSendError(error, {
216
215
  signal: sendOptions.signal,
217
216
  context: errorContext,
218
217
  phase: "response"
219
218
  });
220
219
  }
221
- return wrapResponseBodyErrors(response, (error) => mapAdvancedSendError(error, {
222
- signal: sendOptions.signal,
223
- context: errorContext,
224
- phase: "body"
225
- }));
220
+ return response;
226
221
  } catch (error) {
227
222
  sendOptions.signal?.removeEventListener("abort", abortListener);
228
223
  if (activeConn) {
@@ -235,6 +230,14 @@ function createAgent(dialer, baseUrl, options = {}) {
235
230
  throw error;
236
231
  }
237
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
+ }
238
241
  return {
239
242
  [Symbol.dispose]: forceClose,
240
243
  close: forceClose,