diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index ce7b73ee9e..0000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,14 +0,0 @@ -// https://eslint.org/docs/latest/user-guide/configuring -// "off" or 0 - turn the rule off -// "warn" or 1 - turn the rule on as a warning (doesn’t affect exit code) -// "error" or 2 - turn the rule on as an error (exit code will be 1) - -/** @type { import('eslint').Linter.Config } */ -module.exports = { - extends: ['plugin:prettier/recommended'], - rules: { - 'prettier/prettier': 'warn', - }, - - reportUnusedDisableDirectives: true, -}; diff --git a/.vscode/settings.json b/.vscode/settings.json index df31aeb4b6..bd7c665059 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,5 @@ "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true, "editor.formatOnSaveMode": "file", - "cSpell.words": ["testid"] + "cSpell.words": ["blocksuite", "testid"] } diff --git a/package.json b/package.json index bfe30f73ae..e29a1a6c64 100644 --- a/package.json +++ b/package.json @@ -10,14 +10,17 @@ "lint": "pnpm --filter @pathfinder/app lint", "test": "playwright test", "test:e2e": "playwright test", - "test:e2e:codegen":"npx playwright codegen http://localhost:8080", + "test:e2e:codegen": "npx playwright codegen http://localhost:8080", "test:unit": "jest" }, "devDependencies": { "@jest/globals": "^29.3.1", "@playwright/test": "^1.28.1", - "@types/node": "18.7.18", - "eslint": "8.22.0", + "@typescript-eslint/eslint-plugin": "^5.47.0", + "@typescript-eslint/parser": "^5.47.0", + "@types/eslint": "^8.4.10", + "@types/node": "^18.11.17", + "eslint": "^8.30.0", "eslint-config-next": "12.3.1", "eslint-config-prettier": "^8.5.0", "eslint-plugin-prettier": "^4.2.1", @@ -25,5 +28,30 @@ "prettier": "^2.7.1", "ts-jest": "^29.0.3", "typescript": "^4.9.3" + }, + "eslintConfig": { + "root": true, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": [ + "./tsconfig.json" + ] + }, + "plugins": [ + "@typescript-eslint" + ], + "rules": { + "prettier/prettier": "warn" + }, + "reportUnusedDisableDirectives": true, + "ignorePatterns": [ + "src/**/*.test.ts", + "package/**/dist/*" + ] } } diff --git a/packages/app/.eslintrc.js b/packages/app/.eslintrc.js deleted file mode 100644 index 6dca46e2e5..0000000000 --- a/packages/app/.eslintrc.js +++ /dev/null @@ -1,19 +0,0 @@ -// https://eslint.org/docs/latest/user-guide/configuring -// "off" or 0 - turn the rule off -// "warn" or 1 - turn the rule on as a warning (doesn’t affect exit code) -// "error" or 2 - turn the rule on as an error (exit code will be 1) - -/** @type { import('eslint').Linter.Config } */ -module.exports = { - extends: [ - 'next/core-web-vitals', - 'plugin:@next/next/recommended', - 'plugin:prettier/recommended', - // 'next/babel', - ], - rules: { - 'prettier/prettier': 'warn', - }, - - reportUnusedDisableDirectives: true, -}; diff --git a/packages/app/package.json b/packages/app/package.json index 38787f670a..600ce5c384 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -48,5 +48,15 @@ "eslint-config-prettier": "^8.5.0", "eslint-plugin-prettier": "^4.2.1", "typescript": "4.8.3" + }, + "eslintConfig": { + "extends": [ + "next/core-web-vitals", + "plugin:@next/next/recommended" + ], + "rules": { + "prettier/prettier": "warn" + }, + "reportUnusedDisableDirectives": true } } diff --git a/packages/app/src/components/login-modal/LoginOptionButton.tsx b/packages/app/src/components/login-modal/LoginOptionButton.tsx index 8070e51254..b10432214a 100644 --- a/packages/app/src/components/login-modal/LoginOptionButton.tsx +++ b/packages/app/src/components/login-modal/LoginOptionButton.tsx @@ -1,4 +1,4 @@ -import { signInWithGoogle, login, setToken } from '@pathfinder/data-services'; +import { signInWithGoogle } from '@pathfinder/data-services'; import { styled } from '@/styles'; import { Button } from '@/ui/button'; import { useModal } from '@/providers/global-modal-provider'; @@ -10,13 +10,7 @@ export const GoogleLoginButton = () => { { signInWithGoogle() - .then(async user => { - const idToken = await user.user.getIdToken(); - const token = await login({ token: idToken, type: 'Google' }); - setToken({ - accessToken: token.token, - refreshToken: token.refresh, - }); + .then(async => { triggerLoginModal(); }) .catch(error => { diff --git a/packages/app/src/components/workspace-setting/general/general.tsx b/packages/app/src/components/workspace-setting/general/general.tsx new file mode 100644 index 0000000000..917928c88f --- /dev/null +++ b/packages/app/src/components/workspace-setting/general/general.tsx @@ -0,0 +1,79 @@ +import Modal, { ModalCloseButton } from '@/ui/modal'; +import { + StyledDeleteButtonContainer, + StyledSettingAvatar, + StyledSettingAvatarContent, + StyledSettingInputContainer, +} from './style'; + +import { useState } from 'react'; +import { Button } from '@/ui/button'; +import Input from '@/ui/input'; +import { Workspace, WorkspaceType } from '@pathfinder/data-services'; +import { useAppState } from '@/providers/app-state-provider'; +import { WorkspaceDetails } from '@/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent'; +import { StyledSettingH2 } from '../style'; +export const GeneralPage = ({ + workspace, + owner, +}: { + workspace: Workspace; + owner: WorkspaceDetails[string]['owner']; +}) => { + const { workspaces, user, currentWorkspace } = useAppState(); + const [workspaceName, setWorkspaceName] = useState( + workspaces[workspace.id]?.meta.name || + (workspace.type === WorkspaceType.Private && user + ? user.name + : `workspace-${workspace?.id}`) + ); + const isOwner = user && owner.id === user.id; + const handleChangeWorkSpaceName = (newName: string) => { + setWorkspaceName(newName); + currentWorkspace?.meta.setName(newName); + workspaces[workspace.id]?.meta.setName(newName); + }; + return workspace ? ( +
+ Workspace Avatar + + + W + + {/* {isOwner ? ( + upload + ) : null} */} + {/* */} + + Workspace Name + + + + Workspace Owner + + + + + + +
+ ) : null; +}; diff --git a/packages/app/src/components/workspace-setting/general/index.ts b/packages/app/src/components/workspace-setting/general/index.ts new file mode 100644 index 0000000000..12bc2fe54d --- /dev/null +++ b/packages/app/src/components/workspace-setting/general/index.ts @@ -0,0 +1 @@ +export * from './general'; diff --git a/packages/app/src/components/workspace-setting/general/style.ts b/packages/app/src/components/workspace-setting/general/style.ts new file mode 100644 index 0000000000..bd34ccdb59 --- /dev/null +++ b/packages/app/src/components/workspace-setting/general/style.ts @@ -0,0 +1,28 @@ +import { styled } from '@/styles'; +import MuiAvatar from '@mui/material/Avatar'; + +export const StyledSettingInputContainer = styled('div')(({ theme }) => { + return { + marginTop: '12px', + }; +}); + +export const StyledDeleteButtonContainer = styled('div')(({ theme }) => { + return { + marginTop: '154px', + }; +}); + +export const StyledSettingAvatarContent = styled('div')(({ theme }) => { + return { + marginTop: '12px', + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + height: '72px', + }; +}); + +export const StyledSettingAvatar = styled(MuiAvatar)(({ theme }) => { + return { height: '72px', width: '72px' }; +}); diff --git a/packages/app/src/components/workspace-setting/style.ts b/packages/app/src/components/workspace-setting/style.ts index c24c41b12a..01ae218272 100644 --- a/packages/app/src/components/workspace-setting/style.ts +++ b/packages/app/src/components/workspace-setting/style.ts @@ -29,6 +29,7 @@ export const StyledSettingSidebar = styled('div')(({ theme }) => { export const StyledSettingContent = styled('div')(({ theme }) => { return { paddingLeft: '48px', + height: '620px', }; }); @@ -103,20 +104,6 @@ export const StyledSettingH2 = styled('h2')<{ marginTop?: number }>( } ); -export const StyledSettingAvatarContent = styled('div')(({ theme }) => { - return { - marginTop: '12px', - display: 'flex', - flexDirection: 'row', - alignItems: 'center', - height: '72px', - }; -}); - -export const StyledSettingAvatar = styled(MuiAvatar)(({ theme }) => { - return { height: '72px', width: '72px' }; -}); - export const StyledAvatarUploadBtn = styled(Button)(({ theme }) => { return { backgroundColor: theme.colors.hoverBackground, @@ -125,18 +112,6 @@ export const StyledAvatarUploadBtn = styled(Button)(({ theme }) => { }; }); -export const StyledSettingInputContainer = styled('div')(({ theme }) => { - return { - marginTop: '12px', - }; -}); - -export const StyledDeleteButtonContainer = styled('div')(({ theme }) => { - return { - marginTop: '154px', - }; -}); - export const StyledMemberTitleContainer = styled('div')(({ theme }) => { return { display: 'flex', diff --git a/packages/app/src/components/workspace-setting/workspace-setting.tsx b/packages/app/src/components/workspace-setting/workspace-setting.tsx index 61fcd35ef4..db515a65d0 100644 --- a/packages/app/src/components/workspace-setting/workspace-setting.tsx +++ b/packages/app/src/components/workspace-setting/workspace-setting.tsx @@ -2,7 +2,6 @@ import Modal, { ModalCloseButton } from '@/ui/modal'; import { StyledAvatarUploadBtn, StyledCopyButtonContainer, - StyledDeleteButtonContainer, StyledMemberAvatar, StyledMemberButtonContainer, StyledMemberEmail, @@ -17,12 +16,9 @@ import { StyledPublishContent, StyledPublishCopyContainer, StyledPublishExplanation, - StyledSettingAvatar, - StyledSettingAvatarContent, StyledSettingContainer, StyledSettingContent, StyledSettingH2, - StyledSettingInputContainer, StyledSettingSidebar, StyledSettingSidebarHeader, StyledSettingTabContainer, @@ -52,6 +48,10 @@ import { Avatar } from '@mui/material'; import { Menu, MenuItem } from '@/ui/menu'; import { toast } from '@/ui/toast'; import { useConfirm } from '@/providers/confirm-provider'; +import { useAppState } from '@/providers/app-state-provider'; +import { WorkspaceDetails } from '../workspace-slider-bar/WorkspaceSelector/SelectorPopperContent'; +import { GeneralPage } from './general'; + enum ActiveTab { 'general' = 'general', 'members' = 'members', @@ -66,7 +66,8 @@ type SettingTabProps = { type WorkspaceSettingProps = { isShow: boolean; onClose?: () => void; - workspace?: Workspace; + workspace: Workspace; + owner: WorkspaceDetails[string]['owner']; }; const WorkspaceSettingTab = ({ activeTab, onTabChange }: SettingTabProps) => { @@ -113,7 +114,9 @@ export const WorkspaceSetting = ({ isShow, onClose, workspace, + owner, }: WorkspaceSettingProps) => { + const { workspaces, user } = useAppState(); const [activeTab, setActiveTab] = useState(ActiveTab.general); const handleTabChange = (tab: ActiveTab) => { setActiveTab(tab); @@ -121,7 +124,7 @@ export const WorkspaceSetting = ({ const handleClickClose = () => { onClose && onClose(); }; - const isPrivate = workspace?.type === WorkspaceType.Private; + const isOwner = user && owner.id === user.id; useEffect(() => { // reset tab when modal is closed if (!isShow) { @@ -132,18 +135,20 @@ export const WorkspaceSetting = ({ - - - Workspace Settings - - - + {isOwner ? ( + + + Workspace Settings + + + + ) : null} {activeTab === ActiveTab.general && ( - + )} {activeTab === ActiveTab.members && workspace && ( @@ -155,32 +160,6 @@ export const WorkspaceSetting = ({ ); }; -const GeneralPage = ({ workspace }: { workspace?: Workspace }) => { - return ( -
- Workspace Avatar - - W - {/* upload - */} - - Workspace Name - - - - Workspace Owner - - - - - - -
- ); -}; - const MembersPage = ({ workspace }: { workspace: Workspace }) => { const [isInviteModalShow, setIsInviteModalShow] = useState(false); const [members, setMembers] = useState([]); diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx index 656ecb6cfa..2e752c99ab 100644 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx +++ b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/SelectorPopperContent.tsx @@ -14,7 +14,7 @@ import { WorkspaceSetting } from '@/components/workspace-setting'; import { useCallback, useEffect, useState } from 'react'; import { getWorkspaceDetail, WorkspaceType } from '@pathfinder/data-services'; -type WorkspaceDetails = Record< +export type WorkspaceDetails = Record< string, { memberCount: number; owner: { id: string; name: string } } >; @@ -39,6 +39,9 @@ export const SelectorPopperContent = ({ const handleCloseWorkSpace = () => { setSettingWorkspaceId(null); }; + const settingWorkspace = settingWorkspaceId + ? workspacesMeta.find(workspace => workspace.id === settingWorkspaceId) + : undefined; const refreshDetails = useCallback(async () => { const workspaceDetailList = await Promise.all( @@ -103,7 +106,9 @@ export const SelectorPopperContent = ({ onClick={handleClickSettingWorkspace} name={ workspaces[workspace.id]?.meta.name || - `workspace-${workspace.id}` + (workspace.type === WorkspaceType.Private + ? user.name + : `workspace-${workspace.id}`) } memberCount={workSpaceDetails[workspace.id]?.memberCount || 1} /> @@ -111,17 +116,20 @@ export const SelectorPopperContent = ({ })} - workspace.id === settingWorkspaceId - ) - : undefined - } - /> + {settingWorkspace ? ( + + ) : null} } diff --git a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/WorkspaceItem.tsx b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/WorkspaceItem.tsx index debe408651..965649ba46 100644 --- a/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/WorkspaceItem.tsx +++ b/packages/app/src/components/workspace-slider-bar/WorkspaceSelector/WorkspaceItem/WorkspaceItem/WorkspaceItem.tsx @@ -8,6 +8,7 @@ import { import { FooterSetting } from './FooterSetting'; import { FooterUsers } from './FooterUsers'; import { WorkspaceType } from '@pathfinder/data-services'; +import { useAppState } from '@/providers/app-state-provider'; interface WorkspaceItemProps { id: string; @@ -28,6 +29,8 @@ export const WorkspaceItem = ({ }: WorkspaceItemProps) => { const router = useRouter(); + const { currentWorkspaceId } = useAppState(); + const handleClickSetting = async () => { onClick && onClick(id); }; @@ -37,7 +40,9 @@ export const WorkspaceItem = ({ onClick={() => { router.push(`/workspace/${id}`); }} - isPrivate={type === WorkspaceType.Private} + canSet={ + type !== WorkspaceType.Private && currentWorkspaceId === String(id) + } > {name.charAt(0)} @@ -64,17 +69,17 @@ const Name = styled('div')(({ theme }) => { }; }); -const StyledWrapper = styled(WorkspaceItemWrapper)<{ isPrivate: boolean }>( - ({ isPrivate }) => { +const StyledWrapper = styled(WorkspaceItemWrapper)<{ canSet: boolean }>( + ({ canSet }) => { return { '& .footer-setting': { display: 'none', }, ':hover .footer-users': { - display: isPrivate ? 'block' : 'none', + display: canSet ? 'none' : '', }, ':hover .footer-setting': { - display: isPrivate ? 'none' : 'block', + display: canSet ? 'block' : 'none', }, }; } diff --git a/packages/app/src/providers/app-state-provider/dynamic-blocksuite.tsx b/packages/app/src/providers/app-state-provider/dynamic-blocksuite.tsx index 04611c2d70..2f22e01a07 100644 --- a/packages/app/src/providers/app-state-provider/dynamic-blocksuite.tsx +++ b/packages/app/src/providers/app-state-provider/dynamic-blocksuite.tsx @@ -89,10 +89,10 @@ const DynamicBlocksuite = ({ p => p instanceof IndexedDBDocProvider ); if (indexDBProvider) { - (indexDBProvider as IndexedDBDocProvider)?.on('synced', async () => { + (indexDBProvider as IndexedDBDocProvider).on('synced', async () => { const updates = await downloadWorkspace({ workspaceId }); - if (updates.byteLength) { + if (updates && updates.byteLength) { Workspace.Y.applyUpdate(workspace.doc, new Uint8Array(updates)); // if after update, the space:meta is empty, then we need to get map with doc workspace.doc.getMap('space:meta'); diff --git a/packages/app/src/providers/app-state-provider/hooks.ts b/packages/app/src/providers/app-state-provider/hooks.ts index 6abce3eaf1..69129c87e7 100644 --- a/packages/app/src/providers/app-state-provider/hooks.ts +++ b/packages/app/src/providers/app-state-provider/hooks.ts @@ -28,21 +28,23 @@ export const useLoadPage = () => { return; } const page = pageId ? workspace?.getPage(pageId) : null; - if (!page) { - const savedPageId = workspace.meta.pageMetas[0]?.id; - if (savedPageId) { - router.push(`/workspace/${currentWorkspaceId}/${savedPageId}`); + if (page) { + loadPage?.current?.(pageId); + return; + } + + const savedPageId = workspace.meta.pageMetas[0]?.id; + if (savedPageId) { + router.push(`/workspace/${currentWorkspaceId}/${savedPageId}`); + return; + } + + createPage?.current?.()?.then(async pageId => { + if (!pageId) { return; } - - createPage?.current?.()?.then(async pageId => { - if (!pageId) { - return; - } - router.push(`/workspace/${currentWorkspaceId}/${pageId}`); - }); - } - loadPage?.current?.(pageId); + router.push(`/workspace/${currentWorkspaceId}/${pageId}`); + }); }, [workspace, pageId, loadPage, createPage, router, currentWorkspaceId]); return currentPage?.pageId === pageId ? currentPage : null; diff --git a/packages/app/src/providers/app-state-provider/provider.tsx b/packages/app/src/providers/app-state-provider/provider.tsx index a22d23476e..2e38922e06 100644 --- a/packages/app/src/providers/app-state-provider/provider.tsx +++ b/packages/app/src/providers/app-state-provider/provider.tsx @@ -78,7 +78,7 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => { if (pageId === currentPage?.pageId) { return currentPage; } - const page = currentWorkspace?.getPage(pageId) || null; + const page = (pageId ? currentWorkspace?.getPage(pageId) : null) || null; setState(state => ({ ...state, currentPage: page })); return page; }; @@ -94,7 +94,7 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => { const editor = createEditorHandler?.(currentPage) || null; if (editor) { - const pageMeta = currentWorkspace?.meta.pageMetas.find( + const pageMeta = currentWorkspace.meta.pageMetas.find( p => p.id === currentPage.pageId ); if (pageMeta?.mode) { @@ -133,13 +133,13 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => { const callback = async (user: AccessTokenMessage | null) => { const workspacesMeta = user ? await getWorkspaces() : []; const workspacesList = await Promise.all( - workspacesMeta?.map(async ({ id }) => { + workspacesMeta.map(async ({ id }) => { const workspace = (await loadWorkspaceHandler?.(id)) || null; return { id, workspace }; }) ); - let workspaces: Record = {}; + const workspaces: Record = {}; workspacesList.forEach(({ id, workspace }) => { workspaces[id] = workspace; diff --git a/packages/app/src/ui/button/styles.ts b/packages/app/src/ui/button/styles.ts index 106826804b..7cd236b50d 100644 --- a/packages/app/src/ui/button/styles.ts +++ b/packages/app/src/ui/button/styles.ts @@ -87,6 +87,7 @@ export const StyledTextButton = styled('button', { 'hoverBackground', 'hoverColor', 'hoverStyle', + 'bold', ].includes(prop); }, })< @@ -141,9 +142,13 @@ export const StyledTextButton = styled('button', { export const StyledButton = styled('button', { shouldForwardProp: prop => { - return !['hoverBackground', 'hoverColor', 'hoverStyle', 'type'].includes( - prop - ); + return ![ + 'hoverBackground', + 'hoverColor', + 'hoverStyle', + 'type', + 'bold', + ].includes(prop); }, })< Pick< diff --git a/packages/app/src/ui/input/input.tsx b/packages/app/src/ui/input/input.tsx index d4ddb5c0c6..bb64b18414 100644 --- a/packages/app/src/ui/input/input.tsx +++ b/packages/app/src/ui/input/input.tsx @@ -7,6 +7,7 @@ type inputProps = { disabled?: boolean; width?: number; maxLength?: number; + minLength?: number; onChange?: (value: string) => void; onBlur?: (e: any) => void; }; @@ -17,6 +18,7 @@ export const Input = (props: inputProps) => { value: valueProp, placeholder, maxLength, + minLength, width = 260, onChange, onBlur, @@ -39,6 +41,7 @@ export const Input = (props: inputProps) => { placeholder={placeholder} width={width} maxLength={maxLength} + minLength={minLength} onChange={handleChange} onBlur={handleBlur} > diff --git a/packages/data-services/package.json b/packages/data-services/package.json index 6dc645fdd4..2af370726e 100644 --- a/packages/data-services/package.json +++ b/packages/data-services/package.json @@ -25,6 +25,7 @@ "axios": "^1.2.0", "encoding": "^0.1.13", "firebase": "^9.13.0", + "ky": "^0.33.0", "swr": "^2.0.0" } } diff --git a/packages/data-services/src/auth.ts b/packages/data-services/src/auth.ts index 9896fc7757..c8d9e0a301 100644 --- a/packages/data-services/src/auth.ts +++ b/packages/data-services/src/auth.ts @@ -7,6 +7,8 @@ import { signInWithPopup, } from 'firebase/auth'; import type { User } from 'firebase/auth'; +import { login } from './sdks'; +import { setToken } from './request'; /** * firebaseConfig reference: https://firebase.google.com/docs/web/setup#add_firebase_to_your_app @@ -32,8 +34,14 @@ const signIn = (email: string, password: string) => { }; const googleAuthProvider = new GoogleAuthProvider(); -export const signInWithGoogle = () => { - return signInWithPopup(firebaseAuth, googleAuthProvider); +export const signInWithGoogle = async () => { + const user = await signInWithPopup(firebaseAuth, googleAuthProvider); + const idToken = await user.user.getIdToken(); + const token = await login({ token: idToken, type: 'Google' }); + setToken({ + accessToken: token.token, + refreshToken: token.refresh, + }); }; export const onAuthStateChanged = (callback: (user: User | null) => void) => { diff --git a/packages/data-services/src/request/ServiceError.ts b/packages/data-services/src/request/ServiceError.ts deleted file mode 100644 index 07ba217007..0000000000 --- a/packages/data-services/src/request/ServiceError.ts +++ /dev/null @@ -1,9 +0,0 @@ -export class ServiceError extends Error { - public message: string; - public code: string; - constructor(code: string, message: string) { - super(message); - this.message = message; - this.code = code; - } -} diff --git a/packages/data-services/src/request/axios.ts b/packages/data-services/src/request/axios.ts deleted file mode 100644 index 1b4bb6d73b..0000000000 --- a/packages/data-services/src/request/axios.ts +++ /dev/null @@ -1,23 +0,0 @@ -import axios from 'axios'; -import { setAuthorization } from './request'; -import { handleResponseError, handleResponse } from './response'; - -declare module 'axios' { - interface AxiosRequestConfig { - /** - * If true, request will send with Authorization header. - */ - withAuthorization?: boolean; - /** - * If true, indicate this request is refreshing token. - */ - refreshTokenRequest?: boolean; - } -} - -export const request = axios.create({ - withAuthorization: true, -}); - -request.interceptors.request.use(setAuthorization); -request.interceptors.response.use(handleResponse, handleResponseError); diff --git a/packages/data-services/src/request/request/authorization/events.ts b/packages/data-services/src/request/events.ts similarity index 92% rename from packages/data-services/src/request/request/authorization/events.ts rename to packages/data-services/src/request/events.ts index e8d65b8259..d4444bcb63 100644 --- a/packages/data-services/src/request/request/authorization/events.ts +++ b/packages/data-services/src/request/events.ts @@ -1,4 +1,4 @@ -import type { AccessTokenMessage } from './types'; +import { AccessTokenMessage } from './token'; type Callback = (user: AccessTokenMessage | null) => void; diff --git a/packages/data-services/src/request/index.ts b/packages/data-services/src/request/index.ts index ad1a78ad8f..bbd2f2e73d 100644 --- a/packages/data-services/src/request/index.ts +++ b/packages/data-services/src/request/index.ts @@ -1,4 +1,50 @@ -export { request } from './axios'; -export { ServiceError } from './ServiceError'; -export { setToken, getToken, authorizationEvent } from './request'; -export type { AccessTokenMessage } from './request'; +import ky from 'ky'; +import { + getToken, + setToken, + isAccessTokenExpired, + refreshToken, + authorizationEvent, +} from './token'; + +export const request = ky.extend({ + retry: 1, + hooks: { + beforeRequest: [ + async request => { + if (!request.headers.has('token') || request.headers.get('token')) { + const token = getToken(); + if (token) { + if (isAccessTokenExpired(token.accessToken)) { + await refreshToken(); + } + + request.headers.set('Authorization', token.accessToken); + } + } + }, + ], + // afterResponse: [ + // async (_request, _options, response) => { + // if (response.status === 200) { + // const data = await response.json(); + // if (data.error) { + // return new Response(data.error.message, { + // status: data.error.code, + // }); + // } + // } + // return response; + // }, + // ], + beforeRetry: [ + async ({ request }) => { + const token = await refreshToken(); + request.headers.set('Authorization', token.accessToken); + }, + ], + }, +}); + +export type { AccessTokenMessage } from './token'; +export { authorizationEvent, getToken, setToken }; diff --git a/packages/data-services/src/request/request/authorization/index.ts b/packages/data-services/src/request/request/authorization/index.ts deleted file mode 100644 index fbac5e9287..0000000000 --- a/packages/data-services/src/request/request/authorization/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './authorization'; -export type { AccessTokenMessage } from './types'; diff --git a/packages/data-services/src/request/request/authorization/types.ts b/packages/data-services/src/request/request/authorization/types.ts deleted file mode 100644 index fa7069395b..0000000000 --- a/packages/data-services/src/request/request/authorization/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface AccessTokenMessage { - create_at: number; - exp: number; - email: string; - id: string; - name: string; - avatar_url: string; -} diff --git a/packages/data-services/src/request/request/index.ts b/packages/data-services/src/request/request/index.ts deleted file mode 100644 index a31c82791d..0000000000 --- a/packages/data-services/src/request/request/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { - setAuthorization, - setToken, - getToken, - authorizationEvent, -} from './authorization'; -export type { AccessTokenMessage } from './authorization'; diff --git a/packages/data-services/src/request/response/handle-error.ts b/packages/data-services/src/request/response/handle-error.ts deleted file mode 100644 index 7d8fe807e4..0000000000 --- a/packages/data-services/src/request/response/handle-error.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { AxiosResponse, AxiosError } from 'axios'; -import { ServiceError } from '../ServiceError'; -import { refreshToken } from '../request/authorization'; -import { request } from '../axios'; - -export async function handleResponseError(error: AxiosError) { - const { response, config, message } = error; - const status = response?.status; - - if (status === 401) { - if (!config) { - throw new ServiceError(message, status.toString()); - } - if (config.refreshTokenRequest) { - throw new ServiceError(message, status.toString()); - } - await refreshToken(); - return request({ ...config, refreshTokenRequest: true }); - } - return error; -} - -export async function handleResponse(response: AxiosResponse) { - const { status, data } = response; - if (status === 200) { - if (data.error) { - // TODO - common error handling - const error = new ServiceError(data.error.message, data.error.code); - throw error; - } - return response; - } - return response; -} diff --git a/packages/data-services/src/request/response/index.ts b/packages/data-services/src/request/response/index.ts deleted file mode 100644 index 94547c0213..0000000000 --- a/packages/data-services/src/request/response/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { handleResponseError, handleResponse } from './handle-error'; diff --git a/packages/data-services/src/request/request/authorization/authorization.ts b/packages/data-services/src/request/token.ts similarity index 70% rename from packages/data-services/src/request/request/authorization/authorization.ts rename to packages/data-services/src/request/token.ts index 04d135f224..057bae13f0 100644 --- a/packages/data-services/src/request/request/authorization/authorization.ts +++ b/packages/data-services/src/request/token.ts @@ -1,44 +1,17 @@ -import type { AxiosRequestConfig } from 'axios'; -import { login } from '../../../sdks'; import { AuthorizationEvent } from './events'; -import type { AccessTokenMessage } from './types'; +import { login } from '../sdks'; + +export interface AccessTokenMessage { + create_at: number; + exp: number; + email: string; + id: string; + name: string; + avatar_url: string; +} const TOKEN_KEY = 'affine_token'; -export const authorizationEvent = new AuthorizationEvent(); -authorizationEvent.triggerChange( - parseAccessToken(getToken()?.accessToken || '') -); - -interface Token { - accessToken: string; - refreshToken: string; -} - -/** - * set null to clear token - */ -export function setToken(token: Token | null): void { - if (token === null) { - window.localStorage.removeItem(TOKEN_KEY); - authorizationEvent.triggerChange(null); - return; - } - window.localStorage.setItem(TOKEN_KEY, JSON.stringify(token)); - authorizationEvent.triggerChange(parseAccessToken(token.accessToken)); -} - -export function getToken(): { - accessToken: string; - refreshToken: string; -} | null { - try { - return JSON.parse(window.localStorage.getItem(TOKEN_KEY) || ''); - } catch (error) { - return null; - } -} - function b64DecodeUnicode(str: string) { // Going backwards: from byte stream, to percent-encoding, to original string. return decodeURIComponent( @@ -64,7 +37,7 @@ function parseAccessToken(token: string): AccessTokenMessage | null { } } -function isAccessTokenExpired(token: string) { +export function isAccessTokenExpired(token: string) { const message = parseAccessToken(token); if (!message) { return true; @@ -72,37 +45,39 @@ function isAccessTokenExpired(token: string) { return Date.now() - message.create_at > message.exp; } -async function isLoggedIn(): Promise { - const token = getToken(); - if (!token) { - return false; +export function getToken(): { + accessToken: string; + refreshToken: string; +} | null { + try { + return JSON.parse(window.localStorage.getItem(TOKEN_KEY) || ''); + } catch (error) { + return null; } - return isAccessTokenExpired(token.accessToken); +} + +export const authorizationEvent = new AuthorizationEvent(); +authorizationEvent.triggerChange( + parseAccessToken(getToken()?.accessToken || '') +); + +interface Token { + accessToken: string; + refreshToken: string; +} + +export function setToken(token: Token | null): void { + if (token === null) { + window.localStorage.removeItem(TOKEN_KEY); + authorizationEvent.triggerChange(null); + return; + } + window.localStorage.setItem(TOKEN_KEY, JSON.stringify(token)); + authorizationEvent.triggerChange(parseAccessToken(token.accessToken)); } let refreshingToken: ReturnType | undefined; -export async function setAuthorization(config: AxiosRequestConfig) { - if (!config.headers) { - config.headers = {}; - } - - if (config.withAuthorization) { - let token = getToken(); - if (!token) { - throw new Error('No authorization token.'); - } - if (isAccessTokenExpired(token.accessToken)) { - await refreshToken(); - } - if (!config.headers) { - config.headers = {}; - } - config.headers['Authorization'] = token.accessToken; - } - return config; -} - export const refreshToken = async () => { let token = getToken(); if (!token) { @@ -121,4 +96,5 @@ export const refreshToken = async () => { }; setToken(token); refreshingToken = undefined; + return token; }; diff --git a/packages/data-services/src/sdks/user.ts b/packages/data-services/src/sdks/user.ts index 8f3c699c3a..1b319e0385 100644 --- a/packages/data-services/src/sdks/user.ts +++ b/packages/data-services/src/sdks/user.ts @@ -27,13 +27,9 @@ export interface LoginResponse { } export async function login(params: LoginParams): Promise { - const data = await request({ - url: '/api/user/token', - method: 'POST', - data: params, - withAuthorization: false, - }); - return data.data; + return request + .post('/api/user/token', { json: params, headers: { token: undefined } }) + .json(); } export interface GetUserByEmailParams { @@ -52,10 +48,5 @@ export interface User { export async function getUserByEmail( params: GetUserByEmailParams ): Promise { - const data = await request({ - url: '/api/user', - method: 'GET', - params, - }); - return data.data; + return request.get('/api/user', { json: params }).json(); } diff --git a/packages/data-services/src/sdks/workspace.ts b/packages/data-services/src/sdks/workspace.ts index 23e843ea26..421f278fe7 100644 --- a/packages/data-services/src/sdks/workspace.ts +++ b/packages/data-services/src/sdks/workspace.ts @@ -26,12 +26,7 @@ export interface Workspace { } export async function getWorkspaces(): Promise { - const data = await request({ - url: '/api/workspace', - method: 'GET', - }); - - return data.data; + return request.get('/api/workspace').json(); } export interface WorkspaceDetail extends Workspace { @@ -42,14 +37,7 @@ export interface WorkspaceDetail extends Workspace { export async function getWorkspaceDetail( params: GetWorkspaceDetailParams ): Promise { - const data = await request({ - url: `/api/workspace/${params.id}`, - method: 'GET', - }); - if (data.data?.owner.id) { - data.data.owner.id = String(data.data?.owner.id); - } - return data.data; + return request.get(`/api/workspace/${params.id}`).json(); } export interface Permission { @@ -80,12 +68,7 @@ export interface GetWorkspaceMembersParams { export async function getWorkspaceMembers( params: GetWorkspaceDetailParams ): Promise { - const data = await request({ - url: `/api/workspace/${params.id}/permission`, - method: 'GET', - }); - - return data.data; + return request.get(`/api/workspace/${params.id}/permission`).json(); } export interface CreateWorkspaceParams { @@ -96,13 +79,7 @@ export interface CreateWorkspaceParams { export async function createWorkspace( params: CreateWorkspaceParams ): Promise { - const data = await request({ - url: '/api/workspace', - method: 'POST', - data: params, - }); - - return data.data; + return request.post('/api/workspace', { json: params }).json(); } export interface UpdateWorkspaceParams { @@ -113,15 +90,13 @@ export interface UpdateWorkspaceParams { export async function updateWorkspace( params: UpdateWorkspaceParams ): Promise { - const data = await request({ - url: `/api/workspace/${params.id}`, - method: 'POST', - data: { - public: params.public, - }, - }); - - return data.data; + return request + .post(`/api/workspace/${params.id}`, { + json: { + public: params.public, + }, + }) + .json(); } export interface DeleteWorkspaceParams { @@ -131,12 +106,7 @@ export interface DeleteWorkspaceParams { export async function deleteWorkspace( params: DeleteWorkspaceParams ): Promise { - const data = await request({ - url: `/api/workspace/${params.id}`, - method: 'DELETE', - }); - - return data.data; + await request.delete(`/api/workspace/${params.id}`); } export interface InviteMemberParams { @@ -148,15 +118,13 @@ export interface InviteMemberParams { * Notice: Only support normal(contrast to private) workspace. */ export async function inviteMember(params: InviteMemberParams): Promise { - const data = await request({ - url: `/api/workspace/${params.id}/permission`, - method: 'POST', - data: { - email: params.email, - }, - }); - - return data.data; + return request + .post(`/api/workspace/${params.id}/permission`, { + json: { + email: params.email, + }, + }) + .json(); } export interface RemoveMemberParams { @@ -164,12 +132,7 @@ export interface RemoveMemberParams { } export async function removeMember(params: RemoveMemberParams): Promise { - const data = await request({ - url: `/api/permission/${params.permissionId}`, - method: 'DELETE', - }); - - return data.data; + await request.delete(`/api/permission/${params.permissionId}`); } export interface AcceptInvitingParams { @@ -179,12 +142,7 @@ export interface AcceptInvitingParams { export async function acceptInviting( params: AcceptInvitingParams ): Promise { - const data = await request({ - url: `/api/invite/${params.invitingCode}`, - method: 'POST', - }); - - return data.data; + await request.post(`/api/invite/${params.invitingCode}`); } export interface DownloadWOrkspaceParams { @@ -193,28 +151,22 @@ export interface DownloadWOrkspaceParams { export async function downloadWorkspace( params: DownloadWOrkspaceParams ): Promise { - const data = await request({ - url: `/api/workspace/${params.workspaceId}/doc`, - method: 'GET', - responseType: 'arraybuffer', - }); - - return data.data; + return request.get(`/api/workspace/${params.workspaceId}/doc`).arrayBuffer(); } export async function uploadBlob(params: { blob: Blob }): Promise { - const data = await request({ - url: '/api/blob', - method: 'PUT', - data: params.blob, - }); - return data.data; + return request.post('/api/blob', { body: params.blob }).text(); + + // const data = await request({ + // url: '/api/blob', + // method: 'PUT', + // data: params.blob, + // }); + // return data.data; } -export async function getBlob(params: { blobId: string }): Promise { - const data = await request({ - url: `/api/blob/${params.blobId}`, - method: 'GET', - }); - return data.data; +export async function getBlob(params: { + blobId: string; +}): Promise { + return request.get(`/api/blob/${params.blobId}`).arrayBuffer(); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c93560ef3f..1fa306fb75 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,8 +6,11 @@ importers: specifiers: '@jest/globals': ^29.3.1 '@playwright/test': ^1.28.1 - '@types/node': 18.7.18 - eslint: 8.22.0 + '@types/eslint': ^8.4.10 + '@types/node': ^18.11.17 + '@typescript-eslint/eslint-plugin': ^5.47.0 + '@typescript-eslint/parser': ^5.47.0 + eslint: ^8.30.0 eslint-config-next: 12.3.1 eslint-config-prettier: ^8.5.0 eslint-plugin-prettier: ^4.2.1 @@ -18,12 +21,15 @@ importers: devDependencies: '@jest/globals': 29.3.1 '@playwright/test': 1.28.1 - '@types/node': 18.7.18 - eslint: 8.22.0 - eslint-config-next: 12.3.1_tg6quxtr5dyl3tikvj7rwonxxi - eslint-config-prettier: 8.5.0_eslint@8.22.0 - eslint-plugin-prettier: 4.2.1_i2cojdczqdiurzgttlwdgf764e - jest: 29.3.1_@types+node@18.7.18 + '@types/eslint': 8.4.10 + '@types/node': 18.11.17 + '@typescript-eslint/eslint-plugin': 5.47.0_dvmqlqg4r5ba7a4i47pzcunkky + '@typescript-eslint/parser': 5.47.0_f5jcydormhcqaoeadqwgqigppy + eslint: 8.30.0 + eslint-config-next: 12.3.1_f5jcydormhcqaoeadqwgqigppy + eslint-config-prettier: 8.5.0_eslint@8.30.0 + eslint-plugin-prettier: 4.2.1_bat6r7ilbbslsp5dhd45s4onze + jest: 29.3.1_@types+node@18.11.17 prettier: 2.7.1 ts-jest: 29.0.3_4f6uxrzmuwipl5rr3bcogf6k74 typescript: 4.9.3 @@ -112,12 +118,14 @@ importers: axios: ^1.2.0 encoding: ^0.1.13 firebase: ^9.13.0 + ky: ^0.33.0 swr: ^2.0.0 typescript: ^4.8.4 dependencies: - axios: 1.2.0 + axios: 1.2.1 encoding: 0.1.13 firebase: 9.13.0_encoding@0.1.13 + ky: 0.33.0 swr: 2.0.0 devDependencies: typescript: 4.9.3 @@ -736,6 +744,23 @@ packages: - supports-color dev: true + /@eslint/eslintrc/1.4.0: + resolution: {integrity: sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.4 + espree: 9.4.0 + globals: 13.19.0 + ignore: 5.2.0 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + /@firebase/analytics-compat/0.1.17_uhwflrzfcfz2g667jhvqg7sd7i: resolution: {integrity: sha512-36ByEDsH6/3YNuD6yig30s2A/+E1pt333r8SJirUE8+aHYl/DGX0PXplKvJWDGamYYjMwet3Kt4XRrB1NY8mLg==} peerDependencies: @@ -1216,7 +1241,7 @@ packages: engines: {node: ^8.13.0 || >=10.10.0} dependencies: '@grpc/proto-loader': 0.7.3 - '@types/node': 18.7.18 + '@types/node': 18.11.17 dev: false /@grpc/proto-loader/0.6.13: @@ -1254,10 +1279,26 @@ packages: - supports-color dev: true + /@humanwhocodes/config-array/0.11.8: + resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + dev: true + /@humanwhocodes/gitignore-to-minimatch/1.0.2: resolution: {integrity: sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==} dev: true + /@humanwhocodes/module-importer/1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + /@humanwhocodes/object-schema/1.2.1: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true @@ -1283,7 +1324,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.3.1 - '@types/node': 18.7.18 + '@types/node': 18.11.17 chalk: 4.1.2 jest-message-util: 29.3.1 jest-util: 29.3.1 @@ -1304,14 +1345,14 @@ packages: '@jest/test-result': 29.3.1 '@jest/transform': 29.3.1 '@jest/types': 29.3.1 - '@types/node': 18.7.18 + '@types/node': 18.11.17 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.7.0 exit: 0.1.2 graceful-fs: 4.2.10 jest-changed-files: 29.2.0 - jest-config: 29.3.1_@types+node@18.7.18 + jest-config: 29.3.1_@types+node@18.11.17 jest-haste-map: 29.3.1 jest-message-util: 29.3.1 jest-regex-util: 29.2.0 @@ -1338,7 +1379,7 @@ packages: dependencies: '@jest/fake-timers': 29.3.1 '@jest/types': 29.3.1 - '@types/node': 18.7.18 + '@types/node': 18.11.17 jest-mock: 29.3.1 dev: true @@ -1365,7 +1406,7 @@ packages: dependencies: '@jest/types': 29.3.1 '@sinonjs/fake-timers': 9.1.2 - '@types/node': 18.7.18 + '@types/node': 18.11.17 jest-message-util: 29.3.1 jest-mock: 29.3.1 jest-util: 29.3.1 @@ -1398,7 +1439,7 @@ packages: '@jest/transform': 29.3.1 '@jest/types': 29.3.1 '@jridgewell/trace-mapping': 0.3.17 - '@types/node': 18.7.18 + '@types/node': 18.11.17 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 @@ -1486,7 +1527,7 @@ packages: '@jest/schemas': 29.0.0 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 18.7.18 + '@types/node': 18.11.17 '@types/yargs': 17.0.15 chalk: 4.1.2 dev: true @@ -1982,7 +2023,7 @@ packages: engines: {node: '>=14'} hasBin: true dependencies: - '@types/node': 18.7.18 + '@types/node': 18.11.17 playwright-core: 1.28.1 dev: true @@ -2283,6 +2324,17 @@ packages: '@babel/types': 7.20.5 dev: true + /@types/eslint/8.4.10: + resolution: {integrity: sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==} + dependencies: + '@types/estree': 1.0.0 + '@types/json-schema': 7.0.11 + dev: true + + /@types/estree/1.0.0: + resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==} + dev: true + /@types/flexsearch/0.7.3: resolution: {integrity: sha512-HXwADeHEP4exXkCIwy2n1+i0f1ilP1ETQOH5KDOugjkTFZPntWo0Gr8stZOaebkxsdx+k0X/K6obU/+it07ocg==} dev: false @@ -2290,7 +2342,7 @@ packages: /@types/graceful-fs/4.1.5: resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==} dependencies: - '@types/node': 18.7.18 + '@types/node': 18.11.17 dev: true /@types/istanbul-lib-coverage/2.0.4: @@ -2309,6 +2361,10 @@ packages: '@types/istanbul-lib-report': 3.0.0 dev: true + /@types/json-schema/7.0.11: + resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} + dev: true + /@types/json5/0.0.29: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true @@ -2317,8 +2373,12 @@ packages: resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} dev: false + /@types/node/18.11.17: + resolution: {integrity: sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==} + /@types/node/18.7.18: resolution: {integrity: sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==} + dev: true /@types/parse-json/4.0.0: resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} @@ -2373,6 +2433,10 @@ packages: /@types/scheduler/0.16.2: resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} + /@types/semver/7.3.13: + resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==} + dev: true + /@types/stack-utils/2.0.1: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} dev: true @@ -2391,8 +2455,35 @@ packages: '@types/yargs-parser': 21.0.0 dev: true - /@typescript-eslint/parser/5.38.0_76twfck5d7crjqrmw4yltga7zm: - resolution: {integrity: sha512-/F63giJGLDr0ms1Cr8utDAxP2SPiglaD6V+pCOcG35P2jCqdfR7uuEhz1GIC3oy4hkUF8xA1XSXmd9hOh/a5EA==} + /@typescript-eslint/eslint-plugin/5.47.0_dvmqlqg4r5ba7a4i47pzcunkky: + resolution: {integrity: sha512-AHZtlXAMGkDmyLuLZsRpH3p4G/1iARIwc/T0vIem2YB+xW6pZaXYXzCBnZSF/5fdM97R9QqZWZ+h3iW10XgevQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/parser': 5.47.0_f5jcydormhcqaoeadqwgqigppy + '@typescript-eslint/scope-manager': 5.47.0 + '@typescript-eslint/type-utils': 5.47.0_f5jcydormhcqaoeadqwgqigppy + '@typescript-eslint/utils': 5.47.0_f5jcydormhcqaoeadqwgqigppy + debug: 4.3.4 + eslint: 8.30.0 + ignore: 5.2.0 + natural-compare-lite: 1.4.0 + regexpp: 3.2.0 + semver: 7.3.7 + tsutils: 3.21.0_typescript@4.9.3 + typescript: 4.9.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser/5.47.0_76twfck5d7crjqrmw4yltga7zm: + resolution: {integrity: sha512-udPU4ckK+R1JWCGdQC4Qa27NtBg7w020ffHqGyAK8pAgOVuNw7YaKXGChk+udh+iiGIJf6/E/0xhVXyPAbsczw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -2401,9 +2492,9 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.38.0 - '@typescript-eslint/types': 5.38.0 - '@typescript-eslint/typescript-estree': 5.38.0_typescript@4.8.3 + '@typescript-eslint/scope-manager': 5.47.0 + '@typescript-eslint/types': 5.47.0 + '@typescript-eslint/typescript-estree': 5.47.0_typescript@4.8.3 debug: 4.3.4 eslint: 8.22.0 typescript: 4.8.3 @@ -2411,8 +2502,8 @@ packages: - supports-color dev: true - /@typescript-eslint/parser/5.38.0_tg6quxtr5dyl3tikvj7rwonxxi: - resolution: {integrity: sha512-/F63giJGLDr0ms1Cr8utDAxP2SPiglaD6V+pCOcG35P2jCqdfR7uuEhz1GIC3oy4hkUF8xA1XSXmd9hOh/a5EA==} + /@typescript-eslint/parser/5.47.0_f5jcydormhcqaoeadqwgqigppy: + resolution: {integrity: sha512-udPU4ckK+R1JWCGdQC4Qa27NtBg7w020ffHqGyAK8pAgOVuNw7YaKXGChk+udh+iiGIJf6/E/0xhVXyPAbsczw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -2421,31 +2512,51 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.38.0 - '@typescript-eslint/types': 5.38.0 - '@typescript-eslint/typescript-estree': 5.38.0_typescript@4.9.3 + '@typescript-eslint/scope-manager': 5.47.0 + '@typescript-eslint/types': 5.47.0 + '@typescript-eslint/typescript-estree': 5.47.0_typescript@4.9.3 debug: 4.3.4 - eslint: 8.22.0 + eslint: 8.30.0 typescript: 4.9.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager/5.38.0: - resolution: {integrity: sha512-ByhHIuNyKD9giwkkLqzezZ9y5bALW8VNY6xXcP+VxoH4JBDKjU5WNnsiD4HJdglHECdV+lyaxhvQjTUbRboiTA==} + /@typescript-eslint/scope-manager/5.47.0: + resolution: {integrity: sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.38.0 - '@typescript-eslint/visitor-keys': 5.38.0 + '@typescript-eslint/types': 5.47.0 + '@typescript-eslint/visitor-keys': 5.47.0 dev: true - /@typescript-eslint/types/5.38.0: - resolution: {integrity: sha512-HHu4yMjJ7i3Cb+8NUuRCdOGu2VMkfmKyIJsOr9PfkBVYLYrtMCK/Ap50Rpov+iKpxDTfnqvDbuPLgBE5FwUNfA==} + /@typescript-eslint/type-utils/5.47.0_f5jcydormhcqaoeadqwgqigppy: + resolution: {integrity: sha512-1J+DFFrYoDUXQE1b7QjrNGARZE6uVhBqIvdaXTe5IN+NmEyD68qXR1qX1g2u4voA+nCaelQyG8w30SAOihhEYg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 5.47.0_typescript@4.9.3 + '@typescript-eslint/utils': 5.47.0_f5jcydormhcqaoeadqwgqigppy + debug: 4.3.4 + eslint: 8.30.0 + tsutils: 3.21.0_typescript@4.9.3 + typescript: 4.9.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types/5.47.0: + resolution: {integrity: sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree/5.38.0_typescript@4.8.3: - resolution: {integrity: sha512-6P0RuphkR+UuV7Avv7MU3hFoWaGcrgOdi8eTe1NwhMp2/GjUJoODBTRWzlHpZh6lFOaPmSvgxGlROa0Sg5Zbyg==} + /@typescript-eslint/typescript-estree/5.47.0_typescript@4.8.3: + resolution: {integrity: sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: typescript: '*' @@ -2453,8 +2564,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.38.0 - '@typescript-eslint/visitor-keys': 5.38.0 + '@typescript-eslint/types': 5.47.0 + '@typescript-eslint/visitor-keys': 5.47.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 @@ -2465,8 +2576,8 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree/5.38.0_typescript@4.9.3: - resolution: {integrity: sha512-6P0RuphkR+UuV7Avv7MU3hFoWaGcrgOdi8eTe1NwhMp2/GjUJoODBTRWzlHpZh6lFOaPmSvgxGlROa0Sg5Zbyg==} + /@typescript-eslint/typescript-estree/5.47.0_typescript@4.9.3: + resolution: {integrity: sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: typescript: '*' @@ -2474,8 +2585,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.38.0 - '@typescript-eslint/visitor-keys': 5.38.0 + '@typescript-eslint/types': 5.47.0 + '@typescript-eslint/visitor-keys': 5.47.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 @@ -2486,11 +2597,31 @@ packages: - supports-color dev: true - /@typescript-eslint/visitor-keys/5.38.0: - resolution: {integrity: sha512-MxnrdIyArnTi+XyFLR+kt/uNAcdOnmT+879os7qDRI+EYySR4crXJq9BXPfRzzLGq0wgxkwidrCJ9WCAoacm1w==} + /@typescript-eslint/utils/5.47.0_f5jcydormhcqaoeadqwgqigppy: + resolution: {integrity: sha512-U9xcc0N7xINrCdGVPwABjbAKqx4GK67xuMV87toI+HUqgXj26m6RBp9UshEXcTrgCkdGYFzgKLt8kxu49RilDw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@types/json-schema': 7.0.11 + '@types/semver': 7.3.13 + '@typescript-eslint/scope-manager': 5.47.0 + '@typescript-eslint/types': 5.47.0 + '@typescript-eslint/typescript-estree': 5.47.0_typescript@4.9.3 + eslint: 8.30.0 + eslint-scope: 5.1.1 + eslint-utils: 3.0.0_eslint@8.30.0 + semver: 7.3.7 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys/5.47.0: + resolution: {integrity: sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.38.0 + '@typescript-eslint/types': 5.47.0 eslint-visitor-keys: 3.3.0 dev: true @@ -2634,8 +2765,8 @@ packages: engines: {node: '>=4'} dev: true - /axios/1.2.0: - resolution: {integrity: sha512-zT7wZyNYu3N5Bu0wuZ6QccIf93Qk1eV8LOewxgjOZFd2DenOs98cJ7+Y6703d0wkaXGY6/nZd4EweJaHz9uzQw==} + /axios/1.2.1: + resolution: {integrity: sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==} dependencies: follow-redirects: 1.15.2 form-data: 4.0.0 @@ -3203,11 +3334,11 @@ packages: dependencies: '@next/eslint-plugin-next': 12.3.1 '@rushstack/eslint-patch': 1.2.0 - '@typescript-eslint/parser': 5.38.0_76twfck5d7crjqrmw4yltga7zm + '@typescript-eslint/parser': 5.47.0_76twfck5d7crjqrmw4yltga7zm eslint: 8.22.0 eslint-import-resolver-node: 0.3.6 eslint-import-resolver-typescript: 2.7.1_2iahngt3u2tkbdlu6s4gkur3pu - eslint-plugin-import: 2.26.0_dz6mtv6jua3j7xbldvgsafodwi + eslint-plugin-import: 2.26.0_erzq45onfaeij7wmfvjxpvebie eslint-plugin-jsx-a11y: 6.6.1_eslint@8.22.0 eslint-plugin-react: 7.31.8_eslint@8.22.0 eslint-plugin-react-hooks: 4.6.0_eslint@8.22.0 @@ -3217,7 +3348,7 @@ packages: - supports-color dev: true - /eslint-config-next/12.3.1_tg6quxtr5dyl3tikvj7rwonxxi: + /eslint-config-next/12.3.1_f5jcydormhcqaoeadqwgqigppy: resolution: {integrity: sha512-EN/xwKPU6jz1G0Qi6Bd/BqMnHLyRAL0VsaQaWA7F3KkjAgZHi4f1uL1JKGWNxdQpHTW/sdGONBd0bzxUka/DJg==} peerDependencies: eslint: ^7.23.0 || ^8.0.0 @@ -3228,14 +3359,14 @@ packages: dependencies: '@next/eslint-plugin-next': 12.3.1 '@rushstack/eslint-patch': 1.2.0 - '@typescript-eslint/parser': 5.38.0_tg6quxtr5dyl3tikvj7rwonxxi - eslint: 8.22.0 + '@typescript-eslint/parser': 5.47.0_f5jcydormhcqaoeadqwgqigppy + eslint: 8.30.0 eslint-import-resolver-node: 0.3.6 - eslint-import-resolver-typescript: 2.7.1_2iahngt3u2tkbdlu6s4gkur3pu - eslint-plugin-import: 2.26.0_dz6mtv6jua3j7xbldvgsafodwi - eslint-plugin-jsx-a11y: 6.6.1_eslint@8.22.0 - eslint-plugin-react: 7.31.8_eslint@8.22.0 - eslint-plugin-react-hooks: 4.6.0_eslint@8.22.0 + eslint-import-resolver-typescript: 2.7.1_2lbwmhbr7bncddqbzzpg77o75m + eslint-plugin-import: 2.26.0_r5yriwyq5glbgsbtddyqgajogq + eslint-plugin-jsx-a11y: 6.6.1_eslint@8.30.0 + eslint-plugin-react: 7.31.8_eslint@8.30.0 + eslint-plugin-react-hooks: 4.6.0_eslint@8.30.0 typescript: 4.9.3 transitivePeerDependencies: - eslint-import-resolver-webpack @@ -3251,6 +3382,15 @@ packages: eslint: 8.22.0 dev: true + /eslint-config-prettier/8.5.0_eslint@8.30.0: + resolution: {integrity: sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.30.0 + dev: true + /eslint-import-resolver-node/0.3.6: resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==} dependencies: @@ -3269,7 +3409,7 @@ packages: dependencies: debug: 4.3.4 eslint: 8.22.0 - eslint-plugin-import: 2.26.0_dz6mtv6jua3j7xbldvgsafodwi + eslint-plugin-import: 2.26.0_erzq45onfaeij7wmfvjxpvebie glob: 7.2.3 is-glob: 4.0.3 resolve: 1.22.1 @@ -3278,7 +3418,25 @@ packages: - supports-color dev: true - /eslint-module-utils/2.7.4_c3nlkncy4cvyvjj2ycqweyustu: + /eslint-import-resolver-typescript/2.7.1_2lbwmhbr7bncddqbzzpg77o75m: + resolution: {integrity: sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==} + engines: {node: '>=4'} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + dependencies: + debug: 4.3.4 + eslint: 8.30.0 + eslint-plugin-import: 2.26.0_r5yriwyq5glbgsbtddyqgajogq + glob: 7.2.3 + is-glob: 4.0.3 + resolve: 1.22.1 + tsconfig-paths: 3.14.1 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-module-utils/2.7.4_5x2zxwgwkh3hozpqf3invsv6ui: resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} engines: {node: '>=4'} peerDependencies: @@ -3299,7 +3457,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.38.0_tg6quxtr5dyl3tikvj7rwonxxi + '@typescript-eslint/parser': 5.47.0_76twfck5d7crjqrmw4yltga7zm debug: 3.2.7 eslint: 8.22.0 eslint-import-resolver-node: 0.3.6 @@ -3308,7 +3466,37 @@ packages: - supports-color dev: true - /eslint-plugin-import/2.26.0_dz6mtv6jua3j7xbldvgsafodwi: + /eslint-module-utils/2.7.4_nif3prfnpejayun4zfrdsrpede: + resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 5.47.0_f5jcydormhcqaoeadqwgqigppy + debug: 3.2.7 + eslint: 8.30.0 + eslint-import-resolver-node: 0.3.6 + eslint-import-resolver-typescript: 2.7.1_2lbwmhbr7bncddqbzzpg77o75m + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-plugin-import/2.26.0_erzq45onfaeij7wmfvjxpvebie: resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} engines: {node: '>=4'} peerDependencies: @@ -3318,14 +3506,45 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.38.0_tg6quxtr5dyl3tikvj7rwonxxi + '@typescript-eslint/parser': 5.47.0_76twfck5d7crjqrmw4yltga7zm array-includes: 3.1.5 array.prototype.flat: 1.3.0 debug: 2.6.9 doctrine: 2.1.0 eslint: 8.22.0 eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.4_c3nlkncy4cvyvjj2ycqweyustu + eslint-module-utils: 2.7.4_5x2zxwgwkh3hozpqf3invsv6ui + has: 1.0.3 + is-core-module: 2.10.0 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.values: 1.1.5 + resolve: 1.22.1 + tsconfig-paths: 3.14.1 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + + /eslint-plugin-import/2.26.0_r5yriwyq5glbgsbtddyqgajogq: + resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@typescript-eslint/parser': 5.47.0_f5jcydormhcqaoeadqwgqigppy + array-includes: 3.1.5 + array.prototype.flat: 1.3.0 + debug: 2.6.9 + doctrine: 2.1.0 + eslint: 8.30.0 + eslint-import-resolver-node: 0.3.6 + eslint-module-utils: 2.7.4_nif3prfnpejayun4zfrdsrpede has: 1.0.3 is-core-module: 2.10.0 is-glob: 4.0.3 @@ -3361,6 +3580,45 @@ packages: semver: 6.3.0 dev: true + /eslint-plugin-jsx-a11y/6.6.1_eslint@8.30.0: + resolution: {integrity: sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + dependencies: + '@babel/runtime': 7.19.0 + aria-query: 4.2.2 + array-includes: 3.1.5 + ast-types-flow: 0.0.7 + axe-core: 4.4.3 + axobject-query: 2.2.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 8.30.0 + has: 1.0.3 + jsx-ast-utils: 3.3.3 + language-tags: 1.0.5 + minimatch: 3.1.2 + semver: 6.3.0 + dev: true + + /eslint-plugin-prettier/4.2.1_bat6r7ilbbslsp5dhd45s4onze: + resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} + engines: {node: '>=12.0.0'} + peerDependencies: + eslint: '>=7.28.0' + eslint-config-prettier: '*' + prettier: '>=2.0.0' + peerDependenciesMeta: + eslint-config-prettier: + optional: true + dependencies: + eslint: 8.30.0 + eslint-config-prettier: 8.5.0_eslint@8.30.0 + prettier: 2.7.1 + prettier-linter-helpers: 1.0.0 + dev: true + /eslint-plugin-prettier/4.2.1_i2cojdczqdiurzgttlwdgf764e: resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} engines: {node: '>=12.0.0'} @@ -3387,6 +3645,15 @@ packages: eslint: 8.22.0 dev: true + /eslint-plugin-react-hooks/4.6.0_eslint@8.30.0: + resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + dependencies: + eslint: 8.30.0 + dev: true + /eslint-plugin-react/7.31.8_eslint@8.22.0: resolution: {integrity: sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==} engines: {node: '>=4'} @@ -3410,6 +3677,37 @@ packages: string.prototype.matchall: 4.0.7 dev: true + /eslint-plugin-react/7.31.8_eslint@8.30.0: + resolution: {integrity: sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + dependencies: + array-includes: 3.1.5 + array.prototype.flatmap: 1.3.0 + doctrine: 2.1.0 + eslint: 8.30.0 + estraverse: 5.3.0 + jsx-ast-utils: 3.3.3 + minimatch: 3.1.2 + object.entries: 1.1.5 + object.fromentries: 2.0.5 + object.hasown: 1.1.1 + object.values: 1.1.5 + prop-types: 15.8.1 + resolve: 2.0.0-next.4 + semver: 6.3.0 + string.prototype.matchall: 4.0.7 + dev: true + + /eslint-scope/5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + dev: true + /eslint-scope/7.1.1: resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3428,6 +3726,16 @@ packages: eslint-visitor-keys: 2.1.0 dev: true + /eslint-utils/3.0.0_eslint@8.30.0: + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + dependencies: + eslint: 8.30.0 + eslint-visitor-keys: 2.1.0 + dev: true + /eslint-visitor-keys/2.1.0: resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} engines: {node: '>=10'} @@ -3485,6 +3793,54 @@ packages: - supports-color dev: true + /eslint/8.30.0: + resolution: {integrity: sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint/eslintrc': 1.4.0 + '@humanwhocodes/config-array': 0.11.8 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.1.1 + eslint-utils: 3.0.0_eslint@8.30.0 + eslint-visitor-keys: 3.3.0 + espree: 9.4.0 + esquery: 1.4.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.19.0 + grapheme-splitter: 1.0.4 + ignore: 5.2.0 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-sdsl: 4.2.0 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.1 + regexpp: 3.2.0 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + /espree/9.4.0: resolution: {integrity: sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3514,6 +3870,11 @@ packages: estraverse: 5.3.0 dev: true + /estraverse/4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + dev: true + /estraverse/5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -3838,6 +4199,13 @@ packages: type-fest: 0.20.2 dev: true + /globals/13.19.0: + resolution: {integrity: sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + /globby/11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} @@ -4096,6 +4464,11 @@ packages: engines: {node: '>=0.12.0'} dev: true + /is-path-inside/3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + /is-regex/1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} @@ -4212,7 +4585,7 @@ packages: '@jest/expect': 29.3.1 '@jest/test-result': 29.3.1 '@jest/types': 29.3.1 - '@types/node': 18.7.18 + '@types/node': 18.11.17 chalk: 4.1.2 co: 4.6.0 dedent: 0.7.0 @@ -4231,7 +4604,7 @@ packages: - supports-color dev: true - /jest-cli/29.3.1_@types+node@18.7.18: + /jest-cli/29.3.1_@types+node@18.11.17: resolution: {integrity: sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -4248,7 +4621,7 @@ packages: exit: 0.1.2 graceful-fs: 4.2.10 import-local: 3.1.0 - jest-config: 29.3.1_@types+node@18.7.18 + jest-config: 29.3.1_@types+node@18.11.17 jest-util: 29.3.1 jest-validate: 29.3.1 prompts: 2.4.2 @@ -4259,7 +4632,7 @@ packages: - ts-node dev: true - /jest-config/29.3.1_@types+node@18.7.18: + /jest-config/29.3.1_@types+node@18.11.17: resolution: {integrity: sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -4274,7 +4647,7 @@ packages: '@babel/core': 7.20.5 '@jest/test-sequencer': 29.3.1 '@jest/types': 29.3.1 - '@types/node': 18.7.18 + '@types/node': 18.11.17 babel-jest: 29.3.1_@babel+core@7.20.5 chalk: 4.1.2 ci-info: 3.7.0 @@ -4333,7 +4706,7 @@ packages: '@jest/environment': 29.3.1 '@jest/fake-timers': 29.3.1 '@jest/types': 29.3.1 - '@types/node': 18.7.18 + '@types/node': 18.11.17 jest-mock: 29.3.1 jest-util: 29.3.1 dev: true @@ -4349,7 +4722,7 @@ packages: dependencies: '@jest/types': 29.3.1 '@types/graceful-fs': 4.1.5 - '@types/node': 18.7.18 + '@types/node': 18.11.17 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.10 @@ -4400,7 +4773,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.3.1 - '@types/node': 18.7.18 + '@types/node': 18.11.17 jest-util: 29.3.1 dev: true @@ -4455,7 +4828,7 @@ packages: '@jest/test-result': 29.3.1 '@jest/transform': 29.3.1 '@jest/types': 29.3.1 - '@types/node': 18.7.18 + '@types/node': 18.11.17 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.10 @@ -4486,7 +4859,7 @@ packages: '@jest/test-result': 29.3.1 '@jest/transform': 29.3.1 '@jest/types': 29.3.1 - '@types/node': 18.7.18 + '@types/node': 18.11.17 chalk: 4.1.2 cjs-module-lexer: 1.2.2 collect-v8-coverage: 1.0.1 @@ -4542,7 +4915,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.3.1 - '@types/node': 18.7.18 + '@types/node': 18.11.17 chalk: 4.1.2 ci-info: 3.7.0 graceful-fs: 4.2.10 @@ -4567,7 +4940,7 @@ packages: dependencies: '@jest/test-result': 29.3.1 '@jest/types': 29.3.1 - '@types/node': 18.7.18 + '@types/node': 18.11.17 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -4579,13 +4952,13 @@ packages: resolution: {integrity: sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 18.7.18 + '@types/node': 18.11.17 jest-util: 29.3.1 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true - /jest/29.3.1_@types+node@18.7.18: + /jest/29.3.1_@types+node@18.11.17: resolution: {integrity: sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -4598,13 +4971,17 @@ packages: '@jest/core': 29.3.1 '@jest/types': 29.3.1 import-local: 3.1.0 - jest-cli: 29.3.1_@types+node@18.7.18 + jest-cli: 29.3.1_@types+node@18.11.17 transitivePeerDependencies: - '@types/node' - supports-color - ts-node dev: true + /js-sdsl/4.2.0: + resolution: {integrity: sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==} + dev: true + /js-tokens/4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -4679,6 +5056,11 @@ packages: engines: {node: '>=14.16'} dev: false + /ky/0.33.0: + resolution: {integrity: sha512-peKzuOlN/q3Q3jOgi4t0cp6DOgif5rVnmiSIsjsmkiOcdnSjkrKSUqQmRWYCTqjUtR9b3xQQr8aj7KwSW1r49A==} + engines: {node: '>=14.16'} + dev: false + /language-subtag-registry/0.3.22: resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} dev: true @@ -4878,6 +5260,10 @@ packages: hasBin: true dev: false + /natural-compare-lite/1.4.0: + resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} + dev: true + /natural-compare/1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true @@ -5273,7 +5659,7 @@ packages: '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 '@types/long': 4.0.2 - '@types/node': 18.7.18 + '@types/node': 18.11.17 long: 4.0.0 dev: false @@ -5292,7 +5678,7 @@ packages: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 18.7.18 + '@types/node': 18.11.17 long: 5.2.0 dev: false @@ -5911,7 +6297,7 @@ packages: dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 - jest: 29.3.1_@types+node@18.7.18 + jest: 29.3.1_@types+node@18.11.17 jest-util: 29.3.1 json5: 2.2.1 lodash.memoize: 4.1.2 diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000000..592edefeb6 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "experimentalDecorators": true, + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +}