@ariyana/appauth
Version:
A general purpose OAuth client.
143 lines • 14.9 kB
JavaScript
;
/*
* Copyright 2017 Google Inc.
*
* 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
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.TestRequestor = exports.FetchRequestor = exports.JQueryRequestor = exports.Requestor = void 0;
var errors_1 = require("./errors");
/**
* An class that abstracts away the ability to make an XMLHttpRequest.
*/
var Requestor = /** @class */ (function () {
function Requestor() {
}
return Requestor;
}());
exports.Requestor = Requestor;
/**
* Uses $.ajax to makes the Ajax requests.
*/
var JQueryRequestor = /** @class */ (function (_super) {
__extends(JQueryRequestor, _super);
function JQueryRequestor() {
return _super !== null && _super.apply(this, arguments) || this;
}
JQueryRequestor.prototype.xhr = function (settings) {
// NOTE: using jquery to make XHR's as whatwg-fetch requires
// that I target ES6.
var xhr = $.ajax(settings);
return new Promise(function (resolve, reject) {
xhr.then(function (data, textStatus, jqXhr) {
resolve(data);
}, function (jqXhr, textStatus, error) {
reject(new errors_1.AppAuthError(error));
});
});
};
return JQueryRequestor;
}(Requestor));
exports.JQueryRequestor = JQueryRequestor;
/**
* Uses fetch API to make Ajax requests
*/
var FetchRequestor = /** @class */ (function (_super) {
__extends(FetchRequestor, _super);
function FetchRequestor() {
return _super !== null && _super.apply(this, arguments) || this;
}
FetchRequestor.prototype.xhr = function (settings) {
if (!settings.url) {
return Promise.reject(new errors_1.AppAuthError('A URL must be provided.'));
}
var url = new URL(settings.url);
var requestInit = {};
requestInit.method = settings.method;
requestInit.mode = 'cors';
if (settings.data) {
if (settings.method && settings.method.toUpperCase() === 'POST') {
requestInit.body = settings.data;
}
else {
var searchParams = new URLSearchParams(settings.data);
searchParams.forEach(function (value, key) {
url.searchParams.append(key, value);
});
}
}
// Set the request headers
requestInit.headers = {};
if (settings.headers) {
for (var i in settings.headers) {
if (settings.headers.hasOwnProperty(i)) {
requestInit.headers[i] = settings.headers[i];
}
}
}
var isJsonDataType = settings.dataType && settings.dataType.toLowerCase() === 'json';
// Set 'Accept' header value for json requests (Taken from
// https://github.com/jquery/jquery/blob/e0d941156900a6bff7c098c8ea7290528e468cf8/src/ajax.js#L644
// )
if (isJsonDataType) {
requestInit.headers['Accept'] = 'application/json, text/javascript, */*; q=0.01';
}
return fetch(url.toString(), requestInit).then(function (response) {
if (response.status >= 200 && response.status < 300) {
var contentType = response.headers.get('content-type');
if (isJsonDataType || (contentType && contentType.indexOf('application/json') !== -1)) {
return response.json();
}
else {
return response.text();
}
}
else {
return Promise.reject(new errors_1.AppAuthError(response.status.toString(), response.statusText));
}
});
};
return FetchRequestor;
}(Requestor));
exports.FetchRequestor = FetchRequestor;
/**
* Should be used only in the context of testing. Just uses the underlying
* Promise to mock the behavior of the Requestor.
*/
var TestRequestor = /** @class */ (function (_super) {
__extends(TestRequestor, _super);
function TestRequestor(promise) {
var _this = _super.call(this) || this;
_this.promise = promise;
return _this;
}
TestRequestor.prototype.xhr = function (settings) {
return this.promise; // unsafe cast
};
return TestRequestor;
}(Requestor));
exports.TestRequestor = TestRequestor;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoieGhyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3hoci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7OztHQVlHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFSCxtQ0FBc0M7QUFFdEM7O0dBRUc7QUFDSDtJQUFBO0lBRUEsQ0FBQztJQUFELGdCQUFDO0FBQUQsQ0FBQyxBQUZELElBRUM7QUFGcUIsOEJBQVM7QUFJL0I7O0dBRUc7QUFDSDtJQUFxQyxtQ0FBUztJQUE5Qzs7SUFlQSxDQUFDO0lBZEMsNkJBQUcsR0FBSCxVQUFPLFFBQTRCO1FBQ2pDLDREQUE0RDtRQUM1RCxxQkFBcUI7UUFDckIsSUFBTSxHQUFHLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUM3QixPQUFPLElBQUksT0FBTyxDQUFJLFVBQUMsT0FBTyxFQUFFLE1BQU07WUFDcEMsR0FBRyxDQUFDLElBQUksQ0FDSixVQUFDLElBQUksRUFBRSxVQUFVLEVBQUUsS0FBSztnQkFDdEIsT0FBTyxDQUFDLElBQVMsQ0FBQyxDQUFDO1lBQ3JCLENBQUMsRUFDRCxVQUFDLEtBQUssRUFBRSxVQUFVLEVBQUUsS0FBSztnQkFDdkIsTUFBTSxDQUFDLElBQUkscUJBQVksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBQ2xDLENBQUMsQ0FBQyxDQUFDO1FBQ1QsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBQ0gsc0JBQUM7QUFBRCxDQUFDLEFBZkQsQ0FBcUMsU0FBUyxHQWU3QztBQWZZLDBDQUFlO0FBa0I1Qjs7R0FFRztBQUNIO0lBQW9DLGtDQUFTO0lBQTdDOztJQXFEQSxDQUFDO0lBcERDLDRCQUFHLEdBQUgsVUFBTyxRQUE0QjtRQUNqQyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsRUFBRTtZQUNqQixPQUFPLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxxQkFBWSxDQUFDLHlCQUF5QixDQUFDLENBQUMsQ0FBQztTQUNw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T0FBTyxDQUFDLENBQUUsY0FBYztJQUN0QyxDQUFDO0lBQ0gsb0JBQUM7QUFBRCxDQUFDLEFBUEQsQ0FBbUMsU0FBUyxHQU8zQztBQVBZLHNDQUFhIiwic291cmNlc0NvbnRlbnQiOlsiLypcclxuICogQ29weXJpZ2h0IDIwMTcgR29vZ2xlIEluYy5cclxuICpcclxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTsgeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHRcclxuICogaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcclxuICpcclxuICogaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXHJcbiAqXHJcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmUgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlXHJcbiAqIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLCBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyXHJcbiAqIGV4cHJlc3Mgb3IgaW1wbGllZC4gU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxyXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cclxuICovXHJcblxyXG5pbXBvcnQge0FwcEF1dGhFcnJvcn0gZnJvbSAnLi9lcnJvcnMnO1xyXG5cclxuLyoqXHJcbiAqIEFuIGNsYXNzIHRoYXQgYWJzdHJhY3RzIGF3YXkgdGhlIGFiaWxpdHkgdG8gbWFrZSBhbiBYTUxIdHRwUmVxdWVzdC5cclxuICovXHJcbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBSZXF1ZXN0b3Ige1xyXG4gIGFic3RyYWN0IHhocjxUPihzZXR0aW5nczogSlF1ZXJ5QWpheFNldHRpbmdzKTogUHJvbWlzZTxUPjtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVzZXMgJC5hamF4IHRvIG1ha2VzIHRoZSBBamF4IHJlcXVlc3RzLlxyXG4gKi9cclxuZXhwb3J0IGNsYXNzIEpRdWVyeVJlcXVlc3RvciBleHRlbmRzIFJlcXVlc3RvciB7XHJcbiAgeGhyPFQ+KHNldHRpbmdzOiBKUXVlcnlBamF4U2V0dGluZ3MpOiBQcm9taXNlPFQ+IHtcclxuICAgIC8vIE5PVEU6IHVzaW5nIGpxdWVyeSB0byBtYWtlIFhIUidzIGFzIHdoYXR3Zy1mZXRjaCByZXF1aXJlc1xyXG4gICAgLy8gdGhhdCBJIHRhcmdldCBFUzYuXHJcbiAgICBjb25zdCB4aHIgPSAkLmFqYXgoc2V0dGluZ3MpO1xyXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlPFQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgICAgeGhyLnRoZW4oXHJcbiAgICAgICAgICAoZGF0YSwgdGV4dFN0YXR1cywganFYaHIpID0+IHtcclxuICAgICAgICAgICAgcmVzb2x2ZShkYXRhIGFzIFQpO1xyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIChqcVhociwgdGV4dFN0YXR1cywgZXJyb3IpID0+IHtcclxuICAgICAgICAgICAgcmVqZWN0KG5ldyBBcHBBdXRoRXJyb3IoZXJyb3IpKTtcclxuICAgICAgICAgIH0pO1xyXG4gICAgfSk7XHJcbiAgfVxyXG59XHJcblxyXG5cclxuLyoqXHJcbiAqIFVzZXMgZmV0Y2ggQVBJIHRvIG1ha2UgQWpheCByZXF1ZXN0c1xyXG4gKi9cclxuZXhwb3J0IGNsYXNzIEZldGNoUmVxdWVzdG9yIGV4dGVuZHMgUmVxdWVzdG9yIHtcclxuICB4aHI8VD4oc2V0dGluZ3M6IEpRdWVyeUFqYXhTZXR0aW5ncyk6IFByb21pc2U8VD4ge1xyXG4gICAgaWYgKCFzZXR0aW5ncy51cmwpIHtcclxuICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KG5ldyBBcHBBdXRoRXJyb3IoJ0EgVVJMIG11c3QgYmUgcHJvdmlkZWQuJykpO1xyXG4gICAgfVxyXG4gICAgbGV0IHVybDogVVJMID0gbmV3IFVSTCg8c3RyaW5nPnNldHRpbmdzLnVybCk7XHJcbiAgICBsZXQgcmVxdWVzdEluaXQ6IFJlcXVlc3RJbml0ID0ge307XHJcbiAgICByZXF1ZXN0SW5pdC5tZXRob2QgPSBzZXR0aW5ncy5tZXRob2Q7XHJcbiAgICByZXF1ZXN0SW5pdC5tb2RlID0gJ2NvcnMnO1xyXG5cclxuICAgIGlmIChzZXR0aW5ncy5kYXRhKSB7XHJcbiAgICAgIGlmIChzZXR0aW5ncy5tZXRob2QgJiYgc2V0dGluZ3MubWV0aG9kLnRvVXBwZXJDYXNlKCkgPT09ICdQT1NUJykge1xyXG4gICAgICAgIHJlcXVlc3RJbml0LmJvZHkgPSA8c3RyaW5nPnNldHRpbmdzLmRhdGE7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbGV0IHNlYXJjaFBhcmFtcyA9IG5ldyBVUkxTZWFyY2hQYXJhbXMoc2V0dGluZ3MuZGF0YSk7XHJcbiAgICAgICAgc2VhcmNoUGFyYW1zLmZvckVhY2goKHZhbHVlLCBrZXkpID0+wqB7XHJcbiAgICAgICAgICB1cmwuc2VhcmNoUGFyYW1zLmFwcGVuZChrZXksIHZhbHVlKTtcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFNldCB0aGUgcmVxdWVzdCBoZWFkZXJzXHJcbiAgICByZXF1ZXN0SW5pdC5oZWFkZXJzID0ge307XHJcbiAgICBpZiAoc2V0dGluZ3MuaGVhZGVycykge1xyXG4gICAgICBmb3IgKGxldCBpIGluIHNldHRpbmdzLmhlYWRlcnMpIHtcclxuICAgICAgICBpZiAoc2V0dGluZ3MuaGVhZGVycy5oYXNPd25Qcm9wZXJ0eShpKSkge1xyXG4gICAgICAgICAgcmVxdWVzdEluaXQuaGVhZGVyc1tpXSA9IDxzdHJpbmc+c2V0dGluZ3MuaGVhZGVyc1tpXTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBpc0pzb25EYXRhVHlwZSA9IHNldHRpbmdzLmRhdGFUeXBlICYmIHNldHRpbmdzLmRhdGFUeXBlLnRvTG93ZXJDYXNlKCkgPT09ICdqc29uJztcclxuXHJcbiAgICAvLyBTZXQgJ0FjY2VwdCcgaGVhZGVyIHZhbHVlIGZvciBqc29uIHJlcXVlc3RzIChUYWtlbiBmcm9tXHJcbiAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vanF1ZXJ5L2pxdWVyeS9ibG9iL2UwZDk0MTE1NjkwMGE2YmZmN2MwOThjOGVhNzI5MDUyOGU0NjhjZjgvc3JjL2FqYXguanMjTDY0NFxyXG4gICAgLy8gKVxyXG4gICAgaWYgKGlzSnNvbkRhdGFUeXBlKSB7XHJcbiAgICAgIHJlcXVlc3RJbml0LmhlYWRlcnNbJ0FjY2VwdCddID0gJ2FwcGxpY2F0aW9uL2pzb24sIHRleHQvamF2YXNjcmlwdCwgKi8qOyBxPTAuMDEnO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBmZXRjaCh1cmwudG9TdHJpbmcoKSwgcmVxdWVzdEluaXQpLnRoZW4ocmVzcG9uc2UgPT4ge1xyXG4gICAgICBpZiAocmVzcG9uc2Uuc3RhdHVzID49IDIwMCAmJiByZXNwb25zZS5zdGF0dXMgPCAzMDApIHtcclxuICAgICAgICBjb25zdCBjb250ZW50VHlwZSA9IHJlc3BvbnNlLmhlYWRlcnMuZ2V0KCdjb250ZW50LXR5cGUnKTtcclxuICAgICAgICBpZiAoaXNKc29uRGF0YVR5cGUgfHwgKGNvbnRlbnRUeXBlICYmIGNvbnRlbnRUeXBlLmluZGV4T2YoJ2FwcGxpY2F0aW9uL2pzb24nKSAhPT0gLTEpKSB7XHJcbiAgICAgICAgICByZXR1cm4gcmVzcG9uc2UuanNvbigpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICByZXR1cm4gcmVzcG9uc2UudGV4dCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZWplY3QobmV3IEFwcEF1dGhFcnJvcihyZXNwb25zZS5zdGF0dXMudG9TdHJpbmcoKSwgcmVzcG9uc2Uuc3RhdHVzVGV4dCkpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTaG91bGQgYmUgdXNlZCBvbmx5IGluIHRoZSBjb250ZXh0IG9mIHRlc3RpbmcuIEp1c3QgdXNlcyB0aGUgdW5kZXJseWluZ1xyXG4gKiBQcm9taXNlIHRvIG1vY2sgdGhlIGJlaGF2aW9yIG9mIHRoZSBSZXF1ZXN0b3IuXHJcbiAqL1xyXG5leHBvcnQgY2xhc3MgVGVzdFJlcXVlc3RvciBleHRlbmRzIFJlcXVlc3RvciB7XHJcbiAgY29uc3RydWN0b3IocHVibGljIHByb21pc2U6IFByb21pc2U8YW55Pikge1xyXG4gICAgc3VwZXIoKTtcclxuICB9XHJcbiAgeGhyPFQ+KHNldHRpbmdzOiBKUXVlcnlBamF4U2V0dGluZ3MpOiBQcm9taXNlPFQ+IHtcclxuICAgIHJldHVybiB0aGlzLnByb21pc2U7ICAvLyB1bnNhZmUgY2FzdFxyXG4gIH1cclxufVxyXG4iXX0=