UNPKG

magicbell

Version:
90 lines 3.74 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Client = exports.DEFAULT_OPTIONS = void 0; const tslib_1 = require("tslib"); require("../lib/signal-polyfill.js"); const ky_1 = tslib_1.__importDefault(require("@smeijer/ky")); const url_join_1 = tslib_1.__importDefault(require("url-join")); const utils_js_1 = require("../lib/utils.js"); const cache_js_1 = require("./cache.js"); const error_js_1 = require("./error.js"); const headers_js_1 = require("./headers.js"); const log_js_1 = require("./log.js"); const options_js_1 = require("./options.js"); const telemetry_js_1 = require("./telemetry.js"); exports.DEFAULT_OPTIONS = { host: 'https://api.magicbell.com', timeout: 30_000, maxRetries: 3, maxRetryDelay: 60, telemetry: true, cacheTTL: 1000, }; class Client { #options; #cache; constructor(options) { (0, options_js_1.assertHasValidOptions)(options); (0, options_js_1.assertHasSomeOptions)(options, ['token', 'apiKey']); this.#options = { ...exports.DEFAULT_OPTIONS, ...options }; this.#cache = new cache_js_1.Cache({ ttl: this.#options.cacheTTL }); } hasFlag(flag) { return this.#options.features?.[flag] || false; } async request({ method, path, data, params, headers: reqHeaders }, options) { const requestOptions = { ...this.#options, ...options, headers: { ...this.#options.headers, ...reqHeaders }, }; // don't just use `new URL(path, host)` as that will strip the path from the host const url = new URL((0, url_join_1.default)(requestOptions.host, path)); for (const [key, value] of Object.entries(params || {}).sort()) { const val = Array.isArray(value) ? [...value].sort().join(',') : value; url.searchParams.append(key, val); } const hooks = (0, options_js_1.mergeHooks)((0, headers_js_1.withRequestHeaders)(requestOptions), (0, telemetry_js_1.withRequestTelemetry)(requestOptions), (0, log_js_1.withRequestLogging)(), this.#options.hooks); const requestKey = this.#cache.getRequestKey({ method, url, data, headers: reqHeaders }); // Check if there's already a pending request let promise = this.#cache.get(requestKey); if (promise) { return promise; } promise = (0, ky_1.default)(url, { method, body: data && JSON.stringify(data), retry: { limit: requestOptions.maxRetries, // all methods, as post get idempotency keys methods: ['get', 'post', 'put', 'head', 'delete', 'options', 'trace'], }, timeout: requestOptions.timeout, hooks, }) .then((response) => response .text() // handle cases where the response is empty .then((text) => JSON.parse(text)) .catch(() => undefined)) .catch(async (error) => { const body = (0, utils_js_1.tryParse)(await error?.response?.text()); throw (0, error_js_1.createError)({ code: error.code, name: error.name, message: error.message, type: error['type'], status: error?.response?.status, statusText: error?.response?.statusText, responseBody: body, ...body?.errors?.[0], stack: error.stack, }); }); // Cache the promise so we can dedupe parallel requests this.#cache.set(requestKey, promise); return promise; } } exports.Client = Client; //# sourceMappingURL=client.js.map