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:
parent
7948974949
commit
1ab3f21917
5 changed files with 16 additions and 321 deletions
|
@ -1,10 +1,8 @@
|
|||
import React from "react";
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { Integrations } from "@sentry/tracing";
|
||||
import { Auth0Provider } from "@auth0/auth0-react";
|
||||
import { ChakraProvider, Box, useColorModeValue } from "@chakra-ui/react";
|
||||
import { ApolloProvider } from "@apollo/client";
|
||||
import { useAuth0 } from "@auth0/auth0-react";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
import { Global } from "@emotion/react";
|
||||
|
||||
|
@ -15,46 +13,23 @@ export default function AppProvider({ children }) {
|
|||
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<Auth0Provider
|
||||
domain="openneo.us.auth0.com"
|
||||
clientId="8LjFauVox7shDxVufQqnviUIywMuuC4r"
|
||||
redirectUri={
|
||||
process.env.NODE_ENV === "development"
|
||||
? "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>
|
||||
<DTIApolloProvider>
|
||||
<ChakraProvider resetCSS={false}>
|
||||
<ScopedCSSReset>{children}</ScopedCSSReset>
|
||||
</ChakraProvider>
|
||||
</DTIApolloProvider>
|
||||
</BrowserRouter>
|
||||
);
|
||||
}
|
||||
|
||||
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`,
|
||||
// which we'll use to initialize the client without having to wait a tick.
|
||||
const [initialCacheState, unusedSetInitialCacheState] =
|
||||
React.useState(additionalCacheState);
|
||||
|
||||
const client = React.useMemo(
|
||||
() =>
|
||||
buildApolloClient({
|
||||
getAuth0: () => auth0Ref.current,
|
||||
initialCacheState,
|
||||
}),
|
||||
() => buildApolloClient({ initialCacheState }),
|
||||
[initialCacheState],
|
||||
);
|
||||
|
||||
|
|
|
@ -3,8 +3,6 @@ import { loadErrorMessages, loadDevMessages } from "@apollo/client/dev";
|
|||
import { setContext } from "@apollo/client/link/context";
|
||||
import { createPersistedQueryLink } from "apollo-link-persisted-queries";
|
||||
|
||||
import { getAuthModeFeatureFlag } from "./components/useCurrentUser";
|
||||
|
||||
// Use Apollo's error messages in development.
|
||||
if (process.env["NODE_ENV"] === "development") {
|
||||
loadErrorMessages();
|
||||
|
@ -162,73 +160,19 @@ const typePolicies = {
|
|||
const httpLink = createHttpLink({
|
||||
uri: "https://impress-2020.openneo.net/api/graphql",
|
||||
});
|
||||
const buildAuthLink = (getAuth0) =>
|
||||
setContext(async (_, { headers = {}, sendAuth = false }) => {
|
||||
if (!sendAuth) {
|
||||
return;
|
||||
}
|
||||
|
||||
const token = await getAccessToken(getAuth0);
|
||||
if (token) {
|
||||
return {
|
||||
headers: {
|
||||
...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);
|
||||
const buildLink = () =>
|
||||
createPersistedQueryLink({
|
||||
useGETForHashedQueries: true,
|
||||
}).concat(httpLink);
|
||||
|
||||
/**
|
||||
* apolloClient is the global Apollo Client instance we use for GraphQL
|
||||
* queries. This is how we communicate with the server!
|
||||
*/
|
||||
const buildClient = ({ getAuth0, initialCacheState }) => {
|
||||
const buildClient = ({ initialCacheState }) => {
|
||||
return new ApolloClient({
|
||||
link: buildLink(getAuth0),
|
||||
link: buildLink(),
|
||||
cache: new InMemoryCache({ typePolicies }).restore(initialCacheState),
|
||||
connectToDevTools: true,
|
||||
});
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { gql, useMutation, useQuery } from "@apollo/client";
|
||||
import { useAuth0 } from "@auth0/auth0-react";
|
||||
import { useLocalStorage } from "../util";
|
||||
|
||||
const NOT_LOGGED_IN_USER = {
|
||||
|
@ -10,13 +9,7 @@ const NOT_LOGGED_IN_USER = {
|
|||
};
|
||||
|
||||
function useCurrentUser() {
|
||||
const [authMode] = useAuthModeFeatureFlag();
|
||||
const currentUserViaAuth0 = useCurrentUserViaAuth0({
|
||||
isEnabled: authMode === "auth0",
|
||||
});
|
||||
const currentUserViaDb = useCurrentUserViaDb({
|
||||
isEnabled: authMode === "db",
|
||||
});
|
||||
const currentUser = useCurrentUserQuery();
|
||||
|
||||
// In development, you can start the server with
|
||||
// `IMPRESS_LOG_IN_AS=12345 vc dev` to simulate logging in as user 12345.
|
||||
|
@ -39,42 +32,10 @@ function useCurrentUser() {
|
|||
};
|
||||
}
|
||||
|
||||
if (authMode === "auth0") {
|
||||
return currentUserViaAuth0;
|
||||
} else if (authMode === "db") {
|
||||
return currentUserViaDb;
|
||||
} else {
|
||||
console.error(`Unexpected auth mode: ${JSON.stringify(authMode)}`);
|
||||
return NOT_LOGGED_IN_USER;
|
||||
}
|
||||
return currentUser;
|
||||
}
|
||||
|
||||
function useCurrentUserViaAuth0({ isEnabled }) {
|
||||
// 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 }) {
|
||||
function useCurrentUserQuery() {
|
||||
const { loading, data } = useQuery(
|
||||
gql`
|
||||
query useCurrentUser {
|
||||
|
@ -85,7 +46,6 @@ function useCurrentUserViaDb({ isEnabled }) {
|
|||
}
|
||||
`,
|
||||
{
|
||||
skip: !isEnabled,
|
||||
onError: (error) => {
|
||||
// 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
|
||||
|
@ -99,9 +59,7 @@ function useCurrentUserViaDb({ isEnabled }) {
|
|||
},
|
||||
);
|
||||
|
||||
if (!isEnabled) {
|
||||
return NOT_LOGGED_IN_USER;
|
||||
} else if (loading) {
|
||||
if (loading) {
|
||||
return { ...NOT_LOGGED_IN_USER, isLoading: true };
|
||||
} else if (data?.currentUser == null) {
|
||||
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;
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
"name": "app",
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.6.9",
|
||||
"@auth0/auth0-react": "^1.0.0",
|
||||
"@chakra-ui/icons": "^1.0.4",
|
||||
"@chakra-ui/react": "^1.6.0",
|
||||
"@emotion/react": "^11.1.4",
|
||||
|
|
62
yarn.lock
62
yarn.lock
|
@ -21,26 +21,6 @@
|
|||
tslib "^2.3.0"
|
||||
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":
|
||||
version "7.22.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.10.tgz#1c20e612b768fefa75f6e90d6ecb86329247f0a3"
|
||||
|
@ -1078,11 +1058,6 @@
|
|||
dependencies:
|
||||
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:
|
||||
version "3.2.1"
|
||||
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"
|
||||
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:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
||||
|
@ -1184,11 +1152,6 @@ copy-to-clipboard@3.3.1:
|
|||
dependencies:
|
||||
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:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
|
||||
|
@ -1242,11 +1205,6 @@ error-ex@^1.3.1:
|
|||
dependencies:
|
||||
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:
|
||||
version "4.2.8"
|
||||
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"
|
||||
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:
|
||||
version "1.1.0"
|
||||
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"
|
||||
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:
|
||||
version "1.4.0"
|
||||
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"
|
||||
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:
|
||||
version "15.8.1"
|
||||
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"
|
||||
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:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.0.tgz#772199899b9c9a50526fedc4993fc7fa1f7e32d5"
|
||||
|
|
Loading…
Reference in a new issue