UNPKG

kinto

Version:

An Offline-First JavaScript client for Kinto.

214 lines (191 loc) 6.63 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var _errorsJs = require("./errors.js"); var _errorsJs2 = _interopRequireDefault(_errorsJs); /** * Enhanced HTTP client for the Kinto protocol. */ var HTTP = (function () { _createClass(HTTP, null, [{ key: "DEFAULT_REQUEST_HEADERS", /** * Default HTTP request headers applied to each outgoing request. * * @type {Object} */ get: function get() { return { "Accept": "application/json", "Content-Type": "application/json" }; } /** * Default options. * * @type {Object} */ }, { key: "defaultOptions", get: function get() { return { timeout: 5000, requestMode: "cors" }; } /** * Constructor. * * Options: * - {Number} timeout The request timeout in ms (default: `5000`). * - {String} requestMode The HTTP request mode (default: `"cors"`). * * @param {EventEmitter} events The event handler. * @param {Object} options The options object. */ }]); function HTTP(events) { var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; _classCallCheck(this, HTTP); // public properties /** * The event emitter instance. * @type {EventEmitter} */ if (!events) { throw new Error("No events handler provided"); } this.events = events; options = Object.assign({}, HTTP.defaultOptions, options); /** * The request mode. * @see https://fetch.spec.whatwg.org/#requestmode * @type {String} */ this.requestMode = options.requestMode; /** * The request timeout. * @type {Number} */ this.timeout = options.timeout; } /** * Performs an HTTP request to the Kinto server. * * Options: * - `{Object} headers` The request headers object (default: {}) * * Resolves with an objet containing the following HTTP response properties: * - `{Number} status` The HTTP status code. * - `{Object} json` The JSON response body. * - `{Headers} headers` The response headers object; see the ES6 fetch() spec. * * @param {String} url The URL. * @param {Object} options The fetch() options object. * @return {Promise} */ _createClass(HTTP, [{ key: "request", value: function request(url) { var _this = this; var options = arguments.length <= 1 || arguments[1] === undefined ? { headers: {} } : arguments[1]; var response = undefined, status = undefined, statusText = undefined, headers = undefined, _timeoutId = undefined, hasTimedout = undefined; // Ensure default request headers are always set options.headers = Object.assign({}, HTTP.DEFAULT_REQUEST_HEADERS, options.headers); options.mode = this.requestMode; return new Promise(function (resolve, reject) { _timeoutId = setTimeout(function () { hasTimedout = true; reject(new Error("Request timeout.")); }, _this.timeout); fetch(url, options).then(function (res) { if (!hasTimedout) { clearTimeout(_timeoutId); resolve(res); } })["catch"](function (err) { if (!hasTimedout) { clearTimeout(_timeoutId); reject(err); } }); }).then(function (res) { response = res; headers = res.headers; status = res.status; statusText = res.statusText; _this._checkForDeprecationHeader(headers); _this._checkForBackoffHeader(status, headers); return res.text(); }) // Check if we have a body; if so parse it as JSON. .then(function (text) { if (text.length === 0) { return null; } // Note: we can't consume the response body twice. return JSON.parse(text); })["catch"](function (err) { var error = new Error("HTTP " + (status || 0) + "; " + err); error.response = response; error.stack = err.stack; throw error; }).then(function (json) { if (json && status >= 400) { var message = "HTTP " + status + "; "; if (json.errno && json.errno in _errorsJs2["default"]) { message += _errorsJs2["default"][json.errno]; if (json.message) { message += ": " + json.message; } } else { message += statusText || ""; } var error = new Error(message.trim()); error.response = response; error.data = json; throw error; } return { status: status, json: json, headers: headers }; }); } }, { key: "_checkForDeprecationHeader", value: function _checkForDeprecationHeader(headers) { var alertHeader = headers.get("Alert"); if (!alertHeader) { return; } var alert = undefined; try { alert = JSON.parse(alertHeader); } catch (err) { console.warn("Unable to parse Alert header message", alertHeader); return; } console.warn(alert.message, alert.url); this.events.emit("deprecated", alert); } }, { key: "_checkForBackoffHeader", value: function _checkForBackoffHeader(status, headers) { var backoffMs = undefined; var backoffSeconds = parseInt(headers.get("Backoff"), 10); if (backoffSeconds > 0) { backoffMs = new Date().getTime() + backoffSeconds * 1000; } else { backoffMs = 0; } this.events.emit("backoff", backoffMs); } }]); return HTTP; })(); exports["default"] = HTTP; module.exports = exports["default"];