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)); }