@memberjunction/network-utils 0.0.0 → 6.1.0-edge.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.
- package/LICENSE +183 -0
- package/README.md +458 -27
- package/dist/HttpClient.d.ts +620 -0
- package/dist/HttpClient.d.ts.map +1 -0
- package/dist/HttpClient.js +670 -0
- package/dist/HttpClient.js.map +1 -0
- package/dist/SSRFGuard.d.ts +168 -0
- package/dist/SSRFGuard.d.ts.map +1 -0
- package/dist/SSRFGuard.js +408 -0
- package/dist/SSRFGuard.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -7
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A dependency-free HTTP client built on Node's native `fetch`.
|
|
3
|
+
*
|
|
4
|
+
* This exists to replace `axios` across the MJ codebase. Node 18+ ships a spec-compliant `fetch`,
|
|
5
|
+
* so a third-party HTTP client buys nothing but supply-chain surface — while costing us the ability
|
|
6
|
+
* to route every outbound request through one place. That one place matters: {@link HttpClient}
|
|
7
|
+
* and {@link HttpRequest} can opt into the SSRF guard in this same package (`ValidateUrl`), which
|
|
8
|
+
* is impossible to enforce when every package reaches for `axios` directly.
|
|
9
|
+
*
|
|
10
|
+
* The shape deliberately mirrors the parts of axios MJ actually used — a config object, a response
|
|
11
|
+
* with a parsed `Data`, a throw-on-non-2xx default, per-instance defaults, and request/retry hooks
|
|
12
|
+
* standing in for interceptors — so call sites port over mechanically.
|
|
13
|
+
*
|
|
14
|
+
* SSRF NOTE: `ValidateUrl` defaults to **false** here. That is intentional. Most MJ call sites talk
|
|
15
|
+
* to fixed, well-known provider endpoints, and some legitimately talk to internal hosts (MJServer
|
|
16
|
+
* posting to its own API, MetadataSync resolving a `@url:` reference on a dev box). Guarding those
|
|
17
|
+
* by default would break them. Set `ValidateUrl: true` — or use {@link SafeFetch} directly —
|
|
18
|
+
* wherever the URL is caller-controlled.
|
|
19
|
+
*/
|
|
20
|
+
/** HTTP methods supported by {@link HttpRequest}. */
|
|
21
|
+
export type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
|
|
22
|
+
/**
|
|
23
|
+
* How to interpret the response body.
|
|
24
|
+
* - `json` — parse as JSON; falls back to raw text when the body is empty or not valid JSON.
|
|
25
|
+
* - `text` — return the body as a string.
|
|
26
|
+
* - `arraybuffer` — return the body as an `ArrayBuffer` (binary downloads).
|
|
27
|
+
* - `blob` — return the body as a `Blob`.
|
|
28
|
+
* - `stream` — return the raw `ReadableStream` body without consuming it.
|
|
29
|
+
* - `none` — discard the body and return `null`.
|
|
30
|
+
*/
|
|
31
|
+
export type HttpResponseType = "json" | "text" | "arraybuffer" | "blob" | "stream" | "none";
|
|
32
|
+
/**
|
|
33
|
+
* Values accepted in a query-string object. Arrays are serialized as repeated keys, and `Date`
|
|
34
|
+
* values as ISO 8601 — matching how axios's default param serializer rendered them.
|
|
35
|
+
*/
|
|
36
|
+
export type HttpQueryValue = string | number | boolean | Date | null | undefined | ReadonlyArray<string | number | boolean | Date>;
|
|
37
|
+
/**
|
|
38
|
+
* The result of a request. Returned for 2xx responses, and — when `ThrowOnError` is disabled —
|
|
39
|
+
* for any response at all.
|
|
40
|
+
*
|
|
41
|
+
* The axios equivalent is its response object, with the fields renamed to MJ's `PascalCase`
|
|
42
|
+
* convention: `data` -> `Data`, `status` -> `Status`, `headers` -> `Headers`.
|
|
43
|
+
*
|
|
44
|
+
* @typeParam T - the shape of the parsed response body. Supply it at the call site
|
|
45
|
+
* (`HttpGet<Payload>(...)`) so `Data` is typed rather than `unknown`.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* interface Repo { id: number; full_name: string }
|
|
50
|
+
* const response = await HttpGet<Repo>('https://api.github.com/repos/a/b');
|
|
51
|
+
* response.Data.full_name; // typed as string
|
|
52
|
+
* response.Status; // 200
|
|
53
|
+
* response.Headers['etag']; // header keys are always lower-cased
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export interface HttpResponse<T = unknown> {
|
|
57
|
+
/** The parsed response body, per the request's `ResponseType`. */
|
|
58
|
+
Data: T;
|
|
59
|
+
/** HTTP status code. */
|
|
60
|
+
Status: number;
|
|
61
|
+
/** HTTP status text. */
|
|
62
|
+
StatusText: string;
|
|
63
|
+
/** Response headers, lower-cased keys. */
|
|
64
|
+
Headers: Record<string, string>;
|
|
65
|
+
/** The final URL the response came from (after any redirects). */
|
|
66
|
+
Url: string;
|
|
67
|
+
/** True when `Status` is in the 2xx range. */
|
|
68
|
+
Ok: boolean;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Everything {@link HttpRequest} accepts. Only `Url` is required.
|
|
72
|
+
*
|
|
73
|
+
* When used through {@link HttpClient}, each field falls back to the client's corresponding
|
|
74
|
+
* option, except `Headers`, which is *merged* over the client's defaults key-by-key.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* await HttpRequest({
|
|
79
|
+
* Url: '/reports',
|
|
80
|
+
* BaseURL: 'https://api.example.com/v2',
|
|
81
|
+
* Method: 'POST',
|
|
82
|
+
* Query: { format: 'json', tag: ['a', 'b'] }, // -> ?format=json&tag=a&tag=b
|
|
83
|
+
* Body: { name: 'Q3' }, // JSON-encoded automatically
|
|
84
|
+
* Timeout: 15000,
|
|
85
|
+
* ValidateUrl: false,
|
|
86
|
+
* });
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export interface HttpRequestConfig {
|
|
90
|
+
/** Target URL. Resolved against `BaseURL` when that is set and this is relative. */
|
|
91
|
+
Url: string;
|
|
92
|
+
/** HTTP method. Default: `GET`. */
|
|
93
|
+
Method?: HttpMethod;
|
|
94
|
+
/** Prefix applied to a relative `Url`. */
|
|
95
|
+
BaseURL?: string;
|
|
96
|
+
/** Request headers. Merged over any client-level defaults. */
|
|
97
|
+
Headers?: Record<string, string>;
|
|
98
|
+
/** Query-string parameters appended to the URL. */
|
|
99
|
+
Query?: Record<string, HttpQueryValue>;
|
|
100
|
+
/**
|
|
101
|
+
* Request body. A plain object or array is JSON-encoded (with a `Content-Type: application/json`
|
|
102
|
+
* default); `string`, `URLSearchParams`, `FormData`, `Blob`, `ArrayBuffer`, and typed arrays are
|
|
103
|
+
* passed through to `fetch` untouched so it can set the right `Content-Type` itself.
|
|
104
|
+
*/
|
|
105
|
+
Body?: unknown;
|
|
106
|
+
/** How to interpret the response body. Default: `json`. */
|
|
107
|
+
ResponseType?: HttpResponseType;
|
|
108
|
+
/** Request timeout in milliseconds. Default: 30000. Pass 0 to disable. */
|
|
109
|
+
Timeout?: number;
|
|
110
|
+
/** When true, run the URL through the SSRF guard (and re-check every redirect hop). Default: false. */
|
|
111
|
+
ValidateUrl?: boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Maximum redirect hops to follow. Default: 5.
|
|
114
|
+
*
|
|
115
|
+
* With `ValidateUrl` off, `0` returns the 3xx response itself rather than following it. With
|
|
116
|
+
* `ValidateUrl` on, {@link SafeFetch} drives redirects manually, so `0` makes a redirected
|
|
117
|
+
* request throw once the cap is hit rather than returning the 3xx.
|
|
118
|
+
*/
|
|
119
|
+
MaxRedirects?: number;
|
|
120
|
+
/** When true (default), a non-2xx status throws {@link HttpError} instead of returning. */
|
|
121
|
+
ThrowOnError?: boolean;
|
|
122
|
+
/** Caller-supplied abort signal, honored alongside `Timeout`. */
|
|
123
|
+
Signal?: AbortSignal;
|
|
124
|
+
/**
|
|
125
|
+
* HTTP Basic credentials. Encoded into an `Authorization: Basic ...` header — the replacement
|
|
126
|
+
* for axios's `auth` option. An explicit `Authorization` header takes precedence.
|
|
127
|
+
*/
|
|
128
|
+
BasicAuth?: {
|
|
129
|
+
Username: string;
|
|
130
|
+
Password: string;
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Thrown for a non-2xx response (when `ThrowOnError` is on), a timeout, a caller-initiated
|
|
135
|
+
* cancellation, or a transport failure.
|
|
136
|
+
*
|
|
137
|
+
* Unlike axios's error — which nests response details under `error.response` and leaves you
|
|
138
|
+
* guessing whether that property exists — every field here is always present. A request that
|
|
139
|
+
* never reached a server reports `Status: 0`, so `error.Status === 404` is safe to write without
|
|
140
|
+
* an optional-chain dance.
|
|
141
|
+
*
|
|
142
|
+
* Distinguish the three failure modes with `Status`, {@link HttpError.IsTimeout}, and
|
|
143
|
+
* {@link HttpError.IsCancelled}.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* try {
|
|
148
|
+
* await client.Get('/thing');
|
|
149
|
+
* } catch (error) {
|
|
150
|
+
* if (!IsHttpError(error)) throw error;
|
|
151
|
+
* if (error.IsCancelled) return; // caller aborted; not a failure
|
|
152
|
+
* if (error.IsTimeout) LogError('upstream slow');
|
|
153
|
+
* else if (error.Status === 404) LogError('missing');
|
|
154
|
+
* else if (error.Status === 429) await backOff(error.Headers['retry-after']);
|
|
155
|
+
* else LogError(`HTTP ${error.Status}`, error.Data);
|
|
156
|
+
* }
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export declare class HttpError extends Error {
|
|
160
|
+
/** HTTP status code, or 0 when the request never produced a response (timeout / network error). */
|
|
161
|
+
readonly Status: number;
|
|
162
|
+
/** HTTP status text, empty when there was no response. */
|
|
163
|
+
readonly StatusText: string;
|
|
164
|
+
/** Parsed response body, when one was received. */
|
|
165
|
+
readonly Data: unknown;
|
|
166
|
+
/** Response headers, lower-cased keys. Empty when there was no response. */
|
|
167
|
+
readonly Headers: Record<string, string>;
|
|
168
|
+
/** The URL that was requested. */
|
|
169
|
+
readonly Url: string;
|
|
170
|
+
/** The HTTP method used. */
|
|
171
|
+
readonly Method: HttpMethod;
|
|
172
|
+
/** True when the failure was this request's own `Timeout` elapsing. */
|
|
173
|
+
readonly IsTimeout: boolean;
|
|
174
|
+
/** True when the caller's own `Signal` aborted the request — the `axios.isCancel` equivalent. */
|
|
175
|
+
readonly IsCancelled: boolean;
|
|
176
|
+
constructor(message: string, details: {
|
|
177
|
+
Status?: number;
|
|
178
|
+
StatusText?: string;
|
|
179
|
+
Data?: unknown;
|
|
180
|
+
Headers?: Record<string, string>;
|
|
181
|
+
Url: string;
|
|
182
|
+
Method: HttpMethod;
|
|
183
|
+
IsTimeout?: boolean;
|
|
184
|
+
IsCancelled?: boolean;
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Narrows an unknown caught value to {@link HttpError} — the replacement for axios's
|
|
189
|
+
* `isAxiosError`.
|
|
190
|
+
*
|
|
191
|
+
* @param error - the value from a `catch` block.
|
|
192
|
+
* @returns true when the value is an {@link HttpError}, narrowing its type for the caller.
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```ts
|
|
196
|
+
* catch (error) {
|
|
197
|
+
* if (IsHttpError(error) && error.Status === 403) { ... }
|
|
198
|
+
* throw error; // anything else is not ours to interpret
|
|
199
|
+
* }
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
export declare function IsHttpError(error: unknown): error is HttpError;
|
|
203
|
+
/**
|
|
204
|
+
* True when a request failed because the caller's own `Signal` aborted it — the replacement for
|
|
205
|
+
* axios's `isCancel`.
|
|
206
|
+
*
|
|
207
|
+
* A request's own {@link HttpRequestConfig.Timeout} elapsing is NOT a cancellation; that reports
|
|
208
|
+
* {@link HttpError.IsTimeout} instead. The distinction matters because a cancellation is usually
|
|
209
|
+
* an expected outcome to swallow, while a timeout is a fault worth logging or retrying.
|
|
210
|
+
*
|
|
211
|
+
* A native `AbortError` — thrown when the signal was already aborted before the request
|
|
212
|
+
* started — also counts.
|
|
213
|
+
*
|
|
214
|
+
* @param error - the value from a `catch` block.
|
|
215
|
+
* @returns true when the failure was caller-initiated cancellation.
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```ts
|
|
219
|
+
* catch (error) {
|
|
220
|
+
* if (IsCancellationError(error)) return null; // the caller gave up; stay quiet
|
|
221
|
+
* throw error;
|
|
222
|
+
* }
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
export declare function IsCancellationError(error: unknown): boolean;
|
|
226
|
+
/**
|
|
227
|
+
* Serializes a parameter object into a URL-encoded query string.
|
|
228
|
+
*
|
|
229
|
+
* Exported because it is occasionally useful on its own; {@link HttpRequest} applies it to
|
|
230
|
+
* `Query` automatically, so you rarely need to call it directly.
|
|
231
|
+
*
|
|
232
|
+
* Rules: `null` and `undefined` entries are omitted entirely (rather than becoming the strings
|
|
233
|
+
* `"null"`/`"undefined"`), arrays expand to repeated keys, and `Date` values render as ISO 8601.
|
|
234
|
+
*
|
|
235
|
+
* @param query - the parameters to serialize.
|
|
236
|
+
* @returns the encoded query string, WITHOUT a leading `?`. Empty when nothing survives.
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* ```ts
|
|
240
|
+
* BuildQueryString({ q: 'a b', tag: ['x', 'y'], skip: null });
|
|
241
|
+
* // 'q=a+b&tag=x&tag=y'
|
|
242
|
+
* ```
|
|
243
|
+
*/
|
|
244
|
+
export declare function BuildQueryString(query: Record<string, HttpQueryValue>): string;
|
|
245
|
+
/**
|
|
246
|
+
* Performs a single HTTP request using native `fetch`. This is the primitive the rest of the
|
|
247
|
+
* module is built on — the method shorthands and {@link HttpClient} all funnel through it.
|
|
248
|
+
*
|
|
249
|
+
* Reach for a shorthand ({@link HttpGet}, {@link HttpPost}, …) for one-off calls, and for
|
|
250
|
+
* {@link HttpClient} when several requests share a base URL, credentials, or retry policy.
|
|
251
|
+
*
|
|
252
|
+
* @typeParam T - the expected shape of the parsed response body.
|
|
253
|
+
* @param config - the request configuration; see {@link HttpRequestConfig}.
|
|
254
|
+
* @returns the {@link HttpResponse}, whose `Data` is parsed per `ResponseType`.
|
|
255
|
+
* @throws {HttpError} on a non-2xx status (unless `ThrowOnError` is disabled), on a timeout, on
|
|
256
|
+
* caller cancellation, or on a transport failure. Inspect `Status` / `IsTimeout` / `IsCancelled`
|
|
257
|
+
* to tell them apart.
|
|
258
|
+
* @throws {SSRFError} when `ValidateUrl` is enabled and the URL — or any redirect hop — resolves
|
|
259
|
+
* to a private or reserved address. This propagates as itself rather than being wrapped in an
|
|
260
|
+
* {@link HttpError}, so a security decision is never mistaken for an unreachable host.
|
|
261
|
+
*
|
|
262
|
+
* @example Reading a JSON payload
|
|
263
|
+
* ```ts
|
|
264
|
+
* const response = await HttpRequest<{ items: Item[] }>({
|
|
265
|
+
* Url: 'https://api.example.com/items',
|
|
266
|
+
* Query: { page: 1 },
|
|
267
|
+
* });
|
|
268
|
+
* return response.Data.items;
|
|
269
|
+
* ```
|
|
270
|
+
*
|
|
271
|
+
* @example Inspecting a non-2xx instead of catching it
|
|
272
|
+
* ```ts
|
|
273
|
+
* const response = await HttpRequest({ Url: url, ThrowOnError: false });
|
|
274
|
+
* if (response.Status === 404) return null;
|
|
275
|
+
* ```
|
|
276
|
+
*/
|
|
277
|
+
export declare function HttpRequest<T = unknown>(config: HttpRequestConfig): Promise<HttpResponse<T>>;
|
|
278
|
+
/**
|
|
279
|
+
* Sends a `GET` request. Shorthand for {@link HttpRequest} with `Method: 'GET'`.
|
|
280
|
+
*
|
|
281
|
+
* @typeParam T - the expected shape of the parsed response body.
|
|
282
|
+
* @param url - absolute URL, or a path when `config.BaseURL` is supplied.
|
|
283
|
+
* @param config - optional per-request settings (query, headers, timeout, …).
|
|
284
|
+
* @returns the {@link HttpResponse}.
|
|
285
|
+
* @throws {HttpError} on a non-2xx status, timeout, cancellation, or transport failure.
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* ```ts
|
|
289
|
+
* const { Data } = await HttpGet<User[]>('https://api.example.com/users', {
|
|
290
|
+
* Query: { active: true },
|
|
291
|
+
* Headers: { Authorization: `Bearer ${token}` },
|
|
292
|
+
* });
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
export declare function HttpGet<T = unknown>(url: string, config?: Omit<HttpRequestConfig, "Url" | "Method" | "Body">): Promise<HttpResponse<T>>;
|
|
296
|
+
/**
|
|
297
|
+
* Sends a `POST` request. Shorthand for {@link HttpRequest} with `Method: 'POST'`.
|
|
298
|
+
*
|
|
299
|
+
* A plain object or array `body` is JSON-encoded and given a JSON `Content-Type`. Pass a
|
|
300
|
+
* `URLSearchParams` for form encoding or a `FormData` for multipart, and `fetch` sets the correct
|
|
301
|
+
* `Content-Type` (including the multipart boundary) itself.
|
|
302
|
+
*
|
|
303
|
+
* @typeParam T - the expected shape of the parsed response body.
|
|
304
|
+
* @param url - absolute URL, or a path when `config.BaseURL` is supplied.
|
|
305
|
+
* @param body - the request body.
|
|
306
|
+
* @param config - optional per-request settings.
|
|
307
|
+
* @returns the {@link HttpResponse}.
|
|
308
|
+
* @throws {HttpError} on a non-2xx status, timeout, cancellation, or transport failure.
|
|
309
|
+
*
|
|
310
|
+
* @example
|
|
311
|
+
* ```ts
|
|
312
|
+
* await HttpPost('https://api.example.com/items', { name: 'Widget' }); // JSON
|
|
313
|
+
* await HttpPost(tokenUrl, new URLSearchParams({ grant_type: 'refresh_token' })); // form
|
|
314
|
+
* ```
|
|
315
|
+
*/
|
|
316
|
+
export declare function HttpPost<T = unknown>(url: string, body?: unknown, config?: Omit<HttpRequestConfig, "Url" | "Method" | "Body">): Promise<HttpResponse<T>>;
|
|
317
|
+
/**
|
|
318
|
+
* Sends a `PUT` request. Shorthand for {@link HttpRequest} with `Method: 'PUT'`.
|
|
319
|
+
* Body handling matches {@link HttpPost}.
|
|
320
|
+
*
|
|
321
|
+
* @typeParam T - the expected shape of the parsed response body.
|
|
322
|
+
* @param url - absolute URL, or a path when `config.BaseURL` is supplied.
|
|
323
|
+
* @param body - the request body.
|
|
324
|
+
* @param config - optional per-request settings.
|
|
325
|
+
* @returns the {@link HttpResponse}.
|
|
326
|
+
* @throws {HttpError} on a non-2xx status, timeout, cancellation, or transport failure.
|
|
327
|
+
*/
|
|
328
|
+
export declare function HttpPut<T = unknown>(url: string, body?: unknown, config?: Omit<HttpRequestConfig, "Url" | "Method" | "Body">): Promise<HttpResponse<T>>;
|
|
329
|
+
/**
|
|
330
|
+
* Sends a `PATCH` request. Shorthand for {@link HttpRequest} with `Method: 'PATCH'`.
|
|
331
|
+
* Body handling matches {@link HttpPost}.
|
|
332
|
+
*
|
|
333
|
+
* @typeParam T - the expected shape of the parsed response body.
|
|
334
|
+
* @param url - absolute URL, or a path when `config.BaseURL` is supplied.
|
|
335
|
+
* @param body - the request body.
|
|
336
|
+
* @param config - optional per-request settings.
|
|
337
|
+
* @returns the {@link HttpResponse}.
|
|
338
|
+
* @throws {HttpError} on a non-2xx status, timeout, cancellation, or transport failure.
|
|
339
|
+
*/
|
|
340
|
+
export declare function HttpPatch<T = unknown>(url: string, body?: unknown, config?: Omit<HttpRequestConfig, "Url" | "Method" | "Body">): Promise<HttpResponse<T>>;
|
|
341
|
+
/**
|
|
342
|
+
* Sends a `DELETE` request. Shorthand for {@link HttpRequest} with `Method: 'DELETE'`.
|
|
343
|
+
*
|
|
344
|
+
* @typeParam T - the expected shape of the parsed response body.
|
|
345
|
+
* @param url - absolute URL, or a path when `config.BaseURL` is supplied.
|
|
346
|
+
* @param config - optional per-request settings.
|
|
347
|
+
* @returns the {@link HttpResponse}.
|
|
348
|
+
* @throws {HttpError} on a non-2xx status, timeout, cancellation, or transport failure.
|
|
349
|
+
*/
|
|
350
|
+
export declare function HttpDelete<T = unknown>(url: string, config?: Omit<HttpRequestConfig, "Url" | "Method" | "Body">): Promise<HttpResponse<T>>;
|
|
351
|
+
/**
|
|
352
|
+
* Sends a `HEAD` request. Shorthand for {@link HttpRequest} with `Method: 'HEAD'`.
|
|
353
|
+
*
|
|
354
|
+
* `ResponseType` is forced to `none` because a HEAD response has no body by definition, so `Data`
|
|
355
|
+
* is always `null` — use `Status` and `Headers`. Pair with `ThrowOnError: false` when probing a
|
|
356
|
+
* URL's reachability, so a 4xx is reported as a status rather than thrown.
|
|
357
|
+
*
|
|
358
|
+
* @typeParam T - unused in practice; `Data` is always `null`.
|
|
359
|
+
* @param url - absolute URL, or a path when `config.BaseURL` is supplied.
|
|
360
|
+
* @param config - optional per-request settings.
|
|
361
|
+
* @returns the {@link HttpResponse}, with `Data` set to `null`.
|
|
362
|
+
* @throws {HttpError} on a non-2xx status (unless `ThrowOnError` is disabled), timeout,
|
|
363
|
+
* cancellation, or transport failure.
|
|
364
|
+
*
|
|
365
|
+
* @example Probing whether a link is alive
|
|
366
|
+
* ```ts
|
|
367
|
+
* const response = await HttpHead(url, { ThrowOnError: false, Timeout: 10000 });
|
|
368
|
+
* const reachable = response.Status >= 200 && response.Status < 400;
|
|
369
|
+
* ```
|
|
370
|
+
*/
|
|
371
|
+
export declare function HttpHead<T = unknown>(url: string, config?: Omit<HttpRequestConfig, "Url" | "Method" | "Body">): Promise<HttpResponse<T>>;
|
|
372
|
+
/**
|
|
373
|
+
* {@link HttpRequest} with the SSRF guard switched on — equivalent to passing
|
|
374
|
+
* `ValidateUrl: true`, but named so a reviewer can see at a glance that the call site handles an
|
|
375
|
+
* untrusted URL.
|
|
376
|
+
*
|
|
377
|
+
* Use this (or set `ValidateUrl` explicitly) wherever the URL can be influenced by an AI agent, an
|
|
378
|
+
* Action parameter, an API caller, or stored data those can write. Prefer {@link SafeFetch} when
|
|
379
|
+
* you want the raw `Response` rather than a parsed body.
|
|
380
|
+
*
|
|
381
|
+
* @typeParam T - the expected shape of the parsed response body.
|
|
382
|
+
* @param config - the request configuration; `ValidateUrl` is forced on.
|
|
383
|
+
* @returns the {@link HttpResponse}.
|
|
384
|
+
* @throws {SSRFError} when the URL, or any redirect hop, resolves to a private or reserved address.
|
|
385
|
+
* @throws {HttpError} on a non-2xx status, timeout, cancellation, or transport failure.
|
|
386
|
+
*
|
|
387
|
+
* @example
|
|
388
|
+
* ```ts
|
|
389
|
+
* try {
|
|
390
|
+
* const response = await SafeHttpRequest({ Url: userSuppliedUrl });
|
|
391
|
+
* return response.Data;
|
|
392
|
+
* } catch (error) {
|
|
393
|
+
* if (error instanceof SSRFError) {
|
|
394
|
+
* return { Success: false, ResultCode: 'SSRF_BLOCKED' };
|
|
395
|
+
* }
|
|
396
|
+
* throw error;
|
|
397
|
+
* }
|
|
398
|
+
* ```
|
|
399
|
+
*/
|
|
400
|
+
export declare function SafeHttpRequest<T = unknown>(config: HttpRequestConfig): Promise<HttpResponse<T>>;
|
|
401
|
+
/**
|
|
402
|
+
* Per-instance defaults and hooks for {@link HttpClient}.
|
|
403
|
+
*
|
|
404
|
+
* The three hooks replace what axios interceptors did, with one important difference: they are
|
|
405
|
+
* plain options on the instance rather than entries appended to a mutable global chain, so what a
|
|
406
|
+
* given client does is visible at its construction site and cannot be changed from elsewhere.
|
|
407
|
+
*
|
|
408
|
+
* | axios | here |
|
|
409
|
+
* |---|---|
|
|
410
|
+
* | `interceptors.request.use(fn)` | {@link HttpClientOptions.OnRequest} |
|
|
411
|
+
* | `interceptors.response.use(onOk)` | {@link HttpClientOptions.OnResponse} |
|
|
412
|
+
* | `interceptors.response.use(_, onErr)` | {@link HttpClientOptions.OnRetry} |
|
|
413
|
+
*/
|
|
414
|
+
export interface HttpClientOptions {
|
|
415
|
+
/** Prefix applied to every relative request URL. */
|
|
416
|
+
BaseURL?: string;
|
|
417
|
+
/** Headers merged under each request's own headers. */
|
|
418
|
+
Headers?: Record<string, string>;
|
|
419
|
+
/** Default request timeout in milliseconds. Default: 30000. */
|
|
420
|
+
Timeout?: number;
|
|
421
|
+
/** When true, every request runs through the SSRF guard. Default: false. */
|
|
422
|
+
ValidateUrl?: boolean;
|
|
423
|
+
/** Default maximum redirect hops. Default: 5. */
|
|
424
|
+
MaxRedirects?: number;
|
|
425
|
+
/** Maximum retry attempts allowed when `OnRetry` asks for one. Default: 3. */
|
|
426
|
+
MaxRetries?: number;
|
|
427
|
+
/** Default HTTP Basic credentials applied to every request. */
|
|
428
|
+
BasicAuth?: {
|
|
429
|
+
Username: string;
|
|
430
|
+
Password: string;
|
|
431
|
+
};
|
|
432
|
+
/**
|
|
433
|
+
* Called before each request with the fully merged config; return the config to actually send.
|
|
434
|
+
* The replacement for an axios request interceptor — this is where token injection, request
|
|
435
|
+
* signing, and per-request query defaults belong.
|
|
436
|
+
*
|
|
437
|
+
* Treat the incoming config as immutable and return a new object; it is re-derived on every
|
|
438
|
+
* retry attempt, so a token read here is always current rather than captured at construction.
|
|
439
|
+
*
|
|
440
|
+
* @example
|
|
441
|
+
* ```ts
|
|
442
|
+
* OnRequest: (config) => ({
|
|
443
|
+
* ...config,
|
|
444
|
+
* Headers: { ...config.Headers, Authorization: `Bearer ${this.getAccessToken()}` },
|
|
445
|
+
* })
|
|
446
|
+
* ```
|
|
447
|
+
*/
|
|
448
|
+
OnRequest?: (config: HttpRequestConfig) => HttpRequestConfig | Promise<HttpRequestConfig>;
|
|
449
|
+
/**
|
|
450
|
+
* Called after each successful response. Observation only: whatever this does, the response is
|
|
451
|
+
* still returned to the caller unchanged. Replaces the success half of an axios response
|
|
452
|
+
* interceptor — logging, metrics, and rate-limit headroom tracking belong here.
|
|
453
|
+
*
|
|
454
|
+
* @example
|
|
455
|
+
* ```ts
|
|
456
|
+
* OnResponse: (response) => {
|
|
457
|
+
* const remaining = response.Headers['x-rate-limit-remaining'];
|
|
458
|
+
* if (remaining) LogStatus(`Rate limit remaining: ${remaining}`);
|
|
459
|
+
* }
|
|
460
|
+
* ```
|
|
461
|
+
*/
|
|
462
|
+
OnResponse?: (response: HttpResponse<unknown>) => void | Promise<void>;
|
|
463
|
+
/**
|
|
464
|
+
* Called when a request fails. Return `true` to retry, `false` to let the error propagate.
|
|
465
|
+
* Replaces the error half of an axios response interceptor — 429 back-off, and one-shot token
|
|
466
|
+
* refresh on a 401, belong here.
|
|
467
|
+
*
|
|
468
|
+
* Retries are bounded by `MaxRetries` (default 3) so a hook that always returns `true` cannot
|
|
469
|
+
* loop forever. Await the back-off inside the hook; the retry fires as soon as it resolves, and
|
|
470
|
+
* `OnRequest` runs again first, so a refreshed token is picked up automatically.
|
|
471
|
+
*
|
|
472
|
+
* Only an {@link HttpError} reaches this hook — an {@link SSRFError} is a security decision and
|
|
473
|
+
* is never retried.
|
|
474
|
+
*
|
|
475
|
+
* @example
|
|
476
|
+
* ```ts
|
|
477
|
+
* OnRetry: async (error, attempt) => {
|
|
478
|
+
* if (error.Status !== 429) return false;
|
|
479
|
+
* const retryAfter = Number(error.Headers['retry-after']) || 2 ** attempt;
|
|
480
|
+
* await new Promise((r) => setTimeout(r, retryAfter * 1000));
|
|
481
|
+
* return true;
|
|
482
|
+
* }
|
|
483
|
+
* ```
|
|
484
|
+
*/
|
|
485
|
+
OnRetry?: (error: HttpError, attempt: number) => boolean | Promise<boolean>;
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* A configured HTTP client — the replacement for `axios.create(...)`.
|
|
489
|
+
*
|
|
490
|
+
* Holds a base URL, default headers, a timeout, and the {@link HttpClientOptions} hooks that stand
|
|
491
|
+
* in for axios interceptors. Construct one per upstream API, typically behind a lazy getter on a
|
|
492
|
+
* provider base class so the cost is paid only when that provider is actually used.
|
|
493
|
+
*
|
|
494
|
+
* Instances are stateless apart from their options and safe to share across concurrent requests.
|
|
495
|
+
* Nothing is cached between calls, so a client whose `OnRequest` reads a token always sends the
|
|
496
|
+
* current one.
|
|
497
|
+
*
|
|
498
|
+
* @example A provider client with auth injection and 429 back-off
|
|
499
|
+
* ```ts
|
|
500
|
+
* private _client: HttpClient | null = null;
|
|
501
|
+
*
|
|
502
|
+
* protected get httpClient(): HttpClient {
|
|
503
|
+
* if (!this._client) {
|
|
504
|
+
* this._client = new HttpClient({
|
|
505
|
+
* BaseURL: 'https://graph.facebook.com/v18.0',
|
|
506
|
+
* Timeout: 30000,
|
|
507
|
+
* Headers: { Accept: 'application/json' },
|
|
508
|
+
*
|
|
509
|
+
* // Runs before every attempt, so a refreshed token is picked up automatically.
|
|
510
|
+
* OnRequest: (config) => ({
|
|
511
|
+
* ...config,
|
|
512
|
+
* Query: { ...config.Query, access_token: this.getAccessToken() },
|
|
513
|
+
* }),
|
|
514
|
+
*
|
|
515
|
+
* // Bounded by MaxRetries (default 3).
|
|
516
|
+
* OnRetry: async (error) => {
|
|
517
|
+
* if (error.Status !== 429) return false;
|
|
518
|
+
* await this.handleRateLimit(60);
|
|
519
|
+
* return true;
|
|
520
|
+
* },
|
|
521
|
+
* });
|
|
522
|
+
* }
|
|
523
|
+
* return this._client;
|
|
524
|
+
* }
|
|
525
|
+
*
|
|
526
|
+
* // Then, at the call sites:
|
|
527
|
+
* const response = await this.httpClient.Get<FacebookPagedResponse<Post>>('/me/feed');
|
|
528
|
+
* return response.Data.data;
|
|
529
|
+
* ```
|
|
530
|
+
*/
|
|
531
|
+
export declare class HttpClient {
|
|
532
|
+
private readonly _options;
|
|
533
|
+
constructor(options?: HttpClientOptions);
|
|
534
|
+
/**
|
|
535
|
+
* The options this client was constructed with. Read-only — a client's behavior is fixed at
|
|
536
|
+
* construction, so build a second client rather than trying to mutate one.
|
|
537
|
+
*/
|
|
538
|
+
get Options(): Readonly<HttpClientOptions>;
|
|
539
|
+
/**
|
|
540
|
+
* Sends a request using this client's defaults and hooks. Every other method on the class
|
|
541
|
+
* delegates here.
|
|
542
|
+
*
|
|
543
|
+
* Per-request values win over client defaults, except `Headers`, which are merged key-by-key so
|
|
544
|
+
* one request can override a single default header without discarding the rest. `OnRequest`
|
|
545
|
+
* then gets the last word on the merged config.
|
|
546
|
+
*
|
|
547
|
+
* @typeParam T - the expected shape of the parsed response body.
|
|
548
|
+
* @param config - per-request configuration, merged over the client's defaults.
|
|
549
|
+
* @returns the {@link HttpResponse}.
|
|
550
|
+
* @throws {HttpError} when the request fails and `OnRetry` does not ask for another attempt, or
|
|
551
|
+
* once `MaxRetries` is exhausted.
|
|
552
|
+
* @throws {SSRFError} when `ValidateUrl` is enabled and the target resolves to a blocked
|
|
553
|
+
* address. Never retried.
|
|
554
|
+
*/
|
|
555
|
+
Request<T = unknown>(config: HttpRequestConfig): Promise<HttpResponse<T>>;
|
|
556
|
+
/**
|
|
557
|
+
* Sends a `GET` request through this client.
|
|
558
|
+
*
|
|
559
|
+
* @typeParam T - the expected shape of the parsed response body.
|
|
560
|
+
* @param url - absolute URL, or a path resolved against the client's `BaseURL`.
|
|
561
|
+
* @param config - optional per-request settings, merged over the client's defaults.
|
|
562
|
+
* @returns the {@link HttpResponse}.
|
|
563
|
+
* @throws {HttpError} on a non-2xx status, timeout, cancellation, or transport failure.
|
|
564
|
+
*/
|
|
565
|
+
Get<T = unknown>(url: string, config?: Omit<HttpRequestConfig, "Url" | "Method" | "Body">): Promise<HttpResponse<T>>;
|
|
566
|
+
/**
|
|
567
|
+
* Sends a `POST` request through this client. Body handling matches {@link HttpPost}.
|
|
568
|
+
*
|
|
569
|
+
* @typeParam T - the expected shape of the parsed response body.
|
|
570
|
+
* @param url - absolute URL, or a path resolved against the client's `BaseURL`.
|
|
571
|
+
* @param body - the request body.
|
|
572
|
+
* @param config - optional per-request settings, merged over the client's defaults.
|
|
573
|
+
* @returns the {@link HttpResponse}.
|
|
574
|
+
* @throws {HttpError} on a non-2xx status, timeout, cancellation, or transport failure.
|
|
575
|
+
*/
|
|
576
|
+
Post<T = unknown>(url: string, body?: unknown, config?: Omit<HttpRequestConfig, "Url" | "Method" | "Body">): Promise<HttpResponse<T>>;
|
|
577
|
+
/**
|
|
578
|
+
* Sends a `PUT` request through this client. Body handling matches {@link HttpPost}.
|
|
579
|
+
*
|
|
580
|
+
* @typeParam T - the expected shape of the parsed response body.
|
|
581
|
+
* @param url - absolute URL, or a path resolved against the client's `BaseURL`.
|
|
582
|
+
* @param body - the request body.
|
|
583
|
+
* @param config - optional per-request settings, merged over the client's defaults.
|
|
584
|
+
* @returns the {@link HttpResponse}.
|
|
585
|
+
* @throws {HttpError} on a non-2xx status, timeout, cancellation, or transport failure.
|
|
586
|
+
*/
|
|
587
|
+
Put<T = unknown>(url: string, body?: unknown, config?: Omit<HttpRequestConfig, "Url" | "Method" | "Body">): Promise<HttpResponse<T>>;
|
|
588
|
+
/**
|
|
589
|
+
* Sends a `PATCH` request through this client. Body handling matches {@link HttpPost}.
|
|
590
|
+
*
|
|
591
|
+
* @typeParam T - the expected shape of the parsed response body.
|
|
592
|
+
* @param url - absolute URL, or a path resolved against the client's `BaseURL`.
|
|
593
|
+
* @param body - the request body.
|
|
594
|
+
* @param config - optional per-request settings, merged over the client's defaults.
|
|
595
|
+
* @returns the {@link HttpResponse}.
|
|
596
|
+
* @throws {HttpError} on a non-2xx status, timeout, cancellation, or transport failure.
|
|
597
|
+
*/
|
|
598
|
+
Patch<T = unknown>(url: string, body?: unknown, config?: Omit<HttpRequestConfig, "Url" | "Method" | "Body">): Promise<HttpResponse<T>>;
|
|
599
|
+
/**
|
|
600
|
+
* Sends a `DELETE` request through this client.
|
|
601
|
+
*
|
|
602
|
+
* @typeParam T - the expected shape of the parsed response body.
|
|
603
|
+
* @param url - absolute URL, or a path resolved against the client's `BaseURL`.
|
|
604
|
+
* @param config - optional per-request settings, merged over the client's defaults.
|
|
605
|
+
* @returns the {@link HttpResponse}.
|
|
606
|
+
* @throws {HttpError} on a non-2xx status, timeout, cancellation, or transport failure.
|
|
607
|
+
*/
|
|
608
|
+
Delete<T = unknown>(url: string, config?: Omit<HttpRequestConfig, "Url" | "Method" | "Body">): Promise<HttpResponse<T>>;
|
|
609
|
+
/**
|
|
610
|
+
* Sends a `HEAD` request through this client. `ResponseType` is forced to `none`, so `Data` is always `null`.
|
|
611
|
+
*
|
|
612
|
+
* @typeParam T - the expected shape of the parsed response body.
|
|
613
|
+
* @param url - absolute URL, or a path resolved against the client's `BaseURL`.
|
|
614
|
+
* @param config - optional per-request settings, merged over the client's defaults.
|
|
615
|
+
* @returns the {@link HttpResponse}.
|
|
616
|
+
* @throws {HttpError} on a non-2xx status, timeout, cancellation, or transport failure.
|
|
617
|
+
*/
|
|
618
|
+
Head<T = unknown>(url: string, config?: Omit<HttpRequestConfig, "Url" | "Method" | "Body">): Promise<HttpResponse<T>>;
|
|
619
|
+
}
|
|
620
|
+
//# sourceMappingURL=HttpClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpClient.d.ts","sourceRoot":"","sources":["../src/HttpClient.ts"],"names":[],"mappings":"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"}
|