Skip to content

Commit aad1347

Browse files
committed
docs: add pages for ky, wretch, make-fetch-happen, needle, typed-rest-client
- Extend index, getting-started, and testing for all adapters - Point MkDocs nav and repo links at proxymesh/javascript-proxy-headers - Core API: prefer needle adapter over raw agent example Made-with: Cursor
1 parent a0bde06 commit aad1347

10 files changed

Lines changed: 486 additions & 16 deletions

File tree

docs/core-api.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ import { fetch, setGlobalDispatcher, Agent } from 'undici';
203203

204204
### With needle
205205

206+
For normal use, prefer the [needle adapter](needle.md) (`proxyNeedleGet` / `createProxyNeedle`), which merges CONNECT headers onto the response. To wire the agent yourself:
207+
206208
```javascript
207209
import { ProxyHeadersAgent } from 'javascript-proxy-headers';
208210
import needle from 'needle';
@@ -211,7 +213,6 @@ const agent = new ProxyHeadersAgent('http://proxy:8080', {
211213
proxyHeaders: { 'X-ProxyMesh-Country': 'US' }
212214
});
213215

214-
// needle accepts custom agent
215216
needle.get('https://httpbin.org/ip', { agent }, (err, resp) => {
216217
console.log(resp.body);
217218
console.log(agent.lastProxyHeaders);

docs/getting-started.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,15 @@ npm install node-fetch
1919
npm install got
2020
npm install undici
2121
npm install superagent
22+
npm install ky
23+
npm install wretch
24+
npm install make-fetch-happen
25+
npm install needle
26+
npm install typed-rest-client
2227
```
2328

29+
Use [ky](ky.md) or [wretch](wretch.md) together with `node-fetch` (the adapters build on the same proxy-aware fetch as the node-fetch module).
30+
2431
## Quick Examples
2532

2633
### axios
@@ -101,6 +108,81 @@ console.log(response.body);
101108
console.log(response.headers['x-proxymesh-ip']);
102109
```
103110

111+
### ky
112+
113+
```javascript
114+
import { createProxyKy } from 'javascript-proxy-headers/ky';
115+
116+
const api = await createProxyKy({
117+
proxy: 'http://user:pass@proxy.example.com:8080',
118+
proxyHeaders: { 'X-ProxyMesh-Country': 'US' },
119+
});
120+
121+
const response = await api('https://httpbin.org/ip');
122+
const data = await response.json();
123+
console.log(data);
124+
console.log(response.proxyHeaders.get('x-proxymesh-ip'));
125+
```
126+
127+
### wretch
128+
129+
```javascript
130+
import { createProxyWretch } from 'javascript-proxy-headers/wretch';
131+
132+
const wretch = await createProxyWretch({
133+
proxy: 'http://user:pass@proxy.example.com:8080',
134+
proxyHeaders: { 'X-ProxyMesh-Country': 'US' },
135+
});
136+
137+
const response = await wretch('https://httpbin.org/ip').get().res();
138+
console.log(await response.json());
139+
console.log(response.proxyHeaders.get('x-proxymesh-ip'));
140+
```
141+
142+
### make-fetch-happen
143+
144+
```javascript
145+
import { createProxyMakeFetchHappen } from 'javascript-proxy-headers/make-fetch-happen';
146+
147+
const fetch = createProxyMakeFetchHappen({
148+
proxy: 'http://user:pass@proxy.example.com:8080',
149+
proxyHeaders: { 'X-ProxyMesh-Country': 'US' },
150+
});
151+
152+
const response = await fetch('https://httpbin.org/ip');
153+
console.log(await response.json());
154+
console.log(response.proxyHeaders.get('x-proxymesh-ip'));
155+
```
156+
157+
### needle
158+
159+
```javascript
160+
import { proxyNeedleGet } from 'javascript-proxy-headers/needle';
161+
162+
const res = await proxyNeedleGet('https://httpbin.org/ip', {
163+
proxy: 'http://user:pass@proxy.example.com:8080',
164+
proxyHeaders: { 'X-ProxyMesh-Country': 'US' },
165+
});
166+
167+
console.log(res.body);
168+
console.log(res.headers['x-proxymesh-ip']);
169+
```
170+
171+
### typed-rest-client
172+
173+
```javascript
174+
import { createProxyRestClient } from 'javascript-proxy-headers/typed-rest-client';
175+
176+
const client = createProxyRestClient({
177+
userAgent: 'my-app',
178+
proxy: 'http://user:pass@proxy.example.com:8080',
179+
proxyHeaders: { 'X-ProxyMesh-Country': 'US' },
180+
});
181+
182+
await client.get('https://httpbin.org/ip');
183+
console.log(client.proxyAgent.lastProxyHeaders?.get('x-proxymesh-ip'));
184+
```
185+
104186
## Understanding Proxy Headers
105187
106188
### Sending Headers to the Proxy
@@ -132,6 +214,10 @@ Proxy response headers from the CONNECT request are captured and made available.
132214
| got | `response.headers['header-name']` (merged) |
133215
| undici | `proxyHeaders.get('header-name')` |
134216
| superagent | `response.headers['header-name']` (merged) |
217+
| ky / wretch | `response.proxyHeaders.get('header-name')` on the fetch `Response` |
218+
| make-fetch-happen | `response.proxyHeaders.get('header-name')` |
219+
| needle | `res.headers['header-name']` (merged where not already set) |
220+
| typed-rest-client | `client.proxyAgent.lastProxyHeaders.get('header-name')` |
135221
136222
## Proxy Authentication
137223

docs/index.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ This library solves both problems for popular JavaScript HTTP libraries.
3131
| [got](got.md) | `javascript-proxy-headers/got` | Human-friendly HTTP client |
3232
| [undici](undici.md) | `javascript-proxy-headers/undici` | Fast HTTP client (Node.js core) |
3333
| [superagent](superagent.md) | `javascript-proxy-headers/superagent` | Flexible HTTP client |
34+
| [ky](ky.md) | `javascript-proxy-headers/ky` | Tiny fetch wrapper (via node-fetch + agent) |
35+
| [wretch](wretch.md) | `javascript-proxy-headers/wretch` | Fetch wrapper (global fetch polyfill) |
36+
| [make-fetch-happen](make-fetch-happen.md) | `javascript-proxy-headers/make-fetch-happen` | npm-style fetch (cache, retries, proxy) |
37+
| [needle](needle.md) | `javascript-proxy-headers/needle` | Lean HTTP client |
38+
| [typed-rest-client](typed-rest-client.md) | `javascript-proxy-headers/typed-rest-client` | Azure / DevOps–style REST client |
3439

3540
## Quick Start
3641

@@ -43,7 +48,7 @@ npm install javascript-proxy-headers
4348
Then install the HTTP library you want to use:
4449

4550
```bash
46-
npm install axios # or node-fetch, got, undici, superagent
51+
npm install axios # or node-fetch, got, undici, superagent, ky, wretch, …
4752
```
4853

4954
!!! note
@@ -84,4 +89,4 @@ We at [ProxyMesh](https://proxymesh.com) created these extension modules to supp
8489

8590
## License
8691

87-
MIT License - see [LICENSE](https://github.com/proxymeshai/javascript-proxy-headers/blob/main/LICENSE) for details.
92+
MIT License - see [LICENSE](https://github.com/proxymesh/javascript-proxy-headers/blob/main/LICENSE) for details.

docs/ky.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# ky
2+
3+
[ky](https://github.com/sindresorhus/ky) is a small HTTP client built on `fetch`. This package wires ky to a custom `fetch` implemented with [node-fetch](node-fetch.md) and `ProxyHeadersAgent`, so CONNECT proxy headers work the same way as in the node-fetch adapter.
4+
5+
## Getting Started
6+
7+
### Prerequisites
8+
9+
```bash
10+
npm install javascript-proxy-headers ky node-fetch
11+
```
12+
13+
`node-fetch` is required because the underlying `fetch` is shared with the node-fetch integration.
14+
15+
### Quick Example
16+
17+
```javascript
18+
import { createProxyKy } from 'javascript-proxy-headers/ky';
19+
20+
const api = await createProxyKy({
21+
proxy: 'http://user:pass@proxy.example.com:8080',
22+
proxyHeaders: { 'X-ProxyMesh-Country': 'US' },
23+
});
24+
25+
const response = await api('https://httpbin.org/ip');
26+
const data = await response.json();
27+
28+
// CONNECT response headers (ProxyResponse)
29+
console.log(response.proxyHeaders.get('x-proxymesh-ip'));
30+
```
31+
32+
## API Reference
33+
34+
### createProxyKy(options)
35+
36+
Creates a ky instance (`ky.create`) whose `fetch` sends custom headers on the proxy CONNECT and surfaces CONNECT response headers on each `Response` as `proxyHeaders`.
37+
38+
**Parameters:**
39+
40+
| Name | Type | Description |
41+
|------|------|-------------|
42+
| `options.proxy` | `string` | Proxy URL (e.g. `http://user:pass@proxy:8080`) |
43+
| `options.proxyHeaders` | `Object` | Headers to send to the proxy on CONNECT |
44+
| `options.onProxyConnect` | `Function` | Called when CONNECT completes: `(headers: Map) => void` |
45+
| `options.kyOptions` | `Object` | Passed to `ky.create()` (prefixUrl, timeout, hooks, etc.) |
46+
47+
**Returns:** `Promise<KyInstance>`
48+
49+
**Example:**
50+
51+
```javascript
52+
import { createProxyKy } from 'javascript-proxy-headers/ky';
53+
54+
const api = await createProxyKy({
55+
proxy: 'http://proxy:8080',
56+
proxyHeaders: {
57+
'X-ProxyMesh-Country': 'US',
58+
'X-ProxyMesh-Session': 'my-session',
59+
},
60+
onProxyConnect: (headers) => {
61+
console.log('CONNECT headers:', headers.get('x-proxymesh-ip'));
62+
},
63+
kyOptions: {
64+
prefixUrl: 'https://api.example.com',
65+
timeout: 30000,
66+
},
67+
});
68+
69+
const res = await api.get('v1/status').json();
70+
```
71+
72+
## Accessing Proxy Headers
73+
74+
Responses are [`ProxyResponse`](node-fetch.md) instances: use `response.proxyHeaders.get('x-proxymesh-ip')` (and the usual `response.json()`, `response.text()`, etc.). Proxy CONNECT failures use the same errors as the underlying fetch stack; see [Core API](core-api.md) for `ConnectError` on the agent.

docs/make-fetch-happen.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# make-fetch-happen
2+
3+
[make-fetch-happen](https://github.com/npm/make-fetch-happen) is npm’s fetch implementation (caching, retries, proxy integration). This package supplies a `ProxyHeadersAgent` as the `agent` option so `@npmcli/agent` uses it as-is, and wraps the returned `Response` so CONNECT response headers are available.
4+
5+
## Getting Started
6+
7+
### Prerequisites
8+
9+
```bash
10+
npm install javascript-proxy-headers make-fetch-happen
11+
```
12+
13+
### Quick Example
14+
15+
```javascript
16+
import { createProxyMakeFetchHappen } from 'javascript-proxy-headers/make-fetch-happen';
17+
18+
const fetch = createProxyMakeFetchHappen({
19+
proxy: 'http://user:pass@proxy.example.com:8080',
20+
proxyHeaders: { 'X-ProxyMesh-Country': 'US' },
21+
});
22+
23+
const response = await fetch('https://httpbin.org/ip');
24+
const data = await response.json();
25+
26+
console.log(response.proxyHeaders.get('x-proxymesh-ip'));
27+
```
28+
29+
## API Reference
30+
31+
### createProxyMakeFetchHappen(options)
32+
33+
Builds `make-fetch-happen` with a `ProxyHeadersAgent`, then wraps the fetch so each response includes `proxyHeaders` from the last CONNECT.
34+
35+
**Parameters:**
36+
37+
| Name | Type | Description |
38+
|------|------|-------------|
39+
| `options.proxy` | `string` | Proxy URL (required) |
40+
| `options.proxyHeaders` | `Object` | Headers to send on CONNECT |
41+
| `options.onProxyConnect` | `Function` | CONNECT callback |
42+
| *(other)* || Any other properties are forwarded to `make-fetch-happen.defaults()` (for example cache, retry, `agent` is set internally) |
43+
44+
**Returns:** A `fetch` function with:
45+
46+
- `.defaults(url, opts)` — same pattern as make-fetch-happen, still wrapped with `ProxyResponse`
47+
- `.proxyAgent` — the `ProxyHeadersAgent` instance (for example `fetch.proxyAgent.lastProxyHeaders`)
48+
49+
**Example:**
50+
51+
```javascript
52+
import { createProxyMakeFetchHappen } from 'javascript-proxy-headers/make-fetch-happen';
53+
54+
const fetch = createProxyMakeFetchHappen({
55+
proxy: 'http://proxy:8080',
56+
proxyHeaders: { 'X-ProxyMesh-Country': 'US' },
57+
onProxyConnect: (h) => console.log(h.get('x-proxymesh-ip')),
58+
});
59+
60+
const scoped = fetch.defaults('https://api.example.com', {
61+
headers: { Accept: 'application/json' },
62+
});
63+
64+
const res = await scoped('/v1/status');
65+
console.log(res.proxyHeaders.get('x-proxymesh-ip'));
66+
```
67+
68+
## Accessing Proxy Headers
69+
70+
Use `response.proxyHeaders.get('x-proxymesh-ip')` on the wrapped response, or read `fetch.proxyAgent.lastProxyHeaders` after a request.
71+
72+
## Synchronous Factory
73+
74+
Unlike some adapters, `createProxyMakeFetchHappen` is **not** async: it returns the wrapped fetch immediately.

docs/needle.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# needle
2+
3+
[needle](https://github.com/tomas/needle) is a lean HTTP client for Node. This package routes HTTPS through `ProxyHeadersAgent` and merges CONNECT response headers into the needle response where the same keys are not already set.
4+
5+
## Getting Started
6+
7+
### Prerequisites
8+
9+
```bash
10+
npm install javascript-proxy-headers needle
11+
```
12+
13+
### Quick Example
14+
15+
```javascript
16+
import { proxyNeedleGet } from 'javascript-proxy-headers/needle';
17+
18+
const res = await proxyNeedleGet('https://httpbin.org/ip', {
19+
proxy: 'http://user:pass@proxy.example.com:8080',
20+
proxyHeaders: { 'X-ProxyMesh-Country': 'US' },
21+
});
22+
23+
console.log(res.body);
24+
// CONNECT headers merged into res.headers when missing
25+
console.log(res.headers['x-proxymesh-ip']);
26+
console.log(res.proxyAgent.lastProxyHeaders);
27+
```
28+
29+
## API Reference
30+
31+
### proxyNeedleGet(url, options)
32+
33+
Promise-based GET with proxy headers. Needle’s proxy handling is disabled (`proxy: null`, `use_proxy_from_env_var: false`) so only `ProxyHeadersAgent` is used.
34+
35+
**Parameters:**
36+
37+
| Name | Type | Description |
38+
|------|------|-------------|
39+
| `url` | `string` | Target URL (HTTPS recommended) |
40+
| `options.proxy` | `string` | Proxy URL (required) |
41+
| `options.proxyHeaders` | `Object` | CONNECT headers |
42+
| `options.onProxyConnect` | `Function` | CONNECT callback |
43+
| `options.needleOptions` | `Object` | Extra options passed to `needle.get` |
44+
45+
**Returns:** `Promise<NeedleResponse>` with `proxyAgent` set to the agent used.
46+
47+
### createProxyNeedle(options)
48+
49+
Returns a small helper bound to one proxy configuration:
50+
51+
**Returns:** `{ get(url, opts?), proxyAgent }`
52+
53+
- `get` — same behavior as `proxyNeedleGet` but merges `needleOptions` from `createProxyNeedle` with per-call `opts`.
54+
- `proxyAgent` — shared `ProxyHeadersAgent`.
55+
56+
```javascript
57+
import { createProxyNeedle } from 'javascript-proxy-headers/needle';
58+
59+
const { get, proxyAgent } = createProxyNeedle({
60+
proxy: 'http://proxy:8080',
61+
proxyHeaders: { 'X-ProxyMesh-Country': 'US' },
62+
needleOptions: { compressed: true },
63+
});
64+
65+
const res = await get('https://httpbin.org/ip');
66+
```
67+
68+
## Accessing Proxy Headers
69+
70+
Prefer `res.headers['x-proxymesh-ip']` after merge, or `res.proxyAgent.lastProxyHeaders` for the raw `Map` from the last CONNECT.
71+
72+
## Core Agent
73+
74+
You can also pass `ProxyHeadersAgent` to needle yourself; see [Core API](core-api.md).

0 commit comments

Comments
 (0)