UNPKG

14.2 kBTypeScriptView Raw
1/// <reference lib="dom"/>
2
3type Primitive = null | undefined | string | number | boolean | symbol | bigint;
4
5type LiteralUnion<LiteralType extends BaseType, BaseType extends Primitive> =
6 | LiteralType
7 | (BaseType & {_?: never});
8
9export type Input = Request | URL | string;
10
11export type BeforeRequestHook = (
12 request: Request,
13 options: NormalizedOptions,
14) => Request | Response | void | Promise<Request | Response | void>;
15
16export type BeforeRetryHook = (options: {
17 request: Request;
18 response: Response;
19 options: NormalizedOptions;
20 error: Error;
21 retryCount: number;
22}) => void | Promise<void>;
23
24export type AfterResponseHook = (
25 request: Request,
26 options: NormalizedOptions,
27 response: Response,
28) => Response | void | Promise<Response | void>;
29
30export interface DownloadProgress {
31 percent: number;
32 transferredBytes: number;
33
34 /**
35 Note: If it's not possible to retrieve the body size, it will be `0`.
36 */
37 totalBytes: number;
38}
39
40export interface Hooks {
41 /**
42 This hook enables you to modify the request right before it is sent. Ky will make no further changes to the request after this. The hook function receives normalized input and options as arguments. You could, for example, modify `options.headers` here.
43
44 A [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) can be returned from this hook to completely avoid making a HTTP request. This can be used to mock a request, check an internal cache, etc. An **important** consideration when returning a `Response` from this hook is that all the following hooks will be skipped, so **ensure you only return a `Response` from the last hook**.
45
46 @default []
47 */
48 beforeRequest?: BeforeRequestHook[];
49
50 /**
51 This hook enables you to modify the request right before retry. Ky will make no further changes to the request after this. The hook function receives the normalized input and options, an error instance and the retry count as arguments. You could, for example, modify `options.headers` here.
52
53 @example
54 ```
55 import ky from 'ky';
56
57 (async () => {
58 await ky('https://example.com', {
59 hooks: {
60 beforeRetry: [
61 async (input, options, errors, retryCount) => {
62 const token = await ky('https://example.com/refresh-token');
63 options.headers.set('Authorization', `token ${token}`);
64 }
65 ]
66 }
67 });
68 })();
69 ```
70
71 @default []
72 */
73 beforeRetry?: BeforeRetryHook[];
74
75 /**
76 This hook enables you to read and optionally modify the response. The hook function receives normalized input, options, and a clone of the response as arguments. The return value of the hook function will be used by Ky as the response object if it's an instance of [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response).
77
78 @default []
79
80 @example
81 ```
82 import ky from 'ky';
83
84 (async () => {
85 await ky('https://example.com', {
86 hooks: {
87 afterResponse: [
88 (_input, _options, response) => {
89 // You could do something with the response, for example, logging.
90 log(response);
91
92 // Or return a `Response` instance to overwrite the response.
93 return new Response('A different response', {status: 200});
94 },
95
96 // Or retry with a fresh token on a 403 error
97 async (input, options, response) => {
98 if (response.status === 403) {
99 // Get a fresh token
100 const token = await ky('https://example.com/token').text();
101
102 // Retry with the token
103 options.headers.set('Authorization', `token ${token}`);
104
105 return ky(input, options);
106 }
107 }
108 ]
109 }
110 });
111 })();
112 ```
113 */
114 afterResponse?: AfterResponseHook[];
115}
116
117export interface RetryOptions {
118 /**
119 The number of times to retry failed requests.
120
121 @default 2
122 */
123 limit?: number;
124
125 /**
126 The HTTP methods allowed to retry.
127
128 @default ['get', 'put', 'head', 'delete', 'options', 'trace']
129 */
130 methods?: string[];
131
132 /**
133 The HTTP status codes allowed to retry.
134
135 @default [408, 413, 429, 500, 502, 503, 504]
136 */
137 statusCodes?: number[];
138
139 /**
140 The HTTP status codes allowed to retry with a `Retry-After` header.
141
142 @default [413, 429, 503]
143 */
144 afterStatusCodes?: number[];
145
146 /**
147 If the `Retry-After` header is greater than `maxRetryAfter`, the request will be canceled.
148
149 @default Infinity
150 */
151 maxRetryAfter?: number;
152}
153
154/**
155Options are the same as `window.fetch`, with some exceptions.
156*/
157export interface Options extends Omit<RequestInit, 'headers'> {
158 /**
159 HTTP method used to make the request.
160
161 Internally, the standard methods (`GET`, `POST`, `PUT`, `PATCH`, `HEAD` and `DELETE`) are uppercased in order to avoid server errors due to case sensitivity.
162 */
163 method?: LiteralUnion<'get' | 'post' | 'put' | 'delete' | 'patch' | 'head', string>;
164
165 /**
166 HTTP headers used to make the request.
167
168 You can pass a `Headers` instance or a plain object.
169
170 You can remove a header with `.extend()` by passing the header with an `undefined` value.
171
172 @example
173 ```
174 import ky from 'ky';
175
176 const url = 'https://sindresorhus.com';
177
178 const original = ky.create({
179 headers: {
180 rainbow: 'rainbow',
181 unicorn: 'unicorn'
182 }
183 });
184
185 const extended = original.extend({
186 headers: {
187 rainbow: undefined
188 }
189 });
190
191 const response = await extended(url).json();
192
193 console.log('rainbow' in response);
194 //=> false
195
196 console.log('unicorn' in response);
197 //=> true
198 ```
199 */
200 headers?: HeadersInit | {[key: string]: undefined};
201
202 /**
203 Shortcut for sending JSON. Use this instead of the `body` option.
204
205 Accepts any plain object or value, which will be `JSON.stringify()`'d and sent in the body with the correct header set.
206 */
207 json?: unknown;
208
209 /**
210 Search parameters to include in the request URL. Setting this will override all existing search parameters in the input URL.
211
212 Accepts any value supported by [`URLSearchParams()`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/URLSearchParams).
213 */
214 searchParams?: string | {[key: string]: string | number | boolean} | Array<Array<string | number | boolean>> | URLSearchParams;
215
216 /**
217 A prefix to prepend to the `input` URL when making the request. It can be any valid URL, either relative or absolute. A trailing slash `/` is optional and will be added automatically, if needed, when it is joined with `input`. Only takes effect when `input` is a string. The `input` argument cannot start with a slash `/` when using this option.
218
219 Useful when used with [`ky.extend()`](#kyextenddefaultoptions) to create niche-specific Ky-instances.
220
221 Notes:
222 - After `prefixUrl` and `input` are joined, the result is resolved against the [base URL](https://developer.mozilla.org/en-US/docs/Web/API/Node/baseURI) of the page (if any).
223 - Leading slashes in `input` are disallowed when using this option to enforce consistency and avoid confusion about how the `input` URL is handled, given that `input` will not follow the normal URL resolution rules when `prefixUrl` is being used, which changes the meaning of a leading slash.
224
225 @example
226 ```
227 import ky from 'ky';
228
229 // On https://example.com
230
231 (async () => {
232 await ky('unicorn', {prefixUrl: '/api'});
233 //=> 'https://example.com/api/unicorn'
234
235 await ky('unicorn', {prefixUrl: 'https://cats.com'});
236 //=> 'https://cats.com/unicorn'
237 })();
238 ```
239 */
240 prefixUrl?: URL | string;
241
242 /**
243 An object representing `limit`, `methods`, `statusCodes` and `maxRetryAfter` fields for maximum retry count, allowed methods, allowed status codes and maximum [`Retry-After`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) time.
244
245 If `retry` is a number, it will be used as `limit` and other defaults will remain in place.
246
247 If `maxRetryAfter` is set to `undefined`, it will use `options.timeout`. If [`Retry-After`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) header is greater than `maxRetryAfter`, it will cancel the request.
248
249 Delays between retries is calculated with the function `0.3 * (2 ** (retry - 1)) * 1000`, where `retry` is the attempt number (starts from 1).
250
251 @example
252 ```
253 import ky from 'ky';
254
255 (async () => {
256 const parsed = await ky('https://example.com', {
257 retry: {
258 limit: 10,
259 methods: ['get'],
260 statusCodes: [413]
261 }
262 }).json();
263 })();
264 ```
265 */
266 retry?: RetryOptions | number;
267
268 /**
269 Timeout in milliseconds for getting a response. Can not be greater than 2147483647.
270 If set to `false`, there will be no timeout.
271
272 @default 10000
273 */
274 timeout?: number | false;
275
276 /**
277 Hooks allow modifications during the request lifecycle. Hook functions may be async and are run serially.
278 */
279 hooks?: Hooks;
280
281 /**
282 Throw a `HTTPError` for error responses (non-2xx status codes).
283
284 Setting this to `false` may be useful if you are checking for resource availability and are expecting error responses.
285
286 @default true
287 */
288 throwHttpErrors?: boolean;
289
290 /**
291 Download progress event handler.
292
293 @param chunk - Note: It's empty for the first call.
294
295 @example
296 ```
297 import ky from 'ky';
298
299 (async () => {
300 await ky('https://example.com', {
301 onDownloadProgress: (progress, chunk) => {
302 // Example output:
303 // `0% - 0 of 1271 bytes`
304 // `100% - 1271 of 1271 bytes`
305 console.log(`${progress.percent * 100}% - ${progress.transferredBytes} of ${progress.totalBytes} bytes`);
306 }
307 });
308 })();
309 ```
310 */
311 onDownloadProgress?: (progress: DownloadProgress, chunk: Uint8Array) => void;
312}
313
314/**
315Normalized options passed to the `fetch` call and the `beforeRequest` hooks.
316*/
317export interface NormalizedOptions extends RequestInit {
318 // Extended from `RequestInit`, but ensured to be set (not optional).
319 method: RequestInit['method'];
320 credentials: RequestInit['credentials'];
321
322 // Extended from custom `KyOptions`, but ensured to be set (not optional).
323 retry: Options['retry'];
324 prefixUrl: Options['prefixUrl'];
325 onDownloadProgress: Options['onDownloadProgress'];
326}
327
328/**
329Returns a `Response` object with `Body` methods added for convenience. So you can, for example, call `ky.get(input).json()` directly without having to await the `Response` first. When called like that, an appropriate `Accept` header will be set depending on the body method used. Unlike the `Body` methods of `window.Fetch`; these will throw an `HTTPError` if the response status is not in the range of `200...299`. Also, `.json()` will return an empty string if the response status is `204` instead of throwing a parse error due to an empty body.
330*/
331export interface ResponsePromise extends Promise<Response> {
332 arrayBuffer: () => Promise<ArrayBuffer>;
333
334 blob: () => Promise<Blob>;
335
336 formData: () => Promise<FormData>;
337
338 // TODO: Use `json<T extends JSONValue>(): Promise<T>;` when it's fixed in TS.
339 // See https://github.com/microsoft/TypeScript/issues/15300 and https://github.com/sindresorhus/ky/pull/80
340 /**
341 Get the response body as JSON.
342
343 @example
344 ```
345 import ky from 'ky';
346
347 const parsed = await ky(…).json();
348 ```
349
350 @example
351 ```
352 import ky from 'ky';
353
354 interface Result {
355 value: number;
356 }
357
358 const result = await ky(…).json<Result>();
359 ```
360 */
361 json: <T>() => Promise<T>;
362
363 text: () => Promise<string>;
364}
365
366/**
367The error has a response property with the `Response` object.
368*/
369declare class HTTPError extends Error {
370 constructor(response: Response);
371 response: Response;
372}
373
374/**
375The error thrown when the request times out.
376*/
377declare class TimeoutError extends Error {
378 constructor();
379}
380
381declare const ky: {
382 /**
383 Fetch the given `url`.
384
385 @param url - `Request` object, `URL` object, or URL string.
386 @returns A promise with `Body` method added.
387
388 @example
389 ```
390 import ky from 'ky';
391
392 (async () => {
393 const parsed = await ky('https://example.com', {json: {foo: true}}).json();
394
395 console.log(parsed);
396 //=> `{data: '🦄'}`
397 })();
398 ```
399 */
400 (url: Input, options?: Options): ResponsePromise;
401
402 /**
403 Fetch the given `url` using the option `{method: 'get'}`.
404
405 @param url - `Request` object, `URL` object, or URL string.
406 @returns A promise with `Body` methods added.
407 */
408 get: (url: Input, options?: Options) => ResponsePromise;
409
410 /**
411 Fetch the given `url` using the option `{method: 'post'}`.
412
413 @param url - `Request` object, `URL` object, or URL string.
414 @returns A promise with `Body` methods added.
415 */
416 post: (url: Input, options?: Options) => ResponsePromise;
417
418 /**
419 Fetch the given `url` using the option `{method: 'put'}`.
420
421 @param url - `Request` object, `URL` object, or URL string.
422 @returns A promise with `Body` methods added.
423 */
424 put: (url: Input, options?: Options) => ResponsePromise;
425
426 /**
427 Fetch the given `url` using the option `{method: 'delete'}`.
428
429 @param url - `Request` object, `URL` object, or URL string.
430 @returns A promise with `Body` methods added.
431 */
432 delete: (url: Input, options?: Options) => ResponsePromise;
433
434 /**
435 Fetch the given `url` using the option `{method: 'patch'}`.
436
437 @param url - `Request` object, `URL` object, or URL string.
438 @returns A promise with `Body` methods added.
439 */
440 patch: (url: Input, options?: Options) => ResponsePromise;
441
442 /**
443 Fetch the given `url` using the option `{method: 'head'}`.
444
445 @param url - `Request` object, `URL` object, or URL string.
446 @returns A promise with `Body` methods added.
447 */
448 head: (url: Input, options?: Options) => ResponsePromise;
449
450 /**
451 Create a new Ky instance with complete new defaults.
452
453 @returns A new Ky instance.
454 */
455 create: (defaultOptions: Options) => typeof ky;
456
457 /**
458 Create a new Ky instance with some defaults overridden with your own.
459
460 In contrast to `ky.create()`, `ky.extend()` inherits defaults from its parent.
461
462 @returns A new Ky instance.
463 */
464 extend: (defaultOptions: Options) => typeof ky;
465
466 /**
467 A `Symbol` that can be returned by a `beforeRetry` hook to stop the retry.
468 This will also short circuit the remaining `beforeRetry` hooks.
469
470 @example
471 ```
472 import ky from 'ky';
473
474 (async () => {
475 await ky('https://example.com', {
476 hooks: {
477 beforeRetry: [
478 async (request, options, errors, retryCount) => {
479 const shouldStopRetry = await ky('https://example.com/api');
480 if (shouldStopRetry) {
481 return ky.stop;
482 }
483 }
484 ]
485 }
486 });
487 })();
488 ```
489 */
490 readonly stop: unique symbol;
491 readonly TimeoutError: typeof TimeoutError;
492 readonly HTTPError: typeof HTTPError;
493};
494
495declare namespace ky {
496 export type TimeoutError = InstanceType<typeof TimeoutError>;
497 export type HTTPError = InstanceType<typeof HTTPError>;
498}
499
500export default ky;