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 | if (!promise) {
|
42 | promise = asPromise(request);
|
43 | }
|
44 | return promise;
|
45 | };
|
46 | let iteration = 0;
|
47 | const iterateHandlers = (newOptions) => {
|
48 | const handler = defaults.handlers[iteration++] ?? lastHandler;
|
49 | const result = handler(newOptions, iterateHandlers);
|
50 | if (is.promise(result) && !request.options.isStream) {
|
51 | if (!promise) {
|
52 | promise = asPromise(request);
|
53 | }
|
54 | if (result !== promise) {
|
55 | const descriptors = Object.getOwnPropertyDescriptors(promise);
|
56 | for (const key in descriptors) {
|
57 | if (key in result) {
|
58 |
|
59 | delete descriptors[key];
|
60 | }
|
61 | }
|
62 |
|
63 | Object.defineProperties(result, descriptors);
|
64 | result.cancel = promise.cancel;
|
65 | }
|
66 | }
|
67 | return result;
|
68 | };
|
69 | return iterateHandlers(request.options);
|
70 | });
|
71 | got.extend = (...instancesOrOptions) => {
|
72 | const options = new Options(undefined, undefined, defaults.options);
|
73 | const handlers = [...defaults.handlers];
|
74 | let mutableDefaults;
|
75 | for (const value of instancesOrOptions) {
|
76 | if (isGotInstance(value)) {
|
77 | options.merge(value.defaults.options);
|
78 | handlers.push(...value.defaults.handlers);
|
79 | mutableDefaults = value.defaults.mutableDefaults;
|
80 | }
|
81 | else {
|
82 | options.merge(value);
|
83 | if (value.handlers) {
|
84 | handlers.push(...value.handlers);
|
85 | }
|
86 | mutableDefaults = value.mutableDefaults;
|
87 | }
|
88 | }
|
89 | return create({
|
90 | options,
|
91 | handlers,
|
92 | mutableDefaults: Boolean(mutableDefaults),
|
93 | });
|
94 | };
|
95 |
|
96 | const paginateEach = (async function* (url, options) {
|
97 | let normalizedOptions = new Options(url, options, defaults.options);
|
98 | normalizedOptions.resolveBodyOnly = false;
|
99 | const { pagination } = normalizedOptions;
|
100 | assert.function_(pagination.transform);
|
101 | assert.function_(pagination.shouldContinue);
|
102 | assert.function_(pagination.filter);
|
103 | assert.function_(pagination.paginate);
|
104 | assert.number(pagination.countLimit);
|
105 | assert.number(pagination.requestLimit);
|
106 | assert.number(pagination.backoff);
|
107 | const allItems = [];
|
108 | let { countLimit } = pagination;
|
109 | let numberOfRequests = 0;
|
110 | while (numberOfRequests < pagination.requestLimit) {
|
111 | if (numberOfRequests !== 0) {
|
112 |
|
113 | await delay(pagination.backoff);
|
114 | }
|
115 |
|
116 | const response = (await got(undefined, undefined, normalizedOptions));
|
117 |
|
118 | const parsed = await pagination.transform(response);
|
119 | const currentItems = [];
|
120 | assert.array(parsed);
|
121 | for (const item of parsed) {
|
122 | if (pagination.filter({ item, currentItems, allItems })) {
|
123 | if (!pagination.shouldContinue({ item, currentItems, allItems })) {
|
124 | return;
|
125 | }
|
126 | yield item;
|
127 | if (pagination.stackAllItems) {
|
128 | allItems.push(item);
|
129 | }
|
130 | currentItems.push(item);
|
131 | if (--countLimit <= 0) {
|
132 | return;
|
133 | }
|
134 | }
|
135 | }
|
136 | const optionsToMerge = pagination.paginate({
|
137 | response,
|
138 | currentItems,
|
139 | allItems,
|
140 | });
|
141 | if (optionsToMerge === false) {
|
142 | return;
|
143 | }
|
144 | if (optionsToMerge === response.request.options) {
|
145 | normalizedOptions = response.request.options;
|
146 | }
|
147 | else {
|
148 | normalizedOptions.merge(optionsToMerge);
|
149 | assert.any([is.urlInstance, is.undefined], optionsToMerge.url);
|
150 | if (optionsToMerge.url !== undefined) {
|
151 | normalizedOptions.prefixUrl = '';
|
152 | normalizedOptions.url = optionsToMerge.url;
|
153 | }
|
154 | }
|
155 | numberOfRequests++;
|
156 | }
|
157 | });
|
158 | got.paginate = paginateEach;
|
159 | got.paginate.all = (async (url, options) => {
|
160 | const results = [];
|
161 | for await (const item of paginateEach(url, options)) {
|
162 | results.push(item);
|
163 | }
|
164 | return results;
|
165 | });
|
166 |
|
167 | got.paginate.each = paginateEach;
|
168 |
|
169 | got.stream = ((url, options) => got(url, { ...options, isStream: true }));
|
170 |
|
171 | for (const method of aliases) {
|
172 | got[method] = ((url, options) => got(url, { ...options, method }));
|
173 | got.stream[method] = ((url, options) => got(url, { ...options, method, isStream: true }));
|
174 | }
|
175 | if (!defaults.mutableDefaults) {
|
176 | Object.freeze(defaults.handlers);
|
177 | defaults.options.freeze();
|
178 | }
|
179 | Object.defineProperty(got, 'defaults', {
|
180 | value: defaults,
|
181 | writable: false,
|
182 | configurable: false,
|
183 | enumerable: true,
|
184 | });
|
185 | return got;
|
186 | };
|
187 | export default create;
|