Skip to content

Commit d176a94

Browse files
docs(types): add API docs for public surface
1 parent e8f4ff8 commit d176a94

16 files changed

Lines changed: 505 additions & 0 deletions

File tree

src/client/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ class WreqClient implements Client {
196196
}
197197
}
198198

199+
/** Creates a reusable client with mergeable default options. */
199200
export function createClient(defaults: ClientDefaults = {}): Client {
200201
return new WreqClient(defaults);
201202
}

src/errors/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@ type RequestErrorOptions = {
99
attempt?: number;
1010
};
1111

12+
/** Base error type used by HTTP and WebSocket operations. */
1213
export class RequestError extends Error {
14+
/** Machine-readable error code when one is available. */
1315
code?: string;
16+
/** Original error that caused this failure. */
1417
cause?: unknown;
18+
/** Request associated with the failure, when available. */
1519
request?: Request;
20+
/** Response associated with the failure, when available. */
1621
response?: Response;
22+
/** Attempt number associated with the failure, when available. */
1723
attempt?: number;
1824

1925
constructor(message: string, options?: RequestErrorOptions) {
@@ -27,7 +33,9 @@ export class RequestError extends Error {
2733
}
2834
}
2935

36+
/** Error raised for disallowed HTTP status codes. */
3037
export class HTTPError extends RequestError {
38+
/** HTTP status code returned by the server. */
3139
status: number;
3240

3341
constructor(message: string, status: number, options?: RequestErrorOptions) {
@@ -37,20 +45,23 @@ export class HTTPError extends RequestError {
3745
}
3846
}
3947

48+
/** Error raised when a request exceeds its configured timeout. */
4049
export class TimeoutError extends RequestError {
4150
constructor(message = 'Request timed out', options?: RequestErrorOptions) {
4251
super(message, { ...options, code: 'ERR_TIMEOUT' });
4352
this.name = 'TimeoutError';
4453
}
4554
}
4655

56+
/** Error raised when an operation is aborted. */
4757
export class AbortError extends RequestError {
4858
constructor(message = 'The operation was aborted', options?: RequestErrorOptions) {
4959
super(message, { ...options, code: 'ERR_ABORTED' });
5060
this.name = 'AbortError';
5161
}
5262
}
5363

64+
/** Error raised for WebSocket connection and I/O failures. */
5465
export class WebSocketError extends RequestError {
5566
constructor(message = 'WebSocket operation failed', options?: RequestErrorOptions) {
5667
super(message, { ...options, code: 'ERR_WEBSOCKET' });

src/headers/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ function isPlainObject(value: unknown): value is Record<string, unknown> {
1919
return prototype === Object.prototype || prototype === null;
2020
}
2121

22+
/** Minimal `Headers` implementation used by the public API. */
2223
export class Headers implements Iterable<HeaderTuple> {
2324
private readonly store = new Map<string, HeaderEntry>();
2425
private entriesList: HeaderTuple[] = [];
@@ -69,6 +70,7 @@ export class Headers implements Iterable<HeaderTuple> {
6970
return { key: trimmed.toLowerCase(), display: trimmed };
7071
}
7172

73+
/** Appends a header value without removing existing values for the same name. */
7274
append(name: string, value: unknown): void {
7375
const normalized = this.normalizeName(name);
7476
const entry = this.store.get(normalized.key);
@@ -88,6 +90,7 @@ export class Headers implements Iterable<HeaderTuple> {
8890
});
8991
}
9092

93+
/** Replaces all existing values for a header name. */
9194
set(name: string, value: unknown): void {
9295
const normalized = this.normalizeName(name);
9396
const stringValue = String(value);
@@ -100,22 +103,26 @@ export class Headers implements Iterable<HeaderTuple> {
100103
name: normalized.display,
101104
values: [stringValue],
102105
});
106+
103107
this.entriesList.push([normalized.display, stringValue]);
104108
}
105109

110+
/** Returns the combined header value for `name`, or `null` when absent. */
106111
get(name: string): string | null {
107112
const normalized = this.normalizeName(name);
108113
const entry = this.store.get(normalized.key);
109114

110115
return entry ? entry.values.join(', ') : null;
111116
}
112117

118+
/** Returns `true` when the header collection contains `name`. */
113119
has(name: string): boolean {
114120
const normalized = this.normalizeName(name);
115121

116122
return this.store.has(normalized.key);
117123
}
118124

125+
/** Removes all values associated with `name`. */
119126
delete(name: string): void {
120127
const normalized = this.normalizeName(name);
121128

@@ -125,6 +132,7 @@ export class Headers implements Iterable<HeaderTuple> {
125132
);
126133
}
127134

135+
/** Converts the header collection into a plain object. */
128136
toObject(): Record<string, string> {
129137
const result: Record<string, string> = {};
130138

@@ -135,10 +143,12 @@ export class Headers implements Iterable<HeaderTuple> {
135143
return result;
136144
}
137145

146+
/** Returns headers as ordered `[name, value]` tuples. */
138147
toTuples(): HeaderTuple[] {
139148
return this.entriesList.map(([name, value]) => [name, value]);
140149
}
141150

151+
/** Returns unique header names preserving their original casing. */
142152
toOriginalNames(): string[] {
143153
const names: string[] = [];
144154
const seen = new Set<string>();
@@ -157,12 +167,14 @@ export class Headers implements Iterable<HeaderTuple> {
157167
return names;
158168
}
159169

170+
/** Iterates over normalized `[name, value]` header entries. */
160171
*entries(): IterableIterator<HeaderTuple> {
161172
for (const entry of this.store.values()) {
162173
yield [entry.name, entry.values.join(', ')];
163174
}
164175
}
165176

177+
/** Iterates over normalized `[name, value]` header entries. */
166178
[Symbol.iterator](): IterableIterator<HeaderTuple> {
167179
return this.entries();
168180
}

src/http/fetch.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
} from './pipeline/redirects';
2525
import { runRetryDelay, shouldRetryRequest } from './pipeline/retries';
2626

27+
/** Performs an HTTP request using the native transport pipeline. */
2728
export async function fetch(input: RequestInput, init?: WreqInit) {
2829
const merged = await mergeInputAndInit(input, init);
2930
const state = (merged.init.context ? { ...merged.init.context } : {}) as Record<string, unknown>;

src/http/request.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,15 @@ import {
1010
toBodyBytes,
1111
} from './body/bytes';
1212

13+
/** WHATWG-style request wrapper used by the public API. */
1314
export class Request {
15+
/** Fully resolved request URL. */
1416
readonly url: string;
17+
/** Uppercased HTTP method. */
1518
readonly method: string;
19+
/** Request headers. */
1620
readonly headers: Headers;
21+
/** Abort signal associated with the request, if any. */
1722
readonly signal: AbortSignal | null;
1823
#bodyBytes: Uint8Array | null;
1924
#multipartBody: globalThis.Request | null;
@@ -52,6 +57,7 @@ export class Request {
5257
this.#setBody(init.body);
5358
}
5459

60+
/** Returns the request body as a readable byte stream. */
5561
get body(): ReadableStream<Uint8Array> | null {
5662
if (this.#bodyUsed || (this.#bodyBytes === null && this.#multipartBody === null)) {
5763
return null;
@@ -68,10 +74,12 @@ export class Request {
6874
return this.#stream;
6975
}
7076

77+
/** Indicates whether the request body has already been consumed. */
7178
get bodyUsed(): boolean {
7279
return this.#bodyUsed;
7380
}
7481

82+
/** Creates a clone whose body can be consumed independently. */
7583
clone(): Request {
7684
if (this.#bodyUsed) {
7785
throw new TypeError('Request body is already used');
@@ -89,22 +97,27 @@ export class Request {
8997
return cloned;
9098
}
9199

100+
/** Reads the request body as UTF-8 text. */
92101
async text(): Promise<string> {
93102
return Buffer.from(await this.#consumeBytes()).toString('utf8');
94103
}
95104

105+
/** Reads the request body as JSON. */
96106
async json<T = unknown>(): Promise<T> {
97107
return JSON.parse(await this.text()) as T;
98108
}
99109

110+
/** Reads the request body as an `ArrayBuffer`. */
100111
async arrayBuffer(): Promise<ArrayBuffer> {
101112
return Uint8Array.from(await this.#consumeBytes()).buffer;
102113
}
103114

115+
/** Reads the request body as a `Blob`. */
104116
async blob(): Promise<Blob> {
105117
return new Blob([await this.#consumeBytes()]);
106118
}
107119

120+
/** Reads the request body as `FormData`. */
108121
async formData(): Promise<FormData> {
109122
if (this.#multipartBody) {
110123
if (this.#bodyUsed) {
@@ -132,6 +145,7 @@ export class Request {
132145
return formData;
133146
}
134147

148+
/** Internal helper that clones the encoded request body bytes. */
135149
async _cloneBodyBytes(): Promise<Uint8Array | null> {
136150
if (this.#bodyBytes !== null) {
137151
return cloneBytes(this.#bodyBytes);
@@ -144,16 +158,19 @@ export class Request {
144158
return new Uint8Array(await this.#multipartBody.clone().arrayBuffer());
145159
}
146160

161+
/** Internal helper that prepares body bytes for native dispatch. */
147162
async _getBodyBytesForDispatch(): Promise<Uint8Array | undefined> {
148163
return (await this._cloneBodyBytes()) ?? undefined;
149164
}
150165

166+
/** Internal helper that marks the request body as consumed. */
151167
_markBodyUsed(): void {
152168
if (this.#bodyBytes !== null || this.#multipartBody !== null) {
153169
this.#bodyUsed = true;
154170
}
155171
}
156172

173+
/** Internal helper that creates a modified request copy. */
157174
_replace(input: {
158175
url?: string;
159176
method?: string;

src/http/response-meta.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,31 @@ import { Readable } from 'node:stream';
22
import type { RequestTimings, RedirectEntry, TlsPeerInfo, WreqResponseMeta } from '../types';
33
import type { Response } from './response';
44

5+
/** Implementation backing the `response.wreq` metadata surface. */
56
export class ResponseMeta implements WreqResponseMeta {
67
constructor(private readonly response: Response) {}
78

9+
/** Cookies parsed from the final response state. */
810
get cookies(): Record<string, string> {
911
return { ...this.response._cookies };
1012
}
1113

14+
/** Raw `Set-Cookie` header values from the final response. */
1215
get setCookies(): string[] {
1316
return [...this.response._setCookies];
1417
}
1518

19+
/** Timing metrics collected for the request. */
1620
get timings(): RequestTimings | undefined {
1721
return this.response._timings ? { ...this.response._timings } : undefined;
1822
}
1923

24+
/** Redirect chain leading to the final response. */
2025
get redirectChain(): RedirectEntry[] {
2126
return [...this.response._redirectChain];
2227
}
2328

29+
/** Parsed `content-length` header value when present. */
2430
get contentLength(): number | undefined {
2531
const value = this.response.headers.get('content-length');
2632

@@ -33,6 +39,7 @@ export class ResponseMeta implements WreqResponseMeta {
3339
return Number.isFinite(parsed) ? parsed : undefined;
3440
}
3541

42+
/** TLS peer certificate information when requested. */
3643
get tls(): TlsPeerInfo | undefined {
3744
return this.response._tls
3845
? {
@@ -46,6 +53,7 @@ export class ResponseMeta implements WreqResponseMeta {
4653
: undefined;
4754
}
4855

56+
/** Converts the response body into a Node.js readable stream. */
4957
readable(): Readable {
5058
const body = this.response.clone().body;
5159

src/http/response.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,19 +95,33 @@ function cloneTlsInfo(value: TlsPeerInfo | undefined): TlsPeerInfo | undefined {
9595
};
9696
}
9797

98+
/** WHATWG-style response wrapper. */
9899
export class Response {
100+
/** HTTP status code. */
99101
readonly status: number;
102+
/** HTTP reason phrase. */
100103
readonly statusText: string;
104+
/** Whether `status` is in the 2xx range. */
101105
readonly ok: boolean;
106+
/** Final response URL. */
102107
readonly url: string;
108+
/** Response headers. */
103109
readonly headers: Headers;
110+
/** Response type exposed for Fetch API compatibility. */
104111
readonly type = 'basic' as const;
112+
/** Extra transport metadata exposed by node-wreq. */
105113
readonly wreq: WreqResponseMeta;
114+
/** Internal cookie map used to build `response.wreq.cookies`. */
106115
_cookies: Record<string, string>;
116+
/** Internal raw `Set-Cookie` list used to build `response.wreq.setCookies`. */
107117
_setCookies: string[];
118+
/** Internal timing metadata used to build `response.wreq.timings`. */
108119
_timings?: RequestTimings;
120+
/** Internal redirect chain used to build `response.wreq.redirectChain`. */
109121
_redirectChain: RedirectEntry[];
122+
/** Internal TLS metadata used to build `response.wreq.tls`. */
110123
_tls?: TlsPeerInfo;
124+
/** Whether the response was produced after at least one redirect hop. */
111125
redirected: boolean;
112126
#payloadBytes: Uint8Array | null;
113127
#bodyHandle: number | null;
@@ -154,49 +168,59 @@ export class Response {
154168
this.#orphanedStreamReaders = [];
155169
}
156170

171+
/** Indicates whether the response body has already been consumed. */
157172
get bodyUsed(): boolean {
158173
return this.#bodyUsed;
159174
}
160175

176+
/** Attaches redirect metadata and returns the same response instance. */
161177
setRedirectMetadata(chain: RedirectEntry[]): this {
162178
this.redirected = chain.length > 0;
163179
this._redirectChain = [...chain];
164180

165181
return this;
166182
}
167183

184+
/** Attaches timing metadata and returns the same response instance. */
168185
setTimings(timings: RequestTimings): this {
169186
this._timings = { ...timings };
170187

171188
return this;
172189
}
173190

191+
/** Returns the response body as a readable byte stream. */
174192
get body(): ReadableStream<Uint8Array> | null {
175193
return this.#ensureStream();
176194
}
177195

196+
/** Reads the response body as text, honoring the declared charset when possible. */
178197
async text(): Promise<string> {
179198
return decodeText(await this.#consumeBytes(), this.headers.get('content-type'));
180199
}
181200

201+
/** Reads the response body as JSON. */
182202
async json<T = unknown>(): Promise<T> {
183203
return JSON.parse(await this.text()) as T;
184204
}
185205

206+
/** Reads the response body as an `ArrayBuffer`. */
186207
async arrayBuffer(): Promise<ArrayBuffer> {
187208
return Uint8Array.from(await this.#consumeBytes()).buffer;
188209
}
189210

211+
/** Reads the response body as a `Blob`. */
190212
async blob(): Promise<Blob> {
191213
return new Blob([await this.#consumeBytes()]);
192214
}
193215

216+
/** Reads the response body as `FormData`. */
194217
async formData(): Promise<FormData> {
195218
const contentType = this.headers.get('content-type') ?? '';
196219

197220
return parseResponseFormData(await this.#consumeBytes(), contentType);
198221
}
199222

223+
/** Creates a clone whose body can be consumed independently. */
200224
clone(): Response {
201225
if (this.#isBodyUnusable()) {
202226
throw new TypeError('Response.clone: Body has already been consumed.');

src/native/profiles.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { getBinding } from './binding';
33

44
let cachedProfiles: BrowserProfile[] | undefined;
55

6+
/** Returns the list of browser profiles supported by the native transport. */
67
export function getProfiles(): BrowserProfile[] {
78
cachedProfiles ??= getBinding().getProfiles() as BrowserProfile[];
89

0 commit comments

Comments
 (0)