208 lines
5.6 KiB
JavaScript
208 lines
5.6 KiB
JavaScript
var __awaiter = this && this.__awaiter || function (thisArg, _arguments, P, generator) {
|
|
function adopt(value) {
|
|
return value instanceof P ? value : new P(function (resolve) {
|
|
resolve(value);
|
|
});
|
|
}
|
|
|
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
function fulfilled(value) {
|
|
try {
|
|
step(generator.next(value));
|
|
} catch (e) {
|
|
reject(e);
|
|
}
|
|
}
|
|
|
|
function rejected(value) {
|
|
try {
|
|
step(generator["throw"](value));
|
|
} catch (e) {
|
|
reject(e);
|
|
}
|
|
}
|
|
|
|
function step(result) {
|
|
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
}
|
|
|
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
});
|
|
};
|
|
|
|
var __rest = this && this.__rest || function (s, e) {
|
|
var t = {};
|
|
|
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
|
|
|
|
if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
|
|
}
|
|
return t;
|
|
};
|
|
|
|
import { BeeError, BeeNotAJsonError, BeeRequestError, BeeResponseError } from "./error.js";
|
|
import kyFactory from 'ky-universal';
|
|
import { normalizeToReadableStream } from "./stream.js";
|
|
import { deepMerge } from "./merge.js";
|
|
import { isObject, isStrictlyObject } from "./type.js";
|
|
const DEFAULT_KY_CONFIG = {
|
|
headers: {
|
|
accept: 'application/json, text/plain, */*',
|
|
'user-agent': `bee-js`
|
|
}
|
|
};
|
|
|
|
function isHttpError(e) {
|
|
return isObject(e) && typeof e.response !== 'undefined';
|
|
}
|
|
|
|
function isHttpRequestError(e) {
|
|
return isObject(e) && typeof e.request !== 'undefined';
|
|
}
|
|
|
|
function headersToObject(header) {
|
|
return [...header.entries()].reduce((obj, [key, val]) => {
|
|
obj[key] = val;
|
|
return obj;
|
|
}, {});
|
|
}
|
|
|
|
function wrapRequest(request) {
|
|
return {
|
|
url: request.url,
|
|
method: request.method.toUpperCase(),
|
|
headers: headersToObject(request.headers)
|
|
};
|
|
}
|
|
|
|
export function wrapRequestClosure(cb) {
|
|
return request => __awaiter(this, void 0, void 0, function* () {
|
|
yield cb(wrapRequest(request));
|
|
});
|
|
}
|
|
export function wrapResponseClosure(cb) {
|
|
return (request, options, response) => __awaiter(this, void 0, void 0, function* () {
|
|
yield cb({
|
|
headers: headersToObject(response.headers),
|
|
status: response.status,
|
|
statusText: response.statusText,
|
|
request: wrapRequest(request)
|
|
});
|
|
});
|
|
}
|
|
/**
|
|
* Filters out entries that has undefined value from headers object.
|
|
* Modifies the original object!
|
|
*
|
|
* @param obj
|
|
*/
|
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
|
|
export function filterHeaders(obj) {
|
|
if (obj === undefined) {
|
|
return undefined;
|
|
}
|
|
|
|
isStrictlyObject(obj);
|
|
const typedObj = obj;
|
|
|
|
for (const key in typedObj) {
|
|
if (typedObj[key] === undefined) {
|
|
delete typedObj[key];
|
|
}
|
|
}
|
|
|
|
if (Object.keys(typedObj).length === 0) {
|
|
return undefined;
|
|
}
|
|
|
|
return typedObj;
|
|
}
|
|
/**
|
|
* Main utility function to make HTTP requests.
|
|
* @param ky
|
|
* @param config
|
|
*/
|
|
|
|
export function http(ky, config) {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
try {
|
|
const {
|
|
path,
|
|
responseType
|
|
} = config,
|
|
kyConfig = __rest(config, ["path", "responseType"]);
|
|
|
|
const response = yield ky(path, Object.assign(Object.assign({}, kyConfig), {
|
|
searchParams: filterHeaders(kyConfig.searchParams)
|
|
}));
|
|
|
|
switch (responseType) {
|
|
case 'stream':
|
|
if (!response.body) {
|
|
throw new BeeError('Response was expected to get data but did not get any!');
|
|
}
|
|
|
|
response.data = normalizeToReadableStream(response.body);
|
|
break;
|
|
|
|
case 'arraybuffer':
|
|
response.data = yield response.arrayBuffer();
|
|
break;
|
|
|
|
case 'json':
|
|
try {
|
|
response.data = yield response.json();
|
|
} catch (e) {
|
|
throw new BeeNotAJsonError();
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
// If responseType is not set, then no data are expected
|
|
}
|
|
|
|
return response;
|
|
} catch (e) {
|
|
// Passthrough thrown errors
|
|
if (e instanceof BeeNotAJsonError) {
|
|
throw e;
|
|
}
|
|
|
|
if (isHttpError(e)) {
|
|
let message; // We store the response body here as it can be read only once in Response's lifecycle so to make it exposed
|
|
// to the user in the BeeResponseError, for further analysis.
|
|
|
|
const body = yield e.response.text();
|
|
|
|
try {
|
|
// The response can be Bee's JSON with structure `{code, message}` lets try to parse it
|
|
message = JSON.parse(body).message;
|
|
} catch (e) {}
|
|
|
|
if (message) {
|
|
throw new BeeResponseError(e.response.status, e.response, body, config, `${e.response.statusText}: ${message}`);
|
|
} else {
|
|
throw new BeeResponseError(e.response.status, e.response, body, config, e.response.statusText);
|
|
}
|
|
} else if (isHttpRequestError(e)) {
|
|
throw new BeeRequestError(e.message, config);
|
|
} else {
|
|
// Node 18 has native `fetch` implementation called Undici. Errors from this implementation have top level generic
|
|
// message "fetch failed" with the more specific error placed into `cause` property. Instead of "fetch failed" we
|
|
// expose the underlying problem.
|
|
if (e.cause) {
|
|
throw new BeeError(e.cause.message);
|
|
}
|
|
|
|
throw new BeeError(e.message);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
export function makeDefaultKy(kyConfig) {
|
|
return kyFactory.create(deepMerge(DEFAULT_KY_CONFIG, kyConfig));
|
|
} |