UNPKG

@logsn/arweave

Version:
159 lines (158 loc) 5.47 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); class Api { METHOD_GET = "GET"; METHOD_POST = "POST"; config; constructor(config) { this.applyConfig(config); } applyConfig(config) { this.config = this.mergeDefaults(config); } getConfig() { return this.config; } mergeDefaults(config) { const protocol = config.protocol || "http"; const port = config.port || (protocol === "https" ? 443 : 80); return { host: config.host || "127.0.0.1", protocol, port, timeout: config.timeout || 20000, logging: config.logging || false, logger: config.logger || console.log, network: config.network, }; } applyRequestDefaults(endpoint, method, config) { if (!config) { return config; } if (!this.config.defaultResponseTypes) { return config; } if (endpoint === 'tx' && method === this.METHOD_POST) { if (this.config.defaultResponseTypes.postTransaction) { if (!config.responseType) { config.responseType = this.config.defaultResponseTypes.postTransaction; } } } return config; } async get(endpoint, config) { config = this.applyRequestDefaults(endpoint, this.METHOD_GET, config); return await this.request(endpoint, { ...config, method: this.METHOD_GET }); } async post(endpoint, body, config) { config = this.applyRequestDefaults(endpoint, this.METHOD_GET, config); const headers = new Headers(config?.headers || {}); if (!headers.get("content-type")?.includes("application/json")) { headers.append("content-type", "application/json"); } headers.append("accept", "application/json, text/plain, */*"); return await this.request(endpoint, { ...config, method: this.METHOD_POST, body: typeof body !== "string" ? JSON.stringify(body) : body, headers, }); } async request(endpoint, init) { const headers = new Headers(init?.headers || {}); const baseURL = `${this.config.protocol}://${this.config.host}:${this.config.port}`; /* responseType is purely for backwards compatibility with external apps */ let responseType = init?.responseType; delete init?.responseType; if (endpoint.startsWith("/")) { endpoint = endpoint.slice(1); } if (this.config.network) { headers.append("x-network", this.config.network); } if (this.config.logging) { this.config.logger(`Requesting: ${baseURL}/${endpoint}`); } let res = await fetch(`${baseURL}/${endpoint}`, { ...(init || {}), headers, }); if (this.config.logging) { this.config.logger(`Response: ${res.url} - ${res.status}`); } const contentType = res.headers.get("content-type"); const charset = contentType?.match(/charset=([^()<>@,;:\"/[\]?.=\s]*)/i)?.[1]; const response = res; const decodeText = async () => { if (charset) { try { response.data = new TextDecoder(charset).decode(await res.arrayBuffer()); } catch (e) { response.data = (await res.text()); } } else { response.data = (await res.text()); } }; if (responseType === "arraybuffer") { response.data = (await res.arrayBuffer()); } else if (responseType === "text") { await decodeText(); } else if (responseType === "webstream") { response.data = addAsyncIterator(res.body); } else { /** axios defaults to JSON, and then text, we mimic the behaviour */ try { let test = await res.clone().json(); if (typeof test !== "object") { await decodeText(); } else { response.data = (await res.json()); } test = null; } catch { await decodeText(); } } return response; } } exports.default = Api; /** * *** To be removed when browsers catch up with the whatwg standard. *** * [Symbol.AsyncIterator] is needed to use `for-await` on the returned ReadableStream (web stream). * Feature is available in nodejs, and should be available in browsers eventually. */ const addAsyncIterator = (body) => { const bodyWithIter = body; if (typeof bodyWithIter[Symbol.asyncIterator] === "undefined") { bodyWithIter[Symbol.asyncIterator] = webIiterator(body); return bodyWithIter; } return body; }; const webIiterator = function (stream) { return async function* iteratorGenerator() { const reader = stream.getReader(); //lock try { while (true) { const { done, value } = await reader.read(); if (done) return; yield value; } } finally { reader.releaseLock(); //unlock } }; };