UNPKG

portals

Version:

Client-side HTTP requests with middleware support.

282 lines (266 loc) 10.1 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ /* global Reflect, Promise */ var __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; /** * Read all response headers from the given XHR instance into a standard * object literal. */ function getAllHeaders(xhr) { // Read all headers into a string var headers = xhr.getAllResponseHeaders(); // Split the header components apart into an array var arr = headers.trim().split(/[\r\n]+/); // Map over all of the headers to create an object var output = {}; for (var _i = 0, arr_1 = arr; _i < arr_1.length; _i++) { var line = arr_1[_i]; var parts = line.split(": "); var header = parts.shift(); var value = parts.join(": "); if (!!header) { output[header] = value; } } // Return the object return output; } /** * Sends the request to the server. This is used by createPortal() after * all middleware has been applied. */ function send(request) { return new Promise(function (accept, reject) { // Create the XHR object for the request var xhr = new XMLHttpRequest(); // Open the request with the given configuration xhr.open(request.method, request.url, true); xhr.withCredentials = !!request.withCredentials; // Add each header to the XHR request if (typeof request.headers === "object") { for (var k in request.headers) { var value = request.headers[k]; xhr.setRequestHeader(k, (Array.isArray(value) ? value.join(", ") : value)); } } // Reject on error xhr.onerror = function (ev) { reject(ev.error || new Error("XHR request failed without reason.")); }; // Generate a formatted object for the response xhr.onload = function () { var res = { xhr: xhr, statusCode: xhr.status, contentType: xhr.getResponseHeader("Content-Type"), headers: getAllHeaders(xhr), body: xhr.responseText, }; accept(res); }; // Send the request xhr.send(request.body); }); } /** * Creates and returns a new "portal" instance for creating HTTP * requests. Each request and response is passed through the * given middleware. */ function createPortal() { var middleware = []; for (var _i = 0; _i < arguments.length; _i++) { middleware[_i] = arguments[_i]; } // Add our send method as "middleware" middleware = middleware.concat(send); return function portal(request) { var oc_content_type = (request.headers ? request.headers["Content-Type"] : null); // Create a new copy of our request object so middleware doesn't mutate // a given object request = __assign({ method: "GET", withCredentials: false, headers: { "Content-Type": "text/plain", } }, request); // If the request body is a FormData object, then we automatically set // the Content-Type regardless of middleware if (!oc_content_type && request.body instanceof FormData) { request.headers["Content-Type"] = "multipart/form-data"; } // Track the last invoked middleware index var lastIndex = -1; // Next function invokes the next middleware in the stack (only once) function next(i) { // Warn and bail if a middleware is invoking its next() method multiple times if (lastIndex > i) { console.warn("Middleware fired its next() method more than once."); return Promise.reject(new Error("Middleware fired its next() method more than once.")); } // Track the last index that will fire lastIndex = i; // Invoke the next middleware in the stack or report an error try { var res = middleware[i](request, function () { return next(i + 1); }); return Promise.resolve(res); } catch (err) { return Promise.reject(err); } } return next(0); }; } /** * Encode and parse JSON requests and responses. */ function supportsJson() { return function (req, next) { if (req.json === true || (req.body !== null && (typeof req.body === "object" && !(req.body instanceof FormData) || Array.isArray(req.body)))) { if (typeof req.headers !== "object") { req.headers = {}; } req.headers["Content-Type"] = "application/json"; req.body = JSON.stringify(req.body); } return next().then(function (res) { if (res.contentType && res.contentType.indexOf("json") > -1) { res.body = JSON.parse(res.body); } return res; }); }; } /** * Applies the hostname prefix to the URL unless the given * URL already has a hostname. */ function applyHostnamePrefix(url, prefix) { return (url.indexOf("http") === 0 ? url : prefix + url); } /** * Applies a URI prefix. */ function applyResourcePrefix(url, prefix) { if (url.indexOf("http") === 0) { var matches = url.match(/^(https?\:\/\/[^\/?#]+)(?:[\/?#]|$)/i); var domain = matches && matches[1]; return (domain + prefix + url.replace(domain || "", "")); } else { return prefix + url; } } /** * Adds the given prefix string to the request's URL. Application rules * differ if the given prefix includes a hostname or not. */ function withPrefix(prefix) { var applyPrefix = (prefix.indexOf("http") === 0 ? applyHostnamePrefix : applyResourcePrefix); return function (request, next) { request.url = applyPrefix(request.url, prefix); return next(); }; } /** * Add a header to the request that can either override, or be overridden * by, the headers in the request. */ function withHeader(name, value, override) { if (override === void 0) { override = false; } // If value isn't a function, make it one var getValue = (typeof value !== "function" ? function () { return value; } : value); return function (request, next) { var _a; if (typeof request.headers !== "object") { request.headers = {}; } if (override) { request.headers[name] = getValue(request); } else { request.headers = __assign((_a = {}, _a[name] = getValue(request), _a), request.headers); } return next(); }; } /** * Adds the Authorization header with the returned string as the header value. * Won't set the Authorization token if the result from getToken is falsey. */ function withAuthorization(getToken, prefix) { if (prefix === void 0) { prefix = ""; } return function (request, next) { var token = getToken(request); if (!!token) { if (typeof request.headers !== "object") { request.headers = {}; } request.headers["Authorization"] = prefix + token; } return next(); }; } /** * Adds the Authorization header with the returned string as the bearer token. * Won't set the Authorization token if the result from getToken is falsey. */ function withBearer(getToken) { return withAuthorization(getToken, "Bearer "); } /** * Passes along the XSRF header from the XRSF-TOKEN cookie. */ function withXSRFToken(cookieName, headerName) { if (cookieName === void 0) { cookieName = "XSRF-TOKEN"; } if (headerName === void 0) { headerName = "X-XSRF-TOKEN"; } return function (req, next) { var match = document.cookie.match(new RegExp("(^|;\\s*)(" + cookieName + ")=([^;]*)")); var cookie = (match ? decodeURIComponent(match[3]) : ""); if (cookie) { req.headers = __assign({}, req.headers); req.headers[headerName] = cookie; } return next(); }; } (function (Method) { Method["GET"] = "GET"; Method["POST"] = "POST"; Method["PUT"] = "PUT"; Method["PATCH"] = "PATCH"; Method["DELETE"] = "DELETE"; Method["HEAD"] = "HEAD"; Method["UPDATE"] = "UPDATE"; })(exports.Method || (exports.Method = {})); exports.getAllHeaders = getAllHeaders; exports.send = send; exports.createPortal = createPortal; exports.supportsJson = supportsJson; exports.withPrefix = withPrefix; exports.withHeader = withHeader; exports.withAuthorization = withAuthorization; exports.withBearer = withBearer; exports.withXSRFToken = withXSRFToken;