UNPKG

kubo-rpc-client-esm-cjs

Version:
195 lines 7.58 kB
"use strict"; /* eslint-env browser */ 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 __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.HTTPError = exports.Client = exports.errorHandler = void 0; const multiaddr_1 = require("@multiformats/multiaddr"); const env_js_1 = require("ipfs-utils/src/env.js"); const parse_duration_1 = __importDefault(require("parse-duration")); const logger_1 = require("@libp2p/logger"); const http_js_1 = __importDefault(require("ipfs-utils/src/http.js")); const merge_options_1 = __importDefault(require("merge-options")); const to_url_string_1 = require("ipfs-core-utils/to-url-string"); const agent_1 = __importDefault(require("ipfs-core-utils/agent")); const log = (0, logger_1.logger)('js-kubo-rpc-client:lib:error-handler'); const merge = merge_options_1.default.bind({ ignoreUndefined: true }); const DEFAULT_PROTOCOL = env_js_1.isBrowser || env_js_1.isWebWorker ? location.protocol : 'http'; const DEFAULT_HOST = env_js_1.isBrowser || env_js_1.isWebWorker ? location.hostname : 'localhost'; const DEFAULT_PORT = env_js_1.isBrowser || env_js_1.isWebWorker ? location.port : '5001'; /** * @typedef {import('../types').Options} Options */ /** * @typedef {import('../types').Multiaddr} Multiaddr */ /** * @param {Options|URL|Multiaddr|string} [options] * @returns {Options} */ const normalizeOptions = (options = {}) => { let url; /** @type {Options} */ let opts = {}; let agent; if (typeof options === 'string' || (0, multiaddr_1.isMultiaddr)(options)) { url = new URL((0, to_url_string_1.toUrlString)(options)); } else if (options instanceof URL) { url = options; } else if (typeof options.url === 'string' || (0, multiaddr_1.isMultiaddr)(options.url)) { url = new URL((0, to_url_string_1.toUrlString)(options.url)); opts = options; } else if (options.url instanceof URL) { url = options.url; opts = options; } else { opts = options || {}; const protocol = (opts.protocol || DEFAULT_PROTOCOL).replace(':', ''); const host = (opts.host || DEFAULT_HOST).split(':')[0]; const port = (opts.port || DEFAULT_PORT); url = new URL(`${protocol}://${host}:${port}`); } if (opts.apiPath) { url.pathname = opts.apiPath; } else if (url.pathname === '/' || url.pathname === undefined) { url.pathname = 'api/v0'; } if (env_js_1.isNode) { const Agent = (0, agent_1.default)(url); agent = opts.agent || new Agent({ keepAlive: true, // Similar to browsers which limit connections to six per host maxSockets: 6 }); } return Object.assign(Object.assign({}, opts), { host: url.host, protocol: url.protocol.replace(':', ''), port: Number(url.port), apiPath: url.pathname, url, agent }); }; /** * @param {Response} response */ const errorHandler = (response) => __awaiter(void 0, void 0, void 0, function* () { let msg; try { if ((response.headers.get('Content-Type') || '').startsWith('application/json')) { const data = yield response.json(); log(data); msg = data.Message || data.message; } else { msg = yield response.text(); } } catch ( /** @type {any} */err) { log('Failed to parse error response', err); // Failed to extract/parse error message from response msg = err.message; } /** @type {Error} */ let error = new http_js_1.default.HTTPError(response); if (msg) { // This is what rs-ipfs returns where there's a timeout if (msg.includes('deadline has elapsed')) { error = new http_js_1.default.TimeoutError(); } // This is what go-ipfs returns where there's a timeout if (msg && msg.includes('context deadline exceeded')) { error = new http_js_1.default.TimeoutError(); } } // This also gets returned if (msg && msg.includes('request timed out')) { error = new http_js_1.default.TimeoutError(); } // If we managed to extract a message from the response, use it if (msg) { error.message = msg; } throw error; }); exports.errorHandler = errorHandler; const KEBAB_REGEX = /[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g; /** * @param {string} str */ const kebabCase = (str) => { return str.replace(KEBAB_REGEX, function (match) { return '-' + match.toLowerCase(); }); }; /** * @param {string | number} value */ const parseTimeout = (value) => { return typeof value === 'string' ? (0, parse_duration_1.default)(value) : value; }; class Client extends http_js_1.default { /** * @param {Options|URL|Multiaddr|string} [options] */ constructor(options = {}) { const opts = normalizeOptions(options); super({ timeout: parseTimeout(opts.timeout || 0) || undefined, headers: opts.headers, base: `${opts.url}`, handleError: exports.errorHandler, transformSearchParams: (search) => { const out = new URLSearchParams(); for (const [key, value] of search) { if (value !== 'undefined' && value !== 'null' && key !== 'signal') { out.append(kebabCase(key), value); } // @ts-expect-error server timeouts are strings if (key === 'timeout' && !isNaN(value)) { out.append(kebabCase(key), value); } } return out; }, // @ts-expect-error this can be a https agent or a http agent agent: opts.agent }); // @ts-expect-error - cannot delete no-optional fields delete this.get; // @ts-expect-error - cannot delete no-optional fields delete this.put; // @ts-expect-error - cannot delete no-optional fields delete this.delete; // @ts-expect-error - cannot delete no-optional fields delete this.options; const fetch = this.fetch; /** * @param {string | Request} resource * @param {import('../types').HTTPOptions} options */ this.fetch = (resource, options = {}) => { if (typeof resource === 'string' && !resource.startsWith('/')) { resource = `${opts.url}/${resource}`; } return fetch.call(this, resource, merge(options, { method: 'POST' })); }; } } exports.Client = Client; exports.HTTPError = http_js_1.default.HTTPError; //# sourceMappingURL=core.js.map