-
-
Notifications
You must be signed in to change notification settings - Fork 935
/
types.ts
301 lines (240 loc) · 8.07 KB
/
types.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
import * as PCancelable from 'p-cancelable';
import Request, {
Options,
Response,
RequestError,
RequestEvents
} from '../core/index';
/**
All parsing methods supported by Got.
*/
export type ResponseType = 'json' | 'buffer' | 'text';
export interface PaginateData<R, T> {
response: Response<R>;
allItems: T[];
currentItems: T[];
}
export interface PaginationOptions<T, R> {
/**
All options accepted by `got.paginate()`.
*/
pagination?: {
/**
A function that transform [`Response`](#response) into an array of items.
This is where you should do the parsing.
@default response => JSON.parse(response.body)
*/
transform?: (response: Response<R>) => Promise<T[]> | T[];
/**
Checks whether the item should be emitted or not.
@default (item, allItems, currentItems) => true
*/
filter?: (item: T, allItems: T[], currentItems: T[]) => boolean;
/**
The function takes three arguments:
- `response` - The current response object.
- `allItems` - An array of the emitted items.
- `currentItems` - Items from the current response.
It should return an object representing Got options pointing to the next page.
The options are merged automatically with the previous request, therefore the options returned `pagination.paginate(...)` must reflect changes only.
If there are no more pages, `false` should be returned.
@example
```
const got = require('got');
(async () => {
const limit = 10;
const items = got.paginate('https://example.com/items', {
searchParams: {
limit,
offset: 0
},
pagination: {
paginate: (response, allItems, currentItems) => {
const previousSearchParams = response.request.options.searchParams;
const previousOffset = previousSearchParams.get('offset');
if (currentItems.length < limit) {
return false;
}
return {
searchParams: {
...previousSearchParams,
offset: Number(previousOffset) + limit,
}
};
}
}
});
console.log('Items from all pages:', items);
})();
```
*/
paginate?: (paginate: PaginateData<R, T>) => Options | false;
/**
Checks whether the pagination should continue.
For example, if you need to stop **before** emitting an entry with some flag, you should use `(item, allItems, currentItems) => !item.flag`.
If you want to stop **after** emitting the entry, you should use `(item, allItems, currentItems) => allItems.some(entry => entry.flag)` instead.
@default (item, allItems, currentItems) => true
*/
shouldContinue?: (item: T, allItems: T[], currentItems: T[]) => boolean;
/**
The maximum amount of items that should be emitted.
@default Infinity
*/
countLimit?: number;
/**
Milliseconds to wait before the next request is triggered.
@default 0
*/
backoff?: number;
/**
The maximum amount of request that should be triggered.
Retries on failure are not counted towards this limit.
For example, it can be helpful during development to avoid an infinite number of requests.
@default 10000
*/
requestLimit?: number;
/**
Defines how the parameter `allItems` in pagination.paginate, pagination.filter and pagination.shouldContinue is managed.
When set to `false`, the parameter `allItems` is always an empty array.
This option can be helpful to save on memory usage when working with a large dataset.
*/
stackAllItems?: boolean;
};
}
export type AfterResponseHook<ResponseType = unknown> = (response: Response<ResponseType>, retryWithMergedOptions: (options: Options) => CancelableRequest<Response>) => Response | CancelableRequest<Response> | Promise<Response | CancelableRequest<Response>>;
// These should be merged into Options in core/index.ts
export namespace PromiseOnly {
export interface Hooks {
/**
Called with [response object](#response) and a retry function.
Calling the retry function will trigger `beforeRetry` hooks.
Each function should return the response.
This is especially useful when you want to refresh an access token.
__Note__: When using streams, this hook is ignored.
@example
```
const got = require('got');
const instance = got.extend({
hooks: {
afterResponse: [
(response, retryWithMergedOptions) => {
if (response.statusCode === 401) { // Unauthorized
const updatedOptions = {
headers: {
token: getNewToken() // Refresh the access token
}
};
// Save for further requests
instance.defaults.options = got.mergeOptions(instance.defaults.options, updatedOptions);
// Make a new retry
return retryWithMergedOptions(updatedOptions);
}
// No changes otherwise
return response;
}
],
beforeRetry: [
(options, error, retryCount) => {
// This will be called on `retryWithMergedOptions(...)`
}
]
},
mutableDefaults: true
});
```
*/
afterResponse?: AfterResponseHook[];
}
export interface Options extends PaginationOptions<unknown, unknown> {
/**
The parsing method.
The promise also has `.text()`, `.json()` and `.buffer()` methods which return another Got promise for the parsed body.
It's like setting the options to `{responseType: 'json', resolveBodyOnly: true}` but without affecting the main Got promise.
__Note__: When using streams, this option is ignored.
@example
```
(async () => {
const responsePromise = got(url);
const bufferPromise = responsePromise.buffer();
const jsonPromise = responsePromise.json();
const [response, buffer, json] = Promise.all([responsePromise, bufferPromise, jsonPromise]);
// `response` is an instance of Got Response
// `buffer` is an instance of Buffer
// `json` is an object
})();
```
@example
```
// This
const body = await got(url).json();
// is semantically the same as this
const body = await got(url, {responseType: 'json', resolveBodyOnly: true});
```
*/
responseType?: ResponseType;
/**
When set to `true` the promise will return the Response body instead of the Response object.
@default false
*/
resolveBodyOnly?: boolean;
/**
Returns a `Stream` instead of a `Promise`.
This is equivalent to calling `got.stream(url, options?)`.
@default false
*/
isStream?: boolean;
/**
[Encoding](https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings) to be used on `setEncoding` of the response data.
To get a [`Buffer`](https://nodejs.org/api/buffer.html), you need to set `responseType` to `buffer` instead.
Don't set this option to `null`.
__Note__: This doesn't affect streams! Instead, you need to do `got.stream(...).setEncoding(encoding)`.
@default 'utf-8'
*/
encoding?: BufferEncoding;
}
export interface NormalizedOptions {
responseType: ResponseType;
resolveBodyOnly: boolean;
isStream: boolean;
encoding?: BufferEncoding;
pagination?: Required<PaginationOptions<unknown, unknown>['pagination']>;
}
export interface Defaults {
responseType: ResponseType;
resolveBodyOnly: boolean;
isStream: boolean;
pagination?: Required<PaginationOptions<unknown, unknown>['pagination']>;
}
export type HookEvent = 'afterResponse';
}
/**
An error to be thrown when server response code is 2xx, and parsing body fails.
Includes a `response` property.
*/
export class ParseError extends RequestError {
declare readonly response: Response;
constructor(error: Error, response: Response) {
const {options} = response.request;
super(`${error.message} in "${options.url.toString()}"`, error, response.request);
this.name = 'ParseError';
}
}
/**
An error to be thrown when the request is aborted with `.cancel()`.
*/
export class CancelError extends RequestError {
declare readonly response: Response;
constructor(request: Request) {
super('Promise was canceled', {}, request);
this.name = 'CancelError';
}
get isCanceled() {
return true;
}
}
export interface CancelableRequest<T extends Response | Response['body'] = Response['body']> extends PCancelable<T>, RequestEvents<CancelableRequest<T>> {
json: <ReturnType>() => CancelableRequest<ReturnType>;
buffer: () => CancelableRequest<Buffer>;
text: () => CancelableRequest<string>;
}
export * from '../core';