1
0
Fork 0
forked from OpenNeo/impress

Finally remove unused auth0 code

Moreover, this code is in a bit of a flimsy state anyway: it'll kinda
work if you're logged in at impress-2020.openneo.net, but that wasn't
intentionally engineered, and I'm not sure exactly what circumstances
cause those cookies to send vs not send?

My intent is to clean up to replace all this with login code that
references the main app instead… this'll require swapping out some
endpoints to refer to what the main app has, but I'm hoping that's not
so tricky to do, since the main app does offer basically all of this
functionality already anyway. (That's not to say it's simple, but I
think it's a migration in the right direction!)
This commit is contained in:
Emi Matchu 2023-11-01 15:09:24 -07:00
parent 7948974949
commit 1ab3f21917
5 changed files with 16 additions and 321 deletions

View file

@ -1,10 +1,8 @@
import React from "react"; import React from "react";
import * as Sentry from "@sentry/react"; import * as Sentry from "@sentry/react";
import { Integrations } from "@sentry/tracing"; import { Integrations } from "@sentry/tracing";
import { Auth0Provider } from "@auth0/auth0-react";
import { ChakraProvider, Box, useColorModeValue } from "@chakra-ui/react"; import { ChakraProvider, Box, useColorModeValue } from "@chakra-ui/react";
import { ApolloProvider } from "@apollo/client"; import { ApolloProvider } from "@apollo/client";
import { useAuth0 } from "@auth0/auth0-react";
import { BrowserRouter } from "react-router-dom"; import { BrowserRouter } from "react-router-dom";
import { Global } from "@emotion/react"; import { Global } from "@emotion/react";
@ -15,46 +13,23 @@ export default function AppProvider({ children }) {
return ( return (
<BrowserRouter> <BrowserRouter>
<Auth0Provider <DTIApolloProvider>
domain="openneo.us.auth0.com" <ChakraProvider resetCSS={false}>
clientId="8LjFauVox7shDxVufQqnviUIywMuuC4r" <ScopedCSSReset>{children}</ScopedCSSReset>
redirectUri={ </ChakraProvider>
process.env.NODE_ENV === "development" </DTIApolloProvider>
? "http://localhost:3000"
: "https://impress-2020.openneo.net"
}
audience="https://impress-2020.openneo.net/api"
scope=""
>
<DTIApolloProvider>
<ChakraProvider resetCSS={false}>
<ScopedCSSReset>{children}</ScopedCSSReset>
</ChakraProvider>
</DTIApolloProvider>
</Auth0Provider>
</BrowserRouter> </BrowserRouter>
); );
} }
function DTIApolloProvider({ children, additionalCacheState = {} }) { function DTIApolloProvider({ children, additionalCacheState = {} }) {
const auth0 = useAuth0();
const auth0Ref = React.useRef(auth0);
React.useEffect(() => {
auth0Ref.current = auth0;
}, [auth0]);
// Save the first `additionalCacheState` we get as our `initialCacheState`, // Save the first `additionalCacheState` we get as our `initialCacheState`,
// which we'll use to initialize the client without having to wait a tick. // which we'll use to initialize the client without having to wait a tick.
const [initialCacheState, unusedSetInitialCacheState] = const [initialCacheState, unusedSetInitialCacheState] =
React.useState(additionalCacheState); React.useState(additionalCacheState);
const client = React.useMemo( const client = React.useMemo(
() => () => buildApolloClient({ initialCacheState }),
buildApolloClient({
getAuth0: () => auth0Ref.current,
initialCacheState,
}),
[initialCacheState], [initialCacheState],
); );

View file

@ -3,8 +3,6 @@ import { loadErrorMessages, loadDevMessages } from "@apollo/client/dev";
import { setContext } from "@apollo/client/link/context"; import { setContext } from "@apollo/client/link/context";
import { createPersistedQueryLink } from "apollo-link-persisted-queries"; import { createPersistedQueryLink } from "apollo-link-persisted-queries";
import { getAuthModeFeatureFlag } from "./components/useCurrentUser";
// Use Apollo's error messages in development. // Use Apollo's error messages in development.
if (process.env["NODE_ENV"] === "development") { if (process.env["NODE_ENV"] === "development") {
loadErrorMessages(); loadErrorMessages();
@ -162,73 +160,19 @@ const typePolicies = {
const httpLink = createHttpLink({ const httpLink = createHttpLink({
uri: "https://impress-2020.openneo.net/api/graphql", uri: "https://impress-2020.openneo.net/api/graphql",
}); });
const buildAuthLink = (getAuth0) =>
setContext(async (_, { headers = {}, sendAuth = false }) => {
if (!sendAuth) {
return;
}
const token = await getAccessToken(getAuth0); const buildLink = () =>
if (token) { createPersistedQueryLink({
return { useGETForHashedQueries: true,
headers: { }).concat(httpLink);
...headers,
authorization: token ? `Bearer ${token}` : "",
},
};
}
});
// This is a temporary way to pass the DTIAuthMode feature flag back to the
// server!
const authModeLink = setContext((_, { headers = {} }) => {
const authMode = getAuthModeFeatureFlag();
return {
headers: {
...headers,
"DTI-Auth-Mode": authMode,
},
};
});
async function getAccessToken(getAuth0) {
// Wait for auth0 to stop loading, so we can maybe get a token!
// We'll do this hackily by checking every 100ms until it's true.
await new Promise((resolve) => {
function check() {
if (getAuth0().isLoading) {
setTimeout(check, 100);
} else {
resolve();
}
}
check();
});
const { isAuthenticated, getAccessTokenSilently } = getAuth0();
if (isAuthenticated) {
const token = await getAccessTokenSilently();
return token;
}
}
const buildLink = (getAuth0) =>
buildAuthLink(getAuth0)
.concat(authModeLink)
.concat(
createPersistedQueryLink({
useGETForHashedQueries: true,
}),
)
.concat(httpLink);
/** /**
* apolloClient is the global Apollo Client instance we use for GraphQL * apolloClient is the global Apollo Client instance we use for GraphQL
* queries. This is how we communicate with the server! * queries. This is how we communicate with the server!
*/ */
const buildClient = ({ getAuth0, initialCacheState }) => { const buildClient = ({ initialCacheState }) => {
return new ApolloClient({ return new ApolloClient({
link: buildLink(getAuth0), link: buildLink(),
cache: new InMemoryCache({ typePolicies }).restore(initialCacheState), cache: new InMemoryCache({ typePolicies }).restore(initialCacheState),
connectToDevTools: true, connectToDevTools: true,
}); });

View file

@ -1,5 +1,4 @@
import { gql, useMutation, useQuery } from "@apollo/client"; import { gql, useMutation, useQuery } from "@apollo/client";
import { useAuth0 } from "@auth0/auth0-react";
import { useLocalStorage } from "../util"; import { useLocalStorage } from "../util";
const NOT_LOGGED_IN_USER = { const NOT_LOGGED_IN_USER = {
@ -10,13 +9,7 @@ const NOT_LOGGED_IN_USER = {
}; };
function useCurrentUser() { function useCurrentUser() {
const [authMode] = useAuthModeFeatureFlag(); const currentUser = useCurrentUserQuery();
const currentUserViaAuth0 = useCurrentUserViaAuth0({
isEnabled: authMode === "auth0",
});
const currentUserViaDb = useCurrentUserViaDb({
isEnabled: authMode === "db",
});
// In development, you can start the server with // In development, you can start the server with
// `IMPRESS_LOG_IN_AS=12345 vc dev` to simulate logging in as user 12345. // `IMPRESS_LOG_IN_AS=12345 vc dev` to simulate logging in as user 12345.
@ -39,42 +32,10 @@ function useCurrentUser() {
}; };
} }
if (authMode === "auth0") { return currentUser;
return currentUserViaAuth0;
} else if (authMode === "db") {
return currentUserViaDb;
} else {
console.error(`Unexpected auth mode: ${JSON.stringify(authMode)}`);
return NOT_LOGGED_IN_USER;
}
} }
function useCurrentUserViaAuth0({ isEnabled }) { function useCurrentUserQuery() {
// NOTE: I don't think we can actually, by the rule of hooks, *not* ask for
// Auth0 login state when `isEnabled` is false, because `useAuth0`
// doesn't accept a similar parameter to disable itself. We'll just
// accept the redundant network effort during rollout, then delete it
// when we're done. (So, the param isn't actually doing a whole lot; I
// mostly have it for consistency with `useCurrentUserViaDb`, to make
// it clear where the real difference is.)
const { isLoading, isAuthenticated, user } = useAuth0();
if (!isEnabled) {
return NOT_LOGGED_IN_USER;
} else if (isLoading) {
return { ...NOT_LOGGED_IN_USER, isLoading: true };
} else if (!isAuthenticated) {
return NOT_LOGGED_IN_USER;
} else {
return {
isLoading: false,
isLoggedIn: true,
...getUserInfoFromAuth0Data(user),
};
}
}
function useCurrentUserViaDb({ isEnabled }) {
const { loading, data } = useQuery( const { loading, data } = useQuery(
gql` gql`
query useCurrentUser { query useCurrentUser {
@ -85,7 +46,6 @@ function useCurrentUserViaDb({ isEnabled }) {
} }
`, `,
{ {
skip: !isEnabled,
onError: (error) => { onError: (error) => {
// On error, we don't report anything to the user, but we do keep a // On error, we don't report anything to the user, but we do keep a
// record in the console. We figure that most errors are likely to be // record in the console. We figure that most errors are likely to be
@ -99,9 +59,7 @@ function useCurrentUserViaDb({ isEnabled }) {
}, },
); );
if (!isEnabled) { if (loading) {
return NOT_LOGGED_IN_USER;
} else if (loading) {
return { ...NOT_LOGGED_IN_USER, isLoading: true }; return { ...NOT_LOGGED_IN_USER, isLoading: true };
} else if (data?.currentUser == null) { } else if (data?.currentUser == null) {
return NOT_LOGGED_IN_USER; return NOT_LOGGED_IN_USER;
@ -115,123 +73,4 @@ function useCurrentUserViaDb({ isEnabled }) {
} }
} }
function getUserInfoFromAuth0Data(user) {
return {
id: user.sub?.match(/^auth0\|impress-([0-9]+)$/)?.[1],
username: user["https://oauth.impress-2020.openneo.net/username"],
};
}
/**
* useLoginActions returns a `startLogin` function to start login with Auth0,
* and a `logout` function to logout from whatever auth mode is in use.
*
* Note that `startLogin` is only supported with the Auth0 auto mode. In db
* mode, you should open a `LoginModal` instead!
*/
export function useLogout() {
const { logout: logoutWithAuth0 } = useAuth0();
const [authMode] = useAuthModeFeatureFlag();
const [sendLogoutMutation, { loading, error }] = useMutation(
gql`
mutation useLogout_Logout {
logout {
id
}
}
`,
{
update: (cache, { data }) => {
// Evict the `currentUser` from the cache, which will force all queries
// on the page that depend on it to update. (This includes the
// GlobalHeader that shows who you're logged in as!)
//
// We also evict the user themself, to force-update things that we're
// allowed to see about this user (e.g. private lists).
//
// I don't do any optimistic UI here, because auth is complex enough
// that I'd rather only show logout success after validating it through
// an actual server round-trip.
cache.evict({ id: "ROOT_QUERY", fieldName: "currentUser" });
if (data.logout?.id != null) {
cache.evict({ id: `User:${data.logout.id}` });
}
cache.gc();
},
},
);
const logoutWithDb = () => {
sendLogoutMutation().catch((e) => {}); // handled in error UI
};
if (authMode === "auth0") {
return [logoutWithAuth0, { loading: false, error: null }];
} else if (authMode === "db") {
return [logoutWithDb, { loading, error }];
} else {
console.error(`unexpected auth mode: ${JSON.stringify(authMode)}`);
return [() => {}, { loading: false, error: null }];
}
}
/**
* useAuthModeFeatureFlag returns "db" by default, but "auto" if you're falling
* back to the old auth0-backed login mode.
*
* To set this manually, click "Better login system" on the homepage in the
* Coming Soon block, and switch the toggle.
*/
export function useAuthModeFeatureFlag() {
// We'll probably add a like, experimental gradual rollout thing here too.
// But for now we just check your device's local storage! (This is why we
// default to `null` instead of "auth0", I want to be unambiguous that this
// is the *absence* of a localStorage value, and not risk accidentally
// setting this override value to auth0 on everyone's devices 😅)
let [savedValue, setSavedValue] = useLocalStorage(
"DTIAuthModeFeatureFlag",
null,
);
if (!["auth0", "db", null].includes(savedValue)) {
console.warn(
`Unexpected DTIAuthModeFeatureFlag value: %o. Ignoring.`,
savedValue,
);
savedValue = null;
}
const value = savedValue || "db";
return [value, setSavedValue];
}
/**
* getAuthModeFeatureFlag returns the authMode at the time it's called.
* It's generally preferable to use `useAuthModeFeatureFlag` in a React
* setting, but we use this instead for Apollo stuff!
*/
export function getAuthModeFeatureFlag() {
const savedValueString = localStorage.getItem("DTIAuthModeFeatureFlag");
let savedValue;
try {
savedValue = JSON.parse(savedValueString);
} catch (error) {
console.warn(`DTIAuthModeFeatureFlag was not valid JSON. Ignoring.`);
savedValue = null;
}
if (!["auth0", "db", null].includes(savedValue)) {
console.warn(
`Unexpected DTIAuthModeFeatureFlag value: %o. Ignoring.`,
savedValue,
);
savedValue = null;
}
return savedValue || "db";
}
export default useCurrentUser; export default useCurrentUser;

View file

@ -2,7 +2,6 @@
"name": "app", "name": "app",
"dependencies": { "dependencies": {
"@apollo/client": "^3.6.9", "@apollo/client": "^3.6.9",
"@auth0/auth0-react": "^1.0.0",
"@chakra-ui/icons": "^1.0.4", "@chakra-ui/icons": "^1.0.4",
"@chakra-ui/react": "^1.6.0", "@chakra-ui/react": "^1.6.0",
"@emotion/react": "^11.1.4", "@emotion/react": "^11.1.4",

View file

@ -21,26 +21,6 @@
tslib "^2.3.0" tslib "^2.3.0"
zen-observable-ts "^1.2.5" zen-observable-ts "^1.2.5"
"@auth0/auth0-react@^1.0.0":
version "1.12.1"
resolved "https://registry.yarnpkg.com/@auth0/auth0-react/-/auth0-react-1.12.1.tgz#3a469518828137339c635434ab953e206e798fe8"
integrity sha512-8+ecK/4rE0AGsxLW2IDcr1oPbT55tuE6cQEzEIOkQjB6QGQxxWMzQy0D4nMKw3JUAc7nYcFVOABNFNbc471n9Q==
dependencies:
"@auth0/auth0-spa-js" "^1.22.6"
"@auth0/auth0-spa-js@^1.22.6":
version "1.22.6"
resolved "https://registry.yarnpkg.com/@auth0/auth0-spa-js/-/auth0-spa-js-1.22.6.tgz#482c7cf546649e856020d20843cd496258bd9fa0"
integrity sha512-iL3O0vWanfKFVgy1J2ZHDPlAUK6EVHWEHWS6mUXwHEuPiK39tjlQtyUKQIJI1F5YsZB75ijGgRWMTawSDXlwCA==
dependencies:
abortcontroller-polyfill "^1.7.3"
browser-tabs-lock "^1.2.15"
core-js "^3.25.4"
es-cookie "~1.3.2"
fast-text-encoding "^1.0.6"
promise-polyfill "^8.2.3"
unfetch "^4.2.0"
"@babel/code-frame@^7.0.0": "@babel/code-frame@^7.0.0":
version "7.22.10" version "7.22.10"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.10.tgz#1c20e612b768fefa75f6e90d6ecb86329247f0a3" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.10.tgz#1c20e612b768fefa75f6e90d6ecb86329247f0a3"
@ -1078,11 +1058,6 @@
dependencies: dependencies:
tslib "^2.3.0" tslib "^2.3.0"
abortcontroller-polyfill@^1.7.3:
version "1.7.5"
resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed"
integrity sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==
ansi-styles@^3.2.1: ansi-styles@^3.2.1:
version "3.2.1" version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
@ -1134,13 +1109,6 @@ babel-plugin-macros@^3.1.0:
cosmiconfig "^7.0.0" cosmiconfig "^7.0.0"
resolve "^1.19.0" resolve "^1.19.0"
browser-tabs-lock@^1.2.15:
version "1.3.0"
resolved "https://registry.yarnpkg.com/browser-tabs-lock/-/browser-tabs-lock-1.3.0.tgz#4c0381b47b55cd29feaaea5846b7bb97aac76053"
integrity sha512-g6nHaobTiT0eMZ7jh16YpD2kcjAp+PInbiVq3M1x6KKaEIVhT4v9oURNIpZLOZ3LQbQ3XYfNhMAb/9hzNLIWrw==
dependencies:
lodash ">=4.17.21"
callsites@^3.0.0: callsites@^3.0.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
@ -1184,11 +1152,6 @@ copy-to-clipboard@3.3.1:
dependencies: dependencies:
toggle-selection "^1.0.6" toggle-selection "^1.0.6"
core-js@^3.25.4:
version "3.32.0"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.32.0.tgz#7643d353d899747ab1f8b03d2803b0312a0fb3b6"
integrity sha512-rd4rYZNlF3WuoYuRIDEmbR/ga9CeuWX9U05umAvgrrZoHY4Z++cp/xwPQMvUpBB4Ag6J8KfD80G0zwCyaSxDww==
cosmiconfig@^7.0.0: cosmiconfig@^7.0.0:
version "7.1.0" version "7.1.0"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
@ -1242,11 +1205,6 @@ error-ex@^1.3.1:
dependencies: dependencies:
is-arrayish "^0.2.1" is-arrayish "^0.2.1"
es-cookie@~1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/es-cookie/-/es-cookie-1.3.2.tgz#80e831597f72a25721701bdcb21d990319acd831"
integrity sha512-UTlYYhXGLOy05P/vKVT2Ui7WtC7NiRzGtJyAKKn32g5Gvcjn7KAClLPWlipCtxIus934dFg9o9jXiBL0nP+t9Q==
es6-promise@^4.2.8: es6-promise@^4.2.8:
version "4.2.8" version "4.2.8"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
@ -1295,11 +1253,6 @@ fast-json-stable-stringify@^2.0.0:
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
fast-text-encoding@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz#0aa25f7f638222e3396d72bf936afcf1d42d6867"
integrity sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==
find-root@^1.1.0: find-root@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
@ -1443,11 +1396,6 @@ lodash.mergewith@4.6.2:
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55"
integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==
lodash@>=4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
@ -1528,11 +1476,6 @@ prettier@^3.0.3:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643" resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643"
integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg== integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==
promise-polyfill@^8.2.3:
version "8.3.0"
resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.3.0.tgz#9284810268138d103807b11f4e23d5e945a4db63"
integrity sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg==
prop-types@^15.6.2, prop-types@^15.7.2: prop-types@^15.6.2, prop-types@^15.7.2:
version "15.8.1" version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
@ -1785,11 +1728,6 @@ tweenjs@^1.0.2:
resolved "https://registry.yarnpkg.com/tweenjs/-/tweenjs-1.0.2.tgz#768869c4d4ba91fdb4c5ccc661969c58138555af" resolved "https://registry.yarnpkg.com/tweenjs/-/tweenjs-1.0.2.tgz#768869c4d4ba91fdb4c5ccc661969c58138555af"
integrity sha512-WnFozCNkUkmJtLqJyGrToxVojW2Srzudktr8BzFKQijQRVcmlq7Fc+qfo75ccnwIJGiRWbXKfg7qU67Tzbb1bg== integrity sha512-WnFozCNkUkmJtLqJyGrToxVojW2Srzudktr8BzFKQijQRVcmlq7Fc+qfo75ccnwIJGiRWbXKfg7qU67Tzbb1bg==
unfetch@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be"
integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==
use-callback-ref@^1.2.3, use-callback-ref@^1.2.5: use-callback-ref@^1.2.3, use-callback-ref@^1.2.5:
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.0.tgz#772199899b9c9a50526fedc4993fc7fa1f7e32d5" resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.0.tgz#772199899b9c9a50526fedc4993fc7fa1f7e32d5"