1 | import is, { assert } from '@sindresorhus/is';
|
2 | import asPromise from './as-promise/index.js';
|
3 | import Request from './core/index.js';
|
4 | import Options from './core/options.js';
|
5 |
|
6 | const delay = async (ms) => new Promise(resolve => {
|
7 | setTimeout(resolve, ms);
|
8 | });
|
9 | const isGotInstance = (value) => is.function_(value);
|
10 | const aliases = [
|
11 | 'get',
|
12 | 'post',
|
13 | 'put',
|
14 | 'patch',
|
15 | 'head',
|
16 | 'delete',
|
17 | ];
|
18 | const create = (defaults) => {
|
19 | defaults = {
|
20 | options: new Options(undefined, undefined, defaults.options),
|
21 | handlers: [...defaults.handlers],
|
22 | mutableDefaults: defaults.mutableDefaults,
|
23 | };
|
24 | Object.defineProperty(defaults, 'mutableDefaults', {
|
25 | enumerable: true,
|
26 | configurable: false,
|
27 | writable: false,
|
28 | });
|
29 |
|
30 | const got = ((url, options, defaultOptions = defaults.options) => {
|
31 | const request = new Request(url, options, defaultOptions);
|
32 | let promise;
|
33 | const lastHandler = (normalized) => {
|
34 |
|
35 | request.options = normalized;
|
36 | request._noPipe = !normalized.isStream;
|
37 | void request.flush();
|
38 | if (normalized.isStream) {
|
39 | return request;
|
40 | }
|
41 | promise ||= asPromise(request);
|
42 | return promise;
|
43 | };
|
44 | let iteration = 0;
|
45 | const iterateHandlers = (newOptions) => {
|
46 | const handler = defaults.handlers[iteration++] ?? lastHandler;
|
47 | const result = handler(newOptions, iterateHandlers);
|
48 | if (is.promise(result) && !request.options.isStream) {
|
49 | promise ||= asPromise(request);
|
50 | if (result !== promise) {
|
51 | const descriptors = Object.getOwnPropertyDescriptors(promise);
|
52 | for (const key in descriptors) {
|
53 | if (key in result) {
|
54 |
|
55 | delete descriptors[key];
|
56 | }
|
57 | }
|
58 |
|
59 | Object.defineProperties(result, descriptors);
|
60 | result.cancel = promise.cancel;
|
61 | }
|
62 | }
|
63 | return result;
|
64 | };
|
65 | return iterateHandlers(request.options);
|
66 | });
|
67 | got.extend = (...instancesOrOptions) => {
|
68 | const options = new Options(undefined, undefined, defaults.options);
|
69 | const handlers = [...defaults.handlers];
|
70 | let mutableDefaults;
|
71 | for (const value of instancesOrOptions) {
|
72 | if (isGotInstance(value)) {
|
73 | options.merge(value.defaults.options);
|
74 | handlers.push(...value.defaults.handlers);
|
75 | mutableDefaults = value.defaults.mutableDefaults;
|
76 | }
|
77 | else {
|
78 | options.merge(value);
|
79 | if (value.handlers) {
|
80 | handlers.push(...value.handlers);
|
81 | }
|
82 | mutableDefaults = value.mutableDefaults;
|
83 | }
|
84 | }
|
85 | return create({
|
86 | options,
|
87 | handlers,
|
88 | mutableDefaults: Boolean(mutableDefaults),
|
89 | });
|
90 | };
|
91 |
|
92 | const paginateEach = (async function* (url, options) {
|
93 | let normalizedOptions = new Options(url, options, defaults.options);
|
94 | normalizedOptions.resolveBodyOnly = false;
|
95 | const { pagination } = normalizedOptions;
|
96 | assert.function_(pagination.transform);
|
97 | assert.function_(pagination.shouldContinue);
|
98 | assert.function_(pagination.filter);
|
99 | assert.function_(pagination.paginate);
|
100 | assert.number(pagination.countLimit);
|
101 | assert.number(pagination.requestLimit);
|
102 | assert.number(pagination.backoff);
|
103 | const allItems = [];
|
104 | let { countLimit } = pagination;
|
105 | let numberOfRequests = 0;
|
106 | while (numberOfRequests < pagination.requestLimit) {
|
107 | if (numberOfRequests !== 0) {
|
108 |
|
109 | await delay(pagination.backoff);
|
110 | }
|
111 |
|
112 | const response = (await got(undefined, undefined, normalizedOptions));
|
113 |
|
114 | const parsed = await pagination.transform(response);
|
115 | const currentItems = [];
|
116 | assert.array(parsed);
|
117 | for (const item of parsed) {
|
118 | if (pagination.filter({ item, currentItems, allItems })) {
|
119 | if (!pagination.shouldContinue({ item, currentItems, allItems })) {
|
120 | return;
|
121 | }
|
122 | yield item;
|
123 | if (pagination.stackAllItems) {
|
124 | allItems.push(item);
|
125 | }
|
126 | currentItems.push(item);
|
127 | if (--countLimit <= 0) {
|
128 | return;
|
129 | }
|
130 | }
|
131 | }
|
132 | const optionsToMerge = pagination.paginate({
|
133 | response,
|
134 | currentItems,
|
135 | allItems,
|
136 | });
|
137 | if (optionsToMerge === false) {
|
138 | return;
|
139 | }
|
140 | if (optionsToMerge === response.request.options) {
|
141 | normalizedOptions = response.request.options;
|
142 | }
|
143 | else {
|
144 | normalizedOptions.merge(optionsToMerge);
|
145 | assert.any([is.urlInstance, is.undefined], optionsToMerge.url);
|
146 | if (optionsToMerge.url !== undefined) {
|
147 | normalizedOptions.prefixUrl = '';
|
148 | normalizedOptions.url = optionsToMerge.url;
|
149 | }
|
150 | }
|
151 | numberOfRequests++;
|
152 | }
|
153 | });
|
154 | got.paginate = paginateEach;
|
155 | got.paginate.all = (async (url, options) => {
|
156 | const results = [];
|
157 | for await (const item of paginateEach(url, options)) {
|
158 | results.push(item);
|
159 | }
|
160 | return results;
|
161 | });
|
162 |
|
163 | got.paginate.each = paginateEach;
|
164 |
|
165 | got.stream = ((url, options) => got(url, { ...options, isStream: true }));
|
166 |
|
167 | for (const method of aliases) {
|
168 | got[method] = ((url, options) => got(url, { ...options, method }));
|
169 | got.stream[method] = ((url, options) => got(url, { ...options, method, isStream: true }));
|
170 | }
|
171 | if (!defaults.mutableDefaults) {
|
172 | Object.freeze(defaults.handlers);
|
173 | defaults.options.freeze();
|
174 | }
|
175 | Object.defineProperty(got, 'defaults', {
|
176 | value: defaults,
|
177 | writable: false,
|
178 | configurable: false,
|
179 | enumerable: true,
|
180 | });
|
181 | return got;
|
182 | };
|
183 | export default create;
|