@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
package/body.cjs CHANGED
@@ -1,10 +1,10 @@
1
1
  require("./_virtual/_rolldown/runtime.cjs");
2
2
  const require_guards = require("./_internal/guards.cjs");
3
- let _fuman_node = require("@fuman/node");
4
- let node_crypto = require("node:crypto");
3
+ let _fuman_utils = require("@fuman/utils");
5
4
  let node_stream = require("node:stream");
5
+ let _fuman_io = require("@fuman/io");
6
+ let node_crypto = require("node:crypto");
6
7
  let node_util_types = require("node:util/types");
7
- let _fuman_utils = require("@fuman/utils");
8
8
  //#region src/body.ts
9
9
  var BOUNDARY = "-".repeat(2);
10
10
  var makeFormBoundary = () => `formdata-${(0, node_crypto.randomBytes)(8).toString("hex")}`;
@@ -70,6 +70,7 @@ var extractBody = (object) => {
70
70
  body = bytes;
71
71
  size = bytes.byteLength;
72
72
  } else if (require_guards.isReadableStream(object)) body = object;
73
+ else if (require_guards.isFumanReadable(object)) body = object;
73
74
  else if (require_guards.isFormData(object)) {
74
75
  const boundary = makeFormBoundary();
75
76
  type = `multipart/form-data; boundary=${boundary}`;
@@ -93,62 +94,12 @@ var extractBody = (object) => {
93
94
  body
94
95
  };
95
96
  };
96
- var kBodyInternals = Symbol("kBodyInternals");
97
- var toWebBodyInit = (body) => {
98
- if (body == null) return null;
99
- if (require_guards.isReadable(body)) return (0, _fuman_node.nodeReadableToWeb)(body);
100
- return body;
101
- };
102
- var bytesToArrayBuffer = (bytes) => {
103
- const bytesAsArrayBuffer = new ArrayBuffer(bytes.byteLength);
104
- new Uint8Array(bytesAsArrayBuffer).set(bytes);
105
- return bytesAsArrayBuffer;
106
- };
107
- var Body = class {
108
- [kBodyInternals];
109
- constructor(init) {
110
- this[kBodyInternals] = extractBody(init);
111
- }
112
- get body() {
113
- return this[kBodyInternals].body;
114
- }
115
- get bodyUsed() {
116
- const { body } = this[kBodyInternals];
117
- if (require_guards.isReadable(body)) return node_stream.Readable.isDisturbed(body);
118
- if (require_guards.isReadableStream(body)) return body.locked;
119
- return false;
120
- }
121
- async arrayBuffer() {
122
- const { body } = this[kBodyInternals];
123
- if (body == null) return /* @__PURE__ */ new ArrayBuffer(0);
124
- if (body instanceof Uint8Array) return bytesToArrayBuffer(body);
125
- return new Response(toWebBodyInit(body)).arrayBuffer();
126
- }
127
- async formData() {
128
- const { body, contentLength, contentType } = this[kBodyInternals];
129
- const headers = {};
130
- if (contentLength != null) headers["Content-Length"] = String(contentLength);
131
- if (contentType != null) headers["Content-Type"] = contentType;
132
- return new Response(toWebBodyInit(body), { headers }).formData();
133
- }
134
- async blob() {
135
- const { body, contentType } = this[kBodyInternals];
136
- if (body == null) return new Blob([], { type: contentType ?? "" });
137
- if (body instanceof Uint8Array) return new Blob([new Uint8Array(body.buffer, body.byteOffset, body.byteLength)], { type: contentType ?? "" });
138
- return new Response(toWebBodyInit(body), { headers: contentType ? { "Content-Type": contentType } : void 0 }).blob();
139
- }
140
- async json() {
141
- const text = await this.text();
142
- return JSON.parse(text);
143
- }
144
- async text() {
145
- const { body } = this[kBodyInternals];
146
- if (body == null) return "";
147
- if (body instanceof Uint8Array) return _fuman_utils.utf8.decoder.decode(body);
148
- return new Response(toWebBodyInit(body)).text();
149
- }
150
- };
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
+ }
151
102
  //#endregion
152
- exports.Body = Body;
153
103
  exports.extractBody = extractBody;
104
+ exports.fromRequestBody = fromRequestBody;
154
105
  exports.getFormDataLength = getFormDataLength;
package/body.d.cts ADDED
@@ -0,0 +1,12 @@
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 ADDED
@@ -0,0 +1,12 @@
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 CHANGED
@@ -1,9 +1,9 @@
1
- import { isBlob, isFormData, isIterable, isMultipartFormDataStream, isReadable, isReadableStream, isURLSearchParameters } from "./_internal/guards.js";
2
- import { nodeReadableToWeb } from "@fuman/node";
3
- import { randomBytes } from "node:crypto";
1
+ import { isBlob, isFormData, isFumanReadable, isIterable, isMultipartFormDataStream, isReadable, isReadableStream, isURLSearchParameters } from "./_internal/guards.js";
2
+ import { utf8 } from "@fuman/utils";
4
3
  import { Readable } from "node:stream";
4
+ import { webReadableToFuman } from "@fuman/io";
5
+ import { randomBytes } from "node:crypto";
5
6
  import { isAnyArrayBuffer } from "node:util/types";
6
- import { utf8 } from "@fuman/utils";
7
7
  //#region src/body.ts
8
8
  var BOUNDARY = "-".repeat(2);
9
9
  var makeFormBoundary = () => `formdata-${randomBytes(8).toString("hex")}`;
@@ -69,6 +69,7 @@ var extractBody = (object) => {
69
69
  body = bytes;
70
70
  size = bytes.byteLength;
71
71
  } else if (isReadableStream(object)) body = object;
72
+ else if (isFumanReadable(object)) body = object;
72
73
  else if (isFormData(object)) {
73
74
  const boundary = makeFormBoundary();
74
75
  type = `multipart/form-data; boundary=${boundary}`;
@@ -92,60 +93,10 @@ var extractBody = (object) => {
92
93
  body
93
94
  };
94
95
  };
95
- var kBodyInternals = Symbol("kBodyInternals");
96
- var toWebBodyInit = (body) => {
97
- if (body == null) return null;
98
- if (isReadable(body)) return nodeReadableToWeb(body);
99
- return body;
100
- };
101
- var bytesToArrayBuffer = (bytes) => {
102
- const bytesAsArrayBuffer = new ArrayBuffer(bytes.byteLength);
103
- new Uint8Array(bytesAsArrayBuffer).set(bytes);
104
- return bytesAsArrayBuffer;
105
- };
106
- var Body = class {
107
- [kBodyInternals];
108
- constructor(init) {
109
- this[kBodyInternals] = extractBody(init);
110
- }
111
- get body() {
112
- return this[kBodyInternals].body;
113
- }
114
- get bodyUsed() {
115
- const { body } = this[kBodyInternals];
116
- if (isReadable(body)) return Readable.isDisturbed(body);
117
- if (isReadableStream(body)) return body.locked;
118
- return false;
119
- }
120
- async arrayBuffer() {
121
- const { body } = this[kBodyInternals];
122
- if (body == null) return /* @__PURE__ */ new ArrayBuffer(0);
123
- if (body instanceof Uint8Array) return bytesToArrayBuffer(body);
124
- return new Response(toWebBodyInit(body)).arrayBuffer();
125
- }
126
- async formData() {
127
- const { body, contentLength, contentType } = this[kBodyInternals];
128
- const headers = {};
129
- if (contentLength != null) headers["Content-Length"] = String(contentLength);
130
- if (contentType != null) headers["Content-Type"] = contentType;
131
- return new Response(toWebBodyInit(body), { headers }).formData();
132
- }
133
- async blob() {
134
- const { body, contentType } = this[kBodyInternals];
135
- if (body == null) return new Blob([], { type: contentType ?? "" });
136
- if (body instanceof Uint8Array) return new Blob([new Uint8Array(body.buffer, body.byteOffset, body.byteLength)], { type: contentType ?? "" });
137
- return new Response(toWebBodyInit(body), { headers: contentType ? { "Content-Type": contentType } : void 0 }).blob();
138
- }
139
- async json() {
140
- const text = await this.text();
141
- return JSON.parse(text);
142
- }
143
- async text() {
144
- const { body } = this[kBodyInternals];
145
- if (body == null) return "";
146
- if (body instanceof Uint8Array) return utf8.decoder.decode(body);
147
- return new Response(toWebBodyInit(body)).text();
148
- }
149
- };
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
+ }
150
101
  //#endregion
151
- export { Body, extractBody, getFormDataLength };
102
+ export { extractBody, fromRequestBody, getFormDataLength };
package/dialers/proxy.cjs CHANGED
@@ -9,6 +9,13 @@ function normalizeProxy(proxy) {
9
9
  if (parsed == null) throw new TypeError(`Invalid proxy string: ${proxy}`);
10
10
  return parsed;
11
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
+ */
12
19
  var ProxyDialer = class {
13
20
  proxy;
14
21
  #options;
@@ -1,15 +1,22 @@
1
1
  import { NodeTlsUpgradeOptions } from '@fuman/node';
2
2
  import { createProxyConnection, ProxyInfo } from '@npy/proxy-kit';
3
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
+ */
4
12
  export declare class ProxyDialer implements Dialer {
5
13
  #private;
6
- readonly proxy: ProxyDialer.Proxy;
14
+ readonly proxy: ResolvedProxy;
7
15
  constructor(proxy: ProxyDialer.Input, options?: ProxyDialer.Options);
8
16
  dial(target: Dialer.Target, options?: Dialer.Options): Promise<Dialer.ConnectionLike>;
9
17
  }
10
18
  export declare namespace ProxyDialer {
11
- type Proxy = Parameters<typeof createProxyConnection>[0]["proxy"];
12
- type Input = string | Proxy | ProxyInfo;
19
+ type Input = string | ProxyInfo;
13
20
  interface Options {
14
21
  caCerts?: string[];
15
22
  sni?: string;
@@ -17,3 +24,4 @@ export declare namespace ProxyDialer {
17
24
  extraOptions?: NodeTlsUpgradeOptions["extraOptions"];
18
25
  }
19
26
  }
27
+ export {};
@@ -1,15 +1,22 @@
1
1
  import { NodeTlsUpgradeOptions } from '@fuman/node';
2
2
  import { createProxyConnection, ProxyInfo } from '@npy/proxy-kit';
3
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
+ */
4
12
  export declare class ProxyDialer implements Dialer {
5
13
  #private;
6
- readonly proxy: ProxyDialer.Proxy;
14
+ readonly proxy: ResolvedProxy;
7
15
  constructor(proxy: ProxyDialer.Input, options?: ProxyDialer.Options);
8
16
  dial(target: Dialer.Target, options?: Dialer.Options): Promise<Dialer.ConnectionLike>;
9
17
  }
10
18
  export declare namespace ProxyDialer {
11
- type Proxy = Parameters<typeof createProxyConnection>[0]["proxy"];
12
- type Input = string | Proxy | ProxyInfo;
19
+ type Input = string | ProxyInfo;
13
20
  interface Options {
14
21
  caCerts?: string[];
15
22
  sni?: string;
@@ -17,3 +24,4 @@ export declare namespace ProxyDialer {
17
24
  extraOptions?: NodeTlsUpgradeOptions["extraOptions"];
18
25
  }
19
26
  }
27
+ export {};
package/dialers/proxy.js CHANGED
@@ -8,6 +8,13 @@ function normalizeProxy(proxy) {
8
8
  if (parsed == null) throw new TypeError(`Invalid proxy string: ${proxy}`);
9
9
  return parsed;
10
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
+ */
11
18
  var ProxyDialer = class {
12
19
  proxy;
13
20
  #options;
package/dialers/tcp.cjs CHANGED
@@ -13,6 +13,12 @@ function parsePort(value) {
13
13
  if (!Number.isInteger(parsed) || parsed <= 0 || parsed > 65535) throw new TypeError(`Invalid port: ${JSON.stringify(value)}`);
14
14
  return parsed;
15
15
  }
16
+ /**
17
+ * Resolves the effective network address and port for a URL or dial target.
18
+ *
19
+ * @remarks
20
+ * When the input does not include an explicit port, the provided default port is used.
21
+ */
16
22
  function resolveHostPort(target, defaultPort) {
17
23
  const address = target instanceof URL ? target.hostname : target.address;
18
24
  if (!address) throw new TypeError("Target address is required");
@@ -21,6 +27,12 @@ function resolveHostPort(target, defaultPort) {
21
27
  port: target instanceof URL ? parsePort(target.port || String(defaultPort)) : parsePort(target.port || defaultPort)
22
28
  };
23
29
  }
30
+ /**
31
+ * Dialer for plain TCP targets.
32
+ *
33
+ * @remarks
34
+ * This dialer rejects secure targets and is intended for HTTP over raw TCP.
35
+ */
24
36
  var TcpDialer = class {
25
37
  async dial(target, options = {}) {
26
38
  if (target.secure) throw new Error("TcpDialer cannot dial a secure target");
@@ -30,6 +42,13 @@ var TcpDialer = class {
30
42
  });
31
43
  }
32
44
  };
45
+ /**
46
+ * Dialer for TLS targets.
47
+ *
48
+ * @remarks
49
+ * This dialer rejects insecure targets and applies TLS-specific options such as
50
+ * CA certificates, SNI and ALPN.
51
+ */
33
52
  var TlsDialer = class {
34
53
  #options;
35
54
  constructor(options = {}) {
@@ -52,6 +71,9 @@ var TlsDialer = class {
52
71
  });
53
72
  }
54
73
  };
74
+ /**
75
+ * Selects {@link TcpDialer} or {@link TlsDialer} based on the target security mode.
76
+ */
55
77
  var AutoDialer = class {
56
78
  tcpDialer;
57
79
  tlsDialer;
@@ -1,13 +1,32 @@
1
1
  import { NodeTlsConnectOptions } from '@fuman/node';
2
2
  import { Dialer } from '../types/dialer';
3
- type HostPort = {
3
+ export type HostPort = {
4
4
  address: string;
5
5
  port: number;
6
6
  };
7
+ /**
8
+ * Resolves the effective network address and port for a URL or dial target.
9
+ *
10
+ * @remarks
11
+ * When the input does not include an explicit port, the provided default port is used.
12
+ */
7
13
  export declare function resolveHostPort(target: URL | Dialer.Target, defaultPort: number): HostPort;
14
+ /**
15
+ * Dialer for plain TCP targets.
16
+ *
17
+ * @remarks
18
+ * This dialer rejects secure targets and is intended for HTTP over raw TCP.
19
+ */
8
20
  export declare class TcpDialer implements Dialer {
9
21
  dial(target: Dialer.Target, options?: Dialer.Options): Promise<Dialer.ConnectionLike>;
10
22
  }
23
+ /**
24
+ * Dialer for TLS targets.
25
+ *
26
+ * @remarks
27
+ * This dialer rejects insecure targets and applies TLS-specific options such as
28
+ * CA certificates, SNI and ALPN.
29
+ */
11
30
  export declare class TlsDialer implements Dialer {
12
31
  #private;
13
32
  constructor(options?: TlsDialer.Options);
@@ -21,6 +40,9 @@ export declare namespace TlsDialer {
21
40
  extraOptions?: NodeTlsConnectOptions["extraOptions"];
22
41
  }
23
42
  }
43
+ /**
44
+ * Selects {@link TcpDialer} or {@link TlsDialer} based on the target security mode.
45
+ */
24
46
  export declare class AutoDialer implements Dialer {
25
47
  readonly tcpDialer: TcpDialer;
26
48
  readonly tlsDialer: TlsDialer;
@@ -33,4 +55,3 @@ export declare namespace AutoDialer {
33
55
  tls?: TlsDialer;
34
56
  }
35
57
  }
36
- export {};
@@ -1,13 +1,32 @@
1
1
  import { NodeTlsConnectOptions } from '@fuman/node';
2
2
  import { Dialer } from '../types/dialer';
3
- type HostPort = {
3
+ export type HostPort = {
4
4
  address: string;
5
5
  port: number;
6
6
  };
7
+ /**
8
+ * Resolves the effective network address and port for a URL or dial target.
9
+ *
10
+ * @remarks
11
+ * When the input does not include an explicit port, the provided default port is used.
12
+ */
7
13
  export declare function resolveHostPort(target: URL | Dialer.Target, defaultPort: number): HostPort;
14
+ /**
15
+ * Dialer for plain TCP targets.
16
+ *
17
+ * @remarks
18
+ * This dialer rejects secure targets and is intended for HTTP over raw TCP.
19
+ */
8
20
  export declare class TcpDialer implements Dialer {
9
21
  dial(target: Dialer.Target, options?: Dialer.Options): Promise<Dialer.ConnectionLike>;
10
22
  }
23
+ /**
24
+ * Dialer for TLS targets.
25
+ *
26
+ * @remarks
27
+ * This dialer rejects insecure targets and applies TLS-specific options such as
28
+ * CA certificates, SNI and ALPN.
29
+ */
11
30
  export declare class TlsDialer implements Dialer {
12
31
  #private;
13
32
  constructor(options?: TlsDialer.Options);
@@ -21,6 +40,9 @@ export declare namespace TlsDialer {
21
40
  extraOptions?: NodeTlsConnectOptions["extraOptions"];
22
41
  }
23
42
  }
43
+ /**
44
+ * Selects {@link TcpDialer} or {@link TlsDialer} based on the target security mode.
45
+ */
24
46
  export declare class AutoDialer implements Dialer {
25
47
  readonly tcpDialer: TcpDialer;
26
48
  readonly tlsDialer: TlsDialer;
@@ -33,4 +55,3 @@ export declare namespace AutoDialer {
33
55
  tls?: TlsDialer;
34
56
  }
35
57
  }
36
- export {};
package/dialers/tcp.js CHANGED
@@ -13,6 +13,12 @@ function parsePort(value) {
13
13
  if (!Number.isInteger(parsed) || parsed <= 0 || parsed > 65535) throw new TypeError(`Invalid port: ${JSON.stringify(value)}`);
14
14
  return parsed;
15
15
  }
16
+ /**
17
+ * Resolves the effective network address and port for a URL or dial target.
18
+ *
19
+ * @remarks
20
+ * When the input does not include an explicit port, the provided default port is used.
21
+ */
16
22
  function resolveHostPort(target, defaultPort) {
17
23
  const address = target instanceof URL ? target.hostname : target.address;
18
24
  if (!address) throw new TypeError("Target address is required");
@@ -21,6 +27,12 @@ function resolveHostPort(target, defaultPort) {
21
27
  port: target instanceof URL ? parsePort(target.port || String(defaultPort)) : parsePort(target.port || defaultPort)
22
28
  };
23
29
  }
30
+ /**
31
+ * Dialer for plain TCP targets.
32
+ *
33
+ * @remarks
34
+ * This dialer rejects secure targets and is intended for HTTP over raw TCP.
35
+ */
24
36
  var TcpDialer = class {
25
37
  async dial(target, options = {}) {
26
38
  if (target.secure) throw new Error("TcpDialer cannot dial a secure target");
@@ -30,6 +42,13 @@ var TcpDialer = class {
30
42
  });
31
43
  }
32
44
  };
45
+ /**
46
+ * Dialer for TLS targets.
47
+ *
48
+ * @remarks
49
+ * This dialer rejects insecure targets and applies TLS-specific options such as
50
+ * CA certificates, SNI and ALPN.
51
+ */
33
52
  var TlsDialer = class {
34
53
  #options;
35
54
  constructor(options = {}) {
@@ -52,6 +71,9 @@ var TlsDialer = class {
52
71
  });
53
72
  }
54
73
  };
74
+ /**
75
+ * Selects {@link TcpDialer} or {@link TlsDialer} based on the target security mode.
76
+ */
55
77
  var AutoDialer = class {
56
78
  tcpDialer;
57
79
  tlsDialer;
package/encoding.cjs CHANGED
@@ -1,4 +1,5 @@
1
1
  require("./_virtual/_rolldown/runtime.cjs");
2
+ const require_decode_stream_error = require("./_internal/decode-stream-error.cjs");
2
3
  let _fuman_node = require("@fuman/node");
3
4
  let node_stream = require("node:stream");
4
5
  //#region src/encoding.ts
@@ -18,10 +19,11 @@ function encodeStream(stream, contentEncoding) {
18
19
  return applyTransforms(stream, contentEncoding, createEncoders);
19
20
  }
20
21
  /**
21
- * Create a series of decoding streams based on the content-encoding header. The
22
- * resulting streams should be piped together to decode the content.
22
+ * Creates the decoder pipeline for a Content-Encoding or transfer-coding list.
23
23
  *
24
- * @see {@link https://datatracker.ietf.org/doc/html/rfc9110#section-8.4.1}
24
+ * @remarks
25
+ * Decoding is applied in reverse order of encoding, as required by HTTP semantics.
26
+ * The special value `identity` is ignored.
25
27
  */
26
28
  function createDecoders(contentEncoding) {
27
29
  const decoders = [];
@@ -36,13 +38,10 @@ function createDecoders(contentEncoding) {
36
38
  return decoders.reverse();
37
39
  }
38
40
  /**
39
- * Create a series of encoding streams based on the content-encoding header (or
40
- * transfer-coding list).
41
+ * Creates the encoder pipeline for a Content-Encoding or transfer-coding list.
41
42
  *
42
- * The resulting streams should be piped together to apply the encoding in the
43
- * declared order.
44
- *
45
- * @see {@link https://datatracker.ietf.org/doc/html/rfc9110#section-8.4.1}
43
+ * @remarks
44
+ * Encoders are returned in the declared order. The special value `identity` is ignored.
46
45
  */
47
46
  function createEncoders(contentEncoding) {
48
47
  const encoders = [];
@@ -62,15 +61,35 @@ function commaSplit(header) {
62
61
  function normalizeEncoding(encoding) {
63
62
  return encoding.trim().toLowerCase();
64
63
  }
64
+ function tagDecodeErrors(native) {
65
+ const reader = native.readable.getReader();
66
+ const tagged = new ReadableStream({
67
+ pull(controller) {
68
+ return reader.read().then(({ done, value }) => {
69
+ if (done) controller.close();
70
+ else if (value) controller.enqueue(value);
71
+ }, (err) => {
72
+ controller.error(new require_decode_stream_error.DecodeStreamError(err));
73
+ });
74
+ },
75
+ cancel(reason) {
76
+ return reader.cancel(reason);
77
+ }
78
+ });
79
+ return {
80
+ writable: native.writable,
81
+ readable: tagged
82
+ };
83
+ }
65
84
  function createDecoder(normalizedEncoding) {
66
85
  switch (normalizedEncoding) {
67
86
  case "gzip":
68
- case "x-gzip": return new DecompressionStream("gzip");
87
+ case "x-gzip": return tagDecodeErrors(new DecompressionStream("gzip"));
69
88
  case "deflate":
70
- case "x-deflate": return new DecompressionStream("deflate");
89
+ case "x-deflate": return tagDecodeErrors(new DecompressionStream("deflate"));
71
90
  case "zstd":
72
- case "x-zstd": return new DecompressionStream("zstd");
73
- case "br": return new DecompressionStream("brotli");
91
+ case "x-zstd": return tagDecodeErrors(new DecompressionStream("zstd"));
92
+ case "br": return tagDecodeErrors(new DecompressionStream("brotli"));
74
93
  case "identity": return new TransformStream();
75
94
  default: throw new TypeError(`Unsupported content-encoding: "${normalizedEncoding}"`);
76
95
  }
package/encoding.d.cts ADDED
@@ -0,0 +1,35 @@
1
+ export type ByteStream = ReadableStream<Uint8Array>;
2
+ export type ByteTransform = TransformStream<Uint8Array, Uint8Array>;
3
+ /**
4
+ * Applies decoding transforms for the given content-encoding list.
5
+ *
6
+ * @remarks
7
+ * If no supported encodings are provided, the original source is returned unchanged.
8
+ * Async iterables are converted to Web Streams only when transforms are required.
9
+ */
10
+ export declare function decodeStream(stream: ByteStream, contentEncoding?: string | string[]): ByteStream;
11
+ export declare function decodeStream(stream: AsyncIterable<Uint8Array>, contentEncoding?: string | string[]): AsyncIterable<Uint8Array> | ByteStream;
12
+ /**
13
+ * Applies encoding transforms for the given content-encoding list.
14
+ *
15
+ * @remarks
16
+ * If no supported encodings are provided, the original source is returned unchanged.
17
+ * Async iterables are converted to Web Streams only when transforms are required.
18
+ */
19
+ export declare function encodeStream(stream: ByteStream, contentEncoding?: string | string[]): ByteStream;
20
+ export declare function encodeStream(stream: AsyncIterable<Uint8Array>, contentEncoding?: string | string[]): AsyncIterable<Uint8Array> | ByteStream;
21
+ /**
22
+ * Creates the decoder pipeline for a Content-Encoding or transfer-coding list.
23
+ *
24
+ * @remarks
25
+ * Decoding is applied in reverse order of encoding, as required by HTTP semantics.
26
+ * The special value `identity` is ignored.
27
+ */
28
+ export declare function createDecoders(contentEncoding?: string | string[]): ByteTransform[];
29
+ /**
30
+ * Creates the encoder pipeline for a Content-Encoding or transfer-coding list.
31
+ *
32
+ * @remarks
33
+ * Encoders are returned in the declared order. The special value `identity` is ignored.
34
+ */
35
+ export declare function createEncoders(contentEncoding?: string | string[]): ByteTransform[];
package/encoding.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ export type ByteStream = ReadableStream<Uint8Array>;
2
+ export type ByteTransform = TransformStream<Uint8Array, Uint8Array>;
3
+ /**
4
+ * Applies decoding transforms for the given content-encoding list.
5
+ *
6
+ * @remarks
7
+ * If no supported encodings are provided, the original source is returned unchanged.
8
+ * Async iterables are converted to Web Streams only when transforms are required.
9
+ */
10
+ export declare function decodeStream(stream: ByteStream, contentEncoding?: string | string[]): ByteStream;
11
+ export declare function decodeStream(stream: AsyncIterable<Uint8Array>, contentEncoding?: string | string[]): AsyncIterable<Uint8Array> | ByteStream;
12
+ /**
13
+ * Applies encoding transforms for the given content-encoding list.
14
+ *
15
+ * @remarks
16
+ * If no supported encodings are provided, the original source is returned unchanged.
17
+ * Async iterables are converted to Web Streams only when transforms are required.
18
+ */
19
+ export declare function encodeStream(stream: ByteStream, contentEncoding?: string | string[]): ByteStream;
20
+ export declare function encodeStream(stream: AsyncIterable<Uint8Array>, contentEncoding?: string | string[]): AsyncIterable<Uint8Array> | ByteStream;
21
+ /**
22
+ * Creates the decoder pipeline for a Content-Encoding or transfer-coding list.
23
+ *
24
+ * @remarks
25
+ * Decoding is applied in reverse order of encoding, as required by HTTP semantics.
26
+ * The special value `identity` is ignored.
27
+ */
28
+ export declare function createDecoders(contentEncoding?: string | string[]): ByteTransform[];
29
+ /**
30
+ * Creates the encoder pipeline for a Content-Encoding or transfer-coding list.
31
+ *
32
+ * @remarks
33
+ * Encoders are returned in the declared order. The special value `identity` is ignored.
34
+ */
35
+ export declare function createEncoders(contentEncoding?: string | string[]): ByteTransform[];