UNPKG

reduct-js

Version:

ReductStore Client SDK for Javascript/NodeJS/Typescript

167 lines (166 loc) 6.33 kB
import { __require } from "../_virtual/_rolldown/runtime.js"; import { APIError } from "../APIError.js"; import { isBrowser } from "../utils/env.js"; import { PACKAGE_VERSION } from "../version.js"; import { Buffer } from "buffer"; import JSONbig from "json-bigint"; //#region src/http/HttpClient.ts var bigJson = JSONbig({ alwaysParseAsBig: false, useNativeBigInt: true }); var undiciAgent = null; var undiciFetchImpl; if (!isBrowser) try { const { Agent, fetch } = __require("undici"); undiciFetchImpl = fetch; undiciAgent = new Agent({ connect: { rejectUnauthorized: false } }); } catch {} var InMemoryCookieJar = class { constructor() { this.cookies = /* @__PURE__ */ new Map(); } getCookieHeader() { if (this.cookies.size === 0) return; return Array.from(this.cookies.entries()).map(([name, value]) => `${name}=${value}`).join("; "); } setCookies(setCookieHeaders) { for (const header of setCookieHeaders) { const firstPair = header.split(";")[0]?.trim(); if (!firstPair) continue; const equalPos = firstPair.indexOf("="); if (equalPos <= 0) continue; const name = firstPair.slice(0, equalPos).trim(); const value = firstPair.slice(equalPos + 1).trim(); if (!name) continue; this.cookies.set(name, value); } } }; var getSetCookieHeaders = (headers) => { const maybeUndiciHeaders = headers; if (typeof maybeUndiciHeaders.getSetCookie === "function") return maybeUndiciHeaders.getSetCookie(); if (typeof maybeUndiciHeaders.raw === "function") return maybeUndiciHeaders.raw()["set-cookie"] ?? []; const single = headers.get("set-cookie"); return single ? [single] : []; }; var HttpClient = class { constructor(url, options = {}) { this.baseURL = `${url}/api/v1`; this.timeout = options.timeout; this.keepAlive = options.keepAlive ?? false; this.stickySessions = options.stickySessions ?? !isBrowser; this.cookieJar = this.stickySessions ? options.cookieJar ?? new InMemoryCookieJar() : void 0; this.headers = { Authorization: `Bearer ${options.apiToken}`, ...!isBrowser && !this.keepAlive ? { Connection: "close" } : {} }; if (!isBrowser && options.verifySSL === false) this.dispatcher = undiciAgent; this.fetchImpl = this.dispatcher && undiciFetchImpl ? undiciFetchImpl : globalThis.fetch.bind(globalThis); } async close() { if (isBrowser) return; if (this.dispatcher?.close) { await this.dispatcher.close(); return; } const dispatcher = (await import( /* webpackIgnore: true */ "undici" )).getGlobalDispatcher?.(); if (dispatcher?.destroy) { dispatcher.destroy(); return; } if (dispatcher?.close) await dispatcher.close(); } async request(method, url, body, headers) { const controller = new AbortController(); const { signal } = controller; const { timeout } = this; let abortedByTimeout = false; if (timeout) setTimeout(() => { abortedByTimeout = true; controller.abort(); }, timeout); const encodedBody = this.encodeBody(body); const hasReadableStream = typeof ReadableStream !== "undefined" && encodedBody instanceof ReadableStream; const requestHeaders = { ...this.headers, ...headers }; if (this.stickySessions) { const cookieHeader = this.cookieJar?.getCookieHeader(); if (cookieHeader) requestHeaders["Cookie"] = cookieHeader; } const init = { method, headers: requestHeaders, signal }; if (isBrowser && this.stickySessions) init.credentials = "include"; if (encodedBody !== void 0) init.body = encodedBody; if (this.dispatcher) init.dispatcher = this.dispatcher; if (hasReadableStream) init.duplex = "half"; const response = await this.fetchImpl(`${this.baseURL}${url}`, init).catch((err) => { if (abortedByTimeout) throw new APIError(`timeout of ${this.timeout}ms exceeded`, void 0, err); if (signal.aborted) throw new APIError("Request aborted", void 0, err); throw new APIError(err.message, void 0, err); }); if (this.stickySessions) { const setCookieHeaders = getSetCookieHeaders(response.headers); if (setCookieHeaders.length > 0) this.cookieJar?.setCookies(setCookieHeaders); } const apiVersionHeader = response.headers.get("x-reduct-api"); if (!apiVersionHeader) throw new APIError("Server did not provide API version", void 0, { response }); this.apiVersion = checkServeApiVersion(apiVersionHeader); if (!response.ok) throw new APIError(response.headers.get("x-reduct-error") || response.statusText, response.status, { response }); return { data: await this.parseResponse(response), headers: response.headers, status: response.status }; } encodeBody(data) { if (data === void 0 || typeof data === "string" || Buffer.isBuffer(data) || data instanceof Uint8Array || data instanceof ArrayBuffer || data instanceof Blob || data instanceof ReadableStream) return data; return bigJson.stringify(data); } async parseResponse(res) { if (res.status === 204) return {}; const ct = res.headers.get("content-type") ?? ""; if (!res.body) return {}; if (ct.startsWith("application/json")) { const text = await res.text(); return text ? bigJson.parse(text) : {}; } if (ct.startsWith("text/")) return res.text(); return res.body; } get(url, headers) { return this.request("GET", url, void 0, headers); } post(url, data, headers) { return this.request("POST", url, data, headers); } put(url, data, headers) { return this.request("PUT", url, data, headers); } patch(url, data, headers) { return this.request("PATCH", url, data, headers); } delete(url, headers) { return this.request("DELETE", url, void 0, headers); } head(url, headers) { return this.request("HEAD", url, void 0, headers); } }; var checkServeApiVersion = (serverApiVersion) => { const [server_major, server_minor] = serverApiVersion.split(".").map((v) => parseInt(v)); const [client_major, client_minor] = PACKAGE_VERSION.split(".").map((v) => parseInt(v)); if (server_major !== client_major) throw new APIError(`Incompatible server API version: ${serverApiVersion}. Client version: ${PACKAGE_VERSION}. Please update your client.`); if (server_minor + 2 < client_minor) console.error(`Server API version ${serverApiVersion} is too old for this client version ${PACKAGE_VERSION}. Please update your server.`); return [server_major, server_minor]; }; //#endregion export { HttpClient };