UNPKG

react-onegraph

Version:
1,224 lines (1,081 loc) 37.8 kB
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)); } } import React, { createContext, Component } from '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 = createContext(); class AuthProvider extends 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.createElement( AuthContext.Provider, { value: authInterface }, this.props.children ); } } const AuthConsumer = AuthContext.Consumer; export { AuthConsumer, AuthContext, AuthProvider }; //# sourceMappingURL=bundle.es.js.map