Merge branch 'feat/filesystem_and_search' of github.com:toeverything/AFFiNE into feat/filesystem_and_search

This commit is contained in:
DiamondThree
2022-12-22 18:16:46 +08:00
34 changed files with 871 additions and 486 deletions
-14
View File
@@ -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 (doesnt 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,
};
+1 -1
View File
@@ -3,5 +3,5 @@
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.formatOnSaveMode": "file",
"cSpell.words": ["testid"]
"cSpell.words": ["blocksuite", "testid"]
}
+31 -3
View File
@@ -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/*"
]
}
}
-19
View File
@@ -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 (doesnt 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,
};
+10
View File
@@ -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
}
}
@@ -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 = () => {
<StyledGoogleButton
onClick={() => {
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 => {
@@ -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<string>(
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 ? (
<div>
<StyledSettingH2 marginTop={56}>Workspace Avatar</StyledSettingH2>
<StyledSettingAvatarContent>
<StyledSettingAvatar
alt="workspace avatar"
src={workspaces[workspace.id]?.meta.avatar || ''}
>
W
</StyledSettingAvatar>
{/* {isOwner ? (
<StyledAvatarUploadBtn shape="round">upload</StyledAvatarUploadBtn>
) : null} */}
{/* <Button shape="round">remove</Button> */}
</StyledSettingAvatarContent>
<StyledSettingH2 marginTop={36}>Workspace Name</StyledSettingH2>
<StyledSettingInputContainer>
<Input
width={327}
value={workspaceName}
placeholder="Workspace Name"
disabled={!isOwner}
maxLength={14}
minLength={1}
onChange={handleChangeWorkSpaceName}
></Input>
</StyledSettingInputContainer>
<StyledSettingH2 marginTop={36}>Workspace Owner</StyledSettingH2>
<StyledSettingInputContainer>
<Input
width={327}
disabled
value={owner.name}
placeholder="Workspace Owner"
></Input>
</StyledSettingInputContainer>
<StyledDeleteButtonContainer>
<Button type="danger" shape="circle">
Delete Workspace
</Button>
</StyledDeleteButtonContainer>
</div>
) : null;
};
@@ -0,0 +1 @@
export * from './general';
@@ -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' };
});
@@ -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',
@@ -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>(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 = ({
<Modal open={isShow}>
<StyledSettingContainer>
<ModalCloseButton onClick={handleClickClose} />
<StyledSettingSidebar>
<StyledSettingSidebarHeader>
Workspace Settings
</StyledSettingSidebarHeader>
<WorkspaceSettingTab
activeTab={activeTab}
onTabChange={handleTabChange}
/>
</StyledSettingSidebar>
{isOwner ? (
<StyledSettingSidebar>
<StyledSettingSidebarHeader>
Workspace Settings
</StyledSettingSidebarHeader>
<WorkspaceSettingTab
activeTab={activeTab}
onTabChange={handleTabChange}
/>
</StyledSettingSidebar>
) : null}
<StyledSettingContent>
{activeTab === ActiveTab.general && (
<GeneralPage workspace={workspace} />
<GeneralPage workspace={workspace} owner={owner} />
)}
{activeTab === ActiveTab.members && workspace && (
<MembersPage workspace={workspace} />
@@ -155,32 +160,6 @@ export const WorkspaceSetting = ({
);
};
const GeneralPage = ({ workspace }: { workspace?: Workspace }) => {
return (
<div>
<StyledSettingH2 marginTop={56}>Workspace Avatar</StyledSettingH2>
<StyledSettingAvatarContent>
<StyledSettingAvatar alt="workspace avatar">W</StyledSettingAvatar>
{/* <StyledAvatarUploadBtn shape="round">upload</StyledAvatarUploadBtn>
<Button shape="round">remove</Button> */}
</StyledSettingAvatarContent>
<StyledSettingH2 marginTop={36}>Workspace Name</StyledSettingH2>
<StyledSettingInputContainer>
<Input width={327} placeholder="Workspace Name"></Input>
</StyledSettingInputContainer>
<StyledSettingH2 marginTop={36}>Workspace Owner</StyledSettingH2>
<StyledSettingInputContainer>
<Input width={327} placeholder="Workspace Owner"></Input>
</StyledSettingInputContainer>
<StyledDeleteButtonContainer>
<Button type="danger" shape="circle">
Delete Workspace
</Button>
</StyledDeleteButtonContainer>
</div>
);
};
const MembersPage = ({ workspace }: { workspace: Workspace }) => {
const [isInviteModalShow, setIsInviteModalShow] = useState(false);
const [members, setMembers] = useState<Member[]>([]);
@@ -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 = ({
})}
</WorkspaceWrapper>
<CreateWorkspaceItem />
<WorkspaceSetting
isShow={Boolean(settingWorkspaceId)}
onClose={handleCloseWorkSpace}
workspace={
settingWorkspaceId
? workspacesMeta.find(
workspace => workspace.id === settingWorkspaceId
)
: undefined
}
/>
{settingWorkspace ? (
<WorkspaceSetting
isShow={Boolean(settingWorkspaceId)}
onClose={handleCloseWorkSpace}
workspace={settingWorkspace}
owner={
(settingWorkspaceId &&
workSpaceDetails[settingWorkspaceId]?.owner) || {
id: user.id,
name: user.name,
}
}
/>
) : null}
<StyledDivider />
<ListItem
icon={<InformationIcon />}
@@ -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)
}
>
<WorkspaceItemAvatar alt={name} src={icon}>
{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',
},
};
}
@@ -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');
@@ -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;
@@ -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<string, Workspace | null> = {};
const workspaces: Record<string, Workspace | null> = {};
workspacesList.forEach(({ id, workspace }) => {
workspaces[id] = workspace;
+8 -3
View File
@@ -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<
+3
View File
@@ -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}
></StyledInput>
+1
View File
@@ -25,6 +25,7 @@
"axios": "^1.2.0",
"encoding": "^0.1.13",
"firebase": "^9.13.0",
"ky": "^0.33.0",
"swr": "^2.0.0"
}
}
+10 -2
View File
@@ -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) => {
@@ -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;
}
}
@@ -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);
@@ -1,4 +1,4 @@
import type { AccessTokenMessage } from './types';
import { AccessTokenMessage } from './token';
type Callback = (user: AccessTokenMessage | null) => void;
+50 -4
View File
@@ -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 };
@@ -1,2 +0,0 @@
export * from './authorization';
export type { AccessTokenMessage } from './types';
@@ -1,8 +0,0 @@
export interface AccessTokenMessage {
create_at: number;
exp: number;
email: string;
id: string;
name: string;
avatar_url: string;
}
@@ -1,7 +0,0 @@
export {
setAuthorization,
setToken,
getToken,
authorizationEvent,
} from './authorization';
export type { AccessTokenMessage } from './authorization';
@@ -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<any, any>) {
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<any, any>) {
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;
}
@@ -1 +0,0 @@
export { handleResponseError, handleResponse } from './handle-error';
@@ -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<boolean> {
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<typeof login> | undefined;
export async function setAuthorization(config: AxiosRequestConfig<unknown>) {
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;
};
+4 -13
View File
@@ -27,13 +27,9 @@ export interface LoginResponse {
}
export async function login(params: LoginParams): Promise<LoginResponse> {
const data = await request<LoginResponse>({
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<LoginResponse>();
}
export interface GetUserByEmailParams {
@@ -52,10 +48,5 @@ export interface User {
export async function getUserByEmail(
params: GetUserByEmailParams
): Promise<User | null> {
const data = await request<User | null>({
url: '/api/user',
method: 'GET',
params,
});
return data.data;
return request.get('/api/user', { json: params }).json<User | null>();
}
+34 -82
View File
@@ -26,12 +26,7 @@ export interface Workspace {
}
export async function getWorkspaces(): Promise<Workspace[]> {
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<WorkspaceDetail | null> {
const data = await request<WorkspaceDetail | null>({
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<Member[]> {
const data = await request<Member[]>({
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<void> {
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<void> {
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<void> {
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<void> {
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<void> {
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<void> {
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<ArrayBuffer> {
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<string> {
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<string> {
const data = await request({
url: `/api/blob/${params.blobId}`,
method: 'GET',
});
return data.data;
export async function getBlob(params: {
blobId: string;
}): Promise<ArrayBuffer> {
return request.get(`/api/blob/${params.blobId}`).arrayBuffer();
}
+469 -83
View File
@@ -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
+25
View File
@@ -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"]
}