diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fc4e84784b..e257ce9515 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,25 +7,67 @@ on: types: [opened, edited, synchronize, reopened] jobs: - build: - name: Build + build-backend: + name: Build Backend runs-on: ubuntu-latest strategy: matrix: - target: [frontend, backend, backend-admin] + target: [client, admin] steps: - uses: actions/checkout@v4 + + - name: Check if source code has changed + uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + shared: &shared + - 'apps/backend/libs/**' + - 'apps/backend/prisma/**' + - 'apps/backend/*.json' + - 'pnpm-lock.yaml' + client: + - *shared + - 'apps/backend/apps/client/**' + admin: + - *shared + - 'apps/backend/apps/admin/**' + - uses: ./.github/actions/setup-pnpm + if: ${{ steps.filter.outputs[matrix.target] == 'true' }} - name: Generate Prisma Client - if: ${{ matrix.target == 'backend' || matrix.target == 'backend-admin' }} + if: ${{ steps.filter.outputs[matrix.target] == 'true' }} run: pnpm --filter="@codedang/backend" exec prisma generate + - name: Build + if: ${{ steps.filter.outputs[matrix.target] == 'true' }} + run: pnpm --filter="@codedang/backend" build ${{ matrix.target }} + + build-frontend: + name: Build Frontend + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Check if source code has changed + uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + frontend: + - 'apps/frontend/**' + - 'pnpm-lock.yaml' + + - uses: ./.github/actions/setup-pnpm + if: steps.filter.outputs.frontend == 'true' + - name: Setup Next.js build cache - if: ${{ matrix.target == 'frontend' }} uses: actions/cache@v4 + if: steps.filter.outputs.frontend == 'true' with: path: apps/frontend/.next/cache key: ${{ runner.os }}-nextjs-${{ hashFiles('pnpm-lock.yaml') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }} @@ -33,18 +75,15 @@ jobs: ${{ runner.os }}-nextjs-${{ hashFiles('pnpm-lock.yaml') }}- - name: Load Next.js environment - if: ${{ matrix.target == 'frontend' }} + if: steps.filter.outputs.frontend == 'true' run: | echo "NEXT_PUBLIC_BASEURL=https://stage.codedang.com/api" >> apps/frontend/.env echo "NEXT_PUBLIC_GQL_BASEURL=https://stage.codedang.com/graphql" >> apps/frontend/.env echo "NEXT_URL=https://stage.codedang.com" >> apps/frontend/.env - - name: Build (backend admin) - if: ${{ matrix.target == 'backend-admin' }} - run: pnpm --filter="@codedang/backend" build admin - name: Build - if: ${{ matrix.target != 'backend-admin' }} - run: pnpm --filter="apps/${{ matrix.target }}" build + if: steps.filter.outputs.frontend == 'true' + run: pnpm --filter="@codedang/frontend" build typecheck: name: Typecheck @@ -52,12 +91,24 @@ jobs: steps: - uses: actions/checkout@v4 + + - name: Check if source code has changed + uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + backend: + - 'apps/backend/**' + - uses: ./.github/actions/setup-pnpm + if: steps.filter.outputs.backend == 'true' - name: Generate Prisma Client + if: steps.filter.outputs.backend == 'true' run: pnpm --filter="@codedang/backend" exec prisma generate - name: Check types (backend) # For spec files + if: steps.filter.outputs.backend == 'true' run: pnpm --filter="@codedang/backend" exec tsc --noEmit # Typecheck is not performed for frontend intentionally. @@ -98,8 +149,8 @@ jobs: - name: Lint (Node.js) run: pnpm lint - test: - name: Test + test-backend: + name: Test Backend runs-on: ubuntu-latest env: @@ -118,9 +169,21 @@ jobs: steps: - uses: actions/checkout@v4 + + - name: Check if source code has changed + uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + backend: + - 'apps/backend/**' + - 'pnpm-lock.yaml' + - uses: ./.github/actions/setup-pnpm + if: steps.filter.outputs.backend == 'true' - name: Check Prisma Migration + if: steps.filter.outputs.backend == 'true' run: | pnpm --filter="@codedang/backend" exec prisma migrate diff \ --from-migrations ./prisma/migrations \ @@ -131,7 +194,9 @@ jobs: "Please run 'pnpm prisma migrate dev' locally and commit the changes." && exit 1) - name: Migrate Prisma + if: steps.filter.outputs.backend == 'true' run: pnpm --filter="@codedang/backend" exec prisma migrate reset --force - name: Test - run: pnpm -r test + if: steps.filter.outputs.backend == 'true' + run: pnpm --filter="@codedang/backend" test diff --git a/apps/backend/apps/client/src/contest/contest.service.spec.ts b/apps/backend/apps/client/src/contest/contest.service.spec.ts index 11d41267a6..a610840d3f 100644 --- a/apps/backend/apps/client/src/contest/contest.service.spec.ts +++ b/apps/backend/apps/client/src/contest/contest.service.spec.ts @@ -216,7 +216,7 @@ describe('ContestService', () => { groupId, user01Id ) - expect(contests).to.have.lengthOf(takeNum) + expect(contests.data).to.have.lengthOf(takeNum) }) it('should return a contest array which starts with id 9', async () => { @@ -228,7 +228,7 @@ describe('ContestService', () => { groupId, user01Id ) - expect(contests[0].id).to.equals(9) + expect(contests.data[0].id).to.equals(9) }) it('a contest should contain following fields', async () => { @@ -238,12 +238,12 @@ describe('ContestService', () => { groupId, user01Id ) - expect(contests[0]).to.have.property('title') - expect(contests[0]).to.have.property('startTime') - expect(contests[0]).to.have.property('endTime') - expect(contests[0]).to.have.property('participants') - expect(contests[0].group).to.have.property('id') - expect(contests[0].group).to.have.property('groupName') + expect(contests.data[0]).to.have.property('title') + expect(contests.data[0]).to.have.property('startTime') + expect(contests.data[0]).to.have.property('endTime') + expect(contests.data[0]).to.have.property('participants') + expect(contests.data[0].group).to.have.property('id') + expect(contests.data[0].group).to.have.property('groupName') }) it("shold return contests whose title contains '낮'", async () => { @@ -255,7 +255,7 @@ describe('ContestService', () => { user01Id, keyword ) - expect(contests.map((contest) => contest.title)).to.deep.equals([ + expect(contests.data.map((contest) => contest.title)).to.deep.equals([ '소프트의 낮' ]) }) @@ -268,9 +268,7 @@ describe('ContestService', () => { 10, groupId ) - const contestIds = contests.finished - .map((c) => c.id) - .sort((a, b) => a - b) + const contestIds = contests.data.map((c) => c.id).sort((a, b) => a - b) const finishedContestIds = [6, 7, 8, 9, 10, 11, 12, 13] expect(contestIds).to.deep.equal(finishedContestIds) }) diff --git a/apps/backend/apps/client/src/contest/contest.service.ts b/apps/backend/apps/client/src/contest/contest.service.ts index e4d99e1d56..9efb873196 100644 --- a/apps/backend/apps/client/src/contest/contest.service.ts +++ b/apps/backend/apps/client/src/contest/contest.service.ts @@ -211,7 +211,23 @@ export class ContestService { orderBy: [{ endTime: 'desc' }, { id: 'desc' }] }) - return this.renameToParticipants(contests) + const total = await this.prisma.contest.count({ + where: { + groupId, + endTime: { + lte: now + }, + id: { + in: registeredContestIds + }, + title: { + contains: search + }, + isVisible: true + } + }) + + return { data: this.renameToParticipants(contests), total } } async getFinishedContestsByGroupId( @@ -239,7 +255,21 @@ export class ContestService { select: contestSelectOption, orderBy: [{ endTime: 'desc' }, { id: 'desc' }] }) - return { finished: this.renameToParticipants(finished) } + + const total = await this.prisma.contest.count({ + where: { + endTime: { + lte: now + }, + groupId, + isVisible: true, + title: { + contains: search + } + } + }) + + return { data: this.renameToParticipants(finished), total } } // TODO: participants 대신 _count.contestRecord 그대로 사용하는 것 고려해보기 diff --git a/apps/backend/apps/client/src/group/group.service.spec.ts b/apps/backend/apps/client/src/group/group.service.spec.ts index 91ccc6a95d..9701c8c98b 100644 --- a/apps/backend/apps/client/src/group/group.service.spec.ts +++ b/apps/backend/apps/client/src/group/group.service.spec.ts @@ -133,22 +133,25 @@ describe('GroupService', () => { const cursor = null const res = await service.getGroups(cursor, take) - expect(res).to.deep.equal([ - { - id: 3, - groupName: 'Example Private Group 2', - description: - 'This is an example private group just for testing. Check if this group is not shown to users not registered to this group.', - memberNum: 1 - }, - { - id: 4, - groupName: 'Example Private Group 3', - description: - 'This is an example private group just for testing. Check if this group is not shown to users not registered to this group.', - memberNum: 2 - } - ]) + expect(res).to.deep.equal({ + data: [ + { + id: 3, + groupName: 'Example Private Group 2', + description: + 'This is an example private group just for testing. Check if this group is not shown to users not registered to this group.', + memberNum: 1 + }, + { + id: 4, + groupName: 'Example Private Group 3', + description: + 'This is an example private group just for testing. Check if this group is not shown to users not registered to this group.', + memberNum: 2 + } + ], + total: 4 + }) }) }) diff --git a/apps/backend/apps/client/src/group/group.service.ts b/apps/backend/apps/client/src/group/group.service.ts index 7b276649c0..c6aedc41fd 100644 --- a/apps/backend/apps/client/src/group/group.service.ts +++ b/apps/backend/apps/client/src/group/group.service.ts @@ -156,7 +156,19 @@ export class GroupService { } }) - return groups + const total = await this.prisma.group.count({ + where: { + NOT: { + id: 1 + }, + config: { + path: ['showOnList'], + equals: true + } + } + }) + + return { data: groups, total } } async getJoinedGroups(userId: number) { diff --git a/apps/backend/apps/client/src/notice/notice.service.spec.ts b/apps/backend/apps/client/src/notice/notice.service.spec.ts index 124be0277d..5b8735449c 100644 --- a/apps/backend/apps/client/src/notice/notice.service.spec.ts +++ b/apps/backend/apps/client/src/notice/notice.service.spec.ts @@ -9,6 +9,7 @@ const noticeId = 2 const userId = 1 const groupId = 1 const username = 'manager' +const totalNotice = 24 const notice = { id: noticeId, @@ -55,7 +56,8 @@ const db = { findUnique: stub().resolves(notice), findUniqueOrThrow: stub().resolves(notice), findFirst: stub(), - findFirstOrThrow: stub() + findFirstOrThrow: stub(), + count: stub().resolves(24) }, group: { findUnique: stub().resolves(group) @@ -121,7 +123,10 @@ describe('NoticeService', () => { take: 3, groupId: group.id }) - expect(getNoticesByGroupId).to.deep.equal(userNotices) + expect(getNoticesByGroupId).to.deep.equal({ + data: userNotices, + total: totalNotice + }) }) }) @@ -165,7 +170,11 @@ describe('NoticeService', () => { take: 3, groupId: group.id }) - expect(getFixedNoticesByGroupId).to.deep.equal(userNotices) + + expect(getFixedNoticesByGroupId).to.deep.equal({ + data: userNotices, + total: totalNotice + }) }) }) diff --git a/apps/backend/apps/client/src/notice/notice.service.ts b/apps/backend/apps/client/src/notice/notice.service.ts index 9bf1c0912d..4acb4b86bd 100644 --- a/apps/backend/apps/client/src/notice/notice.service.ts +++ b/apps/backend/apps/client/src/notice/notice.service.ts @@ -47,12 +47,26 @@ export class NoticeService { orderBy: { id: 'desc' } }) - return notices.map((notice) => { + const data = notices.map((notice) => { return { ...notice, createdBy: notice.createdBy?.username } }) + + const total = await this.prisma.notice.count({ + where: { + groupId, + isVisible: true, + isFixed: fixed, + title: { + contains: search, + mode: 'insensitive' + } + } + }) + + return { data, total } } async getNoticeByID(id: number, groupId = OPEN_SPACE_ID) { diff --git a/apps/backend/apps/client/src/problem/dto/problems.response.dto.ts b/apps/backend/apps/client/src/problem/dto/problems.response.dto.ts index 4ff6d56408..c299efc744 100644 --- a/apps/backend/apps/client/src/problem/dto/problems.response.dto.ts +++ b/apps/backend/apps/client/src/problem/dto/problems.response.dto.ts @@ -5,7 +5,7 @@ import { Exclude, Expose, Type } from 'class-transformer' export class ProblemsResponseDto { @Expose() @Type(() => Problem) - problems: Problem[] + data: Problem[] @Expose() total: number diff --git a/apps/backend/apps/client/src/problem/dto/related-problems.response.dto.ts b/apps/backend/apps/client/src/problem/dto/related-problems.response.dto.ts index 76880e6468..4ab4d0a2de 100644 --- a/apps/backend/apps/client/src/problem/dto/related-problems.response.dto.ts +++ b/apps/backend/apps/client/src/problem/dto/related-problems.response.dto.ts @@ -5,7 +5,7 @@ import { Exclude, Expose, Transform, Type } from 'class-transformer' export class RelatedProblemsResponseDto { @Expose() @Type(() => Problem) - problems: Problem[] + data: Problem[] @Expose() total: number diff --git a/apps/backend/apps/client/src/problem/problem.service.spec.ts b/apps/backend/apps/client/src/problem/problem.service.spec.ts index f5650c30de..1cf4223be4 100644 --- a/apps/backend/apps/client/src/problem/problem.service.spec.ts +++ b/apps/backend/apps/client/src/problem/problem.service.spec.ts @@ -163,7 +163,7 @@ describe('ProblemService', () => { // then expect(result).to.deep.equal( plainToInstance(ProblemsResponseDto, { - problems: [ + data: [ { ...mockProblems[0], submissionCount: 10, @@ -275,7 +275,7 @@ describe('ContestProblemService', () => { // then expect(result).to.deep.equal( plainToInstance(RelatedProblemsResponseDto, { - problems: mockContestProblems, + data: mockContestProblems, total: 2 }) ) @@ -303,7 +303,7 @@ describe('ContestProblemService', () => { // then expect(result).to.deep.equal( plainToInstance(RelatedProblemsResponseDto, { - problems: mockContestProblems, + data: mockContestProblems, total: 2 }) ) @@ -491,7 +491,7 @@ describe('WorkbookProblemService', () => { // then expect(result).to.deep.equal( plainToInstance(RelatedProblemsResponseDto, { - problems: mockWorkbookProblems, + data: mockWorkbookProblems, total: 2 }) ) @@ -513,7 +513,7 @@ describe('WorkbookProblemService', () => { // then expect(result).to.deep.equal( plainToInstance(RelatedProblemsResponseDto, { - problems: mockWorkbookProblems, + data: mockWorkbookProblems, total: 2 }) ) diff --git a/apps/backend/apps/client/src/problem/problem.service.ts b/apps/backend/apps/client/src/problem/problem.service.ts index 93a94371c9..779f944062 100644 --- a/apps/backend/apps/client/src/problem/problem.service.ts +++ b/apps/backend/apps/client/src/problem/problem.service.ts @@ -54,7 +54,7 @@ export class ProblemService { ) return plainToInstance(ProblemsResponseDto, { - problems: await Promise.all(problems), + data: await Promise.all(problems), total }) } @@ -105,7 +105,7 @@ export class ContestProblemService { await this.problemRepository.getContestProblemTotalCount(contestId) return plainToInstance(RelatedProblemsResponseDto, { - problems: data, + data, total }) } @@ -164,7 +164,7 @@ export class WorkbookProblemService { await this.problemRepository.getWorkbookProblemTotalCount(workbookId) return plainToInstance(RelatedProblemsResponseDto, { - problems: data, + data, total }) } diff --git a/apps/backend/apps/client/src/submission/submission.service.spec.ts b/apps/backend/apps/client/src/submission/submission.service.spec.ts index 68800869d9..444d45cb0a 100644 --- a/apps/backend/apps/client/src/submission/submission.service.spec.ts +++ b/apps/backend/apps/client/src/submission/submission.service.spec.ts @@ -27,7 +27,8 @@ const db = { findMany: stub(), findFirstOrThrow: stub(), create: stub(), - update: stub() + update: stub(), + count: stub().resolves(1) }, submissionResult: { create: stub() @@ -309,7 +310,7 @@ describe('SubmissionService', () => { expect( await service.getSubmissions({ problemId: problems[0].id }) - ).to.be.deep.equal(submissions) + ).to.be.deep.equal({ data: submissions, total: 1 }) }) it('should throw not found error', async () => { diff --git a/apps/backend/apps/client/src/submission/submission.service.ts b/apps/backend/apps/client/src/submission/submission.service.ts index 0cf2fd3dd1..9fea4bbfa4 100644 --- a/apps/backend/apps/client/src/submission/submission.service.ts +++ b/apps/backend/apps/client/src/submission/submission.service.ts @@ -452,7 +452,7 @@ export class SubmissionService implements OnModuleInit { groupId?: number cursor?: number | null take?: number - }): Promise[]> { + }) { const paginator = this.prisma.getPaginator(cursor) await this.prisma.problem.findFirstOrThrow({ @@ -486,7 +486,9 @@ export class SubmissionService implements OnModuleInit { orderBy: [{ id: 'desc' }, { createTime: 'desc' }] }) - return submissions + const total = await this.prisma.submission.count({ where: { problemId } }) + + return { data: submissions, total } } @Span() @@ -638,7 +640,7 @@ export class SubmissionService implements OnModuleInit { groupId?: number cursor?: number | null take?: number - }): Promise[]> { + }) { const paginator = this.prisma.getPaginator(cursor) const isAdmin = await this.prisma.user.findFirst({ @@ -670,7 +672,7 @@ export class SubmissionService implements OnModuleInit { } }) - return await this.prisma.submission.findMany({ + const submissions = await this.prisma.submission.findMany({ ...paginator, take, where: { @@ -692,5 +694,11 @@ export class SubmissionService implements OnModuleInit { }, orderBy: [{ id: 'desc' }, { createTime: 'desc' }] }) + + const total = await this.prisma.submission.count({ + where: { problemId, contestId } + }) + + return { data: submissions, total } } } diff --git a/apps/backend/apps/client/src/user/user.service.ts b/apps/backend/apps/client/src/user/user.service.ts index 283961a50a..d215092d15 100644 --- a/apps/backend/apps/client/src/user/user.service.ts +++ b/apps/backend/apps/client/src/user/user.service.ts @@ -12,7 +12,7 @@ import { generate } from 'generate-password' import { ExtractJwt } from 'passport-jwt' import { type AuthenticatedRequest, JwtAuthService } from '@libs/auth' import { emailAuthenticationPinCacheKey } from '@libs/cache' -import { EMAIL_AUTH_EXPIRE_TIME } from '@libs/constants' +import { EMAIL_AUTH_EXPIRE_TIME, ARGON2_HASH_OPTION } from '@libs/constants' import { ConflictFoundException, DuplicateFoundException, @@ -186,7 +186,7 @@ export class UserService { email }, data: { - password: await hash(newPassword) + password: await hash(newPassword, ARGON2_HASH_OPTION) } }) this.logger.debug(user, 'updateUserPasswordInPrisma') @@ -351,7 +351,7 @@ export class UserService { } async createUser(signUpDto: SignUpDto): Promise { - const encryptedPassword = await hash(signUpDto.password) + const encryptedPassword = await hash(signUpDto.password, ARGON2_HASH_OPTION) const user = await this.prisma.user.create({ data: { diff --git a/apps/backend/apps/client/src/workbook/workbook.service.spec.ts b/apps/backend/apps/client/src/workbook/workbook.service.spec.ts index ebe81c5929..3941fe08ef 100644 --- a/apps/backend/apps/client/src/workbook/workbook.service.spec.ts +++ b/apps/backend/apps/client/src/workbook/workbook.service.spec.ts @@ -107,7 +107,8 @@ const db = { findFirst: stub(), create: stub(), update: stub(), - delete: stub() + delete: stub(), + count: stub().resolves(3) }, workbookProblem: { findMany: stub() @@ -137,7 +138,10 @@ describe('WorkbookService', () => { 0, 3 ) - expect(returnedPublicWorkbooks).to.deep.equal(visiblePublicWorkbooks) + expect(returnedPublicWorkbooks).to.deep.equal({ + data: visiblePublicWorkbooks, + total: 3 + }) }) it('get a list of private group workbooks', async () => { @@ -148,7 +152,10 @@ describe('WorkbookService', () => { 3, PRIVATE_GROUP_ID ) - expect(returnedGroupWorkbooks).to.deep.equal(groupWorkbooks) + expect(returnedGroupWorkbooks).to.deep.equal({ + data: groupWorkbooks, + total: 3 + }) }) it('get details of a workbook (user)', async () => { diff --git a/apps/backend/apps/client/src/workbook/workbook.service.ts b/apps/backend/apps/client/src/workbook/workbook.service.ts index 8abe5e4391..b25507d368 100644 --- a/apps/backend/apps/client/src/workbook/workbook.service.ts +++ b/apps/backend/apps/client/src/workbook/workbook.service.ts @@ -29,7 +29,15 @@ export class WorkbookService { updateTime: true } }) - return workbooks + + const total = await this.prisma.workbook.count({ + where: { + groupId, + isVisible: true + } + }) + + return { data: workbooks, total } } async getWorkbook( diff --git a/apps/backend/libs/constants/src/argon2.constants.ts b/apps/backend/libs/constants/src/argon2.constants.ts new file mode 100644 index 0000000000..edc4da8e7b --- /dev/null +++ b/apps/backend/libs/constants/src/argon2.constants.ts @@ -0,0 +1,5 @@ +export const ARGON2_HASH_OPTION = { + timeCost: 2, + memoryCost: 2 ** 11, + parallelism: 1 +} diff --git a/apps/backend/libs/constants/src/index.ts b/apps/backend/libs/constants/src/index.ts index c7bfca4744..a657100fb6 100644 --- a/apps/backend/libs/constants/src/index.ts +++ b/apps/backend/libs/constants/src/index.ts @@ -2,3 +2,4 @@ export * from './oauth.constants' export * from './time.constants' export * from './rabbitmq.constants' export * from './submission.constants' +export * from './argon2.constants' diff --git a/apps/frontend/__tests__/components.test.tsx b/apps/frontend/__tests__/components.test.tsx new file mode 100644 index 0000000000..e0a9e4b157 --- /dev/null +++ b/apps/frontend/__tests__/components.test.tsx @@ -0,0 +1,24 @@ +import ContestCard from '@/app/(main)/_components/ContestCard' +import { render, screen } from '@testing-library/react' +import { expect, test } from 'vitest' + +test('ContestCard', () => { + render( + + ) + expect(screen.getByText('test')).toBeDefined() + expect(screen.getByText('ongoing')).toBeDefined() +}) diff --git a/apps/frontend/__tests__/utils.test.ts b/apps/frontend/__tests__/utils.test.ts new file mode 100644 index 0000000000..61029133ed --- /dev/null +++ b/apps/frontend/__tests__/utils.test.ts @@ -0,0 +1,15 @@ +import { convertToLetter, dateFormatter } from '@/lib/utils' +import { test, expect } from 'vitest' + +test('convertToLetter', () => { + expect(convertToLetter(0)).toBe('A') + expect(convertToLetter(1)).toBe('B') + expect(convertToLetter(2)).toBe('C') + expect(convertToLetter(25)).toBe('Z') +}) + +test('dateFormatter', () => { + expect(dateFormatter('2022-01-01', 'YYYY-MM-DD')).toBe('2022-01-01') + expect(dateFormatter('2022-01-01', 'DD/MM/YYYY')).toBe('01/01/2022') + expect(dateFormatter('2022-01-01', 'DD MMM YYYY')).toBe('01 Jan 2022') +}) diff --git a/apps/frontend/app/layout.tsx b/apps/frontend/app/layout.tsx index 4a74f7338a..1cc5ad9e1a 100644 --- a/apps/frontend/app/layout.tsx +++ b/apps/frontend/app/layout.tsx @@ -1,21 +1,13 @@ import { Toaster } from '@/components/ui/sonner' import { metaBaseUrl } from '@/lib/constants' -import { cn } from '@/lib/utils' import type { Metadata, Viewport } from 'next' import { Ubuntu_Mono } from 'next/font/google' -import localFont from 'next/font/local' +import 'pretendard/dist/web/variable/pretendardvariable-dynamic-subset.css' import './globals.css' // TODO: 추후에 페이지 별로 revalidate 시간 논의 및 조정 필요 export const revalidate = 5 -const pretendard = localFont({ - src: './PretendardVariable.woff2', - display: 'swap', - weight: '45 920', - variable: '--font-pretendard' -}) - const mono = Ubuntu_Mono({ subsets: ['latin'], weight: ['400'], @@ -42,7 +34,7 @@ export default function RootLayout({ children: React.ReactNode }) { return ( - + {children} ( - 'programming_lang', - problem.languages[0] - ) - const { code, setCode, setLanguage, language } = useEditorStore() const pathname = usePathname() const base = contestId ? `/contest/${contestId}` : '' - - useEffect(() => { - if (!language) { - setLanguage(value ?? problem.languages[0]) - } else if (language && !problem.languages.includes(language)) { - // if value in storage is not in languages, set value to the first language - setLanguage(problem.languages[0]) - } - }, [problem.languages, value, setLanguage, language]) - return (
- +
) } + +function CodeEditorInEditorResizablePanel({ + problem +}: { + problem: ProblemDetail +}) { + // get programming language from localStorage for default value + const { value } = useStorage( + 'programming_lang', + problem.languages[0] + ) + const { code, setCode, setLanguage, language } = useEditorStore() + + useEffect(() => { + if (!language) { + setLanguage(value ?? problem.languages[0]) + } else if (language && !problem.languages.includes(language)) { + // if value in storage is not in languages, set value to the first language + setLanguage(problem.languages[0]) + } + }, [problem.languages, value, setLanguage, language]) + return ( + + ) +} diff --git a/apps/frontend/components/TextEditor.tsx b/apps/frontend/components/TextEditor.tsx index 0749689eb4..d32e733558 100644 --- a/apps/frontend/components/TextEditor.tsx +++ b/apps/frontend/components/TextEditor.tsx @@ -154,7 +154,7 @@ export default function TextEditor({ editorProps: { attributes: { class: - 'rounded-b-md border overflow-y-auto w-full h-[200px] border-input bg-backround px-3 ring-offset-2 disabled:cursur-not-allowed disabled:opacity-50' + 'rounded-b-md border overflow-y-auto w-full h-[200px] border-input bg-backround px-3 ring-offset-2 disabled:cursur-not-allowed disabled:opacity-50 resize-y' } }, onUpdate({ editor }) { diff --git a/apps/frontend/components/ui/command.tsx b/apps/frontend/components/ui/command.tsx index 64db34373e..e40360844c 100644 --- a/apps/frontend/components/ui/command.tsx +++ b/apps/frontend/components/ui/command.tsx @@ -3,8 +3,8 @@ import { Dialog, DialogContent } from '@/components/ui/dialog' import { cn } from '@/lib/utils' import type { DialogProps } from '@radix-ui/react-dialog' +import { MagnifyingGlassIcon } from '@radix-ui/react-icons' import { Command as CommandPrimitive } from 'cmdk' -import { Search } from 'lucide-react' import * as React from 'react' const Command = React.forwardRef< @@ -27,7 +27,7 @@ interface CommandDialogProps extends DialogProps {} const CommandDialog = ({ children, ...props }: CommandDialogProps) => { return ( - + {children} @@ -41,11 +41,11 @@ const CommandInput = React.forwardRef< React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => (
- + =6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.24.1': + resolution: {integrity: sha512-1v202n7aUq4uXAieRTKcwPzNyphlCuqHHDcdSNc+vdhoTEZcFMh+L5yZuCmGaIO7bs1nJUNfHB89TZyoL48xNA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-jsx@7.23.4': resolution: {integrity: sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==} engines: {node: '>=6.9.0'} @@ -1479,6 +1506,144 @@ packages: resolution: {integrity: sha512-4pIMTa1nEFfMXitv7oaNEWOdM+zpOZavesa5GaiWTgda6Zk32CFGxjUp/iIaN0PwgUW1yTq/fztSjbpE8SLGZQ==} engines: {node: '>=4'} + '@esbuild/aix-ppc64@0.20.2': + resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.20.2': + resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.20.2': + resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.20.2': + resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.20.2': + resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.20.2': + resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.20.2': + resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.20.2': + resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.20.2': + resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.20.2': + resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.20.2': + resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.20.2': + resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.20.2': + resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.20.2': + resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.20.2': + resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.20.2': + resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.20.2': + resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.20.2': + resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.20.2': + resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.20.2': + resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.20.2': + resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.20.2': + resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.20.2': + resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.4.0': resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1952,6 +2117,10 @@ packages: resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} engines: {node: '>=8'} + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@josephg/resolvable@1.0.1': resolution: {integrity: sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg==} @@ -3204,6 +3373,86 @@ packages: rollup: optional: true + '@rollup/rollup-android-arm-eabi@4.17.2': + resolution: {integrity: sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.17.2': + resolution: {integrity: sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.17.2': + resolution: {integrity: sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.17.2': + resolution: {integrity: sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-linux-arm-gnueabihf@4.17.2': + resolution: {integrity: sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.17.2': + resolution: {integrity: sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.17.2': + resolution: {integrity: sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.17.2': + resolution: {integrity: sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.17.2': + resolution: {integrity: sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.17.2': + resolution: {integrity: sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.17.2': + resolution: {integrity: sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.17.2': + resolution: {integrity: sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.17.2': + resolution: {integrity: sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.17.2': + resolution: {integrity: sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.17.2': + resolution: {integrity: sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.17.2': + resolution: {integrity: sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==} + cpu: [x64] + os: [win32] + '@rushstack/eslint-patch@1.8.0': resolution: {integrity: sha512-0HejFckBN2W+ucM6cUOlwsByTKt9/+0tWhqUffNIcHqCXkthY/mZ7AuYPK/2IIaGWhdl0h+tICDO0ssLMd6XMQ==} @@ -3280,6 +3529,9 @@ packages: resolution: {integrity: sha512-x0PYIMWcsTauqxgl7vWUY6sANl+XGKtx7DCVnnY7aOIIlIna0jChTAPANTfA2QrK+VK+4I/4JxatCEZBnXh3Og==} engines: {node: '>= 8'} + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + '@sinonjs/commons@2.0.0': resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==} @@ -3530,6 +3782,21 @@ packages: '@tanstack/virtual-core@3.5.0': resolution: {integrity: sha512-KnPRCkQTyqhanNC0K63GBG3wA8I+D1fQuVnAvcBF8f13akOKeQp1gSbu6f77zCxhEk727iV5oQnbHLYzHrECLg==} + '@testing-library/dom@10.1.0': + resolution: {integrity: sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA==} + engines: {node: '>=18'} + + '@testing-library/react@15.0.7': + resolution: {integrity: sha512-cg0RvEdD1TIhhkm1IeYMQxrzy0MtUNfa3minv4MjbgcYzJAZ7yD0i0lwoPOTPr+INtiXFezt2o8xMSnyHhEn2Q==} + engines: {node: '>=18'} + peerDependencies: + '@types/react': ^18.0.0 + react: ^18.0.0 + react-dom: ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@tiptap/core@2.3.2': resolution: {integrity: sha512-4sMpzYuxiG+fYMwPRXy+mLRVU315KEqzQUcBc2FEgSsmw9Kionykmkq3DvEco7rH8r0NdV/l9R49wVEtX54VqQ==} peerDependencies: @@ -3701,6 +3968,21 @@ packages: '@types/apollo-upload-client@18.0.0': resolution: {integrity: sha512-cMgITNemktxasqvp6jiPj15dv84n3FTMvMoYBP1+xonDS+0l6JygIJrj2LJh85rShRzTOOkrElrAsCXXARa3KA==} + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.6.8': + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.20.5': + resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} + '@types/body-parser@1.19.5': resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} @@ -4005,6 +4287,27 @@ packages: '@ungap/structured-clone@1.2.0': resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + '@vitejs/plugin-react@4.2.1': + resolution: {integrity: sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 + + '@vitest/expect@1.6.0': + resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==} + + '@vitest/runner@1.6.0': + resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==} + + '@vitest/snapshot@1.6.0': + resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==} + + '@vitest/spy@1.6.0': + resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==} + + '@vitest/utils@1.6.0': + resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==} + '@webassemblyjs/ast@1.12.1': resolution: {integrity: sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==} @@ -4221,6 +4524,10 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} @@ -4515,6 +4822,10 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + cache-manager-redis-yet@5.0.0: resolution: {integrity: sha512-ooBCA71CVUFPoLBx54vig0zhEe5yLcGDQmy9FGS1lBm0wc/efccC+KHdW9mURbuAtL7bi4mRiDA0bHg1a3Vbhw==} engines: {node: '>= 18'} @@ -4795,6 +5106,9 @@ packages: resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} engines: {'0': node >= 0.8} + confbox@0.1.7: + resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==} + config-chain@1.1.13: resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} @@ -5109,6 +5423,10 @@ packages: didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} @@ -5146,6 +5464,9 @@ packages: doctypes@1.1.0: resolution: {integrity: sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==} + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + dom-serializer@1.4.1: resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} @@ -5314,6 +5635,11 @@ packages: es6-error@4.1.1: resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + esbuild@0.20.2: + resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} + engines: {node: '>=12'} + hasBin: true + escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} @@ -5493,6 +5819,9 @@ packages: estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -6508,6 +6837,9 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-tokens@9.0.0: + resolution: {integrity: sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==} + js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true @@ -6745,6 +7077,10 @@ packages: resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} engines: {node: '>=6.11.5'} + local-pkg@0.5.0: + resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==} + engines: {node: '>=14'} + localforage@1.10.0: resolution: {integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==} @@ -6913,6 +7249,10 @@ packages: peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + magic-string@0.16.0: resolution: {integrity: sha512-c4BEos3y6G2qO0B9X7K0FVLOPT9uGrjYwYRLFmDqyl5YMboUviyecnXWp94fJTSMwPw2/sf+CEYt5AGpmklkkQ==} @@ -7180,6 +7520,9 @@ packages: engines: {node: '>=10'} hasBin: true + mlly@1.7.0: + resolution: {integrity: sha512-U9SDaXGEREBYQgfejV97coK0UL1r+qnF2SyO9A3qcI8MzKnsIFKHNVEkrDyNncQTKQQumsasmeq84eNMdBfsNQ==} + mocha@10.4.0: resolution: {integrity: sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==} engines: {node: '>= 14.0.0'} @@ -7528,6 +7871,10 @@ packages: resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + p-limit@5.0.0: + resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} + engines: {node: '>=18'} + p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -7689,6 +8036,9 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} @@ -7742,6 +8092,9 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + pkg-types@1.1.1: + resolution: {integrity: sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==} + pkginfo@0.3.1: resolution: {integrity: sha512-yO5feByMzAp96LtP58wvPKSbaKAi/1C4kV9XpTctr6EepnP6F33RBNOiVrdz9BrPA98U2BMFsTNHo44TWcbQ2A==} engines: {node: '>= 0.4.0'} @@ -7815,6 +8168,9 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + pretendard@1.3.9: + resolution: {integrity: sha512-PaQAADyLY5v4kYFwkpSJHbSSYIkiriY/1xXw75TKoZ9UQQqeU+tvP05yTdZAWibiIYoo8ZKtRv8PM7w0IaywSw==} + prettier-linter-helpers@1.0.0: resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} engines: {node: '>=6.0.0'} @@ -7876,6 +8232,14 @@ packages: engines: {node: '>=14'} hasBin: true + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + pretty-format@3.8.0: resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==} @@ -8135,6 +8499,16 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} + engines: {node: '>=0.10.0'} + react-remove-scroll-bar@2.3.6: resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==} engines: {node: '>=10'} @@ -8360,6 +8734,11 @@ packages: engines: {node: '>=10.0.0'} hasBin: true + rollup@4.17.2: + resolution: {integrity: sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + rope-sequence@1.3.4: resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} @@ -8529,6 +8908,9 @@ packages: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -8544,6 +8926,7 @@ packages: sinon@17.0.2: resolution: {integrity: sha512-uihLiaB9FhzesElPDFZA7hDcNABzsVHwr3YfmM9sBllVwab3l0ltGlRV1XhpNfIacNDLGD1QRZNLs5nU5+hTuA==} + deprecated: There sirv@2.0.4: resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==} @@ -8624,6 +9007,9 @@ packages: stack-generator@2.0.10: resolution: {integrity: sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + stackframe@1.3.4: resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} @@ -8648,6 +9034,9 @@ packages: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} + std-env@3.7.0: + resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} + streamsearch@0.1.2: resolution: {integrity: sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA==} engines: {node: '>=0.8.0'} @@ -8730,6 +9119,9 @@ packages: resolution: {integrity: sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==} engines: {node: '>=14.16'} + strip-literal@2.1.0: + resolution: {integrity: sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==} + strip-outer@1.0.1: resolution: {integrity: sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==} engines: {node: '>=0.10.0'} @@ -8886,6 +9278,17 @@ packages: through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + tinybench@2.8.0: + resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==} + + tinypool@0.8.4: + resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} + engines: {node: '>=14.0.0'} + + tinyspy@2.2.1: + resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} + engines: {node: '>=14.0.0'} + tippy.js@6.3.7: resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==} @@ -9083,6 +9486,9 @@ packages: uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + ufo@1.5.3: + resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} + uglify-js@3.17.4: resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} engines: {node: '>=0.8.0'} @@ -9217,6 +9623,64 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} + vite-node@1.6.0: + resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + + vite@5.2.11: + resolution: {integrity: sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vitest@1.6.0: + resolution: {integrity: sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 1.6.0 + '@vitest/ui': 1.6.0 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vlq@0.2.3: resolution: {integrity: sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==} @@ -9341,6 +9805,11 @@ packages: engines: {node: '>= 8'} hasBin: true + why-is-node-running@2.2.2: + resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} + engines: {node: '>=8'} + hasBin: true + with@7.0.2: resolution: {integrity: sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==} engines: {node: '>= 10.0.0'} @@ -10576,6 +11045,16 @@ snapshots: '@babel/core': 7.24.5 '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-transform-react-jsx-self@7.24.5(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + + '@babel/plugin-transform-react-jsx-source@7.24.1(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-plugin-utils': 7.24.5 + '@babel/plugin-transform-react-jsx@7.23.4(@babel/core@7.24.5)': dependencies: '@babel/core': 7.24.5 @@ -11095,6 +11574,75 @@ snapshots: to-pascal-case: 1.0.0 unescape-js: 1.1.4 + '@esbuild/aix-ppc64@0.20.2': + optional: true + + '@esbuild/android-arm64@0.20.2': + optional: true + + '@esbuild/android-arm@0.20.2': + optional: true + + '@esbuild/android-x64@0.20.2': + optional: true + + '@esbuild/darwin-arm64@0.20.2': + optional: true + + '@esbuild/darwin-x64@0.20.2': + optional: true + + '@esbuild/freebsd-arm64@0.20.2': + optional: true + + '@esbuild/freebsd-x64@0.20.2': + optional: true + + '@esbuild/linux-arm64@0.20.2': + optional: true + + '@esbuild/linux-arm@0.20.2': + optional: true + + '@esbuild/linux-ia32@0.20.2': + optional: true + + '@esbuild/linux-loong64@0.20.2': + optional: true + + '@esbuild/linux-mips64el@0.20.2': + optional: true + + '@esbuild/linux-ppc64@0.20.2': + optional: true + + '@esbuild/linux-riscv64@0.20.2': + optional: true + + '@esbuild/linux-s390x@0.20.2': + optional: true + + '@esbuild/linux-x64@0.20.2': + optional: true + + '@esbuild/netbsd-x64@0.20.2': + optional: true + + '@esbuild/openbsd-x64@0.20.2': + optional: true + + '@esbuild/sunos-x64@0.20.2': + optional: true + + '@esbuild/win32-arm64@0.20.2': + optional: true + + '@esbuild/win32-ia32@0.20.2': + optional: true + + '@esbuild/win32-x64@0.20.2': + optional: true + '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': dependencies: eslint: 8.57.0 @@ -11791,6 +12339,10 @@ snapshots: '@istanbuljs/schema@0.1.3': {} + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.8 + '@josephg/resolvable@1.0.1': {} '@jridgewell/gen-mapping@0.3.5': @@ -13210,6 +13762,54 @@ snapshots: optionalDependencies: rollup: 2.78.0 + '@rollup/rollup-android-arm-eabi@4.17.2': + optional: true + + '@rollup/rollup-android-arm64@4.17.2': + optional: true + + '@rollup/rollup-darwin-arm64@4.17.2': + optional: true + + '@rollup/rollup-darwin-x64@4.17.2': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.17.2': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.17.2': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.17.2': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.17.2': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.17.2': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.17.2': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.17.2': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.17.2': + optional: true + + '@rollup/rollup-linux-x64-musl@4.17.2': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.17.2': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.17.2': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.17.2': + optional: true + '@rushstack/eslint-patch@1.8.0': {} '@selderee/plugin-htmlparser2@0.11.0': @@ -13341,6 +13941,8 @@ snapshots: - encoding - supports-color + '@sinclair/typebox@0.27.8': {} + '@sinonjs/commons@2.0.0': dependencies: type-detect: 4.0.8 @@ -13719,6 +14321,27 @@ snapshots: '@tanstack/virtual-core@3.5.0': {} + '@testing-library/dom@10.1.0': + dependencies: + '@babel/code-frame': 7.24.2 + '@babel/runtime': 7.24.5 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + chalk: 4.1.2 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + pretty-format: 27.5.1 + + '@testing-library/react@15.0.7(@types/react@18.3.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.24.5 + '@testing-library/dom': 10.1.0 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.1 + '@tiptap/core@2.3.2(@tiptap/pm@2.3.2)': dependencies: '@tiptap/pm': 2.3.2 @@ -13922,6 +14545,29 @@ snapshots: - react-dom - subscriptions-transport-ws + '@types/aria-query@5.0.4': {} + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.24.5 + '@babel/types': 7.24.5 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.5 + + '@types/babel__generator@7.6.8': + dependencies: + '@babel/types': 7.24.5 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.24.5 + '@babel/types': 7.24.5 + + '@types/babel__traverse@7.20.5': + dependencies: + '@babel/types': 7.24.5 + '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 @@ -14331,6 +14977,46 @@ snapshots: '@ungap/structured-clone@1.2.0': {} + '@vitejs/plugin-react@4.2.1(vite@5.2.11(@types/node@20.12.11)(terser@5.31.0))': + dependencies: + '@babel/core': 7.24.5 + '@babel/plugin-transform-react-jsx-self': 7.24.5(@babel/core@7.24.5) + '@babel/plugin-transform-react-jsx-source': 7.24.1(@babel/core@7.24.5) + '@types/babel__core': 7.20.5 + react-refresh: 0.14.2 + vite: 5.2.11(@types/node@20.12.11)(terser@5.31.0) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@1.6.0': + dependencies: + '@vitest/spy': 1.6.0 + '@vitest/utils': 1.6.0 + chai: 4.4.1 + + '@vitest/runner@1.6.0': + dependencies: + '@vitest/utils': 1.6.0 + p-limit: 5.0.0 + pathe: 1.1.2 + + '@vitest/snapshot@1.6.0': + dependencies: + magic-string: 0.30.5 + pathe: 1.1.2 + pretty-format: 29.7.0 + + '@vitest/spy@1.6.0': + dependencies: + tinyspy: 2.2.1 + + '@vitest/utils@1.6.0': + dependencies: + diff-sequences: 29.6.3 + estree-walker: 3.0.3 + loupe: 2.3.7 + pretty-format: 29.7.0 + '@webassemblyjs/ast@1.12.1': dependencies: '@webassemblyjs/helper-numbers': 1.11.6 @@ -14588,6 +15274,8 @@ snapshots: dependencies: color-convert: 2.0.1 + ansi-styles@5.2.0: {} + ansi-styles@6.2.1: {} any-promise@1.3.0: {} @@ -14962,6 +15650,8 @@ snapshots: bytes@3.1.2: {} + cac@6.7.14: {} + cache-manager-redis-yet@5.0.0: dependencies: '@redis/bloom': 1.2.0(@redis/client@1.5.14) @@ -15332,6 +16022,8 @@ snapshots: readable-stream: 2.3.8 typedarray: 0.0.6 + confbox@0.1.7: {} + config-chain@1.1.13: dependencies: ini: 1.3.8 @@ -15626,6 +16318,8 @@ snapshots: didyoumean@1.2.2: {} + diff-sequences@29.6.3: {} + diff@4.0.2: {} diff@5.0.0: {} @@ -15657,6 +16351,8 @@ snapshots: doctypes@1.1.0: optional: true + dom-accessibility-api@0.5.16: {} + dom-serializer@1.4.1: dependencies: domelementtype: 2.3.0 @@ -15896,6 +16592,32 @@ snapshots: es6-error@4.1.1: {} + esbuild@0.20.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.20.2 + '@esbuild/android-arm': 0.20.2 + '@esbuild/android-arm64': 0.20.2 + '@esbuild/android-x64': 0.20.2 + '@esbuild/darwin-arm64': 0.20.2 + '@esbuild/darwin-x64': 0.20.2 + '@esbuild/freebsd-arm64': 0.20.2 + '@esbuild/freebsd-x64': 0.20.2 + '@esbuild/linux-arm': 0.20.2 + '@esbuild/linux-arm64': 0.20.2 + '@esbuild/linux-ia32': 0.20.2 + '@esbuild/linux-loong64': 0.20.2 + '@esbuild/linux-mips64el': 0.20.2 + '@esbuild/linux-ppc64': 0.20.2 + '@esbuild/linux-riscv64': 0.20.2 + '@esbuild/linux-s390x': 0.20.2 + '@esbuild/linux-x64': 0.20.2 + '@esbuild/netbsd-x64': 0.20.2 + '@esbuild/openbsd-x64': 0.20.2 + '@esbuild/sunos-x64': 0.20.2 + '@esbuild/win32-arm64': 0.20.2 + '@esbuild/win32-ia32': 0.20.2 + '@esbuild/win32-x64': 0.20.2 + escalade@3.1.2: {} escape-goat@2.1.1: {} @@ -16162,6 +16884,10 @@ snapshots: estree-walker@2.0.2: {} + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.5 + esutils@2.0.3: {} etag@1.8.1: {} @@ -17330,6 +18056,8 @@ snapshots: js-tokens@4.0.0: {} + js-tokens@9.0.0: {} + js-yaml@3.14.1: dependencies: argparse: 1.0.10 @@ -17615,6 +18343,11 @@ snapshots: loader-runner@4.3.0: {} + local-pkg@0.5.0: + dependencies: + mlly: 1.7.0 + pkg-types: 1.1.1 + localforage@1.10.0: dependencies: lie: 3.1.1 @@ -17750,6 +18483,8 @@ snapshots: dependencies: react: 18.3.1 + lz-string@1.5.0: {} + magic-string@0.16.0: dependencies: vlq: 0.2.3 @@ -18229,6 +18964,13 @@ snapshots: mkdirp@1.0.4: {} + mlly@1.7.0: + dependencies: + acorn: 8.11.3 + pathe: 1.1.2 + pkg-types: 1.1.1 + ufo: 1.5.3 + mocha@10.4.0: dependencies: ansi-colors: 4.1.1 @@ -18636,6 +19378,10 @@ snapshots: dependencies: yocto-queue: 1.0.0 + p-limit@5.0.0: + dependencies: + yocto-queue: 1.0.0 + p-locate@4.1.0: dependencies: p-limit: 2.3.0 @@ -18806,6 +19552,8 @@ snapshots: path-type@4.0.0: {} + pathe@1.1.2: {} + pathval@1.1.1: {} pause@0.0.1: {} @@ -18874,6 +19622,12 @@ snapshots: dependencies: find-up: 4.1.0 + pkg-types@1.1.1: + dependencies: + confbox: 0.1.7 + mlly: 1.7.0 + pathe: 1.1.2 + pkginfo@0.3.1: {} pluralize@8.0.0: {} @@ -18938,6 +19692,8 @@ snapshots: prelude-ls@1.2.1: {} + pretendard@1.3.9: {} + prettier-linter-helpers@1.0.0: dependencies: fast-diff: 1.3.0 @@ -18950,6 +19706,18 @@ snapshots: prettier@3.2.5: {} + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + pretty-format@3.8.0: {} pretty-ms@9.0.0: @@ -19316,6 +20084,12 @@ snapshots: react-is@16.13.1: {} + react-is@17.0.2: {} + + react-is@18.3.1: {} + + react-refresh@0.14.2: {} + react-remove-scroll-bar@2.3.6(@types/react@18.3.1)(react@18.3.1): dependencies: react: 18.3.1 @@ -19558,6 +20332,28 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + rollup@4.17.2: + dependencies: + '@types/estree': 1.0.5 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.17.2 + '@rollup/rollup-android-arm64': 4.17.2 + '@rollup/rollup-darwin-arm64': 4.17.2 + '@rollup/rollup-darwin-x64': 4.17.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.17.2 + '@rollup/rollup-linux-arm-musleabihf': 4.17.2 + '@rollup/rollup-linux-arm64-gnu': 4.17.2 + '@rollup/rollup-linux-arm64-musl': 4.17.2 + '@rollup/rollup-linux-powerpc64le-gnu': 4.17.2 + '@rollup/rollup-linux-riscv64-gnu': 4.17.2 + '@rollup/rollup-linux-s390x-gnu': 4.17.2 + '@rollup/rollup-linux-x64-gnu': 4.17.2 + '@rollup/rollup-linux-x64-musl': 4.17.2 + '@rollup/rollup-win32-arm64-msvc': 4.17.2 + '@rollup/rollup-win32-ia32-msvc': 4.17.2 + '@rollup/rollup-win32-x64-msvc': 4.17.2 + fsevents: 2.3.3 + rope-sequence@1.3.4: {} rrweb-cssom@0.6.0: {} @@ -19769,6 +20565,8 @@ snapshots: get-intrinsic: 1.2.4 object-inspect: 1.13.1 + siginfo@2.0.0: {} + signal-exit@3.0.7: {} signal-exit@4.1.0: {} @@ -19869,6 +20667,8 @@ snapshots: dependencies: stackframe: 1.3.4 + stackback@0.0.2: {} + stackframe@1.3.4: {} stacktrace-gps@3.1.2: @@ -19892,6 +20692,8 @@ snapshots: statuses@2.0.1: {} + std-env@3.7.0: {} + streamsearch@0.1.2: {} streamsearch@1.1.0: {} @@ -19980,6 +20782,10 @@ snapshots: strip-json-comments@5.0.1: {} + strip-literal@2.1.0: + dependencies: + js-tokens: 9.0.0 + strip-outer@1.0.1: dependencies: escape-string-regexp: 1.0.5 @@ -20153,6 +20959,12 @@ snapshots: through@2.3.8: {} + tinybench@2.8.0: {} + + tinypool@0.8.4: {} + + tinyspy@2.2.1: {} + tippy.js@6.3.7: dependencies: '@popperjs/core': 2.11.8 @@ -20351,6 +21163,8 @@ snapshots: uc.micro@2.1.0: {} + ufo@1.5.3: {} + uglify-js@3.17.4: optional: true @@ -20468,6 +21282,67 @@ snapshots: vary@1.1.2: {} + vite-node@1.6.0(@types/node@20.12.11)(terser@5.31.0): + dependencies: + cac: 6.7.14 + debug: 4.3.4(supports-color@8.1.1) + pathe: 1.1.2 + picocolors: 1.0.0 + vite: 5.2.11(@types/node@20.12.11)(terser@5.31.0) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + + vite@5.2.11(@types/node@20.12.11)(terser@5.31.0): + dependencies: + esbuild: 0.20.2 + postcss: 8.4.38 + rollup: 4.17.2 + optionalDependencies: + '@types/node': 20.12.11 + fsevents: 2.3.3 + terser: 5.31.0 + + vitest@1.6.0(@types/node@20.12.11)(jsdom@24.0.0)(terser@5.31.0): + dependencies: + '@vitest/expect': 1.6.0 + '@vitest/runner': 1.6.0 + '@vitest/snapshot': 1.6.0 + '@vitest/spy': 1.6.0 + '@vitest/utils': 1.6.0 + acorn-walk: 8.3.2 + chai: 4.4.1 + debug: 4.3.4(supports-color@8.1.1) + execa: 8.0.1 + local-pkg: 0.5.0 + magic-string: 0.30.5 + pathe: 1.1.2 + picocolors: 1.0.0 + std-env: 3.7.0 + strip-literal: 2.1.0 + tinybench: 2.8.0 + tinypool: 0.8.4 + vite: 5.2.11(@types/node@20.12.11)(terser@5.31.0) + vite-node: 1.6.0(@types/node@20.12.11)(terser@5.31.0) + why-is-node-running: 2.2.2 + optionalDependencies: + '@types/node': 20.12.11 + jsdom: 24.0.0 + transitivePeerDependencies: + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + vlq@0.2.3: {} void-elements@3.1.0: @@ -20680,6 +21555,11 @@ snapshots: dependencies: isexe: 2.0.0 + why-is-node-running@2.2.2: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + with@7.0.2: dependencies: '@babel/parser': 7.24.5