diff --git a/types/got/got-tests.ts b/types/got/got-tests.ts index 1626cae86a..f1f88845d5 100644 --- a/types/got/got-tests.ts +++ b/types/got/got-tests.ts @@ -286,3 +286,75 @@ got('http://todomvc.com', { // Test got.TimeoutError. got('http://todomvc.com', {timeout: 1}).catch((err) => err instanceof got.TimeoutError); + +// Test hooks. +got('example.com', { + hooks: { + beforeRedirect: [ + options => { + if (options.hostname === 'deadSite') { + options.hostname = 'fallbackSite'; + } + } + ] + } +}); +got('example.com', { + hooks: { + beforeRetry: [ + (options, error, retryCount) => { + if (error.statusCode === 413) { // Payload too large + options.body = 'test'; + } + } + ] + } +}); +got('example.com', { + hooks: { + afterResponse: [ + (response, retryWithMergedOptions) => { + if (response.statusCode === 401) { // Unauthorized + const updatedOptions = { + headers: { + token: 'new token' // Refresh the access token + } + }; + + // Make a new retry + return retryWithMergedOptions(updatedOptions); + } + + // No changes otherwise + return response; + } + ] + } +}); +// Test async hooks. +{ + const doSomethingAsync = () => { + throw new Error('unimplemented'); + }; + + got('example.com', { + hooks: { + beforeRedirect: [ + async () => { + await doSomethingAsync(); + } + ], + beforeRetry: [ + async () => { + await doSomethingAsync(); + } + ], + afterResponse: [ + async (response) => { + await doSomethingAsync(); + return response; + } + ] + } + }); +} diff --git a/types/got/index.d.ts b/types/got/index.d.ts index 079e84ff62..0ceb6b945c 100644 --- a/types/got/index.d.ts +++ b/types/got/index.d.ts @@ -1,4 +1,4 @@ -// Type definitions for got 9.2 +// Type definitions for got 9.3 // Project: https://github.com/sindresorhus/got#readme // Definitions by: BendingBender // Linus Unnebäck @@ -102,12 +102,50 @@ declare namespace got { type GotUrl = string | https.RequestOptions | Url | URL; - type Hook = (options: T) => any; - type Hooks = Record<'beforeRequest', Array>>; + /** + * Hooks allow modifications during the request lifecycle. Hook functions may be async and are + * run serially. + * + * @see https://github.com/sindresorhus/got#hooks + * @template Options Request options. + * @template Body Response body type. + */ + interface Hooks { + beforeRequest?: Array>; + beforeRedirect?: Array>; + beforeRetry?: Array>; + afterResponse?: Array>; + } + + /** + * @param options Normalized request options. + */ + type BeforeRequestHook = (options: Options) => any; + + /** + * @param options Normalized request options. + */ + type BeforeRedirectHook = (options: Options) => any; + + /** + * @param options Normalized request options. + * @param error Error from previous attempt. + * @param retryCount Number of retry. + */ + type BeforeRetryHook = (options: Options, error: HTTPError, retryCount: number) => any; + + /** + * @param options Normalized request options. + * @param retryWithMergedOptions Retries request with the updated options. + */ + type AfterResponseHook = ( + response: Response, + retryWithMergedOptions: (updateOptions: Options) => GotPromise + ) => Response | Promise>; interface GotBodyOptions extends GotOptions { body?: string | Buffer | nodeStream.Readable; - hooks?: Hooks>; + hooks?: Hooks, string | Buffer | nodeStream.Readable>; } interface GotJSONOptions extends GotOptions { @@ -115,14 +153,14 @@ declare namespace got { body?: object; form?: boolean; json: true; - hooks?: Hooks; + hooks?: Hooks; } interface GotFormOptions extends GotOptions { - body?: {[key: string]: any}; + body?: Record; form: true; json?: boolean; - hooks?: Hooks>; + hooks?: Hooks, Record>; } interface GotOptions extends InternalRequestOptions {