tunnelfetch 1.11.0 → 1.13.0
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.
- package/README.md +420 -64
- package/README.zh-CN.md +114 -31
- package/package.json +1 -1
- package/src/connect.js +187 -0
- package/src/index.js +1 -0
- package/src/proxy/http-connect.js +2 -10
- package/src/proxy/socks5.js +2 -10
- package/src/proxy/tunnel.js +110 -0
- package/src/util/bytes.js +35 -18
- package/types/connect.d.ts +78 -0
- package/types/index.d.ts +1 -0
- package/types/proxy/tunnel.d.ts +11 -0
- package/types/util/bytes.d.ts +14 -10
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/** @typedef {import('./proxy/index.js').ConnectFn} ConnectFn */
|
|
2
|
+
/** @typedef {import('./proxy/index.js').Duplex} Duplex */
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {object} ResolveConnectOptions
|
|
5
|
+
* @property {ConnectFn} [connect] an already-obtained socket factory. Checked first and returned
|
|
6
|
+
* as-is, so the recommended path costs no import and cannot be defeated by a bundler.
|
|
7
|
+
* @property {string[]} [specifiers] module specifiers to try, in order. The first module whose
|
|
8
|
+
* `exportName` is callable wins.
|
|
9
|
+
* @property {(specifier: string) => Promise<object>} [importModule] the importer. Defaults to a
|
|
10
|
+
* dynamic `import()`; override it to hand the bundler a literal specifier.
|
|
11
|
+
* @property {string} [exportName] the export to read off each module. Default 'connect'.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Is `value` shaped like a socket factory? Only callability can be checked without dialling, so
|
|
15
|
+
* that is what this checks — the duplex contract is enforced when a socket is actually opened.
|
|
16
|
+
* @param {unknown} value
|
|
17
|
+
* @returns {value is ConnectFn}
|
|
18
|
+
*/
|
|
19
|
+
export function isConnectFn(value: unknown): value is ConnectFn;
|
|
20
|
+
/**
|
|
21
|
+
* Resolve a ConnectFn from an injected factory or from the first module specifier that yields one.
|
|
22
|
+
*
|
|
23
|
+
* Resolution order, and nothing else is consulted:
|
|
24
|
+
* 1. `options.connect`, when callable.
|
|
25
|
+
* 2. each entry of `options.specifiers`, in order.
|
|
26
|
+
*
|
|
27
|
+
* Throws ConfigError (CONFIG_UNSATISFIABLE) when nothing resolves, listing every specifier tried
|
|
28
|
+
* with the reason it failed. A socket factory that cannot be found is a deployment mistake, and a
|
|
29
|
+
* deployment mistake deserves to name the thing that was missing rather than surface later as
|
|
30
|
+
* "connect is not a function" from inside the TLS layer.
|
|
31
|
+
*
|
|
32
|
+
* @param {ResolveConnectOptions} [options]
|
|
33
|
+
* @returns {Promise<ConnectFn>}
|
|
34
|
+
*/
|
|
35
|
+
export function resolveConnect(options?: ResolveConnectOptions): Promise<ConnectFn>;
|
|
36
|
+
/**
|
|
37
|
+
* Flatten a runtime socket into a plain duplex object.
|
|
38
|
+
*
|
|
39
|
+
* Worth its own function because of a trap that has already cost this package a bug: on the edge
|
|
40
|
+
* runtime a socket's `readable` and `writable` are ACCESSORS ON THE PROTOTYPE, so `{ ...socket }`
|
|
41
|
+
* copies neither and the first read fails far away, inside the TLS layer, with "Cannot read
|
|
42
|
+
* properties of undefined (reading 'getReader')". Reading the properties explicitly — which is
|
|
43
|
+
* what this does — is the only spread-safe way to hand a host socket to code that may copy it.
|
|
44
|
+
*
|
|
45
|
+
* @param {Duplex} socket
|
|
46
|
+
* @returns {Duplex}
|
|
47
|
+
*/
|
|
48
|
+
export function normaliseSocket(socket: Duplex): Duplex;
|
|
49
|
+
/**
|
|
50
|
+
* Wrap a ConnectFn so every socket it returns is flattened by normaliseSocket. Useful when the
|
|
51
|
+
* factory comes from a runtime whose sockets are host objects rather than plain records.
|
|
52
|
+
* @param {ConnectFn} connect
|
|
53
|
+
* @returns {ConnectFn}
|
|
54
|
+
*/
|
|
55
|
+
export function normalisingConnect(connect: ConnectFn): ConnectFn;
|
|
56
|
+
export type ConnectFn = import("./proxy/index.js").ConnectFn;
|
|
57
|
+
export type Duplex = import("./proxy/index.js").Duplex;
|
|
58
|
+
export type ResolveConnectOptions = {
|
|
59
|
+
/**
|
|
60
|
+
* an already-obtained socket factory. Checked first and returned
|
|
61
|
+
* as-is, so the recommended path costs no import and cannot be defeated by a bundler.
|
|
62
|
+
*/
|
|
63
|
+
connect?: import("./proxy/index.js").ConnectFn | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* module specifiers to try, in order. The first module whose
|
|
66
|
+
* `exportName` is callable wins.
|
|
67
|
+
*/
|
|
68
|
+
specifiers?: string[] | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* the importer. Defaults to a
|
|
71
|
+
* dynamic `import()`; override it to hand the bundler a literal specifier.
|
|
72
|
+
*/
|
|
73
|
+
importModule?: ((specifier: string) => Promise<object>) | undefined;
|
|
74
|
+
/**
|
|
75
|
+
* the export to read off each module. Default 'connect'.
|
|
76
|
+
*/
|
|
77
|
+
exportName?: string | undefined;
|
|
78
|
+
};
|
package/types/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export { Client, createFetch, install } from "./client.js";
|
|
|
13
13
|
export { ConnectionPool, poolKey } from "./pool.js";
|
|
14
14
|
export { openConnection, targetFromUrl, nativeFetchCanServe } from "./transport.js";
|
|
15
15
|
export { openTunnel, parseProxy } from "./proxy/index.js";
|
|
16
|
+
export { resolveConnect, isConnectFn, normaliseSocket, normalisingConnect } from "./connect.js";
|
|
16
17
|
export { verifyChain, rootStoreProvenance } from "./trust/index.js";
|
|
17
18
|
export { TunnelFetchError, ProxyError, HttpError, TlsError, TlsUnsupportedError, Http2Error, CertificateError, TimeoutError, LimitError, ConfigError, codes } from "./errors.js";
|
|
18
19
|
export { profiles, curl, chrome, applyProfile } from "./profiles.js";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wrap a proxy handshake's buffered reader plus its socket as one byte stream.
|
|
3
|
+
*
|
|
4
|
+
* @param {{ readable: ReadableStream<Uint8Array> }} socket the raw transport
|
|
5
|
+
* @param {import('../util/bytes.js').ByteReader} reader the handshake's reader, possibly holding
|
|
6
|
+
* bytes that belong to the tunnel
|
|
7
|
+
* @returns {ReadableStream<Uint8Array>}
|
|
8
|
+
*/
|
|
9
|
+
export function tunnelReadable(socket: {
|
|
10
|
+
readable: ReadableStream<Uint8Array>;
|
|
11
|
+
}, reader: import("../util/bytes.js").ByteReader): ReadableStream<Uint8Array>;
|
package/types/util/bytes.d.ts
CHANGED
|
@@ -74,21 +74,25 @@ export class UnexpectedEofError extends TunnelFetchError {
|
|
|
74
74
|
* be retained beyond the caller's immediate use if memory matters.
|
|
75
75
|
*
|
|
76
76
|
* When the source is a byte stream — on the target runtime, a socket's readable is one — the
|
|
77
|
-
* reader pulls with BYOB reads
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
77
|
+
* reader pulls with BYOB reads instead of taking the source's own chunking. This is measured, not
|
|
78
|
+
* stylistic: the runtime delivers socket data in chunks of at most 4096 bytes, ~1200 of them for a
|
|
79
|
+
* 4 MB body, and every chunk is a runtime/JS boundary crossing; a BYOB read collects several of
|
|
80
|
+
* them into one.
|
|
81
|
+
*
|
|
82
|
+
* How MANY it collects is the transport's decision, not the view's. A BYOB read resolves the
|
|
83
|
+
* instant any byte is available and never waits to fill, so the view is a ceiling that is normally
|
|
84
|
+
* not reached: measured over a 4 MB body, 37 KB average fill on a direct socket and 8 KB through a
|
|
85
|
+
* proxy, whatever the view size. Sizing the view far above that buys nothing and costs the
|
|
86
|
+
* allocation — see BYOB_PULL_BYTES. Sources that are not byte streams (every in-process
|
|
83
87
|
* ReadableStream in this package and its tests) take the default-reader path unchanged.
|
|
84
88
|
*/
|
|
85
89
|
export class ByteReader {
|
|
86
90
|
/**
|
|
87
91
|
* @param {ReadableStream<Uint8Array>} readable
|
|
88
|
-
* @param {number} [pullBytes] size of each BYOB view pulled from the source. Tunable because
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
+
* @param {number} [pullBytes] size of each BYOB view pulled from the source. Tunable because the
|
|
93
|
+
* right value depends on how much the transport hands over per read, and that differs by a
|
|
94
|
+
* factor of four between a direct socket and a proxied one — see BYOB_PULL_BYTES for the sweep.
|
|
95
|
+
* Ignored on sources that are not byte streams, which take the default-reader path.
|
|
92
96
|
*/
|
|
93
97
|
constructor(readable: ReadableStream<Uint8Array>, pullBytes?: number);
|
|
94
98
|
_pullBytes: number;
|