@npy/fetch 0.1.3 → 0.1.4

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 (141) hide show
  1. package/LICENSE +21 -0
  2. package/_internal/consts.cjs +4 -0
  3. package/_internal/consts.d.cts +3 -0
  4. package/_internal/consts.d.ts +3 -0
  5. package/_internal/consts.js +4 -0
  6. package/_internal/decode-stream-error.cjs +18 -0
  7. package/{src/_internal/decode-stream-error.ts → _internal/decode-stream-error.d.cts} +2 -7
  8. package/_internal/decode-stream-error.d.ts +11 -0
  9. package/_internal/decode-stream-error.js +18 -0
  10. package/_internal/error-mapping.cjs +44 -0
  11. package/_internal/error-mapping.d.cts +15 -0
  12. package/_internal/error-mapping.d.ts +15 -0
  13. package/_internal/error-mapping.js +41 -0
  14. package/_internal/guards.cjs +23 -0
  15. package/_internal/guards.d.cts +15 -0
  16. package/_internal/guards.d.ts +15 -0
  17. package/_internal/guards.js +15 -0
  18. package/_internal/net.cjs +95 -0
  19. package/_internal/net.d.cts +11 -0
  20. package/_internal/net.d.ts +11 -0
  21. package/_internal/net.js +92 -0
  22. package/_internal/promises.cjs +18 -0
  23. package/_internal/promises.d.cts +1 -0
  24. package/_internal/promises.d.ts +1 -0
  25. package/_internal/promises.js +18 -0
  26. package/_internal/streams.cjs +37 -0
  27. package/_internal/streams.d.cts +21 -0
  28. package/_internal/streams.d.ts +21 -0
  29. package/_internal/streams.js +36 -0
  30. package/_internal/symbols.cjs +4 -0
  31. package/_internal/symbols.d.cts +1 -0
  32. package/_internal/symbols.d.ts +1 -0
  33. package/_internal/symbols.js +4 -0
  34. package/_virtual/_rolldown/runtime.cjs +23 -0
  35. package/agent-pool.cjs +96 -0
  36. package/agent-pool.d.cts +2 -0
  37. package/agent-pool.d.ts +2 -0
  38. package/agent-pool.js +95 -0
  39. package/agent.cjs +260 -0
  40. package/agent.d.cts +3 -0
  41. package/agent.d.ts +3 -0
  42. package/agent.js +259 -0
  43. package/body.cjs +105 -0
  44. package/body.d.cts +12 -0
  45. package/body.d.ts +12 -0
  46. package/body.js +102 -0
  47. package/dialers/index.d.cts +3 -0
  48. package/dialers/index.d.ts +3 -0
  49. package/dialers/proxy.cjs +56 -0
  50. package/dialers/proxy.d.cts +27 -0
  51. package/dialers/proxy.d.ts +27 -0
  52. package/dialers/proxy.js +55 -0
  53. package/dialers/tcp.cjs +92 -0
  54. package/dialers/tcp.d.cts +57 -0
  55. package/dialers/tcp.d.ts +57 -0
  56. package/dialers/tcp.js +89 -0
  57. package/encoding.cjs +114 -0
  58. package/encoding.d.cts +35 -0
  59. package/encoding.d.ts +35 -0
  60. package/encoding.js +110 -0
  61. package/errors.cjs +275 -0
  62. package/errors.d.cts +110 -0
  63. package/errors.d.ts +110 -0
  64. package/errors.js +259 -0
  65. package/fetch.cjs +353 -0
  66. package/fetch.d.cts +58 -0
  67. package/fetch.d.ts +58 -0
  68. package/fetch.js +350 -0
  69. package/http-client.cjs +75 -0
  70. package/http-client.d.cts +39 -0
  71. package/http-client.d.ts +39 -0
  72. package/http-client.js +75 -0
  73. package/index.cjs +49 -0
  74. package/index.d.cts +14 -0
  75. package/index.d.ts +14 -0
  76. package/index.js +11 -0
  77. package/io/_utils.cjs +56 -0
  78. package/io/_utils.d.cts +10 -0
  79. package/io/_utils.d.ts +10 -0
  80. package/io/_utils.js +51 -0
  81. package/io/buf-writer.cjs +149 -0
  82. package/io/buf-writer.d.cts +13 -0
  83. package/io/buf-writer.d.ts +13 -0
  84. package/io/buf-writer.js +148 -0
  85. package/io/io.cjs +199 -0
  86. package/io/io.d.cts +5 -0
  87. package/io/io.d.ts +5 -0
  88. package/io/io.js +198 -0
  89. package/io/readers.cjs +337 -0
  90. package/io/readers.d.cts +69 -0
  91. package/io/readers.d.ts +69 -0
  92. package/io/readers.js +333 -0
  93. package/io/writers.cjs +196 -0
  94. package/io/writers.d.cts +22 -0
  95. package/io/writers.d.ts +22 -0
  96. package/io/writers.js +195 -0
  97. package/package.json +30 -25
  98. package/{src/types/agent.ts → types/agent.d.cts} +21 -47
  99. package/types/agent.d.ts +72 -0
  100. package/{src/types/dialer.ts → types/dialer.d.cts} +9 -19
  101. package/types/dialer.d.ts +30 -0
  102. package/types/index.d.cts +2 -0
  103. package/types/index.d.ts +2 -0
  104. package/bun.lock +0 -68
  105. package/examples/custom-proxy-client.ts +0 -32
  106. package/examples/http-client.ts +0 -47
  107. package/examples/proxy.ts +0 -16
  108. package/examples/simple.ts +0 -15
  109. package/src/_internal/consts.ts +0 -3
  110. package/src/_internal/error-mapping.ts +0 -160
  111. package/src/_internal/guards.ts +0 -78
  112. package/src/_internal/net.ts +0 -173
  113. package/src/_internal/promises.ts +0 -22
  114. package/src/_internal/streams.ts +0 -52
  115. package/src/_internal/symbols.ts +0 -1
  116. package/src/agent-pool.ts +0 -157
  117. package/src/agent.ts +0 -408
  118. package/src/body.ts +0 -179
  119. package/src/dialers/index.ts +0 -3
  120. package/src/dialers/proxy.ts +0 -102
  121. package/src/dialers/tcp.ts +0 -162
  122. package/src/encoding.ts +0 -222
  123. package/src/errors.ts +0 -357
  124. package/src/fetch.ts +0 -626
  125. package/src/http-client.ts +0 -111
  126. package/src/index.ts +0 -14
  127. package/src/io/_utils.ts +0 -82
  128. package/src/io/buf-writer.ts +0 -183
  129. package/src/io/io.ts +0 -322
  130. package/src/io/readers.ts +0 -576
  131. package/src/io/writers.ts +0 -331
  132. package/src/types/index.ts +0 -2
  133. package/tests/agent-pool.test.ts +0 -111
  134. package/tests/agent.test.ts +0 -134
  135. package/tests/body.test.ts +0 -228
  136. package/tests/errors.test.ts +0 -152
  137. package/tests/fetch.test.ts +0 -421
  138. package/tests/io-options.test.ts +0 -127
  139. package/tests/multipart.test.ts +0 -348
  140. package/tests/test-utils.ts +0 -335
  141. package/tsconfig.json +0 -15
package/io/writers.js ADDED
@@ -0,0 +1,195 @@
1
+ import { bytesToStream } from "../_internal/streams.js";
2
+ import { createEncoders, encodeStream } from "../encoding.js";
3
+ import { parseContentLength, parseTransferEncoding } from "./_utils.js";
4
+ import { sanitizeHeaderValue } from "./readers.js";
5
+ import { isFumanReadable, isReadableStream } from "../_internal/guards.js";
6
+ import { extractBody } from "../body.js";
7
+ import { BufWriter } from "./buf-writer.js";
8
+ import { nodeReadableToWeb } from "@fuman/node";
9
+ import { Bytes, fumanReadableToWeb, write } from "@fuman/io";
10
+ //#region src/io/writers.ts
11
+ function toRequestTarget(url) {
12
+ return (url.pathname?.startsWith("/") ? url.pathname : "/") + (url.search || "");
13
+ }
14
+ function encodeHead(into, head) {
15
+ write.rawString(into, `${head.method.toUpperCase()} ${head.target} HTTP/1.1\r
16
+ `);
17
+ for (const [k, v] of head.headers) write.rawString(into, `${k}: ${sanitizeHeaderValue(v)}\r
18
+ `);
19
+ write.rawString(into, "\r\n");
20
+ }
21
+ function prepareBody(headers, init) {
22
+ const state = extractBody(init);
23
+ if (state.body != null && !headers.has("content-type")) headers.set("content-type", state.contentType ?? "application/octet-stream");
24
+ const body = state.body;
25
+ if (body == null) return { kind: "none" };
26
+ if (body instanceof Uint8Array) return {
27
+ kind: "bytes",
28
+ bytes: body,
29
+ length: body.byteLength
30
+ };
31
+ if (isReadableStream(body)) return {
32
+ kind: "stream",
33
+ stream: body,
34
+ length: state.contentLength
35
+ };
36
+ if (isFumanReadable(body)) return {
37
+ kind: "stream",
38
+ stream: fumanReadableToWeb(body),
39
+ length: state.contentLength
40
+ };
41
+ return {
42
+ kind: "stream",
43
+ stream: nodeReadableToWeb(body),
44
+ length: state.contentLength
45
+ };
46
+ }
47
+ function finalizeDelimitation(headers, body) {
48
+ if (body.kind === "none") return { chunked: false };
49
+ const te = parseTransferEncoding(headers);
50
+ if (te.has) {
51
+ headers.delete("content-length");
52
+ if (!te.chunked) {
53
+ const tokens = [...te.codings, "chunked"].filter(Boolean);
54
+ headers.set("transfer-encoding", tokens.join(", "));
55
+ }
56
+ return { chunked: true };
57
+ }
58
+ const knownLength = body.kind === "bytes" ? body.length : body.length ?? null;
59
+ if (knownLength != null) {
60
+ const existing = parseContentLength(headers);
61
+ if (existing != null && existing !== knownLength) throw new Error(`Conflicting content-length: header=${existing} body=${knownLength}`);
62
+ if (existing == null) headers.set("content-length", String(knownLength));
63
+ return { chunked: false };
64
+ }
65
+ if (parseContentLength(headers) != null) return { chunked: false };
66
+ headers.set("transfer-encoding", "chunked");
67
+ headers.delete("content-length");
68
+ return { chunked: true };
69
+ }
70
+ function createBufferedConnWriter(dst, opts) {
71
+ const bufferSize = opts.writeBufferSize ?? 16 * 1024;
72
+ const directWriteThreshold = opts.directWriteThreshold ?? 64 * 1024;
73
+ const bufWriter = new BufWriter(dst, bufferSize);
74
+ const flush = async () => {
75
+ await bufWriter.flush();
76
+ };
77
+ const writeBytes = async (bytes) => {
78
+ if (bytes.length === 0) return;
79
+ if (bytes.length >= directWriteThreshold) {
80
+ await bufWriter.flush();
81
+ await dst.write(bytes);
82
+ return;
83
+ }
84
+ await bufWriter.write(bytes);
85
+ };
86
+ const writeRawString = async (str) => {
87
+ if (str.length === 0) return;
88
+ write.rawString(bufWriter, str);
89
+ };
90
+ return {
91
+ flush,
92
+ writeBytes,
93
+ writeRawString,
94
+ directWriteThreshold
95
+ };
96
+ }
97
+ async function writeBody(dst, body, chunked, opts, signal) {
98
+ const bw = createBufferedConnWriter(dst, opts);
99
+ const writeChunk = async (chunk) => {
100
+ if (signal?.aborted) throw signal.reason ?? /* @__PURE__ */ new Error("Request aborted");
101
+ if (!chunked) {
102
+ await bw.writeBytes(chunk);
103
+ return;
104
+ }
105
+ if (chunk.length === 0) return;
106
+ await bw.writeRawString(chunk.length.toString(16));
107
+ await bw.writeRawString("\r\n");
108
+ await bw.writeBytes(chunk);
109
+ await bw.writeRawString("\r\n");
110
+ };
111
+ if (body.kind === "bytes") await writeChunk(body.bytes);
112
+ else for await (const chunk of body.stream) await writeChunk(chunk);
113
+ if (chunked) await bw.writeRawString(`0\r
114
+ \r
115
+ `);
116
+ await bw.flush();
117
+ }
118
+ async function writeCoalesced(dst, scratch, head, bodyBytes, chunked) {
119
+ scratch.reset();
120
+ encodeHead(scratch, head);
121
+ if (!chunked) {
122
+ write.bytes(scratch, bodyBytes);
123
+ await dst.write(scratch.result());
124
+ scratch.reset();
125
+ return;
126
+ }
127
+ write.rawString(scratch, bodyBytes.length.toString(16));
128
+ write.rawString(scratch, "\r\n");
129
+ write.bytes(scratch, bodyBytes);
130
+ write.rawString(scratch, `\r
131
+ 0\r
132
+ \r
133
+ `);
134
+ await dst.write(scratch.result());
135
+ scratch.reset();
136
+ }
137
+ function createRequestWriter(dst, opts = {}) {
138
+ const scratch = Bytes.alloc(opts.writeBufferSize ?? 16 * 1024);
139
+ const write = async (req) => {
140
+ if (req.signal?.aborted) throw req.signal.reason ?? /* @__PURE__ */ new Error("Request aborted");
141
+ const method = req.method.toUpperCase();
142
+ const headers = req.headers ? new Headers(req.headers) : new Headers();
143
+ const url = req.url;
144
+ if (!headers.has("host")) headers.set("host", url.host);
145
+ if (!headers.has("date")) headers.set("date", (/* @__PURE__ */ new Date()).toUTCString());
146
+ const target = toRequestTarget(url);
147
+ let body = prepareBody(headers, req.body ?? null);
148
+ const ceRaw = headers.get("content-encoding") ?? void 0;
149
+ const ceEncoders = createEncoders(ceRaw);
150
+ if (body.kind !== "none" && ceEncoders.length > 0) {
151
+ body = {
152
+ kind: "stream",
153
+ stream: encodeStream(body.kind === "stream" ? body.stream : bytesToStream(body.bytes), ceRaw),
154
+ length: null
155
+ };
156
+ headers.delete("content-length");
157
+ }
158
+ const teInfo = parseTransferEncoding(headers);
159
+ if (body.kind !== "none" && teInfo.has && teInfo.codings.length > 0) {
160
+ body = {
161
+ kind: "stream",
162
+ stream: encodeStream(body.kind === "stream" ? body.stream : bytesToStream(body.bytes), teInfo.codings),
163
+ length: null
164
+ };
165
+ headers.delete("content-length");
166
+ }
167
+ const { chunked } = finalizeDelimitation(headers, body);
168
+ const head = {
169
+ method,
170
+ target,
171
+ headers
172
+ };
173
+ if (body.kind === "bytes") {
174
+ const max = opts.coalesceBodyMaxBytes ?? 64 * 1024;
175
+ if (body.bytes.length <= max) {
176
+ await writeCoalesced(dst, scratch, head, body.bytes, chunked);
177
+ return;
178
+ }
179
+ }
180
+ scratch.reset();
181
+ encodeHead(scratch, head);
182
+ await dst.write(scratch.result());
183
+ scratch.reset();
184
+ if (body.kind === "none") return;
185
+ if (body.kind === "bytes" && !chunked) {
186
+ if (req.signal?.aborted) throw req.signal.reason ?? /* @__PURE__ */ new Error("Request aborted");
187
+ await dst.write(body.bytes);
188
+ return;
189
+ }
190
+ await writeBody(dst, body, chunked, opts, req.signal);
191
+ };
192
+ return { write };
193
+ }
194
+ //#endregion
195
+ export { createRequestWriter };
package/package.json CHANGED
@@ -1,13 +1,9 @@
1
1
  {
2
2
  "name": "@npy/fetch",
3
3
  "type": "module",
4
- "version": "0.1.3",
5
- "license": "MIT",
4
+ "version": "0.1.4",
6
5
  "description": "HTTP/1.1 client built from raw TCP sockets with fetch-compatible primitives and proxy support.",
7
- "sideEffects": false,
8
- "exports": {
9
- ".": "./src/index.ts"
10
- },
6
+ "license": "MIT",
11
7
  "keywords": [
12
8
  "fetch",
13
9
  "http",
@@ -19,29 +15,38 @@
19
15
  "node",
20
16
  "bun"
21
17
  ],
22
- "scripts": {
23
- "bench": "node --import=tsx ./benchmarks/index.ts",
24
- "bench:direct": "node --import=tsx ./benchmarks/direct.ts",
25
- "bench:proxy": "node --import=tsx ./benchmarks/proxy.ts"
26
- },
27
- "devDependencies": {
28
- "@types/bytes": "^3.1.5",
29
- "axios": "^1.8.4",
30
- "got": "^14.4.6",
31
- "hpagent": "^1.2.0",
32
- "http-proxy-agent": "^7.0.2",
33
- "node-fetch": "^3.3.2",
34
- "proxy-chain": "^2.7.1",
35
- "undici": "^7.13.0",
36
- "mitata": "^1.0.34"
37
- },
18
+ "scripts": {},
38
19
  "dependencies": {
39
20
  "@fuman/io": "^0.0.19",
40
21
  "@fuman/net": "^0.0.19",
41
22
  "@fuman/node": "^0.0.19",
42
23
  "@fuman/utils": "^0.0.19",
43
- "@npy/proxy-kit": "workspace:*",
24
+ "@npy/proxy-kit": "0.1.2",
44
25
  "bytes": "^3.1.2",
45
26
  "generic-pool": "^3.9.0"
46
- }
47
- }
27
+ },
28
+ "exports": {
29
+ ".": {
30
+ "import": {
31
+ "types": "./index.d.ts",
32
+ "default": "./index.js"
33
+ },
34
+ "require": {
35
+ "types": "./index.d.cts",
36
+ "default": "./index.cjs"
37
+ }
38
+ }
39
+ },
40
+ "sideEffects": false,
41
+ "homepage": "https://github.com/neeopy/npy",
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/neeopy/npy.git"
45
+ },
46
+ "bugs": {
47
+ "url": "https://github.com/neeopy/npy/issues"
48
+ },
49
+ "files": [
50
+ "**/*"
51
+ ]
52
+ }
@@ -1,15 +1,12 @@
1
- import type { BodyInit } from "../body";
2
- import type { LineReader, Readers } from "../io/readers";
3
- import type { Writers } from "../io/writers";
4
- import type { Dialer } from "./dialer";
5
-
1
+ import { BodyInit } from '../body';
2
+ import { LineReader, Readers } from '../io/readers';
3
+ import { Writers } from '../io/writers';
4
+ import { Dialer } from './dialer';
6
5
  export interface Agent {
7
6
  [Symbol.dispose](): void;
8
7
  close(): void;
9
-
10
8
  readonly hostname: string;
11
9
  readonly port: number;
12
-
13
10
  /**
14
11
  * Sends a single HTTP request and returns the raw {@link Response}.
15
12
  *
@@ -18,81 +15,58 @@ export interface Agent {
18
15
  * Limits configured through reader options are enforced while the body is consumed.
19
16
  */
20
17
  send(options: Agent.SendOptions): Promise<Response>;
21
-
22
18
  whenIdle(): Promise<void>;
23
-
24
19
  readonly isIdle: boolean;
25
20
  readonly lastUsed: number;
26
21
  }
27
-
28
- export namespace Agent {
29
- export interface ConnectOptions {
22
+ export declare namespace Agent {
23
+ interface ConnectOptions {
30
24
  timeout?: number;
31
-
32
25
  keepAlive?: boolean | null;
33
-
34
26
  noDelay?: boolean;
35
27
  }
36
-
37
- export type ReaderOptions = Readers.Options & LineReader.ReadHeadersOptions;
38
-
39
- export type WriterOptions = Writers.Options;
40
-
41
- export interface IOOptions {
28
+ type ReaderOptions = Readers.Options & LineReader.ReadHeadersOptions;
29
+ type WriterOptions = Writers.Options;
30
+ interface IOOptions {
42
31
  reader?: ReaderOptions;
43
32
  writer?: WriterOptions;
44
33
  }
45
-
46
- export interface Options {
34
+ interface Options {
47
35
  connect?: ConnectOptions;
48
36
  io?: IOOptions;
49
37
  }
50
-
51
- export interface SendOptions {
38
+ interface SendOptions {
52
39
  url: string | URL;
53
-
54
40
  method: string;
55
-
56
41
  headers?: Headers;
57
-
58
42
  body?: BodyInit | null;
59
43
  signal?: AbortSignal;
60
44
  }
61
45
  }
62
-
63
46
  export interface AgentPool {
64
47
  [Symbol.asyncDispose](): Promise<void>;
65
48
  close(): Promise<void>;
66
-
67
49
  readonly hostname: string;
68
50
  readonly port: number;
69
-
70
51
  send(options: Agent.SendOptions): Promise<Response>;
71
52
  }
72
-
73
- export namespace AgentPool {
74
- export interface Options {
53
+ export declare namespace AgentPool {
54
+ interface Options {
75
55
  dialer?: Dialer;
76
-
77
56
  poolMaxIdlePerHost?: number;
78
57
  poolMaxPerHost?: number;
79
-
80
58
  poolIdleTimeout?: number | false;
81
-
82
59
  connect?: Agent.ConnectOptions;
83
-
84
60
  io?: Agent.IOOptions;
85
61
  }
86
62
  }
87
-
88
- export interface AgentConnectOptions extends Agent.ConnectOptions {}
89
-
90
- export interface AgentPoolOptions extends AgentPool.Options {}
91
-
92
- export interface SendOptions extends Agent.SendOptions {}
93
-
94
- export interface AgentIOOptions extends Agent.IOOptions {}
95
-
63
+ export interface AgentConnectOptions extends Agent.ConnectOptions {
64
+ }
65
+ export interface AgentPoolOptions extends AgentPool.Options {
66
+ }
67
+ export interface SendOptions extends Agent.SendOptions {
68
+ }
69
+ export interface AgentIOOptions extends Agent.IOOptions {
70
+ }
96
71
  export type AgentReaderOptions = Agent.ReaderOptions;
97
-
98
72
  export type AgentWriterOptions = Agent.WriterOptions;
@@ -0,0 +1,72 @@
1
+ import { BodyInit } from '../body';
2
+ import { LineReader, Readers } from '../io/readers';
3
+ import { Writers } from '../io/writers';
4
+ import { Dialer } from './dialer';
5
+ export interface Agent {
6
+ [Symbol.dispose](): void;
7
+ close(): void;
8
+ readonly hostname: string;
9
+ readonly port: number;
10
+ /**
11
+ * Sends a single HTTP request and returns the raw {@link Response}.
12
+ *
13
+ * @remarks
14
+ * The returned response body preserves the advanced error mapping of this library.
15
+ * Limits configured through reader options are enforced while the body is consumed.
16
+ */
17
+ send(options: Agent.SendOptions): Promise<Response>;
18
+ whenIdle(): Promise<void>;
19
+ readonly isIdle: boolean;
20
+ readonly lastUsed: number;
21
+ }
22
+ export declare namespace Agent {
23
+ interface ConnectOptions {
24
+ timeout?: number;
25
+ keepAlive?: boolean | null;
26
+ noDelay?: boolean;
27
+ }
28
+ type ReaderOptions = Readers.Options & LineReader.ReadHeadersOptions;
29
+ type WriterOptions = Writers.Options;
30
+ interface IOOptions {
31
+ reader?: ReaderOptions;
32
+ writer?: WriterOptions;
33
+ }
34
+ interface Options {
35
+ connect?: ConnectOptions;
36
+ io?: IOOptions;
37
+ }
38
+ interface SendOptions {
39
+ url: string | URL;
40
+ method: string;
41
+ headers?: Headers;
42
+ body?: BodyInit | null;
43
+ signal?: AbortSignal;
44
+ }
45
+ }
46
+ export interface AgentPool {
47
+ [Symbol.asyncDispose](): Promise<void>;
48
+ close(): Promise<void>;
49
+ readonly hostname: string;
50
+ readonly port: number;
51
+ send(options: Agent.SendOptions): Promise<Response>;
52
+ }
53
+ export declare namespace AgentPool {
54
+ interface Options {
55
+ dialer?: Dialer;
56
+ poolMaxIdlePerHost?: number;
57
+ poolMaxPerHost?: number;
58
+ poolIdleTimeout?: number | false;
59
+ connect?: Agent.ConnectOptions;
60
+ io?: Agent.IOOptions;
61
+ }
62
+ }
63
+ export interface AgentConnectOptions extends Agent.ConnectOptions {
64
+ }
65
+ export interface AgentPoolOptions extends AgentPool.Options {
66
+ }
67
+ export interface SendOptions extends Agent.SendOptions {
68
+ }
69
+ export interface AgentIOOptions extends Agent.IOOptions {
70
+ }
71
+ export type AgentReaderOptions = Agent.ReaderOptions;
72
+ export type AgentWriterOptions = Agent.WriterOptions;
@@ -1,40 +1,30 @@
1
- import type { ITcpConnection, ITlsConnection } from "@fuman/net";
2
- import type { NodeTlsConnectOptions } from "@fuman/node";
3
-
1
+ import { ITcpConnection, ITlsConnection } from '@fuman/net';
2
+ import { NodeTlsConnectOptions } from '@fuman/node';
4
3
  /**
5
4
  * Transport abstraction responsible for opening a connection to an HTTP target.
6
5
  */
7
6
  export interface Dialer {
8
- dial(
9
- target: Dialer.Target,
10
- options?: Dialer.Options,
11
- ): Promise<Dialer.ConnectionLike>;
7
+ dial(target: Dialer.Target, options?: Dialer.Options): Promise<Dialer.ConnectionLike>;
12
8
  }
13
-
14
- export namespace Dialer {
15
- export type ConnectionLike = ITcpConnection | ITlsConnection;
16
-
17
- export interface Target {
9
+ export declare namespace Dialer {
10
+ type ConnectionLike = ITcpConnection | ITlsConnection;
11
+ interface Target {
18
12
  address: string;
19
13
  port: number;
20
14
  secure: boolean;
21
-
22
15
  /** Server Name Indication (TLS). Defaults to the host when applicable. */
23
16
  sni?: string;
24
-
25
17
  /** Defaults to ["http/1.1"] when omitted by the dialer implementation. */
26
18
  alpnProtocols?: string[];
27
-
28
19
  /** Extra Node.js TLS options (minVersion, servername, etc.). */
29
20
  extraOptions?: NodeTlsConnectOptions["extraOptions"];
30
21
  }
31
-
32
- export interface Options {
22
+ interface Options {
33
23
  signal?: AbortSignal;
34
24
  }
35
25
  }
36
-
37
26
  /** Back-compat */
38
27
  export type ConnectionLike = Dialer.ConnectionLike;
39
28
  /** Back-compat */
40
- export interface DialTarget extends Dialer.Target {}
29
+ export interface DialTarget extends Dialer.Target {
30
+ }
@@ -0,0 +1,30 @@
1
+ import { ITcpConnection, ITlsConnection } from '@fuman/net';
2
+ import { NodeTlsConnectOptions } from '@fuman/node';
3
+ /**
4
+ * Transport abstraction responsible for opening a connection to an HTTP target.
5
+ */
6
+ export interface Dialer {
7
+ dial(target: Dialer.Target, options?: Dialer.Options): Promise<Dialer.ConnectionLike>;
8
+ }
9
+ export declare namespace Dialer {
10
+ type ConnectionLike = ITcpConnection | ITlsConnection;
11
+ interface Target {
12
+ address: string;
13
+ port: number;
14
+ secure: boolean;
15
+ /** Server Name Indication (TLS). Defaults to the host when applicable. */
16
+ sni?: string;
17
+ /** Defaults to ["http/1.1"] when omitted by the dialer implementation. */
18
+ alpnProtocols?: string[];
19
+ /** Extra Node.js TLS options (minVersion, servername, etc.). */
20
+ extraOptions?: NodeTlsConnectOptions["extraOptions"];
21
+ }
22
+ interface Options {
23
+ signal?: AbortSignal;
24
+ }
25
+ }
26
+ /** Back-compat */
27
+ export type ConnectionLike = Dialer.ConnectionLike;
28
+ /** Back-compat */
29
+ export interface DialTarget extends Dialer.Target {
30
+ }
@@ -0,0 +1,2 @@
1
+ export * from './agent';
2
+ export * from './dialer';
@@ -0,0 +1,2 @@
1
+ export * from './agent';
2
+ export * from './dialer';
package/bun.lock DELETED
@@ -1,68 +0,0 @@
1
- {
2
- "lockfileVersion": 1,
3
- "configVersion": 1,
4
- "workspaces": {
5
- "": {
6
- "name": "@npy/fetch",
7
- "dependencies": {
8
- "@fuman/io": "^0.0.19",
9
- "@fuman/net": "^0.0.19",
10
- "@fuman/node": "^0.0.19",
11
- "@fuman/utils": "^0.0.19",
12
- "bytes": "^3.1.2",
13
- "generic-pool": "^3.9.0",
14
- },
15
- "devDependencies": {
16
- "@biomejs/biome": "2.4.9",
17
- "@types/bun": "latest",
18
- "@types/bytes": "^3.1.5",
19
- },
20
- "peerDependencies": {
21
- "typescript": "^5",
22
- },
23
- },
24
- },
25
- "packages": {
26
- "@biomejs/biome": ["@biomejs/biome@2.4.9", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.9", "@biomejs/cli-darwin-x64": "2.4.9", "@biomejs/cli-linux-arm64": "2.4.9", "@biomejs/cli-linux-arm64-musl": "2.4.9", "@biomejs/cli-linux-x64": "2.4.9", "@biomejs/cli-linux-x64-musl": "2.4.9", "@biomejs/cli-win32-arm64": "2.4.9", "@biomejs/cli-win32-x64": "2.4.9" }, "bin": { "biome": "bin/biome" } }, "sha512-wvZW92FrwitTcacvCBT8xdAbfbxWfDLwjYMmU3djjqQTh7Ni4ZdiWIT/x5VcZ+RQuxiKzIOzi5D+dcyJDFZMsA=="],
27
-
28
- "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-d5G8Gf2RpH5pYwiHLPA+UpG3G9TLQu4WM+VK6sfL7K68AmhcEQ9r+nkj/DvR/GYhYox6twsHUtmWWWIKfcfQQA=="],
29
-
30
- "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-LNCLNgqDMG7BLdc3a8aY/dwKPK7+R8/JXJoXjCvZh2gx8KseqBdFDKbhrr7HCWF8SzNhbTaALhTBoh/I6rf9lA=="],
31
-
32
- "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-4adnkAUi6K4C/emPRgYznMOcLlUqZdXWM6aIui4VP4LraE764g6Q4YguygnAUoxKjKIXIWPteKMgRbN0wsgwcg=="],
33
-
34
- "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-8RCww5xnPn2wpK4L/QDGDOW0dq80uVWfppPxHIUg6mOs9B6gRmqPp32h1Ls3T8GnW8Wo5A8u7vpTwz4fExN+sw=="],
35
-
36
- "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.9", "", { "os": "linux", "cpu": "x64" }, "sha512-L10na7POF0Ks/cgLFNF1ZvIe+X4onLkTi5oP9hY+Rh60Q+7fWzKDDCeGyiHUFf1nGIa9dQOOUPGe2MyYg8nMSQ=="],
37
-
38
- "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.9", "", { "os": "linux", "cpu": "x64" }, "sha512-5TD+WS9v5vzXKzjetF0hgoaNFHMcpQeBUwKKVi3JbG1e9UCrFuUK3Gt185fyTzvRdwYkJJEMqglRPjmesmVv4A=="],
39
-
40
- "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-aDZr0RBC3sMGJOU10BvG7eZIlWLK/i51HRIfScE2lVhfts2dQTreowLiJJd+UYg/tHKxS470IbzpuKmd0MiD6g=="],
41
-
42
- "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.9", "", { "os": "win32", "cpu": "x64" }, "sha512-NS4g/2G9SoQ4ktKtz31pvyc/rmgzlcIDCGU/zWbmHJAqx6gcRj2gj5Q/guXhoWTzCUaQZDIqiCQXHS7BcGYc0w=="],
43
-
44
- "@fuman/io": ["@fuman/io@0.0.19", "", { "dependencies": { "@fuman/utils": "^0.0.19" } }, "sha512-B+2n3GVa9PCYMJ9xfsdXUlUV9yXO4gKLYfxm815PeJ+MGOw5TbEp166drRmBq1AtxVnP0efy6Oz9rYpKVODgow=="],
45
-
46
- "@fuman/net": ["@fuman/net@0.0.19", "", { "dependencies": { "@fuman/io": "^0.0.19", "@fuman/utils": "^0.0.19" } }, "sha512-yISM+JcZEWBpBYn0v2mUY/Zst4SsicTRaVTvRkVhMiZhgMzdXalfvRwRV/vsgwwL31bntwowCTDW4iilCJLbXg=="],
47
-
48
- "@fuman/node": ["@fuman/node@0.0.19", "", { "dependencies": { "@fuman/io": "^0.0.19", "@fuman/net": "^0.0.19", "@fuman/utils": "^0.0.19" }, "peerDependencies": { "ws": "^8.18.1" }, "optionalPeers": ["ws"] }, "sha512-1VNTBb47yrN5BzuXiP4t6An7mDPklH5N+vUtkeL3XATK+xWbtlQsSsU244T7iqGurmDpYrLM9kIUjdMFm8OhDw=="],
49
-
50
- "@fuman/utils": ["@fuman/utils@0.0.19", "", {}, "sha512-4qVrZ9AjKYztLJsNr1Tp7kL48b22dvVLN1iVW+Me8ZSQ0ILN0qknoxjsczVPReF7+GDWgknNxR2l6ggrA4SZyw=="],
51
-
52
- "@types/bun": ["@types/bun@1.3.11", "", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="],
53
-
54
- "@types/bytes": ["@types/bytes@3.1.5", "", {}, "sha512-VgZkrJckypj85YxEsEavcMmmSOIzkUHqWmM4CCyia5dc54YwsXzJ5uT4fYxBQNEXx+oF1krlhgCbvfubXqZYsQ=="],
55
-
56
- "@types/node": ["@types/node@25.5.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw=="],
57
-
58
- "bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="],
59
-
60
- "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
61
-
62
- "generic-pool": ["generic-pool@3.9.0", "", {}, "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g=="],
63
-
64
- "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
65
-
66
- "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
67
- }
68
- }
@@ -1,32 +0,0 @@
1
- import { ProxyDialer } from "../src/dialers/proxy";
2
- import { createFetch } from "../src/fetch";
3
- import { HttpClient } from "../src/http-client";
4
-
5
- const proxyUrl = process.env.HTTP_PROXY as string;
6
-
7
- const client = new HttpClient({
8
- dialer: new ProxyDialer(proxyUrl),
9
- poolMaxPerHost: 16,
10
- poolMaxIdlePerHost: 4,
11
- connect: {
12
- keepAlive: true,
13
- noDelay: true,
14
- },
15
- });
16
-
17
- const fetch = createFetch(client);
18
-
19
- try {
20
- const response = await fetch("https://httpbin.org/ip");
21
-
22
- if (!response.ok) {
23
- throw new Error(`HTTP ${response.status}`);
24
- }
25
-
26
- const data = await response.json();
27
-
28
- console.log("proxy:", proxyUrl);
29
- console.log("origin seen by server:", data.origin);
30
- } finally {
31
- await client.close();
32
- }