react-onegraph
Version:
React bindings for OneGraph
1,236 lines (1,090 loc) • 40.5 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) :
typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) :
(global = global || self, factory(global['react-onegraph'] = {}, global.React));
}(this, (function (exports, React) { 'use strict';
function __$$styleInject(css, ref) {
if ( ref === void 0 ) ref = {};
var insertAt = ref.insertAt;
if (!css || typeof document === 'undefined') { return; }
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
if (insertAt === 'top') {
if (head.firstChild) {
head.insertBefore(style, head.firstChild);
} else {
head.appendChild(style);
}
} else {
head.appendChild(style);
}
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
}
var React__default = 'default' in React ? React['default'] : React;
function OAuthError(errorObject, fileName, lineNumber) {
var message = "OAuthError: " + errorObject.error + " " + errorObject.error_description;
// $FlowFixMe
var instance = new Error(message, fileName, lineNumber);
// $FlowFixMe
instance.oauthError = errorObject;
Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
if (Error.captureStackTrace) {
Error.captureStackTrace(instance, OAuthError);
}
return instance;
}
OAuthError.prototype = Object.create(Error.prototype, {
constructor: {
value: Error,
enumerable: false,
writable: true,
configurable: true
}
});
if (Object.setPrototypeOf) {
Object.setPrototypeOf(OAuthError, Error);
} else {
// $FlowFixMe: Ignore
OAuthError.__proto__ = Error;
}
var classCallCheck = function (instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
};
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;
};
}();
var _extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
var objectWithoutProperties = function (obj, keys) {
var target = {};
for (var i in obj) {
if (keys.indexOf(i) >= 0) continue;
if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
target[i] = obj[i];
}
return target;
};
var slicedToArray = function () {
function sliceIterator(arr, i) {
var _arr = [];
var _n = true;
var _d = false;
var _e = undefined;
try {
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i["return"]) _i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
return function (arr, i) {
if (Array.isArray(arr)) {
return arr;
} else if (Symbol.iterator in Object(arr)) {
return sliceIterator(arr, i);
} else {
throw new TypeError("Invalid attempt to destructure non-iterable instance");
}
};
}();
var toConsumableArray = function (arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
} else {
return Array.from(arr);
}
};
var InMemoryStorage = function InMemoryStorage() {
var _this = this;
classCallCheck(this, InMemoryStorage);
this.state = {};
this.getItem = function (key) {
return _this.state[key];
};
this.setItem = function (key, value) {
_this.state[key] = value;
};
this.removeItem = function (key) {
delete _this.state[key];
};
};
var OG_PREFIX = 'oneGraph:';
var LocalStorage = function () {
function LocalStorage() {
classCallCheck(this, LocalStorage);
}
createClass(LocalStorage, [{
key: 'getItem',
value: function getItem(key) {
return localStorage.getItem(OG_PREFIX + key);
}
}, {
key: 'setItem',
value: function setItem(key, value) {
return localStorage.setItem(OG_PREFIX + key, value);
}
}, {
key: 'removeItem',
value: function removeItem(key) {
return localStorage.removeItem(OG_PREFIX + key);
}
}]);
return LocalStorage;
}();
var DEBUG_KEY = '__og_debug';
function hasLocalStorage() {
try {
localStorage.setItem(DEBUG_KEY, 'debug');
localStorage.removeItem(DEBUG_KEY);
return true;
} catch (e) {
return (
// $FlowFixMe
e instanceof DOMException && (
// everything except Firefox
e.code === 22 ||
// Firefox
e.code === 1014 ||
// test name field too, because code might not be present
// everything except Firefox
e.name === 'QuotaExceededError' ||
// Firefox
e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
// acknowledge QuotaExceededError only if there's something already stored
localStorage.length !== 0
);
}
}
var URI_REGEX = new RegExp(['^(https?://[^:/?#]*(?::[0-9]+)?)', // origin
'(/{0,1}[^?#]*)', // path
'(\\?[^#]*|)', // search
'(#.*|)$'].join(''));
function parseQuery(queryString) {
return queryString.split(/[?&]/).reduce(function (query, part) {
var _part$split = part.split('='),
_part$split2 = slicedToArray(_part$split, 2),
param = _part$split2[0],
value = _part$split2[1];
if (param != null && value != null) {
query[param] = value;
}
return query;
}, {});
}
function parse(uriString) {
var match = uriString.match(URI_REGEX);
if (!match) {
throw new Error('invalid url ' + uriString);
}
return {
origin: match[1],
path: match[2],
query: parseQuery(match[3])
};
}
function safeParse(uriString) {
try {
return parse(uriString);
} catch (e) {
return null;
}
}
function addQueryParams(uri, query) {
return _extends({}, uri, {
query: _extends({}, uri.query, query)
});
}
function setPath(uri, path) {
return _extends({}, uri, {
path: path
});
}
function queryToString(query) {
return Object.keys(query).map(function (k) {
return k + '=' + query[k];
}).join('&');
}
function toString(uri) {
var origin = uri.origin,
path = uri.path,
query = uri.query;
var queryString = queryToString(query);
return origin + path + (queryString ? '?' + queryString : '');
}
function make(_ref) {
var origin = _ref.origin,
path = _ref.path,
query = _ref.query;
var uri = parse(origin);
uri = setPath(uri, path);
uri = addQueryParams(uri, query);
return uri;
}
var URI = {
parse: parse,
safeParse: safeParse,
addQueryParams: addQueryParams,
setPath: setPath,
toString: toString,
make: make,
queryToString: queryToString
};
function getCrypto() {
return window.crypto || window.msCrypto;
}
function getSubtle() {
var crypto = getCrypto();
return crypto.subtle || crypto.webkitSubtle;
}
// https://tools.ietf.org/html/rfc7636#section-4.1
function generateVerifier() {
var chars = '0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz-._~';
var s = '';
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = getCrypto().getRandomValues(new Uint8Array(64))[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var value = _step.value;
s = s + chars[value % chars.length];
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return s;
}
function supportsSha256() {
var subtle = getSubtle();
return subtle && subtle.digest && typeof TextEncoder !== 'undefined' && typeof btoa !== 'undefined' &&
// Skip old version of subtle.digest on IE that returns a CryptoOperation
typeof subtle.digest({ name: 'SHA-256' }, new Uint8Array(2)).process === 'undefined';
}
function sha256(s) {
return getSubtle().digest({ name: 'SHA-256' }, new TextEncoder().encode(s));
}
function urlSafeBase64(s) {
return s.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
}
function codeChallengeOfVerifier(verifier) {
if (!supportsSha256()) {
return Promise.resolve({
challenge: verifier,
method: 'plain'
});
} else {
return sha256(verifier).then(function (s) {
return {
challenge: urlSafeBase64(btoa(String.fromCharCode.apply(String, toConsumableArray(Array.from(new Uint8Array(s)))))),
method: 'S256'
};
});
}
}
var PKCE = {
generateVerifier: generateVerifier,
codeChallengeOfVerifier: codeChallengeOfVerifier
};
function findMissingAuthServices(results) {
/* Detect and normalize between:
1. The full graphql result
2. The `result.errors` of a graphql result
3. Apollo's GraphQL error structure
*/
var errors = results && (
// Full GraphQL result
results.errors ||
// Apollo error
results.graphQLErrors ||
// Possibly result.errors
results);
// If errors aren't an array, bail
if (!Array.isArray(errors)) {
return [];
}
var missingServiceErrors = errors.filter(function (error) {
var _ref;
return ((_ref = error) != null ? (_ref = _ref.extensions) != null ? _ref.type : _ref : _ref) === 'auth/missing-auth';
});
var missingServices = missingServiceErrors.map(function (error) {
var _ref2;
return (_ref2 = error) != null ? (_ref2 = _ref2.extensions) != null ? _ref2.service : _ref2 : _ref2;
}).filter(Boolean);
return missingServices;
} // $FlowFixMe
// $FlowFixMe
var POLL_INTERVAL = 35;
var ALL_SERVICES = ['adroll', 'asana', 'box', 'contentful', 'dev-to', 'dribbble', 'dropbox', 'eggheadio', 'eventil', 'facebook', 'firebase', 'github', 'gmail', 'google', 'google-ads', 'google-analytics', 'google-calendar', 'google-compute', 'google-docs', 'google-search-console', 'google-translate', 'hubspot', 'intercom', 'mailchimp', 'meetup', 'netlify', 'product-hunt', 'quickbooks', 'salesforce', 'slack', 'spotify', 'stripe', 'trello', 'twilio', 'twitch-tv', 'twitter', 'ynab', 'youtube', 'zeit', 'zendesk'];
function _friendlyServiceName(service) {
switch (service) {
case 'adroll':
return 'Adroll';
case 'asana':
return 'Asana';
case 'box':
return 'Box';
case 'dev-to':
return 'Dev.to';
case 'dribbble':
return 'Dribbble';
case 'dropbox':
return 'Dropbox';
case 'contentful':
return 'Contentful';
case 'eggheadio':
return 'Egghead.io';
case 'eventil':
return 'Eventil';
case 'facebook':
return 'Facebook';
case 'firebase':
return 'Firebase';
case 'github':
return 'GitHub';
case 'gmail':
return 'Gmail';
case 'google':
return 'Google';
case 'google-ads':
return 'Google Ads';
case 'google-analytics':
return 'Google Analytics';
case 'google-calendar':
return 'Google Calendar';
case 'google-compute':
return 'Google Compute';
case 'google-docs':
return 'Google Docs';
case 'google-search-console':
return 'Google Search Console';
case 'google-translate':
return 'Google Translate';
case 'hubspot':
return 'Hubspot';
case 'intercom':
return 'Intercom';
case 'mailchimp':
return 'Mailchimp';
case 'meetup':
return 'Meetup';
case 'netlify':
return 'Netlify';
case 'product-hunt':
return 'Product Hunt';
case 'quickbooks':
return 'QuickBooks';
case 'salesforce':
return 'Salesforce';
case 'slack':
return 'Slack';
case 'spotify':
return 'Spotify';
case 'stripe':
return 'Stripe';
case 'trello':
return 'Trello';
case 'twilio':
return 'Twilio';
case 'twitter':
return 'Twitter';
case 'twitch-tv':
return 'Twitch';
case 'ynab':
return 'You Need a Budget';
case 'youtube':
return 'YouTube';
case 'zeit':
return 'Vercel';
case 'zendesk':
return 'Zendesk';
default:
return service;
}
}
function getWindowOpts() {
var windowWidth = Math.min(800, Math.floor(window.outerWidth * 0.8));
var windowHeight = Math.min(630, Math.floor(window.outerHeight * 0.5));
var windowArea = {
width: windowWidth,
height: windowHeight,
left: Math.round(window.screenX + (window.outerWidth - windowWidth) / 2),
top: Math.round(window.screenY + (window.outerHeight - windowHeight) / 8)
};
// TODO: figure out how to show the toolbar icons in the window for password managers
return {
width: windowArea.width,
height: windowArea.height,
left: windowArea.left,
top: windowArea.top,
toolbar: 0,
scrollbars: 1,
status: 1,
resizable: 1,
menuBar: 0
};
}
function createAuthWindow(_ref3) {
var url = _ref3.url,
service = _ref3.service;
var windowOpts = getWindowOpts();
var w = window.open(url || '',
// A unqiue name prevents orphaned popups from stealing our window.open
(service + '_' + Math.random()).replace('.', ''), Object.keys(windowOpts).map(function (k) {
return k + '=' + windowOpts[k];
}).join(','));
if (!url && w && w.document) {
try {
w.document.title = 'Log in with ' + _friendlyServiceName(service);
w.document.body.innerHTML = '<div style="display:flex;justify-content:center;align-items:center;height:100vh;width:100vw%"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" width="48px" height="48px" style="background: none;"><circle cx="50" cy="50" fill="none" stroke="#3cc7b6" stroke-width="8" r="24" stroke-dasharray="112 40" transform="rotate(138.553 50 50)"><animateTransform attributeName="transform" type="rotate" calcMode="linear" values="0 50 50;360 50 50" keyTimes="0;1" dur="1s" begin="0s" repeatCount="indefinite"></animateTransform></circle></svg></div>';
} catch (e) {}
}
return w;
}
// Cycles path through URL.origin to ensure that it's the same format we'll
// see in the auth window's location
function normalizeRedirectOrigin(origin) {
return URI.parse(origin).origin;
}
// Cycles path through URL.pathname to ensure that it's the same format we'll
// see in the auth window's location
function normalizeRedirectPath(path) {
return path === '/' ? '' : path;
}
var loggedInQuery = '\nquery LoggedInQuery {\n me {\n serviceMetadata {\n loggedInServices {\n service\n foreignUserId\n usedTestFlow\n }\n }\n }\n}\n';
var allServicesQuery = '\nquery AllServicesQuery {\n oneGraph {\n services(filter: {supportsOauthLogin: true}) {\n service\n friendlyServiceName\n supportsTestFlow\n }\n }\n}\n';
function getServiceEnum(service) {
return service.toUpperCase().replace(/-/g, '_');
}
function fromServiceEnum(serviceEnum) {
return serviceEnum.toLowerCase().replace(/_/g, '-');
}
function getIsLoggedIn(queryResult, service, foreignUserId) {
var _ref;
var serviceEnum = getServiceEnum(service);
var loggedInServices = ((_ref = queryResult) != null ? (_ref = _ref.data) != null ? (_ref = _ref.me) != null ? (_ref = _ref.serviceMetadata) != null ? _ref.loggedInServices : _ref : _ref : _ref : _ref) || [];
return !!loggedInServices.find(function (serviceInfo) {
return serviceInfo.service === serviceEnum && (!foreignUserId || foreignUserId === serviceInfo.foreignUserId);
});
}
function getServiceErrors(errors, service) {
return errors.filter(function (error) {
return error.path && error.path.includes(service);
});
}
var logoutMutation = 'mutation SignOutServicesMutation(\n $services: [OneGraphServiceEnum!]!\n) {\n signoutServices(data: { services: $services }) {\n me {\n serviceMetadata {\n loggedInServices {\n service\n foreignUserId\n }\n }\n }\n }\n}';
var logoutUserMutation = 'mutation SignOutServicesMutation(\n $service: OneGraphServiceEnum!\n $foreignUserId: String!\n) {\n signoutServiceUser(\n input: {\n service: $service\n foreignUserId: $foreignUserId\n }\n ) {\n me {\n serviceMetadata {\n loggedInServices {\n service\n foreignUserId\n }\n }\n }\n }\n}';
function fetchQuery(fetchUrl, query, variables, token) {
var headers = {
'Content-Type': 'application/json',
Accept: 'application/json'
};
if (token) {
headers.Authorization = 'Bearer ' + token.accessToken;
}
return fetch(fetchUrl, {
method: 'POST',
headers: headers,
body: JSON.stringify({ query: query, variables: variables })
}).then(function (response) {
return response.json();
});
}
function exchangeCode(oneGraphOrigin, appId, redirectOrigin, redirectPath, code, token, verifier) {
var redirectUri = redirectOrigin + redirectPath;
var url = URI.make({
origin: oneGraphOrigin,
path: '/oauth/code',
query: {
app_id: appId,
redirect_uri: redirectUri,
code: code,
code_verifier: verifier
}
});
var headers = {
'Content-Type': 'application/json',
Accept: 'application/json'
};
if (token) {
headers.Authorization = 'Bearer ' + token.accessToken;
}
return fetch(URI.toString(url), {
method: 'POST',
headers: headers
}).then(function (response) {
return response.json();
});
}
function exchangeRefreshToken(oneGraphOrigin, appId, refreshToken) {
var url = URI.make({
origin: oneGraphOrigin,
path: '/oauth/token',
query: {
app_id: appId
}
});
var headers = {
'Content-Type': 'application/x-www-form-urlencoded',
accept: 'application/json'
};
return fetch(URI.toString(url), {
method: 'POST',
headers: headers,
body: URI.queryToString({
grant_type: 'refresh_token',
refresh_token: refreshToken
})
}).then(function (response) {
return response.json();
});
}
function byteArrayToString(byteArray) {
return byteArray.reduce(function (acc, byte) {
return acc + (byte & 0xff).toString(16).slice(-2);
}, '');
}
function makeStateParam() {
return byteArrayToString(window.crypto.getRandomValues(new Uint8Array(32)));
}
function isExpired(token) {
return token.expireDate < Date.now();
}
function tokenFromStorage(storage, appId) {
var v = storage.getItem(appId);
if (v) {
var possibleToken = JSON.parse(v);
if (typeof possibleToken.accessToken === 'string' && typeof possibleToken.expireDate === 'number' && !isExpired(possibleToken)) {
return possibleToken;
}
}
return null;
}
var DEFAULT_ONEGRAPH_ORIGIN = 'https://serve.onegraph.com';
var OneGraphAuth = function () {
function OneGraphAuth(opts) {
var _this = this;
classCallCheck(this, OneGraphAuth);
this._authWindows = {};
this._intervalIds = {};
this._messageListeners = {};
this._accessToken = null;
this.supportedServices = ALL_SERVICES;
this._clearInterval = function (service) {
clearInterval(_this._intervalIds[service]);
delete _this._intervalIds[service];
};
this._clearMessageListener = function (service) {
window.removeEventListener('message', _this._messageListeners[service], false);
delete _this._messageListeners[service];
};
this.closeAuthWindow = function (service) {
var w = _this._authWindows[service];
w && w.close();
delete _this._authWindows[service];
};
this.cleanup = function (service, keepWindowOpen) {
_this._clearInterval(service);
_this._clearMessageListener(service);
if (!keepWindowOpen) {
_this.closeAuthWindow(service);
}
};
this.accessToken = function () {
return _this._accessToken;
};
this.tokenExpireDate = function () {
if (!_this._accessToken) {
return null;
}
return new Date(_this._accessToken.expireDate);
};
this.tokenExpiresSecondsFromNow = function () {
var expireDate = _this.tokenExpireDate();
if (!expireDate) {
return null;
}
var seconds = expireDate - new Date();
if (seconds < 0) {
return null;
}
return Math.floor(seconds / 1000);
};
this.refreshToken = function (refreshToken) {
return exchangeRefreshToken(_this.oneGraphOrigin, _this.appId, refreshToken).then(function (response) {
if (!response) {
throw new OAuthError({
error: 'invalid_grant',
error_description: 'Invalid response refreshing token.'
});
}
if (response.error) {
throw new OAuthError({
error: response.error,
error_description: response.error_description
});
}
if (!response.access_token || !response.expires_in || !response.refresh_token) {
throw new OAuthError({
error: 'invalid_grant',
error_description: 'Inavlid response from server while refreshing token.'
});
} else {
var _token = {
accessToken: response.access_token,
expireDate: Date.now() + response.expires_in * 1000,
refreshToken: response.refresh_token
};
_this.setToken(_token);
return _token;
}
});
};
this.authHeaders = function () {
if (_this._accessToken) {
return { Authorization: 'Bearer ' + _this._accessToken.accessToken };
} else {
return {};
}
};
this._makeAuthUrl = function (_ref4) {
var service = _ref4.service,
verifier = _ref4.verifier,
stateParam = _ref4.stateParam,
scopes = _ref4.scopes,
useTestFlow = _ref4.useTestFlow;
return PKCE.codeChallengeOfVerifier(verifier).then(function (challenge) {
var query = _extends({
service: service,
app_id: _this.appId,
response_type: 'code',
redirect_origin: _this._redirectOrigin,
redirect_path: _this._redirectPath,
communication_mode: _this._communicationMode,
code_challenge: challenge.challenge,
code_challenge_method: challenge.method,
state: stateParam
}, scopes ? { scopes: scopes.join(',') } : {});
if (useTestFlow) {
query.test = 'true';
}
var authUrl = URI.make({
origin: _this.oneGraphOrigin,
path: '/oauth/start',
query: query
});
return URI.toString(authUrl);
});
};
this.setToken = function (token) {
_this._accessToken = token;
var refreshToken = token.refreshToken,
storableToken = objectWithoutProperties(token, ['refreshToken']);
_this._storage.setItem(_this._storageKey, JSON.stringify(storableToken));
};
this._waitForAuthFinishPostMessage = function (service, stateParam, verifier) {
return new Promise(function (resolve, reject) {
function parseEvent(event) {
try {
return JSON.parse(event.data);
} catch (e) {
return {};
}
}
var listener = function listener(event) {
var message = parseEvent(event);
if (message && message.version <= 2) {
var state = message.state;
if (state !== stateParam) {
console.warn('Invalid state param, skipping event');
} else {
var error = message.error,
error_description = message.error_description,
code = message.code;
if (!code) {
reject(new OAuthError({
error: error || 'invalid_grant',
error_description: error_description || 'Missing code'
}));
} else {
exchangeCode(_this.oneGraphOrigin, _this.appId, _this._redirectOrigin, _this._redirectPath, code, _this._accessToken, verifier).then(function (response) {
if (response.error) {
reject(new OAuthError(response));
} else if (typeof response.access_token === 'string' && typeof response.expires_in === 'number') {
var _token2 = {
accessToken: response.access_token,
expireDate: Date.now() + response.expires_in * 1000,
refreshToken: response.refresh_token
};
_this.setToken(_token2);
resolve({
token: _token2,
service: response.service,
foreignUserId: response.foreign_user_id
});
} else {
reject(new Error('Unexpected result from server'));
}
}).catch(function (e) {
return reject(e);
});
}
}
}
};
_this._messageListeners[service] = listener;
window.addEventListener('message', listener, false);
});
};
this._waitForAuthFinishRedirect = function (service, stateParam, verifier) {
return new Promise(function (resolve, reject) {
_this._intervalIds[service] = setInterval(function () {
try {
var authUri = URI.safeParse(_this._authWindows[service].location.toString());
if (authUri && authUri.origin === _this._redirectOrigin) {
var params = authUri.query;
if (stateParam !== params.state) {
reject(new OAuthError({
error: 'invalid_request',
error_description: 'The state param does not match'
}));
} else {
var code = params.code;
if (!code) {
reject(new OAuthError({
error: 'invalid_grant',
error_description: 'Missing code'
}));
} else {
exchangeCode(_this.oneGraphOrigin, _this.appId, _this._redirectOrigin, _this._redirectPath, code, _this._accessToken, verifier).then(function (response) {
if (response.error) {
reject(new OAuthError(response));
} else if (typeof response.access_token === 'string' && typeof response.expires_in === 'number') {
var _token3 = {
accessToken: response.access_token,
expireDate: Date.now() + response.expires_in * 1000,
refreshToken: response.refresh_token
};
_this.setToken(_token3);
resolve({ token: _token3 });
} else {
reject(new Error('Unexpected result from server'));
}
}).catch(function (e) {
return reject(e);
});
}
}
}
} catch (e) {
if (e instanceof window.DOMException) ;else {
console.error('unexpected error waiting for auth to finish for ' + service, e);
reject(e);
}
}
}, POLL_INTERVAL);
});
};
this.login = function (service, scopes, useTestFlow) {
if (!service) {
throw new OAuthError({
error: 'invalid_request',
error_description: "Missing required argument. Provide service as first argument to login (e.g. `auth.login('stripe')`)."
});
}
_this.cleanup(service);
var stateParam = makeStateParam();
var verifier = PKCE.generateVerifier();
// Create an auth window without a URL initially so that browser associates
// window.open with the event (usually a click) that triggered login.
// If we waited until _makeAuthUrl's promise resolved, we might trigger
// a popup blocker
var authWindow = createAuthWindow({ service: service });
_this._authWindows[service] = authWindow;
var authFinish = _this._communicationMode === 'redirect' ? _this._waitForAuthFinishRedirect : _this._waitForAuthFinishPostMessage;
var windowUrl = _this._makeAuthUrl({
service: service,
verifier: verifier,
stateParam: stateParam,
scopes: scopes,
useTestFlow: useTestFlow
});
return windowUrl.then(function (url) {
try {
authWindow.location.href = url;
} catch (e) {
throw new OAuthError({
error: 'invalid_response',
error_description: 'Popup window was closed or blocked'
});
}
return authFinish(service, stateParam, verifier).then(function (result) {
_this.cleanup(service);
return result;
});
}).catch(function (e) {
_this.cleanup(service, true);
throw e;
});
};
this.isLoggedIn = function (args) {
var accessToken = _this._accessToken;
if (accessToken) {
var _service = typeof args === 'string' ? args : args.service;
if (!_service) {
throw new Error("Missing required argument. Provide service as first argument to isLoggedIn (e.g. `auth.isLoggedIn('stripe')`).");
}
var _foreignUserId = typeof args === 'string' ? null : args.foreignUserId;
return fetchQuery(_this._fetchUrl, loggedInQuery, {}, accessToken).then(function (result) {
return getIsLoggedIn(result, _service, _foreignUserId);
});
} else {
return Promise.resolve(false);
}
};
this.servicesStatus = function () {
var accessToken = _this._accessToken;
if (accessToken) {
return fetchQuery(_this._fetchUrl, loggedInQuery, {}, accessToken).then(function (result) {
return ALL_SERVICES.reduce(function (acc, service) {
acc[service] = { isLoggedIn: getIsLoggedIn(result, service) };
return acc;
}, {});
});
} else {
return Promise.resolve(ALL_SERVICES.reduce(function (acc, service) {
acc[service] = { isLoggedIn: false };
return acc;
}, {}));
}
};
this.allServices = function () {
return fetchQuery(_this._fetchUrl, allServicesQuery, {}, null).then(function (result) {
return result.data.oneGraph.services.map(function (serviceInfo) {
return {
serviceEnum: serviceInfo.service,
service: fromServiceEnum(serviceInfo.service),
friendlyServiceName: serviceInfo.friendlyServiceName,
supportsTestFlow: serviceInfo.supportsTestFlow
};
});
});
};
this.loggedInServices = function () {
var accessToken = _this._accessToken;
if (accessToken) {
return fetchQuery(_this._fetchUrl, loggedInQuery, {}, accessToken).then(function (result) {
var _ref2;
var loggedInServices = ((_ref2 = result) != null ? (_ref2 = _ref2.data) != null ? (_ref2 = _ref2.me) != null ? (_ref2 = _ref2.serviceMetadata) != null ? _ref2.loggedInServices : _ref2 : _ref2 : _ref2 : _ref2) || [];
return loggedInServices.reduce(function (acc, serviceInfo) {
var serviceKey = fromServiceEnum(serviceInfo.service);
var loggedInInfo = acc[serviceKey] || {
serviceEnum: serviceInfo.service,
foreignUserIds: []
};
acc[serviceKey] = _extends({}, loggedInInfo, {
usedTestFlow: serviceInfo.usedTestFlow,
foreignUserIds: [serviceInfo.foreignUserId].concat(toConsumableArray(loggedInInfo.foreignUserIds))
});
return acc;
}, {});
});
} else {
return Promise.resolve({});
}
};
this.logout = function (service, foreignUserId) {
if (!service) {
throw new Error("Missing required argument. Provide service as first argument to logout (e.g. `auth.logout('stripe')`).");
}
_this.cleanup(service);
var accessToken = _this._accessToken;
if (accessToken) {
var _serviceEnum = getServiceEnum(service);
var signoutPromise = foreignUserId ? fetchQuery(_this._fetchUrl, logoutUserMutation, {
service: _serviceEnum,
foreignUserId: foreignUserId
}, accessToken) : fetchQuery(_this._fetchUrl, logoutMutation, {
services: [_serviceEnum]
}, accessToken);
return signoutPromise.then(function (result) {
if (result.errors && result.errors.length && getServiceErrors(result.errors).length) {
return { result: 'failure', errors: result.errors };
} else {
var loggedIn = getIsLoggedIn({ data: result.signoutServices }, service, foreignUserId);
return { result: loggedIn ? 'failure' : 'success' };
}
});
} else {
return Promise.resolve({ result: 'failure' });
}
};
this.destroy = function () {
Object.keys(_this._intervalIds).forEach(function (key) {
return _this.cleanup(key);
});
Object.keys(_this._authWindows).forEach(function (key) {
return _this.cleanup(key);
});
_this._storage.removeItem(_this._storageKey);
_this._accessToken = null;
};
this.findMissingAuthServices = findMissingAuthServices;
var appId = opts.appId,
oauthFinishOrigin = opts.oauthFinishOrigin,
oauthFinishPath = opts.oauthFinishPath;
this.oneGraphOrigin = opts.oneGraphOrigin || DEFAULT_ONEGRAPH_ORIGIN;
this.appId = appId;
var windowUri = URI.parse(window.location.toString());
this._redirectOrigin = normalizeRedirectOrigin(oauthFinishOrigin || windowUri.origin);
if (this._redirectOrigin !== windowUri.origin) {
console.warn('oauthFinishOrigin does not match window.location.origin');
}
this._redirectPath = normalizeRedirectPath(oauthFinishPath || windowUri.path);
var fetchUrl = URI.make({
origin: opts.oneGraphOrigin || DEFAULT_ONEGRAPH_ORIGIN,
path: '/dynamic',
query: { app_id: appId }
});
this._fetchUrl = opts.graphqlUrl || URI.toString(fetchUrl);
this._storage = opts.storage || (hasLocalStorage() ? new LocalStorage() : new InMemoryStorage());
this._storageKey = this.appId;
this._accessToken = tokenFromStorage(this._storage, this._storageKey);
this._communicationMode = opts.communicationMode || 'post_message';
}
createClass(OneGraphAuth, [{
key: 'friendlyServiceName',
value: function friendlyServiceName(service) {
return _friendlyServiceName(service);
}
/**
* @throws {OAuthError}
*/
}]);
return OneGraphAuth;
}();
var _extends$1 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
const AuthContext = React.createContext();
class AuthProvider extends React.Component {
constructor(...args) {
var _temp;
return _temp = super(...args), this.state = {
auth: this.props.auth || new OneGraphAuth({
appId: this.props.appId
}),
status: {},
headers: {}
}, this.login = (service, callback) => {
const { auth, status } = this.state;
if (auth) {
auth.login(service).then(() => {
auth.isLoggedIn(service).then(isLoggedIn => {
callback && callback(isLoggedIn);
this.setState({
status: _extends$1({}, status, {
[service]: isLoggedIn
}),
headers: auth.authHeaders()
});
});
});
}
}, this.logout = (service, callback) => {
const { auth, status } = this.state;
auth.logout(service).then(() => {
auth.isLoggedIn(service).then(isLoggedIn => {
callback && callback(isLoggedIn);
this.setState({
status: _extends$1({}, status, {
[service]: isLoggedIn
}),
headers: auth.authHeaders()
});
});
});
}, _temp;
}
componentDidMount() {
const { auth } = this.state;
auth.servicesStatus().then(status => this.setState({
headers: auth.authHeaders(),
status: Object.keys(status).reduce((out, service) => {
out[service] = status[service].isLoggedIn;
return out;
}, {}),
auth
}));
}
render() {
const { appId } = this.props;
const { status, headers } = this.state;
const authInterface = {
status,
headers,
login: this.login,
logout: this.logout,
appId
};
return React__default.createElement(
AuthContext.Provider,
{ value: authInterface },
this.props.children
);
}
}
const AuthConsumer = AuthContext.Consumer;
exports.AuthConsumer = AuthConsumer;
exports.AuthContext = AuthContext;
exports.AuthProvider = AuthProvider;
Object.defineProperty(exports, '__esModule', { value: true });
})));
//# sourceMappingURL=bundle.umd.js.map