mirror of
https://github.com/MetaFam/TheGame.git
synced 2026-04-24 03:00:09 -04:00
Fixed edit profile field saving, updated useUser to load from composeDB
This commit is contained in:
committed by
Alec LaLonde
parent
509a45cd5c
commit
907cdf17ca
@@ -30,16 +30,17 @@ import {
|
||||
} from '@metafam/ds';
|
||||
import {
|
||||
ComposeDBImageMetadata,
|
||||
ComposeDBProfile,
|
||||
getMimeType,
|
||||
HasuraImageFieldKey,
|
||||
hasuraImageFields,
|
||||
isHasuraImageField,
|
||||
profileMapping,
|
||||
} from '@metafam/utils';
|
||||
import { Maybe, Player } from 'graphql/autogen/types';
|
||||
import { Maybe, Player, Profile } from 'graphql/autogen/types';
|
||||
import { getPlayer } from 'graphql/getPlayer';
|
||||
import { PlayerProfile } from 'graphql/types';
|
||||
import { useWeb3 } from 'lib/hooks';
|
||||
import { hasuraToComposeDBProfile } from 'lib/hooks/ceramic/usePlayerSetupSaveToComposeDB';
|
||||
import { useSaveToComposeDB } from 'lib/hooks/ceramic/useSaveToComposeDB';
|
||||
import React, {
|
||||
createRef,
|
||||
@@ -174,7 +175,10 @@ export const EditProfileModal: React.FC<EditProfileModalProps> = ({
|
||||
),
|
||||
);
|
||||
|
||||
const profile: ComposeDBProfile = { ...changedInputs };
|
||||
const profile: PlayerProfile = { ...changedInputs };
|
||||
const profileImages = Object.fromEntries(
|
||||
hasuraImageFields.map((field) => [field, null]),
|
||||
) as Record<HasuraImageFieldKey, Maybe<ComposeDBImageMetadata>>;
|
||||
|
||||
const toType = (key: string) => {
|
||||
const match = key.match(/^(.+?)(Image)?(URL)$/i);
|
||||
@@ -219,8 +223,7 @@ export const EditProfileModal: React.FC<EditProfileModalProps> = ({
|
||||
imageMetadata.height = height;
|
||||
}
|
||||
|
||||
const composeDBKey = profileMapping[key as HasuraImageFieldKey];
|
||||
profile[composeDBKey] = imageMetadata;
|
||||
profileImages[key as HasuraImageFieldKey] = imageMetadata;
|
||||
}
|
||||
}),
|
||||
);
|
||||
@@ -228,7 +231,8 @@ export const EditProfileModal: React.FC<EditProfileModalProps> = ({
|
||||
|
||||
setStatus('Saving to Ceramic…');
|
||||
|
||||
const ceramicStreamID = await save(profile);
|
||||
const payload = hasuraToComposeDBProfile(profile, profileImages);
|
||||
const ceramicStreamID = await save(payload);
|
||||
|
||||
// if they changed their username, the page will 404 on reload
|
||||
if (player && inputs.username !== username) {
|
||||
|
||||
@@ -4,24 +4,10 @@ import { FlexContainer } from 'components/Container';
|
||||
import { MetaLink } from 'components/Link';
|
||||
import { PlayerTile } from 'components/Player/PlayerTile';
|
||||
import { useUser, useWeb3 } from 'lib/hooks';
|
||||
import {
|
||||
hydratePlayerProfile,
|
||||
useGetPlayerProfileFromComposeDB,
|
||||
} from 'lib/hooks/ceramic/useGetPlayerProfileFromComposeDB';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
export const SetupDone: React.FC = () => {
|
||||
const { user } = useUser();
|
||||
const { connected } = useWeb3();
|
||||
const { result } = useGetPlayerProfileFromComposeDB(user?.ceramicProfileId);
|
||||
|
||||
const [hydratedPlayer, setHydratedPlayer] = useState(user);
|
||||
|
||||
useEffect(() => {
|
||||
if (user && result) {
|
||||
setHydratedPlayer(hydratePlayerProfile(user, result));
|
||||
}
|
||||
}, [result, user]);
|
||||
|
||||
if (!user || !connected) {
|
||||
return (
|
||||
@@ -41,7 +27,7 @@ export const SetupDone: React.FC = () => {
|
||||
justify="center"
|
||||
align="center"
|
||||
>
|
||||
{hydratedPlayer && <PlayerTile player={hydratedPlayer} />}
|
||||
<PlayerTile player={user} />
|
||||
<Stack spacing={4} p={4} maxW="25rem" fontSize="md" h="100%">
|
||||
<Text fontSize="lg">Congrats on making yourself a profile! 🎉</Text>
|
||||
<Text fontSize="md">
|
||||
|
||||
@@ -5,14 +5,8 @@ import { composeDBDefinition, Maybe } from '@metafam/utils';
|
||||
import { CONFIG } from 'config';
|
||||
import { DIDSession } from 'did-session';
|
||||
import { cacheDIDSession, getCachedDIDSession } from 'lib/auth';
|
||||
import { useWeb3 } from 'lib/hooks';
|
||||
import {
|
||||
createContext,
|
||||
PropsWithChildren,
|
||||
useCallback,
|
||||
useContext,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useWeb3 } from 'lib/hooks/useWeb3';
|
||||
import { createContext, PropsWithChildren, useCallback, useState } from 'react';
|
||||
import { errorHandler } from 'utils/errorHandler';
|
||||
|
||||
export type ComposeDBContextType = {
|
||||
@@ -109,6 +103,3 @@ export const ComposeDBContextProvider: React.FC<PropsWithChildren> = ({
|
||||
</ComposeDBContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useComposeDB = (): ComposeDBContextType =>
|
||||
useContext(ComposeDBContext);
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Player } from 'graphql/autogen/types';
|
||||
import { buildPlayerProfileQuery } from 'graphql/composeDB/queries/profile';
|
||||
import { getPlayer } from 'graphql/getPlayer';
|
||||
import { ComposeDBProfileQueryResult } from 'graphql/types';
|
||||
import { useComposeDB } from 'lib/hooks/ceramic/useComposeDB';
|
||||
import { hydratePlayerProfile } from 'lib/hooks/ceramic/useGetPlayerProfileFromComposeDB';
|
||||
import {
|
||||
createContext,
|
||||
@@ -12,8 +13,6 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import { useComposeDB } from './ComposeDBContext';
|
||||
|
||||
export type PlayerHydrationContextType = {
|
||||
hydratedPlayer: Player;
|
||||
isHydrating: boolean;
|
||||
|
||||
@@ -9,8 +9,6 @@ import React, {
|
||||
} from 'react';
|
||||
import { SetupOptions } from 'utils/setupOptions';
|
||||
|
||||
import { ComposeDBContextProvider } from './ComposeDBContext';
|
||||
|
||||
const urlPrefix = '/profile/setup/';
|
||||
|
||||
type SetupContextType = {
|
||||
@@ -71,19 +69,17 @@ export const SetupContextProvider: React.FC<PropsWithChildren> = ({
|
||||
}, [router, options, stepIndex]);
|
||||
|
||||
return (
|
||||
<ComposeDBContextProvider>
|
||||
<SetupContext.Provider
|
||||
value={{
|
||||
options,
|
||||
stepIndex,
|
||||
onNextPress,
|
||||
onBackPress,
|
||||
nextButtonLabel,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</SetupContext.Provider>
|
||||
</ComposeDBContextProvider>
|
||||
<SetupContext.Provider
|
||||
value={{
|
||||
options,
|
||||
stepIndex,
|
||||
onNextPress,
|
||||
onBackPress,
|
||||
nextButtonLabel,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</SetupContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -64,6 +64,8 @@ export type GuildMetadata = {
|
||||
};
|
||||
};
|
||||
|
||||
export type PlayerProfile = Omit<Profile, 'playerId' | 'player' | 'id'>;
|
||||
|
||||
export type ComposeDBProfileQueryResult = {
|
||||
node: ComposeDBProfile;
|
||||
};
|
||||
|
||||
8
packages/web/lib/hooks/ceramic/useComposeDB.ts
Normal file
8
packages/web/lib/hooks/ceramic/useComposeDB.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import {
|
||||
ComposeDBContext,
|
||||
ComposeDBContextType,
|
||||
} from 'contexts/ComposeDBContext';
|
||||
import { useContext } from 'react';
|
||||
|
||||
export const useComposeDB = (): ComposeDBContextType =>
|
||||
useContext(ComposeDBContext);
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
Maybe,
|
||||
profileMapping,
|
||||
} from '@metafam/utils';
|
||||
import { useComposeDB } from 'contexts/ComposeDBContext';
|
||||
import { Player } from 'graphql/autogen/types';
|
||||
import { buildPlayerProfileQuery } from 'graphql/composeDB/queries/profile';
|
||||
import { ComposeDBProfileQueryResult } from 'graphql/types';
|
||||
@@ -16,6 +15,8 @@ import { CeramicError } from 'lib/errors';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { errorHandler } from 'utils/errorHandler';
|
||||
|
||||
import { useComposeDB } from './useComposeDB';
|
||||
|
||||
const genericFetchError = new CeramicError(
|
||||
'An unexpected error occurred when querying Ceramic.',
|
||||
);
|
||||
@@ -65,7 +66,7 @@ export const useGetPlayerProfileFromComposeDB = (
|
||||
export const hydratePlayerProfile = (
|
||||
player: Player,
|
||||
profileData: ComposeDBProfile,
|
||||
) => {
|
||||
): Player => {
|
||||
const hasComposeDBData = Object.values(profileData).some((value) => !!value);
|
||||
if (hasComposeDBData) {
|
||||
const hasuraProfile = composeDBToHasuraProfile(profileData);
|
||||
|
||||
@@ -2,19 +2,17 @@ import { useToast } from '@metafam/ds';
|
||||
import {
|
||||
ComposeDBField,
|
||||
ComposeDBImageMetadata,
|
||||
ComposeDBPayloadValue,
|
||||
composeDBProfileFieldAvatar,
|
||||
composeDBProfileFieldFiveColorDisposition,
|
||||
dispositionFor,
|
||||
getMimeType,
|
||||
HasuraImageFieldKey,
|
||||
isComposeDBImageField,
|
||||
isImageMetadata,
|
||||
Maybe,
|
||||
profileMapping,
|
||||
} from '@metafam/utils';
|
||||
import { useSetupFlow } from 'contexts/SetupContext';
|
||||
import { Profile } from 'graphql/autogen/types';
|
||||
import { PlayerProfile } from 'graphql/types';
|
||||
import { CeramicError } from 'lib/errors';
|
||||
import { ReactElement, useCallback, useEffect, useState } from 'react';
|
||||
import { errorHandler } from 'utils/errorHandler';
|
||||
@@ -128,7 +126,7 @@ export function usePlayerSetupSaveToComposeDB({
|
||||
}
|
||||
|
||||
export const hasuraToComposeDBProfile = (
|
||||
profile: Profile,
|
||||
profile: PlayerProfile,
|
||||
images: Record<HasuraImageFieldKey, Maybe<ComposeDBImageMetadata>>,
|
||||
) => {
|
||||
// todo we should be able to make this typesafe
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { ComposeDBProfile, Maybe } from '@metafam/utils';
|
||||
import { useComposeDB } from 'contexts/ComposeDBContext';
|
||||
import { useLinkOwnCeramicNodeMutation } from 'graphql/autogen/types';
|
||||
import {
|
||||
ComposeDBCreateProfileResponseData,
|
||||
@@ -9,6 +8,7 @@ import { CeramicError, handleCeramicAuthenticationError } from 'lib/errors';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
import { useUser } from '../useUser';
|
||||
import { useComposeDB } from './useComposeDB';
|
||||
|
||||
export type SaveToComposeDBStatus = 'authenticating' | 'querying' | undefined;
|
||||
|
||||
|
||||
@@ -2,9 +2,14 @@ import { Maybe } from '@metafam/utils';
|
||||
import { Player, useGetMeQuery } from 'graphql/autogen/types';
|
||||
import { useWeb3 } from 'lib/hooks/useWeb3';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { CombinedError, RequestPolicy } from 'urql';
|
||||
|
||||
import {
|
||||
hydratePlayerProfile,
|
||||
useGetPlayerProfileFromComposeDB,
|
||||
} from './ceramic/useGetPlayerProfileFromComposeDB';
|
||||
|
||||
type UseUserOpts = {
|
||||
redirectTo?: string;
|
||||
redirectIfNotFound?: boolean;
|
||||
@@ -30,7 +35,9 @@ export const useUser = ({
|
||||
});
|
||||
const [me] = data?.me ?? [];
|
||||
|
||||
const user = useMemo(
|
||||
const [hydratedPlayer, setHydratedPlayer] = useState<Player | null>(null);
|
||||
|
||||
const hasuraUser = useMemo(
|
||||
() =>
|
||||
!error && !fetching && authToken && me && connected
|
||||
? (me.record as Player)
|
||||
@@ -38,6 +45,22 @@ export const useUser = ({
|
||||
[error, authToken, me, connected, fetching],
|
||||
);
|
||||
|
||||
const {
|
||||
result,
|
||||
fetching: composeDBFetching,
|
||||
error: composeDBError,
|
||||
} = useGetPlayerProfileFromComposeDB(hasuraUser?.ceramicProfileId);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasuraUser) {
|
||||
if (hasuraUser.ceramicProfileId == null || composeDBError) {
|
||||
setHydratedPlayer(hasuraUser);
|
||||
} else if (hasuraUser && result) {
|
||||
setHydratedPlayer(hydratePlayerProfile(hasuraUser, result));
|
||||
}
|
||||
}
|
||||
}, [result, hasuraUser, composeDBError]);
|
||||
|
||||
if (error) {
|
||||
console.error('useUser error', error);
|
||||
}
|
||||
@@ -52,16 +75,23 @@ export const useUser = ({
|
||||
|
||||
// If redirectTo is set and redirectIfNotFound is set then
|
||||
// redirect if the user was not found.
|
||||
if (redirectTo && redirectIfNotFound && !user) {
|
||||
if (redirectTo && redirectIfNotFound && !hasuraUser) {
|
||||
router.push(redirectTo);
|
||||
}
|
||||
}, [router, user, fetching, connecting, redirectIfNotFound, redirectTo]);
|
||||
}, [
|
||||
router,
|
||||
hasuraUser,
|
||||
fetching,
|
||||
connecting,
|
||||
redirectIfNotFound,
|
||||
redirectTo,
|
||||
]);
|
||||
|
||||
return {
|
||||
connecting,
|
||||
connected,
|
||||
user,
|
||||
fetching,
|
||||
user: hydratedPlayer,
|
||||
fetching: fetching || composeDBFetching,
|
||||
error,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import { ChakraProvider, CSSReset, MetaTheme } from '@metafam/ds';
|
||||
import { UserbackProvider } from '@userback/react';
|
||||
import { MegaMenu } from 'components/MegaMenu/index';
|
||||
import { CONFIG } from 'config';
|
||||
import { ComposeDBContextProvider } from 'contexts/ComposeDBContext';
|
||||
import { Web3ContextProvider } from 'contexts/Web3Context';
|
||||
import { wrapUrqlClient } from 'graphql/client';
|
||||
import Head from 'next/head';
|
||||
@@ -59,9 +60,11 @@ const App: React.FC<WithUrqlProps> = ({
|
||||
{environment === 'production' && <Analytics />}
|
||||
</Head>
|
||||
<Web3ContextProvider {...{ resetUrqlClient }}>
|
||||
<MegaMenu hide={pageProps.hideTopMenu}>
|
||||
<Component {...pageProps} />
|
||||
</MegaMenu>
|
||||
<ComposeDBContextProvider>
|
||||
<MegaMenu hide={pageProps.hideTopMenu}>
|
||||
<Component {...pageProps} />
|
||||
</MegaMenu>
|
||||
</ComposeDBContextProvider>
|
||||
</Web3ContextProvider>
|
||||
</ChakraProvider>
|
||||
</React.StrictMode>
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
} from 'components/Player/Section/config';
|
||||
import { HeadComponent } from 'components/Seo';
|
||||
import { CONFIG } from 'config';
|
||||
import { ComposeDBContextProvider } from 'contexts/ComposeDBContext';
|
||||
import {
|
||||
PlayerHydrationContextProvider,
|
||||
usePlayerHydrationContext,
|
||||
@@ -60,14 +59,12 @@ export const PlayerPage: React.FC<PlayerPageProps> = ({
|
||||
if (!player) return <Page404 />;
|
||||
|
||||
return (
|
||||
<ComposeDBContextProvider>
|
||||
<PlayerHydrationContextProvider
|
||||
player={player}
|
||||
isHydratedAlready={isHydratedFromComposeDB}
|
||||
>
|
||||
<PlayerPageContent />
|
||||
</PlayerHydrationContextProvider>
|
||||
</ComposeDBContextProvider>
|
||||
<PlayerHydrationContextProvider
|
||||
player={player}
|
||||
isHydratedAlready={isHydratedFromComposeDB}
|
||||
>
|
||||
<PlayerPageContent />
|
||||
</PlayerHydrationContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -3010,7 +3010,8 @@ input jsonb_comparison_exp {
|
||||
}
|
||||
|
||||
type LinkCeramicProfileNodeResponse {
|
||||
verified: Boolean
|
||||
error: String
|
||||
verified: Boolean!
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
42
yarn.lock
42
yarn.lock
@@ -5751,11 +5751,6 @@
|
||||
elliptic "^6.5.4"
|
||||
typedarray-to-buffer "^4.0.0"
|
||||
|
||||
"@tokenizer/token@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@tokenizer/token/-/token-0.3.0.tgz#fe98a93fe789247e998c75e74e9c7c63217aa276"
|
||||
integrity sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==
|
||||
|
||||
"@tootallnate/once@1":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||
@@ -11699,15 +11694,6 @@ file-selector@^0.6.0:
|
||||
dependencies:
|
||||
tslib "^2.4.0"
|
||||
|
||||
file-type@18.2.0:
|
||||
version "18.2.0"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-18.2.0.tgz#c2abec00d1af0f09151e1549e3588aab0bac5001"
|
||||
integrity sha512-M3RQMWY3F2ykyWZ+IHwNCjpnUmukYhtdkGGC1ZVEUb0ve5REGF7NNJ4Q9ehCUabtQKtSVFOMbFTXgJlFb0DQIg==
|
||||
dependencies:
|
||||
readable-web-to-node-stream "^3.0.2"
|
||||
strtok3 "^7.0.0"
|
||||
token-types "^5.0.1"
|
||||
|
||||
file-uri-to-path@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
|
||||
@@ -17544,11 +17530,6 @@ pbkdf2@^3.0.17, pbkdf2@^3.0.3:
|
||||
safe-buffer "^5.0.1"
|
||||
sha.js "^2.4.8"
|
||||
|
||||
peek-readable@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/peek-readable/-/peek-readable-5.0.0.tgz#7ead2aff25dc40458c60347ea76cfdfd63efdfec"
|
||||
integrity sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==
|
||||
|
||||
peer-id@^0.16.0:
|
||||
version "0.16.0"
|
||||
resolved "https://registry.yarnpkg.com/peer-id/-/peer-id-0.16.0.tgz#0913062cfa4378707fe69c949b5720b3efadbf32"
|
||||
@@ -18640,13 +18621,6 @@ readable-stream@~1.0.15:
|
||||
isarray "0.0.1"
|
||||
string_decoder "~0.10.x"
|
||||
|
||||
readable-web-to-node-stream@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz#5d52bb5df7b54861fd48d015e93a2cb87b3ee0bb"
|
||||
integrity sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==
|
||||
dependencies:
|
||||
readable-stream "^3.6.0"
|
||||
|
||||
readdir-scoped-modules@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309"
|
||||
@@ -20105,14 +20079,6 @@ strong-log-transformer@^2.1.0:
|
||||
minimist "^1.2.0"
|
||||
through "^2.3.4"
|
||||
|
||||
strtok3@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strtok3/-/strtok3-7.0.0.tgz#868c428b4ade64a8fd8fee7364256001c1a4cbe5"
|
||||
integrity sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==
|
||||
dependencies:
|
||||
"@tokenizer/token" "^0.3.0"
|
||||
peek-readable "^5.0.0"
|
||||
|
||||
style-to-js@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.1.tgz#417786986cda61d4525c80aed9d1123a6a7af9b8"
|
||||
@@ -20471,14 +20437,6 @@ toidentifier@1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
|
||||
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
|
||||
|
||||
token-types@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/token-types/-/token-types-5.0.1.tgz#aa9d9e6b23c420a675e55413b180635b86a093b4"
|
||||
integrity sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==
|
||||
dependencies:
|
||||
"@tokenizer/token" "^0.3.0"
|
||||
ieee754 "^1.2.1"
|
||||
|
||||
touch@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b"
|
||||
|
||||
Reference in New Issue
Block a user