@logsn/arweave
Version:
Arweave JS client library
159 lines (158 loc) • 5.47 kB
JavaScript
;
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
}
};
};