mirror of https://github.com/sylv/micro.git
feat: replace apollo with urql
This commit is contained in:
parent
fc0071165f
commit
bdcafc8347
|
@ -16,8 +16,6 @@
|
|||
"watch": "concurrently \"vavite serve\" \"pnpm generate --watch\""
|
||||
},
|
||||
"devDependencies": {
|
||||
"@0no-co/graphqlsp": "^1.3.0",
|
||||
"@apollo/client": "^3.8.9",
|
||||
"@atlasbot/configs": "^10.5.15",
|
||||
"@fastify/early-hints": "^1.0.1",
|
||||
"@fastify/http-proxy": "^9.3.0",
|
||||
|
@ -32,6 +30,8 @@
|
|||
"@types/node": "^20.10.6",
|
||||
"@types/react": "^18.2.47",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"@urql/devtools": "^2.0.3",
|
||||
"@urql/exchange-graphcache": "^6.4.1",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"clsx": "^2.1.0",
|
||||
"concurrently": "^8.2.2",
|
||||
|
@ -61,6 +61,7 @@
|
|||
"tailwindcss": "^3.4.1",
|
||||
"tsup": "^8.0.1",
|
||||
"typescript": "^5.3.3",
|
||||
"urql": "^4.0.6",
|
||||
"vavite": "^4.0.1",
|
||||
"vike": "^0.4.156",
|
||||
"vite": "^5.0.11",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import clsx from 'clsx';
|
||||
import React, { forwardRef } from 'react';
|
||||
import { forwardRef } from 'react';
|
||||
import { FiArrowLeft } from 'react-icons/fi';
|
||||
|
||||
export interface BreadcrumbsProps {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable react/button-has-type */
|
||||
import clsx from 'clsx';
|
||||
import type { FC, HTMLAttributes } from 'react';
|
||||
import React, { forwardRef } from 'react';
|
||||
import { forwardRef } from 'react';
|
||||
import { Spinner } from './spinner';
|
||||
|
||||
export interface ButtonProps extends Omit<HTMLAttributes<HTMLButtonElement | HTMLAnchorElement>, 'prefix' | 'style'> {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import clsx from 'clsx';
|
||||
import type { FC, ReactNode } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
export interface ContainerProps {
|
||||
centerX?: boolean;
|
||||
|
|
|
@ -13,7 +13,7 @@ import { Link } from '../link';
|
|||
import { useToasts } from '../toast';
|
||||
import { HeaderUser } from './header-user';
|
||||
import { graphql } from '../../@generated';
|
||||
import { useMutation } from '@apollo/client';
|
||||
import { useMutation } from 'urql';
|
||||
|
||||
const ResendVerificationEmail = graphql(`
|
||||
mutation ResendVerificationEmail($data: ResendVerificationEmailDto) {
|
||||
|
@ -40,7 +40,7 @@ export const Header = memo(() => {
|
|||
setShowEmailInput(false);
|
||||
});
|
||||
|
||||
const [resendMutation] = useMutation(ResendVerificationEmail);
|
||||
const [, resendMutation] = useMutation(ResendVerificationEmail);
|
||||
const [resendVerification, sendingVerification] = useAsync(async () => {
|
||||
if (resent || !user.data) return;
|
||||
if (!user.data.email && !email) {
|
||||
|
@ -51,9 +51,7 @@ export const Header = memo(() => {
|
|||
const payload = !user.data.email && email ? { email } : null;
|
||||
try {
|
||||
await resendMutation({
|
||||
variables: {
|
||||
data: payload,
|
||||
},
|
||||
data: payload,
|
||||
});
|
||||
|
||||
setShowEmailInput(false);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { forwardRef, Fragment, type HTMLAttributes } from 'react';
|
||||
import { forwardRef, type HTMLAttributes } from 'react';
|
||||
|
||||
export interface LinkProps extends HTMLAttributes<HTMLAnchorElement> {
|
||||
href: string;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import clsx from 'clsx';
|
||||
import type { FC, HTMLAttributes } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
export interface SpinnerProps extends HTMLAttributes<SVGElement> {
|
||||
size?: 'small' | 'medium' | 'large';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import { ToastProps } from "./toast";
|
||||
import React from 'react';
|
||||
import { ToastProps } from './toast';
|
||||
|
||||
export type ToastContextData = null | ((toast: ToastProps) => void);
|
||||
export const ToastContext = React.createContext<ToastContextData>(null);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { nanoid } from 'nanoid';
|
||||
import type { FC, ReactNode } from 'react';
|
||||
import React, { Fragment, useCallback, useState } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { ToastContext } from './context';
|
||||
import type { ToastProps } from './toast';
|
||||
import { Toast, TRANSITION_DURATION } from './toast';
|
||||
import { TRANSITION_DURATION, Toast } from './toast';
|
||||
|
||||
// spread operators on arrays are to fix this
|
||||
// https://stackoverflow.com/questions/56266575/why-is-usestate-not-triggering-re-render
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import clsx from 'clsx';
|
||||
import type { FC } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export interface ToastProps {
|
||||
text: string;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useQuery } from '@apollo/client';
|
||||
import type { FC } from 'react';
|
||||
import { Fragment } from 'react';
|
||||
import { useQuery } from 'urql';
|
||||
import { graphql } from '../../@generated';
|
||||
import { Breadcrumbs } from '../../components/breadcrumbs';
|
||||
import { Card } from '../../components/card';
|
||||
|
@ -51,9 +51,10 @@ const GetPastesQuery = graphql(`
|
|||
|
||||
export const FileList: FC = () => {
|
||||
const [filter, setFilter] = useQueryState('filter', 'files');
|
||||
const files = useQuery(GetFilesQuery, { skip: filter !== 'files' });
|
||||
const pastes = useQuery(GetPastesQuery, { skip: filter !== 'pastes' });
|
||||
const [files, filesFetchMore] = useQuery({ query: GetFilesQuery, pause: filter !== 'files' });
|
||||
const [pastes, pastesFetchMore] = useQuery({ query: GetPastesQuery, pause: filter !== 'pastes' });
|
||||
const source = filter === 'files' ? files : pastes;
|
||||
const fetchMore = filter === 'files' ? filesFetchMore : pastesFetchMore;
|
||||
if (source.error) {
|
||||
return <Error error={source.error} />;
|
||||
}
|
||||
|
@ -102,7 +103,7 @@ export const FileList: FC = () => {
|
|||
{pastes.data?.user.pastes.edges.map(({ node }) => <PasteCard key={node.id} paste={node} />)}
|
||||
</div>
|
||||
)}
|
||||
{!source.loading && !hasContent && (
|
||||
{!source.fetching && !hasContent && (
|
||||
<Card className="text-gray-500">
|
||||
You haven't uploaded anything yet. Once you upload something, it will appear here.
|
||||
</Card>
|
||||
|
@ -113,7 +114,7 @@ export const FileList: FC = () => {
|
|||
className="w-full bg-dark-200 px-2 py-2 text-gray-500 hover:bg-dark-300 transition"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
source.fetchMore({
|
||||
fetchMore({
|
||||
variables: {
|
||||
after: currentPageInfo.pageInfo.endCursor,
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useQuery } from '@apollo/client';
|
||||
import { CombinedError, useQuery } from 'urql';
|
||||
import { graphql } from '../@generated';
|
||||
|
||||
const ConfigQuery = graphql(`
|
||||
|
@ -24,9 +24,9 @@ const ConfigQuery = graphql(`
|
|||
`);
|
||||
|
||||
export const useConfig = () => {
|
||||
const config = useQuery(ConfigQuery);
|
||||
const [config] = useQuery({ query: ConfigQuery });
|
||||
return {
|
||||
...config,
|
||||
error: config.error as CombinedError | undefined,
|
||||
data: config.data?.config,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { TypedDocumentNode, useMutation, useQuery } from '@apollo/client';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { CombinedError, TypedDocumentNode, useMutation, useQuery } from 'urql';
|
||||
import { graphql } from '../@generated';
|
||||
import type { GetUserQuery, LoginMutationVariables, RegularUserFragment } from '../@generated/graphql';
|
||||
import { navigate, reload } from '../helpers/routing';
|
||||
|
@ -38,10 +38,10 @@ const LogoutMutation = graphql(`
|
|||
|
||||
export const useLoginUser = () => {
|
||||
const [otp, setOtp] = useState(false);
|
||||
const [loginMutation] = useMutation(LoginMutation);
|
||||
const [, loginMutation] = useMutation(LoginMutation);
|
||||
const [login] = useAsync(async (variables: LoginMutationVariables) => {
|
||||
try {
|
||||
await loginMutation({ variables });
|
||||
await loginMutation(variables);
|
||||
navigate('/dashboard');
|
||||
} catch (error: any) {
|
||||
if (error.message.toLowerCase().includes('otp')) {
|
||||
|
@ -59,7 +59,7 @@ export const useLoginUser = () => {
|
|||
};
|
||||
|
||||
export const useLogoutUser = () => {
|
||||
const [logoutMutation] = useMutation(LogoutMutation);
|
||||
const [, logoutMutation] = useMutation(LogoutMutation);
|
||||
const [logout] = useAsync(async () => {
|
||||
await logoutMutation({});
|
||||
reload();
|
||||
|
@ -69,27 +69,27 @@ export const useLogoutUser = () => {
|
|||
};
|
||||
|
||||
export const useUserRedirect = (
|
||||
query: { data: { user: RegularUserFragment } | null | undefined; loading: boolean; called: boolean },
|
||||
query: { data?: { user: RegularUserFragment } | null | undefined; fetching: boolean },
|
||||
redirect: boolean | undefined,
|
||||
) => {
|
||||
useEffect(() => {
|
||||
if (!query.data && !query.loading && query.called && redirect) {
|
||||
if (!query.data && !query.fetching && redirect) {
|
||||
navigate(`/login?to=${window.location.href}`);
|
||||
}
|
||||
}, [redirect, query.data, query.loading, query.called]);
|
||||
}, [redirect, query.data, query.fetching]);
|
||||
};
|
||||
|
||||
export const useUser = <T extends TypedDocumentNode<GetUserQuery, any>>(redirect?: boolean, query?: T) => {
|
||||
const { login, otpRequired } = useLoginUser();
|
||||
const { logout } = useLogoutUser();
|
||||
const { data, loading, called, error } = useQuery((query || UserQuery) as T);
|
||||
const [{ data, fetching, error }] = useQuery({ query: (query || UserQuery) as T });
|
||||
|
||||
useUserRedirect({ data, loading, called }, redirect);
|
||||
useUserRedirect({ data, fetching }, redirect);
|
||||
|
||||
return {
|
||||
data: data?.user as RegularUserFragment | null | undefined,
|
||||
loading: loading,
|
||||
error: error,
|
||||
fetching: fetching,
|
||||
error: error as CombinedError | undefined,
|
||||
otpRequired: otpRequired,
|
||||
login: login,
|
||||
logout: logout,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useMutation, useQuery } from '@apollo/client';
|
||||
import { useMutation, useQuery } from 'urql';
|
||||
import clsx from 'clsx';
|
||||
import { QRCodeSVG } from 'qrcode.react';
|
||||
import { FC, Fragment, useCallback, useMemo } from 'react';
|
||||
|
@ -32,10 +32,10 @@ const ConfirmOTP = graphql(`
|
|||
`);
|
||||
|
||||
export const Page: FC = () => {
|
||||
const result = useQuery(GenerateOtp);
|
||||
const [result] = useQuery({ query: GenerateOtp });
|
||||
const createToast = useToasts();
|
||||
const [currentStep, setCurrentStep] = useQueryState('step', 0, Number);
|
||||
const [confirmOtp] = useMutation(ConfirmOTP);
|
||||
const [, confirmOtp] = useMutation(ConfirmOTP);
|
||||
|
||||
const copyable = useMemo(() => {
|
||||
if (!result.data) return;
|
||||
|
@ -64,7 +64,7 @@ export const Page: FC = () => {
|
|||
|
||||
const [confirm, confirming] = useAsync(async (otpCode: string) => {
|
||||
try {
|
||||
await confirmOtp({ variables: { otpCode } });
|
||||
await confirmOtp({ otpCode });
|
||||
createToast({ text: 'Successfully enabled 2FA!' });
|
||||
navigate('/dashboard', { overwriteLastHistoryEntry: true });
|
||||
} catch (error: any) {
|
||||
|
@ -77,7 +77,7 @@ export const Page: FC = () => {
|
|||
}
|
||||
});
|
||||
|
||||
if (result.loading) return <PageLoader />;
|
||||
if (result.fetching) return <PageLoader />;
|
||||
if (!result.data) return <Error error={result.error} />;
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { useMutation, useQuery } from '@apollo/client';
|
||||
import { FC, Fragment } from 'react';
|
||||
import { useMutation, useQuery } from 'urql';
|
||||
import { graphql } from '../../../@generated';
|
||||
import { GetUserDocument } from '../../../@generated/graphql';
|
||||
import { Breadcrumbs } from '../../../components/breadcrumbs';
|
||||
import { Button } from '../../../components/button';
|
||||
import { Container } from '../../../components/container';
|
||||
|
@ -39,22 +38,20 @@ const UserQueryWithToken = graphql(`
|
|||
`);
|
||||
|
||||
export const Page: FC = () => {
|
||||
const user = useQuery(UserQueryWithToken);
|
||||
const [user] = useQuery({ query: UserQueryWithToken });
|
||||
const { logout } = useLogoutUser();
|
||||
const [refreshMutation] = useMutation(RefreshToken);
|
||||
const [, refreshMutation] = useMutation(RefreshToken);
|
||||
const [refresh, refreshing] = useAsync(async () => {
|
||||
// eslint-disable-next-line no-alert
|
||||
const confirmation = confirm('Are you sure? This will invalidate all existing configs and sessions and will sign you out of the dashboard.') // prettier-ignore
|
||||
if (!confirmation) return;
|
||||
await refreshMutation();
|
||||
await refreshMutation({});
|
||||
await logout();
|
||||
});
|
||||
|
||||
useUserRedirect(user, true);
|
||||
|
||||
const [disableOTP, disableOTPMut] = useMutation(DisableOtp, {
|
||||
refetchQueries: [{ query: GetUserDocument }],
|
||||
});
|
||||
const [disableOTPMut, disableOTP] = useMutation(DisableOtp);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
|
@ -125,11 +122,9 @@ export const Page: FC = () => {
|
|||
<div className="right flex items-center col-span-full md:col-span-1">
|
||||
{user.data && user.data.user.otpEnabled && (
|
||||
<OtpInput
|
||||
loading={disableOTPMut.loading}
|
||||
loading={disableOTPMut.fetching}
|
||||
onCode={(otpCode) => {
|
||||
disableOTP({
|
||||
variables: { otpCode },
|
||||
});
|
||||
disableOTP({ otpCode });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { useMutation, useQuery } from '@apollo/client';
|
||||
import clsx from 'clsx';
|
||||
import copyToClipboard from 'copy-to-clipboard';
|
||||
import type { FC, ReactNode } from 'react';
|
||||
import { Fragment, useState } from 'react';
|
||||
import { FiDownload, FiShare, FiTrash } from 'react-icons/fi';
|
||||
import { useMutation, useQuery } from 'urql';
|
||||
import { graphql } from '../../../@generated';
|
||||
import { Container } from '../../../components/container';
|
||||
import { Embed } from '../../../components/embed/embed';
|
||||
|
@ -72,14 +72,15 @@ export const Page: FC<PageProps> = ({ routeParams }) => {
|
|||
const [deleteKey] = useQueryState<string | undefined>('deleteKey');
|
||||
const [confirm, setConfirm] = useState(false);
|
||||
const createToast = useToasts();
|
||||
const file = useQuery(GetFile, {
|
||||
skip: !fileId,
|
||||
const [file] = useQuery({
|
||||
query: GetFile,
|
||||
pause: !fileId,
|
||||
variables: {
|
||||
fileId: fileId as string,
|
||||
},
|
||||
});
|
||||
|
||||
const [deleteMutation] = useMutation(DeleteFile);
|
||||
const [, deleteMutation] = useMutation(DeleteFile);
|
||||
const copyLink = () => {
|
||||
copyToClipboard(file.data?.file.urls.view ?? window.location.href);
|
||||
createToast({
|
||||
|
@ -100,10 +101,8 @@ export const Page: FC<PageProps> = ({ routeParams }) => {
|
|||
}
|
||||
|
||||
await deleteMutation({
|
||||
variables: {
|
||||
fileId: file.data.file.id,
|
||||
deleteKey: deleteKey,
|
||||
},
|
||||
fileId: file.data.file.id,
|
||||
deleteKey: deleteKey,
|
||||
});
|
||||
|
||||
createToast({ text: `Deleted "${file.data.file.displayName}"` });
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { useMutation, useQuery } from '@apollo/client';
|
||||
import { FC, useEffect } from 'react';
|
||||
import { graphql } from '../../../@generated';
|
||||
import { Container } from '../../../components/container';
|
||||
|
@ -14,6 +13,7 @@ import { navigate, prefetch } from '../../../helpers/routing';
|
|||
import { useAsync } from '../../../hooks/useAsync';
|
||||
import { useConfig } from '../../../hooks/useConfig';
|
||||
import { PageProps } from '../../../renderer/types';
|
||||
import { useQuery, useMutation } from 'urql';
|
||||
|
||||
const GetInvite = graphql(`
|
||||
query GetInvite($inviteId: ID!) {
|
||||
|
@ -36,23 +36,21 @@ export const Page: FC<PageProps> = ({ routeParams }) => {
|
|||
const config = useConfig();
|
||||
const createToast = useToasts();
|
||||
const inviteToken = routeParams.inviteToken;
|
||||
const invite = useQuery(GetInvite, { skip: !inviteToken, variables: { inviteId: inviteToken! } });
|
||||
const [invite] = useQuery({ query: GetInvite, pause: !inviteToken, variables: { inviteId: inviteToken! } });
|
||||
const expiresAt = invite.data?.invite.expiresAt;
|
||||
|
||||
useEffect(() => {
|
||||
prefetch('/login');
|
||||
}, []);
|
||||
|
||||
const [createUserMutation] = useMutation(CreateUser);
|
||||
const [, createUserMutation] = useMutation(CreateUser);
|
||||
const [onSubmit] = useAsync(async (data: SignupData) => {
|
||||
try {
|
||||
if (!inviteToken) return;
|
||||
await createUserMutation({
|
||||
variables: {
|
||||
user: {
|
||||
...data,
|
||||
invite: inviteToken,
|
||||
},
|
||||
user: {
|
||||
...data,
|
||||
invite: inviteToken,
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { useMutation } from '@apollo/client';
|
||||
import { Form, Formik } from 'formik';
|
||||
import { FC } from 'react';
|
||||
import * as Yup from 'yup';
|
||||
|
@ -15,6 +14,7 @@ import { Title } from '../../components/title';
|
|||
import { encryptContent } from '../../helpers/encrypt.helper';
|
||||
import { useConfig } from '../../hooks/useConfig';
|
||||
import { useUser } from '../../hooks/useUser';
|
||||
import { useMutation } from 'urql';
|
||||
|
||||
const EXPIRY_OPTIONS = [
|
||||
{ name: '15 minutes', value: 15 },
|
||||
|
@ -98,7 +98,7 @@ const CreatePaste = graphql(`
|
|||
export const Page: FC = () => {
|
||||
const user = useUser();
|
||||
const config = useConfig();
|
||||
const [pasteMutation] = useMutation(CreatePaste);
|
||||
const [, pasteMutation] = useMutation(CreatePaste);
|
||||
if (user.error) {
|
||||
return <Error error={user.error} />;
|
||||
}
|
||||
|
@ -148,12 +148,9 @@ export const Page: FC = () => {
|
|||
}
|
||||
|
||||
const paste = await pasteMutation({
|
||||
variables: {
|
||||
input: body,
|
||||
},
|
||||
input: body,
|
||||
});
|
||||
|
||||
if (paste.errors && paste.errors[0]) throw paste.errors[0];
|
||||
const url = new URL(paste.data!.createPaste.urls.view);
|
||||
if (body.burn) url.searchParams.set('burn_unless', user.data.id);
|
||||
if (encryptionKey) url.hash = `key=${encryptionKey}`;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { useQuery } from '@apollo/client';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { FiBookOpen, FiClock, FiTrash } from 'react-icons/fi';
|
||||
import { graphql } from '../../../@generated';
|
||||
|
@ -14,6 +13,7 @@ import { hashToObject } from '../../../helpers/hash-to-object';
|
|||
import { navigate } from '../../../helpers/routing';
|
||||
import { useUser } from '../../../hooks/useUser';
|
||||
import { PageProps } from '../../../renderer/types';
|
||||
import { useQuery } from 'urql';
|
||||
|
||||
const PasteQuery = graphql(`
|
||||
query GetPaste($pasteId: ID!) {
|
||||
|
@ -47,8 +47,9 @@ export const Page: FC<PageProps> = ({ routeParams }) => {
|
|||
const skipQuery =
|
||||
!pasteId || (!confirmedBurn && (burnUnless === undefined || (burnUnless ? burnUnless !== user.data?.id : false)));
|
||||
|
||||
const paste = useQuery(PasteQuery, {
|
||||
skip: skipQuery,
|
||||
const [paste] = useQuery({
|
||||
query: PasteQuery,
|
||||
pause: skipQuery,
|
||||
variables: {
|
||||
pasteId: pasteId!,
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useMutation } from '@apollo/client';
|
||||
import { useMutation } from 'urql';
|
||||
import { Form, Formik } from 'formik';
|
||||
import { FC, useState } from 'react';
|
||||
import * as Yup from 'yup';
|
||||
|
@ -30,7 +30,7 @@ const Shorten = graphql(`
|
|||
`);
|
||||
|
||||
export const Page: FC = () => {
|
||||
const [shortenMutation] = useMutation(Shorten);
|
||||
const [, shortenMutation] = useMutation(Shorten);
|
||||
const [result, setResult] = useState<string | null>(null);
|
||||
const config = useConfig();
|
||||
|
||||
|
@ -48,10 +48,8 @@ export const Page: FC = () => {
|
|||
validationSchema={schema}
|
||||
onSubmit={async (values) => {
|
||||
const result = await shortenMutation({
|
||||
variables: {
|
||||
link: values.url,
|
||||
host: values.host,
|
||||
},
|
||||
link: values.url,
|
||||
host: values.host,
|
||||
});
|
||||
|
||||
setResult(result.data!.createLink.urls.view);
|
||||
|
|
|
@ -1,32 +1,42 @@
|
|||
import { ApolloClient, ApolloProvider, HttpLink, InMemoryCache } from '@apollo/client';
|
||||
import { createClient, fetchExchange, ssrExchange } from 'urql';
|
||||
import { Provider as UrqlProvider } from 'urql';
|
||||
import { hydrateRoot } from 'react-dom/client';
|
||||
import { HelmetProvider } from 'react-helmet-async';
|
||||
import { OnRenderClientAsync } from 'vike/types';
|
||||
import { App } from '../app';
|
||||
import { typePolicies } from './policy';
|
||||
import { PageContextProvider } from './usePageContext';
|
||||
import { HelmetProvider } from 'react-helmet-async';
|
||||
import { cacheOptions } from './cache';
|
||||
import { cacheExchange } from '@urql/exchange-graphcache';
|
||||
|
||||
export const onRenderClient: OnRenderClientAsync = async (pageContext) => {
|
||||
const { Page } = pageContext;
|
||||
const client = new ApolloClient({
|
||||
link: new HttpLink({ uri: '/api/graphql' }),
|
||||
cache: new InMemoryCache({ typePolicies }),
|
||||
const ssr = ssrExchange({ isClient: true });
|
||||
const exchanges = [ssr, cacheExchange(cacheOptions), fetchExchange];
|
||||
|
||||
if (import.meta.env.MODE === 'development') {
|
||||
const { devtoolsExchange } = await import('@urql/devtools');
|
||||
exchanges.unshift(devtoolsExchange);
|
||||
}
|
||||
|
||||
const client = createClient({
|
||||
url: '/api/graphql',
|
||||
exchanges: exchanges,
|
||||
});
|
||||
|
||||
if (pageContext.state) {
|
||||
client.cache.restore(pageContext.state);
|
||||
ssr.restoreData(pageContext.state);
|
||||
}
|
||||
|
||||
hydrateRoot(
|
||||
document.getElementById('root')!,
|
||||
<PageContextProvider pageContext={pageContext}>
|
||||
<ApolloProvider client={client}>
|
||||
<UrqlProvider value={client}>
|
||||
<HelmetProvider>
|
||||
<App>
|
||||
<Page routeParams={pageContext.routeParams || {}} />
|
||||
</App>
|
||||
</HelmetProvider>
|
||||
</ApolloProvider>
|
||||
</UrqlProvider>
|
||||
</PageContextProvider>,
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import { ApolloClient, ApolloProvider, HttpLink, InMemoryCache } from '@apollo/client';
|
||||
import { renderToStringWithData } from '@apollo/client/react/ssr';
|
||||
import { createClient, fetchExchange, ssrExchange } from 'urql';
|
||||
import { HelmetProvider, HelmetServerState } from 'react-helmet-async';
|
||||
import { Provider as UrqlProvider } from 'urql';
|
||||
import { dangerouslySkipEscape, escapeInject } from 'vike/server';
|
||||
import type { OnRenderHtmlAsync } from 'vike/types';
|
||||
import { App } from '../app';
|
||||
import { typePolicies } from './policy';
|
||||
import { renderToStringWithData } from './prepass';
|
||||
import { PageProps } from './types';
|
||||
import { PageContextProvider } from './usePageContext';
|
||||
import { cacheExchange } from '@urql/exchange-graphcache';
|
||||
import { cacheOptions } from './cache';
|
||||
|
||||
const GRAPHQL_URL = (import.meta.env.PUBLIC_ENV__FRONTEND_API_URL || import.meta.env.FRONTEND_API_URL) + '/graphql';
|
||||
|
||||
|
@ -15,30 +17,30 @@ export const onRenderHtml: OnRenderHtmlAsync = async (pageContext): ReturnType<O
|
|||
const pageProps: PageProps = { routeParams: pageContext.routeParams };
|
||||
|
||||
const headers = pageContext.cookies ? { Cookie: pageContext.cookies } : undefined;
|
||||
const client = new ApolloClient({
|
||||
ssrMode: true,
|
||||
cache: new InMemoryCache({ typePolicies }),
|
||||
link: new HttpLink({
|
||||
uri: GRAPHQL_URL,
|
||||
credentials: 'same-origin',
|
||||
const ssr = ssrExchange({ isClient: false });
|
||||
const client = createClient({
|
||||
url: GRAPHQL_URL,
|
||||
exchanges: [ssr, cacheExchange(cacheOptions), fetchExchange],
|
||||
fetchOptions: {
|
||||
headers: headers,
|
||||
}),
|
||||
credentials: 'same-origin',
|
||||
},
|
||||
});
|
||||
|
||||
const helmetContext: { helmet?: HelmetServerState } = {};
|
||||
const tree = (
|
||||
<PageContextProvider pageContext={pageContext}>
|
||||
<ApolloProvider client={client}>
|
||||
<UrqlProvider value={client}>
|
||||
<HelmetProvider context={helmetContext}>
|
||||
<App>
|
||||
<Page {...pageProps} />
|
||||
</App>
|
||||
</HelmetProvider>
|
||||
</ApolloProvider>
|
||||
</UrqlProvider>
|
||||
</PageContextProvider>
|
||||
);
|
||||
|
||||
const pageHtml = await renderToStringWithData(tree);
|
||||
const pageHtml = await renderToStringWithData(client, tree);
|
||||
const helmet = helmetContext.helmet!;
|
||||
const documentHtml = escapeInject`<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
@ -59,7 +61,7 @@ export const onRenderHtml: OnRenderHtmlAsync = async (pageContext): ReturnType<O
|
|||
return {
|
||||
documentHtml: documentHtml,
|
||||
pageContext: {
|
||||
state: client.cache.extract(),
|
||||
state: ssr.extractData(),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import { CacheExchangeOpts } from '@urql/exchange-graphcache';
|
||||
import { relayPagination } from '@urql/exchange-graphcache/extras';
|
||||
|
||||
export const cacheOptions: Partial<CacheExchangeOpts> = {
|
||||
resolvers: {
|
||||
User: {
|
||||
files: relayPagination(),
|
||||
pastes: relayPagination(),
|
||||
},
|
||||
},
|
||||
keys: {
|
||||
User: () => null,
|
||||
Config: () => null,
|
||||
ConfigHost: () => null,
|
||||
FileMetadata: () => null,
|
||||
ResourceLocations: () => null,
|
||||
FilePage: () => null,
|
||||
PastePage: () => null,
|
||||
},
|
||||
updates: {
|
||||
Mutation: {
|
||||
disableOTP: (result, args, cache) => {
|
||||
cache.invalidate('Query', 'user');
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
|
@ -1,13 +0,0 @@
|
|||
import { TypePolicies } from '@apollo/client';
|
||||
import { relayStylePagination } from '@apollo/client/utilities';
|
||||
|
||||
export const typePolicies: TypePolicies = {
|
||||
Config: { keyFields: [] },
|
||||
User: {
|
||||
keyFields: [],
|
||||
fields: {
|
||||
files: relayStylePagination(),
|
||||
pastes: relayStylePagination(),
|
||||
},
|
||||
},
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
import { VNode } from 'preact';
|
||||
import renderToString from 'preact-render-to-string';
|
||||
import { Client } from 'urql';
|
||||
|
||||
const MAX_DEPTH = 3;
|
||||
const isPromiseLike = (value: unknown): value is Promise<unknown> => {
|
||||
if (value && typeof (value as Promise<unknown>).then === 'function') return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Enables urql suspense, then re-renders the tree until there are no suspense errors.
|
||||
* This is a hack workaround because both `react-ssr-prepass` and `preact-ssr-prepass` are not working, both have preact/react compat errors.
|
||||
*/
|
||||
export const renderToStringWithData = async (client: Client, tree: VNode, depth = 0): Promise<string> => {
|
||||
try {
|
||||
client.suspense = true;
|
||||
const result = renderToString(tree);
|
||||
client.suspense = false;
|
||||
return result;
|
||||
} catch (error) {
|
||||
if (isPromiseLike(error)) {
|
||||
if (depth > MAX_DEPTH) {
|
||||
throw new Error(
|
||||
`Exceeded max suspense depth. Try merge your queries so there are not ${MAX_DEPTH}+ on a single page.`,
|
||||
);
|
||||
}
|
||||
|
||||
await error;
|
||||
return renderToStringWithData(client, tree, depth++);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
|
@ -1,12 +1,12 @@
|
|||
import { NormalizedCacheObject } from '@apollo/client';
|
||||
import { FC } from 'react';
|
||||
import { SSRData } from 'urql';
|
||||
|
||||
// https://vike.dev/pageContext#typescript
|
||||
declare global {
|
||||
namespace Vike {
|
||||
interface PageContext {
|
||||
Page: FC<PageProps>;
|
||||
state?: NormalizedCacheObject;
|
||||
state?: SSRData;
|
||||
pageHtml?: string;
|
||||
cookies?: string;
|
||||
}
|
||||
|
|
|
@ -10,11 +10,6 @@
|
|||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"composite": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "@0no-co/graphqlsp",
|
||||
"schema": "../api/src/schema.gql"
|
||||
}
|
||||
]
|
||||
}
|
||||
"noUnusedLocals": true,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -15,10 +15,12 @@ export default defineConfig({
|
|||
},
|
||||
],
|
||||
optimizeDeps: {
|
||||
include: ['preact', 'preact/devtools', 'preact/debug', 'preact/jsx-dev-runtime', 'preact/hooks'],
|
||||
include: ['preact', 'preact/devtools', 'preact/debug', 'preact/jsx-dev-runtime', 'preact/hooks', 'urql'],
|
||||
},
|
||||
define: { 'process.env.NODE_ENV': '"production"' },
|
||||
ssr: { noExternal: ['@apollo/client', 'prism-react-renderer', 'qrcode.react', 'formik', 'react-helmet-async'] },
|
||||
ssr: {
|
||||
noExternal: ['preact', 'urql', 'prism-react-renderer', 'qrcode.react', 'formik', 'react-helmet-async'],
|
||||
},
|
||||
plugins: [
|
||||
preact(),
|
||||
ssr({ disableAutoFullBuild: true }),
|
||||
|
|
205
pnpm-lock.yaml
205
pnpm-lock.yaml
|
@ -228,12 +228,6 @@ importers:
|
|||
|
||||
packages/web:
|
||||
devDependencies:
|
||||
'@0no-co/graphqlsp':
|
||||
specifier: ^1.3.0
|
||||
version: 1.3.0
|
||||
'@apollo/client':
|
||||
specifier: ^3.8.9
|
||||
version: 3.8.10(@preact/compat@17.1.2)(@preact/compat@17.1.2)(graphql@16.8.1)
|
||||
'@atlasbot/configs':
|
||||
specifier: ^10.5.15
|
||||
version: 10.5.15(typescript@5.3.3)
|
||||
|
@ -276,6 +270,12 @@ importers:
|
|||
'@types/react-dom':
|
||||
specifier: ^18.2.18
|
||||
version: 18.2.18
|
||||
'@urql/devtools':
|
||||
specifier: ^2.0.3
|
||||
version: 2.0.3(@urql/core@4.2.3)(graphql@16.8.1)
|
||||
'@urql/exchange-graphcache':
|
||||
specifier: ^6.4.1
|
||||
version: 6.4.1(graphql@16.8.1)
|
||||
autoprefixer:
|
||||
specifier: ^10.4.16
|
||||
version: 10.4.17(postcss@8.4.33)
|
||||
|
@ -363,6 +363,9 @@ importers:
|
|||
typescript:
|
||||
specifier: ^5.3.3
|
||||
version: 5.3.3
|
||||
urql:
|
||||
specifier: ^4.0.6
|
||||
version: 4.0.6(graphql@16.8.1)
|
||||
vavite:
|
||||
specifier: ^4.0.1
|
||||
version: 4.0.2(vite@5.0.12)
|
||||
|
@ -376,16 +379,17 @@ importers:
|
|||
specifier: ^1.3.3
|
||||
version: 1.3.3
|
||||
|
||||
packages/web/dist/server: {}
|
||||
|
||||
packages:
|
||||
|
||||
/@0no-co/graphqlsp@1.3.0:
|
||||
resolution: {integrity: sha512-eL7ZAvAmncEgAIjVgGcyKsrpIOmJ4tQfWxTDVPKxiIgRdRA56K+qjW2HtGdxE/WlufnNpbwcizU9D2HddYg1Zg==}
|
||||
/@0no-co/graphql.web@1.0.4(graphql@16.8.1):
|
||||
resolution: {integrity: sha512-W3ezhHGfO0MS1PtGloaTpg0PbaT8aZSmmaerL7idtU5F7oCI+uu25k+MsMS31BVFlp4aMkHSrNRxiD72IlK8TA==}
|
||||
peerDependencies:
|
||||
graphql: ^14.0.0 || ^15.0.0 || ^16.0.0
|
||||
peerDependenciesMeta:
|
||||
graphql:
|
||||
optional: true
|
||||
dependencies:
|
||||
node-fetch: 2.7.0
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
graphql: 16.8.1
|
||||
dev: true
|
||||
|
||||
/@aashutoshrathi/word-wrap@1.2.6:
|
||||
|
@ -406,41 +410,6 @@ packages:
|
|||
'@jridgewell/trace-mapping': 0.3.22
|
||||
dev: true
|
||||
|
||||
/@apollo/client@3.8.10(@preact/compat@17.1.2)(@preact/compat@17.1.2)(graphql@16.8.1):
|
||||
resolution: {integrity: sha512-p/22RZ8ehHyvySnC20EHPPe0gdu8Xp6ZCiXOfdEe1ZORw5cUteD/TLc66tfKv8qu8NLIfbiWoa+6s70XnKvxqg==}
|
||||
peerDependencies:
|
||||
graphql: ^14.0.0 || ^15.0.0 || ^16.0.0
|
||||
graphql-ws: ^5.5.5
|
||||
react: '*'
|
||||
react-dom: '*'
|
||||
subscriptions-transport-ws: ^0.9.0 || ^0.11.0
|
||||
peerDependenciesMeta:
|
||||
graphql-ws:
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
react-dom:
|
||||
optional: true
|
||||
subscriptions-transport-ws:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@graphql-typed-document-node/core': 3.2.0(graphql@16.8.1)
|
||||
'@wry/equality': 0.5.7
|
||||
'@wry/trie': 0.5.0
|
||||
graphql: 16.8.1
|
||||
graphql-tag: 2.12.6(graphql@16.8.1)
|
||||
hoist-non-react-statics: 3.3.2
|
||||
optimism: 0.18.0
|
||||
prop-types: 15.8.1
|
||||
react: /@preact/compat@17.1.2(preact@10.19.3)
|
||||
react-dom: /@preact/compat@17.1.2(preact@10.19.3)
|
||||
response-iterator: 0.2.6
|
||||
symbol-observable: 4.0.0
|
||||
ts-invariant: 0.10.3
|
||||
tslib: 2.6.2
|
||||
zen-observable-ts: 1.2.5
|
||||
dev: true
|
||||
|
||||
/@ardatan/relay-compiler@12.0.0(graphql@16.8.1):
|
||||
resolution: {integrity: sha512-9anThAaj1dQr6IGmzBMcfzOQKTa5artjuPmw8NYK/fiGEMjADbSguBY2FMDykt+QhilR3wc9VA/3yVju7JHg7Q==}
|
||||
hasBin: true
|
||||
|
@ -1434,7 +1403,7 @@ packages:
|
|||
'@fastify/reply-from': 9.7.0
|
||||
fast-querystring: 1.1.2
|
||||
fastify-plugin: 4.5.1
|
||||
ws: 8.16.0
|
||||
ws: 8.16.0(utf-8-validate@6.0.3)
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
|
@ -1836,7 +1805,7 @@ packages:
|
|||
graphql-ws: 5.14.3(graphql@16.8.1)
|
||||
isomorphic-ws: 5.0.0(ws@8.16.0)
|
||||
tslib: 2.6.2
|
||||
ws: 8.16.0
|
||||
ws: 8.16.0(utf-8-validate@6.0.3)
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
|
@ -1871,7 +1840,7 @@ packages:
|
|||
graphql: 16.8.1
|
||||
isomorphic-ws: 5.0.0(ws@8.16.0)
|
||||
tslib: 2.6.2
|
||||
ws: 8.16.0
|
||||
ws: 8.16.0(utf-8-validate@6.0.3)
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
|
@ -2123,7 +2092,7 @@ packages:
|
|||
isomorphic-ws: 5.0.0(ws@8.16.0)
|
||||
tslib: 2.6.2
|
||||
value-or-promise: 1.0.12
|
||||
ws: 8.16.0
|
||||
ws: 8.16.0(utf-8-validate@6.0.3)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- bufferutil
|
||||
|
@ -4308,6 +4277,36 @@ packages:
|
|||
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
|
||||
dev: true
|
||||
|
||||
/@urql/core@4.2.3(graphql@16.8.1):
|
||||
resolution: {integrity: sha512-DJ9q9+lcs5JL8DcU2J3NqsgeXYJva+1+Qt8HU94kzTPqVOIRRA7ouvy4ksUfPY+B5G2PQ+vLh+JJGyZCNXv0cg==}
|
||||
dependencies:
|
||||
'@0no-co/graphql.web': 1.0.4(graphql@16.8.1)
|
||||
wonka: 6.3.4
|
||||
transitivePeerDependencies:
|
||||
- graphql
|
||||
dev: true
|
||||
|
||||
/@urql/devtools@2.0.3(@urql/core@4.2.3)(graphql@16.8.1):
|
||||
resolution: {integrity: sha512-TktPLiBS9LcBPHD6qcnb8wqOVcg3Bx0iCtvQ80uPpfofwwBGJmqnQTjUdEFU6kwaLOFZULQ9+Uo4831G823mQw==}
|
||||
peerDependencies:
|
||||
'@urql/core': '>= 1.14.0'
|
||||
graphql: '>= 0.11.0'
|
||||
dependencies:
|
||||
'@urql/core': 4.2.3(graphql@16.8.1)
|
||||
graphql: 16.8.1
|
||||
wonka: 6.3.4
|
||||
dev: true
|
||||
|
||||
/@urql/exchange-graphcache@6.4.1(graphql@16.8.1):
|
||||
resolution: {integrity: sha512-hWa4/5B7Op93oA6yWvffPU3L0XH55tlluEaq6aoFE9zsiNhktFjhp/SU2CKvSD8iD0Tfreoo63drv64Ad0+Gxw==}
|
||||
dependencies:
|
||||
'@0no-co/graphql.web': 1.0.4(graphql@16.8.1)
|
||||
'@urql/core': 4.2.3(graphql@16.8.1)
|
||||
wonka: 6.3.4
|
||||
transitivePeerDependencies:
|
||||
- graphql
|
||||
dev: true
|
||||
|
||||
/@vavite/connect@4.0.2(vite@5.0.12):
|
||||
resolution: {integrity: sha512-wEEjsKXUvmOEzQ5jJm33AAKmX9tNwjuxmTA5CHwHzria4QcjRUxgONo0jjhvIY4S+e9/gkf6e24rREjAGfgcfA==}
|
||||
peerDependencies:
|
||||
|
@ -4453,41 +4452,6 @@ packages:
|
|||
tslib: 2.6.2
|
||||
dev: true
|
||||
|
||||
/@wry/caches@1.0.1:
|
||||
resolution: {integrity: sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
dev: true
|
||||
|
||||
/@wry/context@0.7.4:
|
||||
resolution: {integrity: sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
dev: true
|
||||
|
||||
/@wry/equality@0.5.7:
|
||||
resolution: {integrity: sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
dev: true
|
||||
|
||||
/@wry/trie@0.4.3:
|
||||
resolution: {integrity: sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
dev: true
|
||||
|
||||
/@wry/trie@0.5.0:
|
||||
resolution: {integrity: sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
dev: true
|
||||
|
||||
/abort-controller@3.0.0:
|
||||
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
|
||||
engines: {node: '>=6.5'}
|
||||
|
@ -7333,7 +7297,7 @@ packages:
|
|||
peerDependencies:
|
||||
ws: '*'
|
||||
dependencies:
|
||||
ws: 8.16.0
|
||||
ws: 8.16.0(utf-8-validate@6.0.3)
|
||||
dev: true
|
||||
|
||||
/istextorbinary@9.5.0:
|
||||
|
@ -8476,7 +8440,6 @@ packages:
|
|||
/node-gyp-build@4.8.0:
|
||||
resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==}
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/node-html-parser@6.1.12:
|
||||
resolution: {integrity: sha512-/bT/Ncmv+fbMGX96XG9g05vFt43m/+SYKIs9oAemQVYyVcZmDAI2Xq/SbNcpOA35eF0Zk2av3Ksf+Xk8Vt8abA==}
|
||||
|
@ -8661,15 +8624,6 @@ packages:
|
|||
mimic-fn: 4.0.0
|
||||
dev: true
|
||||
|
||||
/optimism@0.18.0:
|
||||
resolution: {integrity: sha512-tGn8+REwLRNFnb9WmcY5IfpOqeX2kpaYJ1s6Ae3mn12AeydLkR3j+jSCmVQFoXqU8D41PAJ1RG1rCRNWmNZVmQ==}
|
||||
dependencies:
|
||||
'@wry/caches': 1.0.1
|
||||
'@wry/context': 0.7.4
|
||||
'@wry/trie': 0.4.3
|
||||
tslib: 2.6.2
|
||||
dev: true
|
||||
|
||||
/optionator@0.9.3:
|
||||
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
@ -9613,11 +9567,6 @@ packages:
|
|||
supports-preserve-symlinks-flag: 1.0.0
|
||||
dev: true
|
||||
|
||||
/response-iterator@0.2.6:
|
||||
resolution: {integrity: sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw==}
|
||||
engines: {node: '>=0.8'}
|
||||
dev: true
|
||||
|
||||
/restore-cursor@3.1.0:
|
||||
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -10225,11 +10174,6 @@ packages:
|
|||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/symbol-observable@4.0.0:
|
||||
resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==}
|
||||
engines: {node: '>=0.10'}
|
||||
dev: true
|
||||
|
||||
/syncpack@12.3.0(typescript@5.3.3):
|
||||
resolution: {integrity: sha512-Gz2uGn96OmGfVVlKztvFac1EJYjP+WptQ2ohA6Uf48C6qLkhSayhkdujKQ6q7bGOTy8HSGI0iDfwfCJu6wvRig==}
|
||||
engines: {node: '>=16'}
|
||||
|
@ -10456,13 +10400,6 @@ packages:
|
|||
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
|
||||
dev: true
|
||||
|
||||
/ts-invariant@0.10.3:
|
||||
resolution: {integrity: sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
dev: true
|
||||
|
||||
/ts-log@2.2.5:
|
||||
resolution: {integrity: sha512-PGcnJoTBnVGy6yYNFxWVNkdcAuAMstvutN9MgDJIV6L0oG8fB+ZNNy1T+wJzah8RPGor1mZuPQkVfXNDpy9eHA==}
|
||||
dev: true
|
||||
|
@ -10916,6 +10853,15 @@ packages:
|
|||
resolution: {integrity: sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==}
|
||||
dev: true
|
||||
|
||||
/urql@4.0.6(graphql@16.8.1):
|
||||
resolution: {integrity: sha512-meXJ2puOd64uCGKh7Fse2R7gPa8+ZpBOoA62jN7CPXXUt7SVZSdeXWSpB3HvlfzLUkEqsWbvshwrgeWRYNNGaQ==}
|
||||
dependencies:
|
||||
'@urql/core': 4.2.3(graphql@16.8.1)
|
||||
wonka: 6.3.4
|
||||
transitivePeerDependencies:
|
||||
- graphql
|
||||
dev: true
|
||||
|
||||
/use-callback-ref@1.3.1(@types/react@18.2.48):
|
||||
resolution: {integrity: sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
@ -10953,7 +10899,6 @@ packages:
|
|||
requiresBuild: true
|
||||
dependencies:
|
||||
node-gyp-build: 4.8.0
|
||||
dev: false
|
||||
|
||||
/util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
|
@ -11291,6 +11236,10 @@ packages:
|
|||
stackback: 0.0.2
|
||||
dev: true
|
||||
|
||||
/wonka@6.3.4:
|
||||
resolution: {integrity: sha512-CjpbqNtBGNAeyNS/9W6q3kSkKE52+FjIj7AkFlLr11s/VWGUu6a2CdYSdGxocIhIVjaW/zchesBQUKPVU69Cqg==}
|
||||
dev: true
|
||||
|
||||
/wordwrap@1.0.0:
|
||||
resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
|
||||
dev: true
|
||||
|
@ -11355,19 +11304,6 @@ packages:
|
|||
utf-8-validate: 6.0.3
|
||||
dev: false
|
||||
|
||||
/ws@8.16.0:
|
||||
resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
utf-8-validate: '>=5.0.2'
|
||||
peerDependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
dev: true
|
||||
|
||||
/ws@8.16.0(utf-8-validate@6.0.3):
|
||||
resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
@ -11381,7 +11317,6 @@ packages:
|
|||
optional: true
|
||||
dependencies:
|
||||
utf-8-validate: 6.0.3
|
||||
dev: false
|
||||
|
||||
/xtend@4.0.2:
|
||||
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
|
||||
|
@ -11478,16 +11413,6 @@ packages:
|
|||
type-fest: 2.19.0
|
||||
dev: true
|
||||
|
||||
/zen-observable-ts@1.2.5:
|
||||
resolution: {integrity: sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==}
|
||||
dependencies:
|
||||
zen-observable: 0.8.15
|
||||
dev: true
|
||||
|
||||
/zen-observable@0.8.15:
|
||||
resolution: {integrity: sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==}
|
||||
dev: true
|
||||
|
||||
/zod-validation-error@2.1.0(zod@3.22.4):
|
||||
resolution: {integrity: sha512-VJh93e2wb4c3tWtGgTa0OF/dTt/zoPCPzXq4V11ZjxmEAFaPi/Zss1xIZdEB5RD8GD00U0/iVXgqkF77RV7pdQ==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
|
Loading…
Reference in New Issue