stealth-fetch 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.
Potentially problematic release.
This version of stealth-fetch might be problematic. Click here for more details.
- package/LICENSE +21 -0
- package/README.md +183 -0
- package/dist/client.d.ts +99 -0
- package/dist/client.js +1117 -0
- package/dist/compat/web.d.ts +15 -0
- package/dist/compat/web.js +31 -0
- package/dist/connection-pool.d.ts +39 -0
- package/dist/connection-pool.js +84 -0
- package/dist/dns-cache.d.ts +25 -0
- package/dist/dns-cache.js +44 -0
- package/dist/http1/chunked.d.ts +35 -0
- package/dist/http1/chunked.js +87 -0
- package/dist/http1/client.d.ts +28 -0
- package/dist/http1/client.js +289 -0
- package/dist/http1/parser.d.ts +29 -0
- package/dist/http1/parser.js +78 -0
- package/dist/http2/client.d.ts +64 -0
- package/dist/http2/client.js +97 -0
- package/dist/http2/connection.d.ts +125 -0
- package/dist/http2/connection.js +666 -0
- package/dist/http2/constants.d.ts +72 -0
- package/dist/http2/constants.js +74 -0
- package/dist/http2/flow-control.d.ts +32 -0
- package/dist/http2/flow-control.js +76 -0
- package/dist/http2/framer.d.ts +47 -0
- package/dist/http2/framer.js +133 -0
- package/dist/http2/hpack.d.ts +54 -0
- package/dist/http2/hpack.js +186 -0
- package/dist/http2/parser.d.ts +35 -0
- package/dist/http2/parser.js +72 -0
- package/dist/http2/stream.d.ts +72 -0
- package/dist/http2/stream.js +252 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +33 -0
- package/dist/protocol-cache.d.ts +14 -0
- package/dist/protocol-cache.js +29 -0
- package/dist/socket/adapter.d.ts +59 -0
- package/dist/socket/adapter.js +145 -0
- package/dist/socket/nat64.d.ts +69 -0
- package/dist/socket/nat64.js +196 -0
- package/dist/socket/tls.d.ts +28 -0
- package/dist/socket/tls.js +33 -0
- package/dist/socket/wasm-pkg/wasm_tls.d.ts +107 -0
- package/dist/socket/wasm-pkg/wasm_tls.js +568 -0
- package/dist/socket/wasm-pkg/wasm_tls_bg.wasm +0 -0
- package/dist/socket/wasm-pkg/wasm_tls_bg.wasm.d.ts +20 -0
- package/dist/socket/wasm-tls-adapter.d.ts +40 -0
- package/dist/socket/wasm-tls-adapter.js +102 -0
- package/dist/socket/wasm-tls-bridge.d.ts +30 -0
- package/dist/socket/wasm-tls-bridge.js +187 -0
- package/dist/utils/headers.d.ts +21 -0
- package/dist/utils/headers.js +36 -0
- package/dist/utils/url.d.ts +16 -0
- package/dist/utils/url.js +12 -0
- package/package.json +87 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* HTTP/1.1 response parser.
|
|
5
|
+
* State machine that parses raw bytes into structured response objects.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
interface ParsedResponse {
|
|
9
|
+
httpVersion: string;
|
|
10
|
+
status: number;
|
|
11
|
+
statusText: string;
|
|
12
|
+
headers: Record<string, string>;
|
|
13
|
+
/** Raw headers preserving original order and multi-values */
|
|
14
|
+
rawHeaders: Array<[string, string]>;
|
|
15
|
+
/** How the body should be read */
|
|
16
|
+
bodyMode: "content-length" | "chunked" | "close";
|
|
17
|
+
/** Content-Length value (if bodyMode is "content-length") */
|
|
18
|
+
contentLength: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Parse HTTP/1.1 response status line and headers from raw data.
|
|
22
|
+
* Returns null if not enough data has been received yet.
|
|
23
|
+
*/
|
|
24
|
+
declare function parseResponseHead(data: Buffer): {
|
|
25
|
+
response: ParsedResponse;
|
|
26
|
+
bodyStart: number;
|
|
27
|
+
} | null;
|
|
28
|
+
|
|
29
|
+
export { type ParsedResponse, parseResponseHead };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
const DOUBLE_CRLF = Buffer.from("\r\n\r\n");
|
|
3
|
+
function parseResponseHead(data) {
|
|
4
|
+
const headerEnd = bufferIndexOf(data, DOUBLE_CRLF);
|
|
5
|
+
if (headerEnd === -1) return null;
|
|
6
|
+
const headSection = data.subarray(0, headerEnd).toString("latin1");
|
|
7
|
+
const bodyStart = headerEnd + 4;
|
|
8
|
+
const lines = headSection.split("\r\n");
|
|
9
|
+
if (lines.length === 0) return null;
|
|
10
|
+
const statusLine = lines[0];
|
|
11
|
+
const firstSpace = statusLine.indexOf(" ");
|
|
12
|
+
if (firstSpace === -1) return null;
|
|
13
|
+
const httpVersion = statusLine.substring(0, firstSpace);
|
|
14
|
+
const rest = statusLine.substring(firstSpace + 1);
|
|
15
|
+
const secondSpace = rest.indexOf(" ");
|
|
16
|
+
const status = secondSpace === -1 ? parseInt(rest, 10) : parseInt(rest.substring(0, secondSpace), 10);
|
|
17
|
+
if (isNaN(status) || status < 100 || status > 999) return null;
|
|
18
|
+
const statusText = secondSpace === -1 ? "" : rest.substring(secondSpace + 1);
|
|
19
|
+
const headers = {};
|
|
20
|
+
const rawHeaders = [];
|
|
21
|
+
for (let i = 1; i < lines.length; i++) {
|
|
22
|
+
const line = lines[i];
|
|
23
|
+
const colonIdx = line.indexOf(":");
|
|
24
|
+
if (colonIdx === -1) continue;
|
|
25
|
+
const key = line.substring(0, colonIdx).trim().toLowerCase();
|
|
26
|
+
const value = line.substring(colonIdx + 1).trim();
|
|
27
|
+
rawHeaders.push([key, value]);
|
|
28
|
+
if (headers[key]) {
|
|
29
|
+
headers[key] += key === "set-cookie" ? `
|
|
30
|
+
${value}` : `, ${value}`;
|
|
31
|
+
} else {
|
|
32
|
+
headers[key] = value;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
let bodyMode = "close";
|
|
36
|
+
let contentLength = 0;
|
|
37
|
+
if (headers["transfer-encoding"]) {
|
|
38
|
+
if (headers["transfer-encoding"].includes("chunked")) {
|
|
39
|
+
bodyMode = "chunked";
|
|
40
|
+
}
|
|
41
|
+
} else if (headers["content-length"]) {
|
|
42
|
+
const cl = parseInt(headers["content-length"], 10);
|
|
43
|
+
if (!isNaN(cl) && cl >= 0) {
|
|
44
|
+
bodyMode = "content-length";
|
|
45
|
+
contentLength = cl;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
response: {
|
|
50
|
+
httpVersion,
|
|
51
|
+
status,
|
|
52
|
+
statusText,
|
|
53
|
+
headers,
|
|
54
|
+
rawHeaders,
|
|
55
|
+
bodyMode,
|
|
56
|
+
contentLength
|
|
57
|
+
},
|
|
58
|
+
bodyStart
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function bufferIndexOf(haystack, needle) {
|
|
62
|
+
const len = needle.length;
|
|
63
|
+
const limit = haystack.length - len;
|
|
64
|
+
for (let i = 0; i <= limit; i++) {
|
|
65
|
+
let found = true;
|
|
66
|
+
for (let j = 0; j < len; j++) {
|
|
67
|
+
if (haystack[i + j] !== needle[j]) {
|
|
68
|
+
found = false;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (found) return i;
|
|
73
|
+
}
|
|
74
|
+
return -1;
|
|
75
|
+
}
|
|
76
|
+
export {
|
|
77
|
+
parseResponseHead
|
|
78
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ParsedUrl } from '../utils/url.js';
|
|
2
|
+
import { Http2Connection, ConnectionOptions } from './connection.js';
|
|
3
|
+
import 'node:buffer';
|
|
4
|
+
import 'node:events';
|
|
5
|
+
import 'node:stream';
|
|
6
|
+
import './stream.js';
|
|
7
|
+
import './constants.js';
|
|
8
|
+
import './flow-control.js';
|
|
9
|
+
|
|
10
|
+
interface Http2RequestOptions {
|
|
11
|
+
method?: string;
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
body?: Uint8Array | ReadableStream<Uint8Array> | null;
|
|
14
|
+
/** Timeout waiting for response headers (ms) */
|
|
15
|
+
headersTimeout?: number;
|
|
16
|
+
/** Timeout waiting for response body data (idle, ms) */
|
|
17
|
+
bodyTimeout?: number;
|
|
18
|
+
}
|
|
19
|
+
interface Http2Response {
|
|
20
|
+
status: number;
|
|
21
|
+
headers: Record<string, string>;
|
|
22
|
+
rawHeaders: Array<[string, string]>;
|
|
23
|
+
protocol: "h2";
|
|
24
|
+
body: ReadableStream<Uint8Array>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* HTTP/2 client. Manages a single connection and allows multiple requests
|
|
28
|
+
* (via stream multiplexing).
|
|
29
|
+
*/
|
|
30
|
+
declare class Http2Client {
|
|
31
|
+
private connection;
|
|
32
|
+
private constructor();
|
|
33
|
+
/**
|
|
34
|
+
* Create an Http2Client from an already-initialized Http2Connection.
|
|
35
|
+
* Used by auto-negotiation when the TLS socket is already established.
|
|
36
|
+
*/
|
|
37
|
+
static fromConnection(connection: Http2Connection): Http2Client;
|
|
38
|
+
/**
|
|
39
|
+
* Connect to a server and perform HTTP/2 handshake via WASM TLS (with ALPN).
|
|
40
|
+
* Uses non-blocking SETTINGS: preface is sent immediately, handshake
|
|
41
|
+
* completes in parallel with the first request's header encoding.
|
|
42
|
+
*/
|
|
43
|
+
static connect(hostname: string, port?: number, tls?: boolean, options?: ConnectionOptions, connectHostname?: string, signal?: AbortSignal): Promise<Http2Client>;
|
|
44
|
+
/**
|
|
45
|
+
* Send an HTTP/2 request and return the response.
|
|
46
|
+
*/
|
|
47
|
+
request(url: string | ParsedUrl, options?: Http2RequestOptions): Promise<Http2Response>;
|
|
48
|
+
/** Whether the connection is still usable */
|
|
49
|
+
get isReady(): boolean;
|
|
50
|
+
/** Number of currently active streams */
|
|
51
|
+
get activeStreamCount(): number;
|
|
52
|
+
/** Remote peer's MAX_CONCURRENT_STREAMS */
|
|
53
|
+
get maxConcurrentStreams(): number;
|
|
54
|
+
/** Whether the connection can accept another stream */
|
|
55
|
+
get hasCapacity(): boolean;
|
|
56
|
+
/** Register a callback for GOAWAY events */
|
|
57
|
+
onGoaway(callback: () => void): void;
|
|
58
|
+
/** Remove a GOAWAY callback */
|
|
59
|
+
offGoaway(callback: () => void): void;
|
|
60
|
+
/** Close the connection */
|
|
61
|
+
close(): Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export { Http2Client, type Http2RequestOptions, type Http2Response };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
import { createWasmTLSSocket, createPlainSocket } from "../socket/tls.js";
|
|
3
|
+
import { parseUrl } from "../utils/url.js";
|
|
4
|
+
import { buildPseudoHeaders, mergeHeaders } from "../utils/headers.js";
|
|
5
|
+
import { Http2Connection } from "./connection.js";
|
|
6
|
+
class Http2Client {
|
|
7
|
+
connection;
|
|
8
|
+
constructor(connection) {
|
|
9
|
+
this.connection = connection;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Create an Http2Client from an already-initialized Http2Connection.
|
|
13
|
+
* Used by auto-negotiation when the TLS socket is already established.
|
|
14
|
+
*/
|
|
15
|
+
static fromConnection(connection) {
|
|
16
|
+
return new Http2Client(connection);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Connect to a server and perform HTTP/2 handshake via WASM TLS (with ALPN).
|
|
20
|
+
* Uses non-blocking SETTINGS: preface is sent immediately, handshake
|
|
21
|
+
* completes in parallel with the first request's header encoding.
|
|
22
|
+
*/
|
|
23
|
+
static async connect(hostname, port = 443, tls = true, options = {}, connectHostname, signal) {
|
|
24
|
+
const socket = tls ? await createWasmTLSSocket(hostname, port, ["h2"], connectHostname, signal) : await createPlainSocket(connectHostname ?? hostname, port);
|
|
25
|
+
const connection = new Http2Connection(socket, options);
|
|
26
|
+
await connection.startInitialize();
|
|
27
|
+
return new Http2Client(connection);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Send an HTTP/2 request and return the response.
|
|
31
|
+
*/
|
|
32
|
+
async request(url, options = {}) {
|
|
33
|
+
const parsed = typeof url === "string" ? parseUrl(url) : url;
|
|
34
|
+
const method = options.method ?? "GET";
|
|
35
|
+
const pseudo = buildPseudoHeaders(method, parsed.hostname, parsed.path, parsed.protocol);
|
|
36
|
+
const allHeaders = mergeHeaders(pseudo, options.headers ?? {});
|
|
37
|
+
const isStreamBody = options.body instanceof ReadableStream;
|
|
38
|
+
if (options.body && !isStreamBody && options.body.byteLength > 0) {
|
|
39
|
+
const hasContentLength = allHeaders.some(([name]) => name === "content-length");
|
|
40
|
+
if (!hasContentLength) {
|
|
41
|
+
allHeaders.push(["content-length", String(options.body.byteLength)]);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const stream = this.connection.createStream();
|
|
45
|
+
if (options.bodyTimeout !== void 0) {
|
|
46
|
+
stream.setBodyTimeout(options.bodyTimeout);
|
|
47
|
+
}
|
|
48
|
+
const hasBody = isStreamBody || options.body && !isStreamBody && options.body.byteLength > 0;
|
|
49
|
+
await this.connection.sendHeaders(stream, allHeaders, !hasBody);
|
|
50
|
+
if (hasBody && options.body) {
|
|
51
|
+
if (isStreamBody) {
|
|
52
|
+
await this.connection.sendData(stream, options.body, true);
|
|
53
|
+
} else {
|
|
54
|
+
await this.connection.sendData(stream, Buffer.from(options.body), true);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const responseData = await stream.waitForResponse(options.headersTimeout);
|
|
58
|
+
return {
|
|
59
|
+
status: responseData.status,
|
|
60
|
+
headers: responseData.headers,
|
|
61
|
+
rawHeaders: responseData.rawHeaders,
|
|
62
|
+
protocol: "h2",
|
|
63
|
+
body: stream.body
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** Whether the connection is still usable */
|
|
67
|
+
get isReady() {
|
|
68
|
+
return this.connection.isReady;
|
|
69
|
+
}
|
|
70
|
+
/** Number of currently active streams */
|
|
71
|
+
get activeStreamCount() {
|
|
72
|
+
return this.connection.activeStreamCount;
|
|
73
|
+
}
|
|
74
|
+
/** Remote peer's MAX_CONCURRENT_STREAMS */
|
|
75
|
+
get maxConcurrentStreams() {
|
|
76
|
+
return this.connection.maxConcurrentStreams;
|
|
77
|
+
}
|
|
78
|
+
/** Whether the connection can accept another stream */
|
|
79
|
+
get hasCapacity() {
|
|
80
|
+
return this.isReady && this.activeStreamCount < this.maxConcurrentStreams;
|
|
81
|
+
}
|
|
82
|
+
/** Register a callback for GOAWAY events */
|
|
83
|
+
onGoaway(callback) {
|
|
84
|
+
this.connection.on("goaway", callback);
|
|
85
|
+
}
|
|
86
|
+
/** Remove a GOAWAY callback */
|
|
87
|
+
offGoaway(callback) {
|
|
88
|
+
this.connection.removeListener("goaway", callback);
|
|
89
|
+
}
|
|
90
|
+
/** Close the connection */
|
|
91
|
+
async close() {
|
|
92
|
+
await this.connection.close();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export {
|
|
96
|
+
Http2Client
|
|
97
|
+
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import { EventEmitter } from 'node:events';
|
|
3
|
+
import { Duplex } from 'node:stream';
|
|
4
|
+
import { Http2Stream } from './stream.js';
|
|
5
|
+
import './constants.js';
|
|
6
|
+
import './flow-control.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* HTTP/2 connection management.
|
|
10
|
+
* Handles the full lifecycle: preface, SETTINGS exchange, frame dispatch,
|
|
11
|
+
* stream creation, and graceful shutdown.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
interface ConnectionOptions {
|
|
15
|
+
/** Maximum header table size for HPACK (default: 1024 to save CPU) */
|
|
16
|
+
headerTableSize?: number;
|
|
17
|
+
/** Initial stream window size for flow control (default: 2 MiB) */
|
|
18
|
+
initialWindowSize?: number;
|
|
19
|
+
/** Connection-level receive window size (default: 4 MiB) */
|
|
20
|
+
connectionWindowSize?: number;
|
|
21
|
+
/** Timeout for SETTINGS exchange in ms (default: 5000) */
|
|
22
|
+
settingsTimeout?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* HTTP/2 connection over a raw socket.
|
|
26
|
+
* Call initialize() after construction to perform the h2 handshake.
|
|
27
|
+
*/
|
|
28
|
+
declare class Http2Connection extends EventEmitter {
|
|
29
|
+
private socket;
|
|
30
|
+
private parser;
|
|
31
|
+
private hpackEncoder;
|
|
32
|
+
private hpackDecoder;
|
|
33
|
+
private remoteSettings;
|
|
34
|
+
private localSettings;
|
|
35
|
+
private nextStreamId;
|
|
36
|
+
private streams;
|
|
37
|
+
private connectionSendWindow;
|
|
38
|
+
private connectionRecvWindowSize;
|
|
39
|
+
private connectionRecvWindowConsumed;
|
|
40
|
+
private goawayReceived;
|
|
41
|
+
private goawaySent;
|
|
42
|
+
private initialized;
|
|
43
|
+
private closed;
|
|
44
|
+
private lastRemoteInitialWindowSize;
|
|
45
|
+
private pendingWrites;
|
|
46
|
+
private flushScheduled;
|
|
47
|
+
private flushPromiseResolvers;
|
|
48
|
+
private settingsAckResolve;
|
|
49
|
+
private remoteSettingsResolve;
|
|
50
|
+
private readyPromise;
|
|
51
|
+
private settingsTimeout;
|
|
52
|
+
private continuationStreamId;
|
|
53
|
+
private continuationBuffer;
|
|
54
|
+
private continuationBufferSize;
|
|
55
|
+
private continuationEndStream;
|
|
56
|
+
constructor(socket: Duplex, options?: ConnectionOptions);
|
|
57
|
+
/**
|
|
58
|
+
* Initialize the HTTP/2 connection.
|
|
59
|
+
* Sends connection preface + SETTINGS, waits for peer SETTINGS + ACK.
|
|
60
|
+
*/
|
|
61
|
+
initialize(timeout?: number): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Non-blocking initialization: sends connection preface + SETTINGS
|
|
64
|
+
* immediately without waiting for the peer's response.
|
|
65
|
+
* Call waitForReady() before sending the first request.
|
|
66
|
+
*/
|
|
67
|
+
startInitialize(): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Wait for the peer's SETTINGS + ACK to complete the handshake.
|
|
70
|
+
* Must be called after startInitialize().
|
|
71
|
+
*/
|
|
72
|
+
waitForReady(timeout?: number): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Create a new HTTP/2 stream for a request.
|
|
75
|
+
*/
|
|
76
|
+
createStream(): Http2Stream;
|
|
77
|
+
/**
|
|
78
|
+
* Send HEADERS frame for a stream.
|
|
79
|
+
* Handles CONTINUATION if header block exceeds max frame size.
|
|
80
|
+
* Auto-waits for SETTINGS exchange if not yet complete.
|
|
81
|
+
*/
|
|
82
|
+
sendHeaders(stream: Http2Stream, headers: Array<[string, string]>, endStream: boolean): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Send DATA frame(s) for a stream, respecting flow control.
|
|
85
|
+
* Accepts Buffer (buffered) or ReadableStream (streaming).
|
|
86
|
+
*/
|
|
87
|
+
sendData(stream: Http2Stream, data: Buffer | ReadableStream<Uint8Array>, endStream: boolean): Promise<void>;
|
|
88
|
+
private sendBufferData;
|
|
89
|
+
/** Stream a ReadableStream body as DATA frames with flow control (pull model). */
|
|
90
|
+
private sendStreamData;
|
|
91
|
+
/**
|
|
92
|
+
* Gracefully close the connection.
|
|
93
|
+
*/
|
|
94
|
+
close(): Promise<void>;
|
|
95
|
+
private handleFrame;
|
|
96
|
+
private handleDataFrame;
|
|
97
|
+
private handleHeadersFrame;
|
|
98
|
+
private processHeaderBlock;
|
|
99
|
+
private handleSettingsFrame;
|
|
100
|
+
private handleWindowUpdateFrame;
|
|
101
|
+
private handlePingFrame;
|
|
102
|
+
private handleGoawayFrame;
|
|
103
|
+
private handleRstStreamFrame;
|
|
104
|
+
/** Send GOAWAY with given error code and close the connection. */
|
|
105
|
+
private sendGoawayAndClose;
|
|
106
|
+
private handleError;
|
|
107
|
+
private handleSocketClose;
|
|
108
|
+
/**
|
|
109
|
+
* Queue a frame for writing. Frames queued in the same microtask
|
|
110
|
+
* are coalesced into a single socket.write() call.
|
|
111
|
+
*/
|
|
112
|
+
private writeRaw;
|
|
113
|
+
/** Flush all pending writes as a single socket.write(). */
|
|
114
|
+
private flush;
|
|
115
|
+
/** Write multiple frames as a single socket.write() immediately (no microtask delay). */
|
|
116
|
+
private writeMulti;
|
|
117
|
+
/** Whether the connection has been initialized and is usable */
|
|
118
|
+
get isReady(): boolean;
|
|
119
|
+
/** Number of currently active (open) streams */
|
|
120
|
+
get activeStreamCount(): number;
|
|
121
|
+
/** Remote peer's MAX_CONCURRENT_STREAMS setting (default: 100) */
|
|
122
|
+
get maxConcurrentStreams(): number;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export { type ConnectionOptions, Http2Connection };
|