UNPKG

infinibrowser

Version:

A TypeScript wrapper for the Infinibrowser API

179 lines (178 loc) 3.82 kB
//#region src/client.ts const buildUrl = (options) => { const url = new URL(`${options.API_URL}${options.path}`); if (options.params) { for (const [key, value] of Object.entries(options.params)) if (value !== null && value !== void 0) url.searchParams.append(key, String(value)); } return url; }; function mergeRequests(...requests) { let mergedResult = {}; const mergedHeaders = new Headers(); for (const request of requests) { if (!request) continue; mergedResult = { ...mergedResult, ...request }; new Headers(request.headers).forEach((value, key) => { mergedHeaders.set(key, value); }); } mergedResult.headers = mergedHeaders; return mergedResult; } function handleError(error) { if (error instanceof SyntaxError) return { ok: false, error_code: "SYNTAX_ERROR", error }; if (error instanceof DOMException) { if (error.name === "AbortError") return { ok: false, error_code: "TIMEOUT", error }; return { ok: false, error_code: "UNKNOWN_ERROR", error }; } return { ok: false, error_code: "UNKNOWN_ERROR", error }; } var Infinibrowser = class Infinibrowser { $config; constructor(config) { this.$config = config; } $refined(config) { return new Infinibrowser({ ...this.$config, ...config }); } async #fetchWithTimeout(url, init = {}) { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), this.$config.timeout); try { const requestInit = mergeRequests(this.$config.request, init, { signal: controller.signal, headers: { "Accept-Encoding": "gzip, deflate, identity" } }); const request = new Request(url, requestInit); const response = await fetch(request); const ok = response.ok; if (!ok) { const text$1 = await response.clone().text(); return { ok, error_code: "NOT_OK", response, data: JSON.parse(text$1) }; } const text = await response.clone().text(); return { ok, data: JSON.parse(text), response }; } catch (error) { return handleError(error); } finally { clearTimeout(timeout); } } async #get(options) { const url = buildUrl({ API_URL: this.$config.API_URL, ...options }); return this.#fetchWithTimeout(url, { method: "GET", headers: { Accept: "application/json" } }); } async #post(options) { const url = buildUrl({ API_URL: this.$config.API_URL, ...options }); return this.#fetchWithTimeout(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(options.payload ?? {}) }); } async getItem(id) { return this.#get({ path: "/item", params: { id } }); } async getRecipes(id, { offset = 0 } = {}) { return this.#get({ path: "/recipes", params: { id, offset } }); } async getUses(id, { offset = 0 } = {}) { return this.#get({ path: "/uses", params: { id, offset } }); } async getLineage(id) { return this.#get({ path: "/recipe", params: { id } }); } async getCustomLineage(id) { return this.#get({ path: "/recipe/custom", params: { id } }); } async optimizeLineage(id) { return this.#post({ path: "/optimize-lineage", params: { id } }); } async shareLineage(steps) { const path = "/analytics/share"; const lastStep = steps.at(-1); if (!lastStep) throw new Error("Lineage must not be empty"); const resultElement = lastStep[2]; const payload = { id: resultElement.id, emoji: resultElement.emoji, steps }; return this.#post({ path, payload }); } }; const API_URL = "https://infinibrowser.wiki/api"; const DEFAULT_OPTIONS = { API_URL, timeout: 1e3 }; const ib = new Infinibrowser(DEFAULT_OPTIONS); //#endregion export { API_URL, DEFAULT_OPTIONS, Infinibrowser, ib };