UNPKG

@sitecore-jss/sitecore-jss

Version:

This module is provided as a part of Sitecore JavaScript Rendering SDK. It contains the core JSS APIs (layout service) and utilities.

205 lines (204 loc) • 9.01 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.NativeDataFetcher = void 0; const debug_1 = __importDefault(require("./debug")); const timeout_promise_1 = __importDefault(require("./utils/timeout-promise")); class NativeDataFetcher { constructor(config = {}) { this.config = config; } /** * Implements a data fetcher. * @param {string} url The URL to request (may include query string) * @param {RequestInit} [options] Optional fetch options * @returns {Promise<NativeDataFetcherResponse<T>>} response */ fetch(url_1) { return __awaiter(this, arguments, void 0, function* (url, options = {}) { var _a; const _b = this.config, { debugger: debugOverride, fetch: fetchOverride } = _b, init = __rest(_b, ["debugger", "fetch"]); const startTimestamp = Date.now(); const fetchImpl = fetchOverride || fetch; const debug = debugOverride || debug_1.default.http; const requestInit = this.getRequestInit(Object.assign(Object.assign({}, init), options)); const fetchWithOptionalTimeout = [fetchImpl(url, requestInit)]; if (init.timeout) { this.abortTimeout = new timeout_promise_1.default(init.timeout); fetchWithOptionalTimeout.push(this.abortTimeout.start); } debug('Request initiated: %o', Object.assign({ url, headers: this.extractDebugHeaders(requestInit.headers) }, requestInit)); try { const response = yield Promise.race(fetchWithOptionalTimeout).then((res) => { var _a; (_a = this.abortTimeout) === null || _a === void 0 ? void 0 : _a.clear(); return res; }); const respData = yield this.parseResponse(response, debug); if (!response.ok) { const error = this.createError(response, respData); debug('Response error: %o', error.response); throw error; } debug('Response in %dms: %o', Date.now() - startTimestamp, { status: response.status, statusText: response.statusText, headers: this.extractDebugHeaders(response.headers), url: response.url, data: respData, }); return { data: respData, status: response.status, statusText: response.statusText, headers: response.headers, }; } catch (error) { (_a = this.abortTimeout) === null || _a === void 0 ? void 0 : _a.clear(); debug('Request failed: %o', error); throw error; } }); } /** * Perform a GET request * @param {string} url The URL to request (may include query string) * @param {RequestInit} [options] Fetch options * @returns {Promise<NativeDataFetcherResponse<T>>} response */ get(url_1) { return __awaiter(this, arguments, void 0, function* (url, options = {}) { return this.fetch(url, Object.assign({ method: 'GET' }, options)); }); } /** * Perform a POST request * @param {string} url The URL to request (may include query string) * @param {unknown} body The data to send with the request * @param {RequestInit} [options] Fetch options * @returns {Promise<NativeDataFetcherResponse<T>>} response */ post(url_1, body_1) { return __awaiter(this, arguments, void 0, function* (url, body, options = {}) { return this.fetch(url, Object.assign({ method: 'POST', body: JSON.stringify(body) }, options)); }); } /** * Perform a DELETE request * @param {string} url The URL to request (may include query string) * @param {RequestInit} [options] Fetch options * @returns {Promise<NativeDataFetcherResponse<T>>} response */ delete(url_1) { return __awaiter(this, arguments, void 0, function* (url, options = {}) { return this.fetch(url, Object.assign({ method: 'DELETE' }, options)); }); } /** * Perform a PUT request * @param {string} url The URL to request (may include query string) * @param {unknown} body The data to send with the request * @param {RequestInit} [options] Fetch options * @returns {Promise<NativeDataFetcherResponse<T>>} response */ put(url_1, body_1) { return __awaiter(this, arguments, void 0, function* (url, body, options = {}) { return this.fetch(url, Object.assign({ method: 'PUT', body: JSON.stringify(body) }, options)); }); } /** * Perform a HEAD request * @param {string} url The URL to request (may include query string) * @param {RequestInit} [options] Fetch options * @returns {Promise<NativeDataFetcherResponse<T>>} response */ head(url, options = {}) { return this.fetch(url, Object.assign({ method: 'HEAD' }, options)); } /** * Determines settings for the request * @param {RequestInit} init Custom settings for request * @returns {RequestInit} The final request settings */ getRequestInit(init = {}) { const headers = new Headers(init.headers); if (!init.method) { init.method = init.body ? 'POST' : 'GET'; } init.headers = headers; return init; } /** * Safely extract all headers for debug logging * @param {HeadersInit} incomingHeaders Incoming headers * @returns Object with headers as key/value pairs */ extractDebugHeaders(incomingHeaders = {}) { const headers = {}; if (typeof (incomingHeaders === null || incomingHeaders === void 0 ? void 0 : incomingHeaders.forEach) !== 'string' && incomingHeaders.forEach) { incomingHeaders === null || incomingHeaders === void 0 ? void 0 : incomingHeaders.forEach((value, key) => { headers[key] = value; }); } return headers; } /** * Parses the response data. * @param {Response} response - The fetch response object. * @param {Function} debug - The debug logger function. * @returns {Promise<unknown>} - The parsed response data. */ parseResponse(response, debug) { return __awaiter(this, void 0, void 0, function* () { const contentType = response.headers.get('Content-Type') || ''; try { if (contentType.includes('application/json')) { return yield response.json(); } return yield response.text(); } catch (error) { debug('Response parsing error: %o', error); return undefined; } }); } /** * Creates a custom error for fetch failures. * @param {Response} response - The fetch response object. * @param {unknown} data - The parsed response data. * @returns {NativeDataFetcherError} - The constructed error object. */ createError(response, data) { return Object.assign(Object.assign({}, new Error(`HTTP ${response.status} ${response.statusText}`)), { response: { status: response.status, statusText: response.statusText, headers: this.extractDebugHeaders(response.headers), data, } }); } } exports.NativeDataFetcher = NativeDataFetcher;