UNPKG

20.6 kBJavaScriptView Raw
1"use strict";
2// Copyright 2018 Google LLC
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15 if (k2 === undefined) k2 = k;
16 var desc = Object.getOwnPropertyDescriptor(m, k);
17 if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
18 desc = { enumerable: true, get: function() { return m[k]; } };
19 }
20 Object.defineProperty(o, k2, desc);
21}) : (function(o, m, k, k2) {
22 if (k2 === undefined) k2 = k;
23 o[k2] = m[k];
24}));
25var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
26 Object.defineProperty(o, "default", { enumerable: true, value: v });
27}) : function(o, v) {
28 o["default"] = v;
29});
30var __importStar = (this && this.__importStar) || function (mod) {
31 if (mod && mod.__esModule) return mod;
32 var result = {};
33 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
34 __setModuleDefault(result, mod);
35 return result;
36};
37var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
38 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
39 if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
40 return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
41};
42var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
43 if (kind === "m") throw new TypeError("Private method is not writable");
44 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
45 if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
46 return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
47};
48var __importDefault = (this && this.__importDefault) || function (mod) {
49 return (mod && mod.__esModule) ? mod : { "default": mod };
50};
51var _Gaxios_instances, _a, _Gaxios_urlMayUseProxy, _Gaxios_applyRequestInterceptors, _Gaxios_applyResponseInterceptors, _Gaxios_prepareRequest, _Gaxios_proxyAgent, _Gaxios_getProxyAgent;
52Object.defineProperty(exports, "__esModule", { value: true });
53exports.Gaxios = void 0;
54const extend_1 = __importDefault(require("extend"));
55const https_1 = require("https");
56const node_fetch_1 = __importDefault(require("node-fetch"));
57const querystring_1 = __importDefault(require("querystring"));
58const is_stream_1 = __importDefault(require("is-stream"));
59const url_1 = require("url");
60const common_1 = require("./common");
61const retry_1 = require("./retry");
62const stream_1 = require("stream");
63const uuid_1 = require("uuid");
64const interceptor_1 = require("./interceptor");
65/* eslint-disable @typescript-eslint/no-explicit-any */
66const fetch = hasFetch() ? window.fetch : node_fetch_1.default;
67function hasWindow() {
68 return typeof window !== 'undefined' && !!window;
69}
70function hasFetch() {
71 return hasWindow() && !!window.fetch;
72}
73function hasBuffer() {
74 return typeof Buffer !== 'undefined';
75}
76function hasHeader(options, header) {
77 return !!getHeader(options, header);
78}
79function getHeader(options, header) {
80 header = header.toLowerCase();
81 for (const key of Object.keys((options === null || options === void 0 ? void 0 : options.headers) || {})) {
82 if (header === key.toLowerCase()) {
83 return options.headers[key];
84 }
85 }
86 return undefined;
87}
88class Gaxios {
89 /**
90 * The Gaxios class is responsible for making HTTP requests.
91 * @param defaults The default set of options to be used for this instance.
92 */
93 constructor(defaults) {
94 _Gaxios_instances.add(this);
95 this.agentCache = new Map();
96 this.defaults = defaults || {};
97 this.interceptors = {
98 request: new interceptor_1.GaxiosInterceptorManager(),
99 response: new interceptor_1.GaxiosInterceptorManager(),
100 };
101 }
102 /**
103 * Perform an HTTP request with the given options.
104 * @param opts Set of HTTP options that will be used for this HTTP request.
105 */
106 async request(opts = {}) {
107 opts = await __classPrivateFieldGet(this, _Gaxios_instances, "m", _Gaxios_prepareRequest).call(this, opts);
108 opts = await __classPrivateFieldGet(this, _Gaxios_instances, "m", _Gaxios_applyRequestInterceptors).call(this, opts);
109 return __classPrivateFieldGet(this, _Gaxios_instances, "m", _Gaxios_applyResponseInterceptors).call(this, this._request(opts));
110 }
111 async _defaultAdapter(opts) {
112 const fetchImpl = opts.fetchImplementation || fetch;
113 const res = (await fetchImpl(opts.url, opts));
114 const data = await this.getResponseData(opts, res);
115 return this.translateResponse(opts, res, data);
116 }
117 /**
118 * Internal, retryable version of the `request` method.
119 * @param opts Set of HTTP options that will be used for this HTTP request.
120 */
121 async _request(opts = {}) {
122 var _b;
123 try {
124 let translatedResponse;
125 if (opts.adapter) {
126 translatedResponse = await opts.adapter(opts, this._defaultAdapter.bind(this));
127 }
128 else {
129 translatedResponse = await this._defaultAdapter(opts);
130 }
131 if (!opts.validateStatus(translatedResponse.status)) {
132 if (opts.responseType === 'stream') {
133 let response = '';
134 await new Promise(resolve => {
135 (translatedResponse === null || translatedResponse === void 0 ? void 0 : translatedResponse.data).on('data', chunk => {
136 response += chunk;
137 });
138 (translatedResponse === null || translatedResponse === void 0 ? void 0 : translatedResponse.data).on('end', resolve);
139 });
140 translatedResponse.data = response;
141 }
142 throw new common_1.GaxiosError(`Request failed with status code ${translatedResponse.status}`, opts, translatedResponse);
143 }
144 return translatedResponse;
145 }
146 catch (e) {
147 const err = e instanceof common_1.GaxiosError
148 ? e
149 : new common_1.GaxiosError(e.message, opts, undefined, e);
150 const { shouldRetry, config } = await (0, retry_1.getRetryConfig)(err);
151 if (shouldRetry && config) {
152 err.config.retryConfig.currentRetryAttempt =
153 config.retryConfig.currentRetryAttempt;
154 // The error's config could be redacted - therefore we only want to
155 // copy the retry state over to the existing config
156 opts.retryConfig = (_b = err.config) === null || _b === void 0 ? void 0 : _b.retryConfig;
157 return this._request(opts);
158 }
159 throw err;
160 }
161 }
162 async getResponseData(opts, res) {
163 switch (opts.responseType) {
164 case 'stream':
165 return res.body;
166 case 'json': {
167 let data = await res.text();
168 try {
169 data = JSON.parse(data);
170 }
171 catch (_b) {
172 // continue
173 }
174 return data;
175 }
176 case 'arraybuffer':
177 return res.arrayBuffer();
178 case 'blob':
179 return res.blob();
180 case 'text':
181 return res.text();
182 default:
183 return this.getResponseDataFromContentType(res);
184 }
185 }
186 /**
187 * By default, throw for any non-2xx status code
188 * @param status status code from the HTTP response
189 */
190 validateStatus(status) {
191 return status >= 200 && status < 300;
192 }
193 /**
194 * Encode a set of key/value pars into a querystring format (?foo=bar&baz=boo)
195 * @param params key value pars to encode
196 */
197 paramsSerializer(params) {
198 return querystring_1.default.stringify(params);
199 }
200 translateResponse(opts, res, data) {
201 // headers need to be converted from a map to an obj
202 const headers = {};
203 res.headers.forEach((value, key) => {
204 headers[key] = value;
205 });
206 return {
207 config: opts,
208 data: data,
209 headers,
210 status: res.status,
211 statusText: res.statusText,
212 // XMLHttpRequestLike
213 request: {
214 responseURL: res.url,
215 },
216 };
217 }
218 /**
219 * Attempts to parse a response by looking at the Content-Type header.
220 * @param {FetchResponse} response the HTTP response.
221 * @returns {Promise<any>} a promise that resolves to the response data.
222 */
223 async getResponseDataFromContentType(response) {
224 let contentType = response.headers.get('Content-Type');
225 if (contentType === null) {
226 // Maintain existing functionality by calling text()
227 return response.text();
228 }
229 contentType = contentType.toLowerCase();
230 if (contentType.includes('application/json')) {
231 let data = await response.text();
232 try {
233 data = JSON.parse(data);
234 }
235 catch (_b) {
236 // continue
237 }
238 return data;
239 }
240 else if (contentType.match(/^text\//)) {
241 return response.text();
242 }
243 else {
244 // If the content type is something not easily handled, just return the raw data (blob)
245 return response.blob();
246 }
247 }
248 /**
249 * Creates an async generator that yields the pieces of a multipart/related request body.
250 * This implementation follows the spec: https://www.ietf.org/rfc/rfc2387.txt. However, recursive
251 * multipart/related requests are not currently supported.
252 *
253 * @param {GaxioMultipartOptions[]} multipartOptions the pieces to turn into a multipart/related body.
254 * @param {string} boundary the boundary string to be placed between each part.
255 */
256 async *getMultipartRequest(multipartOptions, boundary) {
257 const finale = `--${boundary}--`;
258 for (const currentPart of multipartOptions) {
259 const partContentType = currentPart.headers['Content-Type'] || 'application/octet-stream';
260 const preamble = `--${boundary}\r\nContent-Type: ${partContentType}\r\n\r\n`;
261 yield preamble;
262 if (typeof currentPart.content === 'string') {
263 yield currentPart.content;
264 }
265 else {
266 yield* currentPart.content;
267 }
268 yield '\r\n';
269 }
270 yield finale;
271 }
272}
273exports.Gaxios = Gaxios;
274_a = Gaxios, _Gaxios_instances = new WeakSet(), _Gaxios_urlMayUseProxy = function _Gaxios_urlMayUseProxy(url, noProxy = []) {
275 var _b, _c;
276 const candidate = new url_1.URL(url);
277 const noProxyList = [...noProxy];
278 const noProxyEnvList = ((_c = ((_b = process.env.NO_PROXY) !== null && _b !== void 0 ? _b : process.env.no_proxy)) === null || _c === void 0 ? void 0 : _c.split(',')) || [];
279 for (const rule of noProxyEnvList) {
280 noProxyList.push(rule.trim());
281 }
282 for (const rule of noProxyList) {
283 // Match regex
284 if (rule instanceof RegExp) {
285 if (rule.test(candidate.toString())) {
286 return false;
287 }
288 }
289 // Match URL
290 else if (rule instanceof url_1.URL) {
291 if (rule.origin === candidate.origin) {
292 return false;
293 }
294 }
295 // Match string regex
296 else if (rule.startsWith('*.') || rule.startsWith('.')) {
297 const cleanedRule = rule.replace(/^\*\./, '.');
298 if (candidate.hostname.endsWith(cleanedRule)) {
299 return false;
300 }
301 }
302 // Basic string match
303 else if (rule === candidate.origin ||
304 rule === candidate.hostname ||
305 rule === candidate.href) {
306 return false;
307 }
308 }
309 return true;
310}, _Gaxios_applyRequestInterceptors =
311/**
312 * Applies the request interceptors. The request interceptors are applied after the
313 * call to prepareRequest is completed.
314 *
315 * @param {GaxiosOptions} options The current set of options.
316 *
317 * @returns {Promise<GaxiosOptions>} Promise that resolves to the set of options or response after interceptors are applied.
318 */
319async function _Gaxios_applyRequestInterceptors(options) {
320 let promiseChain = Promise.resolve(options);
321 for (const interceptor of this.interceptors.request.values()) {
322 if (interceptor) {
323 promiseChain = promiseChain.then(interceptor.resolved, interceptor.rejected);
324 }
325 }
326 return promiseChain;
327}, _Gaxios_applyResponseInterceptors =
328/**
329 * Applies the response interceptors. The response interceptors are applied after the
330 * call to request is made.
331 *
332 * @param {GaxiosOptions} options The current set of options.
333 *
334 * @returns {Promise<GaxiosOptions>} Promise that resolves to the set of options or response after interceptors are applied.
335 */
336async function _Gaxios_applyResponseInterceptors(response) {
337 let promiseChain = Promise.resolve(response);
338 for (const interceptor of this.interceptors.response.values()) {
339 if (interceptor) {
340 promiseChain = promiseChain.then(interceptor.resolved, interceptor.rejected);
341 }
342 }
343 return promiseChain;
344}, _Gaxios_prepareRequest =
345/**
346 * Validates the options, merges them with defaults, and prepare request.
347 *
348 * @param options The original options passed from the client.
349 * @returns Prepared options, ready to make a request
350 */
351async function _Gaxios_prepareRequest(options) {
352 var _b, _c, _d, _e;
353 const opts = (0, extend_1.default)(true, {}, this.defaults, options);
354 if (!opts.url) {
355 throw new Error('URL is required.');
356 }
357 // baseUrl has been deprecated, remove in 2.0
358 const baseUrl = opts.baseUrl || opts.baseURL;
359 if (baseUrl) {
360 opts.url = baseUrl.toString() + opts.url;
361 }
362 opts.paramsSerializer = opts.paramsSerializer || this.paramsSerializer;
363 if (opts.params && Object.keys(opts.params).length > 0) {
364 let additionalQueryParams = opts.paramsSerializer(opts.params);
365 if (additionalQueryParams.startsWith('?')) {
366 additionalQueryParams = additionalQueryParams.slice(1);
367 }
368 const prefix = opts.url.toString().includes('?') ? '&' : '?';
369 opts.url = opts.url + prefix + additionalQueryParams;
370 }
371 if (typeof options.maxContentLength === 'number') {
372 opts.size = options.maxContentLength;
373 }
374 if (typeof options.maxRedirects === 'number') {
375 opts.follow = options.maxRedirects;
376 }
377 opts.headers = opts.headers || {};
378 if (opts.multipart === undefined && opts.data) {
379 const isFormData = typeof FormData === 'undefined'
380 ? false
381 : (opts === null || opts === void 0 ? void 0 : opts.data) instanceof FormData;
382 if (is_stream_1.default.readable(opts.data)) {
383 opts.body = opts.data;
384 }
385 else if (hasBuffer() && Buffer.isBuffer(opts.data)) {
386 // Do not attempt to JSON.stringify() a Buffer:
387 opts.body = opts.data;
388 if (!hasHeader(opts, 'Content-Type')) {
389 opts.headers['Content-Type'] = 'application/json';
390 }
391 }
392 else if (typeof opts.data === 'object') {
393 // If www-form-urlencoded content type has been set, but data is
394 // provided as an object, serialize the content using querystring:
395 if (!isFormData) {
396 if (getHeader(opts, 'content-type') ===
397 'application/x-www-form-urlencoded') {
398 opts.body = opts.paramsSerializer(opts.data);
399 }
400 else {
401 // } else if (!(opts.data instanceof FormData)) {
402 if (!hasHeader(opts, 'Content-Type')) {
403 opts.headers['Content-Type'] = 'application/json';
404 }
405 opts.body = JSON.stringify(opts.data);
406 }
407 }
408 }
409 else {
410 opts.body = opts.data;
411 }
412 }
413 else if (opts.multipart && opts.multipart.length > 0) {
414 // note: once the minimum version reaches Node 16,
415 // this can be replaced with randomUUID() function from crypto
416 // and the dependency on UUID removed
417 const boundary = (0, uuid_1.v4)();
418 opts.headers['Content-Type'] = `multipart/related; boundary=${boundary}`;
419 const bodyStream = new stream_1.PassThrough();
420 opts.body = bodyStream;
421 (0, stream_1.pipeline)(this.getMultipartRequest(opts.multipart, boundary), bodyStream, () => { });
422 }
423 opts.validateStatus = opts.validateStatus || this.validateStatus;
424 opts.responseType = opts.responseType || 'unknown';
425 if (!opts.headers['Accept'] && opts.responseType === 'json') {
426 opts.headers['Accept'] = 'application/json';
427 }
428 opts.method = opts.method || 'GET';
429 const proxy = opts.proxy ||
430 ((_b = process === null || process === void 0 ? void 0 : process.env) === null || _b === void 0 ? void 0 : _b.HTTPS_PROXY) ||
431 ((_c = process === null || process === void 0 ? void 0 : process.env) === null || _c === void 0 ? void 0 : _c.https_proxy) ||
432 ((_d = process === null || process === void 0 ? void 0 : process.env) === null || _d === void 0 ? void 0 : _d.HTTP_PROXY) ||
433 ((_e = process === null || process === void 0 ? void 0 : process.env) === null || _e === void 0 ? void 0 : _e.http_proxy);
434 const urlMayUseProxy = __classPrivateFieldGet(this, _Gaxios_instances, "m", _Gaxios_urlMayUseProxy).call(this, opts.url, opts.noProxy);
435 if (opts.agent) {
436 // don't do any of the following options - use the user-provided agent.
437 }
438 else if (proxy && urlMayUseProxy) {
439 const HttpsProxyAgent = await __classPrivateFieldGet(_a, _a, "m", _Gaxios_getProxyAgent).call(_a);
440 if (this.agentCache.has(proxy)) {
441 opts.agent = this.agentCache.get(proxy);
442 }
443 else {
444 opts.agent = new HttpsProxyAgent(proxy, {
445 cert: opts.cert,
446 key: opts.key,
447 });
448 this.agentCache.set(proxy, opts.agent);
449 }
450 }
451 else if (opts.cert && opts.key) {
452 // Configure client for mTLS
453 if (this.agentCache.has(opts.key)) {
454 opts.agent = this.agentCache.get(opts.key);
455 }
456 else {
457 opts.agent = new https_1.Agent({
458 cert: opts.cert,
459 key: opts.key,
460 });
461 this.agentCache.set(opts.key, opts.agent);
462 }
463 }
464 if (typeof opts.errorRedactor !== 'function' &&
465 opts.errorRedactor !== false) {
466 opts.errorRedactor = common_1.defaultErrorRedactor;
467 }
468 return opts;
469}, _Gaxios_getProxyAgent = async function _Gaxios_getProxyAgent() {
470 __classPrivateFieldSet(this, _a, __classPrivateFieldGet(this, _a, "f", _Gaxios_proxyAgent) || (await Promise.resolve().then(() => __importStar(require('https-proxy-agent')))).HttpsProxyAgent, "f", _Gaxios_proxyAgent);
471 return __classPrivateFieldGet(this, _a, "f", _Gaxios_proxyAgent);
472};
473/**
474 * A cache for the lazily-loaded proxy agent.
475 *
476 * Should use {@link Gaxios[#getProxyAgent]} to retrieve.
477 */
478// using `import` to dynamically import the types here
479_Gaxios_proxyAgent = { value: void 0 };
480//# sourceMappingURL=gaxios.js.map
\No newline at end of file